1use 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#[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#[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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
81pub enum BoundInterface {
82 Unbound,
83 Bound(Interface),
84}
85
86#[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#[derive(Clone, Copy, Eq, Hash, PartialEq)]
130pub struct Subnet(net_types::ip::SubnetEither);
131
132#[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#[derive(Debug, Clone, PartialEq, Eq)]
194pub enum AddressRange {
195 V4(RangeInclusive<fnet::Ipv4Address>),
196 V6(RangeInclusive<fnet::Ipv6Address>),
197}
198
199#[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 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#[derive(Clone, PartialEq, Eq)]
263pub enum AddressMatcherType {
264 Subnet(Subnet),
265 Range(AddressRange),
266}
267
268#[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#[derive(Debug, Clone, PartialEq, Eq)]
326pub struct Address {
327 pub matcher: AddressMatcherType,
328 pub invert: bool,
329}
330
331#[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#[derive(Debug, Clone, PartialEq, Eq)]
362pub enum BoundAddress {
363 Unbound,
364 Bound(Address),
365}
366
367#[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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
405pub struct Port {
406 range: RangeInclusive<u16>,
407 invert: bool,
408}
409
410#[derive(Debug, Clone, PartialEq, Eq, Hash)]
412pub enum BoundPort {
413 Unbound,
414 Bound(Port),
415}
416
417#[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#[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 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#[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#[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 match self {
588 TransportProtocol::Tcp { src_port, dst_port } => {
589 let mut debug_struct = f.debug_struct("Tcp");
590
591 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 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#[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#[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#[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#[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#[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}