@@ -9,7 +9,7 @@ use std::net::SocketAddr;
99use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
1010use std:: sync:: { Arc , Mutex } ;
1111
12- use dnssec_prover:: query:: build_txt_proof_async;
12+ use dnssec_prover:: query:: { build_txt_proof_async, ProofBuildingError } ;
1313
1414use lightning:: blinded_path:: message:: DNSResolverContext ;
1515use lightning:: ln:: peer_handler:: IgnoringMessageHandler ;
@@ -127,11 +127,25 @@ impl<PH: DNSResolverMessageHandler> DNSResolverMessageHandler for OMDomainResolv
127127 }
128128 let us = Arc :: clone ( & self . state ) ;
129129 runtime. spawn ( async move {
130- if let Ok ( ( proof, _ttl) ) = build_txt_proof_async ( us. resolver , & q. 0 ) . await {
131- let contents = DNSResolverMessage :: DNSSECProof ( DNSSECProof { name : q. 0 , proof } ) ;
132- let instructions = responder. respond ( ) . into_instructions ( ) ;
133- us. pending_replies . lock ( ) . unwrap ( ) . push ( ( contents, instructions) ) ;
134- }
130+ let contents = match build_txt_proof_async ( us. resolver , & q. 0 ) . await {
131+ Ok ( ( proof, _ttl) ) => {
132+ DNSResolverMessage :: DNSSECProof ( DNSSECProof { name : q. 0 , proof } )
133+ } ,
134+ Err ( e) => {
135+ // We might get an Unauthenticated error if the DNS resolver does not support
136+ // DNSSEC, so we only set `definitely_unresolvable` if we get an NXDOMAIN.
137+ let definitely_unresolvable = matches ! (
138+ e. get_ref( ) . and_then( |e| e. downcast_ref:: <ProofBuildingError >( ) ) ,
139+ Some ( ProofBuildingError :: NoSuchName )
140+ ) ;
141+ DNSResolverMessage :: DNSSECError ( DNSSECError {
142+ name : q. 0 ,
143+ definitely_unresolvable,
144+ } )
145+ } ,
146+ } ;
147+ let instructions = responder. respond ( ) . into_instructions ( ) ;
148+ us. pending_replies . lock ( ) . unwrap ( ) . push ( ( contents, instructions) ) ;
135149 us. pending_query_count . fetch_sub ( 1 , Ordering :: Relaxed ) ;
136150 } ) ;
137151 None
@@ -217,6 +231,7 @@ mod test {
217231
218232 struct URIResolver {
219233 resolved_uri : Mutex < Option < ( HumanReadableName , PaymentId , String ) > > ,
234+ resolved_error : Mutex < Option < ( HumanReadableName , PaymentId , bool ) > > ,
220235 resolver : OMNameResolver ,
221236 pending_messages : Mutex < Vec < ( DNSResolverMessage , MessageSendInstructions ) > > ,
222237 }
@@ -236,7 +251,13 @@ mod test {
236251 assert ! ( result. is_none( ) ) ;
237252 }
238253 fn handle_dnssec_error ( & self , msg : DNSSECError , context : DNSResolverContext ) {
239- // TODO
254+ let definitely_unresolvable = msg. definitely_unresolvable ;
255+ let mut failed = self . resolver . handle_dnssec_error ( msg, context) ;
256+ assert_eq ! ( failed. len( ) , 1 ) ;
257+ let ( name, payment_id) = failed. pop ( ) . unwrap ( ) ;
258+ let mut result = Some ( ( name, payment_id, definitely_unresolvable) ) ;
259+ core:: mem:: swap ( & mut * self . resolved_error . lock ( ) . unwrap ( ) , & mut result) ;
260+ assert ! ( result. is_none( ) ) ;
240261 }
241262 fn release_pending_messages ( & self ) -> Vec < ( DNSResolverMessage , MessageSendInstructions ) > {
242263 core:: mem:: take ( & mut * self . pending_messages . lock ( ) . unwrap ( ) )
@@ -286,6 +307,7 @@ mod test {
286307 let payer_id = payer_keys. get_node_id ( Recipient :: Node ) . unwrap ( ) ;
287308 let payer = Arc :: new ( URIResolver {
288309 resolved_uri : Mutex :: new ( None ) ,
310+ resolved_error : Mutex :: new ( None ) ,
289311 resolver : OMNameResolver :: new ( now as u32 , 1 ) ,
290312 pending_messages : Mutex :: new ( Vec :: new ( ) ) ,
291313 } ) ;
@@ -331,6 +353,76 @@ mod test {
331353 assert ! ( resolution. 2 [ .."bitcoin:" . len( ) ] . eq_ignore_ascii_case( "bitcoin:" ) ) ;
332354 }
333355
356+ #[ tokio:: test]
357+ async fn resolution_failure_test ( ) {
358+ // Test that querying for a name which does not exist results in a `DNSSECError` with
359+ // `definitely_unresolvable` set being returned (rather than a `DNSSECProof`).
360+
361+ let ( resolver_messenger, resolver_id) = create_resolver ( ) ;
362+
363+ let resolver_dest = Destination :: Node ( resolver_id) ;
364+ let now = SystemTime :: now ( ) . duration_since ( SystemTime :: UNIX_EPOCH ) . unwrap ( ) . as_secs ( ) ;
365+
366+ let payment_id = PaymentId ( [ 43 ; 32 ] ) ;
367+ // `mattcorallo.com` is DNSSEC-signed, so a name which does not exist under it will result in
368+ // an authenticated NXDOMAIN, i.e. a definitely-unresolvable name.
369+ let name =
370+ HumanReadableName :: from_encoded ( "nonexistent-user-ldk-test@mattcorallo.com" ) . unwrap ( ) ;
371+
372+ let payer_keys = Arc :: new ( KeysManager :: new ( & [ 3 ; 32 ] , 42 , 43 , true ) ) ;
373+ let payer_logger = TestLogger { node : "payer" } ;
374+ let payer_id = payer_keys. get_node_id ( Recipient :: Node ) . unwrap ( ) ;
375+ let payer = Arc :: new ( URIResolver {
376+ resolved_uri : Mutex :: new ( None ) ,
377+ resolved_error : Mutex :: new ( None ) ,
378+ resolver : OMNameResolver :: new ( now as u32 , 1 ) ,
379+ pending_messages : Mutex :: new ( Vec :: new ( ) ) ,
380+ } ) ;
381+ let payer_messenger = Arc :: new ( OnionMessenger :: new (
382+ Arc :: clone ( & payer_keys) ,
383+ Arc :: clone ( & payer_keys) ,
384+ payer_logger,
385+ DummyNodeLookup { } ,
386+ DirectlyConnectedRouter { } ,
387+ IgnoringMessageHandler { } ,
388+ IgnoringMessageHandler { } ,
389+ Arc :: clone ( & payer) ,
390+ IgnoringMessageHandler { } ,
391+ ) ) ;
392+
393+ let init_msg = get_om_init ( ) ;
394+ payer_messenger. peer_connected ( resolver_id, & init_msg, true ) . unwrap ( ) ;
395+ resolver_messenger. get_om ( ) . peer_connected ( payer_id, & init_msg, false ) . unwrap ( ) ;
396+
397+ let messages = payer
398+ . resolver
399+ . resolve_name ( payment_id, name. clone ( ) , vec ! [ resolver_dest] , & * payer_keys)
400+ . unwrap ( ) ;
401+ payer. pending_messages . lock ( ) . unwrap ( ) . extend ( messages) ;
402+
403+ let query = payer_messenger. next_onion_message_for_peer ( resolver_id) . unwrap ( ) ;
404+ resolver_messenger. get_om ( ) . handle_onion_message ( payer_id, & query) ;
405+
406+ assert ! ( resolver_messenger. get_om( ) . next_onion_message_for_peer( payer_id) . is_none( ) ) ;
407+ let start = Instant :: now ( ) ;
408+ let response = loop {
409+ tokio:: time:: sleep ( Duration :: from_millis ( 10 ) ) . await ;
410+ if let Some ( msg) = resolver_messenger. get_om ( ) . next_onion_message_for_peer ( payer_id) {
411+ break msg;
412+ }
413+ assert ! ( start. elapsed( ) < Duration :: from_secs( 10 ) , "Resolution took too long" ) ;
414+ } ;
415+
416+ payer_messenger. handle_onion_message ( resolver_id, & response) ;
417+ let ( failed_name, failed_payment_id, definitely_unresolvable) =
418+ payer. resolved_error . lock ( ) . unwrap ( ) . take ( ) . unwrap ( ) ;
419+ assert_eq ! ( failed_name, name) ;
420+ assert_eq ! ( failed_payment_id, payment_id) ;
421+ assert ! ( definitely_unresolvable) ;
422+ // The failed resolution should have been removed from the resolver.
423+ assert ! ( payer. resolved_uri. lock( ) . unwrap( ) . is_none( ) ) ;
424+ }
425+
334426 #[ tokio:: test]
335427 async fn failed_query_does_not_leak_pending_counter ( ) {
336428 use std:: sync:: atomic:: Ordering ;
@@ -368,6 +460,7 @@ mod test {
368460 let payer_id = payer_keys. get_node_id ( Recipient :: Node ) . unwrap ( ) ;
369461 let payer = Arc :: new ( URIResolver {
370462 resolved_uri : Mutex :: new ( None ) ,
463+ resolved_error : Mutex :: new ( None ) ,
371464 resolver : OMNameResolver :: new ( now as u32 , 1 ) ,
372465 pending_messages : Mutex :: new ( Vec :: new ( ) ) ,
373466 } ) ;
0 commit comments