1use std::{
2 collections::{HashMap, hash_map},
3 convert::TryFrom,
4 fmt, mem,
5 net::{IpAddr, SocketAddr},
6 ops::{Index, IndexMut},
7 sync::Arc,
8};
9
10use bytes::{Buf, BufMut, Bytes, BytesMut};
11use rand::{Rng, RngExt, SeedableRng, rngs::StdRng};
12use rustc_hash::FxHashMap;
13use slab::Slab;
14use thiserror::Error;
15use tracing::{debug, error, trace, warn};
16
17use crate::{
18 Duration, FourTuple, INITIAL_MTU, Instant, MAX_CID_SIZE, MIN_INITIAL_SIZE, PathId,
19 RESET_TOKEN_SIZE, ResetToken, Side, Transmit, TransportConfig, TransportError,
20 cid_generator::ConnectionIdGenerator,
21 coding::{BufMutExt, Decodable, Encodable, UnexpectedEnd},
22 config::{ClientConfig, EndpointConfig, ServerConfig},
23 connection::{Connection, ConnectionError, SideArgs},
24 crypto::{self, Keys, UnsupportedVersion},
25 frame,
26 packet::{
27 FixedLengthConnectionIdParser, Header, InitialHeader, InitialPacket, PacketDecodeError,
28 PacketNumber, PartialDecode, ProtectedInitialHeader,
29 },
30 shared::{
31 ConnectionEvent, ConnectionEventInner, ConnectionId, DatagramConnectionEvent, EcnCodepoint,
32 EndpointEvent, EndpointEventInner, IssuedCid,
33 },
34 token::{IncomingToken, InvalidRetryTokenError, Token, TokenPayload},
35 transport_parameters::{PreferredAddress, TransportParameters},
36};
37
38pub struct Endpoint {
43 rng: StdRng,
44 index: ConnectionIndex,
45 connections: Slab<ConnectionMeta>,
46 local_cid_generator: Box<dyn ConnectionIdGenerator>,
47 config: Arc<EndpointConfig>,
48 server_config: Option<Arc<ServerConfig>>,
49 allow_mtud: bool,
51 last_stateless_reset: Option<Instant>,
53 incoming_buffers: Slab<IncomingBuffer>,
55 all_incoming_buffers_total_bytes: u64,
56}
57
58impl Endpoint {
59 pub fn new(
65 config: Arc<EndpointConfig>,
66 server_config: Option<Arc<ServerConfig>>,
67 allow_mtud: bool,
68 ) -> Self {
69 Self {
70 rng: config
71 .rng_seed
72 .map_or_else(|| StdRng::from_rng(&mut rand::rng()), StdRng::from_seed),
73 index: ConnectionIndex::default(),
74 connections: Slab::new(),
75 local_cid_generator: (config.connection_id_generator_factory.as_ref())(),
76 config,
77 server_config,
78 allow_mtud,
79 last_stateless_reset: None,
80 incoming_buffers: Slab::new(),
81 all_incoming_buffers_total_bytes: 0,
82 }
83 }
84
85 pub fn set_server_config(&mut self, server_config: Option<Arc<ServerConfig>>) {
87 self.server_config = server_config;
88 }
89
90 pub fn handle_event(
94 &mut self,
95 ch: ConnectionHandle,
96 event: EndpointEvent,
97 ) -> Option<ConnectionEvent> {
98 use EndpointEventInner::*;
99 match event.0 {
100 NeedIdentifiers(path_id, now, n) => {
101 return Some(self.send_new_identifiers(path_id, now, ch, n));
102 }
103 ResetToken(path_id, remote, token) => {
104 if let Some(old) = self.connections[ch]
105 .reset_token
106 .insert(path_id, (remote, token))
107 {
108 self.index.connection_reset_tokens.remove(old.0, old.1);
109 }
110 if self.index.connection_reset_tokens.insert(remote, token, ch) {
111 warn!("duplicate reset token");
112 }
113 }
114 RetireResetToken(path_id) => {
115 if let Some(old) = self.connections[ch].reset_token.remove(&path_id) {
116 self.index.connection_reset_tokens.remove(old.0, old.1);
117 }
118 }
119 RetireConnectionId(now, path_id, seq, allow_more_cids) => {
120 if let Some(cid) = self.connections[ch]
121 .local_cids
122 .get_mut(&path_id)
123 .and_then(|pcid| pcid.cids.remove(&seq))
124 {
125 trace!(%path_id, "local CID retired {}: {}", seq, cid);
126 self.index.retire(cid);
127 if allow_more_cids {
128 return Some(self.send_new_identifiers(path_id, now, ch, 1));
129 }
130 }
131 }
132 Draining => {
133 }
135 Drained => {
136 if let Some(conn) = self.connections.try_remove(ch.0) {
137 self.index.remove(&conn);
138 } else {
139 error!(id = ch.0, "unknown connection drained");
143 }
144 }
145 }
146 None
147 }
148
149 pub fn handle(
151 &mut self,
152 now: Instant,
153 network_path: FourTuple,
154 ecn: Option<EcnCodepoint>,
155 data: BytesMut,
156 buf: &mut Vec<u8>,
157 ) -> Option<DatagramEvent> {
158 let datagram_len = data.len();
160 let mut event = match PartialDecode::new(
161 data,
162 &FixedLengthConnectionIdParser::new(self.local_cid_generator.cid_len()),
163 &self.config.supported_versions,
164 self.config.grease_quic_bit,
165 ) {
166 Ok((first_decode, remaining)) => DatagramConnectionEvent {
167 now,
168 network_path,
169 path_id: PathId::ZERO, ecn,
171 first_decode,
172 remaining,
173 },
174 Err(PacketDecodeError::UnsupportedVersion {
175 src_cid,
176 dst_cid,
177 version,
178 }) => {
179 if self.server_config.is_none() {
180 debug!("dropping packet with unsupported version");
181 return None;
182 }
183 trace!("sending version negotiation");
184 Header::VersionNegotiate {
186 random: self.rng.random::<u8>() | 0x40,
187 src_cid: dst_cid,
188 dst_cid: src_cid,
189 }
190 .encode(buf);
191 buf.write::<u32>(match version {
193 0x0a1a_2a3a => 0x0a1a_2a4a,
194 _ => 0x0a1a_2a3a,
195 });
196 for &version in &self.config.supported_versions {
197 buf.write(version);
198 }
199 return Some(DatagramEvent::Response(Transmit {
200 destination: network_path.remote,
201 ecn: None,
202 size: buf.len(),
203 segment_size: None,
204 src_ip: network_path.local_ip,
205 }));
206 }
207 Err(e) => {
208 trace!("malformed header: {}", e);
209 return None;
210 }
211 };
212
213 let dst_cid = event.first_decode.dst_cid();
214
215 if let Some(route_to) = self.index.get(&network_path, &event.first_decode) {
216 event.path_id = match route_to {
217 RouteDatagramTo::Incoming(_) => PathId::ZERO,
218 RouteDatagramTo::Connection(_, path_id) => path_id,
219 };
220 match route_to {
221 RouteDatagramTo::Incoming(incoming_idx) => {
222 let incoming_buffer = &mut self.incoming_buffers[incoming_idx];
223 let config = &self.server_config.as_ref().unwrap();
224
225 if incoming_buffer
226 .total_bytes
227 .checked_add(datagram_len as u64)
228 .is_some_and(|n| n <= config.incoming_buffer_size)
229 && self
230 .all_incoming_buffers_total_bytes
231 .checked_add(datagram_len as u64)
232 .is_some_and(|n| n <= config.incoming_buffer_size_total)
233 {
234 incoming_buffer.datagrams.push(event);
235 incoming_buffer.total_bytes += datagram_len as u64;
236 self.all_incoming_buffers_total_bytes += datagram_len as u64;
237 }
238
239 None
240 }
241 RouteDatagramTo::Connection(ch, _path_id) => Some(DatagramEvent::ConnectionEvent(
242 ch,
243 ConnectionEvent(ConnectionEventInner::Datagram(event)),
244 )),
245 }
246 } else if event.first_decode.initial_header().is_some() {
247 self.handle_first_packet(datagram_len, event, network_path, buf)
250 } else if event.first_decode.has_long_header() {
251 debug!(
252 "ignoring non-initial packet for unknown connection {}",
253 dst_cid
254 );
255 None
256 } else if !event.first_decode.is_initial()
257 && self.local_cid_generator.validate(dst_cid).is_err()
258 {
259 debug!("dropping packet with invalid CID");
260 None
261 } else if dst_cid.is_empty() {
262 trace!("dropping unrecognized short packet without ID");
263 None
264 } else {
265 self.stateless_reset(now, datagram_len, network_path, dst_cid, buf)
268 .map(DatagramEvent::Response)
269 }
270 }
271
272 fn stateless_reset(
274 &mut self,
275 now: Instant,
276 inciting_dgram_len: usize,
277 network_path: FourTuple,
278 dst_cid: ConnectionId,
279 buf: &mut Vec<u8>,
280 ) -> Option<Transmit> {
281 if self
282 .last_stateless_reset
283 .is_some_and(|last| last + self.config.min_reset_interval > now)
284 {
285 debug!("ignoring unexpected packet within minimum stateless reset interval");
286 return None;
287 }
288
289 const MIN_PADDING_LEN: usize = 5;
291
292 let max_padding_len = match inciting_dgram_len.checked_sub(RESET_TOKEN_SIZE) {
295 Some(headroom) if headroom > MIN_PADDING_LEN => headroom - 1,
296 _ => {
297 debug!(
298 "ignoring unexpected {} byte packet: not larger than minimum stateless reset size",
299 inciting_dgram_len
300 );
301 return None;
302 }
303 };
304
305 debug!(%dst_cid, %network_path.remote, "sending stateless reset");
306 self.last_stateless_reset = Some(now);
307 const IDEAL_MIN_PADDING_LEN: usize = MIN_PADDING_LEN + MAX_CID_SIZE;
309 let padding_len = if max_padding_len <= IDEAL_MIN_PADDING_LEN {
310 max_padding_len
311 } else {
312 self.rng
313 .random_range(IDEAL_MIN_PADDING_LEN..max_padding_len)
314 };
315 buf.reserve(padding_len + RESET_TOKEN_SIZE);
316 buf.resize(padding_len, 0);
317 self.rng.fill_bytes(&mut buf[0..padding_len]);
318 buf[0] = 0b0100_0000 | (buf[0] >> 2);
319 buf.extend_from_slice(&ResetToken::new(&*self.config.reset_key, dst_cid));
320
321 debug_assert!(buf.len() < inciting_dgram_len);
322
323 Some(Transmit {
324 destination: network_path.remote,
325 ecn: None,
326 size: buf.len(),
327 segment_size: None,
328 src_ip: network_path.local_ip,
329 })
330 }
331
332 pub fn connect(
334 &mut self,
335 now: Instant,
336 config: ClientConfig,
337 remote: SocketAddr,
338 server_name: &str,
339 ) -> Result<(ConnectionHandle, Connection), ConnectError> {
340 if self.cids_exhausted() {
341 return Err(ConnectError::CidsExhausted);
342 }
343 if remote.port() == 0 || remote.ip().is_unspecified() {
344 return Err(ConnectError::InvalidRemoteAddress(remote));
345 }
346 if !self.config.supported_versions.contains(&config.version) {
347 return Err(ConnectError::UnsupportedVersion);
348 }
349
350 let remote_id = (config.initial_dst_cid_provider)();
351 trace!(initial_dcid = %remote_id);
352
353 let ch = ConnectionHandle(self.connections.vacant_key());
354 let local_cid = self.new_cid(ch, PathId::ZERO);
355 let params = TransportParameters::new(
356 &config.transport,
357 &self.config,
358 self.local_cid_generator.as_ref(),
359 local_cid,
360 None,
361 &mut self.rng,
362 );
363 let tls = config
364 .crypto
365 .start_session(config.version, server_name, ¶ms)?;
366
367 let conn = self.add_connection(
368 ch,
369 config.version,
370 remote_id,
371 local_cid,
372 remote_id,
373 FourTuple {
374 remote,
375 local_ip: None,
376 },
377 now,
378 tls,
379 config.transport,
380 SideArgs::Client {
381 token_store: config.token_store,
382 server_name: server_name.into(),
383 },
384 ¶ms,
385 );
386 Ok((ch, conn))
387 }
388
389 fn send_new_identifiers(
391 &mut self,
392 path_id: PathId,
393 now: Instant,
394 ch: ConnectionHandle,
395 num: u64,
396 ) -> ConnectionEvent {
397 let mut ids = vec![];
398 for _ in 0..num {
399 let id = self.new_cid(ch, path_id);
400 let cid_meta = self.connections[ch].local_cids.entry(path_id).or_default();
401 let sequence = cid_meta.issued;
402 cid_meta.issued += 1;
403 cid_meta.cids.insert(sequence, id);
404 ids.push(IssuedCid {
405 path_id,
406 sequence,
407 id,
408 reset_token: ResetToken::new(&*self.config.reset_key, id),
409 });
410 }
411 ConnectionEvent(ConnectionEventInner::NewIdentifiers(
412 ids,
413 now,
414 self.local_cid_generator.cid_len(),
415 self.local_cid_generator.cid_lifetime(),
416 ))
417 }
418
419 fn new_cid(&mut self, ch: ConnectionHandle, path_id: PathId) -> ConnectionId {
421 loop {
422 let cid = self.local_cid_generator.generate_cid();
423 if cid.is_empty() {
424 debug_assert_eq!(self.local_cid_generator.cid_len(), 0);
426 return cid;
427 }
428 if let hash_map::Entry::Vacant(e) = self.index.connection_ids.entry(cid) {
429 e.insert((ch, path_id));
430 break cid;
431 }
432 }
433 }
434
435 fn handle_first_packet(
436 &mut self,
437 datagram_len: usize,
438 event: DatagramConnectionEvent,
439 network_path: FourTuple,
440 buf: &mut Vec<u8>,
441 ) -> Option<DatagramEvent> {
442 let dst_cid = event.first_decode.dst_cid();
443 let header = event.first_decode.initial_header().unwrap();
444
445 let Some(server_config) = &self.server_config else {
446 debug!("packet for unrecognized connection {}", dst_cid);
447 return self
448 .stateless_reset(event.now, datagram_len, network_path, dst_cid, buf)
449 .map(DatagramEvent::Response);
450 };
451
452 if datagram_len < MIN_INITIAL_SIZE as usize {
453 debug!("ignoring short initial for connection {}", dst_cid);
454 return None;
455 }
456
457 if self.cids_exhausted() || self.incoming_buffers.len() >= server_config.max_incoming {
460 debug!(
461 "ignoring initial for connection {} due to saturation",
462 dst_cid
463 );
464 return None;
465 }
466
467 let crypto = match server_config.crypto.initial_keys(header.version, dst_cid) {
468 Ok(keys) => keys,
469 Err(UnsupportedVersion) => {
470 debug!(
473 "ignoring initial packet version {:#x} unsupported by cryptographic layer",
474 header.version
475 );
476 return None;
477 }
478 };
479
480 if let Err(reason) = self.early_validate_first_packet(header) {
481 return Some(DatagramEvent::Response(self.initial_close(
482 header.version,
483 network_path,
484 &crypto,
485 header.src_cid,
486 reason,
487 buf,
488 )));
489 }
490
491 let packet = match event.first_decode.finish(Some(&*crypto.header.remote)) {
492 Ok(packet) => packet,
493 Err(e) => {
494 trace!("unable to decode initial packet: {}", e);
495 return None;
496 }
497 };
498
499 if !packet.reserved_bits_valid() {
500 debug!("dropping connection attempt with invalid reserved bits");
501 return None;
502 }
503
504 let Header::Initial(header) = packet.header else {
505 panic!("non-initial packet in handle_first_packet()");
506 };
507
508 let server_config = self.server_config.as_ref().unwrap().clone();
509
510 let token = match IncomingToken::from_header(&header, &server_config, network_path.remote) {
511 Ok(token) => token,
512 Err(InvalidRetryTokenError) => {
513 debug!("rejecting invalid retry token");
514 return Some(DatagramEvent::Response(self.initial_close(
515 header.version,
516 network_path,
517 &crypto,
518 header.src_cid,
519 TransportError::INVALID_TOKEN(""),
520 buf,
521 )));
522 }
523 };
524
525 let incoming_idx = self.incoming_buffers.insert(IncomingBuffer::default());
526 self.index
527 .insert_initial_incoming(header.dst_cid, incoming_idx);
528
529 Some(DatagramEvent::NewConnection(Incoming {
530 received_at: event.now,
531 network_path,
532 ecn: event.ecn,
533 packet: InitialPacket {
534 header,
535 header_data: packet.header_data,
536 payload: packet.payload,
537 },
538 rest: event.remaining,
539 crypto,
540 token,
541 incoming_idx,
542 improper_drop_warner: IncomingImproperDropWarner,
543 }))
544 }
545
546 pub fn accept(
549 &mut self,
550 mut incoming: Incoming,
551 now: Instant,
552 buf: &mut Vec<u8>,
553 server_config: Option<Arc<ServerConfig>>,
554 ) -> Result<(ConnectionHandle, Connection), Box<AcceptError>> {
555 let remote_address_validated = incoming.remote_address_validated();
556 incoming.improper_drop_warner.dismiss();
557 let incoming_buffer = self.incoming_buffers.remove(incoming.incoming_idx);
558 self.all_incoming_buffers_total_bytes -= incoming_buffer.total_bytes;
559
560 let packet_number = incoming.packet.header.number.expand(0);
561 let InitialHeader {
562 src_cid,
563 dst_cid,
564 version,
565 ..
566 } = incoming.packet.header;
567 let server_config =
568 server_config.unwrap_or_else(|| self.server_config.as_ref().unwrap().clone());
569
570 if server_config
571 .transport
572 .max_idle_timeout
573 .is_some_and(|timeout| {
574 incoming.received_at + Duration::from_millis(timeout.into()) <= now
575 })
576 {
577 debug!("abandoning accept of stale initial");
578 self.index.remove_initial(dst_cid);
579 return Err(Box::new(AcceptError {
580 cause: ConnectionError::TimedOut,
581 response: None,
582 }));
583 }
584
585 if self.cids_exhausted() {
586 debug!("refusing connection");
587 self.index.remove_initial(dst_cid);
588 return Err(Box::new(AcceptError {
589 cause: ConnectionError::CidsExhausted,
590 response: Some(self.initial_close(
591 version,
592 incoming.network_path,
593 &incoming.crypto,
594 src_cid,
595 TransportError::CONNECTION_REFUSED(""),
596 buf,
597 )),
598 }));
599 }
600
601 if incoming
602 .crypto
603 .packet
604 .remote
605 .decrypt(
606 PathId::ZERO,
607 packet_number,
608 &incoming.packet.header_data,
609 &mut incoming.packet.payload,
610 )
611 .is_err()
612 {
613 debug!(packet_number, "failed to authenticate initial packet");
614 self.index.remove_initial(dst_cid);
615 return Err(Box::new(AcceptError {
616 cause: TransportError::PROTOCOL_VIOLATION("authentication failed").into(),
617 response: None,
618 }));
619 };
620
621 let ch = ConnectionHandle(self.connections.vacant_key());
622 let local_cid = self.new_cid(ch, PathId::ZERO);
623 let mut params = TransportParameters::new(
624 &server_config.transport,
625 &self.config,
626 self.local_cid_generator.as_ref(),
627 local_cid,
628 Some(&server_config),
629 &mut self.rng,
630 );
631 params.stateless_reset_token = Some(ResetToken::new(&*self.config.reset_key, local_cid));
632 params.original_dst_cid = Some(incoming.token.orig_dst_cid);
633 params.retry_src_cid = incoming.token.retry_src_cid;
634 let mut pref_addr_cid = None;
635 if server_config.has_preferred_address() {
636 let cid = self.new_cid(ch, PathId::ZERO);
637 pref_addr_cid = Some(cid);
638 params.preferred_address = Some(PreferredAddress {
639 address_v4: server_config.preferred_address_v4,
640 address_v6: server_config.preferred_address_v6,
641 connection_id: cid,
642 stateless_reset_token: ResetToken::new(&*self.config.reset_key, cid),
643 });
644 }
645
646 let tls = server_config.crypto.start_session(version, ¶ms);
647 let transport_config = server_config.transport.clone();
648 let mut conn = self.add_connection(
649 ch,
650 version,
651 dst_cid,
652 local_cid,
653 src_cid,
654 incoming.network_path,
655 incoming.received_at,
656 tls,
657 transport_config,
658 SideArgs::Server {
659 server_config,
660 pref_addr_cid,
661 path_validated: remote_address_validated,
662 },
663 ¶ms,
664 );
665 self.index.insert_initial(dst_cid, ch);
666
667 match conn.handle_first_packet(
668 incoming.received_at,
669 incoming.network_path,
670 incoming.ecn,
671 packet_number,
672 incoming.packet,
673 incoming.rest,
674 ) {
675 Ok(()) => {
676 trace!(
677 id = ch.0,
678 icid = %dst_cid,
679 network_path = %incoming.network_path,
680 "new connection",
681 );
682
683 for event in incoming_buffer.datagrams {
684 conn.handle_event(ConnectionEvent(ConnectionEventInner::Datagram(event)))
685 }
686
687 Ok((ch, conn))
688 }
689 Err(e) => {
690 debug!("handshake failed: {}", e);
691 self.handle_event(ch, EndpointEvent(EndpointEventInner::Drained));
692 let response = match e {
693 ConnectionError::TransportError(ref e) => Some(self.initial_close(
694 version,
695 incoming.network_path,
696 &incoming.crypto,
697 src_cid,
698 e.clone(),
699 buf,
700 )),
701 _ => None,
702 };
703 Err(Box::new(AcceptError { cause: e, response }))
704 }
705 }
706 }
707
708 fn early_validate_first_packet(
710 &mut self,
711 header: &ProtectedInitialHeader,
712 ) -> Result<(), TransportError> {
713 if header.dst_cid.len() < 8
718 && (header.token_pos.is_empty()
719 || header.dst_cid.len() != self.local_cid_generator.cid_len())
720 {
721 debug!(
722 "rejecting connection due to invalid DCID length {}",
723 header.dst_cid.len()
724 );
725 return Err(TransportError::PROTOCOL_VIOLATION(
726 "invalid destination CID length",
727 ));
728 }
729
730 Ok(())
731 }
732
733 pub fn refuse(&mut self, incoming: Incoming, buf: &mut Vec<u8>) -> Transmit {
735 self.clean_up_incoming(&incoming);
736 incoming.improper_drop_warner.dismiss();
737
738 trace!(?incoming.network_path, "refusing incoming");
739
740 self.initial_close(
741 incoming.packet.header.version,
742 incoming.network_path,
743 &incoming.crypto,
744 incoming.packet.header.src_cid,
745 TransportError::CONNECTION_REFUSED(""),
746 buf,
747 )
748 }
749
750 pub fn retry(&mut self, incoming: Incoming, buf: &mut Vec<u8>) -> Result<Transmit, RetryError> {
754 if !incoming.may_retry() {
755 trace!(
756 ?incoming.network_path,
757 "not responding retry on incoming due to missing src CID"
758 );
759 return Err(RetryError(Box::new(incoming)));
760 }
761
762 trace!(?incoming.network_path, "responding retry on incoming");
763
764 self.clean_up_incoming(&incoming);
765 incoming.improper_drop_warner.dismiss();
766
767 let server_config = self.server_config.as_ref().unwrap();
768
769 let local_cid = self.local_cid_generator.generate_cid();
776
777 let payload = TokenPayload::Retry {
778 address: incoming.network_path.remote,
779 orig_dst_cid: incoming.packet.header.dst_cid,
780 issued: server_config.time_source.now(),
781 };
782 let token = Token::new(payload, &mut self.rng).encode(&*server_config.token_key);
783
784 let header = Header::Retry {
785 src_cid: local_cid,
786 dst_cid: incoming.packet.header.src_cid,
787 version: incoming.packet.header.version,
788 };
789
790 let encode = header.encode(buf);
791 buf.put_slice(&token);
792 buf.extend_from_slice(&server_config.crypto.retry_tag(
793 incoming.packet.header.version,
794 incoming.packet.header.dst_cid,
795 buf,
796 ));
797 encode.finish(buf, &*incoming.crypto.header.local, None);
798
799 Ok(Transmit {
800 destination: incoming.network_path.remote,
801 ecn: None,
802 size: buf.len(),
803 segment_size: None,
804 src_ip: incoming.network_path.local_ip,
805 })
806 }
807
808 pub fn ignore(&mut self, incoming: Incoming) {
813 self.clean_up_incoming(&incoming);
814 incoming.improper_drop_warner.dismiss();
815
816 trace!(?incoming.network_path, "ignoring incoming");
817 }
818
819 fn clean_up_incoming(&mut self, incoming: &Incoming) {
821 self.index.remove_initial(incoming.packet.header.dst_cid);
822 let incoming_buffer = self.incoming_buffers.remove(incoming.incoming_idx);
823 self.all_incoming_buffers_total_bytes -= incoming_buffer.total_bytes;
824 }
825
826 fn add_connection(
827 &mut self,
828 ch: ConnectionHandle,
829 version: u32,
830 init_cid: ConnectionId,
831 local_cid: ConnectionId,
832 remote_cid: ConnectionId,
833 network_path: FourTuple,
834 now: Instant,
835 tls: Box<dyn crypto::Session>,
836 transport_config: Arc<TransportConfig>,
837 side_args: SideArgs,
838 params: &TransportParameters,
840 ) -> Connection {
841 let mut rng_seed = [0; 32];
842 self.rng.fill_bytes(&mut rng_seed);
843 let side = side_args.side();
844 let pref_addr_cid = side_args.pref_addr_cid();
845
846 let qlog =
847 transport_config.create_qlog_sink(side_args.side(), network_path.remote, init_cid, now);
848
849 qlog.emit_connection_started(
850 now,
851 local_cid,
852 remote_cid,
853 network_path.remote,
854 network_path.local_ip,
855 params,
856 );
857
858 let conn = Connection::new(
859 self.config.clone(),
860 transport_config,
861 init_cid,
862 local_cid,
863 remote_cid,
864 network_path,
865 tls,
866 self.local_cid_generator.as_ref(),
867 now,
868 version,
869 self.allow_mtud,
870 rng_seed,
871 side_args,
872 qlog,
873 );
874
875 let mut path_cids = PathLocalCids::default();
876 path_cids.cids.insert(path_cids.issued, local_cid);
877 path_cids.issued += 1;
878
879 if let Some(cid) = pref_addr_cid {
880 debug_assert_eq!(path_cids.issued, 1, "preferred address cid seq must be 1");
881 path_cids.cids.insert(path_cids.issued, cid);
882 path_cids.issued += 1;
883 }
884
885 let id = self.connections.insert(ConnectionMeta {
886 init_cid,
887 local_cids: FxHashMap::from_iter([(PathId::ZERO, path_cids)]),
888 network_path,
889 side,
890 reset_token: Default::default(),
891 });
892 debug_assert_eq!(id, ch.0, "connection handle allocation out of sync");
893
894 self.index.insert_conn(network_path, local_cid, ch, side);
895
896 conn
897 }
898
899 fn initial_close(
900 &mut self,
901 version: u32,
902 network_path: FourTuple,
903 crypto: &Keys,
904 remote_id: ConnectionId,
905 reason: TransportError,
906 buf: &mut Vec<u8>,
907 ) -> Transmit {
908 let local_id = self.local_cid_generator.generate_cid();
912 let number = PacketNumber::U8(0);
913 let header = Header::Initial(InitialHeader {
914 dst_cid: remote_id,
915 src_cid: local_id,
916 number,
917 token: Bytes::new(),
918 version,
919 });
920
921 let partial_encode = header.encode(buf);
922 let max_len =
923 INITIAL_MTU as usize - partial_encode.header_len - crypto.packet.local.tag_len();
924 frame::Close::from(reason).encoder(max_len).encode(buf);
925 buf.resize(buf.len() + crypto.packet.local.tag_len(), 0);
926 partial_encode.finish(
927 buf,
928 &*crypto.header.local,
929 Some((0, Default::default(), &*crypto.packet.local)),
930 );
931 Transmit {
932 destination: network_path.remote,
933 ecn: None,
934 size: buf.len(),
935 segment_size: None,
936 src_ip: network_path.local_ip,
937 }
938 }
939
940 pub fn config(&self) -> &EndpointConfig {
942 &self.config
943 }
944
945 pub fn open_connections(&self) -> usize {
947 self.connections.len()
948 }
949
950 pub fn incoming_buffer_bytes(&self) -> u64 {
953 self.all_incoming_buffers_total_bytes
954 }
955
956 #[cfg(test)]
957 pub(crate) fn known_connections(&self) -> usize {
958 let x = self.connections.len();
959 debug_assert_eq!(x, self.index.connection_ids_initial.len());
960 debug_assert!(x >= self.index.connection_reset_tokens.0.len());
962 debug_assert!(x >= self.index.incoming_connection_remotes.len());
964 debug_assert!(x >= self.index.outgoing_connection_remotes.len());
965 x
966 }
967
968 #[cfg(test)]
969 pub(crate) fn known_cids(&self) -> usize {
970 self.index.connection_ids.len()
971 }
972
973 fn cids_exhausted(&self) -> bool {
978 let cid_len = self.local_cid_generator.cid_len();
979 if cid_len == 0 || cid_len > 4 {
980 return false;
981 }
982
983 let bits = (cid_len * 8) as u32;
985 let space = 1u64 << bits;
986 let reserve = 1u64 << (bits - 2);
987 let len = self.index.connection_ids.len() as u64;
988
989 len > (space - reserve)
990 }
991}
992
993impl fmt::Debug for Endpoint {
994 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
995 fmt.debug_struct("Endpoint")
996 .field("rng", &self.rng)
997 .field("index", &self.index)
998 .field("connections", &self.connections)
999 .field("config", &self.config)
1000 .field("server_config", &self.server_config)
1001 .field("incoming_buffers.len", &self.incoming_buffers.len())
1003 .field(
1004 "all_incoming_buffers_total_bytes",
1005 &self.all_incoming_buffers_total_bytes,
1006 )
1007 .finish()
1008 }
1009}
1010
1011#[derive(Default)]
1013struct IncomingBuffer {
1014 datagrams: Vec<DatagramConnectionEvent>,
1015 total_bytes: u64,
1016}
1017
1018#[derive(Copy, Clone, Debug)]
1020enum RouteDatagramTo {
1021 Incoming(usize),
1022 Connection(ConnectionHandle, PathId),
1023}
1024
1025#[derive(Default, Debug)]
1027struct ConnectionIndex {
1028 connection_ids_initial: HashMap<ConnectionId, RouteDatagramTo>,
1034 connection_ids: FxHashMap<ConnectionId, (ConnectionHandle, PathId)>,
1038 incoming_connection_remotes: HashMap<FourTuple, ConnectionHandle>,
1042 outgoing_connection_remotes: HashMap<SocketAddr, ConnectionHandle>,
1052 connection_reset_tokens: ResetTokenTable,
1057}
1058
1059impl ConnectionIndex {
1060 fn insert_initial_incoming(&mut self, dst_cid: ConnectionId, incoming_key: usize) {
1062 if dst_cid.is_empty() {
1063 return;
1064 }
1065 self.connection_ids_initial
1066 .insert(dst_cid, RouteDatagramTo::Incoming(incoming_key));
1067 }
1068
1069 fn remove_initial(&mut self, dst_cid: ConnectionId) {
1071 if dst_cid.is_empty() {
1072 return;
1073 }
1074 let removed = self.connection_ids_initial.remove(&dst_cid);
1075 debug_assert!(removed.is_some());
1076 }
1077
1078 fn insert_initial(&mut self, dst_cid: ConnectionId, connection: ConnectionHandle) {
1080 if dst_cid.is_empty() {
1081 return;
1082 }
1083 self.connection_ids_initial.insert(
1084 dst_cid,
1085 RouteDatagramTo::Connection(connection, PathId::ZERO),
1086 );
1087 }
1088
1089 fn insert_conn(
1092 &mut self,
1093 network_path: FourTuple,
1094 dst_cid: ConnectionId,
1095 connection: ConnectionHandle,
1096 side: Side,
1097 ) {
1098 match dst_cid.len() {
1099 0 => match side {
1100 Side::Server => {
1101 self.incoming_connection_remotes
1102 .insert(network_path, connection);
1103 }
1104 Side::Client => {
1105 self.outgoing_connection_remotes
1106 .insert(network_path.remote, connection);
1107 }
1108 },
1109 _ => {
1110 self.connection_ids
1111 .insert(dst_cid, (connection, PathId::ZERO));
1112 }
1113 }
1114 }
1115
1116 fn retire(&mut self, dst_cid: ConnectionId) {
1118 self.connection_ids.remove(&dst_cid);
1119 }
1120
1121 fn remove(&mut self, conn: &ConnectionMeta) {
1123 if conn.side.is_server() {
1124 self.remove_initial(conn.init_cid);
1125 }
1126 for cid in conn
1127 .local_cids
1128 .values()
1129 .flat_map(|pcids| pcids.cids.values())
1130 {
1131 self.connection_ids.remove(cid);
1132 }
1133 self.incoming_connection_remotes.remove(&conn.network_path);
1134 self.outgoing_connection_remotes
1135 .remove(&conn.network_path.remote);
1136 for (remote, token) in conn.reset_token.values() {
1137 self.connection_reset_tokens.remove(*remote, *token);
1138 }
1139 }
1140
1141 fn get(&self, network_path: &FourTuple, datagram: &PartialDecode) -> Option<RouteDatagramTo> {
1143 if !datagram.dst_cid().is_empty()
1144 && let Some(&(ch, path_id)) = self.connection_ids.get(&datagram.dst_cid())
1145 {
1146 return Some(RouteDatagramTo::Connection(ch, path_id));
1147 }
1148 if (datagram.is_initial() || datagram.is_0rtt())
1149 && let Some(&ch) = self.connection_ids_initial.get(&datagram.dst_cid())
1150 {
1151 return Some(ch);
1152 }
1153 if datagram.dst_cid().is_empty() {
1154 if let Some(&ch) = self.incoming_connection_remotes.get(network_path) {
1155 return Some(RouteDatagramTo::Connection(ch, PathId::ZERO));
1158 }
1159 if let Some(&ch) = self.outgoing_connection_remotes.get(&network_path.remote) {
1160 return Some(RouteDatagramTo::Connection(ch, PathId::ZERO));
1162 }
1163 }
1164 let data = datagram.data();
1165 if data.len() < RESET_TOKEN_SIZE {
1166 return None;
1167 }
1168 self.connection_reset_tokens
1171 .get(network_path.remote, &data[data.len() - RESET_TOKEN_SIZE..])
1172 .cloned()
1173 .map(|ch| RouteDatagramTo::Connection(ch, PathId::ZERO))
1174 }
1175}
1176
1177#[derive(Debug)]
1178pub(crate) struct ConnectionMeta {
1179 init_cid: ConnectionId,
1180 local_cids: FxHashMap<PathId, PathLocalCids>,
1182 network_path: FourTuple,
1187 side: Side,
1188 reset_token: FxHashMap<PathId, (SocketAddr, ResetToken)>,
1198}
1199
1200#[derive(Debug, Default)]
1202struct PathLocalCids {
1203 issued: u64,
1207 cids: FxHashMap<u64, ConnectionId>,
1209}
1210
1211#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
1213pub struct ConnectionHandle(pub usize);
1214
1215impl From<ConnectionHandle> for usize {
1216 fn from(x: ConnectionHandle) -> Self {
1217 x.0
1218 }
1219}
1220
1221impl Index<ConnectionHandle> for Slab<ConnectionMeta> {
1222 type Output = ConnectionMeta;
1223 fn index(&self, ch: ConnectionHandle) -> &ConnectionMeta {
1224 &self[ch.0]
1225 }
1226}
1227
1228impl IndexMut<ConnectionHandle> for Slab<ConnectionMeta> {
1229 fn index_mut(&mut self, ch: ConnectionHandle) -> &mut ConnectionMeta {
1230 &mut self[ch.0]
1231 }
1232}
1233
1234pub enum DatagramEvent {
1236 ConnectionEvent(ConnectionHandle, ConnectionEvent),
1238 NewConnection(Incoming),
1240 Response(Transmit),
1242}
1243
1244#[derive(derive_more::Debug)]
1246pub struct Incoming {
1247 #[debug(skip)]
1248 received_at: Instant,
1249 network_path: FourTuple,
1250 ecn: Option<EcnCodepoint>,
1251 #[debug(skip)]
1252 packet: InitialPacket,
1253 #[debug(skip)]
1254 rest: Option<BytesMut>,
1255 #[debug(skip)]
1256 crypto: Keys,
1257 token: IncomingToken,
1258 incoming_idx: usize,
1259 #[debug(skip)]
1260 improper_drop_warner: IncomingImproperDropWarner,
1261}
1262
1263impl Incoming {
1264 pub fn local_ip(&self) -> Option<IpAddr> {
1266 self.network_path.local_ip
1267 }
1268
1269 pub fn remote_address(&self) -> SocketAddr {
1271 self.network_path.remote
1272 }
1273
1274 pub fn remote_address_validated(&self) -> bool {
1282 self.token.validated
1283 }
1284
1285 pub fn may_retry(&self) -> bool {
1290 self.token.retry_src_cid.is_none()
1291 }
1292
1293 pub fn orig_dst_cid(&self) -> ConnectionId {
1295 self.token.orig_dst_cid
1296 }
1297
1298 pub fn decrypt(&self) -> Option<DecryptedInitial> {
1303 let packet_number = self.packet.header.number.expand(0);
1304 let mut payload = self.packet.payload.clone();
1305 self.crypto
1306 .packet
1307 .remote
1308 .decrypt(
1309 PathId::ZERO,
1310 packet_number,
1311 &self.packet.header_data,
1312 &mut payload,
1313 )
1314 .ok()?;
1315 Some(DecryptedInitial(payload.freeze()))
1316 }
1317}
1318
1319pub struct DecryptedInitial(Bytes);
1324
1325impl DecryptedInitial {
1326 pub fn alpns(&self) -> Option<IncomingAlpns> {
1332 let frames = frame::Iter::new(self.0.clone()).ok()?;
1333 let mut first = None;
1334 let mut rest = Vec::new();
1335 for frame in frames {
1336 match frame {
1337 Ok(frame::Frame::Crypto(crypto)) => match first {
1338 None => first = Some(crypto),
1339 Some(_) => rest.push(crypto),
1340 },
1341 Err(_) => return None,
1342 _ => {}
1343 }
1344 }
1345 let first = first?;
1346
1347 if rest.is_empty() && first.offset == 0 {
1349 let data = find_alpn_data(&first.data).ok()?;
1350 return Some(IncomingAlpns { data, pos: 0 });
1351 }
1352
1353 rest.push(first);
1355 let source = assemble_crypto_frames(&mut rest)?;
1356 let data = find_alpn_data(&source).ok()?;
1357 Some(IncomingAlpns { data, pos: 0 })
1358 }
1359}
1360
1361const TLS_HANDSHAKE_TYPE_CLIENT_HELLO: u8 = 0x01;
1364const TLS_EXTENSION_TYPE_ALPN: u16 = 0x0010;
1367const TLS_CLIENT_HELLO_FIXED_LEN: usize = 2 + 32;
1370
1371pub struct IncomingAlpns {
1376 data: Bytes,
1377 pos: usize,
1378}
1379
1380impl Iterator for IncomingAlpns {
1381 type Item = Result<Bytes, UnexpectedEnd>;
1382
1383 fn next(&mut self) -> Option<Self::Item> {
1384 if self.pos >= self.data.len() {
1385 return None;
1386 }
1387 let len = self.data[self.pos] as usize;
1388 self.pos += 1;
1389 if self.pos + len > self.data.len() {
1390 return Some(Err(UnexpectedEnd));
1391 }
1392 let proto = self.data.slice(self.pos..self.pos + len);
1393 self.pos += len;
1394 Some(Ok(proto))
1395 }
1396}
1397
1398fn assemble_crypto_frames(frames: &mut [frame::Crypto]) -> Option<Bytes> {
1402 frames.sort_by_key(|f| f.offset);
1403 let capacity = frames.iter().map(|f| f.data.len()).sum();
1404 let mut buf = Vec::with_capacity(capacity);
1405 for f in frames.iter() {
1406 let start = f.offset as usize;
1407 if start > buf.len() {
1408 return None;
1409 }
1410 let end = start + f.data.len();
1411 if end > buf.len() {
1412 buf.extend_from_slice(&f.data[buf.len() - start..]);
1413 }
1414 }
1415 Some(Bytes::from(buf))
1416}
1417
1418fn find_alpn_data(source: &Bytes) -> Result<Bytes, UnexpectedEnd> {
1424 let mut r = &**source;
1425
1426 if u8::decode(&mut r)? != TLS_HANDSHAKE_TYPE_CLIENT_HELLO {
1427 return Err(UnexpectedEnd);
1428 }
1429
1430 let len = decode_u24(&mut r)?;
1432 let mut body = take(&mut r, len)?;
1433
1434 skip(&mut body, TLS_CLIENT_HELLO_FIXED_LEN)?;
1436
1437 skip_u8_prefixed(&mut body)?;
1439 skip_u16_prefixed(&mut body)?;
1440 skip_u8_prefixed(&mut body)?;
1441
1442 let mut exts = take_u16_prefixed(&mut body)?;
1444 while exts.has_remaining() {
1445 let ext_type = u16::decode(&mut exts)?;
1446 let ext_data = take_u16_prefixed(&mut exts)?;
1447 if ext_type == TLS_EXTENSION_TYPE_ALPN {
1448 let list = take_u16_prefixed(&mut &*ext_data)?;
1449 return Ok(source.slice_ref(list));
1450 }
1451 }
1452 Err(UnexpectedEnd)
1453}
1454
1455fn decode_u24(r: &mut &[u8]) -> Result<usize, UnexpectedEnd> {
1457 let a = u8::decode(r)?;
1458 let b = u8::decode(r)?;
1459 let c = u8::decode(r)?;
1460 Ok(u32::from_be_bytes([0, a, b, c]) as usize)
1461}
1462
1463fn take<'a>(r: &mut &'a [u8], len: usize) -> Result<&'a [u8], UnexpectedEnd> {
1465 if r.remaining() < len {
1466 return Err(UnexpectedEnd);
1467 }
1468 let data = &r[..len];
1469 r.advance(len);
1470 Ok(data)
1471}
1472
1473fn take_u16_prefixed<'a>(r: &mut &'a [u8]) -> Result<&'a [u8], UnexpectedEnd> {
1475 let len = u16::decode(r)? as usize;
1476 take(r, len)
1477}
1478
1479fn skip(r: &mut &[u8], len: usize) -> Result<(), UnexpectedEnd> {
1481 take(r, len)?;
1482 Ok(())
1483}
1484
1485fn skip_u8_prefixed(r: &mut &[u8]) -> Result<(), UnexpectedEnd> {
1487 let len = u8::decode(r)? as usize;
1488 skip(r, len)
1489}
1490
1491fn skip_u16_prefixed(r: &mut &[u8]) -> Result<(), UnexpectedEnd> {
1493 let len = u16::decode(r)? as usize;
1494 skip(r, len)
1495}
1496
1497struct IncomingImproperDropWarner;
1498
1499impl IncomingImproperDropWarner {
1500 fn dismiss(self) {
1501 mem::forget(self);
1502 }
1503}
1504
1505impl Drop for IncomingImproperDropWarner {
1506 fn drop(&mut self) {
1507 warn!(
1508 "noq_proto::Incoming dropped without passing to Endpoint::accept/refuse/retry/ignore \
1509 (may cause memory leak and eventual inability to accept new connections)"
1510 );
1511 }
1512}
1513
1514#[derive(Debug, Error, Clone, PartialEq, Eq)]
1518pub enum ConnectError {
1519 #[error("endpoint stopping")]
1523 EndpointStopping,
1524 #[error("CIDs exhausted")]
1528 CidsExhausted,
1529 #[error("invalid server name: {0}")]
1531 InvalidServerName(String),
1532 #[error("invalid remote address: {0}")]
1536 InvalidRemoteAddress(SocketAddr),
1537 #[error("no default client config")]
1541 NoDefaultClientConfig,
1542 #[error("unsupported QUIC version")]
1544 UnsupportedVersion,
1545}
1546
1547#[derive(Debug)]
1549pub struct AcceptError {
1550 pub cause: ConnectionError,
1552 pub response: Option<Transmit>,
1554}
1555
1556#[derive(Debug, Error)]
1558#[error("retry() with validated Incoming")]
1559pub struct RetryError(Box<Incoming>);
1560
1561impl RetryError {
1562 pub fn into_incoming(self) -> Incoming {
1564 *self.0
1565 }
1566}
1567
1568#[derive(Default, Debug)]
1573struct ResetTokenTable(HashMap<SocketAddr, HashMap<ResetToken, ConnectionHandle>>);
1574
1575impl ResetTokenTable {
1576 fn insert(&mut self, remote: SocketAddr, token: ResetToken, ch: ConnectionHandle) -> bool {
1577 self.0
1578 .entry(remote)
1579 .or_default()
1580 .insert(token, ch)
1581 .is_some()
1582 }
1583
1584 fn remove(&mut self, remote: SocketAddr, token: ResetToken) {
1585 use std::collections::hash_map::Entry;
1586 match self.0.entry(remote) {
1587 Entry::Vacant(_) => {}
1588 Entry::Occupied(mut e) => {
1589 e.get_mut().remove(&token);
1590 if e.get().is_empty() {
1591 e.remove_entry();
1592 }
1593 }
1594 }
1595 }
1596
1597 fn get(&self, remote: SocketAddr, token: &[u8]) -> Option<&ConnectionHandle> {
1598 let token = ResetToken::from(<[u8; RESET_TOKEN_SIZE]>::try_from(token).ok()?);
1599 self.0.get(&remote)?.get(&token)
1600 }
1601}
1602
1603#[cfg(test)]
1604mod tests {
1605 use super::*;
1606
1607 #[test]
1608 fn assemble_contiguous() {
1609 let data = b"hello world";
1610 let mut frames = vec![
1611 frame::Crypto {
1612 offset: 0,
1613 data: Bytes::from_static(&data[..5]),
1614 },
1615 frame::Crypto {
1616 offset: 5,
1617 data: Bytes::from_static(&data[5..]),
1618 },
1619 ];
1620 assert_eq!(&assemble_crypto_frames(&mut frames).unwrap()[..], &data[..]);
1621 }
1622
1623 #[test]
1624 fn assemble_out_of_order() {
1625 let data = b"hello world";
1626 let mut frames = vec![
1627 frame::Crypto {
1628 offset: 5,
1629 data: Bytes::from_static(&data[5..]),
1630 },
1631 frame::Crypto {
1632 offset: 0,
1633 data: Bytes::from_static(&data[..5]),
1634 },
1635 ];
1636 assert_eq!(&assemble_crypto_frames(&mut frames).unwrap()[..], &data[..]);
1637 }
1638
1639 #[test]
1640 fn assemble_with_overlap() {
1641 let data = b"hello world";
1642 let mut frames = vec![
1643 frame::Crypto {
1644 offset: 0,
1645 data: Bytes::from_static(&data[..7]),
1646 },
1647 frame::Crypto {
1648 offset: 5,
1649 data: Bytes::from_static(&data[5..]),
1650 },
1651 ];
1652 assert_eq!(&assemble_crypto_frames(&mut frames).unwrap()[..], &data[..]);
1653 }
1654
1655 #[test]
1656 fn assemble_with_gap() {
1657 let mut frames = vec![frame::Crypto {
1658 offset: 10,
1659 data: Bytes::from_static(b"world"),
1660 }];
1661 assert!(assemble_crypto_frames(&mut frames).is_none());
1662 }
1663}