X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fmsgs.rs;h=85672f4cd978dbd521b01b4fe5493b7a9f8d438a;hb=2024c5e1049ef399fb24e5c466924f980e949c69;hp=be99596becd82d4627c21c229d9b6172ac385615;hpb=d2955be5cf7fa96057c416a7899e7db6a0c5e622;p=rust-lightning diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index be99596b..85672f4c 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -32,11 +32,13 @@ use bitcoin::hash_types::{Txid, BlockHash}; use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures}; -use std::{cmp, fmt}; -use std::fmt::Debug; +use prelude::*; +use core::{cmp, fmt}; +use core::fmt::Debug; use std::io::Read; use util::events::MessageSendEventsProvider; +use util::logger; use util::ser::{Readable, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedVarInt}; use ln::{PaymentPreimage, PaymentHash, PaymentSecret}; @@ -45,7 +47,7 @@ use ln::{PaymentPreimage, PaymentHash, PaymentSecret}; pub(crate) const MAX_VALUE_MSAT: u64 = 21_000_000_0000_0000_000; /// An error in decoding a message or struct. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub enum DecodeError { /// A version byte specified something we don't know how to handle. /// Includes unknown realm byte in an OnionHopData packet @@ -63,6 +65,8 @@ pub enum DecodeError { /// Error from std::io Io(/// (C-not exported) as ErrorKind doesn't have a reasonable mapping ::std::io::ErrorKind), + /// The message included zlib-compressed values, which we don't support. + UnsupportedCompression, } /// An init message to be sent or received from a peer @@ -480,6 +484,17 @@ impl Readable for Result { } } +impl Readable for NetAddress { + fn read(reader: &mut R) -> Result { + match Readable::read(reader) { + Ok(Ok(res)) => Ok(res), + Ok(Err(_)) => Err(DecodeError::UnknownVersion), + Err(e) => Err(e), + } + } +} + + /// The unsigned part of a node_announcement #[derive(Clone, Debug, PartialEq)] pub struct UnsignedNodeAnnouncement { @@ -674,7 +689,11 @@ pub enum ErrorAction { msg: Option }, /// The peer did something harmless that we weren't able to process, just log and ignore + // New code should *not* use this. New code must use IgnoreAndLog, below! IgnoreError, + /// The peer did something harmless that we weren't able to meaningfully process. + /// If the error is logged, log it at the given level. + IgnoreAndLog(logger::Level), /// The peer did something incorrect. Tell them. SendErrorMessage { /// The message to send. @@ -865,7 +884,8 @@ pub trait RoutingMessageHandler : MessageSendEventsProvider { } mod fuzzy_internal_msgs { - use ln::PaymentSecret; + use prelude::*; + use ln::{PaymentPreimage, PaymentSecret}; // These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize // them from untrusted input): @@ -886,6 +906,7 @@ mod fuzzy_internal_msgs { }, FinalNode { payment_data: Option, + keysend_preimage: Option, }, } @@ -953,6 +974,7 @@ impl fmt::Display for DecodeError { DecodeError::ShortRead => f.write_str("Packet extended beyond the provided bytes"), DecodeError::BadLengthDescriptor => f.write_str("A length descriptor in the packet didn't describe the later data correctly"), DecodeError::Io(ref e) => e.fmt(f), + DecodeError::UnsupportedCompression => f.write_str("We don't support receiving messages with zlib-compressed fields"), } } } @@ -1279,23 +1301,20 @@ impl Writeable for OnionHopData { }, OnionHopDataFormat::NonFinalNode { short_channel_id } => { encode_varint_length_prefixed_tlv!(w, { - (2, HighZeroBytesDroppedVarInt(self.amt_to_forward)), - (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value)), - (6, short_channel_id) - }); - }, - OnionHopDataFormat::FinalNode { payment_data: Some(ref final_data) } => { - if final_data.total_msat > MAX_VALUE_MSAT { panic!("We should never be sending infinite/overflow onion payments"); } - encode_varint_length_prefixed_tlv!(w, { - (2, HighZeroBytesDroppedVarInt(self.amt_to_forward)), - (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value)), - (8, final_data) + (2, HighZeroBytesDroppedVarInt(self.amt_to_forward), required), + (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value), required), + (6, short_channel_id, required) }); }, - OnionHopDataFormat::FinalNode { payment_data: None } => { + OnionHopDataFormat::FinalNode { ref payment_data, ref keysend_preimage } => { + if let Some(final_data) = payment_data { + if final_data.total_msat > MAX_VALUE_MSAT { panic!("We should never be sending infinite/overflow onion payments"); } + } encode_varint_length_prefixed_tlv!(w, { - (2, HighZeroBytesDroppedVarInt(self.amt_to_forward)), - (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value)) + (2, HighZeroBytesDroppedVarInt(self.amt_to_forward), required), + (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value), required), + (8, payment_data, option), + (5482373484, keysend_preimage, option) }); }, } @@ -1318,12 +1337,14 @@ impl Readable for OnionHopData { let mut cltv_value = HighZeroBytesDroppedVarInt(0u32); let mut short_id: Option = None; let mut payment_data: Option = None; - decode_tlv!(&mut rd, { - (2, amt), - (4, cltv_value) - }, { - (6, short_id), - (8, payment_data) + let mut keysend_preimage: Option = None; + // The TLV type is chosen to be compatible with lnd and c-lightning. + decode_tlv_stream!(&mut rd, { + (2, amt, required), + (4, cltv_value, required), + (6, short_id, option), + (8, payment_data, option), + (5482373484, keysend_preimage, option) }); rd.eat_remaining().map_err(|_| DecodeError::ShortRead)?; let format = if let Some(short_channel_id) = short_id { @@ -1338,7 +1359,8 @@ impl Readable for OnionHopData { } } OnionHopDataFormat::FinalNode { - payment_data + payment_data, + keysend_preimage, } }; (format, amt.0, cltv_value.0) @@ -1634,17 +1656,18 @@ impl Readable for QueryShortChannelIds { fn read(r: &mut R) -> Result { let chain_hash: BlockHash = Readable::read(r)?; - // We expect the encoding_len to always includes the 1-byte - // encoding_type and that short_channel_ids are 8-bytes each let encoding_len: u16 = Readable::read(r)?; - if encoding_len == 0 || (encoding_len - 1) % 8 != 0 { - return Err(DecodeError::InvalidValue); - } + let encoding_type: u8 = Readable::read(r)?; // Must be encoding_type=0 uncompressed serialization. We do not // support encoding_type=1 zlib serialization. - let encoding_type: u8 = Readable::read(r)?; if encoding_type != EncodingType::Uncompressed as u8 { + return Err(DecodeError::UnsupportedCompression); + } + + // We expect the encoding_len to always includes the 1-byte + // encoding_type and that short_channel_ids are 8-bytes each + if encoding_len == 0 || (encoding_len - 1) % 8 != 0 { return Err(DecodeError::InvalidValue); } @@ -1746,17 +1769,18 @@ impl Readable for ReplyChannelRange { let number_of_blocks: u32 = Readable::read(r)?; let sync_complete: bool = Readable::read(r)?; - // We expect the encoding_len to always includes the 1-byte - // encoding_type and that short_channel_ids are 8-bytes each let encoding_len: u16 = Readable::read(r)?; - if encoding_len == 0 || (encoding_len - 1) % 8 != 0 { - return Err(DecodeError::InvalidValue); - } + let encoding_type: u8 = Readable::read(r)?; // Must be encoding_type=0 uncompressed serialization. We do not // support encoding_type=1 zlib serialization. - let encoding_type: u8 = Readable::read(r)?; if encoding_type != EncodingType::Uncompressed as u8 { + return Err(DecodeError::UnsupportedCompression); + } + + // We expect the encoding_len to always includes the 1-byte + // encoding_type and that short_channel_ids are 8-bytes each + if encoding_len == 0 || (encoding_len - 1) % 8 != 0 { return Err(DecodeError::InvalidValue); } @@ -1839,6 +1863,7 @@ mod tests { use bitcoin::secp256k1::key::{PublicKey,SecretKey}; use bitcoin::secp256k1::{Secp256k1, Message}; + use prelude::*; use std::io::Cursor; #[test] @@ -2515,6 +2540,7 @@ mod tests { let mut msg = msgs::OnionHopData { format: OnionHopDataFormat::FinalNode { payment_data: None, + keysend_preimage: None, }, amt_to_forward: 0x0badf00d01020304, outgoing_cltv_value: 0xffffffff, @@ -2523,7 +2549,7 @@ mod tests { let target_value = hex::decode("1002080badf00d010203040404ffffffff").unwrap(); assert_eq!(encoded_value, target_value); msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap(); - if let OnionHopDataFormat::FinalNode { payment_data: None } = msg.format { } else { panic!(); } + if let OnionHopDataFormat::FinalNode { payment_data: None, .. } = msg.format { } else { panic!(); } assert_eq!(msg.amt_to_forward, 0x0badf00d01020304); assert_eq!(msg.outgoing_cltv_value, 0xffffffff); } @@ -2537,6 +2563,7 @@ mod tests { payment_secret: expected_payment_secret, total_msat: 0x1badca1f }), + keysend_preimage: None, }, amt_to_forward: 0x0badf00d01020304, outgoing_cltv_value: 0xffffffff, @@ -2549,7 +2576,8 @@ mod tests { payment_data: Some(FinalOnionHopData { payment_secret, total_msat: 0x1badca1f - }) + }), + keysend_preimage: None, } = msg.format { assert_eq!(payment_secret, expected_payment_secret); } else { panic!(); }