Skip to content

Commit a0997ed

Browse files
Support custom onion messages
In ser_macros, we now allow decode_tlv_stream to decode 1 custom TLV within a specified range of TLV types. We also need to fail to deserialize if there is more than 1 TLV in that specified range, otherwise peers could waste our processing time. This change is needed to support offers and async payment onion messages, for the above peers-can-waste-cpu reason.
1 parent a031ff9 commit a0997ed

File tree

6 files changed

+112
-58
lines changed

6 files changed

+112
-58
lines changed

fuzz/src/onion_message.rs

+9-8
Large diffs are not rendered by default.

lightning/src/onion_message/functional_tests.rs

+22-14
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
use chain::keysinterface::{KeysInterface, Recipient};
1313
use ln::features::InitFeatures;
1414
use ln::msgs::{self, OnionMessageHandler};
15-
use super::{BlindedRoute, Destination, OnionMessenger, SendError};
15+
use super::{BlindedRoute, Destination, OnionMessenger, SendError, Tlv};
1616
use util::enforcing_trait_impls::EnforcingSigner;
1717
use util::test_utils;
1818

@@ -80,103 +80,111 @@ fn pass_along_path(path: &Vec<MessengerNode>, expected_path_id: Option<[u8; 32]>
8080
#[test]
8181
fn one_hop() {
8282
let nodes = create_nodes(2);
83+
let test_tlv = Tlv { tag: 4242, value: vec![42; 32] };
8384

84-
nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), None).unwrap();
85+
nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), test_tlv, None).unwrap();
8586
pass_along_path(&nodes, None);
8687
}
8788

8889
#[test]
8990
fn two_unblinded_hops() {
9091
let nodes = create_nodes(3);
92+
let test_tlv = Tlv { tag: 4242, value: vec![42; 32] };
9193

92-
nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk()], Destination::Node(nodes[2].get_node_pk()), None).unwrap();
94+
nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk()], Destination::Node(nodes[2].get_node_pk()), test_tlv, None).unwrap();
9395
pass_along_path(&nodes, None);
9496
}
9597

9698
#[test]
9799
fn two_unblinded_two_blinded() {
98100
let nodes = create_nodes(5);
101+
let test_tlv = Tlv { tag: 4242, value: vec![42; 32] };
99102

100103
let secp_ctx = Secp256k1::new();
101104
let blinded_route = BlindedRoute::new(&[nodes[3].get_node_pk(), nodes[4].get_node_pk()], &*nodes[4].keys_manager, &secp_ctx).unwrap();
102105

103-
nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::BlindedRoute(blinded_route), None).unwrap();
106+
nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::BlindedRoute(blinded_route), test_tlv, None).unwrap();
104107
pass_along_path(&nodes, None);
105108
}
106109

107110
#[test]
108111
fn three_blinded_hops() {
109112
let nodes = create_nodes(4);
113+
let test_tlv = Tlv { tag: 4242, value: vec![42; 32] };
110114

111115
let secp_ctx = Secp256k1::new();
112116
let blinded_route = BlindedRoute::new(&[nodes[1].get_node_pk(), nodes[2].get_node_pk(), nodes[3].get_node_pk()], &*nodes[3].keys_manager, &secp_ctx).unwrap();
113117

114-
nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), None).unwrap();
118+
nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), test_tlv, None).unwrap();
115119
pass_along_path(&nodes, None);
116120
}
117121

118122
#[test]
119123
fn too_big_packet_error() {
120124
// Make sure we error as expected if a packet is too big to send.
121125
let nodes = create_nodes(2);
126+
let test_tlv = Tlv { tag: 4242, value: vec![42; 32] };
122127

123128
let hop_node_id = nodes[1].get_node_pk();
124129
let hops = [hop_node_id; 400];
125-
let err = nodes[0].messenger.send_onion_message(&hops, Destination::Node(hop_node_id), None).unwrap_err();
130+
let err = nodes[0].messenger.send_onion_message(&hops, Destination::Node(hop_node_id), test_tlv, None).unwrap_err();
126131
assert_eq!(err, SendError::TooBigPacket);
127132
}
128133

