Skip to content

Commit ec1af89

Browse files
Refuse to send and forward OMs to disconnected peers
We also refuse to connect to peers that don't advertise onion message forwarding support. However, we don't always enforce this in fuzzing, to maximize coverage.
1 parent f49e04d commit ec1af89

File tree

5 files changed

+71
-14
lines changed

5 files changed

+71
-14
lines changed

lightning/src/ln/features.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,11 @@ mod sealed {
433433
define_feature!(27, ShutdownAnySegwit, [InitContext, NodeContext],
434434
"Feature flags for `opt_shutdown_anysegwit`.", set_shutdown_any_segwit_optional,
435435
set_shutdown_any_segwit_required, supports_shutdown_anysegwit, requires_shutdown_anysegwit);
436+
// We do not yet advertise the onion messages feature bit, but we need to detect when peers
437+
// support it.
438+
define_feature!(39, OnionMessages, [InitContext, NodeContext],
439+
"Feature flags for onion message forwarding.", set_onion_messages_optional,
440+
set_onion_messages_required, supports_onion_messages, requires_onion_messages);
436441
define_feature!(45, ChannelType, [InitContext, NodeContext],
437442
"Feature flags for `option_channel_type`.", set_channel_type_optional,
438443
set_channel_type_required, supports_channel_type, requires_channel_type);
@@ -767,7 +772,7 @@ impl<T: sealed::GossipQueries> Features<T> {
767772

768773
impl<T: sealed::InitialRoutingSync> Features<T> {
769774
// We are no longer setting initial_routing_sync now that gossip_queries
770-
// is enabled. This feature is ignored by a peer when gossip_queries has
775+
// is enabled. This feature is ignored by a peer when gossip_queries has
771776
// been negotiated.
772777
#[cfg(test)]
773778
pub(crate) fn clear_initial_routing_sync(&mut self) {

lightning/src/ln/msgs.rs

+6
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,12 @@ pub trait RoutingMessageHandler : MessageSendEventsProvider {
949949
pub trait OnionMessageHandler : OnionMessageProvider {
950950
/// Handle an incoming onion_message message from the given peer.
951951
fn handle_onion_message(&self, peer_node_id: &PublicKey, msg: &OnionMessage);
952+
/// Called when a connection is established with a peer. Can be used to track which peers
953+
/// advertise onion message support and are online.
954+
fn peer_connected(&self, their_node_id: &PublicKey, init: &Init);
955+
/// Indicates a connection to the peer failed/an existing connection was lost. Allows handlers to
956+
/// drop and refuse to forward onion messages to this peer.
957+
fn peer_disconnected(&self, their_node_id: &PublicKey, no_connection_possible: bool);
952958
}
953959

954960
mod fuzzy_internal_msgs {

lightning/src/ln/peer_handler.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ impl OnionMessageProvider for IgnoringMessageHandler {
8181
}
8282
impl OnionMessageHandler for IgnoringMessageHandler {
8383
fn handle_onion_message(&self, _their_node_id: &PublicKey, _msg: &msgs::OnionMessage) {}
84+
fn peer_connected(&self, _their_node_id: &PublicKey, _init: &msgs::Init) {}
85+
fn peer_disconnected(&self, _their_node_id: &PublicKey, _no_connection_possible: bool) {}
8486
}
8587
impl Deref for IgnoringMessageHandler {
8688
type Target = IgnoringMessageHandler;
@@ -1173,8 +1175,9 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
11731175
}
11741176

11751177
self.message_handler.route_handler.peer_connected(&their_node_id, &msg);
1176-
11771178
self.message_handler.chan_handler.peer_connected(&their_node_id, &msg);
1179+
self.message_handler.onion_message_handler.peer_connected(&their_node_id, &msg);
1180+
11781181
peer_lock.their_features = Some(msg.features);
11791182
return Ok(None);
11801183
} else if peer_lock.their_features.is_none() {
@@ -1729,6 +1732,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
17291732
}
17301733
descriptor.disconnect_socket();
17311734
self.message_handler.chan_handler.peer_disconnected(&node_id, false);
1735+
self.message_handler.onion_message_handler.peer_disconnected(&node_id, false);
17321736
}
17331737
}
17341738
}
@@ -1756,6 +1760,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
17561760
log_pubkey!(node_id), if no_connection_possible { "no " } else { "" });
17571761
self.node_id_to_descriptor.lock().unwrap().remove(&node_id);
17581762
self.message_handler.chan_handler.peer_disconnected(&node_id, no_connection_possible);
1763+
self.message_handler.onion_message_handler.peer_disconnected(&node_id, no_connection_possible);
17591764
}
17601765
}
17611766
};
@@ -1776,6 +1781,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
17761781
log_trace!(self.logger, "Disconnecting peer with id {} due to client request", node_id);
17771782
peers_lock.remove(&descriptor);
17781783
self.message_handler.chan_handler.peer_disconnected(&node_id, no_connection_possible);
1784+
self.message_handler.onion_message_handler.peer_disconnected(&node_id, no_connection_possible);
17791785
descriptor.disconnect_socket();
17801786
}
17811787
}
@@ -1791,6 +1797,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
17911797
if let Some(node_id) = peer.lock().unwrap().their_node_id {
17921798
log_trace!(self.logger, "Disconnecting peer with id {} due to client request to disconnect all peers", node_id);
17931799
self.message_handler.chan_handler.peer_disconnected(&node_id, false);
1800+
self.message_handler.onion_message_handler.peer_disconnected(&node_id, false);
17941801
}
17951802
descriptor.disconnect_socket();
17961803
}
@@ -1881,6 +1888,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
18811888
log_trace!(self.logger, "Disconnecting peer with id {} due to ping timeout", node_id);
18821889
self.node_id_to_descriptor.lock().unwrap().remove(&node_id);
18831890
self.message_handler.chan_handler.peer_disconnected(&node_id, false);
1891+
self.message_handler.onion_message_handler.peer_disconnected(&node_id, false);
18841892
}
18851893
}
18861894
}

