Skip to content
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

Feature/local impl of ip feature #48

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![allow(unused_features)]
#![feature(ip)]
#![recursion_limit = "1024"]

//! An asynchronous abstraction for discovering devices and services on a network.
Expand Down
101 changes: 101 additions & 0 deletions src/message/ip.rs
Original file line number Diff line number Diff line change
@@ -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<Ipv6MulticastScope> {
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)
}
5 changes: 3 additions & 2 deletions src/message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::net::SocketAddr;
use net::connector::UdpConnector;
use net::IpVersionMode;

mod ip;
mod notify;
mod search;
mod ssdp;
Expand Down Expand Up @@ -123,7 +124,7 @@ fn map_local<F, R>(mut f: F) -> io::Result<Vec<R>>
}
}
// 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() && !ip::is_global(&addr.ip()) => {
if let Some(x) = try!(f(&addr)) {
obj_list.push(x);
}
Expand All @@ -142,4 +143,4 @@ fn get_local_addrs() -> io::Result<Vec<SocketAddr>> {
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())
}
}