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