129134
#[test]
130135
fn invalid_blinded_route_error() {
131136
// Make sure we error as expected if a provided blinded route has 0 or 1 hops.
132137
let nodes = create_nodes(3);
138+
let test_tlv = Tlv { tag: 4242, value: vec![42; 32] };
133139

134140
// 0 hops
135141
let secp_ctx = Secp256k1::new();
136142
let mut blinded_route = BlindedRoute::new(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap();
137143
blinded_route.blinded_hops.clear();
138-
let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), None).unwrap_err();
144+
let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), test_tlv.clone(), None).unwrap_err();
139145
assert_eq!(err, SendError::TooFewBlindedHops);
140146

141147
// 1 hop
142148
let mut blinded_route = BlindedRoute::new(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap();
143149
blinded_route.blinded_hops.remove(0);
144150
assert_eq!(blinded_route.blinded_hops.len(), 1);
145-
let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), None).unwrap_err();
151+
let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), test_tlv, None).unwrap_err();
146152
assert_eq!(err, SendError::TooFewBlindedHops);
147153
}
148154

149155
#[test]
150156
fn reply_path() {
151157
let nodes = create_nodes(4);
158+
let test_tlv = Tlv { tag: 4242, value: vec![42; 32] };
152159
let secp_ctx = Secp256k1::new();
153160

154161
// Destination::Node
155162
let reply_path = BlindedRoute::new(&[nodes[2].get_node_pk(), nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap();
156-
nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::Node(nodes[3].get_node_pk()), Some(reply_path)).unwrap();
163+
nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::Node(nodes[3].get_node_pk()), test_tlv.clone(), Some(reply_path)).unwrap();
157164
pass_along_path(&nodes, None);
158165
// Make sure the last node successfully decoded the reply path.
159166
nodes[3].logger.assert_log_contains(
160167
"lightning::onion_message::messenger".to_string(),
161-
format!("Received an onion message with path_id: None and reply_path").to_string(), 1);
168+
format!("Received an onion message with path_id None and a reply_path").to_string(), 1);
162169

163170
// Destination::BlindedRoute
164171
let blinded_route = BlindedRoute::new(&[nodes[1].get_node_pk(), nodes[2].get_node_pk(), nodes[3].get_node_pk()], &*nodes[3].keys_manager, &secp_ctx).unwrap();
165172
let reply_path = BlindedRoute::new(&[nodes[2].get_node_pk(), nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap();
166173

167-
nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), Some(reply_path)).unwrap();
174+
nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), test_tlv, Some(reply_path)).unwrap();
168175
pass_along_path(&nodes, None);
169176
nodes[3].logger.assert_log_contains(
170177
"lightning::onion_message::messenger".to_string(),
171-
format!("Received an onion message with path_id: None and reply_path").to_string(), 2);
178+
format!("Received an onion message with path_id None and a reply_path").to_string(), 2);
172179
}
173180

174181
#[test]
175182
fn peer_buffer_full() {
176183
let nodes = create_nodes(2);
184+
let test_tlv = Tlv { tag: 4242, value: vec![42; 32] };
177185
for _ in 0..188 { // Based on MAX_PER_PEER_BUFFER_SIZE in OnionMessenger
178-
nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), None).unwrap();
186+
nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), test_tlv.clone(), None).unwrap();
179187
}
180-
let err = nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), None).unwrap_err();
188+
let err = nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), test_tlv, None).unwrap_err();
181189
assert_eq!(err, SendError::BufferFull);
182190
}

lightning/src/onion_message/messenger.rs

+25-13
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ use ln::features::{InitFeatures, NodeFeatures};
2020
use ln::msgs::{self, OnionMessageHandler};
2121
use ln::onion_utils;
2222
use super::blinded_route::{BlindedRoute, ForwardTlvs, ReceiveTlvs};
23+
pub use super::packet::Tlv;
2324
use super::packet::{BIG_PACKET_HOP_DATA_LEN, ForwardControlTlvs, Packet, Payload, ReceiveControlTlvs, SMALL_PACKET_HOP_DATA_LEN};
2425
use super::utils;
2526
use util::events::OnionMessageProvider;
2627
use util::logger::Logger;
2728
use util::ser::Writeable;
2829

