clawft_kernel/workload_runtime/infer/
exposure.rs1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
7use std::time::Duration;
8
9use tokio::net::TcpStream;
10use tokio::task::JoinSet;
11
12const CONNECT_TIMEOUT: Duration = Duration::from_millis(300);
13
14pub fn local_addrs() -> Vec<IpAddr> {
17 let mut out: Vec<IpAddr> = Vec::new();
18 let mut head: *mut libc::ifaddrs = std::ptr::null_mut();
19 unsafe {
22 if libc::getifaddrs(&mut head) != 0 {
23 return out;
24 }
25 let mut cur = head;
26 while !cur.is_null() {
27 let a = &*cur;
28 if !a.ifa_addr.is_null() {
29 match i32::from((*a.ifa_addr).sa_family) {
30 libc::AF_INET => {
31 let s = &*(a.ifa_addr as *const libc::sockaddr_in);
32 out.push(IpAddr::V4(Ipv4Addr::from(u32::from_be(s.sin_addr.s_addr))));
33 }
34 libc::AF_INET6 => {
35 let s = &*(a.ifa_addr as *const libc::sockaddr_in6);
36 out.push(IpAddr::V6(Ipv6Addr::from(s.sin6_addr.s6_addr)));
37 }
38 _ => {}
39 }
40 }
41 cur = a.ifa_next;
42 }
43 libc::freeifaddrs(head);
44 }
45 out.retain(|ip| {
46 !ip.is_loopback()
47 && !ip.is_unspecified()
48 && !matches!(ip, IpAddr::V6(v) if v.segments()[0] & 0xffc0 == 0xfe80)
49 });
50 out.sort();
51 out.dedup();
52 out
53}
54
55pub async fn port_in_use(ip: IpAddr, port: u16) -> bool {
57 matches!(
58 tokio::time::timeout(
59 CONNECT_TIMEOUT,
60 TcpStream::connect(SocketAddr::new(ip, port))
61 )
62 .await,
63 Ok(Ok(_))
64 )
65}
66
67pub async fn reachable_beyond_loopback(port: u16) -> Vec<IpAddr> {
69 let mut set = JoinSet::new();
70 for ip in local_addrs() {
71 set.spawn(async move { port_in_use(ip, port).await.then_some(ip) });
72 }
73 let mut out = Vec::new();
74 while let Some(r) = set.join_next().await {
75 if let Ok(Some(ip)) = r {
76 out.push(ip);
77 }
78 }
79 out.sort();
80 out
81}