diff --git a/radicle-node/src/service/session.rs b/radicle-node/src/service/session.rs index 3216e844..a11fb9d7 100644 --- a/radicle-node/src/service/session.rs +++ b/radicle-node/src/service/session.rs @@ -119,10 +119,18 @@ pub enum FetchResult { #[derive(thiserror::Error, Debug)] pub enum Error { + /// The remote peer sent an invalid announcement timestamp, + /// for eg. a timestamp far in the future. #[error("invalid announcement timestamp: {0}")] InvalidTimestamp(u64), + /// The remote peer sent git protocol messages while we were expecting + /// gossip messages. Or vice-versa. + #[error("protocol mismatch")] + ProtocolMismatch, + /// The remote peer did something that violates the protocol rules. #[error("peer misbehaved")] Misbehavior, + /// The remote peer timed out. #[error("peer timed out")] Timeout, } @@ -132,6 +140,7 @@ impl Error { pub fn is_transient(&self) -> bool { match self { Self::InvalidTimestamp(_) => false, + Self::ProtocolMismatch => true, Self::Misbehavior => false, Self::Timeout => true, } diff --git a/radicle-node/src/wire/protocol.rs b/radicle-node/src/wire/protocol.rs index 59083f20..d915e687 100644 --- a/radicle-node/src/wire/protocol.rs +++ b/radicle-node/src/wire/protocol.rs @@ -521,9 +521,11 @@ where Err(e) => { log::error!(target: "wire", "Invalid gossip message from {id}: {e}"); + let mut reason = + DisconnectReason::Session(session::Error::Misbehavior); if let Error::UnknownMessageType(t) = e { - let mut leftover = t.to_be_bytes().to_vec(); - leftover.extend(inbox.unparsed()); + let leftover = + inbox.unparsed().chain(t.to_be_bytes()).collect::>(); if let Ok(header) = str::from_utf8(&leftover[..worker::pktline::HEADER_LEN]) @@ -534,6 +536,10 @@ where "Received possible Git packet-line header `{}` from {id} (protocol mismatch)", header ); + // In case of protocol mismatch, don't penalize the peer. + reason = DisconnectReason::Session( + session::Error::ProtocolMismatch, + ); } } } @@ -542,9 +548,8 @@ where log::debug!(target: "wire", "Dropping read buffer for {id} with {} bytes", inbox.unparsed().count()); } self.disconnect( - fd, - // TODO(cloudhead): Include error in reason. - DisconnectReason::Session(session::Error::Misbehavior), + fd, // TODO(cloudhead): Include error in reason. + reason, ); break; }