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