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