Skip to main content

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