feat(server): bound negotiated packet lengths
This commit is contained in:
7 files changed
+361
-53
No files matched your search
@@ -5,26 +5,46 @@ use crate::config::ServerConfig;
|
||||
/// Produces the parameters the server returns in an open reply and will enforce
|
||||
/// for the session.
|
||||
///
|
||||
/// This slice applies the minimum the specification requires: the requested
|
||||
/// known parameters, with the protocol version rewritten to
|
||||
/// [`PROTOCOL_VERSION`]. A server must return version 1 so that version-1
|
||||
/// clients accept the session; any requested value, including an absent,
|
||||
/// zero, negative or future one, is accepted and answered with 1. Detecting a
|
||||
/// version mismatch is therefore client-side only.
|
||||
/// Two restrictions apply so far.
|
||||
///
|
||||
/// Nothing else is restricted yet. A server *may* reduce or replace requested
|
||||
/// parameters, and later policy slices will add the maximum test duration
|
||||
/// clamp, minimum interval, idle-timeout interval cap, maximum packet length,
|
||||
/// timestamp allowance, DSCP policy and server-fill allow-list. This function
|
||||
/// is where they belong, which is why the configuration is threaded through
|
||||
/// even though no knob reads it yet.
|
||||
/// **Protocol version is rewritten to [`PROTOCOL_VERSION`].** A server must
|
||||
/// return version 1 so that version-1 clients accept the session; any requested
|
||||
/// value, including an absent, zero, negative or future one, is accepted and
|
||||
/// answered with 1. Detecting a version mismatch is therefore client-side only.
|
||||
///
|
||||
/// Negotiation rewriting nothing but the version does not mean every open is
|
||||
/// answered: the core validates what this function returns and silently
|
||||
/// discards an open whose effective parameters it could not execute. That is a
|
||||
/// separate step on purpose — this function decides what the session *would*
|
||||
/// be, and the core decides whether that session can exist.
|
||||
pub(crate) fn negotiate_params(mut requested: Params, _config: &ServerConfig) -> Params {
|
||||
/// **A positive Length above the configured maximum is reduced to it.** That
|
||||
/// bounds the echo datagram — and so the buffer — a remote peer can make this
|
||||
/// server negotiate, which is why it happens here rather than at send time: the
|
||||
/// value returned in the open reply has to be the one the server will actually
|
||||
/// honor. A negative Length is left exactly as requested and a zero stays zero;
|
||||
/// neither asks for space beyond the mandatory field block, which `irtt-proto`
|
||||
/// floors echo sizing at, so there is nothing to reduce and rewriting them would
|
||||
/// answer with a session the client did not ask for.
|
||||
///
|
||||
/// Those two are the whole of the current policy. A server *may* reduce or
|
||||
/// replace requested parameters, and later policy slices will add the maximum
|
||||
/// test duration clamp,
|
||||
/// minimum interval, idle-timeout interval cap, timestamp allowance, DSCP policy
|
||||
/// and server-fill allow-list.
|
||||
///
|
||||
/// Negotiation is not by itself an acknowledgement: the core validates what this
|
||||
/// function returns and silently discards an open whose effective parameters it
|
||||
/// could not execute. That is a separate step on purpose — this function decides
|
||||
/// what the session *would* be, and the core decides whether that session can
|
||||
/// exist. Capping Length here is not enough on its own, because the mandatory
|
||||
/// echo field block can exceed the configured maximum by itself.
|
||||
pub(crate) fn negotiate_params(mut requested: Params, config: &ServerConfig) -> Params {
|
||||
requested.protocol_version = PROTOCOL_VERSION;
|
||||
|
||||
// A configured maximum wider than `i64` cannot restrict anything: the wire
|
||||
// field cannot carry more than `i64::MAX` in the first place. Saturating
|
||||
// there is therefore exact, not an approximation — unlike converting the
|
||||
// requested length the other way, which would turn a value this platform
|
||||
// cannot represent into a plausible buffer size.
|
||||
let max_length = i64::try_from(config.max_packet_length()).unwrap_or(i64::MAX);
|
||||
if requested.length > max_length {
|
||||
requested.length = max_length;
|
||||
}
|
||||
|
||||
requested
|
||||
}
|
||||
Reference in new issue
Block a user