node: Ignore messages from newer protocol versions
This allows for protocol upgrades without breaking old nodes.
This commit is contained in:
parent
6d11ea17c8
commit
3403a66d0f
|
|
@ -62,6 +62,8 @@ pub enum Error {
|
||||||
InvalidOnionAddr(#[from] tor::OnionAddrDecodeError),
|
InvalidOnionAddr(#[from] tor::OnionAddrDecodeError),
|
||||||
#[error("invalid timestamp: {0}")]
|
#[error("invalid timestamp: {0}")]
|
||||||
InvalidTimestamp(u64),
|
InvalidTimestamp(u64),
|
||||||
|
#[error("unknown protocol version `{0}`")]
|
||||||
|
UnknownProtocolVersion(u8),
|
||||||
#[error("unknown address type `{0}`")]
|
#[error("unknown address type `{0}`")]
|
||||||
UnknownAddressType(u8),
|
UnknownAddressType(u8),
|
||||||
#[error("unknown message type `{0}`")]
|
#[error("unknown message type `{0}`")]
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,11 @@ use std::{fmt, io};
|
||||||
|
|
||||||
use crate::{wire, wire::varint, wire::varint::VarInt, wire::Message, Link};
|
use crate::{wire, wire::varint, wire::varint::VarInt, wire::Message, Link};
|
||||||
|
|
||||||
|
/// Protocol version.
|
||||||
|
pub const PROTOCOL_VERSION: u8 = 1;
|
||||||
/// Protocol version strings all start with the magic sequence `rad`, followed
|
/// Protocol version strings all start with the magic sequence `rad`, followed
|
||||||
/// by a version number.
|
/// by a version number.
|
||||||
pub const PROTOCOL_VERSION: Version = Version([b'r', b'a', b'd', 0x1]);
|
pub const PROTOCOL_VERSION_STRING: Version = Version([b'r', b'a', b'd', PROTOCOL_VERSION]);
|
||||||
|
|
||||||
/// Control open byte.
|
/// Control open byte.
|
||||||
const CONTROL_OPEN: u8 = 0;
|
const CONTROL_OPEN: u8 = 0;
|
||||||
|
|
@ -19,11 +21,18 @@ const CONTROL_EOF: u8 = 2;
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct Version([u8; 4]);
|
pub struct Version([u8; 4]);
|
||||||
|
|
||||||
|
impl Version {
|
||||||
|
/// Version number.
|
||||||
|
pub fn number(&self) -> u8 {
|
||||||
|
self.0[3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl wire::Encode for Version {
|
impl wire::Encode for Version {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
||||||
writer.write_all(&PROTOCOL_VERSION.0)?;
|
writer.write_all(&PROTOCOL_VERSION_STRING.0)?;
|
||||||
|
|
||||||
Ok(PROTOCOL_VERSION.0.len())
|
Ok(PROTOCOL_VERSION_STRING.0.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,7 +41,7 @@ impl wire::Decode for Version {
|
||||||
let mut version = [0u8; 4];
|
let mut version = [0u8; 4];
|
||||||
reader.read_exact(&mut version[..])?;
|
reader.read_exact(&mut version[..])?;
|
||||||
|
|
||||||
if version != PROTOCOL_VERSION.0 {
|
if version != PROTOCOL_VERSION_STRING.0 {
|
||||||
return Err(wire::Error::InvalidProtocolVersion(version));
|
return Err(wire::Error::InvalidProtocolVersion(version));
|
||||||
}
|
}
|
||||||
Ok(Self(version))
|
Ok(Self(version))
|
||||||
|
|
@ -197,7 +206,7 @@ impl Frame {
|
||||||
/// Create a 'git' protocol frame.
|
/// Create a 'git' protocol frame.
|
||||||
pub fn git(stream: StreamId, data: Vec<u8>) -> Self {
|
pub fn git(stream: StreamId, data: Vec<u8>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
version: PROTOCOL_VERSION,
|
version: PROTOCOL_VERSION_STRING,
|
||||||
stream,
|
stream,
|
||||||
data: FrameData::Git(data),
|
data: FrameData::Git(data),
|
||||||
}
|
}
|
||||||
|
|
@ -206,7 +215,7 @@ impl Frame {
|
||||||
/// Create a 'control' protocol frame.
|
/// Create a 'control' protocol frame.
|
||||||
pub fn control(link: Link, ctrl: Control) -> Self {
|
pub fn control(link: Link, ctrl: Control) -> Self {
|
||||||
Self {
|
Self {
|
||||||
version: PROTOCOL_VERSION,
|
version: PROTOCOL_VERSION_STRING,
|
||||||
stream: StreamId::control(link),
|
stream: StreamId::control(link),
|
||||||
data: FrameData::Control(ctrl),
|
data: FrameData::Control(ctrl),
|
||||||
}
|
}
|
||||||
|
|
@ -215,7 +224,7 @@ impl Frame {
|
||||||
/// Create a 'gossip' protocol frame.
|
/// Create a 'gossip' protocol frame.
|
||||||
pub fn gossip(link: Link, msg: Message) -> Self {
|
pub fn gossip(link: Link, msg: Message) -> Self {
|
||||||
Self {
|
Self {
|
||||||
version: PROTOCOL_VERSION,
|
version: PROTOCOL_VERSION_STRING,
|
||||||
stream: StreamId::gossip(link),
|
stream: StreamId::gossip(link),
|
||||||
data: FrameData::Gossip(msg),
|
data: FrameData::Gossip(msg),
|
||||||
}
|
}
|
||||||
|
|
@ -306,6 +315,9 @@ impl wire::Encode for Control {
|
||||||
impl wire::Decode for Frame {
|
impl wire::Decode for Frame {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
|
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
|
||||||
let version = Version::decode(reader)?;
|
let version = Version::decode(reader)?;
|
||||||
|
if version.number() > PROTOCOL_VERSION {
|
||||||
|
return Err(wire::Error::UnknownProtocolVersion(version.number()));
|
||||||
|
}
|
||||||
let stream = StreamId::decode(reader)?;
|
let stream = StreamId::decode(reader)?;
|
||||||
|
|
||||||
match stream.kind() {
|
match stream.kind() {
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ use crate::service;
|
||||||
use crate::service::io::Io;
|
use crate::service::io::Io;
|
||||||
use crate::service::FETCH_TIMEOUT;
|
use crate::service::FETCH_TIMEOUT;
|
||||||
use crate::service::{session, DisconnectReason, Metrics, Service};
|
use crate::service::{session, DisconnectReason, Metrics, Service};
|
||||||
|
use crate::wire;
|
||||||
use crate::wire::frame;
|
use crate::wire::frame;
|
||||||
use crate::wire::frame::{Frame, FrameData, StreamId};
|
use crate::wire::frame::{Frame, FrameData, StreamId};
|
||||||
use crate::wire::Encode;
|
use crate::wire::Encode;
|
||||||
|
|
@ -812,6 +813,15 @@ where
|
||||||
// Buffer is empty, or message isn't complete.
|
// Buffer is empty, or message isn't complete.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Err(wire::Error::UnknownProtocolVersion(v)) => {
|
||||||
|
// It's ok for a peer to send frames from a newer protocol version
|
||||||
|
// that we don't understand. We just ignore them.
|
||||||
|
log::debug!(
|
||||||
|
target: "wire",
|
||||||
|
"Ignoring frame with newer protocol version ({v})",
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!(target: "wire", "Invalid gossip message from {nid}: {e}");
|
log::error!(target: "wire", "Invalid gossip message from {nid}: {e}");
|
||||||
|
|
||||||
|
|
@ -1199,7 +1209,7 @@ mod test {
|
||||||
let pong = Message::Pong {
|
let pong = Message::Pong {
|
||||||
zeroes: ZeroBytes::new(42),
|
zeroes: ZeroBytes::new(42),
|
||||||
};
|
};
|
||||||
frame::PROTOCOL_VERSION.encode(&mut stream).unwrap();
|
frame::PROTOCOL_VERSION_STRING.encode(&mut stream).unwrap();
|
||||||
frame::StreamId::gossip(Link::Outbound)
|
frame::StreamId::gossip(Link::Outbound)
|
||||||
.encode(&mut stream)
|
.encode(&mut stream)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue