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