Skip to content

Commit 6b01547

Browse files
Drop OMs from disconnected peers in OnionMessenger
And refuse to forward OMs to disconnected peers
1 parent 90538f8 commit 6b01547

File tree

5 files changed

+74
-12
lines changed

5 files changed

+74
-12
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],
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;
@@ -1123,8 +1125,9 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
11231125
}
11241126

11251127
self.message_handler.route_handler.peer_connected(&their_node_id, &msg);
1126-
11271128
self.message_handler.chan_handler.peer_connected(&their_node_id, &msg);
1129+
self.message_handler.onion_message_handler.peer_connected(&their_node_id, &msg);
1130+
11281131
peer_lock.their_features = Some(msg.features);
11291132
return Ok(None);
11301133
} else if peer_lock.their_features.is_none() {
@@ -1685,6 +1688,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
16851688
}
16861689
descriptor.disconnect_socket();
16871690
self.message_handler.chan_handler.peer_disconnected(&node_id, false);
1691+
self.message_handler.onion_message_handler.peer_disconnected(&node_id, false);
16881692
}
16891693
}
16901694
}
@@ -1712,6 +1716,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
17121716
log_pubkey!(node_id), if no_connection_possible { "no " } else { "" });
17131717
self.node_id_to_descriptor.lock().unwrap().remove(&node_id);
17141718
self.message_handler.chan_handler.peer_disconnected(&node_id, no_connection_possible);
1719+
self.message_handler.onion_message_handler.peer_disconnected(&node_id, no_connection_possible);
17151720
}
17161721
}
17171722
};
@@ -1732,6 +1737,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
17321737
log_trace!(self.logger, "Disconnecting peer with id {} due to client request", node_id);
17331738
peers_lock.remove(&descriptor);
17341739
self.message_handler.chan_handler.peer_disconnected(&node_id, no_connection_possible);
1740+
self.message_handler.onion_message_handler.peer_disconnected(&node_id, no_connection_possible);
17351741
descriptor.disconnect_socket();
17361742
}
17371743
}
@@ -1747,6 +1753,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
17471753
if let Some(node_id) = peer.lock().unwrap().their_node_id {
17481754
log_trace!(self.logger, "Disconnecting peer with id {} due to client request to disconnect all peers", node_id);
17491755
self.message_handler.chan_handler.peer_disconnected(&node_id, false);
1756+
self.message_handler.onion_message_handler.peer_disconnected(&node_id, false);
17501757
}
17511758
descriptor.disconnect_socket();
17521759
}
@@ -1837,6 +1844,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
18371844
log_trace!(self.logger, "Disconnecting peer with id {} due to ping timeout", node_id);
18381845
self.node_id_to_descriptor.lock().unwrap().remove(&node_id);
18391846
self.message_handler.chan_handler.peer_disconnected(&node_id, false);
1847+
self.message_handler.onion_message_handler.peer_disconnected(&node_id, false);
18401848
}
18411849
}
18421850
}

lightning/src/onion_message/functional_tests.rs

+16-10
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,18 +35,26 @@ 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(mut path: Vec<MessengerNode>, expected_path_id: Option<[u8; 32]>) {
@@ -110,12 +119,9 @@ fn three_blinded_hops() {
110119
#[test]
111120
fn too_big_packet_error() {
112121
// 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);
122+
let nodes = create_nodes(2);
118123

124+
let hop_node_id = nodes[1].get_node_pk();
119125
let hops = [hop_node_id; 400];
120126
let err = nodes[0].messenger.send_onion_message(&hops, Destination::Node(hop_node_id)).unwrap_err();
121127
assert_eq!(err, SendError::TooBigPacket);

lightning/src/onion_message/messenger.rs

+37
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ pub struct OnionMessenger<Signer: Sign, K: Deref, L: Deref>
8585
keys_manager: K,
8686
logger: L,
8787
pending_messages: Mutex<HashMap<PublicKey, Vec<msgs::OnionMessage>>>,
88+
peer_set: Mutex<HashSet<PublicKey>>,
8889
secp_ctx: Secp256k1<secp256k1::All>,
8990
// Coming soon:
9091
// invoice_handler: InvoiceHandler,
@@ -121,6 +122,8 @@ pub enum SendError {
121122
/// The provided [`Destination`] was an invalid [`BlindedRoute`], due to having fewer than two
122123
/// blinded hops.
123124
TooFewBlindedHops,
125+
/// Our next-hop peer was offline or does not support onion message forwarding.
126+
InvalidFirstHop,
124127
}
125128

126129
impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
@@ -134,6 +137,7 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
134137
secp_ctx.seeded_randomize(&keys_manager.get_secure_random_bytes());
135138
OnionMessenger {
136139
keys_manager,
140+
peer_set: Mutex::new(HashSet::new()),
137141
pending_messages: Mutex::new(HashMap::new()),
138142
secp_ctx,
139143
logger,
@@ -159,6 +163,9 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
159163
(introduction_node_id, blinding_point),
160164
}
161165
};
166+
if !self.peer_connected(&introduction_node_id) {
167+
return Err(SendError::InvalidFirstHop)
168+
}
162169
let (packet_payloads, packet_keys) = packet_payloads_and_keys(
163170
&self.secp_ctx, intermediate_nodes, destination, &blinding_secret)
164171
.map_err(|e| SendError::Secp256k1(e))?;
@@ -178,6 +185,11 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
178185
Ok(())
179186
}
180187

188+
fn peer_connected(&self, peer_node_id: &PublicKey) -> bool {
189+
let peers = self.peer_set.lock().unwrap();
190+
peers.contains(peer_node_id)
191+
}
192+
181193
#[cfg(test)]
182194
pub(super) fn release_pending_msgs(&self) -> HashMap<PublicKey, Vec<msgs::OnionMessage>> {
183195
let mut pending_msgs = self.pending_messages.lock().unwrap();
@@ -229,6 +241,10 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessageHandler for OnionMessenger<Si
229241
Ok((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
230242
next_node_id, next_blinding_override
231243
})), Some((next_hop_hmac, new_packet_bytes)))) => {
244+
if !self.peer_connected(&next_node_id) {
245+
log_trace!(self.logger, "Dropping onion message to disconnected peer {:?}", next_node_id);
246+
return
247+
}
232248
// TODO: we need to check whether `next_node_id` is our node, in which case this is a dummy
233249
// blinded hop and this onion message is destined for us. In this situation, we should keep
234250
// unwrapping the onion layers to get to the final payload. Since we don't have the option
@@ -281,6 +297,27 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessageHandler for OnionMessenger<Si
281297
},
282298
};
283299
}
300+
301+
fn peer_connected(&self, their_node_id: &PublicKey, init: &msgs::Init) {
302+
if init.features.supports_onion_messages() {
303+
let mut peers = self.peer_set.lock().unwrap();
304+
peers.insert(their_node_id.clone());
305+
}
306+
}
307+
308+
fn peer_disconnected(&self, their_node_id: &PublicKey, no_connection_possible: bool) {
309+
{
310+
let mut peers = self.peer_set.lock().unwrap();
311+
peers.remove(their_node_id);
312+
}
313+
314+
let mut pending_msgs = self.pending_messages.lock().unwrap();
315+
if no_connection_possible {
316+
pending_msgs.remove(their_node_id);
317+
} else if let Some(msgs) = pending_msgs.get_mut(their_node_id) {
318+
msgs.clear();
319+
}
320+
}
284321
}
285322

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

0 commit comments

Comments
 (0)