active_call/
net_tool.rs

1use anyhow::Result;
2use get_if_addrs::get_if_addrs;
3use std::net::IpAddr;
4
5pub fn get_first_non_loopback_interface() -> Result<IpAddr> {
6    for i in get_if_addrs()? {
7        if !i.is_loopback() {
8            match i.addr {
9                get_if_addrs::IfAddr::V4(ref addr) => return Ok(std::net::IpAddr::V4(addr.ip)),
10                _ => continue,
11            }
12        }
13    }
14    Err(anyhow::anyhow!("No IPV4 interface found"))
15}
16/// Check if an IP address is private (RFC 1918, RFC 4193, loopback, etc.)
17pub fn is_private_ip(ip: &IpAddr) -> bool {
18    match ip {
19        IpAddr::V4(ipv4) => {
20            // RFC 1918 private addresses
21            // 10.0.0.0/8
22            if ipv4.octets()[0] == 10 {
23                return true;
24            }
25            // 172.16.0.0/12
26            if ipv4.octets()[0] == 172 && (ipv4.octets()[1] & 0xf0) == 16 {
27                return true;
28            }
29            // 192.168.0.0/16
30            if ipv4.octets()[0] == 192 && ipv4.octets()[1] == 168 {
31                return true;
32            }
33            // 127.0.0.0/8 (loopback)
34            if ipv4.octets()[0] == 127 {
35                return true;
36            }
37            // 169.254.0.0/16 (link-local)
38            if ipv4.octets()[0] == 169 && ipv4.octets()[1] == 254 {
39                return true;
40            }
41            false
42        }
43        IpAddr::V6(ipv6) => {
44            // RFC 4193 unique local addresses (fc00::/7)
45            if (ipv6.octets()[0] & 0xfe) == 0xfc {
46                return true;
47            }
48            // loopback (::1)
49            if ipv6.is_loopback() {
50                return true;
51            }
52            // link-local (fe80::/10)
53            if (ipv6.octets()[0] == 0xfe) && ((ipv6.octets()[1] & 0xc0) == 0x80) {
54                return true;
55            }
56            false
57        }
58    }
59}
60
61/// Parse SDP and extract RTP addresses
62pub fn extract_rtp_addresses_from_sdp(sdp: &str) -> Result<Vec<IpAddr>> {
63    let mut addresses = Vec::new();
64
65    for line in sdp.lines() {
66        if line.starts_with("c=") {
67            // Connection information: c=<nettype> <addrtype> <connection-address>
68            let parts: Vec<&str> = line.splitn(4, ' ').collect();
69            if parts.len() >= 3 {
70                if let Ok(addr) = parts[2].parse::<IpAddr>() {
71                    addresses.push(addr);
72                }
73            }
74        }
75    }
76
77    Ok(addresses)
78}
79
80/// Check if SDP contains any private IP addresses
81pub fn sdp_contains_private_ip(sdp: &str) -> Result<bool> {
82    let addresses = extract_rtp_addresses_from_sdp(sdp)?;
83    Ok(addresses.iter().any(is_private_ip))
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89    use std::net::{Ipv4Addr, Ipv6Addr};
90
91    #[test]
92    fn test_is_private_ip() {
93        // Private IPv4 addresses
94        assert!(is_private_ip(&IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1))));
95        assert!(is_private_ip(&IpAddr::V4(Ipv4Addr::new(172, 16, 0, 1))));
96        assert!(is_private_ip(&IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1))));
97        assert!(is_private_ip(&IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))));
98        assert!(is_private_ip(&IpAddr::V4(Ipv4Addr::new(169, 254, 1, 1))));
99
100        // Public IPv4 addresses
101        assert!(!is_private_ip(&IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8))));
102        assert!(!is_private_ip(&IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1))));
103
104        // Private IPv6 addresses
105        assert!(is_private_ip(&IpAddr::V6(Ipv6Addr::new(
106            0xfc00, 0, 0, 0, 0, 0, 0, 1
107        ))));
108        assert!(is_private_ip(&IpAddr::V6(Ipv6Addr::LOCALHOST)));
109        assert!(is_private_ip(&IpAddr::V6(Ipv6Addr::new(
110            0xfe80, 0, 0, 0, 0, 0, 0, 1
111        ))));
112    }
113
114    #[test]
115    fn test_extract_rtp_addresses_from_sdp() {
116        let sdp = "v=0\r\n\
117                   o=- 1234567890 1234567890 IN IP4 192.168.1.100\r\n\
118                   s=Call\r\n\
119                   c=IN IP4 192.168.1.100\r\n\
120                   t=0 0\r\n\
121                   m=audio 49170 RTP/AVP 0 8 97\r\n";
122
123        let addresses = extract_rtp_addresses_from_sdp(sdp).unwrap();
124        assert_eq!(addresses.len(), 1);
125        assert_eq!(addresses[0], IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)));
126    }
127
128    #[test]
129    fn test_sdp_contains_private_ip() {
130        let private_sdp = "v=0\r\n\
131                          o=- 1234567890 1234567890 IN IP4 192.168.1.100\r\n\
132                          s=Call\r\n\
133                          c=IN IP4 192.168.1.100\r\n\
134                          t=0 0\r\n\
135                          m=audio 49170 RTP/AVP 0 8 97\r\n";
136
137        let public_sdp = "v=0\r\n\
138                         o=- 1234567890 1234567890 IN IP4 8.8.8.8\r\n\
139                         s=Call\r\n\
140                         c=IN IP4 8.8.8.8\r\n\
141                         t=0 0\r\n\
142                         m=audio 49170 RTP/AVP 0 8 97\r\n";
143
144        assert!(sdp_contains_private_ip(private_sdp).unwrap());
145        assert!(!sdp_contains_private_ip(public_sdp).unwrap());
146    }
147}