Skip to content

Commit 276c164

Browse files
feat: QUIC Address discovery extension
add frame types transport parameter encoding and decoding - to my best understanding fix typo add some utility functions add initial observed address frames add frame encoding and decoding adjust stats minimal debugging for received observed addr simplify setting extension in transport parameter rework frame structure and send observed addr frames with path challenge ones tweak example to start testing fix encoding, send with handshake clippy fix docs reject observed addr frames when not negotiated replace request_id with seq_no according to new spec replace code point for transport parameter replace code point for frames remove sending observed address frame in handshake in server side treat as probing frame in payload processing ack is already managed by is_ack_eliciting send with path_response as well add frame to retransmits and ignore old frames send observed addr at least once per path fmt reword comment remove trailing whites keep observed address reports per path remove addressed TODO small improvement in readability add retransmission with fresh info retransmit just once fix should send logic add observed addr event surface the info restore trace level of frames some extra logs rename roles and var improve error msg assuming the default as disabled is ok, remove comment use safe arithmetic with varints for the seq_no move transport param code to method instead of From impl fix example, finally remove excesive log add helper fn carry old report into new path generate notification only on changed values downgrade log add sending test add resumption test on the acceptance case add resumption test on the rejection case spelling actual spelling and undo debug change dumb lints some spelling and formatting add retransmission test make a bit more readable update hexas make naming consistent, add test check docs for consistency
1 parent d23e4e4 commit 276c164

File tree

15 files changed

+828
-10
lines changed

15 files changed

+828
-10
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
//! Address discovery types from
2+
//! <https://datatracker.ietf.org/doc/draft-seemann-quic-address-discovery/>
3+
4+
use crate::VarInt;
5+
6+
pub(crate) const TRANSPORT_PARAMETER_CODE: u64 = 0x9f81a176;
7+
8+
/// The role of each participant.
9+
///
10+
/// When enabled, this is reported as a transport parameter.
11+
#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
12+
pub(crate) enum Role {
13+
/// Is able to report observer addresses to other peers, but it's not interested in receiving
14+
/// reports about its own address.
15+
SendOnly,
16+
/// Is interested on reports about its own observed address, but will not report back to other
17+
/// peers.
18+
ReceiveOnly,
19+
/// Will both report and receive reports of observed addresses.
20+
Both,
21+
/// Address discovery is disabled.
22+
#[default]
23+
Disabled,
24+
}
25+
26+
impl TryFrom<VarInt> for Role {
27+
type Error = crate::transport_parameters::Error;
28+
29+
fn try_from(value: VarInt) -> Result<Self, Self::Error> {
30+
match value.0 {
31+
0 => Ok(Self::SendOnly),
32+
1 => Ok(Self::ReceiveOnly),
33+
2 => Ok(Self::Both),
34+
_ => Err(crate::transport_parameters::Error::IllegalValue),
35+
}
36+
}
37+
}
38+
39+
impl Role {
40+
/// Whether address discovery is disabled.
41+
pub(crate) fn is_disabled(&self) -> bool {
42+
matches!(self, Self::Disabled)
43+
}
44+
45+
/// Whether this peer's role allows for address reporting to other peers.
46+
fn is_reporter(&self) -> bool {
47+
matches!(self, Self::SendOnly | Self::Both)
48+
}
49+
50+
/// Whether this peer's role accepts observed address reports.
51+
fn receives_reports(&self) -> bool {
52+
matches!(self, Self::ReceiveOnly | Self::Both)
53+
}
54+
55+
/// Whether this peer should report observed addresses to the other peer.
56+
pub(crate) fn should_report(&self, other: &Self) -> bool {
57+
self.is_reporter() && other.receives_reports()
58+
}
59+
60+
/// Sets whether this peer should provide observed addresses to other peers.
61+
pub(crate) fn send_reports_to_peers(&mut self, provide: bool) {
62+
if provide {
63+
self.enable_sending_reports_to_peers()
64+
} else {
65+
self.disable_sending_reports_to_peers()
66+
}
67+
}
68+
69+
/// Enables sending reports of observed addresses to other peers.
70+
fn enable_sending_reports_to_peers(&mut self) {
71+
match self {
72+
Self::SendOnly => {} // already enabled
73+
Self::ReceiveOnly => *self = Self::Both,
74+
Self::Both => {} // already enabled
75+
Self::Disabled => *self = Self::SendOnly,
76+
}
77+
}
78+
79+
/// Disables sending reports of observed addresses to other peers.
80+
fn disable_sending_reports_to_peers(&mut self) {
81+
match self {
82+
Self::SendOnly => *self = Self::Disabled,
83+
Self::ReceiveOnly => {} // already disabled
84+
Self::Both => *self = Self::ReceiveOnly,
85+
Self::Disabled => {} // already disabled
86+
}
87+
}
88+
89+
/// Sets whether this peer should accept received reports of observed addresses from other
90+
/// peers.
91+
pub(crate) fn receive_reports_from_peers(&mut self, receive: bool) {
92+
if receive {
93+
self.enable_receiving_reports_from_peers()
94+
} else {
95+
self.disable_receiving_reports_from_peers()
96+
}
97+
}
98+
99+
/// Enables receiving reports of observed addresses from other peers.
100+
fn enable_receiving_reports_from_peers(&mut self) {
101+
match self {
102+
Self::SendOnly => *self = Self::Both,
103+
Self::ReceiveOnly => {} // already enabled
104+
Self::Both => {} // already enabled
105+
Self::Disabled => *self = Self::ReceiveOnly,
106+
}
107+
}
108+
109+
/// Disables receiving reports of observed addresses from other peers.
110+
fn disable_receiving_reports_from_peers(&mut self) {
111+
match self {
112+
Self::SendOnly => {} // already disabled
113+
Self::ReceiveOnly => *self = Self::Disabled,
114+
Self::Both => *self = Self::SendOnly,
115+
Self::Disabled => {} // already disabled
116+
}
117+
}
118+
119+
/// Gives the [`VarInt`] representing this [`Role`] as a transport parameter.
120+
pub(crate) fn as_transport_parameter(&self) -> Option<VarInt> {
121+
match self {
122+
Self::SendOnly => Some(VarInt(0)),
123+
Self::ReceiveOnly => Some(VarInt(1)),
124+
Self::Both => Some(VarInt(2)),
125+
Self::Disabled => None,
126+
}
127+
}
128+
}

