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