From 24c0d3ac53523e9462f3d1e722be73bf66eb3f1c Mon Sep 17 00:00:00 2001 From: ssnover95 Date: Sun, 23 Aug 2020 16:28:38 -0400 Subject: [PATCH 1/2] chore(): Move over ip feature implementation required by IpAddr::is_global --- src/lib.rs | 1 - src/message/mod.rs | 100 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 97 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c60993139..655c68f5f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,4 @@ #![allow(unused_features)] -#![feature(ip)] #![recursion_limit = "1024"] //! An asynchronous abstraction for discovering devices and services on a network. diff --git a/src/message/mod.rs b/src/message/mod.rs index 82f383b4d..274fb9fa2 100644 --- a/src/message/mod.rs +++ b/src/message/mod.rs @@ -1,7 +1,7 @@ //! Messaging primitives for discovering devices and services. use std::io; -use std::net::SocketAddr; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; use net::connector::UdpConnector; use net::IpVersionMode; @@ -123,7 +123,7 @@ fn map_local(mut f: F) -> io::Result> } } // Filter all loopback and global IPv6 addresses - SocketAddr::V6(n) if !n.ip().is_loopback() && !n.ip().is_global() => { + SocketAddr::V6(n) if !n.ip().is_loopback() && !is_global(&addr.ip()) => { if let Some(x) = try!(f(&addr)) { obj_list.push(x); } @@ -135,6 +135,100 @@ fn map_local(mut f: F) -> io::Result> Ok(obj_list) } +fn is_global(addr: &IpAddr) -> bool { + match addr { + IpAddr::V4(addr) => { + // 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.clone()) == 0xc0000009 || u32::from(addr.clone()) == 0xc000000a { + return true; + } + !addr.is_private() + && !addr.is_loopback() + && !addr.is_link_local() + && !addr.is_broadcast() + && !addr.is_documentation() + && !is_shared(addr) + && !is_ietf_protocol_assignment(addr) + && !is_reserved(addr) + && !is_benchmarking(addr) + // Make sure the address is not in 0.0.0.0/8 + && addr.octets()[0] != 0 + } + IpAddr::V6(addr) => { + match multicast_scope(&addr) { + Some(Ipv6MulticastScope::Global) => true, + None => is_unicast_global(&addr), + _ => false, + } + }, + } +} + +fn is_shared(addr: &Ipv4Addr) -> bool { + addr.octets()[0] == 100 && (addr.octets()[1] & 0b1100_0000 == 0b0100_0000) +} + +fn is_ietf_protocol_assignment(addr: &Ipv4Addr) -> bool { + addr.octets()[0] == 192 && addr.octets()[1] == 0 && addr.octets()[2] == 0 +} + +fn is_reserved(addr: &Ipv4Addr) -> bool { + addr.octets()[0] & 240 == 240 && !addr.is_broadcast() +} + +fn is_benchmarking(addr: &Ipv4Addr) -> bool { + addr.octets()[0] == 198 && (addr.octets()[1] & 0xfe) == 18 +} + +enum Ipv6MulticastScope { + InterfaceLocal, + LinkLocal, + RealmLocal, + AdminLocal, + SiteLocal, + OrganizationLocal, + Global, +} + +fn multicast_scope(addr: &Ipv6Addr) -> Option { + if addr.is_multicast() { + match addr.segments()[0] & 0x000f { + 1 => Some(Ipv6MulticastScope::InterfaceLocal), + 2 => Some(Ipv6MulticastScope::LinkLocal), + 3 => Some(Ipv6MulticastScope::RealmLocal), + 4 => Some(Ipv6MulticastScope::AdminLocal), + 5 => Some(Ipv6MulticastScope::SiteLocal), + 8 => Some(Ipv6MulticastScope::OrganizationLocal), + 14 => Some(Ipv6MulticastScope::Global), + _ => None, + } + } else { + None + } +} + +fn is_unicast_global(addr: &Ipv6Addr) -> bool { + !addr.is_multicast() + && !addr.is_loopback() + && !is_unicast_link_local(addr) + && !is_unique_local(addr) + && !addr.is_unspecified() + && !is_documentation(addr) +} + +fn is_unicast_link_local(addr: &Ipv6Addr) -> bool { + (addr.segments()[0] & 0xffc0) == 0xfe80 +} + +fn is_unique_local(addr: &Ipv6Addr) -> bool { + (addr.segments()[0] & 0xfe00) == 0xfc00 +} + +fn is_documentation(addr: &Ipv6Addr) -> bool { + (addr.segments()[0] == 0x2001) && (addr.segments()[1] == 0xdb8) +} + /// Generate a list of some object R constructed from all local `Ipv4Addr` objects. /// /// If any of the `SocketAddr`'s fail to resolve, this function will not return an error. @@ -142,4 +236,4 @@ fn get_local_addrs() -> io::Result> { let iface_iter = try!(get_if_addrs::get_if_addrs()).into_iter(); Ok(iface_iter.filter_map(|iface| Some(SocketAddr::new(iface.addr.ip(), 0))) .collect()) -} \ No newline at end of file +} From 03d832ac3b171f3a733f0f8c4f85f1e17e14d1d6 Mon Sep 17 00:00:00 2001 From: ssnover95 Date: Sun, 23 Aug 2020 16:37:26 -0400 Subject: [PATCH 2/2] refactor(message): Move ip feature implementations to ip.rs and add a note about the condition under which to remove them --- src/message/ip.rs | 101 +++++++++++++++++++++++++++++++++++++++++++++ src/message/mod.rs | 99 ++------------------------------------------ 2 files changed, 104 insertions(+), 96 deletions(-) create mode 100644 src/message/ip.rs diff --git a/src/message/ip.rs b/src/message/ip.rs new file mode 100644 index 000000000..a9f1e7c92 --- /dev/null +++ b/src/message/ip.rs @@ -0,0 +1,101 @@ +//! This module contains a copy of the implementation from the nightly feature +//! "ip" required to use the functionality of `IpAddr::is_global`. +//! These APIs should be removed and their new equivalents replaced when the ip +//! feature is stabilized. See this issue for tracking: +//! https://github.com/rust-lang/rust/issues/27709 + +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + +pub fn is_global(addr: &IpAddr) -> bool { + match addr { + IpAddr::V4(addr) => { + // 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.clone()) == 0xc0000009 || u32::from(addr.clone()) == 0xc000000a { + return true; + } + !addr.is_private() + && !addr.is_loopback() + && !addr.is_link_local() + && !addr.is_broadcast() + && !addr.is_documentation() + && !is_shared(addr) + && !is_ietf_protocol_assignment(addr) + && !is_reserved(addr) + && !is_benchmarking(addr) + // Make sure the address is not in 0.0.0.0/8 + && addr.octets()[0] != 0 + } + IpAddr::V6(addr) => { + match multicast_scope(&addr) { + Some(Ipv6MulticastScope::Global) => true, + None => is_unicast_global(&addr), + _ => false, + } + }, + } +} + +fn is_shared(addr: &Ipv4Addr) -> bool { + addr.octets()[0] == 100 && (addr.octets()[1] & 0b1100_0000 == 0b0100_0000) +} + +fn is_ietf_protocol_assignment(addr: &Ipv4Addr) -> bool { + addr.octets()[0] == 192 && addr.octets()[1] == 0 && addr.octets()[2] == 0 +} + +fn is_reserved(addr: &Ipv4Addr) -> bool { + addr.octets()[0] & 240 == 240 && !addr.is_broadcast() +} + +fn is_benchmarking(addr: &Ipv4Addr) -> bool { + addr.octets()[0] == 198 && (addr.octets()[1] & 0xfe) == 18 +} + +enum Ipv6MulticastScope { + InterfaceLocal, + LinkLocal, + RealmLocal, + AdminLocal, + SiteLocal, + OrganizationLocal, + Global, +} + +fn multicast_scope(addr: &Ipv6Addr) -> Option { + if addr.is_multicast() { + match addr.segments()[0] & 0x000f { + 1 => Some(Ipv6MulticastScope::InterfaceLocal), + 2 => Some(Ipv6MulticastScope::LinkLocal), + 3 => Some(Ipv6MulticastScope::RealmLocal), + 4 => Some(Ipv6MulticastScope::AdminLocal), + 5 => Some(Ipv6MulticastScope::SiteLocal), + 8 => Some(Ipv6MulticastScope::OrganizationLocal), + 14 => Some(Ipv6MulticastScope::Global), + _ => None, + } + } else { + None + } +} + +fn is_unicast_global(addr: &Ipv6Addr) -> bool { + !addr.is_multicast() + && !addr.is_loopback() + && !is_unicast_link_local(addr) + && !is_unique_local(addr) + && !addr.is_unspecified() + && !is_documentation(addr) +} + +fn is_unicast_link_local(addr: &Ipv6Addr) -> bool { + (addr.segments()[0] & 0xffc0) == 0xfe80 +} + +fn is_unique_local(addr: &Ipv6Addr) -> bool { + (addr.segments()[0] & 0xfe00) == 0xfc00 +} + +fn is_documentation(addr: &Ipv6Addr) -> bool { + (addr.segments()[0] == 0x2001) && (addr.segments()[1] == 0xdb8) +} \ No newline at end of file diff --git a/src/message/mod.rs b/src/message/mod.rs index 274fb9fa2..62676823b 100644 --- a/src/message/mod.rs +++ b/src/message/mod.rs @@ -1,11 +1,12 @@ //! Messaging primitives for discovering devices and services. use std::io; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +use std::net::SocketAddr; use net::connector::UdpConnector; use net::IpVersionMode; +mod ip; mod notify; mod search; mod ssdp; @@ -123,7 +124,7 @@ fn map_local(mut f: F) -> io::Result> } } // Filter all loopback and global IPv6 addresses - SocketAddr::V6(n) if !n.ip().is_loopback() && !is_global(&addr.ip()) => { + SocketAddr::V6(n) if !n.ip().is_loopback() && !ip::is_global(&addr.ip()) => { if let Some(x) = try!(f(&addr)) { obj_list.push(x); } @@ -135,100 +136,6 @@ fn map_local(mut f: F) -> io::Result> Ok(obj_list) } -fn is_global(addr: &IpAddr) -> bool { - match addr { - IpAddr::V4(addr) => { - // 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.clone()) == 0xc0000009 || u32::from(addr.clone()) == 0xc000000a { - return true; - } - !addr.is_private() - && !addr.is_loopback() - && !addr.is_link_local() - && !addr.is_broadcast() - && !addr.is_documentation() - && !is_shared(addr) - && !is_ietf_protocol_assignment(addr) - && !is_reserved(addr) - && !is_benchmarking(addr) - // Make sure the address is not in 0.0.0.0/8 - && addr.octets()[0] != 0 - } - IpAddr::V6(addr) => { - match multicast_scope(&addr) { - Some(Ipv6MulticastScope::Global) => true, - None => is_unicast_global(&addr), - _ => false, - } - }, - } -} - -fn is_shared(addr: &Ipv4Addr) -> bool { - addr.octets()[0] == 100 && (addr.octets()[1] & 0b1100_0000 == 0b0100_0000) -} - -fn is_ietf_protocol_assignment(addr: &Ipv4Addr) -> bool { - addr.octets()[0] == 192 && addr.octets()[1] == 0 && addr.octets()[2] == 0 -} - -fn is_reserved(addr: &Ipv4Addr) -> bool { - addr.octets()[0] & 240 == 240 && !addr.is_broadcast() -} - -fn is_benchmarking(addr: &Ipv4Addr) -> bool { - addr.octets()[0] == 198 && (addr.octets()[1] & 0xfe) == 18 -} - -enum Ipv6MulticastScope { - InterfaceLocal, - LinkLocal, - RealmLocal, - AdminLocal, - SiteLocal, - OrganizationLocal, - Global, -} - -fn multicast_scope(addr: &Ipv6Addr) -> Option { - if addr.is_multicast() { - match addr.segments()[0] & 0x000f { - 1 => Some(Ipv6MulticastScope::InterfaceLocal), - 2 => Some(Ipv6MulticastScope::LinkLocal), - 3 => Some(Ipv6MulticastScope::RealmLocal), - 4 => Some(Ipv6MulticastScope::AdminLocal), - 5 => Some(Ipv6MulticastScope::SiteLocal), - 8 => Some(Ipv6MulticastScope::OrganizationLocal), - 14 => Some(Ipv6MulticastScope::Global), - _ => None, - } - } else { - None - } -} - -fn is_unicast_global(addr: &Ipv6Addr) -> bool { - !addr.is_multicast() - && !addr.is_loopback() - && !is_unicast_link_local(addr) - && !is_unique_local(addr) - && !addr.is_unspecified() - && !is_documentation(addr) -} - -fn is_unicast_link_local(addr: &Ipv6Addr) -> bool { - (addr.segments()[0] & 0xffc0) == 0xfe80 -} - -fn is_unique_local(addr: &Ipv6Addr) -> bool { - (addr.segments()[0] & 0xfe00) == 0xfc00 -} - -fn is_documentation(addr: &Ipv6Addr) -> bool { - (addr.segments()[0] == 0x2001) && (addr.segments()[1] == 0xdb8) -} - /// Generate a list of some object R constructed from all local `Ipv4Addr` objects. /// /// If any of the `SocketAddr`'s fail to resolve, this function will not return an error.