Skip to main content

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