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