1#![deny(missing_docs)]
5#![deny(rustdoc::broken_intra_doc_links)]
6#![deny(rustdoc::private_intra_doc_links)]
7
8use std::net::SocketAddr;
9use std::ops::Deref;
10use std::sync::atomic::{AtomicUsize, Ordering};
11use std::sync::{Arc, Mutex};
12
13use dnssec_prover::query::build_txt_proof_async;
14
15use lightning::blinded_path::message::DNSResolverContext;
16use lightning::ln::peer_handler::IgnoringMessageHandler;
17use lightning::onion_message::dns_resolution::{
18 DNSResolverMessage, DNSResolverMessageHandler, DNSSECProof, DNSSECQuery,
19};
20use lightning::onion_message::messenger::{
21 MessageSendInstructions, Responder, ResponseInstruction,
22};
23
24use lightning_types::features::NodeFeatures;
25
26use tokio::runtime::Handle;
27
28#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))]
29const WE_REQUIRE_32_OR_64_BIT_USIZE: u8 = 424242;
30
31pub struct OMDomainResolver<PH: Deref>
34where
35 PH::Target: DNSResolverMessageHandler,
36{
37 state: Arc<OMResolverState>,
38 proof_handler: Option<PH>,
39 runtime_handle: Mutex<Option<Handle>>,
40}
41
42const MAX_PENDING_RESPONSES: usize = 1024;
43struct OMResolverState {
44 resolver: SocketAddr,
45 pending_replies: Mutex<Vec<(DNSResolverMessage, MessageSendInstructions)>>,
46 pending_query_count: AtomicUsize,
47}
48
49impl OMDomainResolver<IgnoringMessageHandler> {
50 pub fn ignoring_incoming_proofs(resolver: SocketAddr) -> Self {
55 Self::new(resolver, None)
56 }
57}
58
59impl<PH: Deref> OMDomainResolver<PH>
60where
61 PH::Target: DNSResolverMessageHandler,
62{
63 pub fn new(resolver: SocketAddr, proof_handler: Option<PH>) -> Self {
74 Self::with_runtime(resolver, proof_handler, Some(Handle::current()))
75 }
76
77 pub fn with_runtime(
87 resolver: SocketAddr, proof_handler: Option<PH>, runtime_handle: Option<Handle>,
88 ) -> Self {
89 Self {
90 state: Arc::new(OMResolverState {
91 resolver,
92 pending_replies: Mutex::new(Vec::new()),
93 pending_query_count: AtomicUsize::new(0),
94 }),
95 proof_handler,
96 runtime_handle: Mutex::new(runtime_handle),
97 }
98 }
99
100 pub fn set_runtime(&self, runtime_handle: Handle) {
102 *self.runtime_handle.lock().unwrap() = Some(runtime_handle);
103 }
104}
105
106impl<PH: Deref> DNSResolverMessageHandler for OMDomainResolver<PH>
107where
108 PH::Target: DNSResolverMessageHandler,
109{
110 fn handle_dnssec_proof(&self, proof: DNSSECProof, context: DNSResolverContext) {
111 if let Some(proof_handler) = &self.proof_handler {
112 proof_handler.handle_dnssec_proof(proof, context);
113 }
114 }
115
116 fn handle_dnssec_query(
117 &self, q: DNSSECQuery, responder_opt: Option<Responder>,
118 ) -> Option<(DNSResolverMessage, ResponseInstruction)> {
119 let responder = match responder_opt {
120 Some(responder) => responder,
121 None => return None,
122 };
123 let runtime = if let Some(runtime) = self.runtime_handle.lock().unwrap().clone() {
124 runtime
125 } else {
126 return None;
127 };
128 if self.state.pending_query_count.fetch_add(1, Ordering::Relaxed) > MAX_PENDING_RESPONSES {
129 self.state.pending_query_count.fetch_sub(1, Ordering::Relaxed);
130 return None;
131 }
132 let us = Arc::clone(&self.state);
133 runtime.spawn(async move {
134 if let Ok((proof, _ttl)) = build_txt_proof_async(us.resolver, &q.0).await {
135 let contents = DNSResolverMessage::DNSSECProof(DNSSECProof { name: q.0, proof });
136 let instructions = responder.respond().into_instructions();
137 us.pending_replies.lock().unwrap().push((contents, instructions));
138 us.pending_query_count.fetch_sub(1, Ordering::Relaxed);
139 }
140 });
141 None
142 }
143
144 fn provided_node_features(&self) -> NodeFeatures {
145 let mut features = NodeFeatures::empty();
146 features.set_dns_resolution_optional();
147 features
148 }
149
150 fn release_pending_messages(&self) -> Vec<(DNSResolverMessage, MessageSendInstructions)> {
151 core::mem::take(&mut *self.state.pending_replies.lock().unwrap())
152 }
153}
154
155#[cfg(test)]
156mod test {
157 use super::*;
158
159 use bitcoin::secp256k1::{self, PublicKey, Secp256k1};
160 use bitcoin::Block;
161
162 use lightning::blinded_path::message::{
163 BlindedMessagePath, MessageContext, MessageForwardNode,
164 };
165 use lightning::blinded_path::NodeIdLookUp;
166 use lightning::events::{Event, PaymentPurpose};
167 use lightning::ln::channelmanager::{OptionalOfferPaymentParams, PaymentId};
168 use lightning::ln::functional_test_utils::*;
169 use lightning::ln::msgs::{
170 BaseMessageHandler, ChannelMessageHandler, Init, OnionMessageHandler,
171 };
172 use lightning::ln::peer_handler::IgnoringMessageHandler;
173 use lightning::offers::offer::Offer;
174 use lightning::onion_message::dns_resolution::{HumanReadableName, OMNameResolver};
175 use lightning::onion_message::messenger::{
176 AOnionMessenger, Destination, MessageRouter, OnionMessagePath, OnionMessenger,
177 };
178 use lightning::sign::{KeysManager, NodeSigner, ReceiveAuthKey, Recipient};
179 use lightning::types::features::InitFeatures;
180 use lightning::types::payment::PaymentHash;
181 use lightning::util::logger::Logger;
182
183 use lightning::{commitment_signed_dance, expect_payment_claimed, get_htlc_update_msgs};
184 use lightning_types::string::UntrustedString;
185
186 use std::ops::Deref;
187 use std::sync::Mutex;
188 use std::time::{Duration, Instant, SystemTime};
189
190 struct TestLogger {
191 node: &'static str,
192 }
193 impl Logger for TestLogger {
194 fn log(&self, record: lightning::util::logger::Record) {
195 eprintln!("{}: {}", self.node, record.args);
196 }
197 }
198 impl Deref for TestLogger {
199 type Target = TestLogger;
200 fn deref(&self) -> &TestLogger {
201 self
202 }
203 }
204
205 struct DummyNodeLookup {}
206 impl NodeIdLookUp for DummyNodeLookup {
207 fn next_node_id(&self, _: u64) -> Option<PublicKey> {
208 None
209 }
210 }
211 impl Deref for DummyNodeLookup {
212 type Target = DummyNodeLookup;
213 fn deref(&self) -> &DummyNodeLookup {
214 self
215 }
216 }
217
218 struct DirectlyConnectedRouter {}
219 impl MessageRouter for DirectlyConnectedRouter {
220 fn find_path(
221 &self, _sender: PublicKey, _peers: Vec<PublicKey>, destination: Destination,
222 ) -> Result<OnionMessagePath, ()> {
223 Ok(OnionMessagePath {
224 destination,
225 first_node_addresses: Vec::new(),
226 intermediate_nodes: Vec::new(),
227 })
228 }
229
230 fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
231 &self, recipient: PublicKey, local_node_receive_key: ReceiveAuthKey,
232 context: MessageContext, _peers: Vec<MessageForwardNode>, secp_ctx: &Secp256k1<T>,
233 ) -> Result<Vec<BlindedMessagePath>, ()> {
234 let keys = KeysManager::new(&[0; 32], 42, 43, true);
235 Ok(vec![BlindedMessagePath::one_hop(
236 recipient,
237 local_node_receive_key,
238 context,
239 &keys,
240 secp_ctx,
241 )])
242 }
243 }
244 impl Deref for DirectlyConnectedRouter {
245 type Target = DirectlyConnectedRouter;
246 fn deref(&self) -> &DirectlyConnectedRouter {
247 self
248 }
249 }
250
251 struct URIResolver {
252 resolved_uri: Mutex<Option<(HumanReadableName, PaymentId, String)>>,
253 resolver: OMNameResolver,
254 pending_messages: Mutex<Vec<(DNSResolverMessage, MessageSendInstructions)>>,
255 }
256 impl DNSResolverMessageHandler for URIResolver {
257 fn handle_dnssec_query(
258 &self, _: DNSSECQuery, _: Option<Responder>,
259 ) -> Option<(DNSResolverMessage, ResponseInstruction)> {
260 panic!();
261 }
262
263 fn handle_dnssec_proof(&self, msg: DNSSECProof, context: DNSResolverContext) {
264 let mut proof = self.resolver.handle_dnssec_proof_for_uri(msg, context).unwrap();
265 assert_eq!(proof.0.len(), 1);
266 let payment = proof.0.pop().unwrap();
267 let mut result = Some((payment.0, payment.1, proof.1));
268 core::mem::swap(&mut *self.resolved_uri.lock().unwrap(), &mut result);
269 assert!(result.is_none());
270 }
271 fn release_pending_messages(&self) -> Vec<(DNSResolverMessage, MessageSendInstructions)> {
272 core::mem::take(&mut *self.pending_messages.lock().unwrap())
273 }
274 }
275
276 fn create_resolver() -> (impl AOnionMessenger, PublicKey) {
277 let resolver_keys = Arc::new(KeysManager::new(&[99; 32], 42, 43, true));
278 let resolver_logger = TestLogger { node: "resolver" };
279 let resolver = OMDomainResolver::ignoring_incoming_proofs("8.8.8.8:53".parse().unwrap());
280 let resolver = Arc::new(resolver);
281 (
282 OnionMessenger::new(
283 Arc::clone(&resolver_keys),
284 Arc::clone(&resolver_keys),
285 resolver_logger,
286 DummyNodeLookup {},
287 DirectlyConnectedRouter {},
288 IgnoringMessageHandler {},
289 IgnoringMessageHandler {},
290 Arc::clone(&resolver),
291 IgnoringMessageHandler {},
292 ),
293 resolver_keys.get_node_id(Recipient::Node).unwrap(),
294 )
295 }
296
297 fn get_om_init() -> Init {
298 let mut init_msg =
299 Init { features: InitFeatures::empty(), networks: None, remote_network_address: None };
300 init_msg.features.set_onion_messages_optional();
301 init_msg
302 }
303
304 #[tokio::test]
305 async fn resolution_test() {
306 let secp_ctx = Secp256k1::new();
307
308 let (resolver_messenger, resolver_id) = create_resolver();
309
310 let resolver_dest = Destination::Node(resolver_id);
311 let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
312
313 let payment_id = PaymentId([42; 32]);
314 let name = HumanReadableName::from_encoded("matt@mattcorallo.com").unwrap();
315
316 let payer_keys = Arc::new(KeysManager::new(&[2; 32], 42, 43, true));
317 let payer_logger = TestLogger { node: "payer" };
318 let payer_id = payer_keys.get_node_id(Recipient::Node).unwrap();
319 let payer = Arc::new(URIResolver {
320 resolved_uri: Mutex::new(None),
321 resolver: OMNameResolver::new(now as u32, 1),
322 pending_messages: Mutex::new(Vec::new()),
323 });
324 let payer_messenger = Arc::new(OnionMessenger::new(
325 Arc::clone(&payer_keys),
326 Arc::clone(&payer_keys),
327 payer_logger,
328 DummyNodeLookup {},
329 DirectlyConnectedRouter {},
330 IgnoringMessageHandler {},
331 IgnoringMessageHandler {},
332 Arc::clone(&payer),
333 IgnoringMessageHandler {},
334 ));
335
336 let init_msg = get_om_init();
337 payer_messenger.peer_connected(resolver_id, &init_msg, true).unwrap();
338 resolver_messenger.get_om().peer_connected(payer_id, &init_msg, false).unwrap();
339
340 let (msg, context) =
341 payer.resolver.resolve_name(payment_id, name.clone(), &*payer_keys).unwrap();
342 let query_context = MessageContext::DNSResolver(context);
343 let receive_key = payer_keys.get_receive_auth_key();
344 let reply_path = BlindedMessagePath::one_hop(
345 payer_id,
346 receive_key,
347 query_context,
348 &*payer_keys,
349 &secp_ctx,
350 );
351 payer.pending_messages.lock().unwrap().push((
352 DNSResolverMessage::DNSSECQuery(msg),
353 MessageSendInstructions::WithSpecifiedReplyPath {
354 destination: resolver_dest,
355 reply_path,
356 },
357 ));
358
359 let query = payer_messenger.next_onion_message_for_peer(resolver_id).unwrap();
360 resolver_messenger.get_om().handle_onion_message(payer_id, &query);
361
362 assert!(resolver_messenger.get_om().next_onion_message_for_peer(payer_id).is_none());
363 let start = Instant::now();
364 let response = loop {
365 tokio::time::sleep(Duration::from_millis(10)).await;
366 if let Some(msg) = resolver_messenger.get_om().next_onion_message_for_peer(payer_id) {
367 break msg;
368 }
369 assert!(start.elapsed() < Duration::from_secs(10), "Resolution took too long");
370 };
371
372 payer_messenger.handle_onion_message(resolver_id, &response);
373 let resolution = payer.resolved_uri.lock().unwrap().take().unwrap();
374 assert_eq!(resolution.0, name);
375 assert_eq!(resolution.1, payment_id);
376 assert!(resolution.2[.."bitcoin:".len()].eq_ignore_ascii_case("bitcoin:"));
377 }
378
379 async fn pay_offer_flow<'a, 'b, 'c>(
380 nodes: &[Node<'a, 'b, 'c>], resolver_messenger: &impl AOnionMessenger,
381 resolver_id: PublicKey, payer_id: PublicKey, payee_id: PublicKey, offer: Offer,
382 name: HumanReadableName, payment_id: PaymentId, payer_note: Option<String>,
383 resolvers: Vec<Destination>,
384 ) {
385 let proof_override = &nodes[0].node.testing_dnssec_proof_offer_resolution_override;
387 proof_override.lock().unwrap().insert(name.clone(), offer);
388 let amt = 42_000;
389 let mut opts = OptionalOfferPaymentParams::default();
390 opts.payer_note = payer_note.clone();
391 #[allow(deprecated)]
392 nodes[0]
393 .node
394 .pay_for_offer_from_human_readable_name(name, amt, payment_id, opts, resolvers)
395 .unwrap();
396
397 let query = nodes[0].onion_messenger.next_onion_message_for_peer(resolver_id).unwrap();
398 resolver_messenger.get_om().handle_onion_message(payer_id, &query);
399
400 assert!(resolver_messenger.get_om().next_onion_message_for_peer(payer_id).is_none());
401 let start = Instant::now();
402 let response = loop {
403 tokio::time::sleep(Duration::from_millis(10)).await;
404 if let Some(msg) = resolver_messenger.get_om().next_onion_message_for_peer(payer_id) {
405 break msg;
406 }
407 assert!(start.elapsed() < Duration::from_secs(10), "Resolution took too long");
408 };
409
410 nodes[0].onion_messenger.handle_onion_message(resolver_id, &response);
411
412 let invreq = nodes[0].onion_messenger.next_onion_message_for_peer(payee_id).unwrap();
413 nodes[1].onion_messenger.handle_onion_message(payer_id, &invreq);
414
415 let inv = nodes[1].onion_messenger.next_onion_message_for_peer(payer_id).unwrap();
416 nodes[0].onion_messenger.handle_onion_message(payee_id, &inv);
417
418 check_added_monitors(&nodes[0], 1);
419 let updates = get_htlc_update_msgs!(nodes[0], payee_id);
420 nodes[1].node.handle_update_add_htlc(payer_id, &updates.update_add_htlcs[0]);
421 commitment_signed_dance!(nodes[1], nodes[0], updates.commitment_signed, false);
422 expect_and_process_pending_htlcs(&nodes[1], false);
423
424 let claimable_events = nodes[1].node.get_and_clear_pending_events();
425 assert_eq!(claimable_events.len(), 1);
426 let our_payment_preimage;
427 if let Event::PaymentClaimable { purpose, amount_msat, .. } = &claimable_events[0] {
428 assert_eq!(*amount_msat, amt);
429 if let PaymentPurpose::Bolt12OfferPayment {
430 payment_preimage, payment_context, ..
431 } = purpose
432 {
433 our_payment_preimage = payment_preimage.unwrap();
434 nodes[1].node.claim_funds(our_payment_preimage);
435 let payment_hash: PaymentHash = our_payment_preimage.into();
436 expect_payment_claimed!(nodes[1], payment_hash, amt);
437 if let Some(note) = payer_note {
438 assert_eq!(
439 payment_context.invoice_request.payer_note_truncated,
440 Some(UntrustedString(note.into()))
441 );
442 } else {
443 assert_eq!(payment_context.invoice_request.payer_note_truncated, None);
444 }
445 } else {
446 panic!();
447 }
448 } else {
449 panic!();
450 }
451
452 check_added_monitors(&nodes[1], 1);
453 let mut updates = get_htlc_update_msgs!(nodes[1], payer_id);
454 nodes[0].node.handle_update_fulfill_htlc(payee_id, updates.update_fulfill_htlcs.remove(0));
455 commitment_signed_dance!(nodes[0], nodes[1], updates.commitment_signed, false);
456
457 expect_payment_sent(&nodes[0], our_payment_preimage, None, true, true);
458 }
459
460 #[tokio::test]
461 async fn end_to_end_test() {
462 let chanmon_cfgs = create_chanmon_cfgs(2);
463 let node_cfgs = create_node_cfgs_with_node_id_message_router(2, &chanmon_cfgs);
464 let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
465 let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
466
467 create_announced_chan_between_nodes(&nodes, 0, 1);
468
469 let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
472 let block = Block {
473 header: create_dummy_header(nodes[0].best_block_hash(), now as u32),
474 txdata: Vec::new(),
475 };
476 connect_block(&nodes[0], &block);
477 connect_block(&nodes[1], &block);
478
479 let payer_id = nodes[0].node.get_our_node_id();
480 let payee_id = nodes[1].node.get_our_node_id();
481
482 let (resolver_messenger, resolver_id) = create_resolver();
483 let init_msg = get_om_init();
484 nodes[0].onion_messenger.peer_connected(resolver_id, &init_msg, true).unwrap();
485 resolver_messenger.get_om().peer_connected(payer_id, &init_msg, false).unwrap();
486
487 let name = HumanReadableName::from_encoded("matt@mattcorallo.com").unwrap();
488
489 let bs_offer = nodes[1].node.create_offer_builder().unwrap().build().unwrap();
490 let resolvers = vec![Destination::Node(resolver_id)];
491
492 pay_offer_flow(
493 &nodes,
494 &resolver_messenger,
495 resolver_id,
496 payer_id,
497 payee_id,
498 bs_offer.clone(),
499 name.clone(),
500 PaymentId([42; 32]),
501 None,
502 resolvers.clone(),
503 )
504 .await;
505
506 pay_offer_flow(
508 &nodes,
509 &resolver_messenger,
510 resolver_id,
511 payer_id,
512 payee_id,
513 bs_offer,
514 name,
515 PaymentId([21; 32]),
516 Some("foo".into()),
517 resolvers,
518 )
519 .await;
520 }
521}