1use std::convert::TryInto as _;
8use std::fmt::Display;
9
10use fidl_fuchsia_net_common as fidl;
11
12use net_types::{Witness as _, ethernet, ip};
13use paste::paste;
14
15pub trait NetTypesIpAddressExt: ip::IpAddress {
17 type Fidl: IntoExt<fidl::IpAddress> + FromExt<Self>;
19}
20
21impl NetTypesIpAddressExt for ip::Ipv4Addr {
22 type Fidl = fidl::Ipv4Address;
23}
24
25impl NetTypesIpAddressExt for ip::Ipv6Addr {
26 type Fidl = fidl::Ipv6Address;
27}
28
29impl FromExt<ip::Ipv4Addr> for fidl::Ipv4Address {
30 fn from_ext(f: ip::Ipv4Addr) -> fidl::Ipv4Address {
31 fidl::Ipv4Address { addr: f.ipv4_bytes() }
32 }
33}
34
35impl FromExt<fidl::Ipv4Address> for ip::Ipv4Addr {
36 fn from_ext(f: fidl::Ipv4Address) -> ip::Ipv4Addr {
37 let fidl::Ipv4Address { addr } = f;
38 ip::Ipv4Addr::new(addr)
39 }
40}
41
42impl FromExt<ip::Ipv6Addr> for fidl::Ipv6Address {
43 fn from_ext(f: ip::Ipv6Addr) -> fidl::Ipv6Address {
44 fidl::Ipv6Address { addr: f.ipv6_bytes() }
45 }
46}
47
48impl FromExt<fidl::Ipv6Address> for ip::Ipv6Addr {
49 fn from_ext(f: fidl::Ipv6Address) -> ip::Ipv6Addr {
50 let fidl::Ipv6Address { addr } = f;
51 ip::Ipv6Addr::from_bytes(addr)
52 }
53}
54
55impl FromExt<ip::IpAddr> for fidl::IpAddress {
56 fn from_ext(f: ip::IpAddr) -> fidl::IpAddress {
57 match f {
58 ip::IpAddr::V4(v4) => {
59 <ip::Ipv4Addr as IntoExt<fidl::Ipv4Address>>::into_ext(v4).into_ext()
60 }
61 ip::IpAddr::V6(v6) => {
62 <ip::Ipv6Addr as IntoExt<fidl::Ipv6Address>>::into_ext(v6).into_ext()
63 }
64 }
65 }
66}
67
68impl FromExt<fidl::IpAddress> for ip::IpAddr {
69 fn from_ext(f: fidl::IpAddress) -> Self {
70 match f {
71 fidl::IpAddress::Ipv4(v4) => ip::IpAddr::V4(v4.into_ext()),
72 fidl::IpAddress::Ipv6(v6) => ip::IpAddr::V6(v6.into_ext()),
73 }
74 }
75}
76
77impl TryFromExt<fidl::Ipv4AddressWithPrefix> for ip::Subnet<ip::Ipv4Addr> {
78 type Error = ip::SubnetError;
79 fn try_from_ext(
80 fidl::Ipv4AddressWithPrefix { addr, prefix_len }: fidl::Ipv4AddressWithPrefix,
81 ) -> Result<ip::Subnet<ip::Ipv4Addr>, Self::Error> {
82 ip::Subnet::new(addr.into_ext(), prefix_len)
83 }
84}
85
86impl TryFromExt<fidl::Ipv6AddressWithPrefix> for ip::Subnet<ip::Ipv6Addr> {
87 type Error = ip::SubnetError;
88 fn try_from_ext(
89 fidl::Ipv6AddressWithPrefix { addr, prefix_len }: fidl::Ipv6AddressWithPrefix,
90 ) -> Result<ip::Subnet<ip::Ipv6Addr>, Self::Error> {
91 ip::Subnet::new(addr.into_ext(), prefix_len)
92 }
93}
94
95impl<A: ip::IpAddress> FromExt<ip::Subnet<A>> for fidl::Subnet {
96 fn from_ext(subnet: ip::Subnet<A>) -> fidl::Subnet {
97 let addr: ip::IpAddr = subnet.network().into();
98 fidl::Subnet { addr: addr.into_ext(), prefix_len: subnet.prefix() }
99 }
100}
101
102impl<A: ip::IpAddress> FromExt<ip::AddrSubnet<A>> for fidl::Subnet {
103 fn from_ext(subnet: ip::AddrSubnet<A>) -> fidl::Subnet {
104 let addr: ip::IpAddr = subnet.addr().get().into();
105 fidl::Subnet { addr: addr.into_ext(), prefix_len: subnet.subnet().prefix() }
106 }
107}
108
109impl FromExt<ip::AddrSubnetEither> for fidl::Subnet {
110 fn from_ext(addr_subnet: ip::AddrSubnetEither) -> fidl::Subnet {
111 match addr_subnet {
112 ip::AddrSubnetEither::V4(addr_subnet) => addr_subnet.into_ext(),
113 ip::AddrSubnetEither::V6(addr_subnet) => addr_subnet.into_ext(),
114 }
115 }
116}
117
118impl FromExt<ip::IpVersion> for fidl::IpVersion {
119 fn from_ext(version: ip::IpVersion) -> fidl::IpVersion {
120 match version {
121 ip::IpVersion::V4 => fidl::IpVersion::V4,
122 ip::IpVersion::V6 => fidl::IpVersion::V6,
123 }
124 }
125}
126
127impl FromExt<fidl::IpVersion> for ip::IpVersion {
128 fn from_ext(version: fidl::IpVersion) -> ip::IpVersion {
129 match version {
130 fidl::IpVersion::V4 => ip::IpVersion::V4,
131 fidl::IpVersion::V6 => ip::IpVersion::V6,
132 }
133 }
134}
135
136pub trait DisplayExt {
138 type Displayable: Display;
139
140 fn display_ext(&self) -> Self::Displayable;
142}
143
144pub trait IpExt {
146 fn is_unicast_link_local(&self) -> bool;
148}
149
150impl IpExt for fidl::Ipv6Address {
151 fn is_unicast_link_local(&self) -> bool {
152 ip::Ipv6Addr::from_bytes(self.addr).is_unicast_link_local()
153 }
154}
155
156pub trait FromExt<T> {
158 fn from_ext(f: T) -> Self;
160}
161
162pub trait IntoExt<T> {
166 fn into_ext(self) -> T;
168}
169
170impl<T, U> IntoExt<U> for T
171where
172 U: FromExt<T>,
173{
174 fn into_ext(self) -> U {
175 U::from_ext(self)
176 }
177}
178
179pub trait TryFromExt<T>: Sized {
181 type Error;
182 fn try_from_ext(f: T) -> Result<Self, Self::Error>;
184}
185
186pub trait TryIntoExt<T>: Sized {
190 type Error;
191 fn try_into_ext(self) -> Result<T, Self::Error>;
193}
194
195impl<T, U> TryIntoExt<U> for T
196where
197 U: TryFromExt<T>,
198{
199 type Error = U::Error;
200 fn try_into_ext(self) -> Result<U, Self::Error> {
201 U::try_from_ext(self)
202 }
203}
204
205impl FromExt<fidl::Ipv4Address> for fidl::IpAddress {
206 fn from_ext(f: fidl::Ipv4Address) -> fidl::IpAddress {
207 fidl::IpAddress::Ipv4(f)
208 }
209}
210
211impl FromExt<fidl::Ipv6Address> for fidl::IpAddress {
212 fn from_ext(f: fidl::Ipv6Address) -> fidl::IpAddress {
213 fidl::IpAddress::Ipv6(f)
214 }
215}
216
217impl FromExt<fidl::Ipv4AddressWithPrefix> for fidl::Subnet {
218 fn from_ext(
219 fidl::Ipv4AddressWithPrefix { addr, prefix_len }: fidl::Ipv4AddressWithPrefix,
220 ) -> fidl::Subnet {
221 fidl::Subnet { addr: addr.into_ext(), prefix_len }
222 }
223}
224
225impl FromExt<fidl::Ipv6AddressWithPrefix> for fidl::Subnet {
226 fn from_ext(
227 fidl::Ipv6AddressWithPrefix { addr, prefix_len }: fidl::Ipv6AddressWithPrefix,
228 ) -> fidl::Subnet {
229 fidl::Subnet { addr: addr.into_ext(), prefix_len }
230 }
231}
232
233impl FromExt<fidl::Ipv4SocketAddress> for fidl::SocketAddress {
234 fn from_ext(f: fidl::Ipv4SocketAddress) -> fidl::SocketAddress {
235 fidl::SocketAddress::Ipv4(f)
236 }
237}
238
239impl FromExt<fidl::Ipv6SocketAddress> for fidl::SocketAddress {
240 fn from_ext(f: fidl::Ipv6SocketAddress) -> fidl::SocketAddress {
241 fidl::SocketAddress::Ipv6(f)
242 }
243}
244
245impl FromExt<fidl::MacAddress> for ethernet::Mac {
246 fn from_ext(fidl::MacAddress { octets }: fidl::MacAddress) -> Self {
247 ethernet::Mac::new(octets)
248 }
249}
250
251impl FromExt<ethernet::Mac> for fidl::MacAddress {
252 fn from_ext(mac: ethernet::Mac) -> fidl::MacAddress {
253 fidl::MacAddress { octets: mac.bytes() }
254 }
255}
256
257#[derive(PartialEq, Eq, Debug, Clone, Copy)]
258pub struct IpAddress(pub std::net::IpAddr);
259
260impl std::fmt::Display for IpAddress {
261 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
262 let IpAddress(ip_address) = self;
263 write!(f, "{}", ip_address)
264 }
265}
266
267impl From<fidl::IpAddress> for IpAddress {
268 fn from(addr: fidl::IpAddress) -> IpAddress {
269 IpAddress(match addr {
270 fidl::IpAddress::Ipv4(fidl::Ipv4Address { addr }) => addr.into(),
271 fidl::IpAddress::Ipv6(fidl::Ipv6Address { addr }) => addr.into(),
272 })
273 }
274}
275
276impl From<IpAddress> for fidl::IpAddress {
277 fn from(IpAddress(ip_address): IpAddress) -> Self {
278 match ip_address {
279 std::net::IpAddr::V4(v4addr) => {
280 fidl::IpAddress::Ipv4(fidl::Ipv4Address { addr: v4addr.octets() })
281 }
282 std::net::IpAddr::V6(v6addr) => {
283 fidl::IpAddress::Ipv6(fidl::Ipv6Address { addr: v6addr.octets() })
284 }
285 }
286 }
287}
288
289impl std::str::FromStr for IpAddress {
290 type Err = anyhow::Error;
291 fn from_str(s: &str) -> Result<Self, Self::Err> {
292 Ok(IpAddress(s.parse()?))
293 }
294}
295
296macro_rules! generate_address_type {
297 ( $ip:ident ) => {
298 paste! {
299 #[derive(PartialEq, Eq, Debug, Clone, Copy)]
300 pub struct [<Ip $ip Address>](pub std::net::[<Ip $ip Addr>]);
301
302 impl std::fmt::Display for [<Ip $ip Address>] {
303 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
304 let Self(addr) = self;
305 write!(f, "{}", addr)
306 }
307 }
308
309 impl From<fidl::[<Ip $ip Address>]> for [<Ip $ip Address>] {
310 fn from(fidl::[<Ip $ip Address>] { addr }: fidl::[<Ip $ip Address>]) -> Self {
311 Self(addr.into())
312 }
313 }
314
315 impl From<[<Ip $ip Address>]> for fidl::[<Ip $ip Address>] {
316 fn from([<Ip $ip Address>](addr): [<Ip $ip Address>]) -> Self {
317 Self { addr: addr.octets() }
318 }
319 }
320
321 impl std::str::FromStr for [<Ip $ip Address>] {
322 type Err = std::net::AddrParseError;
323 fn from_str(s: &str) -> Result<Self, Self::Err> {
324 Ok(Self(s.parse()?))
325 }
326 }
327 }
328 };
329}
330generate_address_type!(v4);
331generate_address_type!(v6);
332
333#[derive(PartialEq, Eq, Debug, Clone, Copy)]
334pub struct Subnet {
335 pub addr: IpAddress,
336 pub prefix_len: u8,
337}
338
339impl std::fmt::Display for Subnet {
340 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
341 let Self { addr, prefix_len } = self;
342 write!(f, "{}/{}", addr, prefix_len)
343 }
344}
345
346impl std::str::FromStr for Subnet {
347 type Err = anyhow::Error;
348
349 fn from_str(s: &str) -> Result<Self, Self::Err> {
354 let mut pieces = s.split('/');
355 let addr = pieces
356 .next()
357 .expect("String#split should never return an empty iterator")
358 .parse::<std::net::IpAddr>()?;
359
360 let addr_len = match addr {
361 std::net::IpAddr::V4(_) => 32,
362 std::net::IpAddr::V6(_) => 128,
363 };
364 let validated_prefix = match pieces.next() {
365 Some(p) => {
366 let parsed_len = p.parse::<u8>()?;
367 if parsed_len > addr_len {
368 Err(anyhow::format_err!(
369 "prefix length provided ({} bits) too large. address {} is only {} bits long",
370 parsed_len,
371 addr,
372 addr_len
373 ))
374 } else {
375 Ok(parsed_len)
376 }
377 }
378 None => Ok(addr_len),
379 };
380
381 match pieces.next() {
382 Some(_) => Err(anyhow::format_err!(
383 "more than one '/' separator found while attempting to parse CIDR string {}",
384 s
385 )),
386 None => Ok(()),
387 }?;
388 let addr = IpAddress(addr);
389 Ok(Subnet { addr, prefix_len: validated_prefix? })
390 }
391}
392
393impl From<fidl::Subnet> for Subnet {
394 fn from(subnet: fidl::Subnet) -> Self {
395 let fidl::Subnet { addr, prefix_len } = subnet;
396 let addr = addr.into();
397 Self { addr, prefix_len }
398 }
399}
400
401impl From<Subnet> for fidl::Subnet {
402 fn from(subnet: Subnet) -> fidl::Subnet {
403 let Subnet { addr, prefix_len } = subnet;
404 let addr = addr.into();
405 fidl::Subnet { addr, prefix_len }
406 }
407}
408
409pub fn apply_subnet_mask(subnet: fidl::Subnet) -> fidl::Subnet {
412 let fidl::Subnet { addr, prefix_len } = subnet;
413 use net_types::ip::IpAddress as _;
414 let addr = match addr {
415 fidl::IpAddress::Ipv4(fidl::Ipv4Address { addr }) => {
416 let addr = net_types::ip::Ipv4Addr::from(addr).mask(prefix_len).ipv4_bytes();
417 fidl::IpAddress::Ipv4(fidl::Ipv4Address { addr })
418 }
419 fidl::IpAddress::Ipv6(fidl::Ipv6Address { addr }) => {
420 let addr = net_types::ip::Ipv6Addr::from(addr).mask(prefix_len).ipv6_bytes();
421 fidl::IpAddress::Ipv6(fidl::Ipv6Address { addr })
422 }
423 };
424 fidl::Subnet { addr, prefix_len }
425}
426
427macro_rules! generate_subnet_type {
428 ( $ip:ident, $prefix_len:literal ) => {
429 paste! {
430 #[derive(PartialEq, Eq, Debug, Clone, Copy)]
431 pub struct [<Subnet $ip:upper>] {
432 pub addr: [<Ip $ip Address>],
433 pub prefix_len: u8,
434 }
435
436 impl std::fmt::Display for [<Subnet $ip:upper>] {
437 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
438 let Self { addr, prefix_len } = self;
439 write!(f, "{}/{}", addr, prefix_len)
440 }
441 }
442
443 impl std::str::FromStr for [<Subnet $ip:upper>] {
444 type Err = anyhow::Error;
445
446 fn from_str(s: &str) -> Result<Self, Self::Err> {
451 let mut pieces = s.split('/');
452 let addr = pieces
453 .next()
454 .expect("String#split should never return an empty iterator")
455 .parse::<std::net::[<Ip $ip Addr>]>()?;
456
457 let addr_len = $prefix_len;
458 let validated_prefix = match pieces.next() {
459 Some(p) => {
460 let parsed_len = p.parse::<u8>()?;
461 if parsed_len > addr_len {
462 Err(anyhow::format_err!(
463 "prefix length provided ({} bits) too large. address {} is only {} bits long",
464 parsed_len,
465 addr,
466 addr_len
467 ))
468 } else {
469 Ok(parsed_len)
470 }
471 }
472 None => Ok(addr_len),
473 };
474
475 match pieces.next() {
476 Some(_) => Err(anyhow::format_err!(
477 "more than one '/' separator found while attempting to parse CIDR string {}",
478 s
479 )),
480 None => Ok(()),
481 }?;
482 let addr = [<Ip $ip Address>](addr);
483 Ok([<Subnet $ip:upper>] { addr, prefix_len: validated_prefix? })
484 }
485 }
486
487 impl From<fidl::[<Ip $ip AddressWithPrefix>]> for [<Subnet $ip:upper>] {
488 fn from(
489 fidl::[<Ip $ip AddressWithPrefix>] { addr, prefix_len }:
490 fidl::[<Ip $ip AddressWithPrefix>]
491 ) -> Self {
492 Self { addr: addr.into(), prefix_len }
493 }
494 }
495
496 impl From<[<Subnet $ip:upper>]> for fidl::[<Ip $ip AddressWithPrefix>] {
497 fn from([<Subnet $ip:upper>] { addr, prefix_len }: [<Subnet $ip:upper>]) -> Self {
498 Self { addr: addr.into(), prefix_len }
499 }
500 }
501 }
502 };
503}
504generate_subnet_type!(v4, 32);
505generate_subnet_type!(v6, 128);
506
507#[derive(PartialEq, Eq, Clone, Copy, Hash)]
508pub struct MacAddress {
509 pub octets: [u8; 6],
510}
511
512impl From<fidl::MacAddress> for MacAddress {
513 fn from(fidl::MacAddress { octets }: fidl::MacAddress) -> Self {
514 Self { octets }
515 }
516}
517
518impl From<MacAddress> for fidl::MacAddress {
519 fn from(MacAddress { octets }: MacAddress) -> fidl::MacAddress {
520 fidl::MacAddress { octets }
521 }
522}
523
524impl MacAddress {
525 fn fmt_octets(octets: [u8; 6], f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
526 for (i, byte) in octets.iter().enumerate() {
527 if i > 0 {
528 write!(f, ":")?;
529 }
530 write!(f, "{:02x}", byte)?;
531 }
532 Ok(())
533 }
534}
535
536impl redactor::Redactable for MacAddress {
537 fn fmt_unredacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
538 Self::fmt_octets(self.octets, f)
539 }
540
541 fn fmt_redacted(
542 &self,
543 redactor: &dyn redactor::Redactor,
544 f: &mut std::fmt::Formatter<'_>,
545 ) -> std::fmt::Result {
546 Self::fmt_octets(redactor.redact_mac(self.octets), f)?;
547 f.write_str(redactor::REDACTED_MARKER)
548 }
549}
550
551redactor::impl_display_via_redactable!(MacAddress);
555redactor::impl_debug_via_redactable!(MacAddress);
556
557impl serde::Serialize for MacAddress {
558 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
559 serializer.collect_str(&redactor::Unredacted(self))
562 }
563}
564
565impl<'de> serde::Deserialize<'de> for MacAddress {
566 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
567 let s = <String as serde::Deserialize>::deserialize(deserializer)?;
568 <Self as std::str::FromStr>::from_str(&s).map_err(serde::de::Error::custom)
569 }
570}
571
572impl std::str::FromStr for MacAddress {
573 type Err = anyhow::Error;
574
575 fn from_str(s: &str) -> Result<Self, Self::Err> {
576 use anyhow::Context;
577
578 let mut octets = [0; 6];
579 let mut iter = s.split(':');
580 for (i, octet) in octets.iter_mut().enumerate() {
581 let next_octet = iter.next().ok_or_else(|| {
582 anyhow::format_err!("MAC address [{}] only specifies {} out of 6 octets", s, i)
583 })?;
584 *octet = u8::from_str_radix(next_octet, 16)
585 .with_context(|| format!("could not parse hex integer from {}", next_octet))?;
586 }
587 if iter.next().is_some() {
588 return Err(anyhow::format_err!("MAC address has more than six octets: {}", s));
589 }
590 Ok(MacAddress { octets })
591 }
592}
593
594#[derive(PartialEq, Eq, Debug, Clone, Copy)]
595pub struct SocketAddress(pub std::net::SocketAddr);
596
597impl std::fmt::Display for SocketAddress {
598 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
599 let Self(socket_addr) = self;
600 std::fmt::Display::fmt(socket_addr, f)
601 }
602}
603
604impl DisplayExt for fidl::SocketAddress {
605 type Displayable = SocketAddress;
606 fn display_ext(&self) -> SocketAddress {
607 self.clone().into()
608 }
609}
610
611impl<T: IntoExt<fidl::SocketAddress> + Clone> DisplayExt for T {
612 type Displayable = SocketAddress;
613 fn display_ext(&self) -> SocketAddress {
614 IntoExt::into_ext(self.clone()).into()
615 }
616}
617
618impl From<fidl::SocketAddress> for SocketAddress {
619 fn from(f: fidl::SocketAddress) -> Self {
620 Self(match f {
621 fidl::SocketAddress::Ipv4(fidl::Ipv4SocketAddress {
622 address: fidl::Ipv4Address { addr },
623 port,
624 }) => std::net::SocketAddr::V4(std::net::SocketAddrV4::new(addr.into(), port)),
625 fidl::SocketAddress::Ipv6(fidl::Ipv6SocketAddress {
626 address: fidl::Ipv6Address { addr },
627 port,
628 zone_index,
629 }) => std::net::SocketAddr::V6(std::net::SocketAddrV6::new(
630 addr.into(),
631 port,
632 0,
633 zone_index.try_into().unwrap_or(0),
634 )),
635 })
636 }
637}
638
639impl From<SocketAddress> for fidl::SocketAddress {
640 fn from(SocketAddress(addr): SocketAddress) -> Self {
641 match addr {
642 std::net::SocketAddr::V4(socket_addr) => {
643 fidl::SocketAddress::Ipv4(fidl::Ipv4SocketAddress {
644 address: fidl::Ipv4Address { addr: socket_addr.ip().octets() },
645 port: socket_addr.port(),
646 })
647 }
648 std::net::SocketAddr::V6(socket_addr) => {
649 fidl::SocketAddress::Ipv6(fidl::Ipv6SocketAddress {
650 address: fidl::Ipv6Address { addr: socket_addr.ip().octets() },
651 port: socket_addr.port(),
652 zone_index: socket_addr.scope_id().into(),
653 })
654 }
655 }
656 }
657}
658
659#[derive(Debug, Default, Clone, PartialEq, Eq)]
661pub struct Marks {
662 pub mark_1: Option<u32>,
664 pub mark_2: Option<u32>,
666}
667
668pub const MAX_MARK_DOMAIN_COUNTS: usize = 2;
670
671impl Marks {
672 pub fn get(&self, domain: fidl::MarkDomain) -> Option<u32> {
673 match domain {
674 fidl::MarkDomain::Mark1 => self.mark_1,
675 fidl::MarkDomain::Mark2 => self.mark_2,
676 }
677 }
678}
679
680impl IntoIterator for Marks {
681 type Item = (fidl::MarkDomain, fidl::Mark);
682
683 type IntoIter = std::iter::Flatten<
684 std::array::IntoIter<Option<(fidl::MarkDomain, fidl::Mark)>, MAX_MARK_DOMAIN_COUNTS>,
685 >;
686
687 fn into_iter(self) -> Self::IntoIter {
688 let Self { mark_1, mark_2 } = self;
689 [
690 mark_1.map(|mark| (fidl::MarkDomain::Mark1, mark)),
691 mark_2.map(|mark| (fidl::MarkDomain::Mark2, mark)),
692 ]
693 .into_iter()
694 .flatten()
695 }
696}
697
698impl From<fidl::Marks> for Marks {
699 fn from(value: fidl::Marks) -> Self {
700 let fidl::Marks { mark_1, mark_2, __source_breaking } = value;
701 return Self { mark_1, mark_2 };
702 }
703}
704
705impl From<Marks> for fidl::Marks {
706 fn from(value: Marks) -> Self {
707 let Marks { mark_1, mark_2 } = value;
708 Self { mark_1, mark_2, __source_breaking: Default::default() }
709 }
710}
711
712#[cfg(test)]
713mod tests {
714 use super::*;
715
716 use assert_matches::assert_matches;
717 use net_declare::{
718 fidl_ip_v4_with_prefix, fidl_ip_v6_with_prefix, fidl_subnet, net_addr_subnet,
719 net_addr_subnet_v4, net_addr_subnet_v6, net_subnet_v4, net_subnet_v6, std_ip, std_ip_v4,
720 std_ip_v6,
721 };
722 use test_case::test_case;
723
724 use std::collections::HashMap;
725 use std::str::FromStr;
726
727 #[test]
728 fn test_from_into_ext() {
729 let a = fidl::Ipv4Address { addr: [0; 4] };
730 assert_eq!(fidl::IpAddress::Ipv4(a), a.into_ext());
731
732 let a = fidl::Ipv4Address { addr: [0; 4] };
733 assert_eq!(net_types::ip::Ipv4Addr::new([0; 4]), a.into_ext());
734
735 let a = fidl::Ipv6Address { addr: [0; 16] };
736 assert_eq!(fidl::IpAddress::Ipv6(a), a.into_ext());
737
738 let a = fidl::Ipv6Address { addr: [0; 16] };
739 assert_eq!(net_types::ip::Ipv6Addr::from_bytes([0; 16]), a.into_ext());
740
741 let a = fidl::Ipv4SocketAddress { address: fidl::Ipv4Address { addr: [0; 4] }, port: 1 };
742 assert_eq!(fidl::SocketAddress::Ipv4(a), a.into_ext());
743
744 let a = fidl::Ipv6SocketAddress {
745 address: fidl::Ipv6Address { addr: [0; 16] },
746 port: 1,
747 zone_index: 2,
748 };
749 assert_eq!(fidl::SocketAddress::Ipv6(a), a.into_ext());
750 }
751
752 #[test]
753 fn test_ipaddr() {
754 let want_ext = IpAddress(std::net::IpAddr::V4(std::net::Ipv4Addr::new(1, 2, 3, 4)));
755 let want_fidl = fidl::IpAddress::Ipv4(fidl::Ipv4Address { addr: [1, 2, 3, 4] });
756 let got_fidl: fidl::IpAddress = want_ext.into();
757 let got_ext = IpAddress::from(got_fidl);
758
759 assert_eq!(want_ext, got_ext);
760 assert_eq!(want_fidl, got_fidl);
761 }
762
763 #[test]
764 fn test_net_types_subnet_into_fidl_subnet() {
765 assert_eq!(fidl_subnet!("192.168.0.0/24"), net_subnet_v4!("192.168.0.0/24").into_ext());
766 assert_eq!(fidl_subnet!("fd::/64"), net_subnet_v6!("fd::/64").into_ext());
767 }
768
769 macro_rules! subnet_from_str_invalid {
772 ($typ:ty) => {
773 paste! {
774 #[test_case("")]
775 #[test_case("/32")] #[test_case(" /32"; "space_slash_32")] #[test_case("192.0.2.0/8/8")] #[test_case("192.0.2.0/33")] #[test_case("192.0.2.0:8080")] #[test_case("2001:db8::e1bf:4fe9:fb62:e3f4/129")] #[test_case("2001:db8::e1bf:4fe9:fb62:e3f4/32%eth0")] fn [<$typ:snake _from_str_invalid>](s: &str) {
783 let _: anyhow::Error = $typ::from_str(s).expect_err(&format!(
784 "a malformed str is wrongfully convertitable to Subnet struct: \"{}\"",
785 s
786 ));
787 }
788 }
789 };
790 }
791
792 subnet_from_str_invalid!(Subnet);
793 subnet_from_str_invalid!(SubnetV4);
794 subnet_from_str_invalid!(SubnetV6);
795
796 #[test_case(
797 "192.0.2.0/24",
798 Subnet { addr: IpAddress(std_ip!("192.0.2.0")), prefix_len: 24 },
799 fidl_subnet!("192.0.2.0/24")
800 )]
801 #[test_case(
802 "2001:db8::/32",
803 Subnet { addr: IpAddress(std_ip!("2001:db8::")), prefix_len: 32 },
804 fidl_subnet!("2001:db8::/32")
805 )]
806 fn subnet_conversions(want_str: &str, want_ext: Subnet, want_fidl: fidl::Subnet) {
807 let got_ext = Subnet::from_str(want_str).ok().expect("conversion error");
808 let got_fidl: fidl::Subnet = got_ext.into();
809 let got_ext_back = Subnet::from(got_fidl);
810 let got_str = &format!("{}", got_ext_back);
811
812 assert_eq!(want_ext, got_ext);
813 assert_eq!(want_fidl, got_fidl);
814 assert_eq!(got_ext, got_ext_back);
815 assert_eq!(want_str, got_str);
816 }
817
818 #[test]
819 fn subnet_v4_from_str() {
820 assert_eq!(
821 SubnetV4::from_str("192.0.2.0/24")
822 .expect("should be able to parse 192.0.2.0/24 into SubnetV4"),
823 SubnetV4 { addr: Ipv4Address(std_ip_v4!("192.0.2.0")), prefix_len: 24 }
824 );
825 }
826
827 #[test]
828 fn subnet_v4_from_v6_str() {
829 let _: anyhow::Error = SubnetV4::from_str("2001:db8::/24")
830 .expect_err("IPv6 subnet should not be parsed as SubnetV4 successfully");
831 }
832
833 #[test]
834 fn subnet_v6_from_str() {
835 assert_eq!(
836 SubnetV6::from_str("2001:db8::/32")
837 .expect("should be able to parse 2001:db8::/32 into SubnetV6"),
838 SubnetV6 { addr: Ipv6Address(std_ip_v6!("2001:db8::")), prefix_len: 32 }
839 );
840 }
841
842 #[test]
843 fn subnet_v6_from_v4_str() {
844 let _: anyhow::Error = SubnetV6::from_str("192.0.2.0/24")
845 .expect_err("IPv4 subnet should not be parsed as SubnetV6 successfully");
846 }
847
848 #[test]
849 fn test_subnet_try_from_ipaddress_with_prefix() {
850 assert_eq!(
852 Ok(net_subnet_v4!("192.168.0.0/24")),
853 fidl_ip_v4_with_prefix!("192.168.0.0/24").try_into_ext()
854 );
855 assert_eq!(
856 Ok(net_subnet_v6!("fe80::/64")),
857 fidl_ip_v6_with_prefix!("fe80::/64").try_into_ext()
858 );
859
860 assert_matches!(
862 ip::Subnet::<ip::Ipv4Addr>::try_from_ext(fidl_ip_v4_with_prefix!("192.168.0.1/24")),
863 Err(ip::SubnetError::HostBitsSet)
864 );
865 assert_matches!(
866 ip::Subnet::<ip::Ipv6Addr>::try_from_ext(fidl_ip_v6_with_prefix!("fe80::1/64")),
867 Err(ip::SubnetError::HostBitsSet)
868 );
869 }
870
871 #[test]
872 fn test_addr_subnet_fidl_subnet() {
873 assert_eq!(
874 fidl::Subnet::from_ext(net_addr_subnet_v4!("192.168.0.8/24")),
875 fidl_subnet!("192.168.0.8/24")
876 );
877
878 assert_eq!(
879 fidl::Subnet::from_ext(net_addr_subnet_v6!("fe80::1234/54")),
880 fidl_subnet!("fe80::1234/54")
881 );
882 }
883
884 #[test]
885 fn test_addr_subnet_either_fidl_subnet() {
886 assert_eq!(
887 fidl::Subnet::from_ext(net_addr_subnet!("192.168.0.8/24")),
888 fidl_subnet!("192.168.0.8/24")
889 );
890 assert_eq!(
891 fidl::Subnet::from_ext(net_addr_subnet!("fe80::1234/54")),
892 fidl_subnet!("fe80::1234/54")
893 );
894 }
895
896 #[test]
897 fn mac_addr_from_str_with_valid_str_returns_mac_addr() {
898 let result = MacAddress::from_str("AA:BB:CC:DD:EE:FF").unwrap();
899 let expected = MacAddress { octets: [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF] };
900
901 assert_eq!(expected, result);
902 }
903
904 #[test]
905 fn mac_addr_from_str_with_invalid_digit_returns_err() {
906 let result = MacAddress::from_str("11:22:33:44:55:GG");
907
908 assert!(result.is_err());
909 }
910
911 #[test]
912 fn mac_addr_from_str_with_invalid_format_returns_err() {
913 let result = MacAddress::from_str("11-22-33-44-55-66");
914
915 assert!(result.is_err());
916 }
917
918 #[test]
919 fn mac_addr_from_str_with_empty_string_returns_err() {
920 let result = MacAddress::from_str("");
921
922 assert!(result.is_err());
923 }
924
925 #[test]
926 fn mac_addr_from_str_with_extra_quotes_returns_err() {
927 let result = MacAddress::from_str("\"11:22:33:44:55:66\"");
928
929 assert!(result.is_err());
930 }
931
932 #[test]
933 fn valid_mac_addr_array_deserializes_to_vec_of_mac_addrs() {
934 let result: Vec<MacAddress> =
935 serde_json::from_str("[\"11:11:11:11:11:11\", \"AA:AA:AA:AA:AA:AA\"]").unwrap();
936 let expected = vec![
937 MacAddress { octets: [0x11, 0x11, 0x11, 0x11, 0x11, 0x11] },
938 MacAddress { octets: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] },
939 ];
940
941 assert_eq!(expected, result);
942 }
943
944 #[test]
945 fn mac_addr_to_mac_addr_map_deserializes_to_hashmap() {
946 let result: HashMap<MacAddress, MacAddress> =
947 serde_json::from_str("{\"11:22:33:44:55:66\": \"AA:BB:CC:DD:EE:FF\"}").unwrap();
948 let expected: HashMap<_, _> = std::iter::once((
949 MacAddress { octets: [0x11, 0x22, 0x33, 0x44, 0x55, 0x66] },
950 MacAddress { octets: [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF] },
951 ))
952 .collect();
953
954 assert_eq!(expected, result);
955 }
956
957 #[test]
958 fn mac_addr_to_mac_addr_map_serializes_to_valid_json() {
959 let mac_addr_map: HashMap<_, _> = std::iter::once((
960 MacAddress { octets: [0x11, 0x22, 0x33, 0x44, 0x55, 0x66] },
961 MacAddress { octets: [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF] },
962 ))
963 .collect();
964
965 let result = serde_json::to_string(&mac_addr_map).unwrap();
966
967 assert_eq!("{\"11:22:33:44:55:66\":\"aa:bb:cc:dd:ee:ff\"}", result);
968 }
969
970 #[test]
971 fn test_socket_addr() {
972 let want_ext = SocketAddress(std::net::SocketAddr::V4(std::net::SocketAddrV4::new(
974 std::net::Ipv4Addr::new(1, 2, 3, 4),
975 5,
976 )));
977 let want_fidl = fidl::SocketAddress::Ipv4(fidl::Ipv4SocketAddress {
978 address: fidl::Ipv4Address { addr: [1, 2, 3, 4] },
979 port: 5,
980 });
981 let got_fidl: fidl::SocketAddress = want_ext.into();
982 let got_ext = SocketAddress::from(want_fidl);
983
984 assert_eq!(want_ext, got_ext);
985 assert_eq!(want_fidl, got_fidl);
986
987 let want_ext = SocketAddress(std::net::SocketAddr::V6(std::net::SocketAddrV6::new(
989 std::net::Ipv6Addr::new(0x0102, 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F10),
990 17,
991 0,
992 18,
993 )));
994 let want_fidl = fidl::SocketAddress::Ipv6(fidl::Ipv6SocketAddress {
995 address: fidl::Ipv6Address {
996 addr: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
997 },
998 port: 17,
999 zone_index: 18,
1000 });
1001 let got_fidl: fidl::SocketAddress = want_ext.into();
1002 let got_ext = SocketAddress::from(got_fidl);
1003
1004 assert_eq!(want_ext, got_ext);
1005 assert_eq!(want_fidl, want_fidl);
1006 }
1007
1008 #[test]
1009 fn test_display_ext() {
1010 let ipv4_sock_addr =
1011 fidl::Ipv4SocketAddress { address: fidl::Ipv4Address { addr: [1, 2, 3, 4] }, port: 5 };
1012 assert_eq!(
1013 SocketAddress(std::net::SocketAddr::V4(std::net::SocketAddrV4::new(
1014 std::net::Ipv4Addr::new(1, 2, 3, 4),
1015 5,
1016 ))),
1017 fidl::SocketAddress::Ipv4(ipv4_sock_addr).display_ext()
1018 );
1019 assert_eq!(
1020 SocketAddress(std::net::SocketAddr::V4(std::net::SocketAddrV4::new(
1021 std::net::Ipv4Addr::new(1, 2, 3, 4),
1022 5,
1023 ))),
1024 ipv4_sock_addr.display_ext()
1025 );
1026 assert_eq!(
1027 SocketAddress(std::net::SocketAddr::V6(std::net::SocketAddrV6::new(
1028 std::net::Ipv6Addr::new(
1029 0x0102, 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F10
1030 ),
1031 17,
1032 0,
1033 18,
1034 ))),
1035 fidl::Ipv6SocketAddress {
1036 address: fidl::Ipv6Address {
1037 addr: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
1038 },
1039 port: 17,
1040 zone_index: 18,
1041 }
1042 .display_ext()
1043 );
1044 }
1045}