lightning/src/onion_message/functional_tests.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010
//! Onion message testing and test utilities live here.
1111
1212
use chain::keysinterface::{KeysInterface, Recipient};
13-
use ln::msgs::OnionMessageHandler;
13+
use ln::features::InitFeatures;
14+
use ln::msgs::{self, OnionMessageHandler};
1415
use super::{BlindedRoute, Destination, OnionMessenger, SendError};
1516
use util::enforcing_trait_impls::EnforcingSigner;
1617
use util::test_utils;
1718

1819
use bitcoin::network::constants::Network;
19-
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
20+
use bitcoin::secp256k1::{PublicKey, Secp256k1};
2021

2122
use sync::Arc;
2223

@@ -34,26 +35,33 @@ impl MessengerNode {
3435
}
3536

3637
fn create_nodes(num_messengers: u8) -> Vec<MessengerNode> {
37-
let mut res = Vec::new();
38+
let mut nodes = Vec::new();
3839
for i in 0..num_messengers {
3940
let logger = Arc::new(test_utils::TestLogger::with_id(format!("node {}", i)));
4041
let seed = [i as u8; 32];
4142
let keys_manager = Arc::new(test_utils::TestKeysInterface::new(&seed, Network::Testnet));
42-
res.push(MessengerNode {
43+
nodes.push(MessengerNode {
4344
keys_manager: keys_manager.clone(),
4445
messenger: OnionMessenger::new(keys_manager, logger.clone()),
4546
logger,
4647
});
4748
}
48-
res
49+
for idx in 0..num_messengers - 1 {
50+
let i = idx as usize;
51+
let mut features = InitFeatures::known();
52+
features.set_onion_messages_optional();
53+
let init_msg = msgs::Init { features, remote_network_address: None };
54+
nodes[i].messenger.peer_connected(&nodes[i + 1].get_node_pk(), &init_msg.clone());
55+
nodes[i + 1].messenger.peer_connected(&nodes[i].get_node_pk(), &init_msg.clone());
56+
}
57+
nodes
4958
}
5059

5160
fn pass_along_path(path: &Vec<MessengerNode>, expected_path_id: Option<[u8; 32]>) {
5261
let mut prev_node = &path[0];
5362
let num_nodes = path.len();
5463
for (idx, node) in path.into_iter().skip(1).enumerate() {
5564
let events = prev_node.messenger.release_pending_msgs();
56-
assert_eq!(events.len(), 1);
5765
let onion_msg = {
5866
let msgs = events.get(&node.get_node_pk()).unwrap();
5967
assert_eq!(msgs.len(), 1);
@@ -110,12 +118,9 @@ fn three_blinded_hops() {
110118
#[test]
111119
fn too_big_packet_error() {
112120
// Make sure we error as expected if a packet is too big to send.
113-
let nodes = create_nodes(1);
114-
115-
let hop_secret = SecretKey::from_slice(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap();
116-
let secp_ctx = Secp256k1::new();
117-
let hop_node_id = PublicKey::from_secret_key(&secp_ctx, &hop_secret);
121+
let nodes = create_nodes(2);
118122

123+
let hop_node_id = nodes[1].get_node_pk();
119124
let hops = [hop_node_id; 400];
120125
let err = nodes[0].messenger.send_onion_message(&hops, Destination::Node(hop_node_id), None).unwrap_err();
121126
assert_eq!(err, SendError::TooBigPacket);

lightning/src/onion_message/messenger.rs

+34-1
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ pub enum SendError {
120120
/// The provided [`Destination`] was an invalid [`BlindedRoute`], due to having fewer than two
121121
/// blinded hops.
122122
TooFewBlindedHops,
123+
/// Our next-hop peer was offline or does not support onion message forwarding.
124+
InvalidFirstHop,
123125
}
124126

125127
impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
@@ -158,6 +160,9 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
158160
(introduction_node_id, blinding_point),
159161
}
160162
};
163+
if !self.peer_is_connected(&introduction_node_id) {
164+
return Err(SendError::InvalidFirstHop)
165+
}
161166
let (packet_payloads, packet_keys) = packet_payloads_and_keys(
162167
&self.secp_ctx, intermediate_nodes, destination, reply_path, &blinding_secret)
163168
.map_err(|e| SendError::Secp256k1(e))?;
@@ -177,11 +182,20 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
177182
Ok(())
178183
}
179184

185+
fn peer_is_connected(&self, peer_node_id: &PublicKey) -> bool {
186+
self.pending_messages.lock().unwrap().contains_key(peer_node_id)
187+
}
188+
180189
#[cfg(test)]
181190
pub(super) fn release_pending_msgs(&self) -> HashMap<PublicKey, VecDeque<msgs::OnionMessage>> {
182191
let mut pending_msgs = self.pending_messages.lock().unwrap();
183192
let mut msgs = HashMap::new();
184-
core::mem::swap(&mut *pending_msgs, &mut msgs);
193+
// We don't want to disconnect the peers by removing them entirely from the original map, so we
194+
// swap the pending message buffers individually.
195+
for (peer_node_id, pending_messages) in &mut *pending_msgs {
196+
msgs.insert(*peer_node_id, VecDeque::new());
197+
core::mem::swap(pending_messages, msgs.get_mut(&peer_node_id).unwrap());
198+
}
185199
msgs
186200
}
187201
}
@@ -230,6 +244,13 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessageHandler for OnionMessenger<Si
230244
Ok((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
231245
next_node_id, next_blinding_override
232246
})), Some((next_hop_hmac, new_packet_bytes)))) => {
247+
if !self.peer_is_connected(&next_node_id) {
248+
#[cfg(not(fuzzing))]
249+
{
250+
log_trace!(self.logger, "Dropping onion message to disconnected peer {:?}", next_node_id);
251+
return
252+
}
253+
}
233254
// TODO: we need to check whether `next_node_id` is our node, in which case this is a dummy
234255
// blinded hop and this onion message is destined for us. In this situation, we should keep
235256
// unwrapping the onion layers to get to the final payload. Since we don't have the option
@@ -285,6 +306,18 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessageHandler for OnionMessenger<Si
285306
},
286307
};
287308
}
309+
310+
fn peer_connected(&self, their_node_id: &PublicKey, init: &msgs::Init) {
311+
if init.features.supports_onion_messages() {
312+
let mut peers = self.pending_messages.lock().unwrap();
313+
peers.insert(their_node_id.clone(), VecDeque::new());
314+
}
315+
}
316+
317+
fn peer_disconnected(&self, their_node_id: &PublicKey, _no_connection_possible: bool) {
318+
let mut pending_msgs = self.pending_messages.lock().unwrap();
319+
pending_msgs.remove(their_node_id);
320+
}
288321
}
289322

290323
impl<Signer: Sign, K: Deref, L: Deref> OnionMessageProvider for OnionMessenger<Signer, K, L>

0 commit comments

Comments
 (0)