address ordering
This commit is contained in:
parent
dc9f71a683
commit
268e280914
@ -223,7 +223,7 @@ impl Network {
|
|||||||
} else {
|
} else {
|
||||||
inner
|
inner
|
||||||
.interfaces
|
.interfaces
|
||||||
.default_route_addresses()
|
.best_addresses()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|a| SocketAddr::new(*a, from.port()))
|
.map(|a| SocketAddr::new(*a, from.port()))
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -96,6 +96,7 @@ pub struct InterfaceAddress {
|
|||||||
|
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
|
|
||||||
|
// less is less preferable, greater is more preferable
|
||||||
impl Ord for InterfaceAddress {
|
impl Ord for InterfaceAddress {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
match (&self.if_addr, &other.if_addr) {
|
match (&self.if_addr, &other.if_addr) {
|
||||||
@ -155,8 +156,30 @@ impl Ord for InterfaceAddress {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(IfAddr::V4(_), IfAddr::V6(_)) => return Ordering::Less,
|
(IfAddr::V4(a), IfAddr::V6(b)) => {
|
||||||
(IfAddr::V6(_), IfAddr::V4(_)) => return Ordering::Greater,
|
// If the IPv6 address is preferred and not temporary, compare if it is global scope
|
||||||
|
if other.flags.is_preferred && !other.flags.is_temporary {
|
||||||
|
let ret = ipv4addr_is_global(&a.ip).cmp(&ipv6addr_is_global(&b.ip));
|
||||||
|
if ret != Ordering::Equal {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default, prefer IPv4 because many IPv6 addresses are not actually routed
|
||||||
|
return Ordering::Greater;
|
||||||
|
}
|
||||||
|
(IfAddr::V6(a), IfAddr::V4(b)) => {
|
||||||
|
// If the IPv6 address is preferred and not temporary, compare if it is global scope
|
||||||
|
if self.flags.is_preferred && !self.flags.is_temporary {
|
||||||
|
let ret = ipv6addr_is_global(&a.ip).cmp(&ipv4addr_is_global(&b.ip));
|
||||||
|
if ret != Ordering::Equal {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default, prefer IPv4 because many IPv6 addresses are not actually routed
|
||||||
|
return Ordering::Less;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// stable sort
|
// stable sort
|
||||||
let ret = self.if_addr.cmp(&other.if_addr);
|
let ret = self.if_addr.cmp(&other.if_addr);
|
||||||
@ -193,6 +216,14 @@ impl InterfaceAddress {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
// enum NetworkInterfaceType {
|
||||||
|
// Mobile, // Least preferable, usually metered and slow
|
||||||
|
// Unknown, // Everything else if we can't detect the type
|
||||||
|
// Wireless, // Wifi is usually free or cheap and medium speed
|
||||||
|
// Wired, // Wired is usually free or cheap and high speed
|
||||||
|
// }
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone)]
|
#[derive(PartialEq, Eq, Clone)]
|
||||||
pub struct NetworkInterface {
|
pub struct NetworkInterface {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -239,36 +270,24 @@ impl NetworkInterface {
|
|||||||
self.flags.has_default_route
|
self.flags.has_default_route
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn primary_ipv4(&self) -> Option<Ipv4Addr> {
|
pub fn primary_ipv4(&self) -> Option<InterfaceAddress> {
|
||||||
let mut ipv4addrs: Vec<&InterfaceAddress> = self
|
let mut ipv4addrs: Vec<&InterfaceAddress> = self
|
||||||
.addrs
|
.addrs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|a| matches!(a.if_addr(), IfAddr::V4(_)))
|
.filter(|a| matches!(a.if_addr(), IfAddr::V4(_)))
|
||||||
.collect();
|
.collect();
|
||||||
ipv4addrs.sort();
|
ipv4addrs.sort();
|
||||||
ipv4addrs
|
ipv4addrs.last().cloned().cloned()
|
||||||
.last()
|
|
||||||
.map(|x| match x.if_addr() {
|
|
||||||
IfAddr::V4(v4) => Some(v4.ip),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.flatten()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn primary_ipv6(&self) -> Option<Ipv6Addr> {
|
pub fn primary_ipv6(&self) -> Option<InterfaceAddress> {
|
||||||
let mut ipv6addrs: Vec<&InterfaceAddress> = self
|
let mut ipv6addrs: Vec<&InterfaceAddress> = self
|
||||||
.addrs
|
.addrs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|a| matches!(a.if_addr(), IfAddr::V6(_)))
|
.filter(|a| matches!(a.if_addr(), IfAddr::V6(_)))
|
||||||
.collect();
|
.collect();
|
||||||
ipv6addrs.sort();
|
ipv6addrs.sort();
|
||||||
ipv6addrs
|
ipv6addrs.last().cloned().cloned()
|
||||||
.last()
|
|
||||||
.map(|x| match x.if_addr() {
|
|
||||||
IfAddr::V6(v6) => Some(v6.ip),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.flatten()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,11 +305,7 @@ impl fmt::Debug for NetworkInterfaces {
|
|||||||
.finish()?;
|
.finish()?;
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
writeln!(
|
writeln!(f, "// best_addresses: {:?}", self.best_addresses())?;
|
||||||
f,
|
|
||||||
"// default_route_addresses: {:?}",
|
|
||||||
self.default_route_addresses()
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -337,18 +352,25 @@ impl NetworkInterfaces {
|
|||||||
self.interfaces.iter()
|
self.interfaces.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_route_addresses(&self) -> Vec<IpAddr> {
|
pub fn best_addresses(&self) -> Vec<IpAddr> {
|
||||||
let mut out = Vec::new();
|
// Reduce interfaces to their best routable ip addresses
|
||||||
|
let mut intf_addrs = Vec::new();
|
||||||
for intf in self.interfaces.values() {
|
for intf in self.interfaces.values() {
|
||||||
if intf.is_running() && intf.has_default_route() && !intf.is_loopback() {
|
if !intf.is_running() || !intf.has_default_route() || intf.is_loopback() {
|
||||||
if let Some(pipv4) = intf.primary_ipv4() {
|
continue;
|
||||||
out.push(IpAddr::V4(pipv4));
|
}
|
||||||
}
|
if let Some(pipv4) = intf.primary_ipv4() {
|
||||||
if let Some(pipv6) = intf.primary_ipv6() {
|
intf_addrs.push(pipv4);
|
||||||
out.push(IpAddr::V6(pipv6));
|
}
|
||||||
}
|
if let Some(pipv6) = intf.primary_ipv6() {
|
||||||
|
intf_addrs.push(pipv6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out
|
|
||||||
|
// Sort one more time to get the best interface addresses overall
|
||||||
|
intf_addrs.sort();
|
||||||
|
|
||||||
|
// Now export just the addresses
|
||||||
|
intf_addrs.iter().map(|x| x.if_addr().ip()).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user