Skip to content

Commit c310c72

Browse files
committed
Add a MessageContext::DNSResolution to protect against probing
When we make a DNSSEC query with a reply path, we don't want to allow the DNS resolver to attempt to respond to various nodes to try to detect (through timining or other analysis) whether we were the one who made the query. Thus, we need to include a nonce in the context in our reply path, which we set up here by creating a new context type for DNS resolutions.
1 parent 355fcb4 commit c310c72

File tree

5 files changed

+40
-8
lines changed

5 files changed

+40
-8
lines changed

lightning/src/blinded_path/message.rs

+24
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,11 @@ pub enum MessageContext {
280280
///
281281
/// [`OffersMessage`]: crate::onion_message::offers::OffersMessage
282282
Offers(OffersContext),
283+
/// Represents a context for a blinded path used in a reply path when requesting a DNSSEC proof
284+
/// in a [`DNSResolverMessage`].
285+
///
286+
/// [`DNSResolverMessage`]: crate::onion_message::dns_resolution::DNSResolverMessage
287+
DNSResolver(DNSResolverContext),
283288
/// Context specific to a [`CustomOnionMessageHandler::CustomMessage`].
284289
///
285290
/// [`CustomOnionMessageHandler::CustomMessage`]: crate::onion_message::messenger::CustomOnionMessageHandler::CustomMessage
@@ -353,6 +358,7 @@ pub enum OffersContext {
353358
impl_writeable_tlv_based_enum!(MessageContext,
354359
{0, Offers} => (),
355360
{1, Custom} => (),
361+
{2, DNSResolver} => (),
356362
);
357363

358364
impl_writeable_tlv_based_enum!(OffersContext,
@@ -369,6 +375,24 @@ impl_writeable_tlv_based_enum!(OffersContext,
369375
},
370376
);
371377

378+
/// Contains a simple nonce for use in a blinded path's context.
379+
///
380+
/// Such a context is required when receiving a [`DNSSECProof`] message.
381+
///
382+
/// [`DNSSECProof`]: crate::onion_message::dns_resolution::DNSSECProof
383+
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
384+
pub struct DNSResolverContext {
385+
/// A nonce which uniquely describes a DNS resolution.
386+
///
387+
/// When we receive a DNSSEC proof message, we should check that it was sent over the blinded
388+
/// path we included in the request by comparing a stored nonce with this one.
389+
pub nonce: [u8; 16],
390+
}
391+
392+
impl_writeable_tlv_based!(DNSResolverContext, {
393+
(0, nonce, required),
394+
});
395+
372396
/// Construct blinded onion message hops for the given `intermediate_nodes` and `recipient_node_id`.
373397
pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
374398
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[MessageForwardNode],

lightning/src/ln/peer_handler.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
use bitcoin::constants::ChainHash;
1919
use bitcoin::secp256k1::{self, Secp256k1, SecretKey, PublicKey};
2020

21-
use crate::blinded_path::message::OffersContext;
21+
use crate::blinded_path::message::{DNSResolverContext, OffersContext};
2222
use crate::sign::{NodeSigner, Recipient};
2323
use crate::events::{MessageSendEvent, MessageSendEventsProvider};
2424
use crate::ln::types::ChannelId;
@@ -161,7 +161,7 @@ impl DNSResolverMessageHandler for IgnoringMessageHandler {
161161
) -> Option<(DNSResolverMessage, ResponseInstruction)> {
162162
None
163163
}
164-
fn dnssec_proof(&self, _message: DNSSECProof) {}
164+
fn dnssec_proof(&self, _message: DNSSECProof, _context: DNSResolverContext) {}
165165
}
166166
impl CustomOnionMessageHandler for IgnoringMessageHandler {
167167
type CustomMessage = Infallible;

lightning/src/onion_message/dns_resolution.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
1818
use dnssec_prover::rr::Name;
1919

20+
use crate::blinded_path::message::DNSResolverContext;
2021
use crate::io;
2122
use crate::ln::msgs::DecodeError;
2223
use crate::onion_message::messenger::{MessageSendInstructions, Responder, ResponseInstruction};
@@ -39,7 +40,7 @@ pub trait DNSResolverMessageHandler {
3940
/// Handle a [`DNSSECProof`] message (in response to a [`DNSSECQuery`] we presumably sent).
4041
///
4142
/// With this, we should be able to validate the DNS record we requested.
42-
fn dnssec_proof(&self, message: DNSSECProof);
43+
fn dnssec_proof(&self, message: DNSSECProof, context: DNSResolverContext);
4344

4445
/// Release any [`DNSResolverMessage`]s that need to be sent.
4546
fn release_pending_messages(&self) -> Vec<(DNSResolverMessage, MessageSendInstructions)> {

lightning/src/onion_message/functional_tests.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//! Onion message testing and test utilities live here.
1111
1212
use crate::blinded_path::EmptyNodeIdLookUp;
13-
use crate::blinded_path::message::{BlindedMessagePath, MessageForwardNode, MessageContext, OffersContext};
13+
use crate::blinded_path::message::{BlindedMessagePath, DNSResolverContext, MessageForwardNode, MessageContext, OffersContext};
1414
use crate::events::{Event, EventsProvider};
1515
use crate::ln::features::{ChannelFeatures, InitFeatures};
1616
use crate::ln::msgs::{self, DecodeError, OnionMessageHandler};
@@ -100,7 +100,7 @@ impl DNSResolverMessageHandler for TestDNSResolverMessageHandler {
100100
) -> Option<(DNSResolverMessage, ResponseInstruction)> {
101101
None
102102
}
103-
fn dnssec_proof(&self, _message: DNSSECProof) {}
103+
fn dnssec_proof(&self, _message: DNSSECProof, _context: DNSResolverContext) {}
104104
}
105105

106106
#[derive(Clone, Debug, PartialEq)]

lightning/src/onion_message/messenger.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,9 @@ where
994994
(ParsedOnionMessageContents::Custom(_), Some(MessageContext::Custom(_))) => {
995995
Ok(PeeledOnion::Receive(message, context, reply_path))
996996
}
997+
(ParsedOnionMessageContents::DNSResolver(_), Some(MessageContext::DNSResolver(_))) => {
998+
Ok(PeeledOnion::Receive(message, context, reply_path))
999+
}
9971000
_ => {
9981001
log_trace!(logger, "Received message was sent on a blinded path with the wrong context.");
9991002
Err(())
@@ -1604,7 +1607,7 @@ where
16041607
let context = match context {
16051608
None => None,
16061609
Some(MessageContext::Offers(context)) => Some(context),
1607-
Some(MessageContext::Custom(_)) => {
1610+
Some(_) => {
16081611
debug_assert!(false, "Shouldn't have triggered this case.");
16091612
return
16101613
}
@@ -1634,13 +1637,17 @@ where
16341637
}
16351638
},
16361639
ParsedOnionMessageContents::DNSResolver(DNSResolverMessage::DNSSECProof(msg)) => {
1637-
self.dns_resolver_handler.dnssec_proof(msg);
1640+
let context = match context {
1641+
Some(MessageContext::DNSResolver(context)) => context,
1642+
_ => return,
1643+
};
1644+
self.dns_resolver_handler.dnssec_proof(msg, context);
16381645
},
16391646
ParsedOnionMessageContents::Custom(msg) => {
16401647
let context = match context {
16411648
None => None,
16421649
Some(MessageContext::Custom(data)) => Some(data),
1643-
Some(MessageContext::Offers(_)) => {
1650+
Some(_) => {
16441651
debug_assert!(false, "Shouldn't have triggered this case.");
16451652
return
16461653
}

0 commit comments

Comments
 (0)