From 29e650be1e0d7b5a42cb20b30fa3cfe5822bf030 Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Thu, 18 Jan 2024 17:56:12 +0200 Subject: [PATCH] Add TOS and TTL information to Datagrams This part of the refactor of #1495. This doesn't include any ECN I/O or other logic, just adds the required fields to the datagram header. --- neqo-client/src/main.rs | 4 +- neqo-common/Cargo.toml | 1 + neqo-common/src/datagram.rs | 94 ++++++++++++++++++- neqo-common/src/lib.rs | 2 +- neqo-interop/src/main.rs | 12 ++- neqo-server/src/main.rs | 2 +- neqo-transport/src/connection/mod.rs | 2 +- neqo-transport/src/connection/tests/close.rs | 5 +- .../src/connection/tests/handshake.rs | 12 ++- .../src/connection/tests/migration.rs | 4 +- neqo-transport/src/connection/tests/vn.rs | 30 +++--- neqo-transport/src/path.rs | 10 +- neqo-transport/src/server.rs | 4 +- neqo-transport/tests/conn_vectors.rs | 5 +- neqo-transport/tests/connection.rs | 6 ++ neqo-transport/tests/retry.rs | 38 ++++++-- neqo-transport/tests/server.rs | 32 +++++-- test-fixture/src/lib.rs | 12 ++- 18 files changed, 215 insertions(+), 60 deletions(-) diff --git a/neqo-client/src/main.rs b/neqo-client/src/main.rs index e204b179cc..8c0f6afd92 100644 --- a/neqo-client/src/main.rs +++ b/neqo-client/src/main.rs @@ -430,7 +430,7 @@ fn process_loop( break 'read; } if sz > 0 { - let d = Datagram::new(remote, *local_addr, &buf[..sz]); + let d = Datagram::new(remote, *local_addr, None, None, &buf[..sz]); datagrams.push(d); } } @@ -1365,7 +1365,7 @@ mod old { break 'read; } if sz > 0 { - let d = Datagram::new(remote, *local_addr, &buf[..sz]); + let d = Datagram::new(remote, *local_addr, None, None, &buf[..sz]); client.process_input(&d, Instant::now()); handler.maybe_key_update(client)?; } diff --git a/neqo-common/Cargo.toml b/neqo-common/Cargo.toml index ca209328e5..584f3100d4 100644 --- a/neqo-common/Cargo.toml +++ b/neqo-common/Cargo.toml @@ -9,6 +9,7 @@ build = "build.rs" [dependencies] log = { version = "0.4.0", default-features = false } +enum-map = "~2.7.3" env_logger = { version = "0.10", default-features = false } lazy_static = "1.3.0" qlog = "0.11.0" diff --git a/neqo-common/src/datagram.rs b/neqo-common/src/datagram.rs index 0316dd2309..2731c666bb 100644 --- a/neqo-common/src/datagram.rs +++ b/neqo-common/src/datagram.rs @@ -7,20 +7,97 @@ use std::net::SocketAddr; use std::ops::Deref; +use enum_map::Enum; + use crate::hex_with_len; +// ECN (Explicit Congestion Notification) codepoints mapped to the +// lower 2 bits of the TOS field. +// https://www.iana.org/assignments/dscp-registry/dscp-registry.xhtml +#[derive(Copy, Clone, PartialEq, Eq, Enum)] +#[repr(u8)] +pub enum IpTosEcn { + NotEct = 0b00, // Not-ECT (Not ECN-Capable Transport) [RFC3168] + Ect1 = 0b01, // ECT(1) (ECN-Capable Transport(1))[1] [RFC8311][RFC Errata 5399][RFC9331] + Ect0 = 0b10, // ECT(0) (ECN-Capable Transport(0)) [RFC3168] + Ce = 0b11, // CE (Congestion Experienced) [RFC3168] +} + +impl From for IpTosEcn { + fn from(v: u8) -> Self { + match v & 0b11 { + 0b00 => IpTosEcn::NotEct, + 0b01 => IpTosEcn::Ect1, + 0b10 => IpTosEcn::Ect0, + 0b11 => IpTosEcn::Ce, + _ => unreachable!(), + } + } +} + +impl From for u8 { + fn from(val: IpTosEcn) -> Self { + val as u8 + } +} + +impl std::fmt::Debug for IpTosEcn { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + IpTosEcn::NotEct => f.write_str("Not-ECT"), + IpTosEcn::Ect1 => f.write_str("ECT(1)"), + IpTosEcn::Ect0 => f.write_str("ECT(0)"), + IpTosEcn::Ce => f.write_str("CE"), + } + } +} + +// DiffServ Codepoints, mapped to the upper six bits of the TOS field. +// https://www.iana.org/assignments/dscp-registry/dscp-registry.xhtml +#[derive(Copy, Clone, PartialEq, Eq)] +#[repr(u8)] +pub enum IpTosDscp { + Cs0 = 0b0000_0000, // [RFC2474] + Cs1 = 0b0010_0000, // [RFC2474] + Cs2 = 0b0100_0000, // [RFC2474] + Cs3 = 0b0110_0000, // [RFC2474] + Cs4 = 0b1000_0000, // [RFC2474] + Cs5 = 0b1010_0000, // [RFC2474] + Cs6 = 0b1100_0000, // [RFC2474] + Cs7 = 0b1110_0000, // [RFC2474] + Af11 = 0b0010_1000, // [RFC2597] + Af12 = 0b0011_0000, // [RFC2597] + Af13 = 0b0011_1000, // [RFC2597] + Af21 = 0b0100_1000, // [RFC2597] + Af22 = 0b0101_0000, // [RFC2597] + Af23 = 0b0101_1000, // [RFC2597] + Af31 = 0b0110_1000, // [RFC2597] + Af32 = 0b0111_0000, // [RFC2597] + Af33 = 0b0111_1000, // [RFC2597] + Af41 = 0b1000_1000, // [RFC2597] + Af42 = 0b1001_0000, // [RFC2597] + Af43 = 0b1001_1000, // [RFC2597] + Ef = 0b1011_1000, // [RFC3246] + VoiceAdmit = 0b1011_0000, // [RFC5865] + Le = 0b0000_0100, // [RFC8622] +} + #[derive(PartialEq, Eq, Clone)] pub struct Datagram { src: SocketAddr, dst: SocketAddr, + tos: Option, + ttl: Option, d: Vec, } impl Datagram { - pub fn new>>(src: SocketAddr, dst: SocketAddr, d: V) -> Self { + pub fn new>>(src: SocketAddr, dst: SocketAddr, tos: Option, ttl: Option, d: V) -> Self { Self { src, dst, + tos, + ttl, d: d.into(), } } @@ -34,7 +111,16 @@ impl Datagram { pub fn destination(&self) -> SocketAddr { self.dst } -} + + #[must_use] + pub fn tos(&self) -> Option { + self.tos + } + + #[must_use] + pub fn ttl(&self) -> Option { + self.ttl + }} impl Deref for Datagram { type Target = Vec; @@ -48,7 +134,9 @@ impl std::fmt::Debug for Datagram { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!( f, - "Datagram {:?}->{:?}: {}", + "Datagram TOS {:?} TTL {:?} {:?}->{:?}: {}", + self.tos, + self.ttl, self.src, self.dst, hex_with_len(&self.d) diff --git a/neqo-common/src/lib.rs b/neqo-common/src/lib.rs index 3fb0fd27ec..dc32e3e37f 100644 --- a/neqo-common/src/lib.rs +++ b/neqo-common/src/lib.rs @@ -18,7 +18,7 @@ pub mod qlog; pub mod timer; pub use self::codec::{Decoder, Encoder}; -pub use self::datagram::Datagram; +pub use self::datagram::{IpTosDscp, IpTosEcn, Datagram}; pub use self::header::Header; pub use self::incrdecoder::{ IncrementalDecoderBuffer, IncrementalDecoderIgnore, IncrementalDecoderUint, diff --git a/neqo-interop/src/main.rs b/neqo-interop/src/main.rs index c274c57d0f..a684a6d284 100644 --- a/neqo-interop/src/main.rs +++ b/neqo-interop/src/main.rs @@ -148,7 +148,7 @@ fn process_loop( continue; } if sz > 0 { - let received = Datagram::new(nctx.remote_addr, nctx.local_addr, &buf[..sz]); + let received = Datagram::new(nctx.remote_addr, nctx.local_addr, None, None, &buf[..sz]); client.process_input(&received, Instant::now()); } } @@ -309,7 +309,7 @@ fn process_loop_h3( continue; } if sz > 0 { - let received = Datagram::new(nctx.remote_addr, nctx.local_addr, &buf[..sz]); + let received = Datagram::new(nctx.remote_addr, nctx.local_addr, None, None, &buf[..sz]); handler.h3.process_input(&received, Instant::now()); } } @@ -682,7 +682,13 @@ impl Handler for VnHandler { fn rewrite_out(&mut self, d: &Datagram) -> Option { let mut payload = d[..].to_vec(); payload[1] = 0x1a; - Some(Datagram::new(d.source(), d.destination(), payload)) + Some(Datagram::new( + d.source(), + d.destination(), + d.tos(), + d.ttl(), + payload, + )) } } diff --git a/neqo-server/src/main.rs b/neqo-server/src/main.rs index ac4c952837..be375df3bc 100644 --- a/neqo-server/src/main.rs +++ b/neqo-server/src/main.rs @@ -606,7 +606,7 @@ fn read_dgram( eprintln!("zero length datagram received?"); Ok(None) } else { - Ok(Some(Datagram::new(remote_addr, *local_address, &buf[..sz]))) + Ok(Some(Datagram::new(remote_addr, *local_address, None, None, &buf[..sz]))) } } diff --git a/neqo-transport/src/connection/mod.rs b/neqo-transport/src/connection/mod.rs index e8d10387e3..ee77fc5737 100644 --- a/neqo-transport/src/connection/mod.rs +++ b/neqo-transport/src/connection/mod.rs @@ -1149,7 +1149,7 @@ impl Connection { /// part that we don't have keys for. fn save_datagram(&mut self, cspace: CryptoSpace, d: &Datagram, remaining: usize, now: Instant) { let d = if remaining < d.len() { - Datagram::new(d.source(), d.destination(), &d[d.len() - remaining..]) + Datagram::new(d.source(), d.destination(), d.tos(), d.ttl(), &d[d.len() - remaining..]) } else { d.clone() }; diff --git a/neqo-transport/src/connection/tests/close.rs b/neqo-transport/src/connection/tests/close.rs index 6efbb6e24f..39b1106ce0 100644 --- a/neqo-transport/src/connection/tests/close.rs +++ b/neqo-transport/src/connection/tests/close.rs @@ -9,9 +9,8 @@ use super::{connect, connect_force_idle, default_client, default_server, send_so use crate::tparams::{self, TransportParameter}; use crate::{AppError, ConnectionError, Error, ERROR_APPLICATION_CLOSE}; -use neqo_common::Datagram; use std::time::Duration; -use test_fixture::{self, addr, now}; +use test_fixture::{self, datagram, now}; fn assert_draining(c: &Connection, expected: &Error) { assert!(c.state().closed()); @@ -201,6 +200,6 @@ fn stateless_reset_client() { .unwrap(); connect_force_idle(&mut client, &mut server); - client.process_input(&Datagram::new(addr(), addr(), vec![77; 21]), now()); + client.process_input(&datagram(vec![77; 21]), now()); assert_draining(&client, &Error::StatelessReset); } diff --git a/neqo-transport/src/connection/tests/handshake.rs b/neqo-transport/src/connection/tests/handshake.rs index 602611d34f..55cd10b667 100644 --- a/neqo-transport/src/connection/tests/handshake.rs +++ b/neqo-transport/src/connection/tests/handshake.rs @@ -30,7 +30,7 @@ use std::mem; use std::net::{IpAddr, Ipv6Addr, SocketAddr}; use std::rc::Rc; use std::time::Duration; -use test_fixture::{self, addr, assertions, fixture_init, now, split_datagram}; +use test_fixture::{self, addr, assertions, datagram, fixture_init, now, split_datagram}; const ECH_CONFIG_ID: u8 = 7; const ECH_PUBLIC_NAME: &str = "public.example"; @@ -615,7 +615,7 @@ fn corrupted_initial() { .find(|(_, &v)| v != 0) .unwrap(); corrupted[idx] ^= 0x76; - let dgram = Datagram::new(d.source(), d.destination(), corrupted); + let dgram = Datagram::new(d.source(), d.destination(), d.tos(), d.ttl(), corrupted); server.process_input(&dgram, now()); // The server should have received two packets, // the first should be dropped, the second saved. @@ -711,7 +711,7 @@ fn extra_initial_invalid_cid() { let mut copy = hs.to_vec(); assert_ne!(copy[5], 0); // The DCID should be non-zero length. copy[6] ^= 0xc4; - let dgram_copy = Datagram::new(hs.destination(), hs.source(), copy); + let dgram_copy = Datagram::new(hs.destination(), hs.source(), hs.tos(), hs.ttl(), copy); let nothing = client.process(Some(&dgram_copy), now).dgram(); assert!(nothing.is_none()); } @@ -814,7 +814,7 @@ fn garbage_initial() { let mut corrupted = Vec::from(&initial[..initial.len() - 1]); corrupted.push(initial[initial.len() - 1] ^ 0xb7); corrupted.extend_from_slice(rest.as_ref().map_or(&[], |r| &r[..])); - let garbage = Datagram::new(addr(), addr(), corrupted); + let garbage = datagram(corrupted); assert_eq!(Output::None, server.process(Some(&garbage), now())); } @@ -832,6 +832,8 @@ fn drop_initial_packet_from_wrong_address() { let dgram = Datagram::new( SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 2)), 443), p.destination(), + p.tos(), + p.ttl(), &p[..], ); @@ -858,6 +860,8 @@ fn drop_handshake_packet_from_wrong_address() { let dgram = Datagram::new( SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 2)), 443), p.destination(), + p.tos(), + p.ttl(), &p[..], ); diff --git a/neqo-transport/src/connection/tests/migration.rs b/neqo-transport/src/connection/tests/migration.rs index b7e5392903..1df8dff7bf 100644 --- a/neqo-transport/src/connection/tests/migration.rs +++ b/neqo-transport/src/connection/tests/migration.rs @@ -52,7 +52,7 @@ fn loopback() -> SocketAddr { } fn change_path(d: &Datagram, a: SocketAddr) -> Datagram { - Datagram::new(a, a, &d[..]) + Datagram::new(a, a, d.tos(), d.ttl(), &d[..]) } fn new_port(a: SocketAddr) -> SocketAddr { @@ -61,7 +61,7 @@ fn new_port(a: SocketAddr) -> SocketAddr { } fn change_source_port(d: &Datagram) -> Datagram { - Datagram::new(new_port(d.source()), d.destination(), &d[..]) + Datagram::new(new_port(d.source()), d.destination(), d.tos(), d.ttl(), &d[..]) } /// As these tests use a new path, that path often has a non-zero RTT. diff --git a/neqo-transport/src/connection/tests/vn.rs b/neqo-transport/src/connection/tests/vn.rs index 4c00253642..e289bc654c 100644 --- a/neqo-transport/src/connection/tests/vn.rs +++ b/neqo-transport/src/connection/tests/vn.rs @@ -13,10 +13,10 @@ use crate::packet::PACKET_BIT_LONG; use crate::tparams::{self, TransportParameter}; use crate::{ConnectionParameters, Error, Version}; -use neqo_common::{event::Provider, Datagram, Decoder, Encoder}; +use neqo_common::{event::Provider, Decoder, Encoder}; use std::mem; use std::time::Duration; -use test_fixture::{self, addr, assertions, now}; +use test_fixture::{self, assertions, datagram, now}; // The expected PTO duration after the first Initial is sent. const INITIAL_PTO: Duration = Duration::from_millis(300); @@ -29,10 +29,7 @@ fn unknown_version() { let mut unknown_version_packet = vec![0x80, 0x1a, 0x1a, 0x1a, 0x1a]; unknown_version_packet.resize(1200, 0x0); - mem::drop(client.process( - Some(&Datagram::new(addr(), addr(), unknown_version_packet)), - now(), - )); + mem::drop(client.process(Some(&datagram(unknown_version_packet)), now())); assert_eq!(1, client.stats().dropped_rx); } @@ -44,10 +41,7 @@ fn server_receive_unknown_first_packet() { unknown_version_packet.resize(1200, 0x0); assert_eq!( - server.process( - Some(&Datagram::new(addr(), addr(), unknown_version_packet,)), - now(), - ), + server.process(Some(&datagram(unknown_version_packet,)), now(),), Output::None ); @@ -86,7 +80,7 @@ fn version_negotiation_current_version() { &[0x1a1a_1a1a, Version::default().wire_version()], ); - let dgram = Datagram::new(addr(), addr(), vn); + let dgram = datagram(vn); let delay = client.process(Some(&dgram), now()).callback(); assert_eq!(delay, INITIAL_PTO); assert_eq!(*client.state(), State::WaitInitial); @@ -105,7 +99,7 @@ fn version_negotiation_version0() { let vn = create_vn(&initial_pkt, &[0, 0x1a1a_1a1a]); - let dgram = Datagram::new(addr(), addr(), vn); + let dgram = datagram(vn); let delay = client.process(Some(&dgram), now()).callback(); assert_eq!(delay, INITIAL_PTO); assert_eq!(*client.state(), State::WaitInitial); @@ -124,7 +118,7 @@ fn version_negotiation_only_reserved() { let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a]); - let dgram = Datagram::new(addr(), addr(), vn); + let dgram = datagram(vn); assert_eq!(client.process(Some(&dgram), now()), Output::None); match client.state() { State::Closed(err) => { @@ -146,7 +140,7 @@ fn version_negotiation_corrupted() { let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a]); - let dgram = Datagram::new(addr(), addr(), &vn[..vn.len() - 1]); + let dgram = datagram(vn[..vn.len() - 1].to_vec()); let delay = client.process(Some(&dgram), now()).callback(); assert_eq!(delay, INITIAL_PTO); assert_eq!(*client.state(), State::WaitInitial); @@ -165,7 +159,7 @@ fn version_negotiation_empty() { let vn = create_vn(&initial_pkt, &[]); - let dgram = Datagram::new(addr(), addr(), vn); + let dgram = datagram(vn); let delay = client.process(Some(&dgram), now()).callback(); assert_eq!(delay, INITIAL_PTO); assert_eq!(*client.state(), State::WaitInitial); @@ -183,7 +177,7 @@ fn version_negotiation_not_supported() { .to_vec(); let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a, 0xff00_0001]); - let dgram = Datagram::new(addr(), addr(), vn); + let dgram = datagram(vn); assert_eq!(client.process(Some(&dgram), now()), Output::None); match client.state() { State::Closed(err) => { @@ -206,7 +200,7 @@ fn version_negotiation_bad_cid() { initial_pkt[6] ^= 0xc4; let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a, 0xff00_0001]); - let dgram = Datagram::new(addr(), addr(), vn); + let dgram = datagram(vn); let delay = client.process(Some(&dgram), now()).callback(); assert_eq!(delay, INITIAL_PTO); assert_eq!(*client.state(), State::WaitInitial); @@ -311,7 +305,7 @@ fn version_negotiation_downgrade() { // Start the handshake and spoof a VN packet. let initial = client.process_output(now()).dgram().unwrap(); let vn = create_vn(&initial, &[DOWNGRADE.wire_version()]); - let dgram = Datagram::new(addr(), addr(), vn); + let dgram = datagram(vn); client.process_input(&dgram, now()); connect_fail( diff --git a/neqo-transport/src/path.rs b/neqo-transport/src/path.rs index 40014c73a1..ca6a17425c 100644 --- a/neqo-transport/src/path.rs +++ b/neqo-transport/src/path.rs @@ -31,7 +31,7 @@ use crate::{ Error, Res, }; -use neqo_common::{hex, qdebug, qinfo, qlog::NeqoQlog, qtrace, Datagram, Encoder}; +use neqo_common::{hex, qdebug, qinfo, qlog::NeqoQlog, qtrace, Datagram, Encoder, IpTosEcn}; use neqo_crypto::random; /// This is the MTU that we assume when using IPv6. @@ -539,6 +539,10 @@ pub struct Path { rtt: RttEstimate, /// A packet sender for the path, which includes congestion control and a pacer. sender: PacketSender, + /// The DSCP/ECN marking to use for outgoing packets on this path. + tos: IpTosEcn, + /// The IP TTL to use for outgoing packets on this path. + ttl: u8, /// The number of bytes received on this path. /// Note that this value might saturate on a long-lived connection, @@ -575,6 +579,8 @@ impl Path { challenge: None, rtt: RttEstimate::default(), sender, + tos: IpTosEcn::NotEct, // TODO: Default to Ect0 when ECN is supported. + ttl: 64, // This is the default TTL on many OSes. received_bytes: 0, sent_bytes: 0, qlog, @@ -697,7 +703,7 @@ impl Path { /// Make a datagram. pub fn datagram>>(&self, payload: V) -> Datagram { - Datagram::new(self.local, self.remote, payload) + Datagram::new(self.local, self.remote, Some(self.tos.into()), Some(self.ttl), payload) } /// Get local address as `SocketAddr` diff --git a/neqo-transport/src/server.rs b/neqo-transport/src/server.rs index a15e1fc1f8..93e4026792 100644 --- a/neqo-transport/src/server.rs +++ b/neqo-transport/src/server.rs @@ -349,7 +349,7 @@ impl Server { &initial.dst_cid, ); if let Ok(p) = packet { - let retry = Datagram::new(dgram.destination(), dgram.source(), p); + let retry = Datagram::new(dgram.destination(), dgram.source(), dgram.tos(), dgram.ttl(), p); Some(retry) } else { qerror!([self], "unable to encode retry, dropping packet"); @@ -594,7 +594,7 @@ impl Server { packet.wire_version(), ); - return Some(Datagram::new(dgram.destination(), dgram.source(), vn)); + return Some(Datagram::new(dgram.destination(), dgram.source(), dgram.tos(), dgram.ttl(), vn)); } match packet.packet_type() { diff --git a/neqo-transport/tests/conn_vectors.rs b/neqo-transport/tests/conn_vectors.rs index f088ebea3f..7597c81621 100644 --- a/neqo-transport/tests/conn_vectors.rs +++ b/neqo-transport/tests/conn_vectors.rs @@ -8,11 +8,10 @@ #![deny(clippy::pedantic)] #![cfg(not(feature = "fuzzing"))] -use neqo_common::Datagram; use neqo_transport::{ Connection, ConnectionParameters, RandomConnectionIdGenerator, State, Version, }; -use test_fixture::{self, addr, now}; +use test_fixture::{self, datagram, now}; use std::cell::RefCell; use std::rc::Rc; @@ -265,7 +264,7 @@ fn make_server(v: Version) -> Connection { fn process_client_initial(v: Version, packet: &[u8]) { let mut server = make_server(v); - let dgram = Datagram::new(addr(), addr(), packet); + let dgram = datagram(packet.to_vec()); assert_eq!(*server.state(), State::Init); let out = server.process(Some(&dgram), now()); assert_eq!(*server.state(), State::Handshaking); diff --git a/neqo-transport/tests/connection.rs b/neqo-transport/tests/connection.rs index 13c70590fa..661909fd22 100644 --- a/neqo-transport/tests/connection.rs +++ b/neqo-transport/tests/connection.rs @@ -39,6 +39,8 @@ fn truncate_long_packet() { let truncated = Datagram::new( dupe.source(), dupe.destination(), + dupe.tos(), + dupe.ttl(), &dupe[..(dupe.len() - tail)], ); let hs_probe = client.process(Some(&truncated), now()).dgram(); @@ -108,6 +110,8 @@ fn reorder_server_initial() { let reordered = Datagram::new( server_initial.source(), server_initial.destination(), + server_initial.tos(), + server_initial.ttl(), packet, ); @@ -182,6 +186,8 @@ fn overflow_crypto() { let dgram = Datagram::new( server_initial.source(), server_initial.destination(), + server_initial.tos(), + server_initial.ttl(), packet, ); client.process_input(&dgram, now()); diff --git a/neqo-transport/tests/retry.rs b/neqo-transport/tests/retry.rs index 0b51eacab1..3fffcba3da 100644 --- a/neqo-transport/tests/retry.rs +++ b/neqo-transport/tests/retry.rs @@ -21,7 +21,7 @@ use std::convert::TryFrom; use std::mem; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::time::Duration; -use test_fixture::{self, addr, assertions, default_client, now, split_datagram}; +use test_fixture::{self, assertions, datagram, default_client, now, split_datagram}; #[test] fn retry_basic() { @@ -150,7 +150,13 @@ fn retry_different_ip() { let dgram = dgram.unwrap(); let other_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)); let other_addr = SocketAddr::new(other_v4, 443); - let from_other = Datagram::new(other_addr, dgram.destination(), &dgram[..]); + let from_other = Datagram::new( + other_addr, + dgram.destination(), + dgram.tos(), + dgram.ttl(), + &dgram[..], + ); let dgram = server.process(Some(&from_other), now()).dgram(); assert!(dgram.is_none()); } @@ -171,7 +177,13 @@ fn new_token_different_ip() { // Now rewrite the source address. let d = dgram.unwrap(); let src = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)), d.source().port()); - let dgram = Some(Datagram::new(src, d.destination(), &d[..])); + let dgram = Some(Datagram::new( + src, + d.destination(), + d.tos(), + d.ttl(), + &d[..], + )); let dgram = server.process(dgram.as_ref(), now()).dgram(); // Retry assert!(dgram.is_some()); assertions::assert_retry(dgram.as_ref().unwrap()); @@ -196,7 +208,13 @@ fn new_token_expired() { let the_future = now() + Duration::from_secs(60 * 60 * 24 * 30); let d = dgram.unwrap(); let src = SocketAddr::new(d.source().ip(), d.source().port() + 1); - let dgram = Some(Datagram::new(src, d.destination(), &d[..])); + let dgram = Some(Datagram::new( + src, + d.destination(), + d.tos(), + d.ttl(), + &d[..], + )); let dgram = server.process(dgram.as_ref(), the_future).dgram(); // Retry assert!(dgram.is_some()); assertions::assert_retry(dgram.as_ref().unwrap()); @@ -257,7 +275,13 @@ fn retry_bad_integrity() { let mut tweaked = retry.to_vec(); tweaked[retry.len() - 1] ^= 0x45; // damage the auth tag - let tweaked_packet = Datagram::new(retry.source(), retry.destination(), tweaked); + let tweaked_packet = Datagram::new( + retry.source(), + retry.destination(), + retry.tos(), + retry.ttl(), + tweaked, + ); // The client should ignore this packet. let dgram = client.process(Some(&tweaked_packet), now()).dgram(); @@ -338,7 +362,7 @@ fn vn_after_retry() { encoder.encode_vec(1, &client.odcid().unwrap()[..]); encoder.encode_vec(1, &[]); encoder.encode_uint(4, 0x5a5a_6a6a_u64); - let vn = Datagram::new(addr(), addr(), encoder); + let vn = datagram(encoder.into()); assert_ne!( client.process(Some(&vn), now()).callback(), @@ -425,6 +449,8 @@ fn mitm_retry() { let new_datagram = Datagram::new( client_initial2.source(), client_initial2.destination(), + client_initial2.tos(), + client_initial2.ttl(), notoken_packet, ); qdebug!("passing modified Initial to the main server"); diff --git a/neqo-transport/tests/server.rs b/neqo-transport/tests/server.rs index a4f07def87..2f1ee3b493 100644 --- a/neqo-transport/tests/server.rs +++ b/neqo-transport/tests/server.rs @@ -23,7 +23,7 @@ use neqo_transport::{ Connection, ConnectionError, ConnectionParameters, Error, Output, State, StreamType, Version, }; use test_fixture::{ - self, assertions, default_client, new_client, now, split_datagram, + self, assertions, datagram, default_client, new_client, now, split_datagram, CountingConnectionIdGenerator, }; @@ -157,6 +157,8 @@ fn duplicate_initial_new_path() { let other = Datagram::new( SocketAddr::new(initial.source().ip(), initial.source().port() ^ 23), initial.destination(), + initial.tos(), + initial.ttl(), &initial[..], ); @@ -235,7 +237,7 @@ fn drop_non_initial() { let mut bogus_data: Vec = header.into(); bogus_data.resize(1200, 66); - let bogus = Datagram::new(test_fixture::addr(), test_fixture::addr(), bogus_data); + let bogus = datagram(bogus_data); assert!(server.process(Some(&bogus), now()).dgram().is_none()); } @@ -254,7 +256,7 @@ fn drop_short_initial() { let mut bogus_data: Vec = header.into(); bogus_data.resize(1199, 66); - let bogus = Datagram::new(test_fixture::addr(), test_fixture::addr(), bogus_data); + let bogus = datagram(bogus_data); assert!(server.process(Some(&bogus), now()).dgram().is_none()); } @@ -371,7 +373,13 @@ fn new_token_different_port() { // Now rewrite the source port, which should not change that the token is OK. let d = dgram.unwrap(); let src = SocketAddr::new(d.source().ip(), d.source().port() + 1); - let dgram = Some(Datagram::new(src, d.destination(), &d[..])); + let dgram = Some(Datagram::new( + src, + d.destination(), + d.tos(), + d.ttl(), + &d[..], + )); let dgram = server.process(dgram.as_ref(), now()).dgram(); // Retry assert!(dgram.is_some()); assertions::assert_initial(dgram.as_ref().unwrap(), false); @@ -426,7 +434,13 @@ fn bad_client_initial() { &mut ciphertext, (header_enc.len() - 1)..header_enc.len(), ); - let bad_dgram = Datagram::new(dgram.source(), dgram.destination(), ciphertext); + let bad_dgram = Datagram::new( + dgram.source(), + dgram.destination(), + dgram.tos(), + dgram.ttl(), + ciphertext, + ); // The server should reject this. let response = server.process(Some(&bad_dgram), now()); @@ -474,7 +488,13 @@ fn version_negotiation_ignored() { let dgram = client.process(None, now()).dgram().expect("a datagram"); let mut input = dgram.to_vec(); input[1] ^= 0x12; - let damaged = Datagram::new(dgram.source(), dgram.destination(), input.clone()); + let damaged = Datagram::new( + dgram.source(), + dgram.destination(), + dgram.tos(), + dgram.ttl(), + input.clone(), + ); let vn = server.process(Some(&damaged), now()).dgram(); let mut dec = Decoder::from(&input[5..]); // Skip past version. diff --git a/test-fixture/src/lib.rs b/test-fixture/src/lib.rs index fa9276bf5c..4989c10b1a 100644 --- a/test-fixture/src/lib.rs +++ b/test-fixture/src/lib.rs @@ -11,7 +11,7 @@ use neqo_common::{ event::Provider, hex, qlog::{new_trace, NeqoQlog}, - qtrace, Datagram, Decoder, Role, + qtrace, Datagram, Decoder, IpTosEcn, Role, }; use neqo_crypto::{init_db, random, AllowZeroRtt, AntiReplay, AuthenticationStatus}; @@ -85,6 +85,12 @@ pub const LONG_CERT_KEYS: &[&str] = &["A long cert"]; pub const DEFAULT_ALPN: &[&str] = &["alpn"]; pub const DEFAULT_ALPN_H3: &[&str] = &["h3"]; +// Create a default datagram with the given data. +#[must_use] +pub fn datagram(data: Vec) -> Datagram { + Datagram::new(addr(), addr(), Some(IpTosEcn::Ect0.into()), Some(128), data) +} + /// Create a default socket address. #[must_use] pub fn addr() -> SocketAddr { @@ -332,8 +338,8 @@ fn split_packet(buf: &[u8]) -> (&[u8], Option<&[u8]>) { pub fn split_datagram(d: &Datagram) -> (Datagram, Option) { let (a, b) = split_packet(&d[..]); ( - Datagram::new(d.source(), d.destination(), a), - b.map(|b| Datagram::new(d.source(), d.destination(), b)), + Datagram::new(d.source(), d.destination(), d.tos(), d.ttl(), a), + b.map(|b| Datagram::new(d.source(), d.destination(), d.tos(), d.ttl(), b)), ) }