Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_shield/src/srv/guard/addr.rs

3.6 KiB, 42 runs

created by r1870400018:864, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1//! SHIELD-side handshake layer on top of the generic
2//! [`oxedyne_fe2o3_net::guard::addr::AddressGuard`].
3//!
4//! The rate-limiter, throttle, and blacklist state machine now lives generically in
5//! `fe2o3_net`. This module keeps only the parts that are specific to the SHIELD UDP wire
6//! protocol -- the three-step HReq1 then HReq2 then HReq3 handshake-sequence check -- and
7//! layers them onto the generic guard via [`AddressGuard::update_log`].
8
9use crate::srv::{
10 guard::data::AddressData,
11 msg::{
12 core::MsgType,
13 handshake::HandshakeType,
14 },
15};
16
17use oxedyne_fe2o3_core::{
18 prelude::*,
19 map::MapMut,
20};
21use oxedyne_fe2o3_iop_hash::api::{
22 Hasher,
23 HashForm,
24};
25use oxedyne_fe2o3_net::guard::addr::{
26 AddressGuard,
27 AddressLog,
28};
29
30use std::{
31 fmt::Debug,
32 net::SocketAddr,
33 time::{
34 Duration,
35 SystemTime,
36 },
37};
38
39pub fn drop_packet<
40 const C: usize,
41 M: MapMut<HashForm, AddressLog<N, AddressData>> + Clone + Debug,
42 H: Hasher + Send + Sync + 'static,
43 const S: usize,
44 const N: usize,
45>(
46 guard: &AddressGuard<C, M, H, S, N, AddressData>,
47 hreq_exp: Duration,
48 msg_typ: MsgType,
49 src_addr: &SocketAddr,
50)
51 -> Outcome<bool>
52{
53 let htyp = HandshakeType::from(msg_typ);
54 let ip = src_addr.ip();
55
56 // Pre-check: an unknown address may only open the handshake with an HReq1. Drop a later
57 // step otherwise, without polluting the guard with a fresh log entry.
58 if htyp != HandshakeType::Unknown
59 && htyp != HandshakeType::Req1
60 && res!(guard.peek(&ip)).is_none()
61 {
62 return Ok(true);
63 }
64
65 // Feed the generic state machine. Under the same shard lock, validate the handshake
66 // sequence on the shield-specific `AddressData`.
67 let (decision, hs_drop) = res!(guard.update_log(&ip, |log, _was_new| {
68 if htyp == HandshakeType::Unknown {
69 // Not a handshake step, so there is no sequence to be out of.
70 return Ok(false);
71 }
72 let pending = log.data.pending;
73 match pending {
74 Some((typ, when)) => {
75 match when.elapsed() {
76 Ok(wait) if wait > hreq_exp => {
77 // Pending step expired: treat this packet as a fresh sequence start.
78 log.data.pending = None;
79 if htyp == HandshakeType::Req1 {
80 log.data.pending =
81 Some((HandshakeType::Req1, SystemTime::now()));
82 }
83 },
84 _ => match typ {
85 HandshakeType::Req1 => {
86 if !htyp.is_hreq2() {
87 return Ok(true);
88 }
89 log.data.pending = Some((htyp, SystemTime::now()));
90 },
91 HandshakeType::Req2 => {
92 if htyp != HandshakeType::Req3 {
93 return Ok(true);
94 }
95 log.data.pending = None;
96 },
97 _ => (),
98 },
99 }
100 },
101 None => match htyp {
102 HandshakeType::Req1 => {
103 log.data.pending = Some((HandshakeType::Req1, SystemTime::now()));
104 },
105 HandshakeType::Req2 | HandshakeType::Req3 => return Ok(true),
106 _ => (),
107 },
108 }
109 Ok(false)
110 }));
111
112 Ok(decision.should_drop() || hs_drop)
113}