quinn-proto/src/config.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use thiserror::Error;
1414
#[cfg(any(feature = "rustls-aws-lc-rs", feature = "rustls-ring"))]
1515
use crate::crypto::rustls::{configured_provider, QuicServerConfig};
1616
use crate::{
17+
address_discovery,
1718
cid_generator::{ConnectionIdGenerator, HashedConnectionIdGenerator},
1819
congestion,
1920
crypto::{self, HandshakeTokenKey, HmacKey},
@@ -63,6 +64,8 @@ pub struct TransportConfig {
6364
pub(crate) congestion_controller_factory: Arc<dyn congestion::ControllerFactory + Send + Sync>,
6465

6566
pub(crate) enable_segmentation_offload: bool,
67+
68+
pub(crate) address_discovery_role: crate::address_discovery::Role,
6669
}
6770

6871
impl TransportConfig {
@@ -334,6 +337,27 @@ impl TransportConfig {
334337
self.enable_segmentation_offload = enabled;
335338
self
336339
}
340+
341+
/// Whether to send observed address reports to peers.
342+
///
343+
/// This will aid peers in inferring their reachable address, which in most NATd networks
344+
/// will not be easily available to them.
345+
pub fn send_observed_address_reports(&mut self, enabled: bool) -> &mut Self {
346+
self.address_discovery_role.send_reports_to_peers(enabled);
347+
self
348+
}
349+
350+
/// Whether to receive observed address reports from other peers.
351+
///
352+
/// Peers with the address discovery extension enabled that are willing to provide observed
353+
/// address reports will do so if this transport parameter is set. In general, observed address
354+
/// reports cannot be trusted. This, however, can aid the current endpoint in inferring its
355+
/// reachable address, which in most NATd networks will not be easily available.
356+
pub fn receive_observed_address_reports(&mut self, enabled: bool) -> &mut Self {
357+
self.address_discovery_role
358+
.receive_reports_from_peers(enabled);
359+
self
360+
}
337361
}
338362

339363
impl Default for TransportConfig {
@@ -374,6 +398,8 @@ impl Default for TransportConfig {
374398
congestion_controller_factory: Arc::new(congestion::CubicConfig::default()),
375399

376400
enable_segmentation_offload: true,
401+
402+
address_discovery_role: address_discovery::Role::default(),
377403
}
378404
}
379405
}
@@ -405,6 +431,7 @@ impl fmt::Debug for TransportConfig {
405431
deterministic_packet_numbers: _,
406432
congestion_controller_factory: _,
407433
enable_segmentation_offload,
434+
address_discovery_role,
408435
} = self;
409436
fmt.debug_struct("TransportConfig")
410437
.field("max_concurrent_bidi_streams", max_concurrent_bidi_streams)
@@ -432,6 +459,7 @@ impl fmt::Debug for TransportConfig {
432459
.field("datagram_send_buffer_size", datagram_send_buffer_size)
433460
.field("congestion_controller_factory", &"[ opaque ]")
434461
.field("enable_segmentation_offload", enable_segmentation_offload)
462+
.field("address_discovery_role", address_discovery_role)
435463
.finish()
436464
}
437465
}

0 commit comments

Comments
 (0)