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