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    /// 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> InspectableValue for AddressMatcher<A> {
613    fn record<I: Inspector>(&self, name: &str, inspector: &mut I) {
614        let AddressMatcher { matcher, invert } = self;
615
616        inspector.record_child(name, |inspector| {
617            inspector.record_bool("invert", *invert);
618            match matcher {
619                AddressMatcherType::Subnet(SubnetMatcher(subnet)) => {
620                    inspector.record_display("subnet", subnet)
621                }
622                AddressMatcherType::Range(range) => {
623                    inspector.record_display("start", range.start());
624                    inspector.record_display("end", range.end());
625                }
626            }
627        })
628    }
629}
630
631impl<A: IpAddress> Matcher<A> for AddressMatcher<A> {
632    fn matches(&self, addr: &A) -> bool {
633        let Self { matcher, invert } = self;
634        matcher.matches(addr) ^ *invert
635    }
636}
637
638/// An address matcher that matches any IP version as specified at runtime.
639pub enum AddressMatcherEither {
640    /// The top-level IPv4 address matcher.
641    V4(AddressMatcher<Ipv4Addr>),
642    /// The top-level IPv6 address matcher.
643    V6(AddressMatcher<Ipv6Addr>),
644}
645
646/// An IP-generic address matcher that matches a (possibly bound) IP address.
647pub enum BoundAddressMatcherEither {
648    /// The target is bound to an address matched by the inner matcher.
649    Bound(AddressMatcherEither),
650    /// The target is not bound to a specific address.
651    Unbound,
652}
653
654impl Matcher<Option<IpAddr>> for BoundAddressMatcherEither {
655    fn matches(&self, addr: &Option<IpAddr>) -> bool {
656        match (self, addr) {
657            (BoundAddressMatcherEither::Unbound, None) => true,
658            (BoundAddressMatcherEither::Bound(matcher), Some(addr)) => match (matcher, addr) {
659                (AddressMatcherEither::V4(matcher), IpAddr::V4(addr)) => matcher.matches(addr),
660                (AddressMatcherEither::V6(matcher), IpAddr::V6(addr)) => matcher.matches(addr),
661                _ => false,
662            },
663            _ => false,
664        }
665    }
666}
667
668/// Allows code to match on properties of a socket without Netstack3 Core
669/// having to specifically expose that state.
670pub trait IpSocketProperties<DeviceClass> {
671    /// Returns whether the provided IP version matches the socket.
672    fn family_matches(&self, family: &net_types::ip::IpVersion) -> bool;
673
674    /// Returns whether the provided address matcher matches the socket's source
675    /// address.
676    fn src_addr_matches(&self, addr: &BoundAddressMatcherEither) -> bool;
677
678    /// Returns whether the provided address matcher matches the socket's
679    /// destination address.
680    fn dst_addr_matches(&self, addr: &BoundAddressMatcherEither) -> bool;
681
682    /// Returns whether the transport protocol matches the socket's
683    /// transport-layer information.
684    fn transport_protocol_matches(&self, matcher: &SocketTransportProtocolMatcher) -> bool;
685
686    /// Returns whether the provided interface matcher matches the socket's
687    /// bound interface, if present.
688    fn bound_interface_matches(&self, iface: &BoundInterfaceMatcher<DeviceClass>) -> bool;
689
690    /// Returns whether the provided cookie matcher matches the socket's cookie.
691    fn cookie_matches(&self, cookie: &SocketCookieMatcher) -> bool;
692
693    /// Returns whether the provided mark matcher matches the corresponding mark.
694    fn mark_matches(&self, matcher: &MarkInDomainMatcher) -> bool;
695}
696
697/// The top-level matcher for IP sockets.
698pub enum IpSocketMatcher<DeviceClass> {
699    /// Matches the socket's address family.
700    Family(net_types::ip::IpVersion),
701    /// Matches the socket's source address.
702    SrcAddr(BoundAddressMatcherEither),
703    /// Matches the socket's destination address.
704    DstAddr(BoundAddressMatcherEither),
705    /// Matches the socket's transport protocol.
706    Proto(SocketTransportProtocolMatcher),
707    /// Matches the socket's bound interface.
708    BoundInterface(BoundInterfaceMatcher<DeviceClass>),
709    /// Matches the socket's cookie.
710    Cookie(SocketCookieMatcher),
711    /// Matches the socket's mark.
712    Mark(MarkInDomainMatcher),
713}
714
715impl<DeviceClass, S: IpSocketProperties<DeviceClass>> Matcher<S> for IpSocketMatcher<DeviceClass> {
716    fn matches(&self, actual: &S) -> bool {
717        match self {
718            IpSocketMatcher::Family(family) => actual.family_matches(family),
719            IpSocketMatcher::SrcAddr(addr) => actual.src_addr_matches(addr),
720            IpSocketMatcher::DstAddr(addr) => actual.dst_addr_matches(addr),
721            IpSocketMatcher::Proto(proto) => actual.transport_protocol_matches(proto),
722            IpSocketMatcher::BoundInterface(iface) => actual.bound_interface_matches(iface),
723            IpSocketMatcher::Cookie(cookie) => actual.cookie_matches(cookie),
724            IpSocketMatcher::Mark(mark) => actual.mark_matches(mark),
725        }
726    }
727}
728
729/// Allows code to take an opaque matcher that works on IP sockets without
730/// needing to know the type(s) of the underlying matcher(s).
731pub trait IpSocketPropertiesMatcher<DeviceClass> {
732    /// Whether the matcher matches `actual`.
733    fn matches_ip_socket<S: IpSocketProperties<DeviceClass>>(&self, actual: &S) -> bool;
734}
735
736impl<DeviceClass> IpSocketPropertiesMatcher<DeviceClass> for IpSocketMatcher<DeviceClass> {
737    fn matches_ip_socket<S: IpSocketProperties<DeviceClass>>(&self, actual: &S) -> bool {
738        self.matches(actual)
739    }
740}
741
742impl<DeviceClass> IpSocketPropertiesMatcher<DeviceClass> for [IpSocketMatcher<DeviceClass>] {
743    fn matches_ip_socket<S: IpSocketProperties<DeviceClass>>(&self, actual: &S) -> bool {
744        self.iter().all(|matcher| matcher.matches(actual))
745    }
746}
747
748#[cfg(any(test, feature = "testutils"))]
749pub(crate) mod testutil {
750    use alloc::string::String;
751    use core::num::NonZeroU64;
752
753    use crate::matchers::InterfaceProperties;
754    use crate::testutil::{FakeDeviceClass, FakeStrongDeviceId, FakeWeakDeviceId};
755    use crate::{DeviceIdentifier, StrongDeviceIdentifier};
756
757    /// A fake device ID for testing matchers.
758    #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
759    #[allow(missing_docs)]
760    pub struct FakeMatcherDeviceId {
761        pub id: NonZeroU64,
762        pub name: String,
763        pub class: FakeDeviceClass,
764    }
765
766    impl FakeMatcherDeviceId {
767        /// Returns a [`FakeMatcherDeviceId`] for an arbitrary WLAN interface.
768        ///
769        /// The interface returned will always be identical.
770        pub fn wlan_interface() -> FakeMatcherDeviceId {
771            FakeMatcherDeviceId {
772                id: NonZeroU64::new(1).unwrap(),
773                name: String::from("wlan"),
774                class: FakeDeviceClass::Wlan,
775            }
776        }
777
778        /// Returns a [`FakeMatcherDeviceId`] for an arbitrary Ethernet interface.
779        ///
780        /// The interface returned will always be identical.
781        pub fn ethernet_interface() -> FakeMatcherDeviceId {
782            FakeMatcherDeviceId {
783                id: NonZeroU64::new(2).unwrap(),
784                name: String::from("eth"),
785                class: FakeDeviceClass::Ethernet,
786            }
787        }
788    }
789
790    impl StrongDeviceIdentifier for FakeMatcherDeviceId {
791        type Weak = FakeWeakDeviceId<Self>;
792
793        fn downgrade(&self) -> Self::Weak {
794            FakeWeakDeviceId(self.clone())
795        }
796    }
797
798    impl DeviceIdentifier for FakeMatcherDeviceId {
799        fn is_loopback(&self) -> bool {
800            false
801        }
802    }
803
804    impl FakeStrongDeviceId for FakeMatcherDeviceId {
805        fn is_alive(&self) -> bool {
806            true
807        }
808    }
809
810    impl PartialEq<FakeWeakDeviceId<FakeMatcherDeviceId>> for FakeMatcherDeviceId {
811        fn eq(&self, FakeWeakDeviceId(other): &FakeWeakDeviceId<FakeMatcherDeviceId>) -> bool {
812            self == other
813        }
814    }
815
816    impl InterfaceProperties<FakeDeviceClass> for FakeMatcherDeviceId {
817        fn id_matches(&self, id: &NonZeroU64) -> bool {
818            &self.id == id
819        }
820
821        fn name_matches(&self, name: &str) -> bool {
822            &self.name == name
823        }
824
825        fn device_class_matches(&self, class: &FakeDeviceClass) -> bool {
826            &self.class == class
827        }
828    }
829}
830
831#[cfg(test)]
832mod tests {
833    use ip_test_macro::ip_test;
834    use net_types::Witness;
835    use net_types::ip::{Ip, IpVersion, Ipv4, Ipv6};
836    use test_case::test_case;
837
838    use super::*;
839    use crate::testutil::{FakeDeviceClass, FakeMatcherDeviceId, TestIpExt};
840
841    /// Only matches `true`.
842    #[derive(Debug)]
843    struct TrueMatcher;
844
845    impl Matcher<bool> for TrueMatcher {
846        fn matches(&self, actual: &bool) -> bool {
847            *actual
848        }
849    }
850
851    #[test]
852    fn test_optional_matcher_optional_value() {
853        assert!(TrueMatcher.matches(&true));
854        assert!(!TrueMatcher.matches(&false));
855
856        assert!(TrueMatcher.required_matches(Some(&true)));
857        assert!(!TrueMatcher.required_matches(Some(&false)));
858        assert!(!TrueMatcher.required_matches(None));
859
860        assert!(Some(TrueMatcher).matches(&true));
861        assert!(!Some(TrueMatcher).matches(&false));
862        assert!(None::<TrueMatcher>.matches(&true));
863        assert!(None::<TrueMatcher>.matches(&false));
864
865        assert!(Some(TrueMatcher).required_matches(Some(&true)));
866        assert!(!Some(TrueMatcher).required_matches(Some(&false)));
867        assert!(!Some(TrueMatcher).required_matches(None));
868        assert!(None::<TrueMatcher>.required_matches(Some(&true)));
869        assert!(None::<TrueMatcher>.required_matches(Some(&false)));
870        assert!(None::<TrueMatcher>.required_matches(None));
871    }
872
873    #[test_case(
874        InterfaceMatcher::Id(FakeMatcherDeviceId::wlan_interface().id),
875        FakeMatcherDeviceId::wlan_interface() => true
876    )]
877    #[test_case(
878        InterfaceMatcher::Id(FakeMatcherDeviceId::wlan_interface().id),
879        FakeMatcherDeviceId::ethernet_interface() => false
880    )]
881    #[test_case(
882        InterfaceMatcher::Name(FakeMatcherDeviceId::wlan_interface().name),
883        FakeMatcherDeviceId::wlan_interface() => true
884    )]
885    #[test_case(
886        InterfaceMatcher::Name(FakeMatcherDeviceId::wlan_interface().name),
887        FakeMatcherDeviceId::ethernet_interface() => false
888    )]
889    #[test_case(
890        InterfaceMatcher::DeviceClass(FakeDeviceClass::Wlan),
891        FakeMatcherDeviceId::wlan_interface() => true
892    )]
893    #[test_case(
894        InterfaceMatcher::DeviceClass(FakeDeviceClass::Wlan),
895        FakeMatcherDeviceId::ethernet_interface() => false
896    )]
897    fn interface_matcher(
898        matcher: InterfaceMatcher<FakeDeviceClass>,
899        device: FakeMatcherDeviceId,
900    ) -> bool {
901        matcher.matches(&device)
902    }
903
904    #[test_case(BoundInterfaceMatcher::Unbound, None => true)]
905    #[test_case(
906        BoundInterfaceMatcher::Unbound,
907        Some(FakeMatcherDeviceId::wlan_interface()) => false
908    )]
909    #[test_case(
910        BoundInterfaceMatcher::Bound(
911            InterfaceMatcher::Id(FakeMatcherDeviceId::wlan_interface().id)
912        ),
913        None => false
914    )]
915    #[test_case(
916        BoundInterfaceMatcher::Bound(
917            InterfaceMatcher::Id(FakeMatcherDeviceId::wlan_interface().id)
918        ),
919        Some(FakeMatcherDeviceId::wlan_interface()) => true
920    )]
921    #[test_case(
922        BoundInterfaceMatcher::Bound(
923            InterfaceMatcher::Id(FakeMatcherDeviceId::wlan_interface().id)
924        ),
925        Some(FakeMatcherDeviceId::ethernet_interface()) => false
926    )]
927    #[test_case(
928        BoundInterfaceMatcher::Bound(
929            InterfaceMatcher::Name(FakeMatcherDeviceId::wlan_interface().name)
930        ),
931        None => false
932    )]
933    #[test_case(
934        BoundInterfaceMatcher::Bound(
935            InterfaceMatcher::Name(FakeMatcherDeviceId::wlan_interface().name)
936        ),
937        Some(FakeMatcherDeviceId::wlan_interface()) => true
938    )]
939    #[test_case(
940        BoundInterfaceMatcher::Bound(
941            InterfaceMatcher::Name(FakeMatcherDeviceId::wlan_interface().name)
942        ),
943        Some(FakeMatcherDeviceId::ethernet_interface()) => false
944    )]
945    #[test_case(
946        BoundInterfaceMatcher::Bound(
947            InterfaceMatcher::DeviceClass(FakeDeviceClass::Wlan)
948        ),
949        None => false
950    )]
951    #[test_case(
952        BoundInterfaceMatcher::Bound(
953            InterfaceMatcher::DeviceClass(FakeDeviceClass::Wlan)
954        ),
955        Some(FakeMatcherDeviceId::wlan_interface()) => true
956    )]
957    #[test_case(
958        BoundInterfaceMatcher::Bound(
959            InterfaceMatcher::DeviceClass(FakeDeviceClass::Wlan)
960        ),
961        Some(FakeMatcherDeviceId::ethernet_interface()) => false
962    )]
963    fn bound_interface_matcher(
964        matcher: BoundInterfaceMatcher<FakeDeviceClass>,
965        device: Option<FakeMatcherDeviceId>,
966    ) -> bool {
967        matcher.matches(&device.as_ref())
968    }
969
970    #[ip_test(I)]
971    fn subnet_matcher<I: Ip + TestIpExt>() {
972        let matcher = SubnetMatcher(I::TEST_ADDRS.subnet);
973        assert!(matcher.matches(&I::TEST_ADDRS.local_ip));
974        assert!(!matcher.matches(&I::get_other_remote_ip_address(1)));
975    }
976
977    #[test_case(MarkMatcher::Unmarked, Mark(None) => true; "unmarked matches none")]
978    #[test_case(MarkMatcher::Unmarked, Mark(Some(0)) => false; "unmarked does not match some")]
979    #[test_case(MarkMatcher::Marked {
980        mask: 1,
981        start: 0,
982        end: 0,
983        invert: false,
984    }, Mark(None) => false; "marked does not match none")]
985    #[test_case(MarkMatcher::Marked {
986        mask: 1,
987        start: 0,
988        end: 0,
989        invert: false,
990    }, Mark(Some(0)) => true; "marked 0 mask 1 matches 0")]
991    #[test_case(MarkMatcher::Marked {
992        mask: 1,
993        start: 0,
994        end: 0,
995        invert: false,
996    }, Mark(Some(1)) => false; "marked 0 mask 1 does not match 1")]
997    #[test_case(MarkMatcher::Marked {
998        mask: 1,
999        start: 0,
1000        end: 0,
1001        invert: false,
1002    }, Mark(Some(2)) => true; "marked 0 mask 1 matches 2")]
1003    #[test_case(MarkMatcher::Marked {
1004        mask: 1,
1005        start: 0,
1006        end: 0,
1007        invert: false,
1008    }, Mark(Some(3)) => false; "marked 0 mask 1 does not match 3")]
1009    #[test_case(MarkMatcher::Marked {
1010        mask: !0,
1011        start: 0,
1012        end: 10,
1013        invert: true,
1014    }, Mark(Some(5)) => false; "marked invert no match in range")]
1015    #[test_case(MarkMatcher::Marked {
1016        mask: !0,
1017        start: 0,
1018        end: 10,
1019        invert: true,
1020    }, Mark(Some(11)) => true; "marked invert matches out of range")]
1021    fn mark_matcher(matcher: MarkMatcher, mark: Mark) -> bool {
1022        matcher.matches(&mark)
1023    }
1024
1025    #[test_case(
1026        MarkMatchers::new(
1027            [(MarkDomain::Mark1, MarkMatcher::Unmarked),
1028            (MarkDomain::Mark2, MarkMatcher::Unmarked)]
1029        ),
1030        Marks::new([]) => true;
1031        "all unmarked matches empty"
1032    )]
1033    #[test_case(
1034        MarkMatchers::new(
1035            [(MarkDomain::Mark1, MarkMatcher::Unmarked),
1036            (MarkDomain::Mark2, MarkMatcher::Unmarked)]
1037        ),
1038        Marks::new([(MarkDomain::Mark1, 1)]) => false;
1039        "all unmarked does not match mark1"
1040    )]
1041    #[test_case(
1042        MarkMatchers::new(
1043            [(MarkDomain::Mark1, MarkMatcher::Unmarked),
1044            (MarkDomain::Mark2, MarkMatcher::Unmarked)]
1045        ),
1046        Marks::new([(MarkDomain::Mark2, 1)]) => false;
1047        "all unmarked does not match mark2"
1048    )]
1049    #[test_case(
1050        MarkMatchers::new(
1051            [(MarkDomain::Mark1, MarkMatcher::Unmarked),
1052            (MarkDomain::Mark2, MarkMatcher::Unmarked)]
1053        ),
1054        Marks::new([
1055            (MarkDomain::Mark1, 1),
1056            (MarkDomain::Mark2, 1),
1057        ]) => false;
1058        "all unmarked does not match mark1 and mark2"
1059    )]
1060    #[test_case(
1061        MarkMatchers::new(
1062            [(MarkDomain::Mark1, MarkMatcher::Marked { mask: !0, start: 1, end: 1, invert: false }),
1063            (MarkDomain::Mark2, MarkMatcher::Unmarked)]
1064        ),
1065        Marks::new([(MarkDomain::Mark1, 1)]) => true;
1066        "mark1 marked matches"
1067    )]
1068    #[test_case(
1069        MarkMatchers::new(
1070            [(MarkDomain::Mark1, MarkMatcher::Marked { mask: !0, start: 1, end: 1, invert: false }),
1071            (MarkDomain::Mark2, MarkMatcher::Unmarked)]
1072        ),
1073        Marks::new([(MarkDomain::Mark1, 2)]) => false;
1074        "mark1 marked no match"
1075    )]
1076    #[test_case(
1077        MarkMatchers::new(
1078            [(MarkDomain::Mark1, MarkMatcher::Marked { mask: !0, start: 1, end: 1, invert: false }),
1079            (MarkDomain::Mark2, MarkMatcher::Marked { mask: !0, start: 2, end: 2, invert: false })]
1080        ),
1081        Marks::new([(MarkDomain::Mark1, 1), (MarkDomain::Mark2, 2)]) => true;
1082        "all marked matches"
1083    )]
1084    #[test_case(
1085        MarkMatchers::new(
1086            [(MarkDomain::Mark1, MarkMatcher::Marked { mask: !0, start: 1, end: 1, invert: false }),
1087            (MarkDomain::Mark2, MarkMatcher::Marked { mask: !0, start: 2, end: 2, invert: false })]
1088        ),
1089        Marks::new([(MarkDomain::Mark1, 1), (MarkDomain::Mark2, 3)]) => false;
1090        "all marked no match mark2"
1091    )]
1092    fn mark_matchers(matchers: MarkMatchers, marks: Marks) -> bool {
1093        matchers.matches(&marks)
1094    }
1095
1096    #[test_case(SocketCookieMatcher { cookie: 123, invert: false }, 123 => true)]
1097    #[test_case(SocketCookieMatcher { cookie: 123, invert: false }, 456 => false)]
1098    #[test_case(SocketCookieMatcher { cookie: 123, invert: true }, 123 => false)]
1099    #[test_case(SocketCookieMatcher { cookie: 123, invert: true }, 456 => true)]
1100    fn socket_cookie_matcher(matcher: SocketCookieMatcher, actual: u64) -> bool {
1101        matcher.matches(&actual)
1102    }
1103
1104    #[test_case(PortMatcher { range: 10..=20, invert: false }, 9 => false)]
1105    #[test_case(PortMatcher { range: 10..=20, invert: false }, 10 => true)]
1106    #[test_case(PortMatcher { range: 10..=20, invert: false }, 15 => true)]
1107    #[test_case(PortMatcher { range: 10..=20, invert: false }, 20 => true)]
1108    #[test_case(PortMatcher { range: 10..=20, invert: false }, 21 => false)]
1109    #[test_case(PortMatcher { range: 10..=20, invert: true }, 9 => true)]
1110    #[test_case(PortMatcher { range: 10..=20, invert: true }, 10 => false)]
1111    #[test_case(PortMatcher { range: 10..=20, invert: true }, 15 => false)]
1112    #[test_case(PortMatcher { range: 10..=20, invert: true }, 20 => false)]
1113    #[test_case(PortMatcher { range: 10..=20, invert: true }, 21 => true)]
1114    fn port_matcher(matcher: PortMatcher, actual: u16) -> bool {
1115        matcher.matches(&actual)
1116    }
1117
1118    #[test_case(BoundPortMatcher::Unbound, None => true)]
1119    #[test_case(BoundPortMatcher::Unbound, Some(80) => false)]
1120    #[test_case(
1121        BoundPortMatcher::Bound(PortMatcher { range: 10..=20, invert: false }),
1122        None => false
1123    )]
1124    #[test_case(
1125        BoundPortMatcher::Bound(PortMatcher { range: 10..=20, invert: false }),
1126        Some(10) => true
1127    )]
1128    #[test_case(
1129        BoundPortMatcher::Bound(PortMatcher { range: 10..=20, invert: false }),
1130        Some(9) => false
1131    )]
1132    fn bound_port_matcher(matcher: BoundPortMatcher, actual: Option<u16>) -> bool {
1133        matcher.matches(&actual)
1134    }
1135
1136    struct FakeTcpSocket {
1137        src_port: Option<u16>,
1138        dst_port: Option<u16>,
1139        state: TcpSocketState,
1140    }
1141
1142    impl MaybeSocketTransportProperties for FakeTcpSocket {
1143        type TcpProps<'a>
1144            = Self
1145        where
1146            Self: 'a;
1147
1148        type UdpProps<'a>
1149            = Never
1150        where
1151            Self: 'a;
1152
1153        fn tcp_socket_properties(&self) -> Option<&Self::TcpProps<'_>> {
1154            Some(self)
1155        }
1156
1157        fn udp_socket_properties(&self) -> Option<&Self::UdpProps<'_>> {
1158            None
1159        }
1160    }
1161
1162    impl TcpSocketProperties for FakeTcpSocket {
1163        fn src_port_matches(&self, matcher: &BoundPortMatcher) -> bool {
1164            matcher.matches(&self.src_port)
1165        }
1166
1167        fn dst_port_matches(&self, matcher: &BoundPortMatcher) -> bool {
1168            matcher.matches(&self.dst_port)
1169        }
1170
1171        fn state_matches(&self, matcher: &TcpStateMatcher) -> bool {
1172            matcher.matches(&self.state)
1173        }
1174    }
1175
1176    struct FakeUdpSocket {
1177        src_port: Option<u16>,
1178        dst_port: Option<u16>,
1179        state: UdpSocketState,
1180    }
1181
1182    impl MaybeSocketTransportProperties for FakeUdpSocket {
1183        type TcpProps<'a>
1184            = Never
1185        where
1186            Self: 'a;
1187
1188        type UdpProps<'a>
1189            = Self
1190        where
1191            Self: 'a;
1192
1193        fn tcp_socket_properties(&self) -> Option<&Self::TcpProps<'_>> {
1194            None
1195        }
1196
1197        fn udp_socket_properties(&self) -> Option<&Self::UdpProps<'_>> {
1198            Some(self)
1199        }
1200    }
1201
1202    impl UdpSocketProperties for FakeUdpSocket {
1203        fn src_port_matches(&self, matcher: &BoundPortMatcher) -> bool {
1204            matcher.matches(&self.src_port)
1205        }
1206
1207        fn dst_port_matches(&self, matcher: &BoundPortMatcher) -> bool {
1208            matcher.matches(&self.dst_port)
1209        }
1210
1211        fn state_matches(&self, matcher: &UdpStateMatcher) -> bool {
1212            matcher.matches(&self.state)
1213        }
1214    }
1215
1216    struct FakeIpSocket<I, T>
1217    where
1218        I: TestIpExt,
1219        T: MaybeSocketTransportProperties,
1220    {
1221        src_ip: Option<I::Addr>,
1222        dst_ip: Option<I::Addr>,
1223        proto: T,
1224        intf: Option<FakeMatcherDeviceId>,
1225        cookie: u64,
1226        marks: Marks,
1227    }
1228
1229    impl<I, T> MaybeSocketTransportProperties for FakeIpSocket<I, T>
1230    where
1231        I: TestIpExt,
1232        T: MaybeSocketTransportProperties,
1233    {
1234        type TcpProps<'a>
1235            = T::TcpProps<'a>
1236        where
1237            Self: 'a;
1238
1239        type UdpProps<'a>
1240            = T::UdpProps<'a>
1241        where
1242            Self: 'a;
1243
1244        fn tcp_socket_properties(&self) -> Option<&Self::TcpProps<'_>> {
1245            self.proto.tcp_socket_properties()
1246        }
1247
1248        fn udp_socket_properties(&self) -> Option<&Self::UdpProps<'_>> {
1249            self.proto.udp_socket_properties()
1250        }
1251    }
1252
1253    impl<I, T> IpSocketProperties<FakeDeviceClass> for FakeIpSocket<I, T>
1254    where
1255        I: TestIpExt,
1256        T: MaybeSocketTransportProperties,
1257    {
1258        fn family_matches(&self, family: &net_types::ip::IpVersion) -> bool {
1259            *family == I::VERSION
1260        }
1261
1262        fn src_addr_matches(&self, addr: &BoundAddressMatcherEither) -> bool {
1263            addr.matches(&self.src_ip.map(|a| a.into()))
1264        }
1265
1266        fn dst_addr_matches(&self, addr: &BoundAddressMatcherEither) -> bool {
1267            addr.matches(&self.dst_ip.map(|a| a.into()))
1268        }
1269
1270        fn transport_protocol_matches(&self, matcher: &SocketTransportProtocolMatcher) -> bool {
1271            matcher.matches(self)
1272        }
1273
1274        fn bound_interface_matches(&self, iface: &BoundInterfaceMatcher<FakeDeviceClass>) -> bool {
1275            iface.matches(&self.intf.as_ref())
1276        }
1277
1278        fn cookie_matches(&self, cookie: &SocketCookieMatcher) -> bool {
1279            cookie.matches(&self.cookie)
1280        }
1281
1282        fn mark_matches(&self, matcher: &MarkInDomainMatcher) -> bool {
1283            matcher.matcher.matches(self.marks.get(matcher.domain))
1284        }
1285    }
1286
1287    #[test_case(
1288        TcpSocketMatcher::Empty,
1289        FakeTcpSocket {
1290            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1291        } => true;
1292        "empty matcher"
1293    )]
1294    #[test_case(
1295        TcpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1296            PortMatcher { range: 80..=80, invert: false }
1297        )),
1298        FakeTcpSocket {
1299            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1300        } => true;
1301        "src_port match"
1302    )]
1303    #[test_case(
1304        TcpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1305            PortMatcher { range: 80..=80, invert: false }
1306        )),
1307        FakeTcpSocket {
1308            src_port: Some(81), dst_port: Some(12345), state: TcpSocketState::Established
1309        } => false;
1310        "src_port no match"
1311    )]
1312    #[test_case(
1313        TcpSocketMatcher::SrcPort(BoundPortMatcher::Bound(PortMatcher {
1314            range: 80..=80, invert: true
1315        })),
1316        FakeTcpSocket {
1317            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1318        } => false;
1319        "src_port invert no match"
1320    )]
1321    #[test_case(
1322        TcpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1323            PortMatcher { range: 80..=80, invert: true }
1324        )),
1325        FakeTcpSocket {
1326            src_port: Some(81), dst_port: Some(12345), state: TcpSocketState::Established
1327        } => true;
1328        "src_port invert match"
1329    )]
1330    #[test_case(
1331        TcpSocketMatcher::DstPort(BoundPortMatcher::Bound(
1332            PortMatcher {range: 12345..=12345, invert: false }
1333        )),
1334        FakeTcpSocket {
1335            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1336        } => true;
1337        "dst_port match"
1338    )]
1339    #[test_case(
1340        TcpSocketMatcher::DstPort(BoundPortMatcher::Bound(
1341            PortMatcher { range: 12345..=12345, invert: false }
1342        )),
1343        FakeTcpSocket {
1344            src_port: Some(80), dst_port: Some(12346), state: TcpSocketState::Established
1345        } => false;
1346        "dst_port no match"
1347    )]
1348    #[test_case(
1349        TcpSocketMatcher::State(TcpStateMatcher::ESTABLISHED),
1350        FakeTcpSocket {
1351            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1352        } => true;
1353        "state match"
1354    )]
1355    #[test_case(
1356        TcpSocketMatcher::State(TcpStateMatcher::SYN_SENT),
1357        FakeTcpSocket {
1358            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1359        } => false;
1360        "state no match"
1361    )]
1362    #[test_case(
1363        TcpSocketMatcher::State(TcpStateMatcher::ESTABLISHED | TcpStateMatcher::SYN_SENT),
1364        FakeTcpSocket {
1365            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1366        } => true;
1367        "state multi match established"
1368    )]
1369    #[test_case(
1370        TcpSocketMatcher::State(TcpStateMatcher::ESTABLISHED | TcpStateMatcher::SYN_SENT),
1371        FakeTcpSocket {
1372            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::SynSent
1373        } => true;
1374        "state multi match syn_sent"
1375    )]
1376    #[test_case(
1377        TcpSocketMatcher::State(TcpStateMatcher::ESTABLISHED | TcpStateMatcher::SYN_SENT),
1378        FakeTcpSocket {
1379            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::FinWait1
1380        } => false;
1381        "state multi no match"
1382    )]
1383    #[test_case(
1384        TcpSocketMatcher::SrcPort(BoundPortMatcher::Unbound),
1385        FakeTcpSocket {
1386            src_port: None, dst_port: Some(12345), state: TcpSocketState::Established
1387        } => true;
1388        "src_port unbound match"
1389    )]
1390    #[test_case(
1391        TcpSocketMatcher::SrcPort(BoundPortMatcher::Unbound),
1392        FakeTcpSocket {
1393            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1394        } => false;
1395        "src_port unbound no match"
1396    )]
1397    #[test_case(
1398        TcpSocketMatcher::DstPort(BoundPortMatcher::Unbound),
1399        FakeTcpSocket {
1400            src_port: Some(80), dst_port: None, state: TcpSocketState::Established
1401        } => true;
1402        "dst_port unbound match"
1403    )]
1404    #[test_case(
1405        TcpSocketMatcher::DstPort(BoundPortMatcher::Unbound),
1406        FakeTcpSocket {
1407            src_port: Some(80), dst_port: Some(12345), state: TcpSocketState::Established
1408        } => false;
1409        "dst_port unbound no match"
1410    )]
1411    fn tcp_socket_matcher(matcher: TcpSocketMatcher, socket: FakeTcpSocket) -> bool {
1412        matcher.matches(&socket)
1413    }
1414
1415    #[test_case(
1416        UdpSocketMatcher::Empty,
1417        FakeUdpSocket {
1418            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Bound
1419        } => true;
1420        "empty matcher"
1421    )]
1422    #[test_case(
1423        UdpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1424            PortMatcher { range: 53..=53, invert: false }
1425        )),
1426        FakeUdpSocket {
1427            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Bound
1428        } => true;
1429        "src_port match"
1430    )]
1431    #[test_case(
1432        UdpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1433            PortMatcher { range: 53..=53, invert: false }
1434        )),
1435        FakeUdpSocket {
1436            src_port: Some(54), dst_port: Some(12345), state: UdpSocketState::Bound
1437        } => false;
1438        "src_port no match"
1439    )]
1440    #[test_case(
1441        UdpSocketMatcher::DstPort(BoundPortMatcher::Bound(
1442            PortMatcher { range: 12345..=12345, invert: false }
1443        )),
1444        FakeUdpSocket {
1445            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Bound
1446         } => true;
1447        "dst_port match"
1448    )]
1449    #[test_case(
1450        UdpSocketMatcher::DstPort(BoundPortMatcher::Bound(
1451            PortMatcher { range: 12345..=12345, invert: false }
1452        )),
1453        FakeUdpSocket {
1454            src_port: Some(53), dst_port: Some(12346), state: UdpSocketState::Bound
1455        } => false;
1456        "dst_port no match"
1457    )]
1458    #[test_case(
1459        UdpSocketMatcher::State(UdpStateMatcher::BOUND),
1460        FakeUdpSocket {
1461            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Bound
1462         } => true;
1463        "state match bound"
1464    )]
1465    #[test_case(
1466        UdpSocketMatcher::State(UdpStateMatcher::CONNECTED),
1467        FakeUdpSocket {
1468            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Bound
1469        } => false;
1470        "state no match connected"
1471    )]
1472    #[test_case(
1473        UdpSocketMatcher::State(UdpStateMatcher::BOUND | UdpStateMatcher::CONNECTED),
1474        FakeUdpSocket {
1475            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Bound
1476         } => true;
1477        "state multi match bound"
1478    )]
1479    #[test_case(
1480        UdpSocketMatcher::State(UdpStateMatcher::BOUND | UdpStateMatcher::CONNECTED),
1481        FakeUdpSocket {
1482            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Connected
1483         } => true;
1484        "state multi match connected"
1485    )]
1486    #[test_case(
1487        UdpSocketMatcher::SrcPort(BoundPortMatcher::Unbound),
1488        FakeUdpSocket {
1489            src_port: None, dst_port: Some(12345), state: UdpSocketState::Bound
1490         } => true;
1491        "src_port unbound match"
1492    )]
1493    #[test_case(
1494        UdpSocketMatcher::SrcPort(BoundPortMatcher::Unbound),
1495        FakeUdpSocket {
1496            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Bound
1497        } => false;
1498        "src_port unbound no match"
1499    )]
1500    #[test_case(
1501        UdpSocketMatcher::DstPort(BoundPortMatcher::Unbound),
1502        FakeUdpSocket { src_port: Some(53), dst_port: None, state: UdpSocketState::Bound } => true;
1503        "dst_port unbound match"
1504    )]
1505    #[test_case(
1506        UdpSocketMatcher::DstPort(BoundPortMatcher::Unbound),
1507        FakeUdpSocket {
1508            src_port: Some(53), dst_port: Some(12345), state: UdpSocketState::Bound
1509        } => false;
1510        "dst_port unbound no match"
1511    )]
1512    fn udp_socket_matcher(matcher: UdpSocketMatcher, socket: FakeUdpSocket) -> bool {
1513        matcher.matches(&socket)
1514    }
1515
1516    #[ip_test(I)]
1517    #[test_case(
1518        IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(TcpSocketMatcher::Empty)),
1519        FakeIpSocket {
1520            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1521            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1522            proto: FakeTcpSocket {
1523                src_port: Some(80),
1524                dst_port: Some(12345),
1525                state: TcpSocketState::Established,
1526            },
1527            cookie: 0,
1528            intf: None,
1529            marks: Marks::default(),
1530        } => true;
1531        "tcpm empty"
1532    )]
1533    #[test_case(
1534        IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(TcpSocketMatcher::Empty)),
1535        FakeIpSocket {
1536            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1537            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1538            proto: FakeUdpSocket {
1539                src_port: Some(53),
1540                dst_port: Some(12345),
1541                state: UdpSocketState::Bound,
1542            },
1543            cookie: 0,
1544            intf: None,
1545            marks: Marks::default(),
1546        } => false;
1547        "tcp empty no match udp"
1548    )]
1549    #[test_case(
1550        IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Udp(UdpSocketMatcher::Empty)),
1551        FakeIpSocket {
1552            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1553            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1554            proto: FakeTcpSocket {
1555                src_port: Some(80),
1556                dst_port: Some(12345),
1557                state: TcpSocketState::Established
1558            },
1559            cookie: 0,
1560            intf: None,
1561            marks: Marks::default(),
1562        } => false;
1563        "udp empty no match tcp"
1564    )]
1565    #[test_case(
1566        IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Udp(UdpSocketMatcher::Empty)),
1567        FakeIpSocket {
1568            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1569            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1570            proto: FakeUdpSocket {
1571                src_port: Some(53),
1572                dst_port: Some(12345),
1573                state: UdpSocketState::Bound,
1574            },
1575            cookie: 0,
1576            intf: None,
1577            marks: Marks::default(),
1578        } => true;
1579        "udp empty"
1580    )]
1581    #[test_case(
1582        IpSocketMatcher::Proto(
1583            SocketTransportProtocolMatcher::Tcp(
1584                TcpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1585                    PortMatcher { range: 80..=80, invert: false }
1586                ))
1587            )
1588        ),
1589        FakeIpSocket {
1590            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1591            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1592            proto: FakeTcpSocket {
1593                src_port: Some(80),
1594                dst_port: Some(12345),
1595                state: TcpSocketState::Established,
1596            },
1597            cookie: 0,
1598            intf: None,
1599            marks: Marks::default(),
1600        } => true;
1601        "tcp src_port match"
1602    )]
1603    #[test_case(
1604        IpSocketMatcher::Proto(
1605            SocketTransportProtocolMatcher::Tcp(
1606                TcpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1607                    PortMatcher { range: 80..=80, invert: false }
1608                ))
1609            )
1610        ),
1611        FakeIpSocket {
1612            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1613            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1614            proto: FakeTcpSocket {
1615                src_port: Some(81),
1616                dst_port: Some(12345),
1617                state: TcpSocketState::Established,
1618            },
1619            cookie: 0,
1620            intf: None,
1621            marks: Marks::default(),
1622        } => false;
1623        "tcp src_port no match"
1624    )]
1625    #[test_case(
1626        IpSocketMatcher::Proto(
1627            SocketTransportProtocolMatcher::Udp(
1628                UdpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1629                    PortMatcher { range: 53..=53, invert: false }
1630                ))
1631            )
1632        ),
1633        FakeIpSocket {
1634            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1635            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1636            proto: FakeUdpSocket {
1637                src_port: Some(53),
1638                dst_port: Some(12345),
1639                state: UdpSocketState::Bound,
1640            },
1641            cookie: 0,
1642            intf: None,
1643            marks: Marks::default(),
1644        } => true;
1645        "udp src_port match"
1646    )]
1647    #[test_case(
1648        IpSocketMatcher::Proto(
1649            SocketTransportProtocolMatcher::Udp(
1650                UdpSocketMatcher::SrcPort(BoundPortMatcher::Bound(
1651                    PortMatcher { range: 53..=53, invert: false }
1652                ))
1653            )
1654        ),
1655        FakeIpSocket {
1656            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1657            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1658            proto: FakeUdpSocket {
1659                src_port: Some(54),
1660                dst_port: Some(12345),
1661                state: UdpSocketState::Bound,
1662            },
1663            cookie: 0,
1664            intf: None,
1665            marks: Marks::default(),
1666        } => false;
1667        "udp src_port no match"
1668    )]
1669    #[test_case(
1670        IpSocketMatcher::Cookie(SocketCookieMatcher { cookie: 123, invert: false }),
1671        FakeIpSocket {
1672            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1673            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1674            proto: FakeTcpSocket {
1675                src_port: Some(80),
1676                dst_port: Some(12345),
1677                state: TcpSocketState::Established,
1678            },
1679            cookie: 123,
1680            intf: None,
1681            marks: Marks::default(),
1682        } => true;
1683        "cookie match"
1684    )]
1685    #[test_case(
1686        IpSocketMatcher::Cookie(SocketCookieMatcher { cookie: 123, invert: false }),
1687        FakeIpSocket {
1688            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1689            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1690            proto: FakeTcpSocket {
1691                src_port: Some(80),
1692                dst_port: Some(12345),
1693                state: TcpSocketState::Established,
1694            },
1695            cookie: 456,
1696            intf: None,
1697            marks: Marks::default(),
1698        } => false;
1699        "cookie no match"
1700    )]
1701    #[test_case(
1702        IpSocketMatcher::Mark(MarkInDomainMatcher {
1703            domain: MarkDomain::Mark1,
1704            matcher: MarkMatcher::Unmarked,
1705        }),
1706        FakeIpSocket {
1707            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1708            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1709            proto: FakeTcpSocket {
1710                src_port: Some(80),
1711                dst_port: Some(12345),
1712                state: TcpSocketState::Established,
1713            },
1714            cookie: 0,
1715            intf: None,
1716            marks: Marks::default(),
1717        } => true;
1718        "mark1 unmarked match"
1719    )]
1720    #[test_case(
1721        IpSocketMatcher::Mark(MarkInDomainMatcher {
1722            domain: MarkDomain::Mark1,
1723            matcher: MarkMatcher::Unmarked,
1724        }),
1725        FakeIpSocket {
1726            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1727            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1728            proto: FakeTcpSocket {
1729                src_port: Some(80),
1730                dst_port: Some(12345),
1731                state: TcpSocketState::Established,
1732            },
1733            cookie: 0,
1734            intf: None,
1735            marks: Marks::new([(MarkDomain::Mark1, 1)]),
1736        } => false;
1737        "mark1 unmarked no match"
1738    )]
1739    #[test_case(
1740        IpSocketMatcher::Mark(MarkInDomainMatcher {
1741            domain: MarkDomain::Mark2,
1742            matcher: MarkMatcher::Unmarked,
1743        }),
1744        FakeIpSocket {
1745            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1746            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1747            proto: FakeTcpSocket {
1748                src_port: Some(80),
1749                dst_port: Some(12345),
1750                state: TcpSocketState::Established,
1751            },
1752            cookie: 0,
1753            intf: None,
1754            marks: Marks::default(),
1755        } => true;
1756        "mark2 unmarked match"
1757    )]
1758    #[test_case(
1759        IpSocketMatcher::Mark(MarkInDomainMatcher {
1760            domain: MarkDomain::Mark2,
1761            matcher: MarkMatcher::Unmarked,
1762        }),
1763        FakeIpSocket {
1764            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1765            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1766            proto: FakeTcpSocket {
1767                src_port: Some(80),
1768                dst_port: Some(12345),
1769                state: TcpSocketState::Established,
1770            },
1771            cookie: 0,
1772            intf: None,
1773            marks: Marks::new([(MarkDomain::Mark2, 1)]),
1774        } => false;
1775        "mark2 unmarked no match"
1776    )]
1777    #[test_case(
1778        IpSocketMatcher::BoundInterface(BoundInterfaceMatcher::Bound(
1779            InterfaceMatcher::Id(FakeMatcherDeviceId::wlan_interface().id)
1780        )),
1781        FakeIpSocket {
1782            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1783            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1784            proto: FakeTcpSocket {
1785                src_port: Some(80),
1786                dst_port: Some(12345),
1787                state: TcpSocketState::Established,
1788            },
1789            cookie: 0,
1790            intf: Some(FakeMatcherDeviceId::wlan_interface()),
1791            marks: Marks::default(),
1792        } => true;
1793        "bound_interface match"
1794    )]
1795    #[test_case(
1796        IpSocketMatcher::BoundInterface(BoundInterfaceMatcher::Bound(
1797            InterfaceMatcher::Id(FakeMatcherDeviceId::wlan_interface().id)
1798        )),
1799        FakeIpSocket {
1800            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1801            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1802            proto: FakeTcpSocket {
1803                src_port: Some(80),
1804                dst_port: Some(12345),
1805                state: TcpSocketState::Established,
1806            },
1807            cookie: 0,
1808            intf: Some(FakeMatcherDeviceId::ethernet_interface()),
1809            marks: Marks::default(),
1810        } => false;
1811        "bound_interface no match"
1812    )]
1813    #[test_case(
1814        IpSocketMatcher::BoundInterface(BoundInterfaceMatcher::Unbound),
1815        FakeIpSocket {
1816            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1817            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1818            proto: FakeTcpSocket {
1819                src_port: Some(80),
1820                dst_port: Some(12345),
1821                state: TcpSocketState::Established,
1822            },
1823            cookie: 0,
1824            intf: None,
1825            marks: Marks::default(),
1826        } => true;
1827        "bound_interface unbound match"
1828    )]
1829    #[test_case(
1830        IpSocketMatcher::BoundInterface(BoundInterfaceMatcher::Unbound),
1831        FakeIpSocket {
1832            src_ip: Some(<I as TestIpExt>::TEST_ADDRS.local_ip.get()),
1833            dst_ip: Some(<I as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1834            proto: FakeTcpSocket {
1835                src_port: Some(80),
1836                dst_port: Some(12345),
1837                state: TcpSocketState::Established,
1838            },
1839            cookie: 0,
1840            intf: Some(FakeMatcherDeviceId::wlan_interface()),
1841            marks: Marks::default(),
1842        } => false;
1843        "bound_interface unbound no match"
1844    )]
1845    fn ip_socket_matcher<I: TestIpExt, T: MaybeSocketTransportProperties>(
1846        matcher: IpSocketMatcher<FakeDeviceClass>,
1847        socket: FakeIpSocket<I, T>,
1848    ) -> bool {
1849        matcher.matches(&socket)
1850    }
1851
1852    #[ip_test(I)]
1853    fn address_matcher_type<I: TestIpExt>() {
1854        let local_ip = I::TEST_ADDRS.local_ip.get();
1855        let remote_ip = I::TEST_ADDRS.remote_ip.get();
1856
1857        let matcher = AddressMatcherType::Subnet(SubnetMatcher(I::TEST_ADDRS.subnet));
1858        assert!(matcher.matches(&local_ip));
1859        assert!(!matcher.matches(&I::get_other_remote_ip_address(1)));
1860
1861        let matcher = AddressMatcherType::Range(local_ip..=remote_ip);
1862        assert!(matcher.matches(&local_ip));
1863        assert!(matcher.matches(&remote_ip));
1864        assert!(!matcher.matches(&I::get_other_remote_ip_address(1)));
1865    }
1866
1867    #[ip_test(I)]
1868    fn address_matcher<I: TestIpExt>() {
1869        let local_ip = I::TEST_ADDRS.local_ip.get();
1870        let remote_ip = I::TEST_ADDRS.remote_ip.get();
1871
1872        let matcher = AddressMatcher {
1873            matcher: AddressMatcherType::Subnet(SubnetMatcher(I::TEST_ADDRS.subnet)),
1874            invert: false,
1875        };
1876        assert!(matcher.matches(&local_ip));
1877        assert!(matcher.matches(&remote_ip));
1878        assert!(!matcher.matches(&I::get_other_remote_ip_address(1)));
1879
1880        let matcher = AddressMatcher {
1881            matcher: AddressMatcherType::Subnet(SubnetMatcher(I::TEST_ADDRS.subnet)),
1882            invert: true,
1883        };
1884        assert!(!matcher.matches(&local_ip));
1885        assert!(!matcher.matches(&remote_ip));
1886        assert!(matcher.matches(&I::get_other_remote_ip_address(1)));
1887
1888        let matcher = AddressMatcher {
1889            matcher: AddressMatcherType::Range(local_ip..=remote_ip),
1890            invert: false,
1891        };
1892        assert!(matcher.matches(&local_ip));
1893        assert!(matcher.matches(&remote_ip));
1894        assert!(!matcher.matches(&I::get_other_remote_ip_address(1)));
1895
1896        let matcher = AddressMatcher {
1897            matcher: AddressMatcherType::Range(local_ip..=remote_ip),
1898            invert: true,
1899        };
1900        assert!(!matcher.matches(&local_ip));
1901        assert!(!matcher.matches(&remote_ip));
1902        assert!(matcher.matches(&I::get_other_remote_ip_address(1)));
1903    }
1904
1905    #[test]
1906    fn agnostic_address_matcher() {
1907        let v4_addr = IpAddr::V4(Ipv4Addr::new([192, 0, 2, 1]));
1908        let v6_addr = IpAddr::V6(Ipv6Addr::new([0x2001, 0xdb8, 0, 0, 0, 0, 0, 1]));
1909
1910        let v4_subnet = Subnet::new(Ipv4Addr::new([192, 0, 2, 0]), 24).unwrap();
1911        let v6_subnet = Subnet::new(Ipv6Addr::new([0x2001, 0xdb8, 0, 0, 0, 0, 0, 0]), 32).unwrap();
1912
1913        let v4_matcher =
1914            BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(AddressMatcher {
1915                matcher: AddressMatcherType::Subnet(SubnetMatcher(v4_subnet)),
1916                invert: false,
1917            }));
1918        assert!(v4_matcher.matches(&Some(v4_addr)));
1919        assert!(!v4_matcher.matches(&Some(v6_addr)));
1920
1921        let v6_matcher =
1922            BoundAddressMatcherEither::Bound(AddressMatcherEither::V6(AddressMatcher {
1923                matcher: AddressMatcherType::Subnet(SubnetMatcher(v6_subnet)),
1924                invert: false,
1925            }));
1926        assert!(!v6_matcher.matches(&Some(v4_addr)));
1927        assert!(v6_matcher.matches(&Some(v6_addr)));
1928    }
1929
1930    #[test_case(IpSocketMatcher::Family(IpVersion::V4) => true; "v4 family matcher on v4 socket")]
1931    #[test_case(IpSocketMatcher::Family(IpVersion::V6) => false; "v6 family matcher on v4 socket")]
1932    #[test_case(IpSocketMatcher::SrcAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(
1933        AddressMatcher {
1934            matcher: AddressMatcherType::Subnet(SubnetMatcher(Ipv4::TEST_ADDRS.subnet)),
1935            invert: false,
1936        }
1937    ))) => true; "src_addr match")]
1938    #[test_case(IpSocketMatcher::SrcAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(
1939        AddressMatcher {
1940            matcher: AddressMatcherType::Subnet(SubnetMatcher(
1941                Subnet::new(Ipv4Addr::new([0, 0, 0, 0]), 32).unwrap()
1942            )),
1943            invert: false,
1944        }
1945    ))) => false; "src_addr no match")]
1946    #[test_case(IpSocketMatcher::DstAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(
1947        AddressMatcher {
1948            matcher: AddressMatcherType::Subnet(SubnetMatcher(Ipv4::TEST_ADDRS.subnet)),
1949            invert: false,
1950        }
1951    ))) => true; "dst_addr match")]
1952    #[test_case(IpSocketMatcher::DstAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(
1953        AddressMatcher {
1954            matcher: AddressMatcherType::Subnet(SubnetMatcher(
1955                Subnet::new(Ipv4Addr::new([0, 0, 0, 0]), 32).unwrap()
1956            )),
1957        invert: false,
1958    }))) => false; "dst_addr no match")]
1959    #[test_case(
1960        IpSocketMatcher::SrcAddr(BoundAddressMatcherEither::Unbound) => false;
1961        "src_addr unbound mismatch"
1962    )]
1963    #[test_case(
1964        IpSocketMatcher::DstAddr(BoundAddressMatcherEither::Unbound) => false;
1965        "dst_addr unbound mismatch"
1966    )]
1967    fn ip_socket_matcher_test_v4(matcher: IpSocketMatcher<FakeDeviceClass>) -> bool {
1968        let socket = FakeIpSocket::<Ipv4, _> {
1969            src_ip: Some(<Ipv4 as TestIpExt>::TEST_ADDRS.local_ip.get()),
1970            dst_ip: Some(<Ipv4 as TestIpExt>::TEST_ADDRS.remote_ip.get()),
1971            proto: FakeTcpSocket {
1972                src_port: Some(80),
1973                dst_port: Some(12345),
1974                state: TcpSocketState::Established,
1975            },
1976            cookie: 0,
1977            intf: None,
1978            marks: Marks::default(),
1979        };
1980        matcher.matches(&socket)
1981    }
1982
1983    #[test_case(IpSocketMatcher::Family(IpVersion::V4) => false; "v4 family matcher on v6 socket")]
1984    #[test_case(IpSocketMatcher::Family(IpVersion::V6) => true; "v6 family matcher on v6 socket")]
1985    #[test_case(IpSocketMatcher::SrcAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V6(
1986        AddressMatcher {
1987            matcher: AddressMatcherType::Subnet(SubnetMatcher(Ipv6::TEST_ADDRS.subnet)),
1988            invert: false,
1989        }
1990    ))) => true; "src_addr match v6")]
1991    #[test_case(IpSocketMatcher::SrcAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V6(
1992        AddressMatcher {
1993            matcher: AddressMatcherType::Subnet(SubnetMatcher(
1994                Subnet::new(Ipv6Addr::new([0; 8]), 128).unwrap()
1995            )),
1996            invert: false,
1997        }
1998    ))) => false; "src_addr no match v6")]
1999    #[test_case(IpSocketMatcher::DstAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V6(
2000        AddressMatcher {
2001            matcher: AddressMatcherType::Subnet(SubnetMatcher(Ipv6::TEST_ADDRS.subnet)),
2002            invert: false,
2003        }
2004    ))) => true; "dst_addr match v6")]
2005    #[test_case(IpSocketMatcher::DstAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V6(
2006        AddressMatcher {
2007            matcher: AddressMatcherType::Subnet(SubnetMatcher(
2008                Subnet::new(Ipv6Addr::new([0; 8]), 128).unwrap()
2009            )),
2010            invert: false,
2011        }
2012    ))) => false; "dst_addr no match v6")]
2013    fn ip_socket_matcher_test_v6(matcher: IpSocketMatcher<FakeDeviceClass>) -> bool {
2014        let socket = FakeIpSocket::<Ipv6, _> {
2015            src_ip: Some(<Ipv6 as TestIpExt>::TEST_ADDRS.local_ip.get()),
2016            dst_ip: Some(<Ipv6 as TestIpExt>::TEST_ADDRS.remote_ip.get()),
2017            proto: FakeTcpSocket {
2018                src_port: Some(80),
2019                dst_port: Some(12345),
2020                state: TcpSocketState::Established,
2021            },
2022            cookie: 0,
2023            intf: None,
2024            marks: Marks::default(),
2025        };
2026        matcher.matches(&socket)
2027    }
2028
2029    #[test_case(
2030        IpSocketMatcher::SrcAddr(BoundAddressMatcherEither::Unbound) => true;
2031        "src_addr unbound match"
2032    )]
2033    #[test_case(IpSocketMatcher::SrcAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(
2034        AddressMatcher {
2035            matcher: AddressMatcherType::Subnet(SubnetMatcher(Ipv4::TEST_ADDRS.subnet)),
2036            invert: false,
2037        }
2038    ))) => false; "src_addr bound mismatch")]
2039    #[test_case(
2040        IpSocketMatcher::DstAddr(BoundAddressMatcherEither::Unbound) => true;
2041        "dst_addr unbound match"
2042    )]
2043    #[test_case(IpSocketMatcher::DstAddr(BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(
2044        AddressMatcher {
2045            matcher: AddressMatcherType::Subnet(SubnetMatcher(Ipv4::TEST_ADDRS.subnet)),
2046            invert: false,
2047        }
2048    ))) => false; "dst_addr bound mismatch")]
2049
2050    fn ip_socket_matcher_unbound(matcher: IpSocketMatcher<FakeDeviceClass>) -> bool {
2051        let socket = FakeIpSocket::<Ipv4, _> {
2052            src_ip: None,
2053            dst_ip: None,
2054            proto: FakeTcpSocket {
2055                src_port: Some(80),
2056                dst_port: Some(12345),
2057                state: TcpSocketState::Established,
2058            },
2059            cookie: 0,
2060            intf: None,
2061            marks: Marks::default(),
2062        };
2063        matcher.matches(&socket)
2064    }
2065}