1use alloc::vec::Vec;
2
3use super::tables::{LinkEntry, ReverseEntry};
4use super::types::{InterfaceId, TransportAction};
5use crate::constants;
6use crate::link::handshake::compute_link_id;
7use crate::packet::RawPacket;
8
9#[derive(Debug, Clone, Copy, Default)]
10pub struct LocalHopRewrite {
11 pub local_hops_delta: u8,
12 pub from_local_client: bool,
13 pub skip_local_hops_delta: bool,
14}
15
16impl LocalHopRewrite {
17 fn hop_byte(self, packet: &RawPacket) -> u8 {
18 if self.local_hops_delta != 0 && self.from_local_client && !self.skip_local_hops_delta {
19 self.local_hops_delta
20 } else {
21 packet.hops
22 }
23 }
24}
25
26pub fn forward_transport_packet(
31 packet: &RawPacket,
32 next_hop: [u8; 16],
33 remaining_hops: u8,
34 _outbound_interface: InterfaceId,
35) -> Vec<u8> {
36 if remaining_hops > 1 || (remaining_hops == 1 && next_hop != packet.destination_hash) {
37 let mut new_raw = Vec::new();
40 new_raw.push(packet.raw[0]); new_raw.push(packet.hops); new_raw.extend_from_slice(&next_hop); new_raw.extend_from_slice(&packet.raw[(constants::TRUNCATED_HASHLENGTH / 8 + 2)..]);
45 new_raw
46 } else if remaining_hops == 1 {
47 let new_flags = (constants::HEADER_1 << 6)
49 | (constants::TRANSPORT_BROADCAST << 4)
50 | (packet.raw[0] & 0x0F);
51 let mut new_raw = Vec::new();
52 new_raw.push(new_flags);
53 new_raw.push(packet.hops);
54 new_raw.extend_from_slice(&packet.raw[(constants::TRUNCATED_HASHLENGTH / 8 + 2)..]);
55 new_raw
56 } else {
57 let new_flags = (constants::HEADER_1 << 6)
59 | (constants::TRANSPORT_BROADCAST << 4)
60 | (packet.raw[0] & 0x0F);
61 let mut new_raw = Vec::new();
62 new_raw.push(new_flags);
63 new_raw.push(packet.hops);
64 new_raw.extend_from_slice(&packet.raw[(constants::TRUNCATED_HASHLENGTH / 8 + 2)..]);
65 new_raw
66 }
67}
68
69pub fn create_link_entry(
71 packet: &RawPacket,
72 next_hop: [u8; 16],
73 outbound_interface: InterfaceId,
74 remaining_hops: u8,
75 receiving_interface: InterfaceId,
76 now: f64,
77 proof_timeout: f64,
78) -> ([u8; 16], LinkEntry) {
79 let hashable = packet.get_hashable_part();
83 let extra = if packet.data.len() > constants::LINK_ECPUBSIZE {
84 packet.data.len() - constants::LINK_ECPUBSIZE
85 } else {
86 0
87 };
88 let link_id = compute_link_id(&hashable, extra);
89
90 let entry = LinkEntry {
91 timestamp: now,
92 next_hop_transport_id: next_hop,
93 next_hop_interface: outbound_interface,
94 remaining_hops,
95 received_interface: receiving_interface,
96 taken_hops: packet.hops,
97 destination_hash: packet.destination_hash,
98 validated: false,
99 proof_timeout,
100 };
101
102 (link_id, entry)
103}
104
105pub fn create_reverse_entry(
107 packet: &RawPacket,
108 outbound_interface: InterfaceId,
109 receiving_interface: InterfaceId,
110 now: f64,
111) -> ([u8; 16], ReverseEntry) {
112 let truncated_hash = packet.get_truncated_hash();
113 let entry = ReverseEntry {
114 receiving_interface,
115 outbound_interface,
116 timestamp: now,
117 };
118 (truncated_hash, entry)
119}
120
121pub fn route_proof_via_reverse(
127 packet: &RawPacket,
128 reverse_entry: &ReverseEntry,
129 receiving_interface: InterfaceId,
130 hop_rewrite: LocalHopRewrite,
131) -> Option<TransportAction> {
132 if receiving_interface == reverse_entry.outbound_interface {
133 let mut new_raw = Vec::new();
134 new_raw.push(packet.raw[0]);
135 new_raw.push(hop_rewrite.hop_byte(packet));
136 new_raw.extend_from_slice(&packet.raw[2..]);
137
138 Some(TransportAction::SendOnInterface {
139 interface: reverse_entry.receiving_interface,
140 raw: new_raw.into(),
141 })
142 } else {
143 None
144 }
145}
146
147pub fn route_via_link_table(
151 packet: &RawPacket,
152 link_entry: &LinkEntry,
153 receiving_interface: InterfaceId,
154 hop_rewrite: LocalHopRewrite,
155) -> Option<(InterfaceId, Vec<u8>)> {
156 let outbound_interface;
157
158 if link_entry.next_hop_interface == link_entry.received_interface {
159 if packet.hops == link_entry.remaining_hops || packet.hops == link_entry.taken_hops {
161 outbound_interface = link_entry.next_hop_interface;
162 } else {
163 return None;
164 }
165 } else {
166 if receiving_interface == link_entry.next_hop_interface {
168 if packet.hops == link_entry.remaining_hops {
169 outbound_interface = link_entry.received_interface;
170 } else {
171 return None;
172 }
173 } else if receiving_interface == link_entry.received_interface {
174 if packet.hops == link_entry.taken_hops {
175 outbound_interface = link_entry.next_hop_interface;
176 } else {
177 return None;
178 }
179 } else {
180 return None;
181 }
182 }
183
184 let mut new_raw = Vec::new();
185 new_raw.push(packet.raw[0]);
186 new_raw.push(hop_rewrite.hop_byte(packet));
187 new_raw.extend_from_slice(&packet.raw[2..]);
188
189 Some((outbound_interface, new_raw))
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195 use crate::packet::PacketFlags;
196
197 fn make_h2_packet(dest: &[u8; 16], transport_id: &[u8; 16], hops: u8) -> RawPacket {
198 let flags = PacketFlags {
199 header_type: constants::HEADER_2,
200 context_flag: constants::FLAG_UNSET,
201 transport_type: constants::TRANSPORT_TRANSPORT,
202 destination_type: constants::DESTINATION_SINGLE,
203 packet_type: constants::PACKET_TYPE_DATA,
204 };
205 RawPacket::pack(
206 flags,
207 hops,
208 dest,
209 Some(transport_id),
210 constants::CONTEXT_NONE,
211 b"payload",
212 )
213 .unwrap()
214 }
215
216 #[test]
217 fn test_forward_transport_multi_hop() {
218 let dest = [0x11; 16];
219 let transport_id = [0x22; 16];
220 let next_hop = [0x33; 16];
221 let packet = make_h2_packet(&dest, &transport_id, 2);
222
223 let new_raw = forward_transport_packet(&packet, next_hop, 3, InterfaceId(1));
224
225 let flags = crate::packet::PacketFlags::unpack(new_raw[0]);
227 assert_eq!(flags.header_type, constants::HEADER_2);
228 assert_eq!(new_raw[1], 2);
230 assert_eq!(&new_raw[2..18], &next_hop);
232 assert_eq!(&new_raw[18..34], &dest);
234 }
235
236 #[test]
237 fn test_forward_transport_last_hop_strips_header() {
238 let dest = [0x11; 16];
239 let transport_id = [0x22; 16];
240 let packet = make_h2_packet(&dest, &transport_id, 3);
241
242 let new_raw = forward_transport_packet(&packet, dest, 1, InterfaceId(1));
243
244 let flags = crate::packet::PacketFlags::unpack(new_raw[0]);
246 assert_eq!(flags.header_type, constants::HEADER_1);
247 assert_eq!(flags.transport_type, constants::TRANSPORT_BROADCAST);
248 assert_eq!(&new_raw[2..18], &dest);
251 }
252
253 #[test]
254 fn test_forward_transport_one_hop_to_transport_keeps_header() {
255 let dest = [0x11; 16];
256 let transport_id = [0x22; 16];
257 let next_transport = [0x33; 16];
258 let packet = make_h2_packet(&dest, &transport_id, 3);
259
260 let new_raw = forward_transport_packet(&packet, next_transport, 1, InterfaceId(1));
261
262 let flags = crate::packet::PacketFlags::unpack(new_raw[0]);
263 assert_eq!(flags.header_type, constants::HEADER_2);
264 assert_eq!(flags.transport_type, constants::TRANSPORT_TRANSPORT);
265 assert_eq!(&new_raw[2..18], &next_transport);
266 assert_eq!(&new_raw[18..34], &dest);
267 }
268
269 #[test]
270 fn forward_transport_packet_strips_header_for_final_local_hop() {
271 let flags = PacketFlags {
272 header_type: constants::HEADER_2,
273 context_flag: constants::FLAG_UNSET,
274 transport_type: constants::TRANSPORT_TRANSPORT,
275 destination_type: constants::DESTINATION_SINGLE,
276 packet_type: constants::PACKET_TYPE_DATA,
277 };
278 let daemon_id = [0x42; 16];
279 let dest_hash = [0x99; 16];
280 let mut raw = Vec::new();
281 raw.push(flags.pack());
282 raw.push(0);
283 raw.extend_from_slice(&daemon_id);
284 raw.extend_from_slice(&dest_hash);
285 raw.push(constants::CONTEXT_NONE);
286 raw.extend_from_slice(b"hello");
287 let packet = RawPacket::unpack(&raw).unwrap();
288
289 let forwarded = forward_transport_packet(&packet, dest_hash, 0, InterfaceId(2));
290 let forwarded_flags = PacketFlags::unpack(forwarded[0]);
291 assert_eq!(forwarded_flags.header_type, constants::HEADER_1);
292 assert_eq!(
293 forwarded_flags.transport_type,
294 constants::TRANSPORT_BROADCAST
295 );
296 assert_eq!(&forwarded[2..18], &dest_hash);
297 assert_eq!(&forwarded[19..], b"hello");
298 }
299
300 #[test]
301 fn test_route_proof_correct_interface() {
302 let flags = PacketFlags {
303 header_type: constants::HEADER_1,
304 context_flag: constants::FLAG_UNSET,
305 transport_type: constants::TRANSPORT_BROADCAST,
306 destination_type: constants::DESTINATION_SINGLE,
307 packet_type: constants::PACKET_TYPE_PROOF,
308 };
309 let packet = RawPacket::pack(
310 flags,
311 2,
312 &[0xAA; 16],
313 None,
314 constants::CONTEXT_NONE,
315 &[0xBB; 32],
316 )
317 .unwrap();
318
319 let reverse = ReverseEntry {
320 receiving_interface: InterfaceId(1),
321 outbound_interface: InterfaceId(2),
322 timestamp: 100.0,
323 };
324
325 let action = route_proof_via_reverse(
326 &packet,
327 &reverse,
328 InterfaceId(2),
329 LocalHopRewrite::default(),
330 );
331 assert!(action.is_some());
332 match action.unwrap() {
333 TransportAction::SendOnInterface { interface, .. } => {
334 assert_eq!(interface, InterfaceId(1));
335 }
336 _ => panic!("Expected SendOnInterface"),
337 }
338 }
339
340 #[test]
341 fn test_route_proof_wrong_interface() {
342 let flags = PacketFlags {
343 header_type: constants::HEADER_1,
344 context_flag: constants::FLAG_UNSET,
345 transport_type: constants::TRANSPORT_BROADCAST,
346 destination_type: constants::DESTINATION_SINGLE,
347 packet_type: constants::PACKET_TYPE_PROOF,
348 };
349 let packet = RawPacket::pack(
350 flags,
351 2,
352 &[0xAA; 16],
353 None,
354 constants::CONTEXT_NONE,
355 &[0xBB; 32],
356 )
357 .unwrap();
358
359 let reverse = ReverseEntry {
360 receiving_interface: InterfaceId(1),
361 outbound_interface: InterfaceId(2),
362 timestamp: 100.0,
363 };
364
365 let action = route_proof_via_reverse(
367 &packet,
368 &reverse,
369 InterfaceId(3),
370 LocalHopRewrite::default(),
371 );
372 assert!(action.is_none());
373 }
374
375 #[test]
376 fn test_route_via_link_table_different_interfaces() {
377 let flags = PacketFlags {
378 header_type: constants::HEADER_1,
379 context_flag: constants::FLAG_UNSET,
380 transport_type: constants::TRANSPORT_BROADCAST,
381 destination_type: constants::DESTINATION_LINK,
382 packet_type: constants::PACKET_TYPE_DATA,
383 };
384 let packet = RawPacket::pack(
385 flags,
386 3,
387 &[0xAA; 16],
388 None,
389 constants::CONTEXT_NONE,
390 b"data",
391 )
392 .unwrap();
393
394 let link = LinkEntry {
395 timestamp: 100.0,
396 next_hop_transport_id: [0; 16],
397 next_hop_interface: InterfaceId(1),
398 remaining_hops: 3,
399 received_interface: InterfaceId(2),
400 taken_hops: 5,
401 destination_hash: [0xAA; 16],
402 validated: true,
403 proof_timeout: 200.0,
404 };
405
406 let result =
408 route_via_link_table(&packet, &link, InterfaceId(1), LocalHopRewrite::default());
409 assert!(result.is_some());
410 let (iface, _) = result.unwrap();
411 assert_eq!(iface, InterfaceId(2));
412
413 let packet2 = RawPacket::pack(
415 flags,
416 5,
417 &[0xAA; 16],
418 None,
419 constants::CONTEXT_NONE,
420 b"data",
421 )
422 .unwrap();
423 let result2 =
424 route_via_link_table(&packet2, &link, InterfaceId(2), LocalHopRewrite::default());
425 assert!(result2.is_some());
426 let (iface2, _) = result2.unwrap();
427 assert_eq!(iface2, InterfaceId(1));
428 }
429
430 #[test]
431 fn test_route_via_link_table_wrong_hops() {
432 let flags = PacketFlags {
433 header_type: constants::HEADER_1,
434 context_flag: constants::FLAG_UNSET,
435 transport_type: constants::TRANSPORT_BROADCAST,
436 destination_type: constants::DESTINATION_LINK,
437 packet_type: constants::PACKET_TYPE_DATA,
438 };
439 let packet = RawPacket::pack(
441 flags,
442 99,
443 &[0xAA; 16],
444 None,
445 constants::CONTEXT_NONE,
446 b"data",
447 )
448 .unwrap();
449
450 let link = LinkEntry {
451 timestamp: 100.0,
452 next_hop_transport_id: [0; 16],
453 next_hop_interface: InterfaceId(1),
454 remaining_hops: 3,
455 received_interface: InterfaceId(2),
456 taken_hops: 5,
457 destination_hash: [0xAA; 16],
458 validated: true,
459 proof_timeout: 200.0,
460 };
461
462 let result =
463 route_via_link_table(&packet, &link, InterfaceId(1), LocalHopRewrite::default());
464 assert!(result.is_none());
465 }
466}