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