1pub mod announce_proc;
2pub mod announce_queue;
3pub mod announce_verify_queue;
4pub mod dedup;
5pub mod destination_filter;
6pub mod inbound;
7pub mod ingress_control;
8pub mod jobs;
9pub mod outbound;
10pub mod path_requests;
11pub mod pathfinder;
12pub mod persistence;
13pub mod queries;
14pub mod rate_limit;
15pub mod retention;
16pub mod tables;
17pub mod tunnel;
18pub mod types;
19
20use alloc::collections::{BTreeMap, BTreeSet, VecDeque};
21use alloc::string::String;
22use alloc::vec::Vec;
23use core::mem::size_of;
24
25use rns_crypto::Rng;
26
27use crate::announce::AnnounceData;
28use crate::constants;
29use crate::hash;
30use crate::packet::RawPacket;
31
32use self::announce_proc::compute_path_expires;
33use self::announce_queue::AnnounceQueues;
34use self::announce_verify_queue::{AnnounceVerifyKey, AnnounceVerifyQueue, PendingAnnounce};
35use self::dedup::{AnnounceSignatureCache, PacketHashlist};
36use self::inbound::{
37 clamp_forwarded_link_request_mtu, create_link_entry, create_reverse_entry,
38 forward_transport_packet, route_proof_via_reverse, route_via_link_table, LocalHopRewrite,
39};
40use self::ingress_control::IngressControl;
41use self::outbound::{route_outbound_into, should_transmit_announce, OutboundRouteOptions};
42use self::pathfinder::{
43 extract_random_blob, timebase_from_random_blob, trusted_timebase_from_random_blobs,
44 MultiPathDecision,
45};
46use self::rate_limit::AnnounceRateLimiter;
47use self::tables::{AnnounceEntry, DiscoveryPathRequest, LinkEntry, PathEntry, PathSet};
48use self::tunnel::TunnelTable;
49use self::types::{
50 BlackholeEntry, InterfaceId, InterfaceInfo, PacketBytes, StampRequirements, TransportAction,
51 TransportConfig,
52};
53
54pub type PathTableRow = ([u8; 16], f64, [u8; 16], u8, f64, f64, String);
55pub type RateTableRow = ([u8; 16], f64, u32, f64, Vec<f64>);
56pub type LrproofRebalanceCandidate = ([u8; 16], [u8; 16], u8, Vec<u8>);
58
59fn lrproof_hop_mismatch_diagnostic(packet_hops: u8, entry: &LinkEntry) -> String {
60 alloc::format!(
61 "Received link request proof with hop mismatch ({}/{}:{}->{}), not transporting it",
62 packet_hops,
63 entry.remaining_hops,
64 entry.next_hop_interface.0,
65 entry.received_interface.0,
66 )
67}
68
69fn link_route_hops_match(
70 packet_hops: u8,
71 entry: &LinkEntry,
72 receiving_interface: InterfaceId,
73) -> bool {
74 if entry.next_hop_interface == entry.received_interface {
75 packet_hops == entry.remaining_hops || packet_hops == entry.taken_hops
76 } else if receiving_interface == entry.next_hop_interface {
77 packet_hops == entry.remaining_hops
78 } else if receiving_interface == entry.received_interface {
79 packet_hops == entry.taken_hops
80 } else {
81 true
83 }
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Default)]
87pub struct RxMetadata {
88 pub rssi: Option<i16>,
89 pub snr: Option<f32>,
90}
91
92#[derive(Debug, Clone, Copy, PartialEq)]
93pub struct InboundFrame<'a> {
94 pub raw: &'a [u8],
95 pub iface: InterfaceId,
96 pub now: f64,
97 pub rx: RxMetadata,
98}
99
100impl<'a> InboundFrame<'a> {
101 pub fn new(raw: &'a [u8], iface: InterfaceId, now: f64) -> Self {
102 Self {
103 raw,
104 iface,
105 now,
106 rx: RxMetadata::default(),
107 }
108 }
109
110 pub fn with_rx(mut self, rx: RxMetadata) -> Self {
111 self.rx = rx;
112 self
113 }
114}
115
116pub struct DecodedPacket {
119 packet: RawPacket<PacketBytes>,
120 hash_deferred: bool,
124}
125
126impl DecodedPacket {
127 pub fn unpack(raw: &[u8]) -> Result<Self, crate::packet::PacketError> {
128 Self::unpack_shared(PacketBytes::from(raw))
129 }
130
131 pub fn unpack_owned(raw: Vec<u8>) -> Result<Self, crate::packet::PacketError> {
133 Self::unpack_shared(PacketBytes::from(raw))
134 }
135
136 pub fn unpack_shared(raw: PacketBytes) -> Result<Self, crate::packet::PacketError> {
138 RawPacket::unpack_shared(raw).map(Self::hashed)
139 }
140
141 fn hashed(packet: RawPacket<PacketBytes>) -> Self {
142 Self {
143 packet,
144 hash_deferred: false,
145 }
146 }
147
148 pub fn packet(&self) -> &RawPacket<PacketBytes> {
151 &self.packet
152 }
153
154 pub fn packet_hash(&self) -> Option<&[u8; 32]> {
156 (!self.hash_deferred).then_some(&self.packet.packet_hash)
157 }
158}
159
160pub struct DecodedInboundFrame {
162 pub decoded: DecodedPacket,
163 pub iface: InterfaceId,
164 pub now: f64,
165 pub rx: RxMetadata,
166}
167
168struct InboundPacketCtx {
169 packet: RawPacket<PacketBytes>,
170 hash_deferred: bool,
173 original_raw: Option<PacketBytes>,
174 iface: InterfaceId,
175 now: f64,
176 from_local_client: bool,
177}
178
179struct VerifiedAnnounceCtx<'a> {
180 packet: &'a RawPacket<PacketBytes>,
181 original_raw: &'a [u8],
182 iface: InterfaceId,
183 now: f64,
184 validated: crate::announce::ValidatedAnnounce,
185 received_from: [u8; 16],
186 random_blob: [u8; 10],
187 announce_emitted: u64,
188}
189
190struct TickCtx<'a> {
191 now: f64,
192 rng: &'a mut dyn Rng,
193 actions: Vec<TransportAction>,
194}
195
196#[doc(hidden)]
201pub struct AcceptedPathRequest {
202 tag: [u8; 16],
203 tag_len: usize,
204 interface_id: InterfaceId,
205 now: f64,
206 destination_hash: [u8; 16],
207 already_in_flight: bool,
208 ext_payload: Option<[u8; constants::PR_EXT_PAYLOAD_LENGTH]>,
211 stamp_value: Option<crate::stamp::StampValue>,
214 stamped: bool,
216}
217
218impl AcceptedPathRequest {
219 pub fn stamp_value(&self) -> Option<crate::stamp::StampValue> {
221 self.stamp_value
222 }
223
224 pub fn stamped(&self) -> bool {
226 self.stamped
227 }
228}
229
230pub struct TransportEngine {
235 config: TransportConfig,
236 path_table: BTreeMap<[u8; 16], PathSet>,
237 announce_table: BTreeMap<[u8; 16], AnnounceEntry>,
238 reverse_table: tables::ReverseTable,
239 link_table: BTreeMap<[u8; 16], LinkEntry>,
240 held_announces: BTreeMap<[u8; 16], AnnounceEntry>,
241 packet_hashlist: PacketHashlist,
242 announce_sig_cache: AnnounceSignatureCache,
243 rate_limiter: AnnounceRateLimiter,
244 path_states: BTreeMap<[u8; 16], u8>,
245 interfaces: BTreeMap<InterfaceId, InterfaceInfo>,
246 interface_hashes: BTreeMap<InterfaceId, [u8; 32]>,
247 local_destinations: BTreeMap<[u8; 16], u8>,
248 blackholed_identities: BTreeMap<[u8; 16], BlackholeEntry>,
249 announce_queues: AnnounceQueues,
250 ingress_control: IngressControl,
251 tunnel_table: TunnelTable,
252 discovery_pr_tags: VecDeque<[u8; 32]>,
253 discovery_pr_tag_set: BTreeSet<[u8; 32]>,
254 path_requests: BTreeMap<[u8; 16], f64>,
255 stamp_prs: bool,
259 stamp_requirements: StampRequirements,
262 destination_filter: destination_filter::DestinationTypeFilter,
265 control_destinations: [[u8; 16]; 2],
269 discovery_path_requests: BTreeMap<[u8; 16], DiscoveryPathRequest>,
270 discovery_path_request_deadlines: BTreeMap<[u8; 16], f64>,
271 pending_local_path_requests: BTreeMap<[u8; 16], (InterfaceId, f64)>,
275 pending_discovery_prs: VecDeque<([u8; 16], Option<InterfaceId>)>,
279 discovery_pr_next_tx: f64,
281 path_destination_cap_evict_count: usize,
282 announces_last_checked: f64,
284 tables_last_culled: f64,
285}
286
287mod engine_state;
288mod inbound_engine;
289mod maintenance;
290mod outbound_engine;
291
292#[cfg(test)]
293mod tests;