Skip to main content

fidl_fuchsia_net_matchers_ext_fdomain/
lib.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Extensions for the fuchsia.net.matchers FIDL library.
6//!
7//! Note that this library as written is not meant for inclusion in the SDK. It
8//! is only meant to be used in conjunction with a netstack that is compiled
9//! against the same API level of the `fuchsia.net.matchers` FIDL library. This
10//! library opts in to compile-time and runtime breakage when the FIDL library
11//! is evolved in order to enforce that it is updated along with the FIDL
12//! library itself.
13
14use std::fmt::Debug;
15use std::num::NonZeroU64;
16use std::ops::RangeInclusive;
17
18use fidl::marker::SourceBreaking;
19use fidl_fuchsia_net_common as fnet;
20use fidl_fuchsia_net_ext::{FromExt, IntoExt};
21use fidl_fuchsia_net_interfaces_common as fnet_interfaces;
22#[cfg(not(feature = "fdomain"))]
23use fidl_fuchsia_net_interfaces_ext as fnet_interfaces_ext;
24#[cfg(feature = "fdomain")]
25use fidl_fuchsia_net_interfaces_ext_fdomain as fnet_interfaces_ext;
26use fidl_fuchsia_net_matchers_common as fnet_matchers;
27use net_types::ip::Ip;
28use thiserror::Error;
29
30/// Extension type for [`fnet_matchers::Interface`].
31#[derive(Debug, Clone, PartialEq, Eq, Hash)]
32pub enum Interface {
33    Id(NonZeroU64),
34    Name(fnet_interfaces::Name),
35    PortClass(fnet_interfaces_ext::PortClass),
36}
37
38/// Errors when creating an [`Interface`].
39#[derive(Debug, Error, PartialEq, Eq)]
40pub enum InterfaceError {
41    #[error("interface matcher specified an invalid ID of 0")]
42    ZeroId,
43    #[error(transparent)]
44    UnknownPortClass(fnet_interfaces_ext::UnknownPortClassError),
45    #[error("interface union is of an unknown variant")]
46    UnknownUnionVariant,
47}
48
49impl From<Interface> for fnet_matchers::Interface {
50    fn from(matcher: Interface) -> Self {
51        match matcher {
52            Interface::Id(id) => Self::Id(id.get()),
53            Interface::Name(name) => Self::Name(name),
54            Interface::PortClass(port_class) => Self::PortClass(port_class.into()),
55        }
56    }
57}
58
59impl TryFrom<fnet_matchers::Interface> for Interface {
60    type Error = InterfaceError;
61
62    fn try_from(matcher: fnet_matchers::Interface) -> Result<Self, Self::Error> {
63        match matcher {
64            fnet_matchers::Interface::Id(id) => {
65                let id = NonZeroU64::new(id).ok_or(InterfaceError::ZeroId)?;
66                Ok(Self::Id(id))
67            }
68            fnet_matchers::Interface::Name(name) => Ok(Self::Name(name)),
69            fnet_matchers::Interface::PortClass(port_class) => {
70                port_class.try_into().map(Self::PortClass).map_err(InterfaceError::UnknownPortClass)
71            }
72            fnet_matchers::Interface::__SourceBreaking { .. } => {
73                Err(InterfaceError::UnknownUnionVariant)
74            }
75        }
76    }
77}
78
79/// Extension type for [`fnet_matchers::BoundInterface`].
80#[derive(Debug, Clone, PartialEq, Eq, Hash)]
81pub enum BoundInterface {
82    Unbound,
83    Bound(Interface),
84}
85
86/// Errors when creating an [`BoundInterface`].
87#[derive(Debug, Error, PartialEq)]
88pub enum BoundInterfaceError {
89    #[error(transparent)]
90    Interface(InterfaceError),
91    #[error("interface union is of an unknown variant")]
92    UnknownUnionVariant(u64),
93}
94
95impl From<BoundInterface> for fnet_matchers::BoundInterface {
96    fn from(matcher: BoundInterface) -> Self {
97        match matcher {
98            BoundInterface::Unbound => fnet_matchers::BoundInterface::Unbound(fnet_matchers::Empty),
99            BoundInterface::Bound(interface) => {
100                fnet_matchers::BoundInterface::Bound(interface.into())
101            }
102        }
103    }
104}
105
106impl TryFrom<fnet_matchers::BoundInterface> for BoundInterface {
107    type Error = BoundInterfaceError;
108
109    fn try_from(matcher: fnet_matchers::BoundInterface) -> Result<Self, Self::Error> {
110        match matcher {
111            fnet_matchers::BoundInterface::Unbound(fnet_matchers::Empty) => {
112                Ok(BoundInterface::Unbound)
113            }
114            fnet_matchers::BoundInterface::Bound(interface) => Ok(BoundInterface::Bound(
115                interface.try_into().map_err(|e| BoundInterfaceError::Interface(e))?,
116            )),
117            fnet_matchers::BoundInterface::__SourceBreaking { unknown_ordinal } => {
118                Err(BoundInterfaceError::UnknownUnionVariant(unknown_ordinal))
119            }
120        }
121    }
122}
123
124/// Extension type for the `Subnet` variant of [`fnet_matchers::Address`].
125///
126/// This type witnesses to the invariant that the prefix length of the subnet is
127/// no greater than the number of bits in the IP address, and that no host bits
128/// in the network address are set.
129#[derive(Clone, Copy, Eq, Hash, PartialEq)]
130pub struct Subnet(net_types::ip::SubnetEither);
131
132/// Errors when creating a [`Subnet`].
133#[derive(Debug, Error, PartialEq)]
134pub enum SubnetError {
135    #[error("prefix length of subnet is longer than number of bits in IP address")]
136    PrefixTooLong,
137    #[error("host bits are set in subnet network")]
138    HostBitsSet,
139}
140
141impl From<Subnet> for net_types::ip::SubnetEither {
142    fn from(subnet: Subnet) -> Self {
143        let Subnet(subnet) = subnet;
144        subnet
145    }
146}
147
148impl From<net_types::ip::SubnetEither> for Subnet {
149    fn from(subnet: net_types::ip::SubnetEither) -> Self {
150        Self(subnet)
151    }
152}
153
154impl From<Subnet> for fnet::Subnet {
155    fn from(subnet: Subnet) -> Self {
156        let Subnet(subnet) = subnet;
157        let (addr, prefix_len) = subnet.net_prefix();
158
159        Self { addr: fnet::IpAddress::from_ext(addr), prefix_len }
160    }
161}
162
163impl TryFrom<fnet::Subnet> for Subnet {
164    type Error = SubnetError;
165
166    fn try_from(subnet: fnet::Subnet) -> Result<Self, Self::Error> {
167        let fnet::Subnet { addr, prefix_len } = subnet;
168
169        match net_types::ip::SubnetEither::new(addr.into_ext(), prefix_len) {
170            Ok(inner) => Ok(Self(inner)),
171            Err(err) => Err(match err {
172                net_types::ip::SubnetError::PrefixTooLong => SubnetError::PrefixTooLong,
173                net_types::ip::SubnetError::HostBitsSet => SubnetError::HostBitsSet,
174            }),
175        }
176    }
177}
178
179impl Debug for Subnet {
180    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181        let Self(subnet) = self;
182        match subnet {
183            net_types::ip::SubnetEither::V4(subnet) => subnet.fmt(f),
184            net_types::ip::SubnetEither::V6(subnet) => subnet.fmt(f),
185        }
186    }
187}
188
189/// Extension type for [`fnet_matchers::AddressRange`].
190///
191/// This type witnesses that `start <= end`. (Comparisons are performed on the
192/// numerical big-endian representation of the IP address.)
193#[derive(Debug, Clone, PartialEq, Eq)]
194pub enum AddressRange {
195    V4(RangeInclusive<fnet::Ipv4Address>),
196    V6(RangeInclusive<fnet::Ipv6Address>),
197}
198
199/// Errors when creating an [`AddressRange`].
200#[derive(Debug, Error, PartialEq)]
201pub enum AddressRangeError {
202    #[error("invalid address range (start must be <= end)")]
203    Invalid,
204    #[error("address range start and end addresses are not the same IP family")]
205    FamilyMismatch,
206}
207
208impl From<AddressRange> for fnet_matchers::AddressRange {
209    fn from(range: AddressRange) -> Self {
210        let (start, end) = match range {
211            AddressRange::V4(range) => ((*range.start()).into_ext(), (*range.end()).into_ext()),
212            AddressRange::V6(range) => ((*range.start()).into_ext(), (*range.end()).into_ext()),
213        };
214
215        Self { start, end }
216    }
217}
218
219impl TryFrom<fnet_matchers::AddressRange> for AddressRange {
220    type Error = AddressRangeError;
221
222    fn try_from(range: fnet_matchers::AddressRange) -> Result<Self, Self::Error> {
223        let fnet_matchers::AddressRange { start, end } = range;
224        match (start, end) {
225            (fnet::IpAddress::Ipv4(start), fnet::IpAddress::Ipv4(end)) => {
226                if u32::from_be_bytes(start.addr) > u32::from_be_bytes(end.addr) {
227                    Err(AddressRangeError::Invalid)
228                } else {
229                    Ok(Self::V4(start..=end))
230                }
231            }
232            (fnet::IpAddress::Ipv6(start), fnet::IpAddress::Ipv6(end)) => {
233                if u128::from_be_bytes(start.addr) > u128::from_be_bytes(end.addr) {
234                    Err(AddressRangeError::Invalid)
235                } else {
236                    Ok(Self::V6(start..=end))
237                }
238            }
239            _ => Err(AddressRangeError::FamilyMismatch),
240        }
241    }
242}
243
244impl AddressRange {
245    /// Create a new [`AddressRange`] for a single address.
246    pub fn new_single<I: Ip>(ip: I::Addr) -> Self {
247        I::map_ip_in(
248            ip,
249            |ip| {
250                let ip = ip.into_ext();
251                Self::V4(ip..=ip)
252            },
253            |ip| {
254                let ip = ip.into_ext();
255                Self::V6(ip..=ip)
256            },
257        )
258    }
259}
260
261/// Extension type for [`fnet_matchers::Address`].
262#[derive(Clone, PartialEq, Eq)]
263pub enum AddressMatcherType {
264    Subnet(Subnet),
265    Range(AddressRange),
266}
267
268/// Errors when creating an [`AddressMatcherType`].
269#[derive(Debug, Error, PartialEq)]
270pub enum AddressMatcherTypeError {
271    #[error("AddressMatcher is of an unknown variant")]
272    UnknownUnionVariant,
273    #[error("subnet conversion error: {0}")]
274    Subnet(SubnetError),
275    #[error("address range conversion error: {0}")]
276    AddressRange(AddressRangeError),
277}
278
279impl From<SubnetError> for AddressMatcherTypeError {
280    fn from(value: SubnetError) -> Self {
281        AddressMatcherTypeError::Subnet(value)
282    }
283}
284impl From<AddressRangeError> for AddressMatcherTypeError {
285    fn from(value: AddressRangeError) -> Self {
286        AddressMatcherTypeError::AddressRange(value)
287    }
288}
289
290impl From<AddressMatcherType> for fnet_matchers::AddressMatcherType {
291    fn from(matcher: AddressMatcherType) -> Self {
292        match matcher {
293            AddressMatcherType::Subnet(subnet) => Self::Subnet(subnet.into()),
294            AddressMatcherType::Range(range) => Self::Range(range.into()),
295        }
296    }
297}
298
299impl TryFrom<fnet_matchers::AddressMatcherType> for AddressMatcherType {
300    type Error = AddressMatcherTypeError;
301
302    fn try_from(matcher: fnet_matchers::AddressMatcherType) -> Result<Self, Self::Error> {
303        match matcher {
304            fnet_matchers::AddressMatcherType::Subnet(subnet) => {
305                Ok(Self::Subnet(subnet.try_into()?))
306            }
307            fnet_matchers::AddressMatcherType::Range(range) => Ok(Self::Range(range.try_into()?)),
308            fnet_matchers::AddressMatcherType::__SourceBreaking { .. } => {
309                Err(AddressMatcherTypeError::UnknownUnionVariant)
310            }
311        }
312    }
313}
314
315impl Debug for AddressMatcherType {
316    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
317        match self {
318            AddressMatcherType::Subnet(subnet) => subnet.fmt(f),
319            AddressMatcherType::Range(address_range) => address_range.fmt(f),
320        }
321    }
322}
323
324/// Extension type for [`fnet_matchers::Address`].
325#[derive(Debug, Clone, PartialEq, Eq)]
326pub struct Address {
327    pub matcher: AddressMatcherType,
328    pub invert: bool,
329}
330
331/// Errors when creating an [`Address`].
332#[derive(Debug, Error, PartialEq)]
333pub enum AddressError {
334    #[error("address matcher conversion failure: {0}")]
335    AddressMatcherType(AddressMatcherTypeError),
336}
337
338impl From<AddressMatcherTypeError> for AddressError {
339    fn from(value: AddressMatcherTypeError) -> Self {
340        Self::AddressMatcherType(value)
341    }
342}
343
344impl From<Address> for fnet_matchers::Address {
345    fn from(matcher: Address) -> Self {
346        let Address { matcher, invert } = matcher;
347        Self { matcher: matcher.into(), invert }
348    }
349}
350
351impl TryFrom<fnet_matchers::Address> for Address {
352    type Error = AddressError;
353
354    fn try_from(matcher: fnet_matchers::Address) -> Result<Self, Self::Error> {
355        let fnet_matchers::Address { matcher, invert } = matcher;
356        Ok(Self { matcher: matcher.try_into()?, invert })
357    }
358}
359
360/// Extension type for [`fnet_matchers::BoundAddress`].
361#[derive(Debug, Clone, PartialEq, Eq)]
362pub enum BoundAddress {
363    Unbound,
364    Bound(Address),
365}
366
367/// Errors when creating an [`BoundAddress`].
368#[derive(Debug, Error, PartialEq)]
369pub enum BoundAddressError {
370    #[error(transparent)]
371    Address(AddressError),
372    #[error("bound address union is of an unknown variant")]
373    UnknownUnionVariant(u64),
374}
375
376impl From<BoundAddress> for fnet_matchers::BoundAddress {
377    fn from(matcher: BoundAddress) -> Self {
378        match matcher {
379            BoundAddress::Unbound => fnet_matchers::BoundAddress::Unbound(fnet_matchers::Empty),
380            BoundAddress::Bound(address) => fnet_matchers::BoundAddress::Bound(address.into()),
381        }
382    }
383}
384
385impl TryFrom<fnet_matchers::BoundAddress> for BoundAddress {
386    type Error = BoundAddressError;
387
388    fn try_from(matcher: fnet_matchers::BoundAddress) -> Result<Self, Self::Error> {
389        match matcher {
390            fnet_matchers::BoundAddress::Unbound(fnet_matchers::Empty) => Ok(BoundAddress::Unbound),
391            fnet_matchers::BoundAddress::Bound(address) => {
392                Ok(BoundAddress::Bound(address.try_into().map_err(BoundAddressError::Address)?))
393            }
394            fnet_matchers::BoundAddress::__SourceBreaking { unknown_ordinal } => {
395                Err(BoundAddressError::UnknownUnionVariant(unknown_ordinal))
396            }
397        }
398    }
399}
400
401/// Extension type for [`fnet_matchers::Port`].
402///
403/// This type witnesses to the invariant that `start <= end`.
404#[derive(Debug, Clone, PartialEq, Eq, Hash)]
405pub struct Port {
406    range: RangeInclusive<u16>,
407    invert: bool,
408}
409
410/// Extension type for [`fnet_matchers::BoundPort`].
411#[derive(Debug, Clone, PartialEq, Eq, Hash)]
412pub enum BoundPort {
413    Unbound,
414    Bound(Port),
415}
416
417/// Errors when creating an [`BoundPort`].
418#[derive(Debug, Error, PartialEq, Eq)]
419pub enum BoundPortError {
420    #[error(transparent)]
421    Port(PortError),
422    #[error("bound port union is of an unknown variant")]
423    UnknownUnionVariant(u64),
424}
425
426impl From<BoundPort> for fnet_matchers::BoundPort {
427    fn from(matcher: BoundPort) -> Self {
428        match matcher {
429            BoundPort::Unbound => fnet_matchers::BoundPort::Unbound(fnet_matchers::Empty),
430            BoundPort::Bound(port) => fnet_matchers::BoundPort::Bound(port.into()),
431        }
432    }
433}
434
435impl TryFrom<fnet_matchers::BoundPort> for BoundPort {
436    type Error = BoundPortError;
437
438    fn try_from(matcher: fnet_matchers::BoundPort) -> Result<Self, Self::Error> {
439        match matcher {
440            fnet_matchers::BoundPort::Unbound(fnet_matchers::Empty) => Ok(BoundPort::Unbound),
441            fnet_matchers::BoundPort::Bound(port) => {
442                Ok(BoundPort::Bound(port.try_into().map_err(BoundPortError::Port)?))
443            }
444            fnet_matchers::BoundPort::__SourceBreaking { unknown_ordinal } => {
445                Err(BoundPortError::UnknownUnionVariant(unknown_ordinal))
446            }
447        }
448    }
449}
450
451/// Errors when creating a `Port`.
452#[derive(Debug, Error, PartialEq, Eq)]
453pub enum PortError {
454    #[error("invalid port range (start must be <= end)")]
455    InvalidPortRange,
456}
457
458impl Port {
459    pub fn new(start: u16, end: u16, invert: bool) -> Result<Self, PortError> {
460        if start > end {
461            return Err(PortError::InvalidPortRange);
462        }
463        Ok(Self { range: start..=end, invert })
464    }
465
466    /// Create a new [`Port`] for a single port.
467    pub fn new_single(port: u16, invert: bool) -> Self {
468        Self::new(port, port, invert).unwrap()
469    }
470
471    pub fn range(&self) -> &RangeInclusive<u16> {
472        &self.range
473    }
474
475    pub fn start(&self) -> u16 {
476        *self.range.start()
477    }
478
479    pub fn end(&self) -> u16 {
480        *self.range.end()
481    }
482
483    pub fn invert(&self) -> bool {
484        self.invert
485    }
486}
487
488impl From<Port> for fnet_matchers::Port {
489    fn from(matcher: Port) -> Self {
490        let Port { range, invert } = matcher;
491        Self { start: *range.start(), end: *range.end(), invert }
492    }
493}
494
495impl TryFrom<fnet_matchers::Port> for Port {
496    type Error = PortError;
497
498    fn try_from(matcher: fnet_matchers::Port) -> Result<Self, Self::Error> {
499        let fnet_matchers::Port { start, end, invert } = matcher;
500        if start > end {
501            return Err(PortError::InvalidPortRange);
502        }
503        Ok(Self { range: start..=end, invert })
504    }
505}
506
507/// Extension type for [`fnet_matchers::PacketTransportProtocol`].
508#[derive(Clone, PartialEq)]
509pub enum TransportProtocol {
510    Tcp { src_port: Option<Port>, dst_port: Option<Port> },
511    Udp { src_port: Option<Port>, dst_port: Option<Port> },
512    Icmp,
513    Icmpv6,
514}
515
516/// Errors when creating a [`TransportProtocol`].
517#[derive(Debug, Error, PartialEq)]
518pub enum TransportProtocolError {
519    #[error("invalid port: {0}")]
520    Port(PortError),
521    #[error("TransportProtocol is of an unknown variant")]
522    UnknownUnionVariant,
523}
524
525impl From<PortError> for TransportProtocolError {
526    fn from(value: PortError) -> Self {
527        TransportProtocolError::Port(value)
528    }
529}
530
531impl From<TransportProtocol> for fnet_matchers::PacketTransportProtocol {
532    fn from(matcher: TransportProtocol) -> Self {
533        match matcher {
534            TransportProtocol::Tcp { src_port, dst_port } => Self::Tcp(fnet_matchers::TcpPacket {
535                src_port: src_port.map(Into::into),
536                dst_port: dst_port.map(Into::into),
537                __source_breaking: SourceBreaking,
538            }),
539            TransportProtocol::Udp { src_port, dst_port } => Self::Udp(fnet_matchers::UdpPacket {
540                src_port: src_port.map(Into::into),
541                dst_port: dst_port.map(Into::into),
542                __source_breaking: SourceBreaking,
543            }),
544            TransportProtocol::Icmp => Self::Icmp(fnet_matchers::IcmpPacket::default()),
545            TransportProtocol::Icmpv6 => Self::Icmpv6(fnet_matchers::Icmpv6Packet::default()),
546        }
547    }
548}
549
550impl TryFrom<fnet_matchers::PacketTransportProtocol> for TransportProtocol {
551    type Error = TransportProtocolError;
552
553    fn try_from(matcher: fnet_matchers::PacketTransportProtocol) -> Result<Self, Self::Error> {
554        match matcher {
555            fnet_matchers::PacketTransportProtocol::Tcp(fnet_matchers::TcpPacket {
556                src_port,
557                dst_port,
558                __source_breaking,
559            }) => Ok(Self::Tcp {
560                src_port: src_port.map(TryInto::try_into).transpose()?,
561                dst_port: dst_port.map(TryInto::try_into).transpose()?,
562            }),
563            fnet_matchers::PacketTransportProtocol::Udp(fnet_matchers::UdpPacket {
564                src_port,
565                dst_port,
566                __source_breaking,
567            }) => Ok(Self::Udp {
568                src_port: src_port.map(TryInto::try_into).transpose()?,
569                dst_port: dst_port.map(TryInto::try_into).transpose()?,
570            }),
571            fnet_matchers::PacketTransportProtocol::Icmp(fnet_matchers::IcmpPacket {
572                __source_breaking,
573            }) => Ok(Self::Icmp),
574            fnet_matchers::PacketTransportProtocol::Icmpv6(fnet_matchers::Icmpv6Packet {
575                __source_breaking,
576            }) => Ok(Self::Icmpv6),
577            fnet_matchers::PacketTransportProtocol::__SourceBreaking { .. } => {
578                Err(TransportProtocolError::UnknownUnionVariant)
579            }
580        }
581    }
582}
583
584impl Debug for TransportProtocol {
585    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
586        // Omit empty fields.
587        match self {
588            TransportProtocol::Tcp { src_port, dst_port } => {
589                let mut debug_struct = f.debug_struct("Tcp");
590
591                // Omit empty fields.
592                if let Some(port) = &src_port {
593                    let _ = debug_struct.field("src_port", port);
594                }
595
596                if let Some(port) = &dst_port {
597                    let _ = debug_struct.field("dst_port", port);
598                }
599
600                debug_struct.finish()
601            }
602            TransportProtocol::Udp { src_port, dst_port } => {
603                let mut debug_struct = f.debug_struct("Udp");
604
605                // Omit empty fields.
606                if let Some(port) = &src_port {
607                    let _ = debug_struct.field("src_port", port);
608                }
609
610                if let Some(port) = &dst_port {
611                    let _ = debug_struct.field("dst_port", port);
612                }
613
614                debug_struct.finish()
615            }
616            TransportProtocol::Icmp => f.write_str("Icmp"),
617            TransportProtocol::Icmpv6 => f.write_str("Icmpv6"),
618        }
619    }
620}
621
622/// An extension type for [`fnet_matchers::Mark`]
623#[derive(Debug, Clone, PartialEq, Eq, Hash)]
624pub enum Mark {
625    Unmarked,
626    Marked { mask: u32, between: RangeInclusive<u32>, invert: bool },
627}
628
629#[derive(Debug, Clone, PartialEq, Error)]
630pub enum MarkError {
631    #[error("mark union is of an unknown variant")]
632    UnknownUnionVariant(u64),
633}
634
635impl TryFrom<fnet_matchers::Mark> for Mark {
636    type Error = MarkError;
637
638    fn try_from(matcher: fnet_matchers::Mark) -> Result<Self, Self::Error> {
639        match matcher {
640            fnet_matchers::Mark::Unmarked(fnet_matchers::Unmarked) => Ok(Mark::Unmarked),
641            fnet_matchers::Mark::Marked(fnet_matchers::Marked {
642                mask,
643                between: fnet_matchers::Between { start, end },
644                invert,
645            }) => Ok(Mark::Marked { mask, between: RangeInclusive::new(start, end), invert }),
646            fnet_matchers::Mark::__SourceBreaking { unknown_ordinal } => {
647                Err(MarkError::UnknownUnionVariant(unknown_ordinal))
648            }
649        }
650    }
651}
652
653impl From<Mark> for fnet_matchers::Mark {
654    fn from(matcher: Mark) -> Self {
655        match matcher {
656            Mark::Unmarked => fnet_matchers::Mark::Unmarked(fnet_matchers::Unmarked),
657            Mark::Marked { mask, between, invert } => {
658                let (start, end) = between.into_inner();
659                fnet_matchers::Mark::Marked(fnet_matchers::Marked {
660                    mask,
661                    between: fnet_matchers::Between { start, end },
662                    invert,
663                })
664            }
665        }
666    }
667}
668
669/// An extension type for [`fnet_matchers::MarkInDomain`].
670#[derive(Debug, Clone, PartialEq, Eq, Hash)]
671pub struct MarkInDomain {
672    pub domain: fnet::MarkDomain,
673    pub mark: Mark,
674}
675
676#[derive(Debug, Clone, PartialEq, Error)]
677pub enum MarkInDomainError {
678    #[error("mark conversion failed: {0}")]
679    Mark(MarkError),
680}
681
682impl TryFrom<fnet_matchers::MarkInDomain> for MarkInDomain {
683    type Error = MarkInDomainError;
684
685    fn try_from(matcher: fnet_matchers::MarkInDomain) -> Result<Self, Self::Error> {
686        let fnet_matchers::MarkInDomain { domain, mark } = matcher;
687        Ok(Self { domain, mark: mark.try_into().map_err(MarkInDomainError::Mark)? })
688    }
689}
690
691impl From<MarkInDomain> for fnet_matchers::MarkInDomain {
692    fn from(matcher: MarkInDomain) -> Self {
693        let MarkInDomain { domain, mark } = matcher;
694        Self { domain, mark: mark.into() }
695    }
696}
697
698/// An extension type for [`fnet_matchers::TcpSocket`]
699#[derive(Debug, Clone, PartialEq, Eq)]
700pub enum TcpSocket {
701    Empty,
702    SrcPort(BoundPort),
703    DstPort(BoundPort),
704    States(fnet_matchers::TcpState),
705}
706
707#[derive(Debug, PartialEq, Eq, Error)]
708pub enum TcpSocketError {
709    #[error("bound port matcher conversion failed: {0}")]
710    BoundPort(BoundPortError),
711    #[error("tcp union is of an unknown variant")]
712    UnknownUnionVariant(u64),
713}
714
715impl TryFrom<fnet_matchers::TcpSocket> for TcpSocket {
716    type Error = TcpSocketError;
717
718    fn try_from(matcher: fnet_matchers::TcpSocket) -> Result<Self, Self::Error> {
719        match matcher {
720            fnet_matchers::TcpSocket::Empty(fnet_matchers::Empty) => Ok(Self::Empty),
721            fnet_matchers::TcpSocket::SrcPort(port) => {
722                Ok(Self::SrcPort(port.try_into().map_err(|e| TcpSocketError::BoundPort(e))?))
723            }
724            fnet_matchers::TcpSocket::DstPort(port) => {
725                Ok(Self::DstPort(port.try_into().map_err(|e| TcpSocketError::BoundPort(e))?))
726            }
727            fnet_matchers::TcpSocket::States(states) => Ok(Self::States(states)),
728            fnet_matchers::TcpSocket::__SourceBreaking { unknown_ordinal } => {
729                Err(TcpSocketError::UnknownUnionVariant(unknown_ordinal))
730            }
731        }
732    }
733}
734
735impl From<TcpSocket> for fnet_matchers::TcpSocket {
736    fn from(matcher: TcpSocket) -> Self {
737        match matcher {
738            TcpSocket::Empty => Self::Empty(fnet_matchers::Empty),
739            TcpSocket::SrcPort(port) => Self::SrcPort(port.into()),
740            TcpSocket::DstPort(port) => Self::DstPort(port.into()),
741            TcpSocket::States(states) => Self::States(states),
742        }
743    }
744}
745
746/// An extension type for [`fnet_matchers::UdpSocket`]
747#[derive(Debug, Clone, PartialEq, Eq)]
748pub enum UdpSocket {
749    Empty,
750    SrcPort(BoundPort),
751    DstPort(BoundPort),
752    States(fnet_matchers::UdpState),
753}
754
755#[derive(Debug, PartialEq, Eq, Error)]
756pub enum UdpSocketError {
757    #[error("bound port matcher conversion failed: {0}")]
758    BoundPort(BoundPortError),
759    #[error("udp union is of an unknown variant")]
760    UnknownUnionVariant(u64),
761}
762
763impl TryFrom<fnet_matchers::UdpSocket> for UdpSocket {
764    type Error = UdpSocketError;
765
766    fn try_from(matcher: fnet_matchers::UdpSocket) -> Result<Self, Self::Error> {
767        match matcher {
768            fnet_matchers::UdpSocket::Empty(fnet_matchers::Empty) => Ok(Self::Empty),
769            fnet_matchers::UdpSocket::SrcPort(port) => {
770                Ok(Self::SrcPort(port.try_into().map_err(|e| UdpSocketError::BoundPort(e))?))
771            }
772            fnet_matchers::UdpSocket::DstPort(port) => {
773                Ok(Self::DstPort(port.try_into().map_err(|e| UdpSocketError::BoundPort(e))?))
774            }
775            fnet_matchers::UdpSocket::States(states) => Ok(Self::States(states)),
776            fnet_matchers::UdpSocket::__SourceBreaking { unknown_ordinal } => {
777                Err(UdpSocketError::UnknownUnionVariant(unknown_ordinal))
778            }
779        }
780    }
781}
782
783impl From<UdpSocket> for fnet_matchers::UdpSocket {
784    fn from(matcher: UdpSocket) -> Self {
785        match matcher {
786            UdpSocket::Empty => Self::Empty(fnet_matchers::Empty),
787            UdpSocket::SrcPort(port) => Self::SrcPort(port.into()),
788            UdpSocket::DstPort(port) => Self::DstPort(port.into()),
789            UdpSocket::States(states) => Self::States(states),
790        }
791    }
792}
793
794/// An extension type for [`fnet_matchers::SocketTransportProtocol`].
795#[derive(Debug, Clone, PartialEq, Eq)]
796pub enum SocketTransportProtocol {
797    Tcp(TcpSocket),
798    Udp(UdpSocket),
799}
800
801#[derive(Debug, PartialEq, Eq, Error)]
802pub enum SocketTransportProtocolError {
803    #[error("invalid tcp matcher: {0}")]
804    Tcp(TcpSocketError),
805    #[error("invalid udp matcher: {0}")]
806    Udp(UdpSocketError),
807    #[error("socket transport protocol union is of an unknown variant")]
808    UnknownUnionVariant(u64),
809}
810
811impl TryFrom<fnet_matchers::SocketTransportProtocol> for SocketTransportProtocol {
812    type Error = SocketTransportProtocolError;
813
814    fn try_from(matcher: fnet_matchers::SocketTransportProtocol) -> Result<Self, Self::Error> {
815        match matcher {
816            fnet_matchers::SocketTransportProtocol::Tcp(tcp) => {
817                Ok(Self::Tcp(tcp.try_into().map_err(|e| SocketTransportProtocolError::Tcp(e))?))
818            }
819            fnet_matchers::SocketTransportProtocol::Udp(udp) => {
820                Ok(Self::Udp(udp.try_into().map_err(|e| SocketTransportProtocolError::Udp(e))?))
821            }
822            fnet_matchers::SocketTransportProtocol::__SourceBreaking { unknown_ordinal } => {
823                Err(SocketTransportProtocolError::UnknownUnionVariant(unknown_ordinal))
824            }
825        }
826    }
827}
828
829impl From<SocketTransportProtocol> for fnet_matchers::SocketTransportProtocol {
830    fn from(matcher: SocketTransportProtocol) -> Self {
831        match matcher {
832            SocketTransportProtocol::Tcp(tcp) => Self::Tcp(tcp.into()),
833            SocketTransportProtocol::Udp(udp) => Self::Udp(udp.into()),
834        }
835    }
836}
837
838#[cfg(test)]
839mod tests {
840    use net_declare::{fidl_ip, fidl_ip_v4, fidl_ip_v6, fidl_subnet, net_subnet_v4, net_subnet_v6};
841    use test_case::test_case;
842
843    use super::*;
844
845    #[test_case(
846        fnet_matchers::Interface::Id(1),
847        Interface::Id(NonZeroU64::new(1).unwrap());
848        "Interface"
849    )]
850    #[test_case(
851        fnet_matchers::BoundInterface::Unbound(fnet_matchers::Empty),
852        BoundInterface::Unbound;
853        "BoundInterface Unbound"
854    )]
855    #[test_case(
856        fnet_matchers::BoundInterface::Bound(fnet_matchers::Interface::Id(1)),
857        BoundInterface::Bound(Interface::Id(NonZeroU64::new(1).unwrap()));
858        "BoundInterface Bound"
859    )]
860    #[test_case(
861        fnet_matchers::Mark::Unmarked(fnet_matchers::Unmarked),
862        Mark::Unmarked;
863        "Unmarked"
864    )]
865    #[test_case(
866        fnet_matchers::Mark::Marked(fnet_matchers::Marked {
867            mask: 0xFF,
868            between: fnet_matchers::Between { start: 10, end: 20 },
869            invert: true,
870        }),
871        Mark::Marked { mask: 0xFF, between: 10..=20, invert: true };
872        "Marked"
873    )]
874    #[test_case(
875        fnet_matchers::MarkInDomain {
876            domain: fnet::MarkDomain::Mark1,
877            mark: fnet_matchers::Mark::Unmarked(fnet_matchers::Unmarked),
878        },
879        MarkInDomain {
880            domain: fnet::MarkDomain::Mark1,
881            mark: Mark::Unmarked,
882        };
883        "MarkInDomain"
884    )]
885    #[test_case(
886        fnet_matchers::AddressMatcherType::Subnet(fidl_subnet!("192.0.2.0/24")),
887        AddressMatcherType::Subnet(Subnet(net_subnet_v4!("192.0.2.0/24").into()));
888        "AddressMatcherTypeV4"
889    )]
890    #[test_case(
891        fnet_matchers::AddressMatcherType::Subnet(fidl_subnet!("2001:db8::/64")),
892        AddressMatcherType::Subnet(Subnet(net_subnet_v6!("2001:db8::/64").into()));
893        "AddressMatcherTypeV6"
894    )]
895    #[test_case(
896        fnet_matchers::Address {
897            matcher: fnet_matchers::AddressMatcherType::Subnet(fidl_subnet!("2001:db8::/64")),
898            invert: true,
899        },
900        Address {
901            matcher: AddressMatcherType::Subnet(Subnet(net_subnet_v6!("2001:db8::/64").into())),
902            invert: true,
903        };
904        "AddressV6"
905    )]
906    #[test_case(
907        fnet_matchers::AddressRange {
908            start: fidl_ip!("192.0.2.0"),
909            end: fidl_ip!("192.0.2.1"),
910        },
911        AddressRange::V4(
912            fidl_ip_v4!("192.0.2.0")..=fidl_ip_v4!("192.0.2.1"),
913        );
914        "AddressRangeV4"
915    )]
916    #[test_case(
917        fnet_matchers::AddressRange {
918            start: fidl_ip!("2001:db8::0"),
919            end: fidl_ip!("2001:db8::8"),
920        },
921        AddressRange::V6(
922            fidl_ip_v6!("2001:db8::0")..=fidl_ip_v6!("2001:db8::8"),
923        );
924        "AddressRangeV6"
925    )]
926    #[test_case(
927        fnet_matchers::PacketTransportProtocol::Udp(fnet_matchers::UdpPacket {
928            src_port: Some(fnet_matchers::Port { start: 1024, end: u16::MAX, invert: false }),
929            dst_port: None,
930            ..Default::default()
931        }),
932        TransportProtocol::Udp {
933            src_port: Some(Port { range: 1024..=u16::MAX, invert: false }),
934            dst_port: None,
935        };
936        "TransportProtocol"
937    )]
938    #[test_case(
939        fnet_matchers::TcpSocket::Empty(fnet_matchers::Empty),
940        TcpSocket::Empty;
941        "TcpSocketEmpty"
942    )]
943    #[test_case(
944        fnet_matchers::TcpSocket::SrcPort(
945            fnet_matchers::BoundPort::Bound(fnet_matchers::Port { start: 1024, end: u16::MAX, invert: false })
946        ),
947        TcpSocket::SrcPort(BoundPort::Bound(Port { range: 1024..=u16::MAX, invert: false }));
948        "TcpSocketSrcPort"
949    )]
950    #[test_case(
951        fnet_matchers::TcpSocket::DstPort(
952            fnet_matchers::BoundPort::Bound(fnet_matchers::Port { start: 80, end: 80, invert: true })
953        ),
954        TcpSocket::DstPort(BoundPort::Bound(Port { range: 80..=80, invert: true }));
955        "TcpSocketDstPort"
956    )]
957    #[test_case(
958        fnet_matchers::TcpSocket::States(fnet_matchers::TcpState::ESTABLISHED),
959        TcpSocket::States(fnet_matchers::TcpState::ESTABLISHED);
960        "TcpSocketStates"
961    )]
962    #[test_case(
963        fnet_matchers::UdpSocket::Empty(fnet_matchers::Empty),
964        UdpSocket::Empty;
965        "UdpSocketEmpty"
966    )]
967    #[test_case(
968        fnet_matchers::UdpSocket::SrcPort(
969            fnet_matchers::BoundPort::Bound(fnet_matchers::Port { start: 1024, end: u16::MAX, invert: false })
970        ),
971        UdpSocket::SrcPort(BoundPort::Bound(Port { range: 1024..=u16::MAX, invert: false }));
972        "UdpSocketSrcPort"
973    )]
974    #[test_case(
975        fnet_matchers::UdpSocket::DstPort(
976            fnet_matchers::BoundPort::Bound(fnet_matchers::Port { start: 53, end: 53, invert: true })
977        ),
978        UdpSocket::DstPort(BoundPort::Bound(Port { range: 53..=53, invert: true }));
979        "UdpSocketDstPort"
980    )]
981    #[test_case(
982        fnet_matchers::UdpSocket::States(fnet_matchers::UdpState::BOUND),
983        UdpSocket::States(fnet_matchers::UdpState::BOUND);
984        "UdpSocketStates"
985    )]
986    #[test_case(
987        fnet_matchers::SocketTransportProtocol::Tcp(
988            fnet_matchers::TcpSocket::SrcPort(
989                fnet_matchers::BoundPort::Bound(fnet_matchers::Port { start: 123, end: 123, invert: false })
990            )
991        ),
992        SocketTransportProtocol::Tcp(TcpSocket::SrcPort(BoundPort::Bound(Port { range: 123..=123, invert: false })));
993        "SocketTransportProtocolTcp"
994    )]
995    #[test_case(
996        fnet_matchers::SocketTransportProtocol::Udp(
997            fnet_matchers::UdpSocket::SrcPort(
998                fnet_matchers::BoundPort::Bound(fnet_matchers::Port { start: 123, end: 123, invert: false })
999            )
1000        ),
1001        SocketTransportProtocol::Udp(UdpSocket::SrcPort(BoundPort::Bound(Port { range: 123..=123, invert: false })));
1002        "SocketTransportProtocolUdp"
1003    )]
1004    #[test_case(
1005        fnet_matchers::BoundPort::Unbound(fnet_matchers::Empty),
1006        BoundPort::Unbound;
1007        "BoundPort Unbound"
1008    )]
1009    #[test_case(
1010        fnet_matchers::BoundAddress::Unbound(fnet_matchers::Empty),
1011        BoundAddress::Unbound;
1012        "BoundAddress Unbound"
1013    )]
1014    #[test_case(
1015        fnet_matchers::TcpSocket::SrcPort(fnet_matchers::BoundPort::Unbound(fnet_matchers::Empty)),
1016        TcpSocket::SrcPort(BoundPort::Unbound);
1017        "TcpSocket SrcPort Unbound"
1018    )]
1019    #[test_case(
1020        fnet_matchers::TcpSocket::DstPort(fnet_matchers::BoundPort::Unbound(fnet_matchers::Empty)),
1021        TcpSocket::DstPort(BoundPort::Unbound);
1022        "TcpSocket DstPort Unbound"
1023    )]
1024    #[test_case(
1025        fnet_matchers::UdpSocket::SrcPort(fnet_matchers::BoundPort::Unbound(fnet_matchers::Empty)),
1026        UdpSocket::SrcPort(BoundPort::Unbound);
1027        "UdpSocket SrcPort Unbound"
1028    )]
1029    #[test_case(
1030        fnet_matchers::UdpSocket::DstPort(fnet_matchers::BoundPort::Unbound(fnet_matchers::Empty)),
1031        UdpSocket::DstPort(BoundPort::Unbound);
1032        "UdpSocket DstPort Unbound"
1033    )]
1034    fn convert_from_fidl_and_back<F, E>(fidl_type: F, local_type: E)
1035    where
1036        E: TryFrom<F> + Clone + Debug + PartialEq,
1037        <E as TryFrom<F>>::Error: Debug + PartialEq,
1038        F: From<E> + Clone + Debug + PartialEq,
1039    {
1040        assert_eq!(fidl_type.clone().try_into(), Ok(local_type.clone()));
1041        assert_eq!(<_ as Into<F>>::into(local_type), fidl_type.clone());
1042    }
1043
1044    #[test_case(
1045        fnet_matchers::BoundInterface::__SourceBreaking { unknown_ordinal: 0 } =>
1046            Err(BoundInterfaceError::UnknownUnionVariant(0));
1047        "UnknownUnionVariant"
1048    )]
1049    #[test_case(
1050        fnet_matchers::BoundInterface::Bound(fnet_matchers::Interface::Id(0)) =>
1051            Err(BoundInterfaceError::Interface(InterfaceError::ZeroId));
1052        "InterfaceError"
1053    )]
1054    fn bound_interface_try_from_error(
1055        fidl: fnet_matchers::BoundInterface,
1056    ) -> Result<BoundInterface, BoundInterfaceError> {
1057        BoundInterface::try_from(fidl)
1058    }
1059
1060    #[test_case(
1061        fnet_matchers::Mark::__SourceBreaking { unknown_ordinal: 0 } =>
1062            Err(MarkError::UnknownUnionVariant(0));
1063        "UnknownUnionVariant"
1064    )]
1065    fn mark_try_from_error(fidl: fnet_matchers::Mark) -> Result<Mark, MarkError> {
1066        Mark::try_from(fidl)
1067    }
1068
1069    #[test_case(
1070        fnet_matchers::MarkInDomain {
1071            domain: fnet::MarkDomain::Mark1,
1072            mark: fnet_matchers::Mark::__SourceBreaking { unknown_ordinal: 0 },
1073        } => Err(MarkInDomainError::Mark(MarkError::UnknownUnionVariant(0)));
1074        "MarkInDomain Mark Error"
1075    )]
1076    fn mark_and_domain_try_from_error(
1077        fidl: fnet_matchers::MarkInDomain,
1078    ) -> Result<MarkInDomain, MarkInDomainError> {
1079        MarkInDomain::try_from(fidl)
1080    }
1081
1082    #[test]
1083    fn address_matcher_type_try_from_unknown_variant() {
1084        assert_eq!(
1085            AddressMatcherType::try_from(fnet_matchers::AddressMatcherType::__SourceBreaking {
1086                unknown_ordinal: 0
1087            }),
1088            Err(AddressMatcherTypeError::UnknownUnionVariant)
1089        );
1090    }
1091
1092    #[test]
1093    fn subnet_try_from_invalid() {
1094        assert_eq!(
1095            Subnet::try_from(fnet::Subnet { addr: fidl_ip!("192.0.2.1"), prefix_len: 33 }),
1096            Err(SubnetError::PrefixTooLong)
1097        );
1098        assert_eq!(Subnet::try_from(fidl_subnet!("192.0.2.1/24")), Err(SubnetError::HostBitsSet));
1099    }
1100
1101    #[test]
1102    fn address_range_try_from_invalid() {
1103        assert_eq!(
1104            AddressRange::try_from(fnet_matchers::AddressRange {
1105                start: fidl_ip!("192.0.2.1"),
1106                end: fidl_ip!("192.0.2.0"),
1107            }),
1108            Err(AddressRangeError::Invalid)
1109        );
1110        assert_eq!(
1111            AddressRange::try_from(fnet_matchers::AddressRange {
1112                start: fidl_ip!("2001:db8::1"),
1113                end: fidl_ip!("2001:db8::"),
1114            }),
1115            Err(AddressRangeError::Invalid)
1116        );
1117    }
1118
1119    #[test]
1120    fn address_range_try_from_family_mismatch() {
1121        assert_eq!(
1122            AddressRange::try_from(fnet_matchers::AddressRange {
1123                start: fidl_ip!("192.0.2.0"),
1124                end: fidl_ip!("2001:db8::"),
1125            }),
1126            Err(AddressRangeError::FamilyMismatch)
1127        );
1128    }
1129
1130    #[test]
1131    fn port_matcher_try_from_invalid() {
1132        assert_eq!(
1133            Port::try_from(fnet_matchers::Port { start: 1, end: 0, invert: false }),
1134            Err(PortError::InvalidPortRange)
1135        );
1136    }
1137
1138    #[test]
1139    fn transport_protocol_try_from_unknown_variant() {
1140        assert_eq!(
1141            TransportProtocol::try_from(fnet_matchers::PacketTransportProtocol::__SourceBreaking {
1142                unknown_ordinal: 0
1143            }),
1144            Err(TransportProtocolError::UnknownUnionVariant)
1145        );
1146    }
1147
1148    #[test_case(
1149        fnet_matchers::TcpSocket::__SourceBreaking { unknown_ordinal: 100 } =>
1150            Err(TcpSocketError::UnknownUnionVariant(100));
1151        "TcpSocket UnknownUnionVariant"
1152    )]
1153    #[test_case(
1154        fnet_matchers::TcpSocket::SrcPort(fnet_matchers::BoundPort::Bound(fnet_matchers::Port {
1155            start: 1,
1156            end: 0,
1157            invert: false,
1158        })) => Err(TcpSocketError::BoundPort(BoundPortError::Port(PortError::InvalidPortRange)));
1159        "TcpSocket SrcPort Error"
1160    )]
1161    #[test_case(
1162        fnet_matchers::TcpSocket::DstPort(fnet_matchers::BoundPort::Bound(fnet_matchers::Port {
1163            start: 1,
1164            end: 0,
1165            invert: false,
1166        })) => Err(TcpSocketError::BoundPort(BoundPortError::Port(PortError::InvalidPortRange)));
1167        "TcpSocket DstPort Error"
1168    )]
1169    fn tcp_socket_try_from_error(
1170        fidl: fnet_matchers::TcpSocket,
1171    ) -> Result<TcpSocket, TcpSocketError> {
1172        TcpSocket::try_from(fidl)
1173    }
1174
1175    #[test_case(
1176        fnet_matchers::UdpSocket::__SourceBreaking { unknown_ordinal: 100 } =>
1177            Err(UdpSocketError::UnknownUnionVariant(100));
1178        "UdpSocket UnknownUnionVariant"
1179    )]
1180    #[test_case(
1181        fnet_matchers::UdpSocket::SrcPort(fnet_matchers::BoundPort::Bound(fnet_matchers::Port {
1182            start: 1,
1183            end: 0,
1184            invert: false,
1185        })) => Err(UdpSocketError::BoundPort(BoundPortError::Port(PortError::InvalidPortRange)));
1186        "UdpSocket SrcPort Error"
1187    )]
1188    #[test_case(
1189        fnet_matchers::UdpSocket::DstPort(fnet_matchers::BoundPort::Bound(fnet_matchers::Port {
1190            start: 1,
1191            end: 0,
1192            invert: false,
1193        })) => Err(UdpSocketError::BoundPort(BoundPortError::Port(PortError::InvalidPortRange)));
1194        "UdpSocket DstPort Error"
1195    )]
1196    fn udp_socket_try_from_error(
1197        fidl: fnet_matchers::UdpSocket,
1198    ) -> Result<UdpSocket, UdpSocketError> {
1199        UdpSocket::try_from(fidl)
1200    }
1201
1202    #[test_case(
1203        fnet_matchers::SocketTransportProtocol::__SourceBreaking {
1204            unknown_ordinal: 100
1205        } => Err(SocketTransportProtocolError::UnknownUnionVariant(100));
1206        "SocketTransportProtocol UnknownUnionVariant"
1207    )]
1208    #[test_case(
1209        fnet_matchers::SocketTransportProtocol::Tcp(
1210            fnet_matchers::TcpSocket::__SourceBreaking { unknown_ordinal: 100 }
1211        ) => Err(SocketTransportProtocolError::Tcp(TcpSocketError::UnknownUnionVariant(100)));
1212        "SocketTransportProtocol Tcp Error"
1213    )]
1214    #[test_case(
1215        fnet_matchers::SocketTransportProtocol::Udp(
1216            fnet_matchers::UdpSocket::__SourceBreaking { unknown_ordinal: 100 }
1217        ) => Err(SocketTransportProtocolError::Udp(UdpSocketError::UnknownUnionVariant(100)));
1218        "SocketTransportProtocol Udp Error"
1219    )]
1220    fn socket_transport_protocol_try_from_error(
1221        fidl: fnet_matchers::SocketTransportProtocol,
1222    ) -> Result<SocketTransportProtocol, SocketTransportProtocolError> {
1223        SocketTransportProtocol::try_from(fidl)
1224    }
1225}