11use crate :: {
2+ packet_decoder:: { find_nord_query, normalize_qname, parse_dns_query_packet, DnsParseError } ,
3+ packet_encoder:: DnsResponseBuilder ,
24 resolver:: Resolver ,
3- zone:: { AuthoritativeZone , ClonableZones , ForwardZone , Records } ,
5+ zone:: { AuthoritativeZone , ClonableZones , ForwardZone , NordZone , Records , NORD_ZONE } ,
46} ;
57use async_trait:: async_trait;
68use hickory_server:: {
@@ -10,6 +12,7 @@ use hickory_server::{
1012} ;
1113use neptun:: noise:: { Tunn , TunnResult } ;
1214use pnet_packet:: {
15+ dns:: DnsQuery ,
1316 ip:: { IpNextHeaderProtocol , IpNextHeaderProtocols } ,
1417 ipv4:: { checksum, Ipv4Packet , MutableIpv4Packet } ,
1518 ipv6:: { Ipv6Packet , MutableIpv6Packet } ,
@@ -87,6 +90,8 @@ async fn update_wg_timers(
8790/// Local name server.
8891#[ derive( Default ) ]
8992pub struct LocalNameServer {
93+ /// .nord peers zone
94+ nord_zone : NordZone ,
9095 zones : Arc < ClonableZones > ,
9196 task_handle : Option < JoinHandle < ( ) > > ,
9297}
@@ -96,6 +101,7 @@ impl LocalNameServer {
96101 /// configured for zone `.`.
97102 pub async fn new ( forward_ips : & [ IpAddr ] ) -> Result < Arc < RwLock < Self > > , String > {
98103 let ns = Arc :: new ( RwLock :: new ( LocalNameServer {
104+ nord_zone : NordZone :: new ( ) ,
99105 zones : Arc :: new ( ClonableZones :: new ( ) ) ,
100106 task_handle : None ,
101107 } ) ) ;
@@ -247,11 +253,6 @@ impl LocalNameServer {
247253 nameserver : Arc < RwLock < LocalNameServer > > ,
248254 request_info : & mut RequestInfo ,
249255 ) -> Result < Vec < u8 > , String > {
250- telio_log_debug ! ( "Resolving dns" ) ;
251- let resolver = Resolver :: new ( ) ;
252- telio_log_debug ! ( "Getting DNS zones" ) ;
253- let zones = nameserver. zones ( ) . await ;
254-
255256 telio_log_debug ! ( "Preparing DNS request" ) ;
256257 let dns_request = match & mut request_info. payload {
257258 PayloadRequestInfo :: Udp {
@@ -262,17 +263,55 @@ impl LocalNameServer {
262263 . ok_or_else ( || String :: from ( "Inexistent DNS request" ) ) ?,
263264 _ => return Ok ( Vec :: new ( ) ) ,
264265 } ;
265- let dns_request = Request :: new ( dns_request, request_info. dns_source ( ) , Protocol :: Udp ) ;
266- telio_log_debug ! ( "DNS request: {:?}" , & dns_request) ;
267266
268- zones
269- . lookup ( & dns_request, resolver. clone ( ) )
270- . await
271- . map_err ( |e| format ! ( "Lookup failed {e}" ) ) ?;
267+ let dns_response = match dns_request {
268+ PayloadDestination :: Local {
269+ id,
270+ recursion_desired,
271+ query,
272+ } => {
273+ telio_log_debug ! (
274+ "Local query for: {:?} {:?}" ,
275+ query. qtype,
276+ query. get_qname_parsed( )
277+ ) ;
278+ // lookup local zone for response
279+ let ( response_kind, ttl) = {
280+ let ns = nameserver. read ( ) . await ;
281+ (
282+ ns. nord_zone . resolve_local_response ( & query) ,
283+ ns. nord_zone . ttl ( ) ,
284+ )
285+ } ;
286+
287+ telio_log_debug ! ( "Local response: {:?}" , response_kind) ;
272288
273- let dns_response = resolver. 0 . lock ( ) . await ;
274- telio_log_debug ! ( "Nameserver response: {:?}" , & dns_response) ;
275- Ok ( dns_response. to_vec ( ) )
289+ // build response packet bytes
290+ DnsResponseBuilder :: new ( id, query, ttl. 0 , response_kind, recursion_desired)
291+ . build ( )
292+ . map_err ( |e| format ! ( "Failed building DNS response packet: {e:?}" ) ) ?
293+ }
294+ PayloadDestination :: Forward ( question) => {
295+ telio_log_debug ! ( "Forwarding request dns" ) ;
296+ let resolver = Resolver :: new ( ) ;
297+ telio_log_debug ! ( "Getting DNS zones" ) ;
298+ let zones = nameserver. zones ( ) . await ;
299+
300+ let dns_request = Request :: new ( question, request_info. dns_source ( ) , Protocol :: Udp ) ;
301+ telio_log_debug ! ( "DNS request: {:?}" , & dns_request) ;
302+
303+ zones
304+ . lookup ( & dns_request, resolver. clone ( ) )
305+ . await
306+ . map_err ( |e| format ! ( "Lookup failed {e}" ) ) ?;
307+
308+ let dns_response = resolver. 0 . lock ( ) . await ;
309+ telio_log_debug ! ( "Nameserver response: {:?}" , & dns_response) ;
310+ dns_response. to_vec ( )
311+ }
312+ } ;
313+
314+ Ok ( dns_response)
276315 }
277316
278317 async fn process_packet (
@@ -347,13 +386,43 @@ impl LocalNameServer {
347386 return Err ( String :: from ( "Invalid DNS port" ) ) ;
348387 }
349388
350- let dns_request = MessageRequest :: from_bytes ( udp_request. payload ( ) )
351- . map_err ( |_| String :: from ( "Failed to build MessageRequest from request packet" ) ) ?;
389+ let payload = udp_request. payload ( ) ;
390+
391+ let dns_request = match parse_dns_query_packet ( payload) {
392+ Ok ( packet) => {
393+ if let Some ( query) = find_nord_query ( & packet) {
394+ // query for local .nord domain
395+ Some ( PayloadDestination :: Local {
396+ id : packet. get_id ( ) ,
397+ recursion_desired : packet. get_is_recursion_desirable ( ) == 1 ,
398+ query,
399+ } )
400+ } else {
401+ // not .nord, forward unchanged
402+ let forward = MessageRequest :: from_bytes ( payload) . map_err ( |_| {
403+ String :: from ( "Failed to build MessageRequest from request packet" )
404+ } ) ?;
405+ Some ( PayloadDestination :: Forward ( forward) )
406+ }
407+ }
408+ Err ( DnsParseError :: UnsupportedOpcode ( c) ) => {
409+ telio_log_warn ! ( "Unsupported DNS query Opcode: {c:?}" ) ;
410+ // still forward it as a fallback
411+ let forward = MessageRequest :: from_bytes ( payload) . map_err ( |_| {
412+ String :: from ( "Failed to build MessageRequest from request packet" )
413+ } ) ?;
414+ Some ( PayloadDestination :: Forward ( forward) )
415+ }
416+ Err ( e) => {
417+ // malformed DNS query
418+ return Err ( format ! ( "Failed to parse DNS payload: {e}" ) ) ;
419+ }
420+ } ;
352421
353422 Ok ( PayloadRequestInfo :: Udp {
354423 source_port : udp_request. get_source ( ) ,
355424 destination_port : udp_request. get_destination ( ) ,
356- dns_request : Some ( dns_request ) ,
425+ dns_request,
357426 } )
358427 }
359428}
@@ -397,12 +466,22 @@ impl IpRequestInfo {
397466 }
398467}
399468
469+ #[ allow( clippy:: large_enum_variant) ]
470+ enum PayloadDestination {
471+ Local {
472+ id : u16 ,
473+ recursion_desired : bool ,
474+ query : DnsQuery ,
475+ } ,
476+ Forward ( MessageRequest ) ,
477+ }
478+
400479#[ allow( clippy:: large_enum_variant) ]
401480enum PayloadRequestInfo {
402481 Udp {
403482 source_port : u16 ,
404483 destination_port : u16 ,
405- dns_request : Option < MessageRequest > ,
484+ dns_request : Option < PayloadDestination > ,
406485 } ,
407486 Tcp {
408487 source_port : u16 ,
@@ -692,11 +771,19 @@ impl NameServer for Arc<RwLock<LocalNameServer>> {
692771 records : & Records ,
693772 ttl_value : TtlValue ,
694773 ) -> Result < ( ) , String > {
695- let azone = Arc :: new ( AuthoritativeZone :: new ( zone, records, ttl_value) . await ?) ;
774+ if normalize_qname ( zone) == NORD_ZONE {
775+ let mut ns = self . write ( ) . await ;
776+ ns. nord_zone
777+ . upsert ( records, ttl_value)
778+ . map_err ( |e| format ! ( "Upsert failed: {e}" ) ) ?;
779+ }
696780
781+ // TODO: LLT-7054: Remove AuthoritativeZone once migration is fully validated
782+ let azone = Arc :: new ( AuthoritativeZone :: new ( zone, records, ttl_value) . await ?) ;
697783 self . zones_mut ( )
698784 . await
699785 . upsert ( LowerName :: from_str ( zone) ?, Box :: new ( azone) ) ;
786+
700787 Ok ( ( ) )
701788 }
702789
@@ -727,7 +814,8 @@ impl NameServer for Arc<RwLock<LocalNameServer>> {
727814
728815#[ cfg( test) ]
729816mod tests {
730- use crate :: zone:: Records ;
817+ use super :: * ;
818+ use crate :: zone:: { Records , NORD_ZONE } ;
731819 use hickory_server:: {
732820 authority:: MessageRequest ,
733821 proto:: {
@@ -739,8 +827,6 @@ mod tests {
739827 } ;
740828 use std:: { net:: Ipv4Addr , str:: FromStr } ;
741829
742- use super :: * ;
743-
744830 fn dns_request ( host : String ) -> Request {
745831 let mut question = Message :: new ( ) ;
746832 let mut query = Query :: new ( ) ;
@@ -767,7 +853,7 @@ mod tests {
767853 . await
768854 . unwrap ( ) ;
769855 nameserver
770- . upsert ( "nord" , & records, TtlValue ( 60 ) )
856+ . upsert ( NORD_ZONE , & records, TtlValue ( 60 ) )
771857 . await
772858 . unwrap ( ) ;
773859 let request = dns_request ( entry_name. clone ( ) ) ;
@@ -803,7 +889,7 @@ mod tests {
803889 . unwrap ( ) ;
804890 let raw_read_ptr1 = Arc :: as_ptr ( & nameserver. zones ( ) . await ) ;
805891 nameserver
806- . upsert ( "nord" , & records, TtlValue ( 60 ) )
892+ . upsert ( NORD_ZONE , & records, TtlValue ( 60 ) )
807893 . await
808894 . unwrap ( ) ;
809895 let raw_read_ptr2 = Arc :: as_ptr ( & nameserver. zones ( ) . await ) ;
@@ -818,7 +904,7 @@ mod tests {
818904
819905 let read_ptr3 = nameserver. zones ( ) . await ;
820906 nameserver
821- . upsert ( "nord2" , & records, TtlValue ( 60 ) )
907+ . upsert ( "nord2. " , & records, TtlValue ( 60 ) )
822908 . await
823909 . unwrap ( ) ;
824910 let raw_read_ptr4 = Arc :: as_ptr ( & nameserver. zones ( ) . await ) ;
@@ -841,7 +927,7 @@ mod tests {
841927 . await
842928 . unwrap ( ) ;
843929 nameserver
844- . upsert ( "nord." , & records, TtlValue ( 60 ) )
930+ . upsert ( NORD_ZONE , & records, TtlValue ( 60 ) )
845931 . await
846932 . unwrap ( ) ;
847933
0 commit comments