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