From ed805e854ffe92e51f1953cc8b59f6ffeb2522ef Mon Sep 17 00:00:00 2001 From: Nils Andreas Svee Date: Tue, 15 Sep 2026 12:31:10 +0700 Subject: [PATCH] docs(server): document DSCP-safe listener pairing --- crates/irtt-server/AGENTS.md | 15 ++++++++------- crates/irtt-server/src/set.rs | 8 ++++++++ docs/irtt-server.md | 9 +++++++++ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/crates/irtt-server/AGENTS.md b/crates/irtt-server/AGENTS.md index 576be03..d3804b3 100644 --- a/crates/irtt-server/AGENTS.md +++ b/crates/irtt-server/AGENTS.md @@ -500,13 +500,14 @@ session policy lives. unmarked reply into a *dropped* one, because an unappliable marking stops the send. Verify a platform before extending that list. - A genuinely dual-stack `[::]` listener still emits **unmarked** IPv4-mapped - replies, and this is known. It is not fixed by choosing the option per reply, - for the macOS reason above, and it predates wildcard source selection. Leave it - until it is worth its own slice, and do not "fix" it by weakening the rule that - an unappliable marking stops the send. The crate forbids unsafe code; - there is no raw `setsockopt` and no `sendmsg`/`cmsg` machinery. Keep the - target lists identical to the pinned `socket2` version's own gates — check - its source rather than copying another crate's older matrix. + replies on Linux. When reply DSCP/traffic-class marking for IPv4 peers + matters, configure the normal same-port `[::]:PORT` plus `0.0.0.0:PORT` + listener pair instead; `ServerSet` makes the IPv6 half IPv6-only for that + pair. Do not force `IPV6_V6ONLY` on every lone IPv6 listener, and do not + weaken the rule that an unappliable marking stops the send. The crate forbids + unsafe code; there is no raw `setsockopt` and no `sendmsg`/`cmsg` machinery. + Keep the target lists identical to the pinned `socket2` version's own gates + — check its source rather than copying another crate's older matrix. ## Rate, lifetime and server-initiated close diff --git a/crates/irtt-server/src/set.rs b/crates/irtt-server/src/set.rs index 9e7566b..b3efc68 100644 --- a/crates/irtt-server/src/set.rs +++ b/crates/irtt-server/src/set.rs @@ -91,6 +91,14 @@ impl ServerSet { /// An IPv4-mapped address such as `[::ffff:0.0.0.0]` is an IPv4 listener /// here, not an IPv6 one, matching how the runtime already reads it. /// + /// A lone explicit dual-stack `[::]:PORT` listener is not the recommended + /// configuration when reply DSCP/traffic-class marking for IPv4 peers + /// matters: Linux serves those peers as IPv4-mapped and cannot retain the + /// negotiated marking on their replies. Request the normal same-port + /// `[::]:PORT` and `0.0.0.0:PORT` pair instead. This method makes the IPv6 + /// half IPv6-only for that pair only; a lone IPv6 listener retains its + /// normal socket behavior. + /// /// # Errors /// /// Returns [`ServerSetError::NoListeners`] if `addrs` is empty — a set diff --git a/docs/irtt-server.md b/docs/irtt-server.md index 92958e5..f69be58 100644 --- a/docs/irtt-server.md +++ b/docs/irtt-server.md @@ -63,6 +63,15 @@ different ports. With no `--bind` at all, see [Description](#description) above for the default wildcard pair and the address-family fallback it allows. +When reply DSCP/traffic-class marking for IPv4 peers matters, do not configure +one explicit dual-stack `[::]:PORT` listener by itself. On Linux, IPv4 peers +served through that socket are IPv4-mapped and their replies cannot retain the +negotiated marking. Configure the ordinary paired `[::]:PORT` and +`0.0.0.0:PORT` listeners instead; the IPv6 listener is made IPv6-only for that +same-port pair, so each family uses the correct socket option. This is a +configuration workaround, not a reason to force `IPV6_V6ONLY` for every lone +IPv6 listener. + ### `--hmac KEY` HMAC key, taken as the UTF-8 bytes of this argument. With a key configured,