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