@@ -148,12 +148,16 @@ async fn encrypt_and_respond_to_query(
148148 ClientCtx :: Udp ( _) => original_packet_size,
149149 ClientCtx :: Tcp ( _) => DNSCRYPT_TCP_RESPONSE_MAX_SIZE ,
150150 } ;
151- let response = match & shared_key {
152- None => response,
153- Some ( shared_key) => dnscrypt:: encrypt (
151+ let response = match ( & shared_key, & nonce) {
152+ ( None , _) => response,
153+ ( Some ( _) , None ) => {
154+ warn ! ( "Shared key provided without nonce" ) ;
155+ bail ! ( "Internal error: shared key without nonce" ) ;
156+ } ,
157+ ( Some ( shared_key) , Some ( nonce) ) => dnscrypt:: encrypt (
154158 maybe_truncate_response ( & client_ctx, packet, response, original_packet_size) ?,
155159 shared_key,
156- nonce. as_ref ( ) . unwrap ( ) ,
160+ nonce,
157161 max_response_size,
158162 ) ?,
159163 } ;
@@ -300,10 +304,31 @@ async fn tcp_acceptor(globals: Arc<Globals>, tcp_listener: TcpListener) -> Resul
300304 if e. kind ( ) == std:: io:: ErrorKind :: WouldBlock {
301305 continue ;
302306 }
303- warn ! ( "TCP accept error: {}" , e) ;
304- if let Some ( tx_oldest) = active_connections. lock ( ) . pop_back ( ) {
305- let _ = tx_oldest. send ( ( ) ) ;
307+ error ! ( "TCP accept error: {}" , e) ;
308+
309+ // Rate limit repeated errors to avoid spinning
310+ let is_resource_error = matches ! (
311+ e. kind( ) ,
312+ std:: io:: ErrorKind :: ConnectionRefused |
313+ std:: io:: ErrorKind :: ConnectionReset |
314+ std:: io:: ErrorKind :: ConnectionAborted |
315+ std:: io:: ErrorKind :: AddrInUse |
316+ std:: io:: ErrorKind :: AddrNotAvailable
317+ ) ;
318+
319+ if is_resource_error {
320+ // For resource-related errors, try to free up connections
321+ let mut connections = active_connections. lock ( ) ;
322+ let freed = connections. len ( ) . min ( 5 ) ;
323+ for _ in 0 ..freed {
324+ if let Some ( tx_oldest) = connections. pop_back ( ) {
325+ let _ = tx_oldest. send ( ( ) ) ;
326+ }
327+ }
328+ info ! ( "Freed {} connections to recover from resource error" , freed) ;
306329 }
330+
331+ // Add delay to prevent CPU spinning on persistent errors
307332 tokio:: time:: sleep ( Duration :: from_secs ( 1 ) ) . await ;
308333 continue ;
309334 }
@@ -384,8 +409,28 @@ async fn udp_acceptor(
384409 if packet_len < DNS_HEADER_SIZE {
385410 continue ;
386411 }
387- let net_udp_socket = net_udp_socket. try_clone ( ) ?;
412+ // Create a socket clone only when we've checked the packet is valid
413+ // This helps avoid resource exhaustion
388414 packet. truncate ( packet_len) ;
415+
416+ // Only create a new socket if there's capacity for a new connection
417+ let active_count = concurrent_connections. load ( Ordering :: Relaxed ) ;
418+ if active_count >= globals. udp_max_active_connections {
419+ debug ! ( "UDP connection limit reached, dropping packet" ) ;
420+ continue ;
421+ }
422+
423+ // Clone the socket for this request
424+ let net_udp_socket = match net_udp_socket. try_clone ( ) {
425+ Ok ( socket) => socket,
426+ Err ( e) => {
427+ error ! ( "Failed to clone UDP socket: {}" , e) ;
428+ // Add a small delay to avoid spinning on socket errors
429+ tokio:: time:: sleep ( Duration :: from_millis ( 100 ) ) . await ;
430+ continue ;
431+ }
432+ } ;
433+
389434 let client_ctx = ClientCtx :: Udp ( UdpClientCtx {
390435 net_udp_socket,
391436 client_addr,
0 commit comments