1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! A sans-IO implementation of the WireGuard protocol.
//!
//! # Example
//!
//! Alice and Bob complete a handshake, then Alice sends Bob a packet. In an application, your
//! event loop sends datagrams over UDP, handles events from [`Tunnel::poll_event`] and drives
//! timers with [`Tunnel::poll_timeout`] and [`Tunnel::handle_timeout`].
//!
//! ```
//! use std::time::{Instant, SystemTime, UNIX_EPOCH};
//!
//! use sanstun::{Committed, Interface, Received, ReceivedMessage, TunnelConfig};
//! use zeroize::Zeroizing;
//!
//! let now = Instant::now();
//! let unix = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
//! let alice_addr = "192.0.2.1:51820".parse().unwrap();
//! let bob_addr = "192.0.2.2:51820".parse().unwrap();
//!
//! let mut alice = Interface::new(Zeroizing::new(rand::random()), now, unix);
//! let mut bob = Interface::new(Zeroizing::new(rand::random()), now, unix);
//! let mut alice_to_bob = alice.new_tunnel(bob.static_public(), TunnelConfig::default(), now)?;
//! let mut bob_to_alice = bob.new_tunnel(alice.static_public(), TunnelConfig::default(), now)?;
//!
//! // Alice initiates the handshake and Bob responds.
//! let initiation = alice_to_bob.initiate_handshake(now).unwrap();
//! let response = match bob.receive(alice_addr, &initiation, now)? {
//! Received::Message(ReceivedMessage::HandshakeInitiation(initiation)) => {
//! bob_to_alice.handle_handshake_initiation(initiation, now)?
//! }
//! // Under load, send the cookie reply back to the peer.
//! Received::SendCookieReply(_) => unreachable!("not under load"),
//! received => unreachable!("expected an initiation, got {received:?}"),
//! };
//!
//! // Alice completes the handshake and confirms it with a keepalive for Bob.
//! let _keepalive = match alice.receive(bob_addr, &response, now)? {
//! Received::Message(ReceivedMessage::HandshakeResponse(response)) => {
//! alice_to_bob.handle_handshake_response(response, now)?
//! }
//! received => unreachable!("expected a response, got {received:?}"),
//! };
//!
//! // Alice encrypts a packet.
//! let packet = b"an IP packet";
//! let mut buf = [0; 64];
//! let data = alice_to_bob.begin_encapsulate(now)?.encrypt(packet, &mut buf)?;
//!
//! // Bob decrypts and accepts it.
//! let decrypted = match bob.receive(alice_addr, &data, now)? {
//! Received::Message(ReceivedMessage::TransportData(message)) => {
//! bob_to_alice.begin_decapsulate(message, now)?.decrypt(&data, [0; 64])
//! }
//! received => unreachable!("expected data, got {received:?}"),
//! };
//! match bob_to_alice.commit_decapsulate(decrypted, now)? {
//! // The plaintext is zero-padded to a multiple of 16 bytes.
//! Committed::Data { buffer, len } => assert_eq!(&buffer[..len], b"an IP packet\0\0\0\0"),
//! // A keepalive carries no packet to forward.
//! Committed::Keepalive => unreachable!("Alice sent a packet"),
//! }
//! # Ok::<(), sanstun::Error>(())
//! ```
//!
//! # Caller responsibilities
//!
//! sanstun handles the protocol and cryptography. Your application is responsible for:
//!
//! - **Cryptokey routing:** check that each decrypted packet's source IP is allowed for the peer
//! that sent it. Authentication alone does not grant permission to use an IP address.
//! - **Handshake routing:** use [`HandshakeInitiation::peer_static_public`] to look up an authorized
//! peer. Anyone can generate a key pair, so an authenticated initiation is no reason to create a
//! tunnel for an unknown key. Replay checks only apply to keys you have created a tunnel for,
//! and only take effect in [`Tunnel::handle_handshake_initiation`]: do not act on an initiation
//! before its tunnel accepts it.
//! - **Endpoint updates:** only update a peer's endpoint after [`Tunnel::handle_handshake_initiation`]
//! or [`Tunnel::handle_handshake_response`] accepts its handshake or
//! [`Tunnel::commit_decapsulate`] accepts its data. A datagram's source address
//! alone does not identify the peer.
//! - **Bounded queues:** limit queues used to send encryption or decryption work to other threads.
//! A [`PendingDecapsulate`] is cheap to create but costly to decrypt, and a flood can exhaust memory.
//! - **Packet validation:** parse decrypted IP packets, check their declared lengths and strip
//! padding before forwarding them. Data messages are zero-padded to a multiple of 16 bytes.
//! - **Errors:** handle [`Error`] locally. Never send errors to peers; they can reveal internal
//! state such as the replay window.
//! - **Time:** use a monotonic clock for `now`. The Unix time passed to [`Interface::new`] must
//! not go backwards across restarts, or peers may reject handshake initiations as replays.
pub use Error;
pub use TunnelId;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;