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.
§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.
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