Skip to content

Commit

Permalink
feat: QUIC Address discovery extension
Browse files Browse the repository at this point in the history
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
  • Loading branch information
divagant-martian committed Nov 14, 2024
1 parent d23e4e4 commit 276c164
Show file tree
Hide file tree
Showing 15 changed files with 828 additions and 10 deletions.
128 changes: 128 additions & 0 deletions quinn-proto/src/address_discovery.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
//! Address discovery types from
//! <https://datatracker.ietf.org/doc/draft-seemann-quic-address-discovery/>

use crate::VarInt;

pub(crate) const TRANSPORT_PARAMETER_CODE: u64 = 0x9f81a176;

/// The role of each participant.
///
/// When enabled, this is reported as a transport parameter.
#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
pub(crate) enum Role {
/// Is able to report observer addresses to other peers, but it's not interested in receiving
/// reports about its own address.
SendOnly,
/// Is interested on reports about its own observed address, but will not report back to other
/// peers.
ReceiveOnly,
/// Will both report and receive reports of observed addresses.
Both,
/// Address discovery is disabled.
#[default]
Disabled,
}

impl TryFrom<VarInt> for Role {
type Error = crate::transport_parameters::Error;

fn try_from(value: VarInt) -> Result<Self, Self::Error> {
match value.0 {
0 => Ok(Self::SendOnly),
1 => Ok(Self::ReceiveOnly),
2 => Ok(Self::Both),
_ => Err(crate::transport_parameters::Error::IllegalValue),
}
}
}

impl Role {
/// Whether address discovery is disabled.
pub(crate) fn is_disabled(&self) -> bool {
matches!(self, Self::Disabled)
}

/// Whether this peer's role allows for address reporting to other peers.
fn is_reporter(&self) -> bool {
matches!(self, Self::SendOnly | Self::Both)
}

/// Whether this peer's role accepts observed address reports.
fn receives_reports(&self) -> bool {
matches!(self, Self::ReceiveOnly | Self::Both)
}

/// Whether this peer should report observed addresses to the other peer.
pub(crate) fn should_report(&self, other: &Self) -> bool {
self.is_reporter() && other.receives_reports()
}

/// Sets whether this peer should provide observed addresses to other peers.
pub(crate) fn send_reports_to_peers(&mut self, provide: bool) {
if provide {
self.enable_sending_reports_to_peers()
} else {
self.disable_sending_reports_to_peers()
}
}

/// Enables sending reports of observed addresses to other peers.
fn enable_sending_reports_to_peers(&mut self) {
match self {
Self::SendOnly => {} // already enabled
Self::ReceiveOnly => *self = Self::Both,
Self::Both => {} // already enabled
Self::Disabled => *self = Self::SendOnly,
}
}

/// Disables sending reports of observed addresses to other peers.
fn disable_sending_reports_to_peers(&mut self) {
match self {
Self::SendOnly => *self = Self::Disabled,
Self::ReceiveOnly => {} // already disabled
Self::Both => *self = Self::ReceiveOnly,
Self::Disabled => {} // already disabled
}
}

/// Sets whether this peer should accept received reports of observed addresses from other
/// peers.
pub(crate) fn receive_reports_from_peers(&mut self, receive: bool) {
if receive {
self.enable_receiving_reports_from_peers()
} else {
self.disable_receiving_reports_from_peers()
}
}

/// Enables receiving reports of observed addresses from other peers.
fn enable_receiving_reports_from_peers(&mut self) {
match self {
Self::SendOnly => *self = Self::Both,
Self::ReceiveOnly => {} // already enabled
Self::Both => {} // already enabled
Self::Disabled => *self = Self::ReceiveOnly,
}
}

/// Disables receiving reports of observed addresses from other peers.
fn disable_receiving_reports_from_peers(&mut self) {
match self {
Self::SendOnly => {} // already disabled
Self::ReceiveOnly => *self = Self::Disabled,
Self::Both => *self = Self::SendOnly,
Self::Disabled => {} // already disabled
}
}

/// Gives the [`VarInt`] representing this [`Role`] as a transport parameter.
pub(crate) fn as_transport_parameter(&self) -> Option<VarInt> {
match self {
Self::SendOnly => Some(VarInt(0)),
Self::ReceiveOnly => Some(VarInt(1)),
Self::Both => Some(VarInt(2)),
Self::Disabled => None,
}
}
}
28 changes: 28 additions & 0 deletions quinn-proto/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use thiserror::Error;
#[cfg(any(feature = "rustls-aws-lc-rs", feature = "rustls-ring"))]
use crate::crypto::rustls::{configured_provider, QuicServerConfig};
use crate::{
address_discovery,
cid_generator::{ConnectionIdGenerator, HashedConnectionIdGenerator},
congestion,
crypto::{self, HandshakeTokenKey, HmacKey},
Expand Down Expand Up @@ -63,6 +64,8 @@ pub struct TransportConfig {
pub(crate) congestion_controller_factory: Arc<dyn congestion::ControllerFactory + Send + Sync>,

pub(crate) enable_segmentation_offload: bool,

pub(crate) address_discovery_role: crate::address_discovery::Role,
}

impl TransportConfig {
Expand Down Expand Up @@ -334,6 +337,27 @@ impl TransportConfig {
self.enable_segmentation_offload = enabled;
self
}

/// Whether to send observed address reports to peers.
///
/// This will aid peers in inferring their reachable address, which in most NATd networks
/// will not be easily available to them.
pub fn send_observed_address_reports(&mut self, enabled: bool) -> &mut Self {
self.address_discovery_role.send_reports_to_peers(enabled);
self
}

/// Whether to receive observed address reports from other peers.
///
/// Peers with the address discovery extension enabled that are willing to provide observed
/// address reports will do so if this transport parameter is set. In general, observed address
/// reports cannot be trusted. This, however, can aid the current endpoint in inferring its
/// reachable address, which in most NATd networks will not be easily available.
pub fn receive_observed_address_reports(&mut self, enabled: bool) -> &mut Self {
self.address_discovery_role
.receive_reports_from_peers(enabled);
self
}
}

impl Default for TransportConfig {
Expand Down Expand Up @@ -374,6 +398,8 @@ impl Default for TransportConfig {
congestion_controller_factory: Arc::new(congestion::CubicConfig::default()),

enable_segmentation_offload: true,

address_discovery_role: address_discovery::Role::default(),
}
}
}
Expand Down Expand Up @@ -405,6 +431,7 @@ impl fmt::Debug for TransportConfig {
deterministic_packet_numbers: _,
congestion_controller_factory: _,
enable_segmentation_offload,
address_discovery_role,
} = self;
fmt.debug_struct("TransportConfig")
.field("max_concurrent_bidi_streams", max_concurrent_bidi_streams)
Expand Down Expand Up @@ -432,6 +459,7 @@ impl fmt::Debug for TransportConfig {
.field("datagram_send_buffer_size", datagram_send_buffer_size)
.field("congestion_controller_factory", &"[ opaque ]")
.field("enable_segmentation_offload", enable_segmentation_offload)
.field("address_discovery_role", address_discovery_role)
.finish()
}
}
Expand Down
Loading

0 comments on commit 276c164

Please sign in to comment.