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