30+
use core::mem;
2931
use core::ops::Deref;
3032
use sync::{Arc, Mutex};
3133
use prelude::*;
@@ -41,7 +43,7 @@ use prelude::*;
4143
/// # use bitcoin::hashes::_export::_core::time::Duration;
4244
/// # use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
4345
/// # use lightning::chain::keysinterface::{InMemorySigner, KeysManager, KeysInterface};
44-
/// # use lightning::onion_message::{BlindedRoute, Destination, OnionMessenger};
46+
/// # use lightning::onion_message::{BlindedRoute, Destination, OnionMessenger, Tlv};
4547
/// # use lightning::util::logger::{Logger, Record};
4648
/// # use std::sync::Arc;
4749
/// # struct FakeLogger {};
@@ -63,20 +65,25 @@ use prelude::*;
6365
/// // ChannelManager.
6466
/// let onion_messenger = OnionMessenger::new(&keys_manager, logger);
6567
///
66-
/// // Send an empty onion message to a node id.
68+
/// // Send an custom onion message to a node id.
6769
/// let intermediate_hops = [hop_node_id1, hop_node_id2];
6870
/// let reply_path = None;
69-
/// onion_messenger.send_onion_message(&intermediate_hops, Destination::Node(destination_node_id), reply_path);
71+
/// # let your_tlv_type = 4242;
72+
/// # let your_message_bytes = vec![42; 32];
73+
/// let message = Tlv { tag: your_tlv_type, value: your_message_bytes };
74+
/// onion_messenger.send_onion_message(&intermediate_hops, Destination::Node(destination_node_id), message, reply_path);
7075
///
7176
/// // Create a blinded route to yourself, for someone to send an onion message to.
7277
/// # let your_node_id = hop_node_id1;
7378
/// let hops = [hop_node_id3, hop_node_id4, your_node_id];
7479
/// let blinded_route = BlindedRoute::new(&hops, &keys_manager, &secp_ctx).unwrap();
7580
///
76-
/// // Send an empty onion message to a blinded route.
81+
/// // Send a custom onion message to a blinded route.
7782
/// # let intermediate_hops = [hop_node_id1, hop_node_id2];
7883
/// let reply_path = None;
79-
/// onion_messenger.send_onion_message(&intermediate_hops, Destination::BlindedRoute(blinded_route), reply_path);
84+
/// # let your_message_bytes = vec![42; 32];
85+
/// let message = Tlv { tag: your_tlv_type, value: your_message_bytes };
86+
/// onion_messenger.send_onion_message(&intermediate_hops, Destination::BlindedRoute(blinded_route), message, reply_path);
8087
/// ```
8188
///
8289
/// [offers]: <https://github.com/lightning/bolts/pull/798>
@@ -147,9 +154,9 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
147154
}
148155
}
149156

