Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 480
Create and handle warning messages#1013
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
f676f551b3249ae137cfb26fe0f72d7b06ed786bfaFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| // This file is Copyright its original authors, visible in version control | ||
| // history. | ||
| // | ||
| // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE | ||
| // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. | ||
| // You may not use this file except in accordance with one or both of these | ||
| // licenses. | ||
| // 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. | ||
| use lightning::ln::msgs; | ||
| use msg_targets::utils::VecWriter; | ||
| use utils::test_logger; | ||
| #[inline] | ||
| pub fn msg_warning_message_test<Out: test_logger::Output>(data: &[u8], _out: Out) { | ||
| test_msg_hole!(msgs::WarningMessage, data, 32, 2); | ||
| } | ||
| #[no_mangle] | ||
| pub extern "C" fn msg_warning_message_run(data: *const u8, datalen: usize) { | ||
| let data = unsafe { std::slice::from_raw_parts(data, datalen) }; | ||
| test_msg_hole!(msgs::WarningMessage, data, 32, 2); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -33,7 +33,7 @@ use bitcoin::hash_types::{Txid, BlockHash}; | ||
| use ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures}; | ||
| use prelude::*; | ||
| use core::{cmp, fmt}; | ||
| use core::fmt; | ||
| use core::fmt::Debug; | ||
| use io::{self, Read}; | ||
| use io_extras::read_to_end; | ||
| @@ -80,12 +80,29 @@ pub struct Init { | ||
| /// An error message to be sent or received from a peer | ||
| #[derive(Clone, Debug, PartialEq)] | ||
| pub struct ErrorMessage { | ||
| /// The channel ID involved in the error | ||
| /// The channel ID involved in the error. | ||
| /// | ||
| /// All-0s indicates a general error unrelated to a specific channel, after which all channels | ||
| /// with the sending peer should be closed. | ||
| pub channel_id: [u8; 32], | ||
| /// A possibly human-readable error description. | ||
| /// The string should be sanitized before it is used (e.g. emitted to logs | ||
| /// or printed to stdout). Otherwise, a well crafted error message may trigger a security | ||
| /// vulnerability in the terminal emulator or the logging subsystem. | ||
| /// The string should be sanitized before it is used (e.g. emitted to logs or printed to | ||
| /// stdout). Otherwise, a well crafted error message may trigger a security vulnerability in | ||
| /// the terminal emulator or the logging subsystem. | ||
| pub data: String, | ||
| } | ||
| /// A warning message to be sent or received from a peer | ||
| #[derive(Clone, Debug, PartialEq)] | ||
| pub struct WarningMessage { | ||
| /// The channel ID involved in the warning. | ||
| /// | ||
| /// All-0s indicates a warning unrelated to a specific channel. | ||
| pub channel_id: [u8; 32], | ||
| /// A possibly human-readable warning description. | ||
| /// The string should be sanitized before it is used (e.g. emitted to logs or printed to | ||
| /// stdout). Otherwise, a well crafted error message may trigger a security vulnerability in | ||
| /// the terminal emulator or the logging subsystem. | ||
TheBlueMatt marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| pub data: String, | ||
| } | ||
| @@ -714,7 +731,16 @@ pub enum ErrorAction { | ||
| /// The peer did something incorrect. Tell them. | ||
| SendErrorMessage { | ||
| /// The message to send. | ||
| msg: ErrorMessage | ||
| msg: ErrorMessage, | ||
| }, | ||
| /// The peer did something incorrect. Tell them without closing any channels. | ||
| SendWarningMessage { | ||
| /// The message to send. | ||
| msg: WarningMessage, | ||
| /// The peer may have done something harmless that we weren't able to meaningfully process, | ||
| /// though we should still tell them about it. | ||
| /// If this event is logged, log it at the given level. | ||
| log_level: logger::Level, | ||
| }, | ||
| } | ||
| @@ -1503,10 +1529,38 @@ impl Readable for ErrorMessage { | ||
| Ok(Self { | ||
| channel_id: Readable::read(r)?, | ||
| data: { | ||
| let mut sz: usize = <u16 as Readable>::read(r)? as usize; | ||
| let data = read_to_end(r)?; | ||
| sz = cmp::min(data.len(), sz); | ||
TheBlueMatt marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| match String::from_utf8(data[..sz as usize].to_vec()) { | ||
| let sz: usize = <u16 as Readable>::read(r)? as usize; | ||
| let mut data = Vec::with_capacity(sz); | ||
| data.resize(sz, 0); | ||
| r.read_exact(&mut data)?; | ||
| match String::from_utf8(data) { | ||
| Ok(s) => s, | ||
| Err(_) => return Err(DecodeError::InvalidValue), | ||
| } | ||
| } | ||
| }) | ||
| } | ||
| } | ||
| impl Writeable for WarningMessage { | ||
| fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> { | ||
| self.channel_id.write(w)?; | ||
| (self.data.len() as u16).write(w)?; | ||
| w.write_all(self.data.as_bytes())?; | ||
| Ok(()) | ||
| } | ||
| } | ||
| impl Readable for WarningMessage { | ||
| fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> { | ||
| Ok(Self { | ||
| channel_id: Readable::read(r)?, | ||
| data: { | ||
| let sz: usize = <u16 as Readable>::read(r)? as usize; | ||
| let mut data = Vec::with_capacity(sz); | ||
| data.resize(sz, 0); | ||
| r.read_exact(&mut data)?; | ||
| match String::from_utf8(data) { | ||
| Ok(s) => s, | ||
| Err(_) => return Err(DecodeError::InvalidValue), | ||
| } | ||
| @@ -2405,6 +2459,17 @@ mod tests { | ||
| assert_eq!(encoded_value, target_value); | ||
| } | ||
| #[test] | ||
| fn encoding_warning() { | ||
| let error = msgs::WarningMessage { | ||
| channel_id: [2; 32], | ||
| data: String::from("rust-lightning"), | ||
| }; | ||
| let encoded_value = error.encode(); | ||
| let target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202000e727573742d6c696768746e696e67").unwrap(); | ||
| assert_eq!(encoded_value, target_value); | ||
| } | ||
| #[test] | ||
| fn encoding_ping() { | ||
| let ping = msgs::Ping { | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -821,6 +821,11 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, L: Deref, CMH: Deref> P | ||
| self.enqueue_message(peer, &msg); | ||
| continue; | ||
| }, | ||
| msgs::ErrorAction::SendWarningMessage { msg, log_level } => { | ||
| log_given_level!(self.logger, log_level, "Error handling message{}; sending warning message with: {}", OptionalFromDebugger(&peer.their_node_id), e.err); | ||
| self.enqueue_message(peer, &msg); | ||
| continue; | ||
| }, | ||
| } | ||
| } | ||
| } | ||
| @@ -897,25 +902,31 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, L: Deref, CMH: Deref> P | ||
| Ok(x) => x, | ||
| Err(e) => { | ||
| match e { | ||
| msgs::DecodeError::UnknownVersion => return Err(PeerHandleError { no_connection_possible: false }), | ||
| msgs::DecodeError::UnknownRequiredFeature => { | ||
| (msgs::DecodeError::UnknownRequiredFeature, _) => { | ||
| log_gossip!(self.logger, "Got a channel/node announcement with an unknown required feature flag, you may want to update!"); | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not necessarily relevant to the PR, but could this happen for non-gossip messages? CollaboratorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, yes, it could, I think there was a time where it couldn't but now it definitely can at least for TLVs. Lets fix that in a followup. | ||
| continue; | ||
| } | ||
| msgs::DecodeError::InvalidValue => { | ||
| (msgs::DecodeError::UnsupportedCompression, _) => { | ||
| log_gossip!(self.logger, "We don't support zlib-compressed message fields, sending a warning and ignoring message"); | ||
| self.enqueue_message(peer, &msgs::WarningMessage { channel_id: [0; 32], data: "Unsupported message compression: zlib".to_owned() }); | ||
| continue; | ||
| } | ||
| (_, Some(ty)) if is_gossip_msg(ty) => { | ||
| log_gossip!(self.logger, "Got an invalid value while deserializing a gossip message"); | ||
| self.enqueue_message(peer, &msgs::WarningMessage { channel_id: [0; 32], data: "Unreadable/bogus gossip message".to_owned() }); | ||
| continue; | ||
| } | ||
| (msgs::DecodeError::UnknownVersion, _) => return Err(PeerHandleError { no_connection_possible: false }), | ||
| (msgs::DecodeError::InvalidValue, _) => { | ||
| log_debug!(self.logger, "Got an invalid value while deserializing message"); | ||
| return Err(PeerHandleError { no_connection_possible: false }); | ||
| } | ||
| msgs::DecodeError::ShortRead => { | ||
| (msgs::DecodeError::ShortRead, _) => { | ||
| log_debug!(self.logger, "Deserialization failed due to shortness of message"); | ||
| return Err(PeerHandleError { no_connection_possible: false }); | ||
| } | ||
| msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }), | ||
| msgs::DecodeError::Io(_) => return Err(PeerHandleError { no_connection_possible: false }), | ||
| msgs::DecodeError::UnsupportedCompression => { | ||
| log_gossip!(self.logger, "We don't support zlib-compressed message fields, ignoring message"); | ||
| continue; | ||
| } | ||
| (msgs::DecodeError::BadLengthDescriptor, _) => return Err(PeerHandleError { no_connection_possible: false }), | ||
| (msgs::DecodeError::Io(_), _) => return Err(PeerHandleError { no_connection_possible: false }), | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An earlier commit handled this for gossip messages, too. I guess this way is more accurate, but just wanted to note the change in behavior. CollaboratorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea, technically I don't think we should be able to hit this ever, but some of the other errors I'm not sure if we can hit them for gossip messages or not, and I'd just rather we return a warning for them anyway. | ||
| } | ||
| } | ||
| }; | ||
| @@ -1022,6 +1033,21 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, L: Deref, CMH: Deref> P | ||
| return Err(PeerHandleError{ no_connection_possible: true }.into()); | ||
| } | ||
| }, | ||
| wire::Message::Warning(msg) => { | ||
| let mut data_is_printable = true; | ||
| for b in msg.data.bytes() { | ||
| if b < 32 || b > 126 { | ||
| data_is_printable = false; | ||
| break; | ||
| } | ||
| } | ||
TheBlueMatt marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| if data_is_printable { | ||
| log_debug!(self.logger, "Got warning message from {}: {}", log_pubkey!(peer.their_node_id.unwrap()), msg.data); | ||
| } else { | ||
| log_debug!(self.logger, "Got warning message from {} with non-ASCII error message", log_pubkey!(peer.their_node_id.unwrap())); | ||
| } | ||
| }, | ||
| wire::Message::Ping(msg) => { | ||
| if msg.ponglen < 65532 { | ||
| @@ -1419,6 +1445,12 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, L: Deref, CMH: Deref> P | ||
| msg.data); | ||
| self.enqueue_message(get_peer_for_forwarding!(node_id), msg); | ||
| }, | ||
| msgs::ErrorAction::SendWarningMessage { ref msg, ref log_level } => { | ||
| log_given_level!(self.logger, *log_level, "Handling SendWarningMessage HandleError event in peer_handler for node {} with message {}", | ||
| log_pubkey!(node_id), | ||
| msg.data); | ||
| self.enqueue_message(get_peer_for_forwarding!(node_id), msg); | ||
| }, | ||
| } | ||
| }, | ||
| MessageSendEvent::SendChannelRangeQuery { ref node_id, ref msg } => { | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did we name
ErrorMessagewith the trailingMessagejust to avoid conflicts with Rust'sErrortype? If so, is the suffix desired here? Maybe ok to parallel it here. No strong feelings.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, I'm not sure if it was specifically to avoid conflicts or just because
Errorseems like something that would be used as anErrorvsErrorMessageis pretty clear. The same logic applies forWarning, IMO, but I also don't have particularly strong feelings.