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 = lan_ips();
22 let rank = |ip: &Ipv4Addr| match ip.octets() {
23 [192, 168, ..] => 0,
24 _ if ip.is_private() => 1,
25 _ => 2,
26 };
27 ips.sort_by_key(|ip| (rank(ip), *ip));
28 ips.first().copied()
29}
30
31pub fn lan_ips() -> Vec<Ipv4Addr> {
33 let mut ips: Vec<Ipv4Addr> = if_addrs::get_if_addrs()
34 .unwrap_or_default()
35 .into_iter()
36 .filter_map(|iface| match iface.ip() {
37 IpAddr::V4(ip) if !ip.is_loopback() && !ip.is_link_local() => Some(ip),
38 _ => None,
39 })
40 .collect();
41 ips.sort();
42 ips.dedup();
43 ips
44}
45
46pub fn local_ip_for(peer: IpAddr) -> Option<Ipv4Addr> {
48 local_ip_towards(peer).or_else(host_ip)
49}