feat(server): bound negotiated packet lengths

This commit is contained in:
Nils Andreas Svee committed 2026-08-12 22:25:14 +07:00
1 parent 964e7d6339
commit 0e7d363f96
7 files changed
+361 -53

No files matched your search

+57 -4
View File
@@ -8,17 +8,36 @@
/// server is not expected to reproduce.
pub const DEFAULT_MAX_SESSIONS: usize = 1024;
/// Default bound on the executable echo datagram size of one session, in bytes.
///
/// This is `irtt-rs` resource policy, not an interoperability requirement and
/// not a protocol constant. The server specification records upstream defaulting
/// to *unlimited*, which leaves a remotely negotiated allocation unbounded; that
/// is explicitly not a compatibility target.
///
/// 65,507 is the largest payload an IPv4 UDP datagram can carry, so it is the
/// conservative ceiling above which no negotiated length could be emitted as one
/// datagram on any address family. It bounds a session's echo buffer to roughly
/// 64 KiB, and it is already the maximum a normal `irtt-rs` client will ask for,
/// so ordinary traffic never meets it.
///
/// It is **not** an MTU and promises nothing about what a path will carry. Path
/// and interface policy is a separate, later concern; this value exists to keep
/// allocation bounded, not to predict fragmentation.
pub const DEFAULT_MAX_PACKET_LENGTH: usize = 65_507;
/// Configuration for a [`ServerCore`](crate::ServerCore).
///
/// Fields are private and set through consuming builder methods, so later
/// slices can add configuration without breaking construction. Only the
/// settings this OPEN/session slice actually uses exist yet; parameter
/// restriction knobs, lifetime policy and rate limits arrive with the slices
/// that implement them.
/// settings this OPEN/session slice actually uses exist yet; the remaining
/// parameter restriction knobs, lifetime policy and rate limits arrive with the
/// slices that implement them.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ServerConfig {
hmac_key: Option<Vec<u8>>,
max_sessions: usize,
max_packet_length: usize,
}
impl ServerConfig {
@@ -45,6 +64,32 @@ impl ServerConfig {
self
}
/// Sets the maximum echo datagram size a session may negotiate, in bytes.
///
/// This governs the *executable* echo datagram of a session, not the size of
/// the open exchange: a requested positive Length above this value is
/// reduced to it during negotiation, and an open whose mandatory echo field
/// block would not fit is silently refused, since the server could not emit
/// a compliant reply for it. Authentication counts toward that field block.
/// The echo slice will additionally use this limit to admit inbound echo
/// request datagrams by their received length.
///
/// The value is trusted local configuration, like
/// [`with_max_sessions`](Self::with_max_sessions): an operator may
/// deliberately raise it far past what any path carries, and that is their
/// resource choice to make. What must stay bounded is the *default*, which
/// is why there is deliberately no unlimited setting.
///
/// Zero is accepted and is not a synonym for unlimited. No session can
/// describe an echo packet smaller than its mandatory field block, so a zero
/// maximum silently refuses every session-creating open — and every no-test
/// open too, since both are validated against the same effective session.
#[must_use]
pub fn with_max_packet_length(mut self, max_packet_length: usize) -> Self {
self.max_packet_length = max_packet_length;
self
}
/// The configured HMAC key, if this server authenticates.
#[must_use]
pub fn hmac_key(&self) -> Option<&[u8]> {
@@ -56,14 +101,22 @@ impl ServerConfig {
pub fn max_sessions(&self) -> usize {
self.max_sessions
}
/// The maximum echo datagram size a session may negotiate, in bytes.
#[must_use]
pub fn max_packet_length(&self) -> usize {
self.max_packet_length
}
}
impl Default for ServerConfig {
/// An unauthenticated server bounded to [`DEFAULT_MAX_SESSIONS`] sessions.
/// An unauthenticated server bounded to [`DEFAULT_MAX_SESSIONS`] sessions,
/// each negotiating at most [`DEFAULT_MAX_PACKET_LENGTH`] bytes per echo.
fn default() -> Self {
Self {
hmac_key: None,
max_sessions: DEFAULT_MAX_SESSIONS,
max_packet_length: DEFAULT_MAX_PACKET_LENGTH,
}
}
}