1mod tools;
2
3use crate::*;
4use serde::*;
5
6cfg_if::cfg_if! {
7 if #[cfg(any(target_os = "linux", target_os = "android"))] {
8 mod netlink;
9 use self::netlink::PlatformSupportNetlink as PlatformSupport;
10 } else if #[cfg(target_os = "windows")] {
11 mod windows;
12 mod sockaddr_tools;
13 use self::windows::PlatformSupportWindows as PlatformSupport;
14 } else if #[cfg(any(target_os = "macos", target_os = "ios"))] {
15 mod apple;
16 mod sockaddr_tools;
17 use self::apple::PlatformSupportApple as PlatformSupport;
18 } else if #[cfg(target_os = "openbsd")] {
19 mod openbsd;
20 mod sockaddr_tools;
21 use self::openbsd::PlatformSupportOpenBSD as PlatformSupport;
22 } else if #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] {
23 mod wasm;
24 use self::wasm::PlatformSupportWasm as PlatformSupport;
25 } else {
26 compile_error!("No network interfaces support for this platform!");
27 }
28}
29
30#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Serialize, Deserialize)]
32pub enum IfAddr {
33 V4(Ifv4Addr),
35 V6(Ifv6Addr),
37}
38
39impl IfAddr {
40 #[must_use]
42 pub fn ip(&self) -> IpAddr {
43 match *self {
44 IfAddr::V4(ref ifv4_addr) => IpAddr::V4(ifv4_addr.ip),
45 IfAddr::V6(ref ifv6_addr) => IpAddr::V6(ifv6_addr.ip),
46 }
47 }
48 #[must_use]
50 pub fn netmask(&self) -> IpAddr {
51 match *self {
52 IfAddr::V4(ref ifv4_addr) => IpAddr::V4(ifv4_addr.netmask),
53 IfAddr::V6(ref ifv6_addr) => IpAddr::V6(ifv6_addr.netmask),
54 }
55 }
56 pub fn broadcast(&self) -> Option<IpAddr> {
58 match *self {
59 IfAddr::V4(ref ifv4_addr) => ifv4_addr.broadcast.map(IpAddr::V4),
60 IfAddr::V6(ref ifv6_addr) => ifv6_addr.broadcast.map(IpAddr::V6),
61 }
62 }
63
64 #[must_use]
66 pub fn network(&self) -> IfAddr {
67 match *self {
68 IfAddr::V4(ref ifv4_addr) => IfAddr::V4(ifv4_addr.network()),
69 IfAddr::V6(ref ifv6_addr) => IfAddr::V6(ifv6_addr.network()),
70 }
71 }
72
73 #[must_use]
75 pub fn contains_address(&self, addr: IpAddr) -> bool {
76 match *self {
77 IfAddr::V4(ref ifv4_addr) => match addr {
78 IpAddr::V4(ipv4_addr) => ifv4_addr.contains_address(ipv4_addr),
79 IpAddr::V6(_consensus_count) => false,
80 },
81 IfAddr::V6(ref ifv6_addr) => match addr {
82 IpAddr::V4(_) => false,
83 IpAddr::V6(ipv6_addr) => ifv6_addr.contains_address(ipv6_addr),
84 },
85 }
86 }
87}
88
89impl fmt::Display for IfAddr {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 match *self {
92 IfAddr::V4(ref ifv4_addr) => write!(f, "{}", f.to_string(ifv4_addr)),
93 IfAddr::V6(ref ifv6_addr) => write!(f, "{}", f.to_string(ifv6_addr)),
94 }
95 }
96}
97
98#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Serialize, Deserialize)]
100pub struct Ifv4Addr {
101 pub ip: Ipv4Addr,
103 pub netmask: Ipv4Addr,
105 pub broadcast: Option<Ipv4Addr>,
107}
108
109impl fmt::Display for Ifv4Addr {
110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 write!(
112 f,
113 "{}/{}",
114 self.ip,
115 if let Some(prefix_len) = self.prefix_len() {
116 format!("{}", prefix_len)
117 } else {
118 format!("(invalid netmask={})", self.netmask)
119 },
120 )
121 }
122}
123
124fn ipv4_netmask_to_prefix_len(netmask: Ipv4Addr) -> Option<u8> {
125 let netmask_u32 = netmask.to_bits();
126 let prefix_len = netmask_u32.leading_ones() as u8;
127 let suffix_len = netmask_u32.trailing_zeros() as u8;
128
129 if suffix_len != 32 - prefix_len {
130 None
131 } else {
132 Some(prefix_len)
133 }
134}
135
136impl Ifv4Addr {
137 #[must_use]
139 pub fn network(&self) -> Ifv4Addr {
140 let v4 = self.ip.octets();
141 let v4mask = self.netmask.octets();
142 let ip = Ipv4Addr::new(
143 v4[0] & v4mask[0],
144 v4[1] & v4mask[1],
145 v4[2] & v4mask[2],
146 v4[3] & v4mask[3],
147 );
148 Ifv4Addr {
149 ip,
150 netmask: self.netmask,
151 broadcast: self.broadcast,
152 }
153 }
154
155 #[must_use]
157 pub fn contains_address(&self, addr: Ipv4Addr) -> bool {
158 let v4mask = self.netmask.octets();
159
160 let self_v4 = self.ip.octets();
161 let self_ip = Ipv4Addr::new(
162 self_v4[0] & v4mask[0],
163 self_v4[1] & v4mask[1],
164 self_v4[2] & v4mask[2],
165 self_v4[3] & v4mask[3],
166 );
167
168 let addr_v4 = addr.octets();
169 let addr_ip = Ipv4Addr::new(
170 addr_v4[0] & v4mask[0],
171 addr_v4[1] & v4mask[1],
172 addr_v4[2] & v4mask[2],
173 addr_v4[3] & v4mask[3],
174 );
175
176 self_ip == addr_ip
177 }
178
179 #[must_use]
181 pub fn prefix_len(&self) -> Option<u8> {
182 ipv4_netmask_to_prefix_len(self.netmask)
183 }
184}
185
186#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Serialize, Deserialize)]
188pub struct Ifv6Addr {
189 pub ip: Ipv6Addr,
191 pub netmask: Ipv6Addr,
193 pub broadcast: Option<Ipv6Addr>,
195}
196
197impl fmt::Display for Ifv6Addr {
198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 write!(
200 f,
201 "{}/{}",
202 self.ip,
203 if let Some(prefix_len) = self.prefix_len() {
204 format!("{}", prefix_len)
205 } else {
206 format!("(invalid netmask={})", self.netmask)
207 },
208 )
209 }
210}
211
212impl Ifv6Addr {
213 #[must_use]
215 pub fn network(&self) -> Ifv6Addr {
216 let v6 = self.ip.segments();
217 let v6mask = self.netmask.segments();
218 let ip = Ipv6Addr::new(
219 v6[0] & v6mask[0],
220 v6[1] & v6mask[1],
221 v6[2] & v6mask[2],
222 v6[3] & v6mask[3],
223 v6[4] & v6mask[4],
224 v6[5] & v6mask[5],
225 v6[6] & v6mask[6],
226 v6[7] & v6mask[7],
227 );
228 Ifv6Addr {
229 ip,
230 netmask: self.netmask,
231 broadcast: self.broadcast,
232 }
233 }
234
235 #[must_use]
237 pub fn contains_address(&self, addr: Ipv6Addr) -> bool {
238 let v6mask = self.netmask.segments();
239
240 let self_v6 = self.ip.segments();
241 let self_ip = Ipv6Addr::new(
242 self_v6[0] & v6mask[0],
243 self_v6[1] & v6mask[1],
244 self_v6[2] & v6mask[2],
245 self_v6[3] & v6mask[3],
246 self_v6[4] & v6mask[4],
247 self_v6[5] & v6mask[5],
248 self_v6[6] & v6mask[6],
249 self_v6[7] & v6mask[7],
250 );
251
252 let addr_v6 = addr.segments();
253 let addr_ip = Ipv6Addr::new(
254 addr_v6[0] & v6mask[0],
255 addr_v6[1] & v6mask[1],
256 addr_v6[2] & v6mask[2],
257 addr_v6[3] & v6mask[3],
258 addr_v6[4] & v6mask[4],
259 addr_v6[5] & v6mask[5],
260 addr_v6[6] & v6mask[6],
261 addr_v6[7] & v6mask[7],
262 );
263
264 self_ip == addr_ip
265 }
266
267 #[must_use]
269 pub fn prefix_len(&self) -> Option<u8> {
270 ipv6_netmask_to_prefix_len(self.netmask)
271 }
272}
273
274fn ipv6_netmask_to_prefix_len(netmask: Ipv6Addr) -> Option<u8> {
275 let netmask_u128 = netmask.to_bits();
276 let prefix_len = netmask_u128.leading_ones() as u8;
277 let suffix_len = netmask_u128.trailing_zeros() as u8;
278
279 if suffix_len != 128 - prefix_len {
280 None
281 } else {
282 Some(prefix_len)
283 }
284}
285
286#[derive(
288 Debug, Default, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Copy, Serialize, Deserialize,
289)]
290pub struct InterfaceFlags {
291 pub is_loopback: bool,
293 pub is_running: bool,
295 pub is_point_to_point: bool,
297 pub is_clat: bool,
299}
300
301#[derive(
303 Debug, Default, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Copy, Serialize, Deserialize,
304)]
305pub struct AddressFlags {
306 pub is_dynamic: bool,
308 pub is_temporary: bool,
310 pub is_preferred: bool,
312 pub is_clat: bool,
314 pub expiration_secs: Option<u64>,
316}
317
318#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
320pub struct InterfaceAddress {
321 pub if_addr: IfAddr,
323 pub flags: AddressFlags,
325}
326
327use core::cmp::Ordering;
328
329impl Ord for InterfaceAddress {
331 fn cmp(&self, other: &Self) -> Ordering {
332 match (&self.if_addr, &other.if_addr) {
333 (IfAddr::V4(a), IfAddr::V4(b)) => {
334 let ret = ipv4addr_is_global(&a.ip).cmp(&ipv4addr_is_global(&b.ip));
336 if ret != Ordering::Equal {
337 return ret;
338 }
339 let ret = ipv4addr_is_private(&a.ip).cmp(&ipv4addr_is_private(&b.ip));
341 if ret != Ordering::Equal {
342 return ret;
343 }
344 let ret = (!self.flags.is_dynamic).cmp(&!other.flags.is_dynamic);
346 if ret != Ordering::Equal {
347 return ret;
348 }
349 }
350 (IfAddr::V6(a), IfAddr::V6(b)) => {
351 let ret = self.flags.is_preferred.cmp(&other.flags.is_preferred);
353 if ret != Ordering::Equal {
354 return ret;
355 }
356 let ret = (!self.flags.is_temporary).cmp(&!other.flags.is_temporary);
358 if ret != Ordering::Equal {
359 return ret;
360 }
361 let ret = ipv6addr_is_global(&a.ip).cmp(&ipv6addr_is_global(&b.ip));
363 if ret != Ordering::Equal {
364 return ret;
365 }
366 let ret = ipv6addr_is_unique_local(&a.ip).cmp(&ipv6addr_is_unique_local(&b.ip));
368 if ret != Ordering::Equal {
369 return ret;
370 }
371 let ret = ipv6addr_is_unicast_site_local(&a.ip)
373 .cmp(&ipv6addr_is_unicast_site_local(&b.ip));
374 if ret != Ordering::Equal {
375 return ret;
376 }
377 let ret = ipv6addr_is_unicast_link_local(&a.ip)
379 .cmp(&ipv6addr_is_unicast_link_local(&b.ip));
380 if ret != Ordering::Equal {
381 return ret;
382 }
383 let ret = (!self.flags.is_dynamic).cmp(&!other.flags.is_dynamic);
385 if ret != Ordering::Equal {
386 return ret;
387 }
388 }
389 (IfAddr::V4(a), IfAddr::V6(b)) => {
390 if other.flags.is_preferred && !other.flags.is_temporary {
392 let ret = ipv4addr_is_global(&a.ip).cmp(&ipv6addr_is_global(&b.ip));
393 if ret != Ordering::Equal {
394 return ret;
395 }
396 }
397
398 return Ordering::Greater;
400 }
401 (IfAddr::V6(a), IfAddr::V4(b)) => {
402 if self.flags.is_preferred && !self.flags.is_temporary {
404 let ret = ipv6addr_is_global(&a.ip).cmp(&ipv4addr_is_global(&b.ip));
405 if ret != Ordering::Equal {
406 return ret;
407 }
408 }
409
410 return Ordering::Less;
412 }
413 }
414 let ret = self.if_addr.cmp(&other.if_addr);
416 if ret != Ordering::Equal {
417 return ret;
418 }
419 self.flags.cmp(&other.flags)
420 }
421}
422impl PartialOrd for InterfaceAddress {
423 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
424 Some(self.cmp(other))
425 }
426}
427
428impl InterfaceAddress {
429 #[must_use]
431 pub fn new(if_addr: IfAddr, flags: AddressFlags) -> Self {
432 Self { if_addr, flags }
433 }
434
435 #[must_use]
437 pub fn if_addr(&self) -> &IfAddr {
438 &self.if_addr
439 }
440
441 #[must_use]
443 pub fn is_temporary(&self) -> bool {
444 self.flags.is_temporary
445 }
446
447 #[must_use]
449 pub fn is_dynamic(&self) -> bool {
450 self.flags.is_dynamic
451 }
452
453 #[must_use]
455 pub fn is_preferred(&self) -> bool {
456 self.flags.is_preferred
457 }
458
459 #[must_use]
461 pub fn is_clat(&self) -> bool {
462 self.flags.is_clat
463 }
464
465 #[must_use]
468 pub fn is_cgnat_or_ds_lite(&self) -> bool {
469 match &self.if_addr {
470 IfAddr::V4(v4) => {
471 ipv4addr_is_shared(&v4.ip) || ipv4addr_is_ietf_protocol_assignment(&v4.ip)
472 }
473 IfAddr::V6(_) => false,
474 }
475 }
476
477 #[must_use]
481 pub fn is_ipv4_link_local(&self) -> bool {
482 match &self.if_addr {
483 IfAddr::V4(v4) => ipv4addr_is_link_local(&v4.ip),
484 IfAddr::V6(_) => false,
485 }
486 }
487}
488
489#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
499pub struct NetworkInterface {
500 pub name: String,
502 pub flags: InterfaceFlags,
504 pub gateways: Vec<IpAddr>,
506 pub addrs: Vec<InterfaceAddress>,
508}
509
510impl fmt::Debug for NetworkInterface {
511 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
512 let alt = f.alternate();
513 let mut ds = f.debug_struct("NetworkInterface");
514 ds.field("name", &self.name)
515 .field("flags", &self.flags)
516 .field("gateways", &self.gateways)
517 .field("addrs", &self.addrs);
518 if alt {
519 ds.field("// primary_ipv4", &self.primary_ipv4());
520 ds.field("// primary_ipv6", &self.primary_ipv6());
521 }
522 ds.finish()
523 }
524}
525impl NetworkInterface {
526 #[must_use]
528 pub fn new(name: String, flags: InterfaceFlags) -> Self {
529 Self {
530 name,
531 flags,
532 gateways: Vec::new(),
533 addrs: Vec::new(),
534 }
535 }
536
537 #[must_use]
539 pub fn name(&self) -> String {
540 self.name.clone()
541 }
542
543 #[must_use]
545 pub fn is_loopback(&self) -> bool {
546 self.flags.is_loopback
547 }
548
549 #[must_use]
551 pub fn is_point_to_point(&self) -> bool {
552 self.flags.is_point_to_point
553 }
554
555 #[must_use]
557 pub fn is_running(&self) -> bool {
558 self.flags.is_running
559 }
560
561 #[must_use]
563 pub fn is_clat(&self) -> bool {
564 self.flags.is_clat
565 }
566
567 pub fn add_address(&mut self, addr: InterfaceAddress) {
569 self.addrs.push(addr);
570 self.addrs.sort();
571 self.addrs.dedup();
572 }
573
574 #[must_use]
576 pub fn addresses(&self) -> &[InterfaceAddress] {
577 &self.addrs
578 }
579
580 pub fn add_gateway(&mut self, gateway: IpAddr) {
582 self.gateways.push(gateway);
583 self.gateways.sort();
584 self.gateways.dedup();
585 }
586
587 #[must_use]
589 pub fn gateways(&self) -> &[IpAddr] {
590 &self.gateways
591 }
592
593 #[must_use]
595 pub fn primary_ipv4(&self) -> Option<InterfaceAddress> {
596 let mut ipv4addrs: Vec<&InterfaceAddress> = self
597 .addrs
598 .iter()
599 .filter(|a| matches!(a.if_addr(), IfAddr::V4(_)))
600 .collect();
601 ipv4addrs.sort();
602 ipv4addrs.last().cloned().cloned()
603 }
604
605 #[must_use]
607 pub fn primary_ipv6(&self) -> Option<InterfaceAddress> {
608 let mut ipv6addrs: Vec<&InterfaceAddress> = self
609 .addrs
610 .iter()
611 .filter(|a| matches!(a.if_addr(), IfAddr::V6(_)))
612 .collect();
613 ipv6addrs.sort();
614 ipv6addrs.last().cloned().cloned()
615 }
616}
617
618#[derive(Clone, Default, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
620pub struct NetworkInterfaceAddressState {
621 pub gateway_addresses: Vec<IpAddr>,
623 pub interface_addresses: Vec<IfAddr>,
625}
626
627#[derive(Clone, Copy, Default, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
629pub struct RawAddressSummary {
630 pub has_non_loopback_ipv4: bool,
632 pub has_non_loopback_ipv6: bool,
634 pub has_unicast_global_ipv6: bool,
636}
637
638pub struct NetworkInterfacesInner {
640 valid: bool,
641 interfaces: BTreeMap<String, NetworkInterface>,
642 interface_address_state_cache: Arc<NetworkInterfaceAddressState>,
643}
644
645#[derive(Clone)]
647pub struct NetworkInterfaces {
648 inner: Arc<Mutex<NetworkInterfacesInner>>,
649}
650
651impl fmt::Debug for NetworkInterfaces {
652 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
653 let inner = self.inner.lock();
654 f.debug_struct("NetworkInterfaces")
655 .field("valid", &inner.valid)
656 .field("interfaces", &inner.interfaces)
657 .finish()?;
658 if f.alternate() {
659 writeln!(f)?;
660 writeln!(
661 f,
662 "// interface_address_state_cache: {:?}",
663 inner.interface_address_state_cache
664 )?;
665 }
666 Ok(())
667 }
668}
669
670impl Default for NetworkInterfaces {
671 fn default() -> Self {
672 Self::new()
673 }
674}
675
676impl NetworkInterfaces {
677 #[must_use]
679 pub fn new() -> Self {
680 Self {
681 inner: Arc::new(Mutex::new(NetworkInterfacesInner {
682 valid: false,
683 interfaces: BTreeMap::new(),
684 interface_address_state_cache: Arc::new(NetworkInterfaceAddressState::default()),
685 })),
686 }
687 }
688
689 #[must_use]
691 pub fn is_valid(&self) -> bool {
692 let inner = self.inner.lock();
693 inner.valid
694 }
695 pub fn clear(&self) {
697 let mut inner = self.inner.lock();
698
699 inner.interfaces.clear();
700 inner.interface_address_state_cache = Arc::new(NetworkInterfaceAddressState::default());
701 inner.valid = false;
702 }
703 pub async fn refresh(&self) -> std::io::Result<bool> {
709 let mut last_interfaces = {
710 let mut last_interfaces = BTreeMap::<String, NetworkInterface>::new();
711 let mut platform_support = PlatformSupport::new();
712 platform_support
713 .get_interfaces(&mut last_interfaces)
714 .await?;
715 last_interfaces
716 };
717
718 #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
724 Self::filter_non_primary_global_addresses(&mut last_interfaces);
725
726 let mut inner = self.inner.lock();
727 core::mem::swap(&mut inner.interfaces, &mut last_interfaces);
728 inner.valid = true;
729
730 if last_interfaces != inner.interfaces {
731 let old_interface_address_state = inner.interface_address_state_cache.clone();
733
734 Self::cache_interface_address_state(&mut inner);
736
737 if old_interface_address_state != inner.interface_address_state_cache {
739 return Ok(true);
740 }
741 }
742 Ok(false)
743 }
744 pub fn with_interfaces<F, R>(&self, f: F) -> R
746 where
747 F: FnOnce(&BTreeMap<String, NetworkInterface>) -> R,
748 {
749 let inner = self.inner.lock();
750 f(&inner.interfaces)
751 }
752
753 #[must_use]
755 pub fn interface_address_state(&self) -> Arc<NetworkInterfaceAddressState> {
756 let inner = self.inner.lock();
757 inner.interface_address_state_cache.clone()
758 }
759
760 #[must_use]
763 pub fn raw_address_summary(&self) -> RawAddressSummary {
764 let inner = self.inner.lock();
765 let mut summary = RawAddressSummary::default();
766 for intf in inner.interfaces.values() {
767 if !intf.is_running() || intf.is_loopback() {
768 continue;
769 }
770 for addr in intf.addresses() {
771 match addr.if_addr() {
772 IfAddr::V4(v4) => {
773 if !v4.ip.is_loopback() && !v4.ip.is_unspecified() {
774 summary.has_non_loopback_ipv4 = true;
775 }
776 }
777 IfAddr::V6(v6) => {
778 if !v6.ip.is_loopback() && !v6.ip.is_unspecified() {
779 summary.has_non_loopback_ipv6 = true;
780 if ipv6addr_is_unicast_global(&v6.ip) {
781 summary.has_unicast_global_ipv6 = true;
782 }
783 }
784 }
785 }
786 }
787 }
788 summary
789 }
790
791 #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
800 fn filter_non_primary_global_addresses(interfaces: &mut BTreeMap<String, NetworkInterface>) {
801 let primary_v4 = primary_source_ipv4();
802 let primary_v6 = primary_source_ipv6();
803
804 interfaces.retain(|_, intf| {
805 intf.addrs.retain(|addr| match addr.if_addr() {
806 IfAddr::V4(v4) => {
807 !ipv4addr_is_global(&v4.ip) || primary_v4.is_some_and(|p| p == v4.ip)
808 }
809 IfAddr::V6(v6) => {
810 !ipv6addr_is_unicast_global(&v6.ip) || primary_v6.is_some_and(|p| p == v6.ip)
811 }
812 });
813 !intf.addrs.is_empty()
814 });
815 }
816
817 fn cache_interface_address_state(inner: &mut NetworkInterfacesInner) {
818 let mut intf_addrs = Vec::new();
820 let mut gateway_addresses = Vec::new();
821 for intf in inner.interfaces.values() {
822 if !intf.is_running() || intf.is_loopback() || intf.is_clat() {
824 continue;
825 }
826
827 for addr in intf.addresses() {
828 if addr.is_temporary() {
830 continue;
831 }
832 if addr.is_clat() {
834 continue;
835 }
836 if addr.is_cgnat_or_ds_lite() {
838 continue;
839 }
840 if addr.is_ipv4_link_local() {
843 continue;
844 }
845 intf_addrs.push(addr.clone());
846 }
847
848 for gateway in intf.gateways() {
849 gateway_addresses.push(*gateway);
850 }
851 }
852
853 let mut interface_addresses = intf_addrs
855 .iter()
856 .map(|x| x.if_addr().clone())
857 .collect::<Vec<_>>();
858
859 interface_addresses.sort();
860 interface_addresses.dedup();
861
862 gateway_addresses.sort();
863 gateway_addresses.dedup();
864
865 inner.interface_address_state_cache = Arc::new(NetworkInterfaceAddressState {
867 gateway_addresses,
868 interface_addresses,
869 });
870 }
871}