Skip to content

Commit f70563e

Browse files
authored
feat(s2n-quic-dc): Add application_data to stream API for peer identity extraction (#3083)
1 parent ce1da94 commit f70563e

11 files changed

Lines changed: 152 additions & 9 deletions

File tree

dc/s2n-quic-dc/src/path/secret/map.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,15 +177,20 @@ impl Map {
177177
queue_id: Option<VarInt>,
178178
features: &TransportFeatures,
179179
control_out: &mut Vec<u8>,
180-
) -> Option<(entry::Bidirectional, dc::ApplicationParams)> {
180+
) -> Option<(
181+
entry::Bidirectional,
182+
dc::ApplicationParams,
183+
Option<entry::ApplicationData>,
184+
)> {
181185
let entry = self
182186
.store
183187
.pre_authentication(credentials, queue_id, control_out)?;
184188

185189
let params = entry.parameters();
186190
let keys = entry.bidi_remote(self.clone(), credentials, queue_id, features);
187191

188-
Some((keys, params))
192+
let application_data = entry.application_data().clone();
193+
Some((keys, params, application_data))
189194
}
190195

191196
pub fn secret_for_credentials(

dc/s2n-quic-dc/src/stream/application.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use crate::{
55
credentials::Id,
66
event::{self, EndpointPublisher as _},
7+
path::secret::map::ApplicationData,
78
stream::{
89
recv::application::{self as recv, Reader},
910
send::application::{self as send, Writer},
@@ -177,6 +178,12 @@ where
177178
self.read.path_secret_id()
178179
}
179180

181+
/// Returns the application data associated with the path secret, if available.
182+
#[inline]
183+
pub fn path_application_data(&self) -> Option<&ApplicationData> {
184+
self.read.path_application_data()
185+
}
186+
180187
/// Returns the validated peer certificate chain, if available.
181188
///
182189
/// Currently this is only available for TLS streams, but in the future it may be opt-in

dc/s2n-quic-dc/src/stream/endpoint.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use crate::{
55
event::{self, api::Subscriber as _, IntoEvent as _},
66
packet,
7-
path::secret::{self, map, Map},
7+
path::secret::{self, map, map::ApplicationData, Map},
88
random::Random,
99
stream::{
1010
self, application,
@@ -75,6 +75,7 @@ where
7575
endpoint::Type::Client,
7676
subscriber,
7777
subscriber_ctx,
78+
None,
7879
)
7980
}
8081

@@ -84,10 +85,17 @@ pub fn derive_stream_credentials(
8485
map: &Map,
8586
features: &stream::TransportFeatures,
8687
secret_control: &mut Vec<u8>,
87-
) -> Result<(secret::map::Bidirectional, dc::ApplicationParams), io::Error> {
88+
) -> Result<
89+
(
90+
secret::map::Bidirectional,
91+
dc::ApplicationParams,
92+
Option<ApplicationData>,
93+
),
94+
io::Error,
95+
> {
8896
let credentials = &packet.credentials;
8997

90-
let Some((crypto, parameters)) = map.pair_for_credentials(
98+
let Some((crypto, parameters, application_data)) = map.pair_for_credentials(
9199
credentials,
92100
packet.source_queue_id,
93101
features,
@@ -100,7 +108,7 @@ pub fn derive_stream_credentials(
100108
return Err(error);
101109
};
102110

103-
Ok((crypto, parameters))
111+
Ok((crypto, parameters, application_data))
104112
}
105113

106114
#[inline]
@@ -115,6 +123,7 @@ pub fn accept_stream<Env, P>(
115123
crypto: secret::map::Bidirectional,
116124
mut parameters: dc::ApplicationParams,
117125
secret_control: Vec<u8>,
126+
application_data: Option<ApplicationData>,
118127
) -> Result<application::Builder<Env::Subscriber>, AcceptError>
119128
where
120129
Env: Environment,
@@ -151,6 +160,7 @@ where
151160
endpoint::Type::Server,
152161
subscriber,
153162
subscriber_ctx,
163+
application_data,
154164
);
155165

156166
match res {
@@ -180,6 +190,7 @@ fn build_stream<Env, P>(
180190
endpoint_type: endpoint::Type,
181191
subscriber: Env::Subscriber,
182192
subscriber_ctx: <Env::Subscriber as event::Subscriber>::ConnectionContext,
193+
application_data: Option<ApplicationData>,
183194
) -> Result<application::Builder<Env::Subscriber>>
184195
where
185196
Env: Environment,
@@ -292,6 +303,7 @@ where
292303
let shared = Arc::new(shared::Shared {
293304
receiver: reader,
294305
sender: writer.0,
306+
application_data,
295307
common,
296308
crypto,
297309
});

dc/s2n-quic-dc/src/stream/recv/application.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::{
66
credentials::Id,
77
event::{self, ConnectionPublisher as _},
88
msg,
9+
path::secret::map::ApplicationData,
910
stream::{
1011
recv, runtime,
1112
shared::{AcceptState, ArcShared, ShutdownKind},
@@ -140,6 +141,11 @@ where
140141
&self.0.shared.credentials().id
141142
}
142143

144+
#[inline]
145+
pub fn path_application_data(&self) -> Option<&ApplicationData> {
146+
self.0.shared.application_data()
147+
}
148+
143149
#[inline]
144150
pub fn protocol(&self) -> socket::Protocol {
145151
self.0.sockets.protocol()

dc/s2n-quic-dc/src/stream/server/tokio/tcp/worker.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ where
411411

412412
let mut secret_control = vec![];
413413

414-
let (crypto, parameters) = match endpoint::derive_stream_credentials(
414+
let (crypto, parameters, application_data) = match endpoint::derive_stream_credentials(
415415
&initial_packet,
416416
&context.secrets,
417417
&TransportFeatures::TCP,
@@ -463,6 +463,7 @@ where
463463
crypto,
464464
parameters,
465465
secret_control,
466+
application_data,
466467
) {
467468
Ok(stream) => stream,
468469
Err(error) => {

dc/s2n-quic-dc/src/stream/server/tokio/udp.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ where
119119
let peer = env::udp::Owned(remote_addr, recv_buffer);
120120

121121
let mut secret_control = vec![];
122-
let (crypto, parameters) = match endpoint::derive_stream_credentials(
122+
let (crypto, parameters, application_data) = match endpoint::derive_stream_credentials(
123123
&packet,
124124
&self.secrets,
125125
&TransportFeatures::UDP,
@@ -148,6 +148,7 @@ where
148148
crypto,
149149
parameters,
150150
secret_control,
151+
application_data,
151152
) {
152153
Ok(stream) => stream,
153154
Err(error) => {

dc/s2n-quic-dc/src/stream/server/tokio/uds.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ where
163163
crypto,
164164
decoded_packet.application_params().clone(),
165165
secret_control,
166+
// application_data is not available for UDS streams because the in-application
167+
// map does not contain the credential ID used by the forwarding process.
168+
None,
166169
) {
167170
Ok(stream) => stream,
168171
Err(error) => {

dc/s2n-quic-dc/src/stream/server/udp.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ where
145145
};
146146

147147
let mut secret_control = vec![];
148-
let (crypto, parameters) = match endpoint::derive_stream_credentials(
148+
let (crypto, parameters, application_data) = match endpoint::derive_stream_credentials(
149149
&self.packet,
150150
&self.secrets,
151151
&TransportFeatures::UDP,
@@ -177,6 +177,7 @@ where
177177
crypto,
178178
parameters,
179179
secret_control,
180+
application_data,
180181
) {
181182
Ok(stream) => stream,
182183
Err(error) => {

dc/s2n-quic-dc/src/stream/shared.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::{
66
credentials::Credentials,
77
event::{self, IntoEvent as _},
88
packet::stream,
9+
path::secret::map::ApplicationData,
910
stream::{
1011
recv::shared as recv,
1112
send::{application, shared as send},
@@ -73,6 +74,7 @@ where
7374
pub receiver: recv::State,
7475
pub sender: send::State,
7576
pub crypto: Crypto,
77+
pub application_data: Option<ApplicationData>,
7678
pub common: Common<Subscriber, Clk>,
7779
}
7880

@@ -188,6 +190,11 @@ where
188190
&*self.common.fixed.credentials.get()
189191
}
190192
}
193+
194+
#[inline]
195+
pub fn application_data(&self) -> Option<&ApplicationData> {
196+
self.application_data.as_ref()
197+
}
191198
}
192199

193200
impl<Sub, C> ops::Deref for Shared<Sub, C>

dc/s2n-quic-dc/src/stream/tests/api.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
use super::testing::dcquic::tcp::*;
5+
use crate::{
6+
path::secret::{stateless_reset::Signer, Map},
7+
psk::{client, server},
8+
stream::{socket::Protocol, testing::bind_pair},
9+
testing::{init_tracing, server_name, NoopSubscriber, TestTlsProvider},
10+
};
11+
use s2n_quic_core::time::StdClock;
12+
use std::sync::Arc;
513

614
#[tokio::test]
715
async fn context_accessible() {
@@ -14,3 +22,94 @@ async fn context_accessible() {
1422
read.query_event_context(|_: &()| ()).unwrap();
1523
write.query_event_context(|_: &()| ()).unwrap();
1624
}
25+
26+
#[tokio::test]
27+
async fn path_application_data_none_by_default() {
28+
let context = Context::new().await;
29+
let (_client, server) = context.pair().await;
30+
31+
// Without a registered make_application_data callback, the server stream
32+
// should have no application_data.
33+
assert!(server.path_application_data().is_none());
34+
}
35+
36+
#[tokio::test]
37+
async fn path_application_data_available_on_server_stream() {
38+
init_tracing();
39+
40+
let tls = TestTlsProvider {};
41+
let sub = NoopSubscriber {};
42+
43+
// Build server Map with application_data callback
44+
let server_map = Map::new(
45+
Signer::new(b"default"),
46+
50_000,
47+
false,
48+
StdClock::default(),
49+
sub.clone(),
50+
);
51+
server_map.register_make_application_data(Box::new(|_session| {
52+
let data: Arc<dyn std::any::Any + Send + Sync> = Arc::new(42u64);
53+
Ok(Some(data))
54+
}));
55+
56+
let server_prov = server::Provider::builder()
57+
.start(
58+
"[::1]:0".parse().unwrap(),
59+
tls.clone(),
60+
sub.clone(),
61+
server_map,
62+
)
63+
.await
64+
.unwrap();
65+
66+
let client_map = Map::new(
67+
Signer::new(b"default"),
68+
50_000,
69+
false,
70+
StdClock::default(),
71+
sub.clone(),
72+
);
73+
let client_prov = client::Provider::builder()
74+
.with_success_jitter(std::time::Duration::ZERO)
75+
.start(
76+
"[::]:0".parse().unwrap(),
77+
client_map,
78+
tls,
79+
sub.clone(),
80+
server_name(),
81+
)
82+
.unwrap();
83+
84+
let (client, server) = bind_pair(
85+
Protocol::Tcp,
86+
"127.0.0.1:0".parse().unwrap(),
87+
client_prov,
88+
server_prov,
89+
);
90+
91+
let acceptor_addr = server.acceptor_addr().expect("acceptor_addr");
92+
let handshake_addr = server.handshake_addr().expect("handshake_addr");
93+
94+
let (client_stream, server_stream) = tokio::join!(
95+
async {
96+
client
97+
.connect(handshake_addr, acceptor_addr, server_name())
98+
.await
99+
.unwrap()
100+
},
101+
async { server.accept().await.unwrap().0 }
102+
);
103+
104+
// Client doesn't have application_data
105+
assert!(client_stream.path_application_data().is_none());
106+
107+
// Server stream should have the application_data we registered
108+
let app_data = server_stream
109+
.path_application_data()
110+
.expect("should have application_data");
111+
let value = app_data
112+
.downcast_ref::<u64>()
113+
.expect("should downcast to u64");
114+
assert_eq!(*value, 42u64);
115+
}

0 commit comments

Comments
 (0)