1use core::fmt::Debug;
6
7use net_types::SpecifiedAddr;
8use net_types::ip::{IpVersion, Ipv4, Ipv6};
9
10pub use netstack3_base::socket::{EitherIpProto, SocketInfo};
11use netstack3_base::{
12 BindingsSyncTypes, GsoInfo, InstantBindingsTypes, InterfaceProperties, IpDeviceAddr,
13 IpDeviceAddressIdContext, MatcherBindingsTypes, RngContext, TimerBindingsTypes, TimerContext,
14 TxMetadataBindingsTypes,
15};
16pub use netstack3_base::{FrameDestination, LocalFrameDestination, Marks, PacketType};
17use packet::FragmentedByteSlice;
18use packet_formats::ip::IpExt;
19
20use crate::FilterIpExt;
21use crate::matchers::BindingsPacketMatcher;
22use crate::packets::FilterIpPacket;
23use crate::state::State;
24
25pub trait FilterBindingsTypes:
27 InstantBindingsTypes + MatcherBindingsTypes + TimerBindingsTypes + BindingsSyncTypes + 'static
28{
29}
30
31impl<BT> FilterBindingsTypes for BT where
32 BT: InstantBindingsTypes
33 + MatcherBindingsTypes
34 + TimerBindingsTypes
35 + BindingsSyncTypes
36 + 'static
37{
38}
39
40pub trait FilterBindingsContext<D>:
42 TimerContext + RngContext + FilterBindingsTypes<BindingsPacketMatcher: BindingsPacketMatcher<D>>
43{
44}
45impl<D, BC> FilterBindingsContext<D> for BC
46where
47 BC: TimerContext + RngContext + FilterBindingsTypes,
48 BC::BindingsPacketMatcher: BindingsPacketMatcher<D>,
49{
50}
51
52pub trait FilterIpContext<I: FilterIpExt, BT: FilterBindingsTypes>:
61 IpDeviceAddressIdContext<I, DeviceId: InterfaceProperties<BT::DeviceClass>>
62{
63 type NatCtx<'a>: NatContext<I, BT, DeviceId = Self::DeviceId, WeakAddressId = Self::WeakAddressId>;
66
67 fn with_filter_state<O, F: FnOnce(&State<I, Self::WeakAddressId, BT>) -> O>(
69 &mut self,
70 cb: F,
71 ) -> O {
72 self.with_filter_state_and_nat_ctx(|state, _ctx| cb(state))
73 }
74
75 fn with_filter_state_and_nat_ctx<
78 O,
79 F: FnOnce(&State<I, Self::WeakAddressId, BT>, &mut Self::NatCtx<'_>) -> O,
80 >(
81 &mut self,
82 cb: F,
83 ) -> O;
84}
85
86pub trait NatContext<I: IpExt, BT: FilterBindingsTypes>:
88 IpDeviceAddressIdContext<I, DeviceId: InterfaceProperties<BT::DeviceClass>>
89{
90 fn get_local_addr_for_remote(
92 &mut self,
93 device_id: &Self::DeviceId,
94 remote: Option<SpecifiedAddr<I::Addr>>,
95 ) -> Option<Self::AddressId>;
96
97 fn get_address_id(
100 &mut self,
101 device_id: &Self::DeviceId,
102 addr: IpDeviceAddr<I::Addr>,
103 ) -> Option<Self::AddressId>;
104}
105
106pub trait FilterContext<BT: FilterBindingsTypes>:
109 IpDeviceAddressIdContext<Ipv4, DeviceId: InterfaceProperties<BT::DeviceClass>>
110 + IpDeviceAddressIdContext<Ipv6, DeviceId: InterfaceProperties<BT::DeviceClass>>
111{
112 fn with_all_filter_state_mut<
114 O,
115 F: FnOnce(
116 &mut State<Ipv4, <Self as IpDeviceAddressIdContext<Ipv4>>::WeakAddressId, BT>,
117 &mut State<Ipv6, <Self as IpDeviceAddressIdContext<Ipv6>>::WeakAddressId, BT>,
118 ) -> O,
119 >(
120 &mut self,
121 cb: F,
122 ) -> O;
123}
124
125#[derive(Copy, Clone, Debug, Eq, PartialEq)]
127pub enum SocketEgressFilterResult {
128 Pass {
130 congestion: bool,
132 },
133
134 Drop {
136 congestion: bool,
138 },
139}
140
141#[derive(Copy, Clone, Debug, Eq, PartialEq)]
143pub enum SocketIngressFilterResult {
144 Accept,
146
147 Drop,
149}
150
151pub trait SocketOpsFilter<D> {
153 fn on_egress<I: FilterIpExt, P: FilterIpPacket<I>>(
155 &self,
156 packet: &P,
157 device: &D,
158 socket_info: SocketInfo,
159 marks: &Marks,
160 gso_info: Option<GsoInfo>,
161 ) -> SocketEgressFilterResult;
162
163 fn on_ingress(
165 &self,
166 ip_version: IpVersion,
167 packet: FragmentedByteSlice<'_, &[u8]>,
168 header_len: usize,
169 device: &D,
170 socket_info: SocketInfo,
171 marks: &Marks,
172 packet_type: PacketType,
173 gso_info: Option<GsoInfo>,
174 ) -> SocketIngressFilterResult;
175}
176
177pub trait SocketOpsFilterBindingContext<D>: TxMetadataBindingsTypes {
179 fn socket_ops_filter(&self) -> impl SocketOpsFilter<D>;
181}
182
183#[cfg(any(test, feature = "testutils"))]
184impl<
185 TimerId: Debug + PartialEq + Clone + Send + Sync + 'static,
186 Event: Debug + 'static,
187 State: 'static,
188 FrameMeta: 'static,
189 D,
190> SocketOpsFilterBindingContext<D>
191 for netstack3_base::testutil::FakeBindingsCtx<TimerId, Event, State, FrameMeta>
192{
193 fn socket_ops_filter(&self) -> impl SocketOpsFilter<D> {
194 crate::testutil::NoOpSocketOpsFilter
195 }
196}
197
198#[cfg(test)]
199pub(crate) mod testutil {
200 use alloc::sync::{Arc, Weak};
201 use alloc::vec::Vec;
202 use core::hash::{Hash, Hasher};
203 use core::ops::Deref;
204 use core::sync::atomic::AtomicUsize;
205 use core::time::Duration;
206
207 use derivative::Derivative;
208 use net_types::ip::{AddrSubnet, GenericOverIp, Ip};
209 use netstack3_base::testutil::{
210 FakeAtomicInstant, FakeCryptoRng, FakeDeviceClass, FakeInstant, FakeMatcherDeviceId,
211 FakeTimerCtx, FakeWeakDeviceId, WithFakeTimerContext,
212 };
213 use netstack3_base::{
214 AnyDevice, AssignedAddrIpExt, DeviceIdContext, InspectableValue, Inspector, InstantContext,
215 IntoCoreTimerCtx, IpAddressId, WeakIpAddressId,
216 };
217 use netstack3_hashmap::HashMap;
218
219 use super::*;
220 use crate::logic::FilterTimerId;
221 use crate::logic::nat::NatConfig;
222 use crate::state::validation::ValidRoutines;
223 use crate::state::{FilterPacketMetadata, IpRoutines, NatRoutines, OneWayBoolean, Routines};
224 use crate::{Interfaces, conntrack};
225
226 pub trait TestIpExt: FilterIpExt + AssignedAddrIpExt {}
227
228 impl<I: FilterIpExt + AssignedAddrIpExt> TestIpExt for I {}
229
230 #[derive(Debug)]
231 pub struct FakePrimaryAddressId<I: AssignedAddrIpExt>(
232 pub Arc<AddrSubnet<I::Addr, I::AssignedWitness>>,
233 );
234
235 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
236 pub struct FakeAddressId<I: AssignedAddrIpExt>(Arc<AddrSubnet<I::Addr, I::AssignedWitness>>);
237
238 #[derive(Clone, Debug)]
239 pub struct FakeWeakAddressId<I: AssignedAddrIpExt>(
240 pub Weak<AddrSubnet<I::Addr, I::AssignedWitness>>,
241 );
242
243 impl<I: AssignedAddrIpExt> PartialEq for FakeWeakAddressId<I> {
244 fn eq(&self, other: &Self) -> bool {
245 let Self(lhs) = self;
246 let Self(rhs) = other;
247 Weak::ptr_eq(lhs, rhs)
248 }
249 }
250
251 impl<I: AssignedAddrIpExt> Eq for FakeWeakAddressId<I> {}
252
253 impl<I: AssignedAddrIpExt> Hash for FakeWeakAddressId<I> {
254 fn hash<H: Hasher>(&self, state: &mut H) {
255 let Self(this) = self;
256 this.as_ptr().hash(state)
257 }
258 }
259
260 impl<I: AssignedAddrIpExt> WeakIpAddressId<I::Addr> for FakeWeakAddressId<I> {
261 type Strong = FakeAddressId<I>;
262
263 fn upgrade(&self) -> Option<Self::Strong> {
264 let Self(inner) = self;
265 inner.upgrade().map(FakeAddressId)
266 }
267
268 fn is_assigned(&self) -> bool {
269 let Self(inner) = self;
270 inner.strong_count() != 0
271 }
272 }
273
274 impl<I: AssignedAddrIpExt> InspectableValue for FakeWeakAddressId<I> {
275 fn record<Inspector: netstack3_base::Inspector>(
276 &self,
277 _name: &str,
278 _inspector: &mut Inspector,
279 ) {
280 unimplemented!()
281 }
282 }
283
284 impl<I: AssignedAddrIpExt> Deref for FakeAddressId<I> {
285 type Target = AddrSubnet<I::Addr, I::AssignedWitness>;
286
287 fn deref(&self) -> &Self::Target {
288 let Self(inner) = self;
289 inner.deref()
290 }
291 }
292
293 impl<I: AssignedAddrIpExt> IpAddressId<I::Addr> for FakeAddressId<I> {
294 type Weak = FakeWeakAddressId<I>;
295
296 fn downgrade(&self) -> Self::Weak {
297 let Self(inner) = self;
298 FakeWeakAddressId(Arc::downgrade(inner))
299 }
300
301 fn addr(&self) -> IpDeviceAddr<I::Addr> {
302 let Self(inner) = self;
303
304 #[derive(GenericOverIp)]
305 #[generic_over_ip(I, Ip)]
306 struct WrapIn<I: AssignedAddrIpExt>(I::AssignedWitness);
307 I::map_ip(
308 WrapIn(inner.addr()),
309 |WrapIn(v4_addr)| IpDeviceAddr::new_from_witness(v4_addr),
310 |WrapIn(v6_addr)| IpDeviceAddr::new_from_ipv6_device_addr(v6_addr),
311 )
312 }
313
314 fn addr_sub(&self) -> AddrSubnet<I::Addr, I::AssignedWitness> {
315 let Self(inner) = self;
316 **inner
317 }
318 }
319
320 pub struct FakeCtx<I: TestIpExt> {
321 state: State<I, FakeWeakAddressId<I>, FakeBindingsCtx<I>>,
322 nat: FakeNatCtx<I>,
323 }
324
325 #[derive(Derivative)]
326 #[derivative(Default(bound = ""))]
327 pub struct FakeNatCtx<I: TestIpExt> {
328 pub(crate) device_addrs: HashMap<FakeMatcherDeviceId, FakePrimaryAddressId<I>>,
329 }
330
331 impl<I: TestIpExt> FakeCtx<I> {
332 pub fn new(bindings_ctx: &mut FakeBindingsCtx<I>) -> Self {
333 Self {
334 state: State {
335 installed_routines: ValidRoutines::default(),
336 uninstalled_routines: Vec::default(),
337 conntrack: conntrack::Table::new::<IntoCoreTimerCtx>(bindings_ctx),
338 nat_installed: OneWayBoolean::default(),
339 },
340 nat: FakeNatCtx::default(),
341 }
342 }
343
344 pub fn with_ip_routines(
345 bindings_ctx: &mut FakeBindingsCtx<I>,
346 routines: IpRoutines<I, FakeBindingsCtx<I>, ()>,
347 ) -> Self {
348 let (installed_routines, uninstalled_routines) =
349 ValidRoutines::new(Routines { ip: routines, ..Default::default() })
350 .expect("invalid state");
351 Self {
352 state: State {
353 installed_routines,
354 uninstalled_routines,
355 conntrack: conntrack::Table::new::<IntoCoreTimerCtx>(bindings_ctx),
356 nat_installed: OneWayBoolean::default(),
357 },
358 nat: FakeNatCtx::default(),
359 }
360 }
361
362 pub fn with_nat_routines_and_device_addrs(
363 bindings_ctx: &mut FakeBindingsCtx<I>,
364 routines: NatRoutines<I, FakeBindingsCtx<I>, ()>,
365 device_addrs: impl IntoIterator<
366 Item = (FakeMatcherDeviceId, AddrSubnet<I::Addr, I::AssignedWitness>),
367 >,
368 ) -> Self {
369 let (installed_routines, uninstalled_routines) =
370 ValidRoutines::new(Routines { nat: routines, ..Default::default() })
371 .expect("invalid state");
372 Self {
373 state: State {
374 installed_routines,
375 uninstalled_routines,
376 conntrack: conntrack::Table::new::<IntoCoreTimerCtx>(bindings_ctx),
377 nat_installed: OneWayBoolean::TRUE,
378 },
379 nat: FakeNatCtx {
380 device_addrs: device_addrs
381 .into_iter()
382 .map(|(device, addr)| (device, FakePrimaryAddressId(Arc::new(addr))))
383 .collect(),
384 },
385 }
386 }
387
388 pub fn conntrack(
389 &mut self,
390 ) -> &conntrack::Table<
391 I,
392 NatConfig<I, FakeWeakAddressId<I>, FakeBindingsCtx<I>>,
393 FakeBindingsCtx<I>,
394 > {
395 &self.state.conntrack
396 }
397 }
398
399 impl<I: TestIpExt> DeviceIdContext<AnyDevice> for FakeCtx<I> {
400 type DeviceId = FakeMatcherDeviceId;
401 type WeakDeviceId = FakeWeakDeviceId<FakeMatcherDeviceId>;
402 }
403
404 impl<I: TestIpExt> IpDeviceAddressIdContext<I> for FakeCtx<I> {
405 type AddressId = FakeAddressId<I>;
406 type WeakAddressId = FakeWeakAddressId<I>;
407 }
408
409 impl<I: TestIpExt> FilterIpContext<I, FakeBindingsCtx<I>> for FakeCtx<I> {
410 type NatCtx<'a> = FakeNatCtx<I>;
411
412 fn with_filter_state_and_nat_ctx<
413 O,
414 F: FnOnce(&State<I, FakeWeakAddressId<I>, FakeBindingsCtx<I>>, &mut Self::NatCtx<'_>) -> O,
415 >(
416 &mut self,
417 cb: F,
418 ) -> O {
419 let Self { state, nat } = self;
420 cb(state, nat)
421 }
422 }
423
424 impl<I: TestIpExt> FakeNatCtx<I> {
425 pub fn new(
426 device_addrs: impl IntoIterator<
427 Item = (FakeMatcherDeviceId, AddrSubnet<I::Addr, I::AssignedWitness>),
428 >,
429 ) -> Self {
430 Self {
431 device_addrs: device_addrs
432 .into_iter()
433 .map(|(device, addr)| (device, FakePrimaryAddressId(Arc::new(addr))))
434 .collect(),
435 }
436 }
437 }
438
439 impl<I: TestIpExt> DeviceIdContext<AnyDevice> for FakeNatCtx<I> {
440 type DeviceId = FakeMatcherDeviceId;
441 type WeakDeviceId = FakeWeakDeviceId<FakeMatcherDeviceId>;
442 }
443
444 impl<I: TestIpExt> IpDeviceAddressIdContext<I> for FakeNatCtx<I> {
445 type AddressId = FakeAddressId<I>;
446 type WeakAddressId = FakeWeakAddressId<I>;
447 }
448
449 impl<I: TestIpExt> NatContext<I, FakeBindingsCtx<I>> for FakeNatCtx<I> {
450 fn get_local_addr_for_remote(
451 &mut self,
452 device_id: &Self::DeviceId,
453 _remote: Option<SpecifiedAddr<I::Addr>>,
454 ) -> Option<Self::AddressId> {
455 let FakePrimaryAddressId(primary) = self.device_addrs.get(device_id)?;
456 Some(FakeAddressId(primary.clone()))
457 }
458
459 fn get_address_id(
460 &mut self,
461 device_id: &Self::DeviceId,
462 addr: IpDeviceAddr<I::Addr>,
463 ) -> Option<Self::AddressId> {
464 let FakePrimaryAddressId(id) = self.device_addrs.get(device_id)?;
465 let id = FakeAddressId(id.clone());
466 if id.addr() == addr { Some(id) } else { None }
467 }
468 }
469
470 pub struct FakeBindingsCtx<I: Ip> {
471 pub timer_ctx: FakeTimerCtx<FilterTimerId<I>>,
472 pub rng: FakeCryptoRng,
473 }
474
475 impl<I: Ip> FakeBindingsCtx<I> {
476 pub(crate) fn new() -> Self {
477 Self { timer_ctx: FakeTimerCtx::default(), rng: FakeCryptoRng::default() }
478 }
479
480 pub(crate) fn sleep(&mut self, time_elapsed: Duration) {
481 self.timer_ctx.instant.sleep(time_elapsed)
482 }
483 }
484
485 impl<I: Ip> InstantBindingsTypes for FakeBindingsCtx<I> {
486 type Instant = FakeInstant;
487 type AtomicInstant = FakeAtomicInstant;
488 }
489
490 #[derive(Debug)]
491 pub struct FakeBindingsPacketMatcher {
492 num_calls: AtomicUsize,
493 result: bool,
494 }
495
496 impl FakeBindingsPacketMatcher {
497 pub fn new(result: bool) -> Arc<Self> {
498 Arc::new(Self { num_calls: AtomicUsize::new(0), result })
499 }
500
501 pub fn num_calls(&self) -> usize {
502 self.num_calls.load(core::sync::atomic::Ordering::SeqCst)
503 }
504 }
505
506 impl BindingsPacketMatcher<FakeMatcherDeviceId> for FakeBindingsPacketMatcher {
507 fn matches<I: FilterIpExt, P: FilterIpPacket<I>>(
508 &self,
509 _packet: &P,
510 _interfaces: Interfaces<'_, FakeMatcherDeviceId>,
511 _socket_info: &impl FilterPacketMetadata,
512 ) -> bool {
513 let _: usize = self.num_calls.fetch_add(1, core::sync::atomic::Ordering::SeqCst);
514 self.result
515 }
516 }
517
518 impl InspectableValue for FakeBindingsPacketMatcher {
519 fn record<I: Inspector>(&self, _name: &str, _inspector: &mut I) {
520 unimplemented!()
521 }
522 }
523
524 impl<I: Ip> MatcherBindingsTypes for FakeBindingsCtx<I> {
525 type DeviceClass = FakeDeviceClass;
526 type BindingsPacketMatcher = Arc<FakeBindingsPacketMatcher>;
527 }
528
529 impl<I: Ip> InstantContext for FakeBindingsCtx<I> {
530 fn now(&self) -> Self::Instant {
531 self.timer_ctx.now()
532 }
533 }
534
535 impl<I: Ip> TimerBindingsTypes for FakeBindingsCtx<I> {
536 type Timer = <FakeTimerCtx<FilterTimerId<I>> as TimerBindingsTypes>::Timer;
537 type DispatchId = <FakeTimerCtx<FilterTimerId<I>> as TimerBindingsTypes>::DispatchId;
538 type UniqueTimerId = <FakeTimerCtx<FilterTimerId<I>> as TimerBindingsTypes>::UniqueTimerId;
539 }
540
541 impl<I: Ip> TimerContext for FakeBindingsCtx<I> {
542 fn new_timer(&mut self, id: Self::DispatchId) -> Self::Timer {
543 self.timer_ctx.new_timer(id)
544 }
545
546 fn schedule_timer_instant(
547 &mut self,
548 time: Self::Instant,
549 timer: &mut Self::Timer,
550 ) -> Option<Self::Instant> {
551 self.timer_ctx.schedule_timer_instant(time, timer)
552 }
553
554 fn cancel_timer(&mut self, timer: &mut Self::Timer) -> Option<Self::Instant> {
555 self.timer_ctx.cancel_timer(timer)
556 }
557
558 fn scheduled_instant(&self, timer: &mut Self::Timer) -> Option<Self::Instant> {
559 self.timer_ctx.scheduled_instant(timer)
560 }
561
562 fn unique_timer_id(&self, timer: &Self::Timer) -> Self::UniqueTimerId {
563 self.timer_ctx.unique_timer_id(timer)
564 }
565 }
566
567 impl<I: Ip> WithFakeTimerContext<FilterTimerId<I>> for FakeBindingsCtx<I> {
568 fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<FilterTimerId<I>>) -> O>(
569 &self,
570 f: F,
571 ) -> O {
572 f(&self.timer_ctx)
573 }
574
575 fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<FilterTimerId<I>>) -> O>(
576 &mut self,
577 f: F,
578 ) -> O {
579 f(&mut self.timer_ctx)
580 }
581 }
582
583 impl<I: Ip> RngContext for FakeBindingsCtx<I> {
584 type Rng<'a>
585 = FakeCryptoRng
586 where
587 Self: 'a;
588
589 fn rng(&mut self) -> Self::Rng<'_> {
590 self.rng.clone()
591 }
592 }
593
594 impl<I: Ip> BindingsSyncTypes for FakeBindingsCtx<I> {
595 type Mutex = netstack3_base::sync::lock_impl::RawMutex;
596 type RwLock = netstack3_base::sync::lock_impl::RawRwLock;
597 type Once = netstack3_base::sync::lock_impl::Once;
598 }
599}