mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-03-15 15:39:09 +01:00
Add DNS(SEC) query and proof messages and onion message handler
This creates the initial DNSSEC proof and query messages in a new module in `onion_message`, as well as a new message handler to handle them. In the coming commits, a default implementation will be added which verifies DNSSEC proofs which can be used to resolve BIP 353 URIs without relying on anything outside of the lightning network.
This commit is contained in:
parent
151a8a1aaf
commit
1cf0393056
5 changed files with 165 additions and 2 deletions
|
@ -43,8 +43,10 @@ lightning-invoice = { version = "0.32.0", path = "../lightning-invoice", default
|
|||
bech32 = { version = "0.9.1", default-features = false }
|
||||
bitcoin = { version = "0.32.2", default-features = false, features = ["secp-recovery"] }
|
||||
|
||||
dnssec-prover = { version = "0.6", default-features = false }
|
||||
hashbrown = { version = "0.13", default-features = false }
|
||||
possiblyrandom = { version = "0.2", path = "../possiblyrandom", default-features = false }
|
||||
|
||||
regex = { version = "1.5.6", optional = true }
|
||||
backtrace = { version = "0.3", optional = true }
|
||||
|
||||
|
|
|
@ -285,7 +285,9 @@ pub enum MessageContext {
|
|||
/// [`AsyncPaymentsMessage`]: crate::onion_message::async_payments::AsyncPaymentsMessage
|
||||
AsyncPayments(AsyncPaymentsContext),
|
||||
/// Represents a context for a blinded path used in a reply path when requesting a DNSSEC proof
|
||||
/// in a `DNSResolverMessage`.
|
||||
/// in a [`DNSResolverMessage`].
|
||||
///
|
||||
/// [`DNSResolverMessage`]: crate::onion_message::dns_resolution::DNSResolverMessage
|
||||
DNSResolver(DNSResolverContext),
|
||||
/// Context specific to a [`CustomOnionMessageHandler::CustomMessage`].
|
||||
///
|
||||
|
@ -434,7 +436,9 @@ impl_writeable_tlv_based_enum!(AsyncPaymentsContext,
|
|||
|
||||
/// Contains a simple nonce for use in a blinded path's context.
|
||||
///
|
||||
/// Such a context is required when receiving a `DNSSECProof` message.
|
||||
/// Such a context is required when receiving a [`DNSSECProof`] message.
|
||||
///
|
||||
/// [`DNSSECProof`]: crate::onion_message::dns_resolution::DNSSECProof
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct DNSResolverContext {
|
||||
/// A nonce which uniquely describes a DNS resolution.
|
||||
|
|
146
lightning/src/onion_message/dns_resolution.rs
Normal file
146
lightning/src/onion_message/dns_resolution.rs
Normal file
|
@ -0,0 +1,146 @@
|
|||
// This file is Copyright its original authors, visible in version control
|
||||
// history.
|
||||
//
|
||||
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
|
||||
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
|
||||
// You may not use this file except in accordance with one or both of these
|
||||
// licenses.
|
||||
|
||||
//! This module defines message handling for DNSSEC proof fetching using [bLIP 32].
|
||||
//!
|
||||
//! It contains [`DNSResolverMessage`]s as well as a [`DNSResolverMessageHandler`] trait to handle
|
||||
//! such messages using an [`OnionMessenger`].
|
||||
//!
|
||||
//! [bLIP 32]: https://github.com/lightning/blips/blob/master/blip-0032.md
|
||||
//! [`OnionMessenger`]: super::messenger::OnionMessenger
|
||||
|
||||
use dnssec_prover::rr::Name;
|
||||
|
||||
use crate::blinded_path::message::DNSResolverContext;
|
||||
use crate::io;
|
||||
use crate::ln::msgs::DecodeError;
|
||||
use crate::onion_message::messenger::{MessageSendInstructions, Responder, ResponseInstruction};
|
||||
use crate::onion_message::packet::OnionMessageContents;
|
||||
use crate::prelude::*;
|
||||
use crate::util::ser::{Hostname, Readable, ReadableArgs, Writeable, Writer};
|
||||
|
||||
/// A handler for an [`OnionMessage`] containing a DNS(SEC) query or a DNSSEC proof
|
||||
///
|
||||
/// [`OnionMessage`]: crate::ln::msgs::OnionMessage
|
||||
pub trait DNSResolverMessageHandler {
|
||||
/// Handle a [`DNSSECQuery`] message.
|
||||
///
|
||||
/// If we provide DNS resolution services to third parties, we should respond with a
|
||||
/// [`DNSSECProof`] message.
|
||||
fn handle_dnssec_query(
|
||||
&self, message: DNSSECQuery, responder: Option<Responder>,
|
||||
) -> Option<(DNSResolverMessage, ResponseInstruction)>;
|
||||
|
||||
/// Handle a [`DNSSECProof`] message (in response to a [`DNSSECQuery`] we presumably sent).
|
||||
///
|
||||
/// With this, we should be able to validate the DNS record we requested.
|
||||
fn handle_dnssec_proof(&self, message: DNSSECProof, context: DNSResolverContext);
|
||||
|
||||
/// Release any [`DNSResolverMessage`]s that need to be sent.
|
||||
fn release_pending_messages(&self) -> Vec<(DNSResolverMessage, MessageSendInstructions)> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
/// An enum containing the possible onion messages which are used uses to request and receive
|
||||
/// DNSSEC proofs.
|
||||
pub enum DNSResolverMessage {
|
||||
/// A query requesting a DNSSEC proof
|
||||
DNSSECQuery(DNSSECQuery),
|
||||
/// A response containing a DNSSEC proof
|
||||
DNSSECProof(DNSSECProof),
|
||||
}
|
||||
|
||||
const DNSSEC_QUERY_TYPE: u64 = 65536;
|
||||
const DNSSEC_PROOF_TYPE: u64 = 65538;
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
/// A message which is sent to a DNSSEC prover requesting a DNSSEC proof for the given name.
|
||||
pub struct DNSSECQuery(pub Name);
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
/// A message which is sent in response to [`DNSSECQuery`] containing a DNSSEC proof.
|
||||
pub struct DNSSECProof {
|
||||
/// The name which the query was for. The proof may not contain a DNS RR for exactly this name
|
||||
/// if it contains a wildcard RR which contains this name instead.
|
||||
pub name: Name,
|
||||
/// An [RFC 9102 DNSSEC AuthenticationChain] providing a DNSSEC proof.
|
||||
///
|
||||
/// [RFC 9102 DNSSEC AuthenticationChain]: https://www.rfc-editor.org/rfc/rfc9102.html#name-dnssec-authentication-chain
|
||||
pub proof: Vec<u8>,
|
||||
}
|
||||
|
||||
impl DNSResolverMessage {
|
||||
/// Returns whether `tlv_type` corresponds to a TLV record for DNS Resolvers.
|
||||
pub fn is_known_type(tlv_type: u64) -> bool {
|
||||
match tlv_type {
|
||||
DNSSEC_QUERY_TYPE | DNSSEC_PROOF_TYPE => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Writeable for DNSResolverMessage {
|
||||
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
|
||||
match self {
|
||||
Self::DNSSECQuery(DNSSECQuery(q)) => {
|
||||
(q.as_str().len() as u8).write(w)?;
|
||||
w.write_all(&q.as_str().as_bytes())
|
||||
},
|
||||
Self::DNSSECProof(DNSSECProof { name, proof }) => {
|
||||
(name.as_str().len() as u8).write(w)?;
|
||||
w.write_all(&name.as_str().as_bytes())?;
|
||||
proof.write(w)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ReadableArgs<u64> for DNSResolverMessage {
|
||||
fn read<R: io::Read>(r: &mut R, message_type: u64) -> Result<Self, DecodeError> {
|
||||
match message_type {
|
||||
DNSSEC_QUERY_TYPE => {
|
||||
let s = Hostname::read(r)?;
|
||||
let name = s.try_into().map_err(|_| DecodeError::InvalidValue)?;
|
||||
Ok(DNSResolverMessage::DNSSECQuery(DNSSECQuery(name)))
|
||||
},
|
||||
DNSSEC_PROOF_TYPE => {
|
||||
let s = Hostname::read(r)?;
|
||||
let name = s.try_into().map_err(|_| DecodeError::InvalidValue)?;
|
||||
let proof = Readable::read(r)?;
|
||||
Ok(DNSResolverMessage::DNSSECProof(DNSSECProof { name, proof }))
|
||||
},
|
||||
_ => Err(DecodeError::InvalidValue),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OnionMessageContents for DNSResolverMessage {
|
||||
#[cfg(c_bindings)]
|
||||
fn msg_type(&self) -> String {
|
||||
match self {
|
||||
DNSResolverMessage::DNSSECQuery(_) => "DNS(SEC) Query".to_string(),
|
||||
DNSResolverMessage::DNSSECProof(_) => "DNSSEC Proof".to_string(),
|
||||
}
|
||||
}
|
||||
#[cfg(not(c_bindings))]
|
||||
fn msg_type(&self) -> &'static str {
|
||||
match self {
|
||||
DNSResolverMessage::DNSSECQuery(_) => "DNS(SEC) Query",
|
||||
DNSResolverMessage::DNSSECProof(_) => "DNSSEC Proof",
|
||||
}
|
||||
}
|
||||
fn tlv_type(&self) -> u64 {
|
||||
match self {
|
||||
DNSResolverMessage::DNSSECQuery(_) => DNSSEC_QUERY_TYPE,
|
||||
DNSResolverMessage::DNSSECProof(_) => DNSSEC_PROOF_TYPE,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
//! [`OnionMessenger`]: self::messenger::OnionMessenger
|
||||
|
||||
pub mod async_payments;
|
||||
pub mod dns_resolution;
|
||||
pub mod messenger;
|
||||
pub mod offers;
|
||||
pub mod packet;
|
||||
|
|
|
@ -37,6 +37,9 @@ use bitcoin::hashes::hmac::Hmac;
|
|||
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
|
||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||
use bitcoin::hash_types::{Txid, BlockHash};
|
||||
|
||||
use dnssec_prover::rr::Name;
|
||||
|
||||
use core::time::Duration;
|
||||
use crate::chain::ClaimId;
|
||||
use crate::ln::msgs::DecodeError;
|
||||
|
@ -1551,6 +1554,13 @@ impl Readable for Hostname {
|
|||
}
|
||||
}
|
||||
|
||||
impl TryInto<Name> for Hostname {
|
||||
type Error = ();
|
||||
fn try_into(self) -> Result<Name, ()> {
|
||||
Name::try_from(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// This is not exported to bindings users as `Duration`s are simply mapped as ints.
|
||||
impl Writeable for Duration {
|
||||
#[inline]
|
||||
|
|
Loading…
Add table
Reference in a new issue