1use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
4
5pub fn local_ip_towards(target: IpAddr) -> Option<Ipv4Addr> {
8 let sock = UdpSocket::bind((Ipv4Addr::UNSPECIFIED, 0)).ok()?;
9 sock.connect(SocketAddr::new(target, 9)).ok()?;
10 match sock.local_addr().ok()?.ip() {
11 IpAddr::V4(ip) if !ip.is_unspecified() && !ip.is_loopback() => Some(ip),
12 _ => None,
13 }
14}
15
16pub fn host_ip() -> Option<Ipv4Addr> {
21 let mut ips: Vec<Ipv4Addr> = if_addrs::get_if_addrs()
22 .ok()?
23 .into_iter()
24 .filter_map(|iface| match iface.ip() {
25 IpAddr::V4(ip) if !ip.is_loopback() && !ip.is_link_local() => Some(ip),
26 _ => None,
27 })
28 .collect();
29 let rank = |ip: &Ipv4Addr| match ip.octets() {
30 [192, 168, ..] => 0,
31 _ if ip.is_private() => 1,
32 _ => 2,
33 };
34 ips.sort_by_key(|ip| (rank(ip), *ip));
35 ips.first().copied()
36}
37
38pub fn local_ip_for(peer: IpAddr) -> Option<Ipv4Addr> {
40 local_ip_towards(peer).or_else(host_ip)
41}