Correctly verify and forward excess data post-signature in signed announcement messages
[[bin]]
name = "msg_error_message_target"
-path = "fuzz_targets/msg_error_message_target.rs"
+path = "fuzz_targets/msg_targets/msg_error_message_target.rs"
[[bin]]
name = "msg_update_add_htlc_target"
-path = "fuzz_targets/msg_update_add_htlc_target.rs"
+path = "fuzz_targets/msg_targets/msg_update_add_htlc_target.rs"
[[bin]]
name = "msg_accept_channel_target"
[[bin]]
name = "msg_channel_reestablish_target"
path = "fuzz_targets/msg_targets/msg_channel_reestablish_target.rs"
+
+[[bin]]
+name = "msg_announcement_signatures_target"
+path = "fuzz_targets/msg_targets/msg_announcement_signatures_target.rs"
+
+[[bin]]
+name = "msg_channel_announcement_target"
+path = "fuzz_targets/msg_targets/msg_channel_announcement_target.rs"
+
+[[bin]]
+name = "msg_channel_update_target"
+path = "fuzz_targets/msg_targets/msg_channel_update_target.rs"
+
+[[bin]]
+name = "msg_decoded_onion_error_packet_target"
+path = "fuzz_targets/msg_targets/msg_decoded_onion_error_packet_target.rs"
+
+[[bin]]
+name = "msg_init_target"
+path = "fuzz_targets/msg_targets/msg_init_target.rs"
+
+[[bin]]
+name = "msg_node_announcement_target"
+path = "fuzz_targets/msg_targets/msg_node_announcement_target.rs"
+
+[[bin]]
+name = "msg_onion_hop_data_target"
+path = "fuzz_targets/msg_targets/msg_onion_hop_data_target.rs"
Ok(msg) => msg,
Err(e) => match e {
msgs::DecodeError::UnknownRealmByte => return,
+ msgs::DecodeError::UnknownRequiredFeature => return,
msgs::DecodeError::BadPublicKey => return,
msgs::DecodeError::BadSignature => return,
msgs::DecodeError::BadText => return,
Ok(msg) => msg,
Err(e) => match e {
msgs::DecodeError::UnknownRealmByte => return,
+ msgs::DecodeError::UnknownRequiredFeature => return,
msgs::DecodeError::BadPublicKey => return,
msgs::DecodeError::BadSignature => return,
msgs::DecodeError::BadText => return,
+++ /dev/null
-extern crate lightning;
-
-use lightning::ln::msgs;
-use lightning::util::reset_rng_state;
-
-use lightning::ln::msgs::{MsgEncodable, MsgDecodable};
-
-#[inline]
-pub fn do_test(data: &[u8]) {
- reset_rng_state();
- if let Ok(msg) = msgs::ErrorMessage::decode(data){
- let enc = msg.encode();
- assert_eq!(&data[0..32], &enc[0..32]);
- assert_eq!(&data[34..enc.len()], &enc[34..]);
- }
-}
-
-#[cfg(feature = "afl")]
-#[macro_use] extern crate afl;
-#[cfg(feature = "afl")]
-fn main() {
- fuzz!(|data| {
- do_test(data);
- });
-}
-
-#[cfg(feature = "honggfuzz")]
-#[macro_use] extern crate honggfuzz;
-#[cfg(feature = "honggfuzz")]
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-extern crate hex;
-#[cfg(test)]
-mod tests {
- #[test]
- fn duplicate_crash() {
- super::do_test(&::hex::decode("00").unwrap());
- }
-}
-for target in CommitmentSigned FundingCreated FundingLocked FundingSigned OpenChannel RevokeAndACK Shutdown UpdateFailHTLC UpdateFailMalformedHTLC UpdateFee UpdateFulfillHTLC AcceptChannel ClosingSigned ChannelReestablish; do
- tn=$(echo $target | sed 's/\([a-z0-9]\)\([A-Z]\)/\1_\2/g')
+#!/bin/sh
+
+GEN_TEST() {
+ tn=$(echo $1 | sed 's/\([a-z0-9]\)\([A-Z]\)/\1_\2/g')
fn=msg_$(echo $tn | tr '[:upper:]' '[:lower:]')_target.rs
- cat msg_target_template.txt | sed s/MSG_TARGET/$target/ > $fn
-done
+ cat msg_target_template.txt | sed s/MSG_TARGET/$1/ | sed "s/TEST_MSG/$2/" | sed "s/EXTRA_ARGS/$3/" > $fn
+}
+
+GEN_TEST AcceptChannel test_msg ""
+GEN_TEST AnnouncementSignatures test_msg ""
+GEN_TEST ChannelReestablish test_msg ""
+GEN_TEST ClosingSigned test_msg ""
+GEN_TEST CommitmentSigned test_msg ""
+GEN_TEST DecodedOnionErrorPacket test_msg ""
+GEN_TEST FundingCreated test_msg ""
+GEN_TEST FundingLocked test_msg ""
+GEN_TEST FundingSigned test_msg ""
+GEN_TEST Init test_msg ""
+GEN_TEST OpenChannel test_msg ""
+GEN_TEST RevokeAndACK test_msg ""
+GEN_TEST Shutdown test_msg ""
+GEN_TEST UpdateFailHTLC test_msg ""
+GEN_TEST UpdateFailMalformedHTLC test_msg ""
+GEN_TEST UpdateFee test_msg ""
+GEN_TEST UpdateFulfillHTLC test_msg ""
+
+GEN_TEST ChannelAnnouncement test_msg_exact ""
+GEN_TEST ChannelUpdate test_msg_exact ""
+GEN_TEST NodeAnnouncement test_msg_exact ""
+
+GEN_TEST UpdateAddHTLC test_msg_hole ", 85, 33"
+GEN_TEST ErrorMessage test_msg_hole ", 32, 2"
+GEN_TEST OnionHopData test_msg_hole ", 1+8+8+4, 12"
--- /dev/null
+// This file is auto-generated by gen_target.sh based on msg_target_template.txt
+// To modify it, modify msg_target_template.txt and run gen_target.sh instead.
+
+extern crate lightning;
+
+use lightning::ln::msgs;
+use lightning::util::reset_rng_state;
+
+use lightning::ln::msgs::{MsgEncodable, MsgDecodable};
+
+mod utils;
+
+#[inline]
+pub fn do_test(data: &[u8]) {
+ reset_rng_state();
+ test_msg!(msgs::AnnouncementSignatures, data);
+}
+
+#[cfg(feature = "afl")]
+#[macro_use] extern crate afl;
+#[cfg(feature = "afl")]
+fn main() {
+ fuzz!(|data| {
+ do_test(data);
+ });
+}
+
+#[cfg(feature = "honggfuzz")]
+#[macro_use] extern crate honggfuzz;
+#[cfg(feature = "honggfuzz")]
+fn main() {
+ loop {
+ fuzz!(|data| {
+ do_test(data);
+ });
+ }
+}
+
+extern crate hex;
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn duplicate_crash() {
+ super::do_test(&::hex::decode("00").unwrap());
+ }
+}
--- /dev/null
+// This file is auto-generated by gen_target.sh based on msg_target_template.txt
+// To modify it, modify msg_target_template.txt and run gen_target.sh instead.
+
+extern crate lightning;
+
+use lightning::ln::msgs;
+use lightning::util::reset_rng_state;
+
+use lightning::ln::msgs::{MsgEncodable, MsgDecodable};
+
+mod utils;
+
+#[inline]
+pub fn do_test(data: &[u8]) {
+ reset_rng_state();
+ test_msg_exact!(msgs::ChannelAnnouncement, data);
+}
+
+#[cfg(feature = "afl")]
+#[macro_use] extern crate afl;
+#[cfg(feature = "afl")]
+fn main() {
+ fuzz!(|data| {
+ do_test(data);
+ });
+}
+
+#[cfg(feature = "honggfuzz")]
+#[macro_use] extern crate honggfuzz;
+#[cfg(feature = "honggfuzz")]
+fn main() {
+ loop {
+ fuzz!(|data| {
+ do_test(data);
+ });
+ }
+}
+
+extern crate hex;
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn duplicate_crash() {
+ super::do_test(&::hex::decode("00").unwrap());
+ }
+}
--- /dev/null
+// This file is auto-generated by gen_target.sh based on msg_target_template.txt
+// To modify it, modify msg_target_template.txt and run gen_target.sh instead.
+
+extern crate lightning;
+
+use lightning::ln::msgs;
+use lightning::util::reset_rng_state;
+
+use lightning::ln::msgs::{MsgEncodable, MsgDecodable};
+
+mod utils;
+
+#[inline]
+pub fn do_test(data: &[u8]) {
+ reset_rng_state();
+ test_msg_exact!(msgs::ChannelUpdate, data);
+}
+
+#[cfg(feature = "afl")]
+#[macro_use] extern crate afl;
+#[cfg(feature = "afl")]
+fn main() {
+ fuzz!(|data| {
+ do_test(data);
+ });
+}
+
+#[cfg(feature = "honggfuzz")]
+#[macro_use] extern crate honggfuzz;
+#[cfg(feature = "honggfuzz")]
+fn main() {
+ loop {
+ fuzz!(|data| {
+ do_test(data);
+ });
+ }
+}
+
+extern crate hex;
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn duplicate_crash() {
+ super::do_test(&::hex::decode("00").unwrap());
+ }
+}
--- /dev/null
+// This file is auto-generated by gen_target.sh based on msg_target_template.txt
+// To modify it, modify msg_target_template.txt and run gen_target.sh instead.
+
+extern crate lightning;
+
+use lightning::ln::msgs;
+use lightning::util::reset_rng_state;
+
+use lightning::ln::msgs::{MsgEncodable, MsgDecodable};
+
+mod utils;
+
+#[inline]
+pub fn do_test(data: &[u8]) {
+ reset_rng_state();
+ test_msg!(msgs::DecodedOnionErrorPacket, data);
+}
+
+#[cfg(feature = "afl")]
+#[macro_use] extern crate afl;
+#[cfg(feature = "afl")]
+fn main() {
+ fuzz!(|data| {
+ do_test(data);
+ });
+}
+
+#[cfg(feature = "honggfuzz")]
+#[macro_use] extern crate honggfuzz;
+#[cfg(feature = "honggfuzz")]
+fn main() {
+ loop {
+ fuzz!(|data| {
+ do_test(data);
+ });
+ }
+}
+
+extern crate hex;
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn duplicate_crash() {
+ super::do_test(&::hex::decode("00").unwrap());
+ }
+}
--- /dev/null
+// This file is auto-generated by gen_target.sh based on msg_target_template.txt
+// To modify it, modify msg_target_template.txt and run gen_target.sh instead.
+
+extern crate lightning;
+
+use lightning::ln::msgs;
+use lightning::util::reset_rng_state;
+
+use lightning::ln::msgs::{MsgEncodable, MsgDecodable};
+
+mod utils;
+
+#[inline]
+pub fn do_test(data: &[u8]) {
+ reset_rng_state();
+ test_msg_hole!(msgs::ErrorMessage, data, 32, 2);
+}
+
+#[cfg(feature = "afl")]
+#[macro_use] extern crate afl;
+#[cfg(feature = "afl")]
+fn main() {
+ fuzz!(|data| {
+ do_test(data);
+ });
+}
+
+#[cfg(feature = "honggfuzz")]
+#[macro_use] extern crate honggfuzz;
+#[cfg(feature = "honggfuzz")]
+fn main() {
+ loop {
+ fuzz!(|data| {
+ do_test(data);
+ });
+ }
+}
+
+extern crate hex;
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn duplicate_crash() {
+ super::do_test(&::hex::decode("00").unwrap());
+ }
+}
--- /dev/null
+// This file is auto-generated by gen_target.sh based on msg_target_template.txt
+// To modify it, modify msg_target_template.txt and run gen_target.sh instead.
+
+extern crate lightning;
+
+use lightning::ln::msgs;
+use lightning::util::reset_rng_state;
+
+use lightning::ln::msgs::{MsgEncodable, MsgDecodable};
+
+mod utils;
+
+#[inline]
+pub fn do_test(data: &[u8]) {
+ reset_rng_state();
+ test_msg!(msgs::Init, data);
+}
+
+#[cfg(feature = "afl")]
+#[macro_use] extern crate afl;
+#[cfg(feature = "afl")]
+fn main() {
+ fuzz!(|data| {
+ do_test(data);
+ });
+}
+
+#[cfg(feature = "honggfuzz")]
+#[macro_use] extern crate honggfuzz;
+#[cfg(feature = "honggfuzz")]
+fn main() {
+ loop {
+ fuzz!(|data| {
+ do_test(data);
+ });
+ }
+}
+
+extern crate hex;
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn duplicate_crash() {
+ super::do_test(&::hex::decode("00").unwrap());
+ }
+}
--- /dev/null
+// This file is auto-generated by gen_target.sh based on msg_target_template.txt
+// To modify it, modify msg_target_template.txt and run gen_target.sh instead.
+
+extern crate lightning;
+
+use lightning::ln::msgs;
+use lightning::util::reset_rng_state;
+
+use lightning::ln::msgs::{MsgEncodable, MsgDecodable};
+
+mod utils;
+
+#[inline]
+pub fn do_test(data: &[u8]) {
+ reset_rng_state();
+ test_msg_exact!(msgs::NodeAnnouncement, data);
+}
+
+#[cfg(feature = "afl")]
+#[macro_use] extern crate afl;
+#[cfg(feature = "afl")]
+fn main() {
+ fuzz!(|data| {
+ do_test(data);
+ });
+}
+
+#[cfg(feature = "honggfuzz")]
+#[macro_use] extern crate honggfuzz;
+#[cfg(feature = "honggfuzz")]
+fn main() {
+ loop {
+ fuzz!(|data| {
+ do_test(data);
+ });
+ }
+}
+
+extern crate hex;
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn duplicate_crash() {
+ super::do_test(&::hex::decode("00").unwrap());
+ }
+}
--- /dev/null
+// This file is auto-generated by gen_target.sh based on msg_target_template.txt
+// To modify it, modify msg_target_template.txt and run gen_target.sh instead.
+
+extern crate lightning;
+
+use lightning::ln::msgs;
+use lightning::util::reset_rng_state;
+
+use lightning::ln::msgs::{MsgEncodable, MsgDecodable};
+
+mod utils;
+
+#[inline]
+pub fn do_test(data: &[u8]) {
+ reset_rng_state();
+ test_msg_hole!(msgs::OnionHopData, data, 1+8+8+4, 12);
+}
+
+#[cfg(feature = "afl")]
+#[macro_use] extern crate afl;
+#[cfg(feature = "afl")]
+fn main() {
+ fuzz!(|data| {
+ do_test(data);
+ });
+}
+
+#[cfg(feature = "honggfuzz")]
+#[macro_use] extern crate honggfuzz;
+#[cfg(feature = "honggfuzz")]
+fn main() {
+ loop {
+ fuzz!(|data| {
+ do_test(data);
+ });
+ }
+}
+
+extern crate hex;
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn duplicate_crash() {
+ super::do_test(&::hex::decode("00").unwrap());
+ }
+}
#[inline]
pub fn do_test(data: &[u8]) {
reset_rng_state();
- test_msg!(msgs::MSG_TARGET, data);
+ TEST_MSG!(msgs::MSG_TARGET, dataEXTRA_ARGS);
}
#[cfg(feature = "afl")]
--- /dev/null
+// This file is auto-generated by gen_target.sh based on msg_target_template.txt
+// To modify it, modify msg_target_template.txt and run gen_target.sh instead.
+
+extern crate lightning;
+
+use lightning::ln::msgs;
+use lightning::util::reset_rng_state;
+
+use lightning::ln::msgs::{MsgEncodable, MsgDecodable};
+
+mod utils;
+
+#[inline]
+pub fn do_test(data: &[u8]) {
+ reset_rng_state();
+ test_msg_hole!(msgs::UpdateAddHTLC, data, 85, 33);
+}
+
+#[cfg(feature = "afl")]
+#[macro_use] extern crate afl;
+#[cfg(feature = "afl")]
+fn main() {
+ fuzz!(|data| {
+ do_test(data);
+ });
+}
+
+#[cfg(feature = "honggfuzz")]
+#[macro_use] extern crate honggfuzz;
+#[cfg(feature = "honggfuzz")]
+fn main() {
+ loop {
+ fuzz!(|data| {
+ do_test(data);
+ });
+ }
+}
+
+extern crate hex;
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn duplicate_crash() {
+ super::do_test(&::hex::decode("00").unwrap());
+ }
+}
}
}
}
+
+#[macro_export]
+macro_rules! test_msg_exact {
+ ($MsgType: path, $data: ident) => {
+ {
+ if let Ok(msg) = <$MsgType as MsgDecodable>::decode($data){
+ let enc = msg.encode();
+ assert_eq!(&$data[..], &enc[..]);
+ }
+ }
+ }
+}
+
+#[macro_export]
+macro_rules! test_msg_hole {
+ ($MsgType: path, $data: ident, $hole: expr, $hole_len: expr) => {
+ {
+ if let Ok(msg) = <$MsgType as MsgDecodable>::decode($data){
+ let enc = msg.encode();
+ assert_eq!(&$data[..$hole], &enc[..$hole]);
+ assert_eq!(&$data[$hole + $hole_len..enc.len()], &enc[$hole + $hole_len..]);
+ }
+ }
+ }
+}
+++ /dev/null
-extern crate lightning;
-
-use lightning::ln::msgs;
-use lightning::util::reset_rng_state;
-
-use lightning::ln::msgs::{MsgEncodable, MsgDecodable};
-
-#[inline]
-pub fn do_test(data: &[u8]) {
- reset_rng_state();
- if let Ok(msg) = msgs::UpdateAddHTLC::decode(data){
- let enc = msg.encode();
- assert_eq!(&data[0..85], &enc[0..85]);
- assert_eq!(&data[85+33..enc.len()], &enc[85+33..]);
- }
-}
-
-#[cfg(feature = "afl")]
-#[macro_use] extern crate afl;
-#[cfg(feature = "afl")]
-fn main() {
- fuzz!(|data| {
- do_test(data);
- });
-}
-
-#[cfg(feature = "honggfuzz")]
-#[macro_use] extern crate honggfuzz;
-#[cfg(feature = "honggfuzz")]
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-extern crate hex;
-#[cfg(test)]
-mod tests {
- #[test]
- fn duplicate_crash() {
- super::do_test(&::hex::decode("00").unwrap());
- }
-}
Ok(msg) => msg,
Err(e) => match e {
msgs::DecodeError::UnknownRealmByte => return,
+ msgs::DecodeError::UnknownRequiredFeature => return,
msgs::DecodeError::BadPublicKey => return,
msgs::DecodeError::BadSignature => return,
msgs::DecodeError::BadText => return,
node_id_2: if were_node_one { self.get_their_node_id() } else { our_node_id },
bitcoin_key_1: if were_node_one { our_bitcoin_key } else { self.their_funding_pubkey.unwrap() },
bitcoin_key_2: if were_node_one { self.their_funding_pubkey.unwrap() } else { our_bitcoin_key },
+ excess_data: Vec::new(),
};
let msghash = Message::from_slice(&Sha256dHash::from_data(&msg.encode()[..])[..]).unwrap();
htlc_minimum_msat: chan.get_our_htlc_minimum_msat(),
fee_base_msat: chan.get_our_fee_base_msat(&*self.fee_estimator),
fee_proportional_millionths: self.fee_proportional_millionths,
+ excess_data: Vec::new(),
};
let msg_hash = Sha256dHash::from_data(&unsigned.encode()[..]);
pub enum DecodeError {
/// Unknown realm byte in an OnionHopData packet
UnknownRealmByte,
+ /// Unknown feature mandating we fail to parse message
+ UnknownRequiredFeature,
/// Failed to decode a public key (ie it's invalid)
BadPublicKey,
/// Failed to decode a signature (ie it's invalid)
/// List of addresses on which this node is reachable. Note that you may only have up to one
/// address of each type, if you have more, they may be silently discarded or we may panic!
pub addresses: Vec<NetAddress>,
+ pub excess_address_data: Vec<u8>,
+ pub excess_data: Vec<u8>,
}
pub struct NodeAnnouncement {
pub signature: Signature,
pub node_id_2: PublicKey,
pub bitcoin_key_1: PublicKey,
pub bitcoin_key_2: PublicKey,
+ pub excess_data: Vec<u8>,
}
#[derive(PartialEq, Clone)]
pub struct ChannelAnnouncement {
pub htlc_minimum_msat: u64,
pub fee_base_msat: u32,
pub fee_proportional_millionths: u32,
+ pub excess_data: Vec<u8>,
}
#[derive(PartialEq, Clone)]
pub struct ChannelUpdate {
}
pub trait RoutingMessageHandler : Send + Sync {
- fn handle_node_announcement(&self, msg: &NodeAnnouncement) -> Result<(), HandleError>;
+ fn handle_node_announcement(&self, msg: &NodeAnnouncement) -> Result<bool, HandleError>;
/// Handle a channel_announcement message, returning true if it should be forwarded on, false
/// or returning an Err otherwise.
fn handle_channel_announcement(&self, msg: &ChannelAnnouncement) -> Result<bool, HandleError>;
- fn handle_channel_update(&self, msg: &ChannelUpdate) -> Result<(), HandleError>;
+ fn handle_channel_update(&self, msg: &ChannelUpdate) -> Result<bool, HandleError>;
fn handle_htlc_fail_channel_update(&self, update: &HTLCFailChannelUpdate);
}
fn description(&self) -> &str {
match *self {
DecodeError::UnknownRealmByte => "Unknown realm byte in Onion packet",
+ DecodeError::UnknownRequiredFeature => "Unknown required feature preventing decode",
DecodeError::BadPublicKey => "Invalid public key in packet",
DecodeError::BadSignature => "Invalid signature in packet",
DecodeError::BadText => "Invalid text in packet",
impl MsgDecodable for UnsignedNodeAnnouncement {
fn decode(v: &[u8]) -> Result<Self, DecodeError> {
let features = GlobalFeatures::decode(&v[..])?;
+ if features.requires_unknown_bits() {
+ return Err(DecodeError::UnknownRequiredFeature);
+ }
+
if v.len() < features.encoded_len() + 4 + 33 + 3 + 32 + 2 {
return Err(DecodeError::ShortRead);
}
loop {
if addr_read_limit <= read_pos { break; }
match v[read_pos] {
- 0 => { read_pos += 1; },
1 => {
if addresses.len() > 0 {
return Err(DecodeError::ExtraAddressesPerType);
}
}
+ let excess_address_data = if read_pos < addr_read_limit {
+ let mut excess_address_data = Vec::with_capacity(addr_read_limit - read_pos);
+ excess_address_data.extend_from_slice(&v[read_pos..addr_read_limit]);
+ excess_address_data
+ } else { Vec::new() };
+
+ let mut excess_data = Vec::with_capacity(v.len() - addr_read_limit);
+ excess_data.extend_from_slice(&v[addr_read_limit..]);
+
let secp_ctx = Secp256k1::without_caps();
Ok(Self {
features,
rgb,
alias,
addresses,
+ excess_address_data,
+ excess_data,
})
}
}
impl MsgEncodable for UnsignedNodeAnnouncement {
fn encode(&self) -> Vec<u8> {
let features = self.features.encode();
- let mut res = Vec::with_capacity(74 + features.len() + self.addresses.len());
+ let mut res = Vec::with_capacity(74 + features.len() + self.addresses.len()*7 + self.excess_address_data.len() + self.excess_data.len());
res.extend_from_slice(&features[..]);
res.extend_from_slice(&byte_utils::be32_to_array(self.timestamp));
res.extend_from_slice(&self.node_id.serialize());
},
}
}
- res.extend_from_slice(&byte_utils::be16_to_array(addr_slice.len() as u16));
+ res.extend_from_slice(&byte_utils::be16_to_array((addr_slice.len() + self.excess_address_data.len()) as u16));
res.extend_from_slice(&addr_slice[..]);
+ res.extend_from_slice(&self.excess_address_data[..]);
+ res.extend_from_slice(&self.excess_data[..]);
res
}
}
impl MsgDecodable for UnsignedChannelAnnouncement {
fn decode(v: &[u8]) -> Result<Self, DecodeError> {
let features = GlobalFeatures::decode(&v[..])?;
+ if features.requires_unknown_bits() {
+ return Err(DecodeError::UnknownRequiredFeature);
+ }
if v.len() < features.encoded_len() + 32 + 8 + 33*4 {
return Err(DecodeError::ShortRead);
}
let start = features.encoded_len();
let secp_ctx = Secp256k1::without_caps();
+ let mut excess_data = Vec::with_capacity(v.len() - start - 172);
+ excess_data.extend_from_slice(&v[start + 172..]);
Ok(Self {
features,
chain_hash: deserialize(&v[start..start + 32]).unwrap(),
node_id_2: secp_pubkey!(&secp_ctx, &v[start + 73..start + 106]),
bitcoin_key_1: secp_pubkey!(&secp_ctx, &v[start + 106..start + 139]),
bitcoin_key_2: secp_pubkey!(&secp_ctx, &v[start + 139..start + 172]),
+ excess_data,
})
}
}
impl MsgEncodable for UnsignedChannelAnnouncement {
fn encode(&self) -> Vec<u8> {
let features = self.features.encode();
- let mut res = Vec::with_capacity(172 + features.len());
+ let mut res = Vec::with_capacity(172 + features.len() + self.excess_data.len());
res.extend_from_slice(&features[..]);
res.extend_from_slice(&self.chain_hash[..]);
res.extend_from_slice(&byte_utils::be64_to_array(self.short_channel_id));
res.extend_from_slice(&self.node_id_2.serialize());
res.extend_from_slice(&self.bitcoin_key_1.serialize());
res.extend_from_slice(&self.bitcoin_key_2.serialize());
+ res.extend_from_slice(&self.excess_data[..]);
res
}
}
if v.len() < 32+8+4+2+2+8+4+4 {
return Err(DecodeError::ShortRead);
}
+ let mut excess_data = Vec::with_capacity(v.len() - 64);
+ excess_data.extend_from_slice(&v[64..]);
Ok(Self {
chain_hash: deserialize(&v[0..32]).unwrap(),
short_channel_id: byte_utils::slice_to_be64(&v[32..40]),
htlc_minimum_msat: byte_utils::slice_to_be64(&v[48..56]),
fee_base_msat: byte_utils::slice_to_be32(&v[56..60]),
fee_proportional_millionths: byte_utils::slice_to_be32(&v[60..64]),
+ excess_data
})
}
}
impl MsgEncodable for UnsignedChannelUpdate {
fn encode(&self) -> Vec<u8> {
- let mut res = Vec::with_capacity(64);
+ let mut res = Vec::with_capacity(64 + self.excess_data.len());
res.extend_from_slice(&self.chain_hash[..]);
res.extend_from_slice(&byte_utils::be64_to_array(self.short_channel_id));
res.extend_from_slice(&byte_utils::be32_to_array(self.timestamp));
res.extend_from_slice(&byte_utils::be64_to_array(self.htlc_minimum_msat));
res.extend_from_slice(&byte_utils::be32_to_array(self.fee_base_msat));
res.extend_from_slice(&byte_utils::be32_to_array(self.fee_proportional_millionths));
+ res.extend_from_slice(&self.excess_data[..]);
res
}
}
#[test]
fn encoding_channel_reestablish_no_secret() {
- let public_key = {
- let secp_ctx = Secp256k1::new();
- PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap())
- };
-
let cr = msgs::ChannelReestablish {
channel_id: [4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0],
next_local_commitment_number: 3,
($thing: expr) => {
match $thing {
Ok(x) => x,
- Err(_e) => {
- //TODO: Handle e?
- return Err(PeerHandleError{ no_connection_possible: false });
- }
- };
- }
- }
-
- macro_rules! try_ignore_potential_decodeerror {
- ($thing: expr) => {
- match $thing {
- Ok(x) => x,
- Err(_e) => {
- log_debug!(self, "Error decoding message, ignoring due to lnd spec incompatibility. See https://github.com/lightningnetwork/lnd/issues/1407");
- continue;
+ Err(e) => {
+ match e {
+ msgs::DecodeError::UnknownRealmByte => return Err(PeerHandleError{ no_connection_possible: false }),
+ msgs::DecodeError::UnknownRequiredFeature => {
+ log_debug!(self, "Got a channel/node announcement with an known required feature flag, you may want to udpate!");
+ continue;
+ },
+ msgs::DecodeError::BadPublicKey => return Err(PeerHandleError{ no_connection_possible: false }),
+ msgs::DecodeError::BadSignature => return Err(PeerHandleError{ no_connection_possible: false }),
+ msgs::DecodeError::BadText => return Err(PeerHandleError{ no_connection_possible: false }),
+ msgs::DecodeError::ShortRead => return Err(PeerHandleError{ no_connection_possible: false }),
+ msgs::DecodeError::ExtraAddressesPerType => {
+ log_debug!(self, "Error decoding message, ignoring due to lnd spec incompatibility. See https://github.com/lightningnetwork/lnd/issues/1407");
+ continue;
+ },
+ msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError{ no_connection_possible: false }),
+ }
}
};
}
}
},
257 => {
- let msg = try_ignore_potential_decodeerror!(msgs::NodeAnnouncement::decode(&msg_data[2..]));
- try_potential_handleerror!(self.message_handler.route_handler.handle_node_announcement(&msg));
+ let msg = try_potential_decodeerror!(msgs::NodeAnnouncement::decode(&msg_data[2..]));
+ let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_node_announcement(&msg));
+
+ if should_forward {
+ // TODO: forward msg along to all our other peers!
+ }
},
258 => {
let msg = try_potential_decodeerror!(msgs::ChannelUpdate::decode(&msg_data[2..]));
- try_potential_handleerror!(self.message_handler.route_handler.handle_channel_update(&msg));
+ let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_update(&msg));
+
+ if should_forward {
+ // TODO: forward msg along to all our other peers!
+ }
},
_ => {
if (msg_type & 1) == 0 {
}
impl RoutingMessageHandler for Router {
- fn handle_node_announcement(&self, msg: &msgs::NodeAnnouncement) -> Result<(), HandleError> {
+ fn handle_node_announcement(&self, msg: &msgs::NodeAnnouncement) -> Result<bool, HandleError> {
let msg_hash = Message::from_slice(&Sha256dHash::from_data(&msg.contents.encode()[..])[..]).unwrap();
secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.signature, &msg.contents.node_id);
+ if msg.contents.features.requires_unknown_bits() {
+ panic!("Unknown-required-features NodeAnnouncements should never deserialize!");
+ }
+
let mut network = self.network_map.write().unwrap();
match network.nodes.get_mut(&msg.contents.node_id) {
None => Err(HandleError{err: "No existing channels for node_announcement", action: Some(ErrorAction::IgnoreError)}),
node.rgb = msg.contents.rgb;
node.alias = msg.contents.alias;
node.addresses = msg.contents.addresses.clone();
- Ok(())
+ Ok(msg.contents.excess_data.is_empty() && msg.contents.excess_address_data.is_empty() && !msg.contents.features.supports_unknown_bits())
}
}
}
//TODO: Only allow bitcoin chain_hash
if msg.contents.features.requires_unknown_bits() {
- return Err(HandleError{err: "Channel announcement required unknown feature flags", action: None});
+ panic!("Unknown-required-features ChannelAnnouncements should never deserialize!");
}
let mut network = self.network_map.write().unwrap();
add_channel_to_node!(msg.contents.node_id_1);
add_channel_to_node!(msg.contents.node_id_2);
- Ok(!msg.contents.features.supports_unknown_bits())
+ Ok(msg.contents.excess_data.is_empty() && !msg.contents.features.supports_unknown_bits())
}
fn handle_htlc_fail_channel_update(&self, update: &msgs::HTLCFailChannelUpdate) {
}
}
- fn handle_channel_update(&self, msg: &msgs::ChannelUpdate) -> Result<(), HandleError> {
+ fn handle_channel_update(&self, msg: &msgs::ChannelUpdate) -> Result<bool, HandleError> {
let mut network = self.network_map.write().unwrap();
let dest_node_id;
let chan_enabled = msg.contents.flags & (1 << 1) != (1 << 1);
mut_node.lowest_inbound_channel_fee_proportional_millionths = lowest_inbound_channel_fee_proportional_millionths;
}
- Ok(())
+ Ok(msg.contents.excess_data.is_empty())
}
}
}
impl msgs::RoutingMessageHandler for TestRoutingMessageHandler {
- fn handle_node_announcement(&self, _msg: &msgs::NodeAnnouncement) -> Result<(), HandleError> {
+ fn handle_node_announcement(&self, _msg: &msgs::NodeAnnouncement) -> Result<bool, HandleError> {
Err(HandleError { err: "", action: None })
}
fn handle_channel_announcement(&self, _msg: &msgs::ChannelAnnouncement) -> Result<bool, HandleError> {
Err(HandleError { err: "", action: None })
}
- fn handle_channel_update(&self, _msg: &msgs::ChannelUpdate) -> Result<(), HandleError> {
+ fn handle_channel_update(&self, _msg: &msgs::ChannelUpdate) -> Result<bool, HandleError> {
Err(HandleError { err: "", action: None })
}
fn handle_htlc_fail_channel_update(&self, _update: &msgs::HTLCFailChannelUpdate) {}