tentacle_multiaddr/
protocol.rs

1use arrayref::array_ref;
2use byteorder::{BigEndian, ByteOrder};
3use bytes::{Buf, BufMut};
4use data_encoding::BASE32;
5use std::{
6    borrow::Cow,
7    fmt,
8    io::Cursor,
9    net::{IpAddr, Ipv4Addr, Ipv6Addr},
10    str::{self, FromStr},
11};
12
13use crate::{Onion3Addr, error::Error};
14
15const DNS4: u32 = 0x36;
16const DNS6: u32 = 0x37;
17const IP4: u32 = 0x04;
18const IP6: u32 = 0x29;
19const P2P: u32 = 0x01a5;
20const TCP: u32 = 0x06;
21const TLS: u32 = 0x01c0;
22const WS: u32 = 0x01dd;
23const WSS: u32 = 0x01de;
24const MEMORY: u32 = 0x0309;
25const ONION3: u32 = 0x01bd;
26
27const SHA256_CODE: u64 = 0x12;
28const SHA256_SIZE: u8 = 32;
29
30/// `Protocol` describes all possible multiaddress protocols.
31#[derive(PartialEq, Eq, Clone, Debug)]
32pub enum Protocol<'a> {
33    Dns4(Cow<'a, str>),
34    Dns6(Cow<'a, str>),
35    Ip4(Ipv4Addr),
36    Ip6(Ipv6Addr),
37    P2P(Cow<'a, [u8]>),
38    Tcp(u16),
39    Tls(Cow<'a, str>),
40    Ws,
41    Wss,
42    /// Contains the "port" to contact. Similar to TCP or UDP, 0 means "assign me a port".
43    Memory(u64),
44    Onion3(Onion3Addr<'a>),
45}
46
47impl<'a> Protocol<'a> {
48    /// Parse a protocol value from the given iterator of string slices.
49    ///
50    /// The parsing only consumes the minimum amount of string slices necessary to
51    /// produce a well-formed protocol. The same iterator can thus be used to parse
52    /// a sequence of protocols in succession. It is up to client code to check
53    /// that iteration has finished whenever appropriate.
54    pub fn from_str_peek<T>(mut iter: T) -> Result<Self, Error>
55    where
56        T: Iterator<Item = &'a str>,
57    {
58        match iter.next().ok_or(Error::InvalidProtocolString)? {
59            "dns4" => {
60                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
61                Ok(Protocol::Dns4(Cow::Borrowed(s)))
62            }
63            "dns6" => {
64                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
65                Ok(Protocol::Dns6(Cow::Borrowed(s)))
66            }
67            "ip4" => {
68                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
69                Ok(Protocol::Ip4(Ipv4Addr::from_str(s)?))
70            }
71            "ip6" => {
72                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
73                Ok(Protocol::Ip6(Ipv6Addr::from_str(s)?))
74            }
75            "tls" => {
76                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
77                Ok(Protocol::Tls(Cow::Borrowed(s)))
78            }
79            "p2p" => {
80                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
81                let decoded = bs58::decode(s).into_vec()?;
82                check_p2p(decoded.as_slice())?;
83                Ok(Protocol::P2P(Cow::Owned(decoded)))
84            }
85            "tcp" => {
86                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
87                Ok(Protocol::Tcp(s.parse()?))
88            }
89            "ws" => Ok(Protocol::Ws),
90            "wss" => Ok(Protocol::Wss),
91            "memory" => {
92                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
93                Ok(Protocol::Memory(s.parse()?))
94            }
95            "onion3" => iter
96                .next()
97                .ok_or(Error::InvalidProtocolString)
98                .and_then(|s| read_onion3(&s.to_uppercase()))
99                .map(|(a, p)| Protocol::Onion3((a, p).into())),
100            _ => Err(Error::UnknownProtocolString),
101        }
102    }
103
104    /// Parse a single `Protocol` value from its byte slice representation,
105    /// returning the protocol as well as the remaining byte slice.
106    pub fn from_bytes(input: &'a [u8]) -> Result<(Self, &'a [u8]), Error> {
107        use unsigned_varint::decode;
108        fn split_header(n: usize, input: &[u8]) -> Result<(&[u8], &[u8]), Error> {
109            if input.len() < n {
110                return Err(Error::DataLessThanLen);
111            }
112            Ok(input.split_at(n))
113        }
114
115        let (id, input) = decode::u32(input)?;
116        match id {
117            DNS4 => {
118                let (n, input) = decode::usize(input)?;
119                let (data, rest) = split_header(n, input)?;
120                Ok((Protocol::Dns4(Cow::Borrowed(str::from_utf8(data)?)), rest))
121            }
122            DNS6 => {
123                let (n, input) = decode::usize(input)?;
124                let (data, rest) = split_header(n, input)?;
125                Ok((Protocol::Dns6(Cow::Borrowed(str::from_utf8(data)?)), rest))
126            }
127            IP4 => {
128                let (data, rest) = split_header(4, input)?;
129                Ok((
130                    Protocol::Ip4(Ipv4Addr::new(data[0], data[1], data[2], data[3])),
131                    rest,
132                ))
133            }
134            IP6 => {
135                let (data, rest) = split_header(16, input)?;
136                let mut rdr = Cursor::new(data);
137                let mut seg = [0_u16; 8];
138
139                for x in seg.iter_mut() {
140                    *x = rdr.get_u16();
141                }
142
143                let addr = Ipv6Addr::new(
144                    seg[0], seg[1], seg[2], seg[3], seg[4], seg[5], seg[6], seg[7],
145                );
146
147                Ok((Protocol::Ip6(addr), rest))
148            }
149            TLS => {
150                let (n, input) = decode::usize(input)?;
151                let (data, rest) = split_header(n, input)?;
152                Ok((Protocol::Tls(Cow::Borrowed(str::from_utf8(data)?)), rest))
153            }
154            P2P => {
155                let (n, input) = decode::usize(input)?;
156                let (data, rest) = split_header(n, input)?;
157                check_p2p(data)?;
158                Ok((Protocol::P2P(Cow::Borrowed(data)), rest))
159            }
160            TCP => {
161                let (data, rest) = split_header(2, input)?;
162                let mut rdr = Cursor::new(data);
163                let num = rdr.get_u16();
164                Ok((Protocol::Tcp(num), rest))
165            }
166            WS => Ok((Protocol::Ws, input)),
167            WSS => Ok((Protocol::Wss, input)),
168            MEMORY => {
169                let (data, rest) = split_header(8, input)?;
170                let mut rdr = Cursor::new(data);
171                let num = rdr.get_u64();
172                Ok((Protocol::Memory(num), rest))
173            }
174            ONION3 => {
175                let (data, rest) = split_header(37, input)?;
176                let port = BigEndian::read_u16(&data[35..]);
177                Ok((
178                    Protocol::Onion3((array_ref!(data, 0, 35), port).into()),
179                    rest,
180                ))
181            }
182            _ => Err(Error::UnknownProtocolId(id)),
183        }
184    }
185
186    /// Encode this protocol by writing its binary representation into
187    /// the given `BufMut` impl.
188    pub fn write_to_bytes<W: BufMut>(&self, w: &mut W) {
189        use unsigned_varint::encode;
190        let mut buf = encode::u32_buffer();
191        match self {
192            Protocol::Dns4(s) => {
193                w.put(encode::u32(DNS4, &mut buf));
194                let bytes = s.as_bytes();
195                w.put(encode::usize(bytes.len(), &mut encode::usize_buffer()));
196                w.put(bytes)
197            }
198            Protocol::Dns6(s) => {
199                w.put(encode::u32(DNS6, &mut buf));
200                let bytes = s.as_bytes();
201                w.put(encode::usize(bytes.len(), &mut encode::usize_buffer()));
202                w.put(bytes)
203            }
204            Protocol::Ip4(addr) => {
205                w.put(encode::u32(IP4, &mut buf));
206                w.put(&addr.octets()[..])
207            }
208            Protocol::Ip6(addr) => {
209                w.put(encode::u32(IP6, &mut buf));
210                for &segment in &addr.segments() {
211                    w.put_u16(segment)
212                }
213            }
214            Protocol::Tcp(port) => {
215                w.put(encode::u32(TCP, &mut buf));
216                w.put_u16(*port)
217            }
218            Protocol::Tls(s) => {
219                w.put(encode::u32(TLS, &mut buf));
220                let bytes = s.as_bytes();
221                w.put(encode::usize(bytes.len(), &mut encode::usize_buffer()));
222                w.put(bytes)
223            }
224            Protocol::P2P(b) => {
225                w.put(encode::u32(P2P, &mut buf));
226                w.put(encode::usize(b.len(), &mut encode::usize_buffer()));
227                w.put(&b[..])
228            }
229            Protocol::Ws => w.put(encode::u32(WS, &mut buf)),
230            Protocol::Wss => w.put(encode::u32(WSS, &mut buf)),
231            Protocol::Memory(port) => {
232                w.put(encode::u32(MEMORY, &mut buf));
233                w.put_u64(*port)
234            }
235            Protocol::Onion3(addr) => {
236                w.put(encode::u32(ONION3, &mut buf));
237                w.put(addr.hash().as_ref());
238                w.put_u16(addr.port());
239            }
240        }
241    }
242
243    /// Turn this `Protocol` into one that owns its data, thus being valid for any lifetime.
244    pub fn acquire<'b>(self) -> Protocol<'b> {
245        match self {
246            Protocol::Dns4(s) => Protocol::Dns4(Cow::Owned(s.into_owned())),
247            Protocol::Dns6(s) => Protocol::Dns6(Cow::Owned(s.into_owned())),
248            Protocol::Ip4(addr) => Protocol::Ip4(addr),
249            Protocol::Ip6(addr) => Protocol::Ip6(addr),
250            Protocol::Tcp(port) => Protocol::Tcp(port),
251            Protocol::Tls(s) => Protocol::Tls(Cow::Owned(s.into_owned())),
252            Protocol::P2P(s) => Protocol::P2P(Cow::Owned(s.into_owned())),
253            Protocol::Ws => Protocol::Ws,
254            Protocol::Wss => Protocol::Wss,
255            Protocol::Memory(a) => Protocol::Memory(a),
256            Protocol::Onion3(addr) => Protocol::Onion3(addr.acquire()),
257        }
258    }
259}
260
261impl fmt::Display for Protocol<'_> {
262    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
263        use self::Protocol::*;
264        match self {
265            Dns4(s) => write!(f, "/dns4/{}", s),
266            Dns6(s) => write!(f, "/dns6/{}", s),
267            Ip4(addr) => write!(f, "/ip4/{}", addr),
268            Ip6(addr) => write!(f, "/ip6/{}", addr),
269            P2P(c) => write!(f, "/p2p/{}", bs58::encode(c).into_string()),
270            Tcp(port) => write!(f, "/tcp/{}", port),
271            Tls(s) => write!(f, "/tls/{}", s),
272            Ws => write!(f, "/ws"),
273            Wss => write!(f, "/wss"),
274            Memory(port) => write!(f, "/memory/{}", port),
275            Onion3(addr) => {
276                write!(f, "/onion3/{}:{}", addr.hash_string(), addr.port())
277            }
278        }
279    }
280}
281
282impl From<IpAddr> for Protocol<'_> {
283    #[inline]
284    fn from(addr: IpAddr) -> Self {
285        match addr {
286            IpAddr::V4(addr) => Protocol::Ip4(addr),
287            IpAddr::V6(addr) => Protocol::Ip6(addr),
288        }
289    }
290}
291
292impl From<Ipv4Addr> for Protocol<'_> {
293    #[inline]
294    fn from(addr: Ipv4Addr) -> Self {
295        Protocol::Ip4(addr)
296    }
297}
298
299impl From<Ipv6Addr> for Protocol<'_> {
300    #[inline]
301    fn from(addr: Ipv6Addr) -> Self {
302        Protocol::Ip6(addr)
303    }
304}
305
306fn check_p2p(data: &[u8]) -> Result<(), Error> {
307    let (code, bytes) = unsigned_varint::decode::u64(data)?;
308
309    if code != SHA256_CODE {
310        return Err(Error::UnknownHash);
311    }
312
313    if bytes.len() != SHA256_SIZE as usize + 1 {
314        return Err(Error::UnknownHash);
315    }
316
317    if bytes[0] != SHA256_SIZE {
318        return Err(Error::UnknownHash);
319    }
320    Ok(())
321}
322
323macro_rules! read_onion_impl {
324    ($name:ident, $len:expr, $encoded_len:expr) => {
325        fn $name(s: &str) -> Result<([u8; $len], u16), Error> {
326            let mut parts = s.split(':');
327
328            // address part (without ".onion")
329            let b32 = parts.next().ok_or(Error::InvalidMultiaddr)?;
330            if b32.len() != $encoded_len {
331                return Err(Error::InvalidMultiaddr);
332            }
333
334            // port number
335            let port = parts
336                .next()
337                .ok_or(Error::InvalidMultiaddr)
338                .and_then(|p| str::parse(p).map_err(From::from))?;
339
340            // port == 0 is not valid for onion
341            if port == 0 {
342                return Err(Error::InvalidMultiaddr);
343            }
344
345            // nothing else expected
346            if parts.next().is_some() {
347                return Err(Error::InvalidMultiaddr);
348            }
349
350            if $len
351                != BASE32
352                    .decode_len(b32.len())
353                    .map_err(|_| Error::InvalidMultiaddr)?
354            {
355                return Err(Error::InvalidMultiaddr);
356            }
357
358            let mut buf = [0u8; $len];
359            BASE32
360                .decode_mut(b32.as_bytes(), &mut buf)
361                .map_err(|_| Error::InvalidMultiaddr)?;
362
363            Ok((buf, port))
364        }
365    };
366}
367
368// Parse a version 3 onion address and return its binary representation.
369//
370// Format: <base-32 address> ":" <port number>
371read_onion_impl!(read_onion3, 35, 56);