1use std::net::Ipv4Addr;
8
9#[derive(Debug, Clone, Default)]
11pub struct Ipv4Route {
12 pub interface: Option<String>,
14 pub source: Option<Ipv4Addr>,
16 pub gateway: Option<Ipv4Addr>,
18 pub is_local: bool,
20 pub prefix_len: u8,
22 pub metric: u32,
24}
25
26impl Ipv4Route {
27 pub fn none() -> Self {
29 Self::default()
30 }
31
32 pub fn local(interface: String, source: Ipv4Addr) -> Self {
34 Self {
35 interface: Some(interface),
36 source: Some(source),
37 gateway: None,
38 is_local: true,
39 prefix_len: 32,
40 metric: 0,
41 }
42 }
43
44 pub fn via_gateway(interface: String, source: Ipv4Addr, gateway: Ipv4Addr) -> Self {
46 Self {
47 interface: Some(interface),
48 source: Some(source),
49 gateway: Some(gateway),
50 is_local: false,
51 prefix_len: 0,
52 metric: 0,
53 }
54 }
55
56 pub fn is_valid(&self) -> bool {
58 self.interface.is_some()
59 }
60
61 pub fn next_hop(&self, dst: Ipv4Addr) -> Ipv4Addr {
63 self.gateway.unwrap_or(dst)
64 }
65}
66
67pub trait Ipv4Router {
69 fn route(&self, dst: Ipv4Addr) -> Ipv4Route;
71}
72
73pub fn get_route(dst: Ipv4Addr) -> Ipv4Route {
78 if dst.is_loopback() {
80 return Ipv4Route::local("lo".to_string(), Ipv4Addr::LOCALHOST);
81 }
82
83 if dst.is_broadcast() || dst == Ipv4Addr::BROADCAST {
84 return get_default_route()
85 .map(|r| Ipv4Route {
86 is_local: true,
87 ..r
88 })
89 .unwrap_or_default();
90 }
91
92 if dst.is_multicast() {
93 return get_default_route()
95 .map(|r| Ipv4Route {
96 gateway: None,
97 is_local: true,
98 ..r
99 })
100 .unwrap_or_default();
101 }
102
103 let interfaces = pnet_datalink::interfaces();
105
106 for iface in &interfaces {
108 if !iface.is_up() || iface.is_loopback() {
109 continue;
110 }
111
112 for ip_network in &iface.ips {
113 if let std::net::IpAddr::V4(ip) = ip_network.ip() {
114 if ip_network.contains(std::net::IpAddr::V4(dst)) {
116 return Ipv4Route {
117 interface: Some(iface.name.clone()),
118 source: Some(ip),
119 gateway: None,
120 is_local: true,
121 prefix_len: ip_network.prefix(),
122 metric: 0,
123 };
124 }
125 }
126 }
127 }
128
129 if let Some(route) = get_default_route() {
131 return route;
132 }
133
134 Ipv4Route::none()
135}
136
137pub fn get_default_route() -> Option<Ipv4Route> {
139 let default_iface = default_net::get_default_interface().ok()?;
141 let gateway = default_net::get_default_gateway().ok()?;
142
143 let interfaces = pnet_datalink::interfaces();
144 let iface = interfaces.iter().find(|i| i.name == default_iface.name)?;
145
146 let source = iface.ips.iter().find_map(|ip| {
148 if let std::net::IpAddr::V4(v4) = ip.ip() {
149 Some(v4)
150 } else {
151 None
152 }
153 })?;
154
155 let gw_ip = match gateway.ip_addr {
156 std::net::IpAddr::V4(v4) => v4,
157 _ => return None,
158 };
159
160 Some(Ipv4Route {
161 interface: Some(iface.name.clone()),
162 source: Some(source),
163 gateway: Some(gw_ip),
164 is_local: false,
165 prefix_len: 0,
166 metric: 0,
167 })
168}
169
170pub fn get_source_for_dst(dst: Ipv4Addr) -> Option<Ipv4Addr> {
174 get_route(dst).source
175}
176
177pub fn get_interface_for_dst(dst: Ipv4Addr) -> Option<String> {
179 get_route(dst).interface
180}
181
182pub fn is_local_destination(dst: Ipv4Addr) -> bool {
184 get_route(dst).is_local
185}
186
187pub fn get_ipv4_interfaces() -> Vec<Ipv4Interface> {
189 pnet_datalink::interfaces()
190 .into_iter()
191 .filter_map(|iface| {
192 if !iface.is_up() {
193 return None;
194 }
195
196 let addrs: Vec<_> = iface
197 .ips
198 .iter()
199 .filter_map(|ip| {
200 if let std::net::IpAddr::V4(v4) = ip.ip() {
201 Some(Ipv4InterfaceAddr {
202 address: v4,
203 prefix_len: ip.prefix(),
204 broadcast: match ip.broadcast() {
206 std::net::IpAddr::V4(v4) => Some(v4),
207 _ => None,
208 },
209 })
210 } else {
211 None
212 }
213 })
214 .collect();
215
216 if addrs.is_empty() {
217 return None;
218 }
219
220 let is_loopback = iface.is_loopback();
223 let is_up = iface.is_up();
224 let is_running = iface.is_running();
225 let is_multicast = iface.is_multicast();
226 let is_broadcast = iface.is_broadcast();
227
228 Some(Ipv4Interface {
229 name: iface.name, index: iface.index,
231 mac: iface.mac.map(|m| m.octets()),
232 addresses: addrs,
233 is_loopback,
234 is_up,
235 is_running,
236 is_multicast,
237 is_broadcast,
238 mtu: None, })
240 })
241 .collect()
242}
243
244#[derive(Debug, Clone)]
246pub struct Ipv4Interface {
247 pub name: String,
249 pub index: u32,
251 pub mac: Option<[u8; 6]>,
253 pub addresses: Vec<Ipv4InterfaceAddr>,
255 pub is_loopback: bool,
257 pub is_up: bool,
259 pub is_running: bool,
261 pub is_multicast: bool,
263 pub is_broadcast: bool,
265 pub mtu: Option<u32>,
267}
268
269impl Ipv4Interface {
270 pub fn primary_address(&self) -> Option<Ipv4Addr> {
272 self.addresses.first().map(|a| a.address)
273 }
274
275 pub fn contains(&self, addr: Ipv4Addr) -> bool {
277 self.addresses.iter().any(|a| {
278 let mask = prefix_to_mask(a.prefix_len);
279 (u32::from(a.address) & mask) == (u32::from(addr) & mask)
280 })
281 }
282}
283
284#[derive(Debug, Clone)]
286pub struct Ipv4InterfaceAddr {
287 pub address: Ipv4Addr,
289 pub prefix_len: u8,
291 pub broadcast: Option<Ipv4Addr>,
293}
294
295impl Ipv4InterfaceAddr {
296 pub fn network(&self) -> Ipv4Addr {
298 let mask = prefix_to_mask(self.prefix_len);
299 Ipv4Addr::from(u32::from(self.address) & mask)
300 }
301
302 pub fn netmask(&self) -> Ipv4Addr {
304 Ipv4Addr::from(prefix_to_mask(self.prefix_len))
305 }
306}
307
308pub fn prefix_to_mask(prefix: u8) -> u32 {
310 if prefix >= 32 {
311 0xFFFFFFFF
312 } else if prefix == 0 {
313 0
314 } else {
315 !((1u32 << (32 - prefix)) - 1)
316 }
317}
318
319pub fn mask_to_prefix(mask: Ipv4Addr) -> u8 {
321 let mask_u32 = u32::from(mask);
322 mask_u32.leading_ones() as u8
323}
324
325pub fn ip_in_network(ip: Ipv4Addr, network: Ipv4Addr, prefix: u8) -> bool {
327 let mask = prefix_to_mask(prefix);
328 (u32::from(ip) & mask) == (u32::from(network) & mask)
329}
330
331pub fn broadcast_address(network: Ipv4Addr, prefix: u8) -> Ipv4Addr {
333 let mask = prefix_to_mask(prefix);
334 Ipv4Addr::from(u32::from(network) | !mask)
335}
336
337pub fn network_host_count(prefix: u8) -> u32 {
339 if prefix >= 31 {
340 2u32.saturating_sub(prefix as u32 - 30)
342 } else {
343 (1u32 << (32 - prefix)) - 2 }
345}
346
347#[cfg(test)]
348mod tests {
349 use super::*;
350
351 #[test]
352 fn test_prefix_to_mask() {
353 assert_eq!(prefix_to_mask(0), 0x00000000);
354 assert_eq!(prefix_to_mask(8), 0xFF000000);
355 assert_eq!(prefix_to_mask(16), 0xFFFF0000);
356 assert_eq!(prefix_to_mask(24), 0xFFFFFF00);
357 assert_eq!(prefix_to_mask(32), 0xFFFFFFFF);
358 }
359
360 #[test]
361 fn test_mask_to_prefix() {
362 assert_eq!(mask_to_prefix(Ipv4Addr::new(255, 0, 0, 0)), 8);
363 assert_eq!(mask_to_prefix(Ipv4Addr::new(255, 255, 0, 0)), 16);
364 assert_eq!(mask_to_prefix(Ipv4Addr::new(255, 255, 255, 0)), 24);
365 assert_eq!(mask_to_prefix(Ipv4Addr::new(255, 255, 255, 255)), 32);
366 }
367
368 #[test]
369 fn test_ip_in_network() {
370 let network = Ipv4Addr::new(192, 168, 1, 0);
371 assert!(ip_in_network(Ipv4Addr::new(192, 168, 1, 100), network, 24));
372 assert!(ip_in_network(Ipv4Addr::new(192, 168, 1, 255), network, 24));
373 assert!(!ip_in_network(Ipv4Addr::new(192, 168, 2, 1), network, 24));
374 }
375
376 #[test]
377 fn test_broadcast_address() {
378 assert_eq!(
379 broadcast_address(Ipv4Addr::new(192, 168, 1, 0), 24),
380 Ipv4Addr::new(192, 168, 1, 255)
381 );
382 assert_eq!(
383 broadcast_address(Ipv4Addr::new(10, 0, 0, 0), 8),
384 Ipv4Addr::new(10, 255, 255, 255)
385 );
386 }
387
388 #[test]
389 fn test_network_host_count() {
390 assert_eq!(network_host_count(24), 254);
391 assert_eq!(network_host_count(16), 65534);
392 assert_eq!(network_host_count(8), 16777214);
393 }
394
395 #[test]
396 fn test_route_loopback() {
397 let route = get_route(Ipv4Addr::LOCALHOST);
398 assert!(route.is_local);
399 assert_eq!(route.interface, Some("lo".to_string()));
400 }
401
402 #[test]
403 fn test_ipv4_route() {
404 let route = Ipv4Route::local("eth0".to_string(), Ipv4Addr::new(192, 168, 1, 100));
405 assert!(route.is_valid());
406 assert!(route.is_local);
407 assert_eq!(
408 route.next_hop(Ipv4Addr::new(192, 168, 1, 200)),
409 Ipv4Addr::new(192, 168, 1, 200)
410 );
411
412 let route = Ipv4Route::via_gateway(
413 "eth0".to_string(),
414 Ipv4Addr::new(192, 168, 1, 100),
415 Ipv4Addr::new(192, 168, 1, 1),
416 );
417 assert!(!route.is_local);
418 assert_eq!(
419 route.next_hop(Ipv4Addr::new(8, 8, 8, 8)),
420 Ipv4Addr::new(192, 168, 1, 1)
421 );
422 }
423
424 #[test]
425 fn test_get_ipv4_interfaces() {
426 let interfaces = get_ipv4_interfaces();
427 for iface in &interfaces {
428 assert!(!iface.name.is_empty());
429 assert!(!iface.addresses.is_empty());
430 }
431 }
432
433 #[test]
434 fn test_interface_addr() {
435 let addr = Ipv4InterfaceAddr {
436 address: Ipv4Addr::new(192, 168, 1, 100),
437 prefix_len: 24,
438 broadcast: Some(Ipv4Addr::new(192, 168, 1, 255)),
439 };
440
441 assert_eq!(addr.network(), Ipv4Addr::new(192, 168, 1, 0));
442 assert_eq!(addr.netmask(), Ipv4Addr::new(255, 255, 255, 0));
443 }
444}