1616mod unix;
1717
1818#[ cfg( any( target_os = "macos" , target_os = "linux" ) ) ]
19- pub ( crate ) use unix:: { flush_system_cache, new_random_socket } ;
19+ pub ( crate ) use unix:: flush_system_cache;
2020
2121#[ cfg( windows) ]
2222mod windows;
2323
2424#[ cfg( windows) ]
25- pub ( crate ) use windows:: { flush_system_cache, new_random_socket } ;
25+ pub ( crate ) use windows:: flush_system_cache;
2626
2727#[ cfg( test) ]
2828mod tests;
2929
30+ mod tcp;
31+ use tcp:: new_tcp_listener;
32+
33+ mod udp;
34+ use udp:: new_random_socket;
35+
3036use async_trait:: async_trait;
3137use hickory_server:: {
3238 ServerFuture ,
@@ -55,7 +61,7 @@ use std::{
5561 time:: { Duration , Instant } ,
5662} ;
5763use tokio:: {
58- net:: UdpSocket ,
64+ net:: { TcpListener , UdpSocket } ,
5965 sync:: { Mutex , mpsc, oneshot} ,
6066} ;
6167use tokio_util:: { either:: Either , sync:: CancellationToken } ;
@@ -111,6 +117,10 @@ const TTL_SECONDS: u32 = 3;
111117/// belongs to the documentation range so should never be reachable.
112118const RESOLVED_ADDR : Ipv4Addr = Ipv4Addr :: new ( 198 , 51 , 100 , 1 ) ;
113119
120+ /// Timeout for TCP client connections.
121+ /// Any client that does not send any DNS requests within the given timeout will be dropped.
122+ pub const TCP_CLIENT_TIMEOUT : Duration = Duration :: from_secs ( 60 ) ;
123+
114124/// Resolver errors
115125#[ derive( thiserror:: Error , Debug ) ]
116126pub enum Error {
@@ -370,16 +380,27 @@ impl LocalResolver {
370380 ) -> Result < ( ResolverHandle , tokio:: task:: JoinHandle < ( ) > ) , Error > {
371381 let ( tx, rx) = mpsc:: unbounded_channel ( ) ;
372382
373- let ( resolver_socket , loopback_alias) =
383+ let ( udp_socket , loopback_alias) =
374384 new_random_socket ( DNS_LISTEN_PORT , use_random_loopback) . await ?;
375- let resolver_addr = resolver_socket . local_addr ( ) . map_err ( Error :: GetSocketAddr ) ?;
385+ let resolver_addr = udp_socket . local_addr ( ) . map_err ( Error :: GetSocketAddr ) ?;
376386
377- let mut server = Self :: new_server ( resolver_socket, tx. clone ( ) ) . await ?;
387+ // Attempt to bind TCP listener to the same port as UDP, but don't fail if it's not possible.
388+ let tcp_listener = new_tcp_listener ( resolver_addr)
389+ . inspect_err ( |_err| {
390+ tracing:: warn!( "Failed to bind TCP socket to {resolver_addr}" ) ;
391+ } )
392+ . ok ( ) ;
393+ let is_tcp_available = tcp_listener. is_some ( ) ;
394+
395+ let mut server = Self :: new_server ( udp_socket, tcp_listener, tx. clone ( ) ) . await ?;
378396
379397 let cloned_shutdown_token = shutdown_token. child_token ( ) ;
380398 let cloned_tx = tx. clone ( ) ;
381399 let dns_server_task = tokio:: spawn ( async move {
382- tracing:: info!( "Running DNS resolver on {resolver_addr}" ) ;
400+ tracing:: info!(
401+ "Running DNS resolver on {resolver_addr} ({})" ,
402+ if is_tcp_available { "udp, tcp" } else { "udp" }
403+ ) ;
383404
384405 loop {
385406 tokio:: select! {
@@ -405,15 +426,19 @@ impl LocalResolver {
405426 tracing:: error!( "DNS server unexpectedly stopped: {err}" ) ;
406427 tracing:: debug!( "Attempting to restart server" ) ;
407428
408- let socket = match UdpSocket :: bind( resolver_addr) . await {
429+ let udp_socket = match UdpSocket :: bind( resolver_addr) . await {
409430 Ok ( socket) => socket,
410431 Err ( e) => {
411- tracing:: error!( "Failed to bind DNS server to {resolver_addr}: {e}" ) ;
432+ tracing:: error!( "Failed to bind UDP socket to {resolver_addr}: {e}" ) ;
412433 break ;
413434 }
414435 } ;
415436
416- match Self :: new_server( socket, cloned_tx. clone( ) ) . await {
437+ let tcp_listener = TcpListener :: bind( resolver_addr) . await . inspect_err( |err| {
438+ tracing:: warn!( "Failed to bind TCP socket to {resolver_addr}: {err}" ) ;
439+ } ) . ok( ) ;
440+
441+ match Self :: new_server( udp_socket, tcp_listener, cloned_tx. clone( ) ) . await {
417442 Ok ( new_server) => {
418443 server = new_server;
419444 }
@@ -452,10 +477,14 @@ impl LocalResolver {
452477
453478 async fn new_server (
454479 server_socket : UdpSocket ,
480+ tcp_listener : Option < TcpListener > ,
455481 tx : mpsc:: UnboundedSender < ResolverMessage > ,
456482 ) -> Result < ServerFuture < ResolverImpl > , Error > {
457483 let mut server = ServerFuture :: new ( ResolverImpl { tx } ) ;
458484 server. register_socket ( server_socket) ;
485+ if let Some ( tcp_listener) = tcp_listener {
486+ server. register_listener ( tcp_listener, TCP_CLIENT_TIMEOUT ) ;
487+ }
459488 Ok ( server)
460489 }
461490
0 commit comments