150-
/// Send an empty onion message to `destination`, routing it through `intermediate_nodes`.
157+
/// Send an onion message with payload `message` to `destination`, routing it through `intermediate_nodes`.
151158
/// See [`OnionMessenger`] for example usage.
152-
pub fn send_onion_message(&self, intermediate_nodes: &[PublicKey], destination: Destination, reply_path: Option<BlindedRoute>) -> Result<(), SendError> {
159+
pub fn send_onion_message(&self, intermediate_nodes: &[PublicKey], destination: Destination, message: Tlv, reply_path: Option<BlindedRoute>) -> Result<(), SendError> {
153160
if let Destination::BlindedRoute(BlindedRoute { ref blinded_hops, .. }) = destination {
154161
if blinded_hops.len() < 2 {
155162
return Err(SendError::TooFewBlindedHops);
@@ -167,7 +174,7 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
167174
}
168175
};
169176
let (packet_payloads, packet_keys) = packet_payloads_and_keys(
170-
&self.secp_ctx, intermediate_nodes, destination, reply_path, &blinding_secret)
177+
&self.secp_ctx, intermediate_nodes, destination, message, reply_path, &blinding_secret)
171178
.map_err(|e| SendError::Secp256k1(e))?;
172179

173180
let prng_seed = self.keys_manager.get_secure_random_bytes();
@@ -256,11 +263,11 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessageHandler for OnionMessenger<Si
256263
msg.onion_routing_packet.hmac, control_tlvs_ss)
257264
{
258265
Ok((Payload::Receive {
259-
control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id }), reply_path,
266+
message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id }), reply_path,
260267
}, None)) => {
261268
log_info!(self.logger,
262-
"Received an onion message with path_id: {:02x?} and {}reply_path",
263-
path_id, if reply_path.is_some() { "" } else { "no " });
269+
"Received an onion message with path_id {:02x?} and {} reply_path: {:?}",
270+
path_id, if reply_path.is_some() { "a" } else { "no" }, message);
264271
},
265272
Ok((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
266273
next_node_id, next_blinding_override
@@ -396,8 +403,8 @@ pub type SimpleRefOnionMessenger<'a, 'b, L> = OnionMessenger<InMemorySigner, &'a
396403
/// Construct onion packet payloads and keys for sending an onion message along the given
397404
/// `unblinded_path` to the given `destination`.
398405
fn packet_payloads_and_keys<T: secp256k1::Signing + secp256k1::Verification>(
399-
secp_ctx: &Secp256k1<T>, unblinded_path: &[PublicKey], destination: Destination, mut reply_path:
400-
Option<BlindedRoute>, session_priv: &SecretKey
406+
secp_ctx: &Secp256k1<T>, unblinded_path: &[PublicKey], destination: Destination, mut message: Tlv,
407+
mut reply_path: Option<BlindedRoute>, session_priv: &SecretKey
401408
) -> Result<(Vec<(Payload, [u8; 32])>, Vec<onion_utils::OnionKeys>), secp256k1::Error> {
402409
let num_hops = unblinded_path.len() + destination.num_hops();
403410
let mut payloads = Vec::with_capacity(num_hops);
@@ -440,9 +447,13 @@ fn packet_payloads_and_keys<T: secp256k1::Signing + secp256k1::Verification>(
440447
control_tlvs_ss));
441448
blinded_path_idx += 1;
442449
} else if let Some(encrypted_payload) = enc_payload_opt {
450+
let mut msg = Tlv { tag: message.tag, value: Vec::new() };
451+
// Used to get around the compiler's "use of moved value" error
452+
mem::swap(&mut msg.value, &mut message.value);
443453
payloads.push((Payload::Receive {
444454
control_tlvs: ReceiveControlTlvs::Blinded(encrypted_payload),
445455
reply_path: reply_path.take(),
456+
message: msg,
446457
}, control_tlvs_ss));
447458
}
448459

@@ -462,6 +473,7 @@ fn packet_payloads_and_keys<T: secp256k1::Signing + secp256k1::Verification>(
462473
payloads.push((Payload::Receive {
463474
control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id: None, }),
464475
reply_path: reply_path.take(),
476+
message,
465477
}, control_tlvs_ss));
466478
}
467479

lightning/src/onion_message/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ mod functional_tests;
2929

3030
// Re-export structs so they can be imported with just the `onion_message::` module prefix.
3131
pub use self::blinded_route::{BlindedRoute, BlindedHop};
32-
pub use self::messenger::{Destination, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
32+
pub use self::messenger::{Destination, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger, Tlv};
3333
pub(crate) use self::packet::Packet;

lightning/src/onion_message/packet.rs

+41-17
Original file line numberDiff line numberDiff line change
@@ -99,18 +99,18 @@ pub(super) enum Payload {
9999
Receive {
100100
control_tlvs: ReceiveControlTlvs,
101101
reply_path: Option<BlindedRoute>,
102-
// Coming soon:
103-
// message: Message,
102+
message: Tlv,
104103
}
105104
}
106105

107-
// Coming soon:
108-
// enum Message {
109-
// InvoiceRequest(InvoiceRequest),
110-
// Invoice(Invoice),
111-
// InvoiceError(InvoiceError),
112-
// CustomMessage<T>,
113-
// }
106+
#[derive(Clone, Debug)]
107+
///
108+
pub struct Tlv {
109+
///
110+
pub tag: u64,
111+
///
112+
pub value: Vec<u8>,
113+
}
114114

115115
/// Forward control TLVs in their blinded and unblinded form.
116116
pub(super) enum ForwardControlTlvs {
@@ -141,11 +141,13 @@ impl Writeable for (Payload, [u8; 32]) {
141141
})
142142
},
143143
Payload::Receive {
144-
control_tlvs: ReceiveControlTlvs::Blinded(encrypted_bytes), reply_path
144+
control_tlvs: ReceiveControlTlvs::Blinded(encrypted_bytes), reply_path,
145+
message: Tlv { tag, value, },
145146
} => {
146147
encode_varint_length_prefixed_tlv!(w, {
147148
(2, reply_path, option),
148-
(4, encrypted_bytes, vec_type)
149+
(4, encrypted_bytes, vec_type),
150+
(*tag, value, vec_type)
149151
})
150152
},
151153
Payload::Forward(ForwardControlTlvs::Unblinded(control_tlvs)) => {
@@ -156,30 +158,45 @@ impl Writeable for (Payload, [u8; 32]) {
156158
},
157159
Payload::Receive {
158160
control_tlvs: ReceiveControlTlvs::Unblinded(control_tlvs), reply_path,
161+
message: Tlv { tag, value, },
159162
} => {
160163
let write_adapter = ChaChaPolyWriteAdapter::new(self.1, &control_tlvs);
161164
encode_varint_length_prefixed_tlv!(w, {
162165
(2, reply_path, option),
163-
(4, write_adapter, required)
166+
(4, write_adapter, required),
167+
(*tag, value, vec_type)
164168
})
165169
},
166170
}
167171
Ok(())
168172
}
169173
}
170174

