Skip to main content

snap_dataplane/
tunnel_gateway.rs

1// Copyright 2026 Anapaya Systems
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//   http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//! Tunnel gateway
15
16use std::{sync::Arc, time::Instant};
17
18use scion_sdk_utils::task_handler::CancelTaskSet;
19use sciparse::identifier::isd_asn::IsdAsn;
20use snap_tun::server::SnapTunAuthorization;
21use tokio::net::UdpSocket;
22
23use crate::{
24    dispatcher::Dispatcher,
25    tunnel_gateway::{dispatcher::TunnelGatewayDispatcherReceiver, gateway::TunnelGateway},
26};
27
28pub mod dispatcher;
29pub mod gateway;
30pub mod metrics;
31pub(crate) mod packet_policy;
32pub mod state;
33
34/// The direction in which the observed packet crossed the SNAP tunnel.
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum ObservedPacketDirection {
37    /// The packet arrived from the client over the SNAP tunnel and is headed
38    /// toward the SCION router.
39    Ingress,
40    /// The packet arrived from the SCION side and was encapsulated toward the
41    /// client over the SNAP tunnel.
42    Egress,
43}
44
45/// Packet metadata captured at the point where a packet has successfully
46/// crossed the SNAP tunnel boundary and can be accounted.
47#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub struct ObservedPacketMeta {
49    /// Source ISD-AS from the parsed SCION packet.
50    pub src_ia: IsdAsn,
51    /// Destination ISD-AS from the parsed SCION packet.
52    pub dst_ia: IsdAsn,
53    /// Total packet length in bytes used for accounting.
54    pub packet_len: usize,
55    /// Direction in which the packet crossed the tunnel.
56    pub direction: ObservedPacketDirection,
57}
58
59/// Observes successfully tunneled packets together with the session data that produced them.
60pub trait TunnelGatewayObserver<S>: Send + Sync {
61    /// Called once a packet has successfully crossed the SNAP tunnel boundary
62    /// and the gateway has recovered the relevant accounting metadata.
63    ///
64    /// `now` is the timestamp captured while processing the relevant packet path.
65    fn observe_packet(&self, now: Instant, session_data: &S, packet: ObservedPacketMeta);
66}
67
68/// A tunnel-gateway observer that ignores all observed packets.
69#[derive(Debug, Default)]
70pub struct NoopTunnelGatewayObserver;
71
72impl<S> TunnelGatewayObserver<S> for NoopTunnelGatewayObserver {
73    fn observe_packet(&self, _now: Instant, _session_data: &S, _packet: ObservedPacketMeta) {}
74}
75
76/// Start the tunnel gateway.
77///
78/// # Arguments
79/// * `tasks`: The task set used to launch the asynchronous tasks.
80/// * `socket`: The UDP socket that terminates SNAP tunnels.
81/// * `authz`: The authorization layer for the snaptun.
82/// * `dispatcher`: Receives validated SCION packets for forwarding.
83/// * `observer`: Receives observed packet metadata together with the resolved current session data.
84///   Used for flow accounting and metrics.
85/// * `tun_dispatcher_rx`: The receiving end of the dispatcher interface.
86/// * `server_static_secret`: The static secret of the tunnel gateway's tunnel endpoint.
87pub fn start_tunnel_gateway<A, D, O>(
88    tasks: &mut CancelTaskSet,
89    socket: UdpSocket,
90    authz: Arc<A>,
91    dispatcher: Arc<D>,
92    observer: Arc<O>,
93    tun_dispatcher_rx: TunnelGatewayDispatcherReceiver,
94    server_static_secret: x25519_dalek::StaticSecret,
95) where
96    A: SnapTunAuthorization + 'static,
97    D: Dispatcher + 'static,
98    O: TunnelGatewayObserver<A::SessionData> + ?Sized + 'static,
99{
100    let tun_gateway = TunnelGateway::new(
101        socket,
102        server_static_secret,
103        authz,
104        dispatcher,
105        observer,
106        tun_dispatcher_rx,
107    );
108    let token = tasks.cancellation_token();
109    tasks.spawn_cancellable_task(async move {
110        tun_gateway.start_server(token).await;
111        Ok(())
112    });
113}