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 | |
| 9 | use crate::srv::{ |
| 10 | guard::data::AddressData, |
| 11 | msg::{ |
| 12 | core::MsgType, |
| 13 | handshake::HandshakeType, |
| 14 | }, |
| 15 | }; |
| 16 | |
| 17 | use oxedyne_fe2o3_core::{ |
| 18 | prelude::*, |
| 19 | map::MapMut, |
| 20 | }; |
| 21 | use oxedyne_fe2o3_iop_hash::api::{ |
| 22 | Hasher, |
| 23 | HashForm, |
| 24 | }; |
| 25 | use oxedyne_fe2o3_net::guard::addr::{ |
| 26 | AddressGuard, |
| 27 | AddressLog, |
| 28 | }; |
| 29 | |
| 30 | use std::{ |
| 31 | fmt::Debug, |
| 32 | net::SocketAddr, |
| 33 | time::{ |
| 34 | Duration, |
| 35 | SystemTime, |
| 36 | }, |
| 37 | }; |
| 38 | |
| 39 | pub 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 | } |