171-
// Uses the provided secret to simultaneously decode and decrypt the control TLVs.
175+
// Uses the provided secret to simultaneously decode and decrypt the control TLVs and data TLV.
172176
impl ReadableArgs<SharedSecret> for Payload {
173177
fn read<R: Read>(r: &mut R, encrypted_tlvs_ss: SharedSecret) -> Result<Self, DecodeError> {
174178
let v: BigSize = Readable::read(r)?;
175179
let mut rd = FixedLengthReader::new(r, v.0);
176180
let mut reply_path: Option<BlindedRoute> = None;
177181
let mut read_adapter: Option<ChaChaPolyReadAdapter<ControlTlvs>> = None;
178182
let rho = onion_utils::gen_rho_from_shared_secret(&encrypted_tlvs_ss.secret_bytes());
183+
let (mut message_type, mut message_bytes) = (None, None);
184+
let mut decode_custom_tlv = |msg_type, mut msg_reader: &mut FixedLengthReader<&mut &mut FixedLengthReader<&mut R>>| {
185+
if msg_type >= 64 {
186+
// Don't allow reading more than one data TLV from an onion message.
187+
if message_bytes.is_some() || message_type.is_some() {
188+
return Err(DecodeError::InvalidValue)
189+
}
190+
message_type = Some(msg_type);
191+
decode_tlv!(msg_reader, message_bytes, vec_type);
192+
return Ok(true)
193+
}
194+
Ok(false)
195+
};
179196
decode_tlv_stream!(&mut rd, {
180197
(2, reply_path, option),
181-
(4, read_adapter, (option: LengthReadableArgs, rho))
182-
});
198+
(4, read_adapter, (option: LengthReadableArgs, rho)),
199+
}, decode_custom_tlv);
183200
rd.eat_remaining().map_err(|_| DecodeError::ShortRead)?;
184201

185202
match read_adapter {
@@ -188,8 +205,15 @@ impl ReadableArgs<SharedSecret> for Payload {
188205
Ok(Payload::Forward(ForwardControlTlvs::Unblinded(tlvs)))
189206
},
190207
Some(ChaChaPolyReadAdapter { readable: ControlTlvs::Receive(tlvs)}) => {
191-
Ok(Payload::Receive { control_tlvs: ReceiveControlTlvs::Unblinded(tlvs), reply_path })
192-
},
208+
if message_type.is_none() || message_bytes.is_none() {
209+
return Err(DecodeError::InvalidValue)
210+
}
211+
Ok(Payload::Receive {
212+
control_tlvs: ReceiveControlTlvs::Unblinded(tlvs),
213+
reply_path,
214+
message: Tlv { tag: message_type.unwrap(), value: message_bytes.unwrap() },
215+
})
216+
}
193217
}
194218
}
195219
}

0 commit comments

Comments
 (0)