node: Ignore non-routable addresses

We ignore addresses that are not globally routable when receiving them
in node announcement message, unless they are coming from a local peer.
This commit is contained in:
cloudhead 2023-08-07 13:11:49 +02:00
parent e888398519
commit dc7d67c1e2
No known key found for this signature in database
3 changed files with 67 additions and 2 deletions

View File

@ -828,6 +828,7 @@ where
pub fn handle_announcement(
&mut self,
relayer: &NodeId,
relayer_addr: &Address,
announcement: &Announcement,
) -> Result<bool, session::Error> {
if !announcement.verify() {
@ -1023,6 +1024,7 @@ where
timestamp,
addresses
.iter()
.filter(|a| a.is_routable() || relayer_addr.is_local())
.map(|a| KnownAddress::new(a.clone(), address::Source::Peer)),
) {
Ok(updated) => {
@ -1100,12 +1102,13 @@ where
match (&mut peer.state, message) {
// Process a peer announcement.
(session::State::Connected { .. }, Message::Announcement(ann)) => {
(session::State::Connected { addr, .. }, Message::Announcement(ann)) => {
let relayer = peer.id;
let relayer_addr = addr.clone();
let announcer = ann.node;
// Returning true here means that the message should be relayed.
if self.handle_announcement(&relayer, &ann)? {
if self.handle_announcement(&relayer, &relayer_addr, &ann)? {
// Choose peers we should relay this message to.
// 1. Don't relay to the peer who sent us this message.
// 2. Don't relay to the peer who signed this announcement.

View File

@ -262,6 +262,24 @@ impl From<CommandResult> for Result<bool, Error> {
#[wrapper_mut(DerefMut)]
pub struct Address(#[serde(with = "crate::serde_ext::string")] NetAddr<HostName>);
impl Address {
/// Check whether this address is local.
pub fn is_local(&self) -> bool {
match self.0.host {
HostName::Ip(ip) => address::is_local(&ip),
_ => false,
}
}
/// Check whether this address is globally routable.
pub fn is_routable(&self) -> bool {
match self.0.host {
HostName::Ip(ip) => address::is_routable(&ip),
_ => true,
}
}
}
impl cyphernet::addr::Host for Address {
fn requires_proxy(&self) -> bool {
self.0.requires_proxy()

View File

@ -50,3 +50,47 @@ impl TryFrom<u8> for AddressType {
}
}
}
/// Check whether an IP address is globally routable.
pub fn is_routable(addr: &net::IpAddr) -> bool {
match addr {
net::IpAddr::V4(addr) => ipv4_is_routable(addr),
net::IpAddr::V6(addr) => ipv6_is_routable(addr),
}
}
/// Check whether an IP address is locally routable.
pub fn is_local(addr: &net::IpAddr) -> bool {
match addr {
net::IpAddr::V4(addr) => {
addr.is_private() || addr.is_loopback() || addr.is_link_local() || addr.is_unspecified()
}
net::IpAddr::V6(_) => false,
}
}
/// Check whether an IPv4 address is globally routable.
///
/// This code is adapted from the Rust standard library's `net::Ipv4Addr::is_global`. It can be
/// replaced once that function is stabilized.
fn ipv4_is_routable(addr: &net::Ipv4Addr) -> bool {
// Check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two
// globally routable addresses in the 192.0.0.0/24 range.
if u32::from(*addr) == 0xc0000009 || u32::from(*addr) == 0xc000000a {
return true;
}
!addr.is_private()
&& !addr.is_loopback()
&& !addr.is_link_local()
&& !addr.is_broadcast()
&& !addr.is_documentation()
// Make sure the address is not in 0.0.0.0/8.
&& addr.octets()[0] != 0
}
/// Check whether an IPv6 address is globally routable.
///
/// For now, this always returns `true`, as IPv6 addresses
/// are not fully supported.
fn ipv6_is_routable(_addr: &net::Ipv6Addr) -> bool {
true
}