nym_gateway_client/
traits.rs

1// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
2// SPDX-License-Identifier: Apache-2.0
3
4use nym_sphinx::addressing::nodes::MAX_NODE_ADDRESS_UNPADDED_LEN;
5use nym_sphinx::params::PacketSize;
6use tracing::{error, trace, warn};
7
8pub trait GatewayPacketRouter {
9    type Error: std::error::Error;
10
11    fn route_received(&self, unwrapped_packets: Vec<Vec<u8>>) -> Result<(), Self::Error> {
12        let mut received_messages = Vec::new();
13        let mut received_acks = Vec::new();
14
15        // remember: gateway removes final layer of sphinx encryption and from the unwrapped
16        // data he takes the SURB-ACK and first hop address.
17        // currently SURB-ACKs are attached in EVERY packet, even cover, so this is always true
18        let sphinx_ack_overhead = PacketSize::AckPacket.size() + MAX_NODE_ADDRESS_UNPADDED_LEN;
19        let outfox_ack_overhead =
20            PacketSize::OutfoxAckPacket.size() + MAX_NODE_ADDRESS_UNPADDED_LEN;
21
22        for received_packet in unwrapped_packets {
23            // note: if we ever fail to route regular outfox, it might be because I've removed a match on
24            // `size == PacketSize::OutfoxRegularPacket.size() - outfox_ack_overhead` since it seemed
25            // redundant given we have `size == PacketSize::OutfoxRegularPacket.plaintext_size() - outfox_ack_overhead`
26            // and all the headers should have already be stripped at this point
27            match received_packet.len() {
28                n if n == PacketSize::AckPacket.plaintext_size() => {
29                    trace!("received sphinx ack");
30                    received_acks.push(received_packet);
31                }
32
33                n if n <= PacketSize::OutfoxAckPacket.plaintext_size() => {
34                    // we don't know the real size of the payload, it could be anything <= 48 bytes
35                    trace!("received outfox ack");
36                    received_acks.push(received_packet);
37                }
38
39                n if n == PacketSize::RegularPacket.plaintext_size() - sphinx_ack_overhead => {
40                    trace!("received regular sphinx packet");
41                    received_messages.push(received_packet);
42                }
43
44                n if n
45                    == PacketSize::OutfoxRegularPacket
46                        .plaintext_size()
47                        .saturating_sub(outfox_ack_overhead) =>
48                {
49                    trace!("received regular outfox packet");
50                    received_messages.push(received_packet);
51                }
52
53                n if n == PacketSize::ExtendedPacket8.plaintext_size() - sphinx_ack_overhead => {
54                    trace!("received extended8 packet");
55                    received_messages.push(received_packet);
56                }
57
58                n if n == PacketSize::ExtendedPacket16.plaintext_size() - sphinx_ack_overhead => {
59                    trace!("received extended16 packet");
60                    received_messages.push(received_packet);
61                }
62
63                n if n == PacketSize::ExtendedPacket32.plaintext_size() - sphinx_ack_overhead => {
64                    trace!("received extended32 packet");
65                    received_messages.push(received_packet);
66                }
67
68                n => {
69                    // this can happen if other clients are not padding their messages
70                    warn!("Received message of unexpected size. Probably from an outdated client... len: {n}");
71                    received_messages.push(received_packet);
72                }
73            }
74        }
75
76        if !received_messages.is_empty() {
77            trace!("routing {} received packets", received_messages.len());
78            if let Err(err) = self.route_mixnet_messages(received_messages) {
79                error!("failed to route received messages: {err}");
80                return Err(err);
81            }
82        }
83
84        if !received_acks.is_empty() {
85            trace!("routing {} received acks", received_acks.len());
86            if let Err(err) = self.route_acks(received_acks) {
87                error!("failed to route received acks: {err}");
88                return Err(err);
89            }
90        }
91
92        Ok(())
93    }
94
95    fn route_mixnet_messages(&self, received_messages: Vec<Vec<u8>>) -> Result<(), Self::Error>;
96
97    fn route_acks(&self, received_acks: Vec<Vec<u8>>) -> Result<(), Self::Error>;
98}