pub struct SnapTunServer<T: SnapTunAuthorization> { /* private fields */ }Expand description
The SnapTunServer manages one Tunn per remote socket address.
The main structural difference between WireGuard (R) and snaptun-ng is that there is a one-to-one relation between a remote socket address (of the initiator) and a tunnel. The SnapTunServer manages that relation.
§Socket address and identity
The remote socket address is the address of an endhost, so the server binds the tunnel to that address and to the static identity that established it. Only that identity keeps the address. A peer that spoofs the address of another endhost can therefore neither take the address over nor tear the tunnel down.
§Scaling
The main methods SnapTunServer::handle_incoming_packet, SnapTunServer::handle_outgoing_packet, and SnapTunServer::update_timers all require an exclusive reference to the internal state. The reason is that processing both, incoming and outgoing packets requires access to the session state.
One simple way to achieve load distribution across different cores/threads is to shard over multiple SnapTunServer-instances based on a hash of the remote socket address.
§Future improvements
- Separate incoming and outgoing code paths and optimistically lock the session state.
§How to use
The SnapTunServer is i/o-free; i.e. it only manages state. The following is a pseudo-code like description of the simplest i/o-layer integration:
let mut server = SnapTunServer::new(/*...*/);
let mut send_to_network = VecDequeue::new();
let mut current_sockaddr = ;
loop {
switch {
(network_packet, sockaddr) = network_socket => {
server.handle_incoming_packet(/*...*/);
/* dispatch packets to tunnel if necessary */
}
tunnel_packet = tunnel_socket => {
server.handle_outgoing_packet(/*...*/);
}
timer = tick(250ms) => {
server.update_timers();
}
}
// dispatch packets to network
for p in send_to_network {
network_socket.send(sockaddr, p);
}
}Implementations§
Source§impl<T: SnapTunAuthorization> SnapTunServer<T>
impl<T: SnapTunAuthorization> SnapTunServer<T>
Sourcepub fn new(
static_private: StaticSecret,
rate_limiter: Arc<RateLimiter>,
authz: Arc<T>,
) -> Self
pub fn new( static_private: StaticSecret, rate_limiter: Arc<RateLimiter>, authz: Arc<T>, ) -> Self
Creates a new SnapTunServer instance.
Sourcepub fn handle_incoming_packet(
&mut self,
packet: Packet,
from: SocketAddr,
send_to_network: &mut VecDeque<WgKind>,
) -> TunnResult
pub fn handle_incoming_packet( &mut self, packet: Packet, from: SocketAddr, send_to_network: &mut VecDeque<WgKind>, ) -> TunnResult
Handle incoming packet for a tunnel assocated with remote socket address
from.
This method never returns TunnResult::WriteToNetwork. Instead, it codifies the expected protocol behavior which is that, upon receiving a packet from the remote, the queue of outgoing packets is completely drained.
If the rate limiter signals that the server is under load, at most one packet is added to the queue.
This compatibility wrapper preserves the original public API for callers that only care about the tunnel result.
Sourcepub fn handle_incoming_packet_with_session(
&mut self,
packet: Packet,
from: SocketAddr,
send_to_network: &mut VecDeque<WgKind>,
) -> HandleIncomingPacketResult<T::SessionData>
pub fn handle_incoming_packet_with_session( &mut self, packet: Packet, from: SocketAddr, send_to_network: &mut VecDeque<WgKind>, ) -> HandleIncomingPacketResult<T::SessionData>
Handles an incoming packet and also returns the active session when one was resolved while processing the packet.
Callers on the dataplane hot path can use this to observe forwarded
packets without re-hashing from for a second active-tunnel lookup,
while existing callers can keep using SnapTunServer::handle_incoming_packet.
The method resolves the tunnel by from before it reads the kind of the
packet, and it authorizes the identity of that tunnel. It parses and
authorizes the identity that a handshake initiation carries only for an
address that holds no tunnel yet. An address that holds a tunnel
therefore stays with the identity of that tunnel.
Sourcepub fn handle_outgoing_packet(
&mut self,
packet: Packet,
to: SocketAddr,
) -> Option<WgKind>
pub fn handle_outgoing_packet( &mut self, packet: Packet, to: SocketAddr, ) -> Option<WgKind>
Handles an outgoing packet sent through the tunnel identified by the
remote socket address to.
Sourcepub fn handle_outgoing_packet_with_session(
&mut self,
packet: Packet,
to: SocketAddr,
) -> Option<HandleOutgoingPacketResult<T::SessionData>>
pub fn handle_outgoing_packet_with_session( &mut self, packet: Packet, to: SocketAddr, ) -> Option<HandleOutgoingPacketResult<T::SessionData>>
Handles an outgoing packet and returns the active tunnel session used to admit the payload into the tunnel pipeline.
This re-checks authorization on the outgoing path. If the active tunnel
no longer has current authorization, the packet is dropped and None is
returned even when the tunnel state itself still exists.
Sourcepub fn update_timers(&mut self) -> Vec<(SocketAddr, WgKind)>
pub fn update_timers(&mut self) -> Vec<(SocketAddr, WgKind)>
Update timers of all tunnels. Generate corresponding keepalive or session handshake initializations.
As a result of this call, all expired tunnels are removed. Note that this is not the same as unauthorized tunnels.
Callers are expected to invoke this periodically; it is also where the rate limiter’s under-load counter is reset. Without that reset the counter only ever grows and the server eventually treats itself as permanently under load.
Auto Trait Implementations§
impl<T> !RefUnwindSafe for SnapTunServer<T>
impl<T> !UnwindSafe for SnapTunServer<T>
impl<T> Freeze for SnapTunServer<T>
impl<T> Send for SnapTunServer<T>
impl<T> Sync for SnapTunServer<T>
impl<T> Unpin for SnapTunServer<T>
impl<T> UnsafeUnpin for SnapTunServer<T>where
Arc<T>: UnsafeUnpin,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more