Skip to main content

netstack3_base/
matchers.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Trait definition for matchers.
6
7use alloc::format;
8use alloc::string::String;
9use core::fmt::Debug;
10use core::num::NonZeroU64;
11use core::ops::RangeInclusive;
12
13use bitflags::bitflags;
14use derivative::Derivative;
15use net_types::ip::{Ip, IpAddr, IpAddress, Ipv4Addr, Ipv6Addr, Subnet};
16
17use crate::{InspectableValue, Inspector, Mark, MarkDomain, MarkStorage, Marks};
18
19/// Trait defining required types for matchers provided by bindings.
20///
21/// Allows rules that match on device class to be installed, storing the
22/// [`MatcherBindingsTypes::DeviceClass`] type at rest, while allowing Netstack3
23/// Core to have Bindings provide the type since it is platform-specific.
24pub trait MatcherBindingsTypes {
25    /// The device class type for devices installed in the netstack.
26    type DeviceClass: Clone + Debug;
27    /// The type used to represent a custom filter matcher.
28    ///
29    /// `Clone` is required because filter validator clones rules when
30    /// installing them.
31    type BindingsPacketMatcher: Clone + Debug + InspectableValue;
32}
33
34/// Common pattern to define a matcher for a metadata input `T`.
35///
36/// Used in matching engines like filtering and routing rules.
37pub trait Matcher<T> {
38    /// Returns whether the provided value matches.
39    fn matches(&self, actual: &T) -> bool;
40
41    /// Returns whether the provided value is set and matches.
42    fn required_matches(&self, actual: Option<&T>) -> bool {
43        actual.map_or(false, |actual| self.matches(actual))
44    }
45}
46
47/// Implement `Matcher` for optional matchers, so that if a matcher is left
48/// unspecified, it matches all inputs by default.
49impl<T, O> Matcher<T> for Option<O>
50where
51    O: Matcher<T>,
52{
53    fn matches(&self, actual: &T) -> bool {
54        self.as_ref().map_or(true, |expected| expected.matches(actual))
55    }
56
57    fn required_matches(&self, actual: Option<&T>) -> bool {
58        self.as_ref().map_or(true, |expected| expected.required_matches(actual))
59    }
60}
61
62/// Matcher that matches IP addresses in a subnet.
63#[derive(Debug, Copy, Clone, PartialEq, Eq)]
64pub struct SubnetMatcher<A: IpAddress>(pub Subnet<A>);
65
66impl<A: IpAddress> Matcher<A> for SubnetMatcher<A> {
67    fn matches(&self, actual: &A) -> bool {
68        let Self(matcher) = self;
69        matcher.contains(actual)
70    }
71}
72
73/// A matcher for network interfaces.
74#[derive(Clone, Derivative, PartialEq, Eq)]
75#[derivative(Debug)]
76pub enum InterfaceMatcher<DeviceClass> {
77    /// The ID of the interface as assigned by the netstack.
78    Id(NonZeroU64),
79    /// Match based on name.
80    Name(String),
81    /// The device class of the interface.
82    DeviceClass(DeviceClass),
83}
84
85impl<DeviceClass: Debug> InspectableValue for InterfaceMatcher<DeviceClass> {
86    fn record<I: Inspector>(&self, name: &str, inspector: &mut I) {
87        match self {
88            InterfaceMatcher::Id(id) => inspector.record_string(name, format!("Id({})", id.get())),
89            InterfaceMatcher::Name(iface_name) => {
90                inspector.record_string(name, format!("Name({iface_name})"))
91            }
92            InterfaceMatcher::DeviceClass(class) => {
93                inspector.record_debug(name, format!("Class({class:?})"))
94            }
95        };
96    }
97}
98
99/// Allows code to match on properties of an interface (ID, name, and device
100/// class) without Netstack3 Core (or Bindings, in the case of the device class)
101/// having to specifically expose that state.
102pub trait InterfaceProperties<DeviceClass> {
103    /// Returns whether the provided ID matches the interface.
104    fn id_matches(&self, id: &NonZeroU64) -> bool;
105
106    /// Returns whether the provided name matches the interface.
107    fn name_matches(&self, name: &str) -> bool;
108
109    /// Returns whether the provided device class matches the interface.
110    fn device_class_matches(&self, device_class: &DeviceClass) -> bool;
111}
112
113impl<DeviceClass, I: InterfaceProperties<DeviceClass>> Matcher<I>
114    for InterfaceMatcher<DeviceClass>
115{
116    fn matches(&self, actual: &I) -> bool {
117        match self {
118            InterfaceMatcher::Id(id) => actual.id_matches(id),
119            InterfaceMatcher::Name(name) => actual.name_matches(name),
120            InterfaceMatcher::DeviceClass(device_class) => {
121                actual.device_class_matches(device_class)
122            }
123        }
124    }
125}
126
127/// Matcher for the bound device of locally generated traffic.
128#[derive(Debug, Clone, PartialEq, Eq)]
129pub enum BoundInterfaceMatcher<DeviceClass> {
130    /// The packet is bound to a device which is matched by the matcher.
131    Bound(InterfaceMatcher<DeviceClass>),
132    /// There is no bound device.
133    Unbound,
134}
135
136impl<'a, DeviceClass, D: InterfaceProperties<DeviceClass>> Matcher<Option<&'a D>>
137    for BoundInterfaceMatcher<DeviceClass>
138{
139    fn matches(&self, actual: &Option<&'a D>) -> bool {
140        match self {
141            BoundInterfaceMatcher::Bound(matcher) => matcher.required_matches(actual.as_deref()),
142            BoundInterfaceMatcher::Unbound => actual.is_none(),
143        }
144    }
145}
146
147impl<DeviceClass: Debug> InspectableValue for BoundInterfaceMatcher<DeviceClass> {
148    fn record<I: Inspector>(&self, name: &str, inspector: &mut I) {
149        match self {
150            BoundInterfaceMatcher::Unbound => inspector.record_str(name, "Unbound"),
151            BoundInterfaceMatcher::Bound(interface) => {
152                inspector.record_inspectable_value(name, interface)
153            }
154        }
155    }
156}
157
158/// A matcher to the socket mark.
159#[derive(Debug, Clone, Copy, PartialEq, Eq)]
160pub enum MarkMatcher {
161    /// Matches a packet if it is unmarked.
162    Unmarked,
163    /// The packet carries a mark that is in the range after masking.
164    Marked {
165        /// The mask to apply.
166        mask: u32,
167        /// Start of the range, inclusive.
168        start: u32,
169        /// End of the range, inclusive.
170        end: u32,
171        /// Inverts the meaning of the match.
172        invert: bool,
173    },
174}
175
176impl Matcher<Mark> for MarkMatcher {
177    fn matches(&self, Mark(actual): &Mark) -> bool {
178        match self {
179            MarkMatcher::Unmarked => actual.is_none(),
180            MarkMatcher::Marked { mask, start, end, invert } => {
181                let val = actual.is_some_and(|actual| (*start..=*end).contains(&(actual & *mask)));
182
183                if *invert { !val } else { val }
184            }
185        }
186    }
187}
188
189/// A matcher for the mark in a specific domain..
190#[derive(Debug, Clone, Copy, PartialEq, Eq)]
191pub struct MarkInDomainMatcher {
192    /// The domain of the mark to match.
193    pub domain: MarkDomain,
194    /// The matcher for the mark.
195    pub matcher: MarkMatcher,
196}
197
198/// The 2 mark matchers a rule can specify. All non-none markers must match.
199#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
200pub struct MarkMatchers(MarkStorage<Option<MarkMatcher>>);
201
202impl MarkMatchers {
203    /// Creates [`MarkMatcher`]s from an iterator of `(MarkDomain, MarkMatcher)`.
204    ///
205    /// An unspecified domain will not have a matcher.
206    ///
207    /// # Panics
208    ///
209    /// Panics if the same domain is specified more than once.
210    pub fn new(matchers: impl IntoIterator<Item = (MarkDomain, MarkMatcher)>) -> Self {
211        MarkMatchers(MarkStorage::new(matchers))
212    }
213
214    /// Returns an iterator over the mark matchers of all domains.
215    pub fn iter(&self) -> impl Iterator<Item = (MarkDomain, &Option<MarkMatcher>)> {
216        let Self(storage) = self;
217        storage.iter()
218    }
219}
220
221impl Matcher<Marks> for MarkMatchers {
222    fn matches(&self, actual: &Marks) -> bool {
223        let Self(matchers) = self;
224        matchers.zip_with(actual).all(|(_domain, matcher, actual)| matcher.matches(actual))
225    }
226}
227
228impl InspectableValue for MarkMatcher {
229    fn record<I: Inspector>(&self, name: &str, inspector: &mut I) {
230        match self {
231            MarkMatcher::Unmarked => inspector.record_str(name, "Unmarked"),
232            MarkMatcher::Marked { start, end, mask, invert } => {
233                inspector.record_child(name, |inspector| {
234                    inspector.record_uint("Mask", *mask);
235                    inspector.record_child("Range", |inspector| {
236                        inspector.record_uint("StartInclusive", *start);
237                        inspector.record_uint("EndInclusive", *end);
238                    });
239                    inspector.record_bool("Invert", *invert);
240                })
241            }
242        }
243    }
244}
245
246impl InspectableValue for MarkMatchers {
247    fn record<I: Inspector>(&self, name: &str, inspector: &mut I) {
248        inspector.record_child(name, |inspector| {
249            for (domain, matcher) in self.iter() {
250                if let Some(matcher) = matcher {
251                    matcher.record(domain.name(), inspector);
252                }
253            }
254        });
255    }
256}
257
258/// A matcher for a socket's cookie.
259pub struct SocketCookieMatcher {
260    /// The cookie to check against.
261    pub cookie: u64,
262    /// Invert the matching criterion (i.e. if the socket cookie isn't the same,
263    /// it matches).
264    pub invert: bool,
265}
266
267impl Matcher<u64> for SocketCookieMatcher {
268    fn matches(&self, actual: &u64) -> bool {
269        let val = *actual == self.cookie;
270        if self.invert { !val } else { val }
271    }
272}
273
274/// A matcher for transport-layer port numbers.
275#[derive(Clone, Debug)]
276pub struct PortMatcher {
277    /// The range of port numbers in which the tested port number must fall.
278    pub range: RangeInclusive<u16>,
279    /// Whether to check for an "inverse" or "negative" match (in which case,
280    /// if the matcher criteria do *not* apply, it *is* considered a match, and
281    /// vice versa).
282    pub invert: bool,
283}
284
285impl Matcher<u16> for PortMatcher {
286    fn matches(&self, actual: &u16) -> bool {
287        let Self { range, invert } = self;
288        range.contains(actual) ^ *invert
289    }
290}
291
292/// A matcher for (possibly bound) transport-layer port numbers.
293#[derive(Clone, Debug)]
294pub enum BoundPortMatcher {
295    /// The target is bound to a port matched by the inner matcher.
296    Bound(PortMatcher),
297    /// The target is not bound to a specific port.
298    Unbound,
299}
300
301impl Matcher<Option<u16>> for BoundPortMatcher {
302    fn matches(&self, actual: &Option<u16>) -> bool {
303        match (self, actual) {
304            (BoundPortMatcher::Unbound, None) => true,
305            (BoundPortMatcher::Bound(matcher), Some(port)) => matcher.matches(&port),
306            _ => false,
307        }
308    }
309}
310
311bitflags! {
312    /// A matcher for TCP state machine state.
313    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
314    pub struct TcpStateMatcher: u32 {
315        /// The TCP ESTABLISHED state.
316        const ESTABLISHED = 1 << 0;
317        /// The TCP SYN_SENT state.
318        const SYN_SENT = 1 << 1;
319        /// The TCP SYN_RECV state.
320        const SYN_RECV = 1 << 2;
321        /// The TCP FIN_WAIT1 state.
322        const FIN_WAIT1 = 1 << 3;
323        /// The TCP FIN_WAIT2 state.
324        const FIN_WAIT2 = 1 << 4;
325        /// The TCP TIME_WAIT state.
326        const TIME_WAIT = 1 << 5;
327        /// The TCP CLOSE state.
328        const CLOSE = 1 << 6;
329        /// The TCP CLOSE_WAIT state.
330        const CLOSE_WAIT = 1 << 7;
331        /// The TCP LAST_ACK state.
332        const LAST_ACK = 1 << 8;
333        /// The TCP LISTEN state.
334        const LISTEN = 1 << 9;
335        /// The TCP CLOSING state.
336        const CLOSING = 1 << 10;
337    }
338}
339
340impl Matcher<TcpSocketState> for TcpStateMatcher {
341    fn matches(&self, actual: &TcpSocketState) -> bool {
342        self.contains(actual.matcher_flag())
343    }
344}
345
346/// Represents the state of a TCP socket's state machine.
347#[derive(Debug, Copy, Clone, PartialEq, Eq)]
348#[allow(missing_docs)]
349pub enum TcpSocketState {
350    Established,
351    SynSent,
352    SynRecv,
353    FinWait1,
354    FinWait2,
355    TimeWait,
356    Close,
357    CloseWait,
358    LastAck,
359    Listen,
360    Closing,
361}
362
363impl TcpSocketState {
364    fn matcher_flag(&self) -> TcpStateMatcher {
365        match self {
366            TcpSocketState::Established => TcpStateMatcher::ESTABLISHED,
367            TcpSocketState::SynSent => TcpStateMatcher::SYN_SENT,
368            TcpSocketState::SynRecv => TcpStateMatcher::SYN_RECV,
369            TcpSocketState::FinWait1 => TcpStateMatcher::FIN_WAIT1,
370            TcpSocketState::FinWait2 => TcpStateMatcher::FIN_WAIT2,
371            TcpSocketState::TimeWait => TcpStateMatcher::TIME_WAIT,
372            TcpSocketState::Close => TcpStateMatcher::CLOSE,
373            TcpSocketState::CloseWait => TcpStateMatcher::CLOSE_WAIT,
374            TcpSocketState::LastAck => TcpStateMatcher::LAST_ACK,
375            TcpSocketState::Listen => TcpStateMatcher::LISTEN,
376            TcpSocketState::Closing => TcpStateMatcher::CLOSING,
377        }
378    }
379}
380
381/// Allows code to match on properties of a TCP socket without Netstack3 Core
382/// having to specifically expose that state.
383pub trait TcpSocketProperties {
384    /// Returns whether the socket's source port is matched by the matcher.
385    fn src_port_matches(&self, matcher: &BoundPortMatcher) -> bool;
386
387    /// Returns whether the socket's destination port is matched by the matcher.
388    fn dst_port_matches(&self, matcher: &BoundPortMatcher) -> bool;
389
390    /// Returns whether the socket's TCP state is matched by the matcher.
391    fn state_matches(&self, matcher: &TcpStateMatcher) -> bool;
392}
393
394impl TcpSocketProperties for ! {
395    fn src_port_matches(&self, _matcher: &BoundPortMatcher) -> bool {
396        unimplemented!()
397    }
398
399    fn dst_port_matches(&self, _matcher: &BoundPortMatcher) -> bool {
400        unimplemented!()
401    }
402
403    fn state_matches(&self, _matcher: &TcpStateMatcher) -> bool {
404        unimplemented!()
405    }
406}
407
408impl<T> TcpSocketProperties for &T
409where
410    T: TcpSocketProperties,
411{
412    fn src_port_matches(&self, matcher: &BoundPortMatcher) -> bool {
413        (*self).src_port_matches(matcher)
414    }
415
416    fn dst_port_matches(&self, matcher: &BoundPortMatcher) -> bool {
417        (*self).dst_port_matches(matcher)
418    }
419
420    fn state_matches(&self, matcher: &TcpStateMatcher) -> bool {
421        (*self).state_matches(matcher)
422    }
423}
424
425/// The top-level matcher for TCP sockets.
426pub enum TcpSocketMatcher {
427    /// Match any TCP socket without further constraints.
428    Empty,
429    /// Match on the source port.
430    SrcPort(BoundPortMatcher),
431    /// Match on the destination port.
432    DstPort(BoundPortMatcher),
433    /// Match on the state of the TCP state machine.
434    State(TcpStateMatcher),
435}
436
437impl<T: TcpSocketProperties> Matcher<T> for TcpSocketMatcher {
438    fn matches(&self, actual: &T) -> bool {
439        match self {
440            TcpSocketMatcher::Empty => true,
441            TcpSocketMatcher::SrcPort(matcher) => actual.src_port_matches(matcher),
442            TcpSocketMatcher::DstPort(matcher) => actual.dst_port_matches(matcher),
443            TcpSocketMatcher::State(matcher) => actual.state_matches(matcher),
444        }
445    }
446}
447
448bitflags! {
449    /// A matcher for UDP states.
450    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
451    pub struct UdpStateMatcher: u32 {
452        /// The UDP socket is bound but not connected.
453        const BOUND = 1 << 0;
454        /// The UDP socket is explicitly connected.
455        const CONNECTED = 1 << 1;
456    }
457}
458
459impl Matcher<UdpSocketState> for UdpStateMatcher {
460    fn matches(&self, actual: &UdpSocketState) -> bool {
461        self.contains(actual.matcher_flag())
462    }
463}
464
465/// Represents the state of a UDP socket.
466#[derive(Debug, Copy, Clone, PartialEq, Eq)]
467pub enum UdpSocketState {
468    /// The socket is bound to a local address and (maybe) port.
469    Bound,
470    /// The socket is connected to a remote peer and has a full 4-tuple.
471    Connected,
472}
473
474impl UdpSocketState {
475    fn matcher_flag(&self) -> UdpStateMatcher {
476        match self {
477            UdpSocketState::Bound => UdpStateMatcher::BOUND,
478            UdpSocketState::Connected => UdpStateMatcher::CONNECTED,
479        }
480    }
481}
482
483/// Allows code to match on properties of a UDP socket without Netstack3 Core
484/// having to specifically expose that state.
485pub trait UdpSocketProperties {
486    /// Returns whether the socket's source port is matched by the matcher.
487    fn src_port_matches(&self, matcher: &BoundPortMatcher) -> bool;
488
489    /// Returns whether the socket's destination port is matched by the matcher.
490    fn dst_port_matches(&self, matcher: &BoundPortMatcher) -> bool;
491
492    /// Returns whether the socket's UDP state is matched by the matcher.
493    fn state_matches(&self, matcher: &UdpStateMatcher) -> bool;
494}
495
496impl UdpSocketProperties for ! {
497    fn src_port_matches(&self, _matcher: &BoundPortMatcher) -> bool {
498        unimplemented!()
499    }
500
501    fn dst_port_matches(&self, _matcher: &BoundPortMatcher) -> bool {
502        unimplemented!()
503    }
504
505    fn state_matches(&self, _matcher: &UdpStateMatcher) -> bool {
506        unimplemented!()
507    }
508}
509
510impl<U> UdpSocketProperties for &U
511where
512    U: UdpSocketProperties,
513{
514    fn src_port_matches(&self, matcher: &BoundPortMatcher) -> bool {
515        (*self).src_port_matches(matcher)
516    }
517
518    fn dst_port_matches(&self, matcher: &BoundPortMatcher) -> bool {
519        (*self).dst_port_matches(matcher)
520    }
521
522    fn state_matches(&self, matcher: &UdpStateMatcher) -> bool {
523        (*self).state_matches(matcher)
524    }
525}
526
527/// The top-level matcher for UDP sockets.
528pub enum UdpSocketMatcher {
529    /// Match any UDP socket without further constraints.
530    Empty,
531    /// Match the source port.
532    SrcPort(BoundPortMatcher),
533    /// Match the destination port.
534    DstPort(BoundPortMatcher),
535    /// Match the UDP state.
536    State(UdpStateMatcher),
537}
538
539impl<T: UdpSocketProperties> Matcher<T> for UdpSocketMatcher {
540    fn matches(&self, actual: &T) -> bool {
541        match self {
542            UdpSocketMatcher::Empty => true,
543            UdpSocketMatcher::SrcPort(matcher) => actual.src_port_matches(matcher),
544            UdpSocketMatcher::DstPort(matcher) => actual.dst_port_matches(matcher),
545            UdpSocketMatcher::State(matcher) => actual.state_matches(matcher),
546        }
547    }
548}
549
550/// Provides optional access to TCP socket properties.
551pub trait MaybeSocketTransportProperties {
552    /// The type that encapsulates TCP socket properties.
553    type TcpProps<'a>: TcpSocketProperties
554    where
555        Self: 'a;
556
557    /// The type that encapsulates UDP socket properties.
558    type UdpProps<'a>: UdpSocketProperties
559    where
560        Self: 'a;
561
562    /// Returns TCP socket properties if the socket is a TCP socket.
563    fn tcp_socket_properties(&self) -> Option<&Self::TcpProps<'_>>;
564
565    /// Returns UDP socket properties if the socket is a UDP socket.
566    fn udp_socket_properties(&self) -> Option<&Self::UdpProps<'_>>;
567}
568
569impl MaybeSocketTransportProperties for ! {
570    type TcpProps<'a>
571        = !
572    where
573        Self: 'a;
574
575    type UdpProps<'a>
576        = !
577    where
578        Self: 'a;
579
580    fn tcp_socket_properties(&self) -> Option<&Self::TcpProps<'_>> {
581        unimplemented!()
582    }
583
584    fn udp_socket_properties(&self) -> Option<&Self::UdpProps<'_>> {
585        unimplemented!()
586    }
587}
588
589/// A matcher for the transport protocol of a socket.
590pub enum SocketTransportProtocolMatcher {
591    /// Match against a TCP socket.
592    Tcp(TcpSocketMatcher),
593    /// Match against a UDP socket.
594    Udp(UdpSocketMatcher),
595}
596
597impl<T: MaybeSocketTransportProperties> Matcher<T> for SocketTransportProtocolMatcher {
598    fn matches(&self, actual: &T) -> bool {
599        match self {
600            SocketTransportProtocolMatcher::Tcp(tcp_matcher) => {
601                actual.tcp_socket_properties().map_or(false, |props| tcp_matcher.matches(props))
602            }
603            SocketTransportProtocolMatcher::Udp(udp_matcher) => {
604                actual.udp_socket_properties().map_or(false, |props| udp_matcher.matches(props))
605            }
606        }
607    }
608}
609
610/// A matcher for IP addresses.
611#[derive(Clone, Derivative)]
612#[derivative(Debug)]
613pub enum AddressMatcherType<A: IpAddress> {
614    /// A subnet that must contain the address.
615    #[derivative(Debug = "transparent")]
616    Subnet(SubnetMatcher<A>),
617    /// An inclusive range of IP addresses that must contain the address.
618    Range(RangeInclusive<A>),
619}
620
621impl<A: IpAddress> Matcher<A> for AddressMatcherType<A> {
622    fn matches(&self, actual: &A) -> bool {
623        match self {
624            Self::Subnet(subnet_matcher) => subnet_matcher.matches(actual),
625            Self::Range(range) => range.contains(actual),
626        }
627    }
628}
629
630/// A matcher for IP addresses.
631#[derive(Clone, Debug)]
632pub struct AddressMatcher<A: IpAddress> {
633    /// The type of the address matcher.
634    pub matcher: AddressMatcherType<A>,
635    /// Whether to check for an "inverse" or "negative" match (in which case,
636    /// if the matcher criteria do *not* apply, it *is* considered a match, and
637    /// vice versa).
638    pub invert: bool,
639}
640
641impl<A: IpAddress> AddressMatcher<A> {
642    /// Creates a matcher that matches all IP addresses.
643    pub fn match_all() -> Self {
644        Self {
645            matcher: AddressMatcherType::Subnet(SubnetMatcher(A::Version::ALL_ADDRS_SUBNET)),
646            invert: false,
647        }
648    }
649}
650
651impl<A: IpAddress> InspectableValue for AddressMatcher<A> {
652    fn record<I: Inspector>(&self, name: &str, inspector: &mut I) {
653        let AddressMatcher { matcher, invert } = self;
654
655        inspector.record_child(name, |inspector| {
656            inspector.record_bool("invert", *invert);
657            match matcher {
658                AddressMatcherType::Subnet(SubnetMatcher(subnet)) => {
659                    inspector.record_display("subnet", subnet)
660                }
661                AddressMatcherType::Range(range) => {
662                    inspector.record_display("start", range.start());
663                    inspector.record_display("end", range.end());
664                }
665            }
666        })
667    }
668}
669
670impl<A: IpAddress> Matcher<A> for AddressMatcher<A> {
671    fn matches(&self, addr: &A) -> bool {
672        let Self { matcher, invert } = self;
673        matcher.matches(addr) ^ *invert
674    }
675}
676
677/// An address matcher that matches any IP version as specified at runtime.
678pub enum AddressMatcherEither {
679    /// The top-level IPv4 address matcher.
680    V4(AddressMatcher<Ipv4Addr>),
681    /// The top-level IPv6 address matcher.
682    V6(AddressMatcher<Ipv6Addr>),
683}
684
685/// An IP-generic address matcher that matches a (possibly bound) IP address.
686pub enum BoundAddressMatcherEither {
687    /// The target is bound to an address matched by the inner matcher.
688    Bound(AddressMatcherEither),
689    /// The target is not bound to a specific address.
690    Unbound,
691}
692
693impl Matcher<Option<IpAddr>> for BoundAddressMatcherEither {
694    fn matches(&self, addr: &Option<IpAddr>) -> bool {
695        match (self, addr) {
696            (BoundAddressMatcherEither::Unbound, None) => true,
697            (BoundAddressMatcherEither::Bound(matcher), Some(addr)) => match (matcher, addr) {
698                (AddressMatcherEither::V4(matcher), IpAddr::V4(addr)) => matcher.matches(addr),
699                (AddressMatcherEither::V6(matcher), IpAddr::V6(addr)) => matcher.matches(addr),
700                _ => false,
701            },
702            _ => false,
703        }
704    }
705}
706
707/// Allows code to match on properties of a socket without Netstack3 Core
708/// having to specifically expose that state.
709pub trait IpSocketProperties<DeviceClass> {
710    /// Returns whether the provided IP version matches the socket.
711    fn family_matches(&self, family: &net_types::ip::IpVersion) -> bool;
712
713    /// Returns whether the provided address matcher matches the socket's source
714    /// address.
715    fn src_addr_matches(&self, addr: &BoundAddressMatcherEither) -> bool;
716
717    /// Returns whether the provided address matcher matches the socket's
718    /// destination address.
719    fn dst_addr_matches(&self, addr: &BoundAddressMatcherEither) -> bool;
720
721    /// Returns whether the transport protocol matches the socket's
722    /// transport-layer information.
723    fn transport_protocol_matches(&self, matcher: &SocketTransportProtocolMatcher) -> bool;
724
725    /// Returns whether the provided interface matcher matches the socket's
726    /// bound interface, if present.
727    fn bound_interface_matches(&self, iface: &BoundInterfaceMatcher<DeviceClass>) -> bool;
728
729    /// Returns whether the provided cookie matcher matches the socket's cookie.
730    fn cookie_matches(&self, cookie: &SocketCookieMatcher) -> bool;
731
732    /// Returns whether the provided mark matcher matches the corresponding mark.
733    fn mark_matches(&self, matcher: &MarkInDomainMatcher) -> bool;
734}
735
736/// The top-level matcher for IP sockets.
737pub enum IpSocketMatcher<DeviceClass> {
738    /// Matches the socket's address family.
739    Family(net_types::ip::IpVersion),
740    /// Matches the socket's source address.
741    SrcAddr(BoundAddressMatcherEither),
742    /// Matches the socket's destination address.
743    DstAddr(BoundAddressMatcherEither),
744    /// Matches the socket's transport protocol.
745    Proto(SocketTransportProtocolMatcher),
746    /// Matches the socket's bound interface.
747    BoundInterface(BoundInterfaceMatcher<DeviceClass>),
748    /// Matches the socket's cookie.
749    Cookie(SocketCookieMatcher),
750    /// Matches the socket's mark.
751    Mark(MarkInDomainMatcher),
752}
753
754impl<DeviceClass, S: IpSocketProperties<DeviceClass>> Matcher<S> for IpSocketMatcher<DeviceClass> {
755    fn matches(&self, actual: &S) -> bool {
756        match self {
757            IpSocketMatcher::Family(family) => actual.family_matches(family),
758            IpSocketMatcher::SrcAddr(addr) => actual.src_addr_matches(addr),
759            IpSocketMatcher::DstAddr(addr) => actual.dst_addr_matches(addr),
760            IpSocketMatcher::Proto(proto) => actual.transport_protocol_matches(proto),
761            IpSocketMatcher::BoundInterface(iface) => actual.bound_interface_matches(iface),
762            IpSocketMatcher::Cookie(cookie) => actual.cookie_matches(cookie),
763            IpSocketMatcher::Mark(mark) => actual.mark_matches(mark),
764        }
765    }
766}
767
768/// Allows code to take an opaque matcher that works on IP sockets without
769/// needing to know the type(s) of the underlying matcher(s).
770pub trait IpSocketPropertiesMatcher<DeviceClass> {
771    /// Whether the matcher matches `actual`.
772    fn matches_ip_socket<S: IpSocketProperties<DeviceClass>>(&self, actual: &S) -> bool;
773}
774
775impl<DeviceClass> IpSocketPropertiesMatcher<DeviceClass> for IpSocketMatcher<DeviceClass> {
776    fn matches_ip_socket<S: IpSocketProperties<DeviceClass>>(&self, actual: &S) -> bool {
777        self.matches(actual)
778    }
779}
780
781impl<DeviceClass> IpSocketPropertiesMatcher<DeviceClass> for [IpSocketMatcher<DeviceClass>] {
782    fn matches_ip_socket<S: IpSocketProperties<DeviceClass>>(&self, actual: &S) -> bool {
783        self.iter().all(|matcher| matcher.matches(actual))
784    }
785}
786
787#[cfg(any(test, feature = "testutils"))]
788pub(crate) mod testutil {
789    use alloc::string::String;
790    use core::num::NonZeroU64;
791
792    use crate::matchers::InterfaceProperties;
793    use crate::testutil::{FakeDeviceClass, FakeStrongDeviceId, FakeWeakDeviceId};
794    use crate::{DeviceIdentifier, StrongDeviceIdentifier};
795
796    /// A fake device ID for testing matchers.
797    #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
798    #[allow(missing_docs)]
799    pub struct FakeMatcherDeviceId {
800        pub id: NonZeroU64,
801        pub name: String,
802        pub class: FakeDeviceClass,
803    }
804
805    impl FakeMatcherDeviceId {
806        /// Returns a [`FakeMatcherDeviceId`] for an arbitrary WLAN interface.
807        ///
808        /// The interface returned will always be identical.
809        pub fn wlan_interface() -> FakeMatcherDeviceId {
810            FakeMatcherDeviceId {
811                id: NonZeroU64::new(1).unwrap(),
812                name: String::from("wlan"),
813                class: FakeDeviceClass::Wlan,
814            }
815        }
816
817        /// Returns a [`FakeMatcherDeviceId`] for an arbitrary Ethernet interface.
818        ///
819        /// The interface returned will always be identical.
820        pub fn ethernet_interface() -> FakeMatcherDeviceId {
821            FakeMatcherDeviceId {
822                id: NonZeroU64::new(2).unwrap(),
823                name: String::from("eth"),
824                class: FakeDeviceClass::Ethernet,
825            }
826        }
827    }
828
829    impl StrongDeviceIdentifier for FakeMatcherDeviceId {
830        type Weak = FakeWeakDeviceId<Self>;
831
832        fn downgrade(&self) -> Self::Weak {
833            FakeWeakDeviceId(self.clone())
834        }
835    }
836
837    impl DeviceIdentifier for FakeMatcherDeviceId {
838        fn is_loopback(&self) -> bool {
839            false
840        }
841    }
842
843    impl FakeStrongDeviceId for FakeMatcherDeviceId {
844        fn is_alive(&self) -> bool {
845            true
846        }
847    }
848
849    impl PartialEq<FakeWeakDeviceId<FakeMatcherDeviceId>> for FakeMatcherDeviceId {
850        fn eq(&self, FakeWeakDeviceId(other): &FakeWeakDeviceId<FakeMatcherDeviceId>) -> bool {
851            self == other
852        }
853    }
854
855    impl InterfaceProperties<FakeDeviceClass> for FakeMatcherDeviceId {
856        fn id_matches(&self, id: &NonZeroU64) -> bool {
857            &self.id == id
858        }
859
860        fn name_matches(&self, name: &str) -> bool {
861            &self.name == name
862        }
863
864        fn device_class_matches(&self, class: &FakeDeviceClass) -> bool {
865            &self.class == class
866        }
867    }
868}
869
870#[cfg(test)]
871mod tests {
872    use ip_test_macro::ip_test;
873    use net_types::Witness;
874    use net_types::ip::{Ip, IpVersion, Ipv4, Ipv6};
875    use test_case::test_case;
876
877    use super::*;
878    use crate::testutil::{FakeDeviceClass, FakeMatcherDeviceId, TestIpExt};
879
880    /// Only matches `true`.
881    #[derive(Debug)]
882    struct TrueMatcher;
883
884    impl Matcher<bool> for TrueMatcher {
885        fn matches(&self, actual: &bool) -> bool {
886            *actual
887        }
888    }
889
890    #[test]
891    fn test_optional_matcher_optional_value() {
892        assert!(TrueMatcher.matches(&true));
893        assert!(!TrueMatcher.matches(&false));
894
895        assert!(TrueMatcher.required_matches(Some(&true)));
896        assert!(!TrueMatcher.required_matches(Some(&false)));
897        assert!(!TrueMatcher.required_matches(None));
898
899        assert!(Some(TrueMatcher).matches(&true));
900        assert!(!Some(TrueMatcher).matches(&false));
901        assert!(None::<TrueMatcher>.matches(&true));
902        assert!(None::<TrueMatcher>.matches(&false));
903
904        assert!(Some(TrueMatcher).required_matches(Some(&true)));
905        assert!(!Some(TrueMatcher).required_matches(Some(&false)));
906        assert!(!Some(TrueMatcher).required_matches(None));
907        assert!(None::<TrueMatcher>.required_matches(Some(&true)));
908        assert!(None::<TrueMatcher>.required_matches(Some(&false)));
909        assert!(None::<TrueMatcher>.required_matches(None));
910    }
911
912    #[test_case(
913        InterfaceMatcher::Id(FakeMatcherDeviceId::wlan_interface().id),
914        FakeMatcherDeviceId::wlan_interface() => true
915    )]
916    #[test_case(
917        InterfaceMatcher::Id(FakeMatcherDeviceId::wlan_interface().id),
918        FakeMatcherDeviceId::ethernet_interface() => false
919    )]
920    #[test_case(
921        InterfaceMatcher::Name(FakeMatcherDeviceId::wlan_interface().name),
922        FakeMatcherDeviceId::wlan_interface() => true
923    )]
924    #[test_case(
925        InterfaceMatcher::Name(FakeMatcherDeviceId::wlan_interface().name),
926        FakeMatcherDeviceId::ethernet_interface() => false
927    )]
928    #[test_case(
929        InterfaceMatcher::DeviceClass(FakeDeviceClass::Wlan),
930        FakeMatcherDeviceId::wlan_interface() => true
931    )]
932    #[test_case(
933        InterfaceMatcher::DeviceClass(FakeDeviceClass::Wlan),
934        FakeMatcherDeviceId::ethernet_interface() => false
935    )]
936    fn interface_matcher(
937        matcher: InterfaceMatcher<FakeDeviceClass>,
938        device: FakeMatcherDeviceId,
939    ) -> bool {
940        matcher.matches(&device)
941    }
942
943    #[test_case(BoundInterfaceMatcher::Unbound, None => true)]
944    #[test_case(
945        BoundInterfaceMatcher::Unbound,
946        Some(FakeMatcherDeviceId::wlan_interface()) => false
947    )]
948    #[test_case(
949        BoundInterfaceMatcher::Bound(
950            InterfaceMatcher::Id(FakeMatcherDeviceId::wlan_interface().id)
951        ),
952        None => false
953    )]
954    #[test_case(
955        BoundInterfaceMatcher::Bound(
956            InterfaceMatcher::Id(FakeMatcherDeviceId::wlan_interface().id)
957        ),
958        Some(FakeMatcherDeviceId::wlan_interface()) => true
959    )]
960    #[test_case(
961        BoundInterfaceMatcher::Bound(
962            InterfaceMatcher::Id(FakeMatcherDeviceId::wlan_interface().id)
963        ),
964        Some(FakeMatcherDeviceId::ethernet_interface()) => false
965    )]
966    #[test_case(
967        BoundInterfaceMatcher::Bound(
968            InterfaceMatcher::Name(FakeMatcherDeviceId::wlan_interface().name)
969        ),
970        None => false
971    )]
972    #[test_case(
973        BoundInterfaceMatcher::Bound(
974            InterfaceMatcher::Name(FakeMatcherDeviceId::wlan_interface().name)
975        ),
976        Some(FakeMatcherDeviceId::wlan_interface()) => true
977    )]
978    #[test_case(
979        BoundInterfaceMatcher::Bound(
980            InterfaceMatcher::Name(FakeMatcherDeviceId::wlan_interface().name)
981        ),
982        Some(FakeMatcherDeviceId::ethernet_interface()) => false
983    )]
984    #[test_case(
985        BoundInterfaceMatcher::Bound(
986            InterfaceMatcher::DeviceClass(FakeDeviceClass::Wlan)
987        ),
988        None => false
989    )]
990    #[test_case(
991        BoundInterfaceMatcher::Bound(
992            InterfaceMatcher::DeviceClass(FakeDeviceClass::Wlan)
993        ),
994        Some(FakeMatcherDeviceId::wlan_interface()) => true
995    )]
996    #[test_case(
997        BoundInterfaceMatcher::Bound(
998            InterfaceMatcher::DeviceClass(FakeDeviceClass::Wlan)
999        ),
1000        Some(FakeMatcherDeviceId::ethernet_interface()) => false
1001    )]
1002    fn bound_interface_matcher(
1003        matcher: BoundInterfaceMatcher<FakeDeviceClass>,
1004        device: Option<FakeMatcherDeviceId>,
1005    ) -> bool {
1006        matcher.matches(&device.as_ref())
1007    }
1008
1009    #[ip_test(I)]
1010    fn subnet_matcher<I: Ip + TestIpExt>() {
1011        let matcher = SubnetMatcher(I::TEST_ADDRS.subnet);
1012        assert!(matcher.matches(&I::TEST_ADDRS.local_ip));
1013        assert!(!matcher.matches(&I::get_other_remote_ip_address(1)));
1014    }
1015
1016    #[test_case(MarkMatcher::Unmarked, Mark(None) => true; "unmarked matches none")]
1017    #[test_case(MarkMatcher::Unmarked, Mark(Some(0)) => false; "unmarked does not match some")]
1018    #[test_case(MarkMatcher::Marked {
1019        mask: 1,
1020        start: 0,
1021        end: 0,
1022        invert: false,
1023    }, Mark(None) => false; "marked does not match none")]
1024    #[test_case(MarkMatcher::Marked {
1025        mask: 1,
1026        start: 0,
1027        end: 0,
1028        invert: false,
1029    }, Mark(Some(0)) => true; "marked 0 mask 1 matches 0")]
1030    #[test_case(MarkMatcher::Marked {
1031        mask: 1,
1032        start: 0,
1033        end: 0,
1034        invert: false,
1035    }, Mark(Some(1)) => false; "marked 0 mask 1 does not match 1")]
1036    #[test_case(MarkMatcher::Marked {
1037        mask: 1,
1038        start: 0,
1039        end: 0,
1040        invert: false,
1041    }, Mark(Some(2)) => true; "marked 0 mask 1 matches 2")]
1042    #[test_case(MarkMatcher::Marked {
1043        mask: 1,
1044        start: 0,
1045        end: 0,
1046        invert: false,
1047    }, Mark(Some(3)) => false; "marked 0 mask 1 does not match 3")]
1048    #[test_case(MarkMatcher::Marked {
1049        mask: !0,
1050        start: 0,
1051        end: 10,
1052        invert: true,
1053    }, Mark(Some(5)) => false; "marked invert no match in range")]
1054    #[test_case(MarkMatcher::Marked {
1055        mask: !0,
1056        start: 0,
1057        end: 10,
1058        invert: true,
1059    }, Mark(Some(11)) => true; "marked invert matches out of range")]
1060    fn mark_matcher(matcher: MarkMatcher, mark: Mark) -> bool {
1061        matcher.matches(&mark)
1062    }
1063
1064    #[test_case(
1065        MarkMatchers::new(
1066            [(MarkDomain::Mark1, MarkMatcher::Unmarked),
1067            (MarkDomain::Mark2, MarkMatcher::Unmarked)]
1068        ),
1069        Marks::new([]) => true;
1070        "all unmarked matches empty"
1071    )]
1072    #[test_case(
1073        MarkMatchers::new(
1074            [(MarkDomain::Mark1, MarkMatcher::Unmarked),
1075            (MarkDomain::Mark2, MarkMatcher::Unmarked)]
1076        ),
1077        Marks::new([(MarkDomain::Mark1, 1)]) => false;
1078        "all unmarked does not match mark1"
1079    )]
1080    #[test_case(
1081        MarkMatchers::new(
1082            [(MarkDomain::Mark1, MarkMatcher::Unmarked),
1083            (MarkDomain::Mark2, MarkMatcher::Unmarked)]
1084        ),
1085        Marks::new([(MarkDomain::Mark2, 1)]) => false;
1086        "all unmarked does not match mark2"
1087    )]
1088    #[test_case(
1089        MarkMatchers::new(
1090            [(MarkDomain::Mark1, MarkMatcher::Unmarked),
1091            (MarkDomain::Mark2, MarkMatcher::Unmarked)]
1092        ),
1093        Marks::new([
1094            (MarkDomain::Mark1, 1),
1095            (MarkDomain::Mark2, 1),
1096        ]) => false;
1097        "all unmarked does not match mark1 and mark2"
1098    )]
1099    #[test_case(
1100        MarkMatchers::new(
1101            [(MarkDomain::Mark1, MarkMatcher::Marked { mask: !0, start: 1, end: 1, invert: false }),
1102            (MarkDomain::Mark2, MarkMatcher::Unmarked)]
1103        ),
1104        Marks::new([(MarkDomain::Mark1, 1)]) => true;
1105        "mark1 marked matches"
1106    )]
1107    #[test_case(
1108        MarkMatchers::new(
1109            [(MarkDomain::Mark1, MarkMatcher::Marked { mask: !0, start: 1, end: 1, invert: false }),
1110            (MarkDomain::Mark2, MarkMatcher::Unmarked)]
1111        ),
1112        Marks::new([(MarkDomain::Mark1, 2)]) => false;
1113        "mark1 marked no match"
1114    )]
1115    #[test_case(
1116        MarkMatchers::new(
1117            [(MarkDomain::Mark1, MarkMatcher::Marked { mask: !0, start: 1, end: 1, invert: false }),
1118            (MarkDomain::Mark2, MarkMatcher::Marked { mask: !0, start: 2, end: 2, invert: false })]
1119        ),
1120        Marks::new([(MarkDomain::Mark1, 1), (MarkDomain::Mark2, 2)]) => true;
1121        "all marked matches"
1122    )]
1123    #[test_case(
1124        MarkMatchers::new(
1125            [(MarkDomain::Mark1, MarkMatcher::Marked { mask: !0, start: 1, end: 1, invert: false }),
1126            (MarkDomain::Mark2, MarkMatcher::Marked { mask: !0, start: 2, end: 2, invert: false })]
1127        ),
1128        Marks::new([(MarkDomain::Mark1, 1), (MarkDomain::Mark2, 3)]) => false;
1129        "all marked no match mark2"
1130    )]
1131    fn mark_matchers(matchers: MarkMatchers, marks: Marks) -> bool {
1132        matchers.matches(&marks)
1133    }
1134
1135    #[test_case(SocketCookieMatcher { cookie: 123, invert: false }, 123 => true)]
1136    #[test_case(SocketCookieMatcher { cookie: 123, invert: false }, 456 => false)]
1137    #[test_case(SocketCookieMatcher { cookie: 123, invert: true }, 123 => false)]
1138    #[test_case(SocketCookieMatcher { cookie: 123, invert: true }, 456 => true)]
1139    fn socket_cookie_matcher(matcher: SocketCookieMatcher, actual: u64) -> bool {
1140        matcher.matches(&actual)
1141    }
1142
1143    #[test_case(PortMatcher { range: 10..=20, invert: false }, 9 => false)]
1144    #[test_case(PortMatcher { range: 10..=20, invert: false }, 10 => true)]
1145    #[test_case(PortMatcher { range: 10..=20, invert: false }, 15 => true)]
1146    #[test_case(PortMatcher { range: 10..=20, invert: false }, 20 => true)]
1147    #[test_case(PortMatcher { range: 10..=20, invert: false }, 21 => false)]
1148    #[test_case(PortMatcher { range: 10..=20, invert: true }, 9 => true)]
1149    #[test_case(PortMatcher { range: 10..=20, invert: true }, 10 => false)]
1150    #[test_case(PortMatcher { range: 10..=20, invert: true }, 15 => false)]
1151    #[test_case(PortMatcher { range: 10..=20, invert: true }, 20 => false)]
1152    #[test_case(PortMatcher { range: 10..=20, invert: true }, 21 => true)]
1153    fn port_matcher(matcher: PortMatcher, actual: u16) -> bool {
1154        matcher.matches(&actual)
1155    }
1156
1157    #[test_case(BoundPortMatcher::Unbound, None => true)]
1158    #[test_case(BoundPortMatcher::Unbound, Some(80) => false)]
1159    #[test_case(
1160        BoundPortMatcher::Bound(PortMatcher { range: 10..=20, invert: false }),
1161        None => false
1162    )]
1163    #[test_case(
1164        BoundPortMatcher::Bound(PortMatcher { range: 10..=20, invert: false }),
1165        Some(10) => true
1166    )]
1167    #[test_case(
1168        BoundPortMatcher::Bound(PortMatcher { range: 10..=20, invert: false }),
1169        Some(9) => false
1170    )]
1171    fn bound_port_matcher(matcher: BoundPortMatcher, actual: Option<u16>) -> bool {
1172        matcher.matches(&actual)
1173    }
1174
1175    struct FakeTcpSocket {
1176        src_port: Option<u16>,
1177        dst_port: Option<u16>,
1178        state: TcpSocketState,
1179    }
1180
1181    impl MaybeSocketTransportProperties for FakeTcpSocket {
1182        type TcpProps<'a>
1183            = Self
1184        where
1185            Self: 'a;
1186
1187        type UdpProps<'a>
1188            = !
1189        where
1190            Self: 'a;
1191
1192        fn tcp_socket_properties(&self) -> Option<&Self::TcpProps<'_>> {
1193            Some(self)
1194        }
1195
1196        fn udp_socket_properties(&self) -> Option<&Self::UdpProps<'_>> {
1197            None
1198        }
1199    }
1200
1201    impl TcpSocketProperties for FakeTcpSocket {
1202        fn src_port_matches(&self, matcher: &BoundPortMatcher) -> bool {
1203            matcher.matches(&self.src_port)
1204        }
1205
1206        fn dst_port_matches(&self, matcher: &BoundPortMatcher) -> bool {
1207            matcher.matches(&self.dst_port)
1208        }
1209
1210        fn state_matches(&self, matcher: &TcpStateMatcher) -> bool {
1211            matcher.matches(&self.state)
1212        }
1213    }
1214
1215    struct FakeUdpSocket {
1216        src_port: Option<u16>,
1217        dst_port: Option<u16>,
1218        state: UdpSocketState,
1219    }
1220
1221    impl MaybeSocketTransportProperties for FakeUdpSocket {
1222        type TcpProps<'a>
1223            = !
1224        where
1225            Self: 'a;
1226
1227        type UdpProps<'a>
1228            = Self
1229        where
1230            Self: 'a;
1231
1232        fn tcp_socket_properties(&self) -> Option<&Self::TcpProps<'_>> {
1233            None
1234        }
1235
1236        fn udp_socket_properties(&self) -> Option<&Self::UdpProps<'_>> {
1237            Some(self)
1238        }
1239    }
1240
1241    impl UdpSocketProperties for FakeUdpSocket {
1242        fn src_port_matches(&self, matcher: &BoundPortMatcher) -> bool {
1243            matcher.matches(&self.src_port)
1244        }
1245
1246        fn dst_port_matches(&self, matcher: &BoundPortMatcher) -> bool {
1247            matcher.matches(&self.dst_port)
1248        }
1249
1250        fn state_matches(&self, matcher: &UdpStateMatcher) -> bool {
1251            matcher.matches(&self.state)
1252        }
1253    }
1254
1255    struct FakeIpSocket<I, T>
1256    where
1257        I: TestIpExt,
1258        T: MaybeSocketTransportProperties,
1259    {
1260        src_ip: Option<I::Addr>,
1261        dst_ip: Option<I::Addr>,
1262        proto: T,
1263        intf: Option<FakeMatcherDeviceId>,
1264        cookie: u64,
1265        marks: Marks,
1266    }
1267
1268    impl<I, T> MaybeSocketTransportProperties for FakeIpSocket<I, T>
1269    where
1270        I: TestIpExt,
1271        T: MaybeSocketTransportProperties,
1272    {
1273        type TcpProps<'a>
1274            = T::TcpProps<'a>
1275        where
1276            Self: 'a;
1277
1278        type UdpProps<'a>
1279            = T::UdpProps<'a>
1280        where
1281            Self: 'a;
1282
1283        fn tcp_socket_properties(&self) -> Option<&Self::TcpProps<'_>> {
1284            self.proto.tcp_socket_properties()
1285        }
1286
1287        fn udp_socket_properties(&self) -> Option<&Self::UdpProps<'_>> {
1288            self.proto.udp_socket_properties()
1289        }
1290    }
1291
1292    impl<I, T> IpSocketProperties<FakeDeviceClass> for FakeIpSocket<I, T>
1293    where
1294        I: TestIpExt,
1295        T: MaybeSocketTransportProperties,
1296    {
1297        fn family_matches(&self, family: &net_types::ip::IpVersion) -> bool {
1298            *family == I::VERSION
1299        }
1300
1301        fn src_addr_matches(&self, addr: &BoundAddressMatcherEither) -> bool {
1302            addr.matches(&self.src_ip.map(|a| a.into()))
1303        }
1304
1305        fn dst_addr_matches(&self, addr: &BoundAddressMatcherEither) -> bool {
1306            addr.matches(&self.dst_ip.map(|a| a.into()))
1307        }
1308
1309        fn transport_protocol_matches(&self, matcher: &SocketTransportProtocolMatcher) -> bool {
1310            matcher.matches(self)
1311        }
1312
1313        fn bound_interface_matches(&self, iface: &BoundInterfaceMatcher<FakeDeviceClass>) -> bool {
1314            iface.matches(&self.intf.as_ref())
1315        }
1316
1317        fn cookie_matches(&self, cookie: &SocketCookieMatcher) -> bool {
1318            cookie.matches(&self.cookie)
1319        }
1320
1321        fn mark_matches(&self, matcher: &MarkInDomainMatcher) -> bool {
1322            matcher.matcher.matches(self.marks.get(matcher.domain))
1323        }
1324    }
1325
1326    #[test_case(
1327        TcpSocketMatcher::Empty,
1328        FakeTcpSocket {
1329            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1330        } => true;
1331        "empty matcher"
1332    )]
1333    #[test_case(
1334        TcpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1335            PortMatcher { range: 80..=80, invert: false }
1336        )),
1337        FakeTcpSocket {
1338            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1339        } => true;
1340        "src_port match"
1341    )]
1342    #[test_case(
1343        TcpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1344            PortMatcher { range: 80..=80, invert: false }
1345        )),
1346        FakeTcpSocket {
1347            src_port: Some(81), dst_port: Some(12345), state: TcpSocketState::Established
1348        } => false;
1349        "src_port no match"
1350    )]
1351    #[test_case(
1352        TcpSocketMatcher::SrcPort(BoundPortMatcher::Bound(PortMatcher {
1353            range: 80..=80, invert: true
1354        })),
1355        FakeTcpSocket {
1356            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1357        } => false;
1358        "src_port invert no match"
1359    )]
1360    #[test_case(
1361        TcpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1362            PortMatcher { range: 80..=80, invert: true }
1363        )),
1364        FakeTcpSocket {
1365            src_port: Some(81), dst_port: Some(12345), state: TcpSocketState::Established
1366        } => true;
1367        "src_port invert match"
1368    )]
1369    #[test_case(
1370        TcpSocketMatcher::DstPort(BoundPortMatcher::Bound(
1371            PortMatcher {range: 12345..=12345, invert: false }
1372        )),
1373        FakeTcpSocket {
1374            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1375        } => true;
1376        "dst_port match"
1377    )]
1378    #[test_case(
1379        TcpSocketMatcher::DstPort(BoundPortMatcher::Bound(
1380            PortMatcher { range: 12345..=12345, invert: false }
1381        )),
1382        FakeTcpSocket {
1383            src_port: Some(80), dst_port: Some(12346), state: TcpSocketState::Established
1384        } => false;
1385        "dst_port no match"
1386    )]
1387    #[test_case(
1388        TcpSocketMatcher::State(TcpStateMatcher::ESTABLISHED),
1389        FakeTcpSocket {
1390            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1391        } => true;
1392        "state match"
1393    )]
1394    #[test_case(
1395        TcpSocketMatcher::State(TcpStateMatcher::SYN_SENT),
1396        FakeTcpSocket {
1397            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1398        } => false;
1399        "state no match"
1400    )]
1401    #[test_case(
1402        TcpSocketMatcher::State(TcpStateMatcher::ESTABLISHED | TcpStateMatcher::SYN_SENT),
1403        FakeTcpSocket {
1404            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1405        } => true;
1406        "state multi match established"
1407    )]
1408    #[test_case(
1409        TcpSocketMatcher::State(TcpStateMatcher::ESTABLISHED | TcpStateMatcher::SYN_SENT),
1410        FakeTcpSocket {
1411            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::SynSent
1412        } => true;
1413        "state multi match syn_sent"
1414    )]
1415    #[test_case(
1416        TcpSocketMatcher::State(TcpStateMatcher::ESTABLISHED | TcpStateMatcher::SYN_SENT),
1417        FakeTcpSocket {
1418            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::FinWait1
1419        } => false;
1420        "state multi no match"
1421    )]
1422    #[test_case(
1423        TcpSocketMatcher::SrcPort(BoundPortMatcher::Unbound),
1424        FakeTcpSocket {
1425            src_port: None, dst_port: Some(12345), state: TcpSocketState::Established
1426        } => true;
1427        "src_port unbound match"
1428    )]
1429    #[test_case(
1430        TcpSocketMatcher::SrcPort(BoundPortMatcher::Unbound),
1431        FakeTcpSocket {
1432            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1433        } => false;
1434        "src_port unbound no match"
1435    )]
1436    #[test_case(
1437        TcpSocketMatcher::DstPort(BoundPortMatcher::Unbound),
1438        FakeTcpSocket {
1439            src_port: Some(80), dst_port: None, state: TcpSocketState::Established
1440        } => true;
1441        "dst_port unbound match"
1442    )]
1443    #[test_case(
1444        TcpSocketMatcher::DstPort(BoundPortMatcher::Unbound),
1445        FakeTcpSocket {
1446            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1447        } => false;
1448        "dst_port unbound no match"
1449    )]
1450    fn tcp_socket_matcher(matcher: TcpSocketMatcher, socket: FakeTcpSocket) -> bool {
1451        matcher.matches(&socket)
1452    }
1453
1454    #[test_case(
1455        UdpSocketMatcher::Empty,
1456        FakeUdpSocket {
1457            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Bound
1458        } => true;
1459        "empty matcher"
1460    )]
1461    #[test_case(
1462        UdpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1463            PortMatcher { range: 53..=53, invert: false }
1464        )),
1465        FakeUdpSocket {
1466            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Bound
1467        } => true;
1468        "src_port match"
1469    )]
1470    #[test_case(
1471        UdpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1472            PortMatcher { range: 53..=53, invert: false }
1473        )),
1474        FakeUdpSocket {
1475            src_port: Some(54), dst_port: Some(12345), state: UdpSocketState::Bound
1476        } => false;
1477        "src_port no match"
1478    )]
1479    #[test_case(
1480        UdpSocketMatcher::DstPort(BoundPortMatcher::Bound(
1481            PortMatcher { range: 12345..=12345, invert: false }
1482        )),
1483        FakeUdpSocket {
1484            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Bound
1485         } => true;
1486        "dst_port match"
1487    )]
1488    #[test_case(
1489        UdpSocketMatcher::DstPort(BoundPortMatcher::Bound(
1490            PortMatcher { range: 12345..=12345, invert: false }
1491        )),
1492        FakeUdpSocket {
1493            src_port: Some(53), dst_port: Some(12346), state: UdpSocketState::Bound
1494        } => false;
1495        "dst_port no match"
1496    )]
1497    #[test_case(
1498        UdpSocketMatcher::State(UdpStateMatcher::BOUND),
1499        FakeUdpSocket {
1500            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Bound
1501         } => true;
1502        "state match bound"
1503    )]
1504    #[test_case(
1505        UdpSocketMatcher::State(UdpStateMatcher::CONNECTED),
1506        FakeUdpSocket {
1507            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Bound
1508        } => false;
1509        "state no match connected"
1510    )]
1511    #[test_case(
1512        UdpSocketMatcher::State(UdpStateMatcher::BOUND | UdpStateMatcher::CONNECTED),
1513        FakeUdpSocket {
1514            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Bound
1515         } => true;
1516        "state multi match bound"
1517    )]
1518    #[test_case(
1519        UdpSocketMatcher::State(UdpStateMatcher::BOUND | UdpStateMatcher::CONNECTED),
1520        FakeUdpSocket {
1521            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Connected
1522         } => true;
1523        "state multi match connected"
1524    )]
1525    #[test_case(
1526        UdpSocketMatcher::SrcPort(BoundPortMatcher::Unbound),
1527        FakeUdpSocket {
1528            src_port: None, dst_port: Some(12345), state: UdpSocketState::Bound
1529         } => true;
1530        "src_port unbound match"
1531    )]
1532    #[test_case(
1533        UdpSocketMatcher::SrcPort(BoundPortMatcher::Unbound),
1534        FakeUdpSocket {
1535            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Bound
1536        } => false;
1537        "src_port unbound no match"
1538    )]
1539    #[test_case(
1540        UdpSocketMatcher::DstPort(BoundPortMatcher::Unbound),
1541        FakeUdpSocket { src_port: Some(53), dst_port: None, state: UdpSocketState::Bound } => true;
1542        "dst_port unbound match"
1543    )]
1544    #[test_case(
1545        UdpSocketMatcher::DstPort(BoundPortMatcher::Unbound),
1546        FakeUdpSocket {
1547            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Bound
1548        } => false;
1549        "dst_port unbound no match"
1550    )]
1551    fn udp_socket_matcher(matcher: UdpSocketMatcher, socket: FakeUdpSocket) -> bool {
1552        matcher.matches(&socket)
1553    }
1554
1555    #[ip_test(I)]
1556    #[test_case(
1557        IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(TcpSocketMatcher::Empty)),
1558        FakeIpSocket {
1559            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1560            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1561            proto: FakeTcpSocket {
1562                src_port: Some(80),
1563                dst_port: Some(12345),
1564                state: TcpSocketState::Established,
1565            },
1566            cookie: 0,
1567            intf: None,
1568            marks: Marks::default(),
1569        } => true;
1570        "tcpm empty"
1571    )]
1572    #[test_case(
1573        IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(TcpSocketMatcher::Empty)),
1574        FakeIpSocket {
1575            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1576            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1577            proto: FakeUdpSocket {
1578                src_port: Some(53),
1579                dst_port: Some(12345),
1580                state: UdpSocketState::Bound,
1581            },
1582            cookie: 0,
1583            intf: None,
1584            marks: Marks::default(),
1585        } => false;
1586        "tcp empty no match udp"
1587    )]
1588    #[test_case(
1589        IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Udp(UdpSocketMatcher::Empty)),
1590        FakeIpSocket {
1591            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1592            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1593            proto: FakeTcpSocket {
1594                src_port: Some(80),
1595                dst_port: Some(12345),
1596                state: TcpSocketState::Established
1597            },
1598            cookie: 0,
1599            intf: None,
1600            marks: Marks::default(),
1601        } => false;
1602        "udp empty no match tcp"
1603    )]
1604    #[test_case(
1605        IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Udp(UdpSocketMatcher::Empty)),
1606        FakeIpSocket {
1607            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1608            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1609            proto: FakeUdpSocket {
1610                src_port: Some(53),
1611                dst_port: Some(12345),
1612                state: UdpSocketState::Bound,
1613            },
1614            cookie: 0,
1615            intf: None,
1616            marks: Marks::default(),
1617        } => true;
1618        "udp empty"
1619    )]
1620    #[test_case(
1621        IpSocketMatcher::Proto(
1622            SocketTransportProtocolMatcher::Tcp(
1623                TcpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1624                    PortMatcher { range: 80..=80, invert: false }
1625                ))
1626            )
1627        ),
1628        FakeIpSocket {
1629            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1630            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1631            proto: FakeTcpSocket {
1632                src_port: Some(80),
1633                dst_port: Some(12345),
1634                state: TcpSocketState::Established,
1635            },
1636            cookie: 0,
1637            intf: None,
1638            marks: Marks::default(),
1639        } => true;
1640        "tcp src_port match"
1641    )]
1642    #[test_case(
1643        IpSocketMatcher::Proto(
1644            SocketTransportProtocolMatcher::Tcp(
1645                TcpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1646                    PortMatcher { range: 80..=80, invert: false }
1647                ))
1648            )
1649        ),
1650        FakeIpSocket {
1651            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1652            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1653            proto: FakeTcpSocket {
1654                src_port: Some(81),
1655                dst_port: Some(12345),
1656                state: TcpSocketState::Established,
1657            },
1658            cookie: 0,
1659            intf: None,
1660            marks: Marks::default(),
1661        } => false;
1662        "tcp src_port no match"
1663    )]
1664    #[test_case(
1665        IpSocketMatcher::Proto(
1666            SocketTransportProtocolMatcher::Udp(
1667                UdpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1668                    PortMatcher { range: 53..=53, invert: false }
1669                ))
1670            )
1671        ),
1672        FakeIpSocket {
1673            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1674            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1675            proto: FakeUdpSocket {
1676                src_port: Some(53),
1677                dst_port: Some(12345),
1678                state: UdpSocketState::Bound,
1679            },
1680            cookie: 0,
1681            intf: None,
1682            marks: Marks::default(),
1683        } => true;
1684        "udp src_port match"
1685    )]
1686    #[test_case(
1687        IpSocketMatcher::Proto(
1688            SocketTransportProtocolMatcher::Udp(
1689                UdpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1690                    PortMatcher { range: 53..=53, invert: false }
1691                ))
1692            )
1693        ),
1694        FakeIpSocket {
1695            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1696            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1697            proto: FakeUdpSocket {
1698                src_port: Some(54),
1699                dst_port: Some(12345),
1700                state: UdpSocketState::Bound,
1701            },
1702            cookie: 0,
1703            intf: None,
1704            marks: Marks::default(),
1705        } => false;
1706        "udp src_port no match"
1707    )]
1708    #[test_case(
1709        IpSocketMatcher::Cookie(SocketCookieMatcher { cookie: 123, invert: false }),
1710        FakeIpSocket {
1711            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1712            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1713            proto: FakeTcpSocket {
1714                src_port: Some(80),
1715                dst_port: Some(12345),
1716                state: TcpSocketState::Established,
1717            },
1718            cookie: 123,
1719            intf: None,
1720            marks: Marks::default(),
1721        } => true;
1722        "cookie match"
1723    )]
1724    #[test_case(
1725        IpSocketMatcher::Cookie(SocketCookieMatcher { cookie: 123, invert: false }),
1726        FakeIpSocket {
1727            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1728            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1729            proto: FakeTcpSocket {
1730                src_port: Some(80),
1731                dst_port: Some(12345),
1732                state: TcpSocketState::Established,
1733            },
1734            cookie: 456,
1735            intf: None,
1736            marks: Marks::default(),
1737        } => false;
1738        "cookie no match"
1739    )]
1740    #[test_case(
1741        IpSocketMatcher::Mark(MarkInDomainMatcher {
1742            domain: MarkDomain::Mark1,
1743            matcher: MarkMatcher::Unmarked,
1744        }),
1745        FakeIpSocket {
1746            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1747            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1748            proto: FakeTcpSocket {
1749                src_port: Some(80),
1750                dst_port: Some(12345),
1751                state: TcpSocketState::Established,
1752            },
1753            cookie: 0,
1754            intf: None,
1755            marks: Marks::default(),
1756        } => true;
1757        "mark1 unmarked match"
1758    )]
1759    #[test_case(
1760        IpSocketMatcher::Mark(MarkInDomainMatcher {
1761            domain: MarkDomain::Mark1,
1762            matcher: MarkMatcher::Unmarked,
1763        }),
1764        FakeIpSocket {
1765            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1766            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1767            proto: FakeTcpSocket {
1768                src_port: Some(80),
1769                dst_port: Some(12345),
1770                state: TcpSocketState::Established,
1771            },
1772            cookie: 0,
1773            intf: None,
1774            marks: Marks::new([(MarkDomain::Mark1, 1)]),
1775        } => false;
1776        "mark1 unmarked no match"
1777    )]
1778    #[test_case(
1779        IpSocketMatcher::Mark(MarkInDomainMatcher {
1780            domain: MarkDomain::Mark2,
1781            matcher: MarkMatcher::Unmarked,
1782        }),
1783        FakeIpSocket {
1784            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1785            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1786            proto: FakeTcpSocket {
1787                src_port: Some(80),
1788                dst_port: Some(12345),
1789                state: TcpSocketState::Established,
1790            },
1791            cookie: 0,
1792            intf: None,
1793            marks: Marks::default(),
1794        } => true;
1795        "mark2 unmarked match"
1796    )]
1797    #[test_case(
1798        IpSocketMatcher::Mark(MarkInDomainMatcher {
1799            domain: MarkDomain::Mark2,
1800            matcher: MarkMatcher::Unmarked,
1801        }),
1802        FakeIpSocket {
1803            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1804            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1805            proto: FakeTcpSocket {
1806                src_port: Some(80),
1807                dst_port: Some(12345),
1808                state: TcpSocketState::Established,
1809            },
1810            cookie: 0,
1811            intf: None,
1812            marks: Marks::new([(MarkDomain::Mark2, 1)]),
1813        } => false;
1814        "mark2 unmarked no match"
1815    )]
1816    #[test_case(
1817        IpSocketMatcher::BoundInterface(BoundInterfaceMatcher::Bound(
1818            InterfaceMatcher::Id(FakeMatcherDeviceId::wlan_interface().id)
1819        )),
1820        FakeIpSocket {
1821            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1822            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1823            proto: FakeTcpSocket {
1824                src_port: Some(80),
1825                dst_port: Some(12345),
1826                state: TcpSocketState::Established,
1827            },
1828            cookie: 0,
1829            intf: Some(FakeMatcherDeviceId::wlan_interface()),
1830            marks: Marks::default(),
1831        } => true;
1832        "bound_interface match"
1833    )]
1834    #[test_case(
1835        IpSocketMatcher::BoundInterface(BoundInterfaceMatcher::Bound(
1836            InterfaceMatcher::Id(FakeMatcherDeviceId::wlan_interface().id)
1837        )),
1838        FakeIpSocket {
1839            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1840            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1841            proto: FakeTcpSocket {
1842                src_port: Some(80),
1843                dst_port: Some(12345),
1844                state: TcpSocketState::Established,
1845            },
1846            cookie: 0,
1847            intf: Some(FakeMatcherDeviceId::ethernet_interface()),
1848            marks: Marks::default(),
1849        } => false;
1850        "bound_interface no match"
1851    )]
1852    #[test_case(
1853        IpSocketMatcher::BoundInterface(BoundInterfaceMatcher::Unbound),
1854        FakeIpSocket {
1855            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1856            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1857            proto: FakeTcpSocket {
1858                src_port: Some(80),
1859                dst_port: Some(12345),
1860                state: TcpSocketState::Established,
1861            },
1862            cookie: 0,
1863            intf: None,
1864            marks: Marks::default(),
1865        } => true;
1866        "bound_interface unbound match"
1867    )]
1868    #[test_case(
1869        IpSocketMatcher::BoundInterface(BoundInterfaceMatcher::Unbound),
1870        FakeIpSocket {
1871            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1872            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1873            proto: FakeTcpSocket {
1874                src_port: Some(80),
1875                dst_port: Some(12345),
1876                state: TcpSocketState::Established,
1877            },
1878            cookie: 0,
1879            intf: Some(FakeMatcherDeviceId::wlan_interface()),
1880            marks: Marks::default(),
1881        } => false;
1882        "bound_interface unbound no match"
1883    )]
1884    fn ip_socket_matcher<I: TestIpExt, T: MaybeSocketTransportProperties>(
1885        matcher: IpSocketMatcher<FakeDeviceClass>,
1886        socket: FakeIpSocket<I, T>,
1887    ) -> bool {
1888        matcher.matches(&socket)
1889    }
1890
1891    #[ip_test(I)]
1892    fn address_matcher_type<I: TestIpExt>() {
1893        let local_ip = I::TEST_ADDRS.local_ip.get();
1894        let remote_ip = I::TEST_ADDRS.remote_ip.get();
1895
1896        let matcher = AddressMatcherType::Subnet(SubnetMatcher(I::TEST_ADDRS.subnet));
1897        assert!(matcher.matches(&local_ip));
1898        assert!(!matcher.matches(&I::get_other_remote_ip_address(1)));
1899
1900        let matcher = AddressMatcherType::Range(local_ip..=remote_ip);
1901        assert!(matcher.matches(&local_ip));
1902        assert!(matcher.matches(&remote_ip));
1903        assert!(!matcher.matches(&I::get_other_remote_ip_address(1)));
1904    }
1905
1906    #[ip_test(I)]
1907    fn address_matcher<I: TestIpExt>() {
1908        let local_ip = I::TEST_ADDRS.local_ip.get();
1909        let remote_ip = I::TEST_ADDRS.remote_ip.get();
1910
1911        let matcher = AddressMatcher {
1912            matcher: AddressMatcherType::Subnet(SubnetMatcher(I::TEST_ADDRS.subnet)),
1913            invert: false,
1914        };
1915        assert!(matcher.matches(&local_ip));
1916        assert!(matcher.matches(&remote_ip));
1917        assert!(!matcher.matches(&I::get_other_remote_ip_address(1)));
1918
1919        let matcher = AddressMatcher {
1920            matcher: AddressMatcherType::Subnet(SubnetMatcher(I::TEST_ADDRS.subnet)),
1921            invert: true,
1922        };
1923        assert!(!matcher.matches(&local_ip));
1924        assert!(!matcher.matches(&remote_ip));
1925        assert!(matcher.matches(&I::get_other_remote_ip_address(1)));
1926
1927        let matcher = AddressMatcher {
1928            matcher: AddressMatcherType::Range(local_ip..=remote_ip),
1929            invert: false,
1930        };
1931        assert!(matcher.matches(&local_ip));
1932        assert!(matcher.matches(&remote_ip));
1933        assert!(!matcher.matches(&I::get_other_remote_ip_address(1)));
1934
1935        let matcher = AddressMatcher {
1936            matcher: AddressMatcherType::Range(local_ip..=remote_ip),
1937            invert: true,
1938        };
1939        assert!(!matcher.matches(&local_ip));
1940        assert!(!matcher.matches(&remote_ip));
1941        assert!(matcher.matches(&I::get_other_remote_ip_address(1)));
1942    }
1943
1944    #[test]
1945    fn agnostic_address_matcher() {
1946        let v4_addr = IpAddr::V4(Ipv4Addr::new([192, 0, 2, 1]));
1947        let v6_addr = IpAddr::V6(Ipv6Addr::new([0x2001, 0xdb8, 0, 0, 0, 0, 0, 1]));
1948
1949        let v4_subnet = Subnet::new(Ipv4Addr::new([192, 0, 2, 0]), 24).unwrap();
1950        let v6_subnet = Subnet::new(Ipv6Addr::new([0x2001, 0xdb8, 0, 0, 0, 0, 0, 0]), 32).unwrap();
1951
1952        let v4_matcher =
1953            BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(AddressMatcher {
1954                matcher: AddressMatcherType::Subnet(SubnetMatcher(v4_subnet)),
1955                invert: false,
1956            }));
1957        assert!(v4_matcher.matches(&Some(v4_addr)));
1958        assert!(!v4_matcher.matches(&Some(v6_addr)));
1959
1960        let v6_matcher =
1961            BoundAddressMatcherEither::Bound(AddressMatcherEither::V6(AddressMatcher {
1962                matcher: AddressMatcherType::Subnet(SubnetMatcher(v6_subnet)),
1963                invert: false,
1964            }));
1965        assert!(!v6_matcher.matches(&Some(v4_addr)));
1966        assert!(v6_matcher.matches(&Some(v6_addr)));
1967    }
1968
1969    #[test_case(IpSocketMatcher::Family(IpVersion::V4) => true; "v4 family matcher on v4 socket")]
1970    #[test_case(IpSocketMatcher::Family(IpVersion::V6) => false; "v6 family matcher on v4 socket")]
1971    #[test_case(IpSocketMatcher::SrcAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(
1972        AddressMatcher {
1973            matcher: AddressMatcherType::Subnet(SubnetMatcher(Ipv4::TEST_ADDRS.subnet)),
1974            invert: false,
1975        }
1976    ))) => true; "src_addr match")]
1977    #[test_case(IpSocketMatcher::SrcAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(
1978        AddressMatcher {
1979            matcher: AddressMatcherType::Subnet(SubnetMatcher(
1980                Subnet::new(Ipv4Addr::new([0, 0, 0, 0]), 32).unwrap()
1981            )),
1982            invert: false,
1983        }
1984    ))) => false; "src_addr no match")]
1985    #[test_case(IpSocketMatcher::DstAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(
1986        AddressMatcher {
1987            matcher: AddressMatcherType::Subnet(SubnetMatcher(Ipv4::TEST_ADDRS.subnet)),
1988            invert: false,
1989        }
1990    ))) => true; "dst_addr match")]
1991    #[test_case(IpSocketMatcher::DstAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(
1992        AddressMatcher {
1993            matcher: AddressMatcherType::Subnet(SubnetMatcher(
1994                Subnet::new(Ipv4Addr::new([0, 0, 0, 0]), 32).unwrap()
1995            )),
1996        invert: false,
1997    }))) => false; "dst_addr no match")]
1998    #[test_case(
1999        IpSocketMatcher::SrcAddr(BoundAddressMatcherEither::Unbound) => false;
2000        "src_addr unbound mismatch"
2001    )]
2002    #[test_case(
2003        IpSocketMatcher::DstAddr(BoundAddressMatcherEither::Unbound) => false;
2004        "dst_addr unbound mismatch"
2005    )]
2006    fn ip_socket_matcher_test_v4(matcher: IpSocketMatcher<FakeDeviceClass>) -> bool {
2007        let socket = FakeIpSocket::<Ipv4, _> {
2008            src_ip: Some(<Ipv4 as TestIpExt>::TEST_ADDRS.local_ip.get()),
2009            dst_ip: Some(<Ipv4 as TestIpExt>::TEST_ADDRS.remote_ip.get()),
2010            proto: FakeTcpSocket {
2011                src_port: Some(80),
2012                dst_port: Some(12345),
2013                state: TcpSocketState::Established,
2014            },
2015            cookie: 0,
2016            intf: None,
2017            marks: Marks::default(),
2018        };
2019        matcher.matches(&socket)
2020    }
2021
2022    #[test_case(IpSocketMatcher::Family(IpVersion::V4) => false; "v4 family matcher on v6 socket")]
2023    #[test_case(IpSocketMatcher::Family(IpVersion::V6) => true; "v6 family matcher on v6 socket")]
2024    #[test_case(IpSocketMatcher::SrcAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V6(
2025        AddressMatcher {
2026            matcher: AddressMatcherType::Subnet(SubnetMatcher(Ipv6::TEST_ADDRS.subnet)),
2027            invert: false,
2028        }
2029    ))) => true; "src_addr match v6")]
2030    #[test_case(IpSocketMatcher::SrcAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V6(
2031        AddressMatcher {
2032            matcher: AddressMatcherType::Subnet(SubnetMatcher(
2033                Subnet::new(Ipv6Addr::new([0; 8]), 128).unwrap()
2034            )),
2035            invert: false,
2036        }
2037    ))) => false; "src_addr no match v6")]
2038    #[test_case(IpSocketMatcher::DstAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V6(
2039        AddressMatcher {
2040            matcher: AddressMatcherType::Subnet(SubnetMatcher(Ipv6::TEST_ADDRS.subnet)),
2041            invert: false,
2042        }
2043    ))) => true; "dst_addr match v6")]
2044    #[test_case(IpSocketMatcher::DstAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V6(
2045        AddressMatcher {
2046            matcher: AddressMatcherType::Subnet(SubnetMatcher(
2047                Subnet::new(Ipv6Addr::new([0; 8]), 128).unwrap()
2048            )),
2049            invert: false,
2050        }
2051    ))) => false; "dst_addr no match v6")]
2052    fn ip_socket_matcher_test_v6(matcher: IpSocketMatcher<FakeDeviceClass>) -> bool {
2053        let socket = FakeIpSocket::<Ipv6, _> {
2054            src_ip: Some(<Ipv6 as TestIpExt>::TEST_ADDRS.local_ip.get()),
2055            dst_ip: Some(<Ipv6 as TestIpExt>::TEST_ADDRS.remote_ip.get()),
2056            proto: FakeTcpSocket {
2057                src_port: Some(80),
2058                dst_port: Some(12345),
2059                state: TcpSocketState::Established,
2060            },
2061            cookie: 0,
2062            intf: None,
2063            marks: Marks::default(),
2064        };
2065        matcher.matches(&socket)
2066    }
2067
2068    #[test_case(
2069        IpSocketMatcher::SrcAddr(BoundAddressMatcherEither::Unbound) => true;
2070        "src_addr unbound match"
2071    )]
2072    #[test_case(IpSocketMatcher::SrcAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(
2073        AddressMatcher {
2074            matcher: AddressMatcherType::Subnet(SubnetMatcher(Ipv4::TEST_ADDRS.subnet)),
2075            invert: false,
2076        }
2077    ))) => false; "src_addr bound mismatch")]
2078    #[test_case(
2079        IpSocketMatcher::DstAddr(BoundAddressMatcherEither::Unbound) => true;
2080        "dst_addr unbound match"
2081    )]
2082    #[test_case(IpSocketMatcher::DstAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(
2083        AddressMatcher {
2084            matcher: AddressMatcherType::Subnet(SubnetMatcher(Ipv4::TEST_ADDRS.subnet)),
2085            invert: false,
2086        }
2087    ))) => false; "dst_addr bound mismatch")]
2088
2089    fn ip_socket_matcher_unbound(matcher: IpSocketMatcher<FakeDeviceClass>) -> bool {
2090        let socket = FakeIpSocket::<Ipv4, _> {
2091            src_ip: None,
2092            dst_ip: None,
2093            proto: FakeTcpSocket {
2094                src_port: Some(80),
2095                dst_port: Some(12345),
2096                state: TcpSocketState::Established,
2097            },
2098            cookie: 0,
2099            intf: None,
2100            marks: Marks::default(),
2101        };
2102        matcher.matches(&socket)
2103    }
2104}