Skip to main content

emissary_core/primitives/
router_address.rs

1// Permission is hereby granted, free of charge, to any person obtaining a
2// copy of this software and associated documentation files (the "Software"),
3// to deal in the Software without restriction, including without limitation
4// the rights to use, copy, modify, merge, publish, distribute, sublicense,
5// and/or sell copies of the Software, and to permit persons to whom the
6// Software is furnished to do so, subject to the following conditions:
7//
8// The above copyright notice and this permission notice shall be included in
9// all copies or substantial portions of the Software.
10//
11// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
16// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17// DEALINGS IN THE SOFTWARE.
18
19use crate::{
20    crypto::{base64_encode, StaticPrivateKey},
21    error::parser::RouterAddressParseError,
22    primitives::{Date, Mapping, Str},
23};
24
25use bytes::{BufMut, BytesMut};
26use nom::{number::complete::be_u8, Err, IResult};
27
28use alloc::{string::ToString, vec::Vec};
29use core::{
30    net::{IpAddr, Ipv4Addr, SocketAddr},
31    str::FromStr,
32};
33
34/// Transport kind.
35#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
36pub enum TransportKind {
37    /// NTCP2.
38    Ntcp2,
39
40    /// SSU2.
41    Ssu2,
42}
43
44impl TryFrom<Str> for TransportKind {
45    type Error = ();
46
47    fn try_from(value: Str) -> Result<Self, Self::Error> {
48        if value.starts_with("SSU") {
49            return Ok(TransportKind::Ssu2);
50        }
51
52        if value.starts_with("NTCP2") {
53            return Ok(TransportKind::Ntcp2);
54        }
55
56        Err(())
57    }
58}
59
60impl TransportKind {
61    /// Serialize [`TransportKind`].
62    fn serialize(&self) -> Vec<u8> {
63        match self {
64            Self::Ntcp2 => Str::from("NTCP2").serialize(),
65            Self::Ssu2 => Str::from("SSU2").serialize(),
66        }
67    }
68}
69
70/// Router address.
71#[derive(Debug, Clone)]
72pub struct RouterAddress {
73    /// Router cost.
74    pub cost: u8,
75
76    /// When the router expires (always 0).
77    pub expires: Date,
78
79    /// Transport.
80    pub transport: TransportKind,
81
82    /// Options.
83    pub options: Mapping,
84
85    /// Router's socket address.
86    pub socket_address: Option<SocketAddr>,
87}
88
89impl RouterAddress {
90    /// Create new unpublished NTCP2 [`RouterAddress`].
91    pub fn new_unpublished_ntcp2(key: [u8; 32], port: u16) -> Self {
92        let static_key = StaticPrivateKey::from(key).public();
93        let key = base64_encode(&static_key);
94
95        let mut options = Mapping::default();
96        options.insert("v".into(), "2".into());
97        options.insert("s".into(), key.into());
98
99        Self {
100            cost: 14,
101            expires: Date::new(0),
102            transport: TransportKind::Ntcp2,
103            socket_address: Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port)),
104            options,
105        }
106    }
107
108    /// Create new unpublished NTCP2 [`RouterAddress`].
109    pub fn new_published_ntcp2(key: [u8; 32], iv: [u8; 16], port: u16, host: Ipv4Addr) -> Self {
110        let static_key = StaticPrivateKey::from(key).public();
111
112        let mut options = Mapping::default();
113        options.insert(Str::from("v"), Str::from("2"));
114        options.insert(Str::from("s"), Str::from(base64_encode(&static_key)));
115        options.insert(Str::from("host"), Str::from(host.to_string()));
116        options.insert(Str::from("port"), Str::from(port.to_string()));
117        options.insert(Str::from("i"), Str::from(base64_encode(iv)));
118
119        Self {
120            cost: 3,
121            expires: Date::new(0),
122            transport: TransportKind::Ntcp2,
123            options,
124            socket_address: Some(SocketAddr::new(IpAddr::V4(host), port)),
125        }
126    }
127
128    /// Create new unpublished SSU2 [`RouterAddress`].
129    pub fn new_unpublished_ssu2(static_key: [u8; 32], intro_key: [u8; 32], port: u16) -> Self {
130        let static_key = {
131            let static_key = StaticPrivateKey::from(static_key).public();
132            base64_encode(&static_key)
133        };
134        let intro_key = base64_encode(intro_key);
135
136        let mut options = Mapping::default();
137        options.insert(Str::from_str("v").unwrap(), Str::from_str("2").unwrap());
138        options.insert(
139            Str::from_str("s").unwrap(),
140            Str::from_str(&static_key).unwrap(),
141        );
142        options.insert(
143            Str::from_str("i").unwrap(),
144            Str::from_str(&intro_key).unwrap(),
145        );
146
147        Self {
148            cost: 14,
149            expires: Date::new(0),
150            transport: TransportKind::Ssu2,
151            socket_address: Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port)),
152            options,
153        }
154    }
155
156    /// Create new unpublished SSU2 [`RouterAddress`].
157    pub fn new_published_ssu2(
158        static_key: [u8; 32],
159        intro_key: [u8; 32],
160        port: u16,
161        host: Ipv4Addr,
162    ) -> Self {
163        let static_key = {
164            let static_key = StaticPrivateKey::from(static_key).public();
165            base64_encode(&static_key)
166        };
167        let intro_key = base64_encode(intro_key);
168
169        let mut options = Mapping::default();
170        options.insert(Str::from("v"), Str::from("2"));
171        options.insert(
172            Str::from_str("s").unwrap(),
173            Str::from_str(&static_key).unwrap(),
174        );
175        options.insert(
176            Str::from_str("i").unwrap(),
177            Str::from_str(&intro_key).unwrap(),
178        );
179        options.insert(Str::from("host"), Str::from(host.to_string()));
180        options.insert(Str::from("port"), Str::from(port.to_string()));
181
182        Self {
183            cost: 8,
184            expires: Date::new(0),
185            transport: TransportKind::Ssu2,
186            options,
187            socket_address: Some(SocketAddr::new(IpAddr::V4(host), port)),
188        }
189    }
190
191    /// Parse [`RouterAddress`] from `input`, returning rest of `input` and parsed address.
192    pub fn parse_frame(input: &[u8]) -> IResult<&[u8], RouterAddress, RouterAddressParseError> {
193        let (rest, cost) = be_u8(input)?;
194        let (rest, expires) = Date::parse_frame(rest)
195            .map_err(|_| Err::Error(RouterAddressParseError::InvalidExpiration))?;
196        let (rest, transport) = Str::parse_frame(rest)
197            .map_err(|_| Err::Error(RouterAddressParseError::InvalidTransport))?;
198        let (rest, options) = Mapping::parse_frame(rest).map_err(Err::convert)?;
199        let socket_address: Option<SocketAddr> = {
200            let maybe_host = options.get(&Str::from("host"));
201            let maybe_port = options.get(&Str::from("port"));
202
203            match (maybe_host, maybe_port) {
204                (Some(host), Some(port)) => {
205                    let port = port.parse::<u16>().ok();
206                    let host = host.parse::<IpAddr>().ok();
207
208                    match (host, port) {
209                        (Some(host), Some(port)) => Some(SocketAddr::new(host, port)),
210                        (_, _) => None,
211                    }
212                }
213                _ => None,
214            }
215        };
216
217        Ok((
218            rest,
219            RouterAddress {
220                cost,
221                expires,
222                transport: TransportKind::try_from(transport)
223                    .map_err(|_| Err::Error(RouterAddressParseError::InvalidTransport))?,
224                options,
225                socket_address,
226            },
227        ))
228    }
229
230    /// Try to convert `bytes` into a [`RouterAddress`].
231    pub fn parse(bytes: impl AsRef<[u8]>) -> Result<RouterAddress, RouterAddressParseError> {
232        Ok(Self::parse_frame(bytes.as_ref())?.1)
233    }
234
235    /// Serialize [`RouterAddress`].
236    pub fn serialize(&self) -> BytesMut {
237        let options = self.options.serialize();
238        let transport = self.transport.serialize();
239        let mut out = BytesMut::with_capacity(1 + 8 + transport.len() + options.len());
240
241        out.put_u8(self.cost);
242        out.put_slice(&self.expires.serialize());
243        out.put_slice(&transport);
244        out.put_slice(&options);
245
246        out
247    }
248}
249
250#[cfg(test)]
251mod tests {
252    use super::*;
253
254    #[test]
255    fn serialize_deserialize_unpublished_ntcp2() {
256        let serialized = RouterAddress::new_unpublished_ntcp2([1u8; 32], 8888).serialize();
257        let static_key = StaticPrivateKey::from([1u8; 32]).public();
258
259        let address = RouterAddress::parse(&serialized).unwrap();
260        assert_eq!(address.cost, 14);
261        assert_eq!(
262            address.options.get(&Str::from("s")),
263            Some(&Str::from(base64_encode(&static_key)))
264        );
265        assert_eq!(address.options.get(&Str::from("v")), Some(&Str::from("2")));
266        assert!(address.options.get(&Str::from("i")).is_none());
267        assert!(address.options.get(&Str::from("host")).is_none());
268        assert!(address.options.get(&Str::from("port")).is_none());
269    }
270
271    #[test]
272    fn serialize_deserialize_published_ntcp2() {
273        let serialized = RouterAddress::new_published_ntcp2(
274            [1u8; 32],
275            [0xaa; 16],
276            8888,
277            "127.0.0.1".parse().unwrap(),
278        )
279        .serialize();
280        let static_key = StaticPrivateKey::from([1u8; 32]).public();
281
282        let address = RouterAddress::parse(&serialized).unwrap();
283        assert_eq!(address.cost, 3);
284        assert_eq!(
285            address.options.get(&Str::from("i")),
286            Some(&Str::from(base64_encode(&[0xaa; 16])))
287        );
288        assert_eq!(
289            address.options.get(&Str::from("s")),
290            Some(&Str::from(base64_encode(&static_key)))
291        );
292        assert_eq!(address.options.get(&Str::from("v")), Some(&Str::from("2")));
293        assert_eq!(
294            address.options.get(&Str::from("host")),
295            Some(&Str::from("127.0.0.1"))
296        );
297        assert_eq!(
298            address.options.get(&Str::from("port")),
299            Some(&Str::from("8888"))
300        );
301    }
302
303    #[test]
304    fn serialize_deserialize_unpublished_ssu2() {
305        let serialized =
306            RouterAddress::new_unpublished_ssu2([1u8; 32], [2u8; 32], 8888).serialize();
307        let static_key = StaticPrivateKey::from([1u8; 32]).public();
308        let intro_key = [2u8; 32];
309
310        let address = RouterAddress::parse(&serialized).unwrap();
311        assert_eq!(address.cost, 14);
312        assert_eq!(
313            address.options.get(&Str::from("s")),
314            Some(&Str::from(base64_encode(&static_key)))
315        );
316        assert_eq!(
317            address.options.get(&Str::from("i")),
318            Some(&Str::from(base64_encode(&intro_key)))
319        );
320        assert_eq!(address.options.get(&Str::from("v")), Some(&Str::from("2")));
321        assert!(address.options.get(&Str::from("host")).is_none());
322        assert!(address.options.get(&Str::from("port")).is_none());
323    }
324
325    #[test]
326    fn serialize_deserialize_published_ssu2() {
327        let serialized = RouterAddress::new_published_ssu2(
328            [1u8; 32],
329            [2u8; 32],
330            8888,
331            "127.0.0.1".parse().unwrap(),
332        )
333        .serialize();
334        let static_key = StaticPrivateKey::from([1u8; 32]).public();
335        let intro_key = [2u8; 32];
336
337        let address = RouterAddress::parse(&serialized).unwrap();
338        assert_eq!(address.cost, 8);
339        assert_eq!(
340            address.options.get(&Str::from("s")),
341            Some(&Str::from(base64_encode(&static_key)))
342        );
343        assert_eq!(
344            address.options.get(&Str::from("i")),
345            Some(&Str::from(base64_encode(&intro_key)))
346        );
347        assert_eq!(address.options.get(&Str::from("v")), Some(&Str::from("2")));
348        assert_eq!(
349            address.options.get(&Str::from("host")),
350            Some(&Str::from("127.0.0.1"))
351        );
352        assert_eq!(
353            address.options.get(&Str::from("port")),
354            Some(&Str::from("8888"))
355        );
356    }
357}