1use std::net::IpAddr;
58
59mod error;
60
61pub use error::Error;
62
63#[cfg(target_os = "linux")]
64pub mod linux;
65#[cfg(target_os = "linux")]
66pub use crate::linux::*;
67
68#[cfg(any(
69 target_os = "freebsd",
70 target_os = "openbsd",
71 target_os = "netbsd",
72 target_os = "dragonfly",
73 target_os = "macos",
74 target_os = "android",
75 target_os = "ios",
76))]
77pub mod unix;
78
79#[cfg(any(
80 target_os = "freebsd",
81 target_os = "openbsd",
82 target_os = "netbsd",
83 target_os = "dragonfly",
84 target_os = "macos",
85 target_os = "android",
86 target_os = "ios",
87))]
88pub use crate::unix::*;
89
90#[cfg(target_family = "windows")]
91pub mod windows;
92#[cfg(target_family = "windows")]
93pub use crate::windows::*;
94
95pub fn local_ip() -> Result<IpAddr, Error> {
108 #[cfg(target_os = "linux")]
109 {
110 crate::linux::local_ip()
111 }
112
113 #[cfg(any(
114 target_os = "freebsd",
115 target_os = "openbsd",
116 target_os = "netbsd",
117 target_os = "dragonfly",
118 target_os = "macos",
119 target_os = "android",
120 target_os = "ios",
121 ))]
122 {
123 let ifas = crate::unix::list_afinet_netifas_info()?;
124
125 ifas.into_iter()
126 .find_map(|ifa| {
127 if !ifa.is_loopback && ifa.addr.is_ipv4() && !ifa.is_mobile_data() {
128 Some(ifa.addr)
129 } else {
130 None
131 }
132 })
133 .ok_or(Error::LocalIpAddressNotFound)
134 }
135
136 #[cfg(target_os = "windows")]
137 {
138 use windows_sys::Win32::Networking::WinSock::AF_INET;
139
140 let ip_addresses = crate::windows::list_local_ip_addresses(AF_INET)?;
141
142 ip_addresses
143 .into_iter()
144 .find(|ip_address| matches!(ip_address, IpAddr::V4(_)))
145 .ok_or(Error::LocalIpAddressNotFound)
146 }
147
148 #[cfg(not(any(
150 target_os = "linux",
151 target_os = "windows",
152 target_os = "macos",
153 target_os = "freebsd",
154 target_os = "openbsd",
155 target_os = "netbsd",
156 target_os = "dragonfly",
157 target_os = "android",
158 target_os = "ios",
159 )))]
160 {
161 Err(Error::PlatformNotSupported(
162 std::env::consts::OS.to_string(),
163 ))
164 }
165}
166
167pub fn local_ipv6() -> Result<IpAddr, Error> {
180 #[cfg(target_os = "linux")]
181 {
182 crate::linux::local_ipv6()
183 }
184
185 #[cfg(any(
186 target_os = "freebsd",
187 target_os = "openbsd",
188 target_os = "netbsd",
189 target_os = "dragonfly",
190 target_os = "macos",
191 target_os = "android",
192 target_os = "ios",
193 ))]
194 {
195 let ifas = crate::unix::list_afinet_netifas_info()?;
196
197 ifas.into_iter()
198 .find_map(|ifa| {
199 if !ifa.is_loopback && ifa.addr.is_ipv6() && !ifa.is_mobile_data() {
200 Some(ifa.addr)
201 } else {
202 None
203 }
204 })
205 .ok_or(Error::LocalIpAddressNotFound)
206 }
207
208 #[cfg(target_os = "windows")]
209 {
210 use windows_sys::Win32::Networking::WinSock::AF_INET6;
211
212 let ip_addresses = crate::windows::list_local_ip_addresses(AF_INET6)?;
213
214 ip_addresses
215 .into_iter()
216 .find(|ip_address| matches!(ip_address, IpAddr::V6(_)))
217 .ok_or(Error::LocalIpAddressNotFound)
218 }
219
220 #[cfg(not(any(
222 target_os = "linux",
223 target_os = "windows",
224 target_os = "macos",
225 target_os = "freebsd",
226 target_os = "openbsd",
227 target_os = "netbsd",
228 target_os = "dragonfly",
229 target_os = "android",
230 target_os = "ios",
231 )))]
232 {
233 Err(Error::PlatformNotSupported(
234 std::env::consts::OS.to_string(),
235 ))
236 }
237}
238
239#[cfg(not(any(
241 target_os = "linux",
242 target_os = "windows",
243 target_os = "macos",
244 target_os = "freebsd",
245 target_os = "openbsd",
246 target_os = "netbsd",
247 target_os = "dragonfly",
248 target_os = "android",
249 target_os = "ios",
250)))]
251pub fn list_afinet_netifas() -> Result<Vec<(String, IpAddr)>, Error> {
252 Err(Error::PlatformNotSupported(
253 std::env::consts::OS.to_string(),
254 ))
255}
256
257mod tests {
258 #[allow(unused_imports)]
259 use super::*;
260
261 #[test]
262 #[cfg(target_os = "linux")]
263 fn find_local_ip() {
264 let my_local_ip = local_ip();
265
266 assert!(matches!(my_local_ip, Ok(IpAddr::V4(_))));
267 println!("Linux 'local_ip': {:?}", my_local_ip);
268 }
269
270 #[test]
271 #[cfg(any(
272 target_os = "freebsd",
273 target_os = "openbsd",
274 target_os = "netbsd",
275 target_os = "dragonfly",
276 target_os = "macos",
277 target_os = "android",
278 target_os = "ios",
279 ))]
280 fn find_local_ip() {
281 let my_local_ip = local_ip();
282
283 assert!(matches!(my_local_ip, Ok(IpAddr::V4(_))));
284 println!("Unix 'local_ip': {:?}", my_local_ip);
285 }
286
287 #[test]
288 #[cfg(target_os = "windows")]
289 fn find_local_ip() {
290 let my_local_ip = local_ip();
291
292 assert!(matches!(my_local_ip, Ok(IpAddr::V4(_))));
293 println!("Windows 'local_ip': {:?}", my_local_ip);
294 }
295
296 #[test]
297 #[cfg(target_os = "linux")]
298 fn find_network_interfaces() {
299 let network_interfaces = list_afinet_netifas();
300
301 assert!(network_interfaces.is_ok());
302 assert!(!network_interfaces.unwrap().is_empty());
303 }
304
305 #[test]
306 #[cfg(any(
307 target_os = "freebsd",
308 target_os = "openbsd",
309 target_os = "netbsd",
310 target_os = "dragonfly",
311 target_os = "macos",
312 target_os = "android",
313 target_os = "ios",
314 ))]
315 fn find_network_interfaces() {
316 let network_interfaces = list_afinet_netifas();
317
318 assert!(network_interfaces.is_ok());
319 assert!(!network_interfaces.unwrap().is_empty());
320 }
321
322 #[test]
323 #[cfg(target_os = "windows")]
324 fn find_network_interfaces() {
325 let network_interfaces = list_afinet_netifas();
326
327 assert!(network_interfaces.is_ok());
328 assert!(!network_interfaces.unwrap().is_empty());
329 }
330}