@@ -32,6 +32,7 @@ mod globals;
3232mod pq;
3333#[ cfg( feature = "metrics" ) ]
3434mod metrics;
35+ mod quic_proxy;
3536mod rate_limiter;
3637mod resolver;
3738#[ cfg( feature = "metrics" ) ]
@@ -64,6 +65,7 @@ use futures::prelude::*;
6465use globals:: * ;
6566use parking_lot:: Mutex ;
6667use parking_lot:: RwLock ;
68+ use quic_proxy:: * ;
6769#[ cfg( target_family = "unix" ) ]
6870use privdrop:: PrivDrop ;
6971use rand:: prelude:: * ;
@@ -169,6 +171,30 @@ async fn encrypt_and_respond_to_query(
169171 respond_to_query ( client_ctx, response) . await
170172}
171173
174+ /// Hand the packet to the QUIC upstream, or return `None` when proxying
175+ /// doesn't apply: disabled, TCP client, or outside the RFC 9443 ranges.
176+ async fn maybe_relay_quic (
177+ globals : & Arc < Globals > ,
178+ client_ctx : ClientCtx ,
179+ packet : & [ u8 ] ,
180+ ) -> Option < Result < ( ) , Error > > {
181+ if globals. quic_proxy . is_none ( ) || !may_be_quic ( packet) {
182+ return None ;
183+ }
184+ match client_ctx {
185+ ClientCtx :: Udp ( udp_client_ctx) => Some (
186+ quic_proxy:: relay (
187+ globals,
188+ udp_client_ctx. net_udp_socket ,
189+ udp_client_ctx. client_addr ,
190+ packet,
191+ )
192+ . await ,
193+ ) ,
194+ ClientCtx :: Tcp ( _) => None ,
195+ }
196+ }
197+
172198async fn handle_client_query (
173199 globals : Arc < Globals > ,
174200 client_ctx : ClientCtx ,
@@ -225,8 +251,22 @@ async fn handle_client_query(
225251 )
226252 . await
227253 }
228- Ok ( None ) => return Ok ( ( ) ) ,
254+ Ok ( None ) => {
255+ // Random QUIC bytes can parse as a valid non-certificate DNS query.
256+ // Relaying one is harmless: a real stray DNS query gets no answer either way.
257+ if let Some ( result) = maybe_relay_quic ( & globals, client_ctx, & packet) . await
258+ {
259+ return result;
260+ }
261+ return Ok ( ( ) ) ;
262+ }
229263 Err ( _) => {
264+ // Not encrypted for us and not a certificate query;
265+ // nothing DNSCrypt-shaped is left for this packet to be.
266+ if let Some ( result) = maybe_relay_quic ( & globals, client_ctx, & packet) . await
267+ {
268+ return result;
269+ }
230270 if may_be_quic ( & packet) {
231271 bail ! ( "Likely a QUIC packet" ) // RFC 9443
232272 }
@@ -428,13 +468,18 @@ async fn udp_acceptor(
428468 let timeout = globals. udp_timeout ;
429469 let concurrent_connections = globals. udp_concurrent_connections . clone ( ) ;
430470 let active_connections = globals. udp_active_connections . clone ( ) ;
471+ // Large enough that a proxied QUIC datagram is never truncated.
472+ let mut recv_buffer = vec ! [ 0u8 ; QUIC_PROXY_BUFFER_SIZE ] ;
431473 loop {
432- let mut packet = vec ! [ 0u8 ; DNSCRYPT_UDP_QUERY_MAX_SIZE ] ;
433- let ( packet_len, client_addr) = tokio_udp_socket. recv_from ( & mut packet) . await ?;
474+ let ( packet_len, client_addr) = tokio_udp_socket. recv_from ( & mut recv_buffer) . await ?;
434475 if packet_len < DNS_HEADER_SIZE {
435476 continue ;
436477 }
437478
479+ if quic_proxy:: try_forward_established ( & globals, client_addr, & recv_buffer[ ..packet_len] ) {
480+ continue ;
481+ }
482+
438483 if let Some ( ref rate_limiter) = globals. rate_limiter {
439484 if !rate_limiter. is_allowed ( client_addr. ip ( ) ) {
440485 debug ! ( "Rate limit exceeded for {}" , client_addr. ip( ) ) ;
@@ -444,7 +489,29 @@ async fn udp_acceptor(
444489 }
445490 }
446491
447- packet. truncate ( packet_len) ;
492+ let packet = recv_buffer[ ..packet_len] . to_vec ( ) ;
493+
494+ // Only relayed Anonymized DNSCrypt queries may exceed the DNSCrypt
495+ // maximum, by the size of the relay header; anything else oversized
496+ // never needs DNS processing.
497+ let oversized_anonymized_dns = globals. anonymized_dns_enabled
498+ && packet_len <= ANONYMIZED_DNSCRYPT_UDP_QUERY_MAX_SIZE
499+ && starts_with_relay_magic ( & packet) ;
500+ if packet_len > DNSCRYPT_UDP_QUERY_MAX_SIZE && !oversized_anonymized_dns {
501+ if globals. quic_proxy . is_some ( ) && may_be_quic ( & packet) {
502+ if let Ok ( net_udp_socket) = net_udp_socket. try_clone ( ) {
503+ let globals = globals. clone ( ) ;
504+ runtime_handle. spawn ( async move {
505+ if let Err ( e) =
506+ quic_proxy:: relay ( & globals, net_udp_socket, client_addr, & packet) . await
507+ {
508+ debug ! ( "QUIC relay error: {:?}" , e) ;
509+ }
510+ } ) ;
511+ }
512+ }
513+ continue ;
514+ }
448515
449516 let active_count = concurrent_connections. load ( Ordering :: Relaxed ) ;
450517 if active_count >= globals. udp_max_active_connections {
@@ -629,11 +696,16 @@ fn set_limits(_config: &Config) -> Result<(), Error> {
629696#[ cfg( target_family = "unix" ) ]
630697fn set_limits ( config : & Config ) -> Result < ( ) , Error > {
631698 use rlimit:: Resource ;
699+ let quic_max_active_flows = match config. quic . upstream_addr {
700+ Some ( _) => config. quic . max_active_flows ,
701+ None => 0 ,
702+ } ;
632703 let nb_descriptors = 4u32
633704 . saturating_mul (
634705 config
635706 . tcp_max_active_connections
636707 . saturating_add ( config. udp_max_active_connections )
708+ . saturating_add ( quic_max_active_flows)
637709 . saturating_add ( config. listen_addrs . len ( ) as u32 ) ,
638710 )
639711 . saturating_add ( 16 ) ;
@@ -888,6 +960,39 @@ fn main() -> Result<(), Error> {
888960 }
889961 _ => None ,
890962 } ;
963+ let quic_proxy = match config. quic . upstream_addr {
964+ None => None ,
965+ Some ( quic_upstream_addr) => {
966+ // Connecting to an unspecified address reaches the local host,
967+ // which could loop back to one of our own listening ports.
968+ if quic_upstream_addr. ip ( ) . is_unspecified ( ) {
969+ bail ! (
970+ "quic.upstream_addr [{}] must be a specific address" ,
971+ quic_upstream_addr
972+ ) ;
973+ }
974+ // A packet forwarded to one of our own UDP ports would fail
975+ // decryption there, look like QUIC again, and be forwarded again.
976+ for listen_addr in & listen_addrs {
977+ if listen_addr. port ( ) == quic_upstream_addr. port ( )
978+ && ( listen_addr. ip ( ) . is_unspecified ( )
979+ || listen_addr. ip ( ) == quic_upstream_addr. ip ( ) )
980+ {
981+ bail ! (
982+ "quic.upstream_addr [{}] would loop back to a listening UDP port" ,
983+ quic_upstream_addr
984+ ) ;
985+ }
986+ }
987+ info ! ( "QUIC proxying enabled, forwarding to [{}]" , quic_upstream_addr) ;
988+ Some ( Arc :: new ( QuicProxy :: new (
989+ quic_upstream_addr,
990+ external_addr,
991+ config. quic . max_active_flows as usize ,
992+ config. quic . idle_timeout ,
993+ ) ) )
994+ }
995+ } ;
891996 let runtime_handle = runtime. handle ( ) ;
892997 let globals = Arc :: new ( Globals {
893998 runtime_handle : runtime_handle. clone ( ) ,
@@ -900,6 +1005,7 @@ fn main() -> Result<(), Error> {
9001005 listen_addrs,
9011006 upstream_addrs : config. upstream_addrs ,
9021007 tls_upstream_addr : config. tls . upstream_addr ,
1008+ quic_proxy,
9031009 external_addr,
9041010 tcp_timeout : Duration :: from_secs ( u64:: from ( config. tcp_timeout ) ) ,
9051011 udp_timeout : Duration :: from_secs ( u64:: from ( config. udp_timeout ) ) ,
0 commit comments