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