parity_multiaddr/
protocol.rs

1
2use arrayref::array_ref;
3use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
4use crate::{Result, Error};
5use data_encoding::BASE32;
6use multihash::Multihash;
7use std::{
8    borrow::Cow,
9    convert::From,
10    fmt,
11    io::{Cursor, Write},
12    net::{IpAddr, Ipv4Addr, Ipv6Addr},
13    str::{self, FromStr}
14};
15use unsigned_varint::{encode, decode};
16use crate::onion_addr::Onion3Addr;
17
18const DCCP: u32 = 33;
19const DNS: u32 = 53;
20const DNS4: u32 = 54;
21const DNS6: u32 = 55;
22const DNSADDR: u32 = 56;
23const HTTP: u32 = 480;
24const HTTPS: u32 = 443;
25const IP4: u32 = 4;
26const IP6: u32 = 41;
27const P2P_WEBRTC_DIRECT: u32 = 276;
28const P2P_WEBRTC_STAR: u32 = 275;
29const P2P_WEBSOCKET_STAR: u32 = 479;
30const MEMORY: u32 = 777;
31const ONION: u32 = 444;
32const ONION3: u32 = 445;
33const P2P: u32 = 421;
34const P2P_CIRCUIT: u32 = 290;
35const QUIC: u32 = 460;
36const SCTP: u32 = 132;
37const TCP: u32 = 6;
38const UDP: u32 = 273;
39const UDT: u32 = 301;
40const UNIX: u32 = 400;
41const UTP: u32 = 302;
42const WS: u32 = 477;
43const WS_WITH_PATH: u32 = 4770;         // Note: not standard
44const WSS: u32 = 478;
45const WSS_WITH_PATH: u32 = 4780;        // Note: not standard
46
47const PATH_SEGMENT_ENCODE_SET: &percent_encoding::AsciiSet = &percent_encoding::CONTROLS
48    .add(b'%')
49    .add(b'/')
50    .add(b'`')
51    .add(b'?')
52    .add(b'{')
53    .add(b'}')
54    .add(b' ')
55    .add(b'"')
56    .add(b'#')
57    .add(b'<')
58    .add(b'>');
59
60/// `Protocol` describes all possible multiaddress protocols.
61///
62/// For `Unix`, `Ws` and `Wss` we use `&str` instead of `Path` to allow
63/// cross-platform usage of `Protocol` since encoding `Paths` to bytes is
64/// platform-specific. This means that the actual validation of paths needs to
65/// happen separately.
66#[derive(PartialEq, Eq, Clone, Debug)]
67pub enum Protocol<'a> {
68    Dccp(u16),
69    Dns(Cow<'a, str>),
70    Dns4(Cow<'a, str>),
71    Dns6(Cow<'a, str>),
72    Dnsaddr(Cow<'a, str>),
73    Http,
74    Https,
75    Ip4(Ipv4Addr),
76    Ip6(Ipv6Addr),
77    P2pWebRtcDirect,
78    P2pWebRtcStar,
79    P2pWebSocketStar,
80    /// Contains the "port" to contact. Similar to TCP or UDP, 0 means "assign me a port".
81    Memory(u64),
82    Onion(Cow<'a, [u8; 10]>, u16),
83    Onion3(Onion3Addr<'a>),
84    P2p(Multihash),
85    P2pCircuit,
86    Quic,
87    Sctp(u16),
88    Tcp(u16),
89    Udp(u16),
90    Udt,
91    Unix(Cow<'a, str>),
92    Utp,
93    Ws(Cow<'a, str>),
94    Wss(Cow<'a, str>),
95}
96
97impl<'a> Protocol<'a> {
98    /// Parse a protocol value from the given iterator of string slices.
99    ///
100    /// The parsing only consumes the minimum amount of string slices necessary to
101    /// produce a well-formed protocol. The same iterator can thus be used to parse
102    /// a sequence of protocols in succession. It is up to client code to check
103    /// that iteration has finished whenever appropriate.
104    pub fn from_str_parts<I>(mut iter: I) -> Result<Self>
105    where
106        I: Iterator<Item=&'a str>
107    {
108        match iter.next().ok_or(Error::InvalidProtocolString)? {
109            "ip4" => {
110                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
111                Ok(Protocol::Ip4(Ipv4Addr::from_str(s)?))
112            }
113            "tcp" => {
114                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
115                Ok(Protocol::Tcp(s.parse()?))
116            }
117            "udp" => {
118                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
119                Ok(Protocol::Udp(s.parse()?))
120            }
121            "dccp" => {
122                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
123                Ok(Protocol::Dccp(s.parse()?))
124            }
125            "ip6" => {
126                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
127                Ok(Protocol::Ip6(Ipv6Addr::from_str(s)?))
128            }
129            "dns" => {
130                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
131                Ok(Protocol::Dns(Cow::Borrowed(s)))
132            }
133            "dns4" => {
134                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
135                Ok(Protocol::Dns4(Cow::Borrowed(s)))
136            }
137            "dns6" => {
138                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
139                Ok(Protocol::Dns6(Cow::Borrowed(s)))
140            }
141            "dnsaddr" => {
142                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
143                Ok(Protocol::Dnsaddr(Cow::Borrowed(s)))
144            }
145            "sctp" => {
146                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
147                Ok(Protocol::Sctp(s.parse()?))
148            }
149            "udt" => Ok(Protocol::Udt),
150            "utp" => Ok(Protocol::Utp),
151            "unix" => {
152                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
153                Ok(Protocol::Unix(Cow::Borrowed(s)))
154            }
155            "p2p" => {
156                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
157                let decoded = bs58::decode(s).into_vec()?;
158                Ok(Protocol::P2p(Multihash::from_bytes(&decoded)?))
159            }
160            "http" => Ok(Protocol::Http),
161            "https" => Ok(Protocol::Https),
162            "onion" =>
163                iter.next()
164                    .ok_or(Error::InvalidProtocolString)
165                    .and_then(|s| read_onion(&s.to_uppercase()))
166                    .map(|(a, p)| Protocol::Onion(Cow::Owned(a), p)),
167            "onion3" =>
168                iter.next()
169                    .ok_or(Error::InvalidProtocolString)
170                    .and_then(|s| read_onion3(&s.to_uppercase()))
171                    .map(|(a, p)| Protocol::Onion3((a, p).into())),
172            "quic" => Ok(Protocol::Quic),
173            "ws" => Ok(Protocol::Ws(Cow::Borrowed("/"))),
174            "wss" => Ok(Protocol::Wss(Cow::Borrowed("/"))),
175            "x-parity-ws" => {
176                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
177                let decoded = percent_encoding::percent_decode(s.as_bytes()).decode_utf8()?;
178                Ok(Protocol::Ws(decoded))
179            }
180            "x-parity-wss" => {
181                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
182                let decoded = percent_encoding::percent_decode(s.as_bytes()).decode_utf8()?;
183                Ok(Protocol::Wss(decoded))
184            }
185            "p2p-websocket-star" => Ok(Protocol::P2pWebSocketStar),
186            "p2p-webrtc-star" => Ok(Protocol::P2pWebRtcStar),
187            "p2p-webrtc-direct" => Ok(Protocol::P2pWebRtcDirect),
188            "p2p-circuit" => Ok(Protocol::P2pCircuit),
189            "memory" => {
190                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
191                Ok(Protocol::Memory(s.parse()?))
192            }
193            unknown => Err(Error::UnknownProtocolString(unknown.to_string()))
194        }
195    }
196
197    /// Parse a single `Protocol` value from its byte slice representation,
198    /// returning the protocol as well as the remaining byte slice.
199    pub fn from_bytes(input: &'a [u8]) -> Result<(Self, &'a [u8])> {
200        fn split_at(n: usize, input: &[u8]) -> Result<(&[u8], &[u8])> {
201            if input.len() < n {
202                return Err(Error::DataLessThanLen)
203            }
204            Ok(input.split_at(n))
205        }
206        let (id, input) = decode::u32(input)?;
207        match id {
208            DCCP => {
209                let (data, rest) = split_at(2, input)?;
210                let mut rdr = Cursor::new(data);
211                let num = rdr.read_u16::<BigEndian>()?;
212                Ok((Protocol::Dccp(num), rest))
213            }
214            DNS => {
215                let (n, input) = decode::usize(input)?;
216                let (data, rest) = split_at(n, input)?;
217                Ok((Protocol::Dns(Cow::Borrowed(str::from_utf8(data)?)), rest))
218            }
219            DNS4 => {
220                let (n, input) = decode::usize(input)?;
221                let (data, rest) = split_at(n, input)?;
222                Ok((Protocol::Dns4(Cow::Borrowed(str::from_utf8(data)?)), rest))
223            }
224            DNS6 => {
225                let (n, input) = decode::usize(input)?;
226                let (data, rest) = split_at(n, input)?;
227                Ok((Protocol::Dns6(Cow::Borrowed(str::from_utf8(data)?)), rest))
228            }
229            DNSADDR => {
230                let (n, input) = decode::usize(input)?;
231                let (data, rest) = split_at(n, input)?;
232                Ok((Protocol::Dnsaddr(Cow::Borrowed(str::from_utf8(data)?)), rest))
233            }
234            HTTP => Ok((Protocol::Http, input)),
235            HTTPS => Ok((Protocol::Https, input)),
236            IP4 => {
237                let (data, rest) = split_at(4, input)?;
238                Ok((Protocol::Ip4(Ipv4Addr::new(data[0], data[1], data[2], data[3])), rest))
239            }
240            IP6 => {
241                let (data, rest) = split_at(16, input)?;
242                let mut rdr = Cursor::new(data);
243                let mut seg = [0_u16; 8];
244
245                for x in seg.iter_mut() {
246                    *x = rdr.read_u16::<BigEndian>()?;
247                }
248
249                let addr = Ipv6Addr::new(seg[0],
250                                         seg[1],
251                                         seg[2],
252                                         seg[3],
253                                         seg[4],
254                                         seg[5],
255                                         seg[6],
256                                         seg[7]);
257
258                Ok((Protocol::Ip6(addr), rest))
259            }
260            P2P_WEBRTC_DIRECT => Ok((Protocol::P2pWebRtcDirect, input)),
261            P2P_WEBRTC_STAR => Ok((Protocol::P2pWebRtcStar, input)),
262            P2P_WEBSOCKET_STAR => Ok((Protocol::P2pWebSocketStar, input)),
263            MEMORY => {
264                let (data, rest) = split_at(8, input)?;
265                let mut rdr = Cursor::new(data);
266                let num = rdr.read_u64::<BigEndian>()?;
267                Ok((Protocol::Memory(num), rest))
268            }
269            ONION => {
270                let (data, rest) = split_at(12, input)?;
271                let port = BigEndian::read_u16(&data[10 ..]);
272                Ok((Protocol::Onion(Cow::Borrowed(array_ref!(data, 0, 10)), port), rest))
273            }
274            ONION3 => {
275                let (data, rest) = split_at(37, input)?;
276                let port = BigEndian::read_u16(&data[35 ..]);
277                Ok((Protocol::Onion3((array_ref!(data, 0, 35), port).into()), rest))
278            }
279            P2P => {
280                let (n, input) = decode::usize(input)?;
281                let (data, rest) = split_at(n, input)?;
282                Ok((Protocol::P2p(Multihash::from_bytes(data)?), rest))
283            }
284            P2P_CIRCUIT => Ok((Protocol::P2pCircuit, input)),
285            QUIC => Ok((Protocol::Quic, input)),
286            SCTP => {
287                let (data, rest) = split_at(2, input)?;
288                let mut rdr = Cursor::new(data);
289                let num = rdr.read_u16::<BigEndian>()?;
290                Ok((Protocol::Sctp(num), rest))
291            }
292            TCP => {
293                let (data, rest) = split_at(2, input)?;
294                let mut rdr = Cursor::new(data);
295                let num = rdr.read_u16::<BigEndian>()?;
296                Ok((Protocol::Tcp(num), rest))
297            }
298            UDP => {
299                let (data, rest) = split_at(2, input)?;
300                let mut rdr = Cursor::new(data);
301                let num = rdr.read_u16::<BigEndian>()?;
302                Ok((Protocol::Udp(num), rest))
303            }
304            UDT => Ok((Protocol::Udt, input)),
305            UNIX => {
306                let (n, input) = decode::usize(input)?;
307                let (data, rest) = split_at(n, input)?;
308                Ok((Protocol::Unix(Cow::Borrowed(str::from_utf8(data)?)), rest))
309            }
310            UTP => Ok((Protocol::Utp, input)),
311            WS => Ok((Protocol::Ws(Cow::Borrowed("/")), input)),
312            WS_WITH_PATH => {
313                let (n, input) = decode::usize(input)?;
314                let (data, rest) = split_at(n, input)?;
315                Ok((Protocol::Ws(Cow::Borrowed(str::from_utf8(data)?)), rest))
316            }
317            WSS => Ok((Protocol::Wss(Cow::Borrowed("/")), input)),
318            WSS_WITH_PATH => {
319                let (n, input) = decode::usize(input)?;
320                let (data, rest) = split_at(n, input)?;
321                Ok((Protocol::Wss(Cow::Borrowed(str::from_utf8(data)?)), rest))
322            }
323            _ => Err(Error::UnknownProtocolId(id))
324        }
325    }
326
327    /// Encode this protocol by writing its binary representation into
328    /// the given `Write` impl.
329    pub fn write_bytes<W: Write>(&self, w: &mut W) -> Result<()> {
330        let mut buf = encode::u32_buffer();
331        match self {
332            Protocol::Ip4(addr) => {
333                w.write_all(encode::u32(IP4, &mut buf))?;
334                w.write_all(&addr.octets())?
335            }
336            Protocol::Ip6(addr) => {
337                w.write_all(encode::u32(IP6, &mut buf))?;
338                for &segment in &addr.segments() {
339                    w.write_u16::<BigEndian>(segment)?
340                }
341            }
342            Protocol::Tcp(port) => {
343                w.write_all(encode::u32(TCP, &mut buf))?;
344                w.write_u16::<BigEndian>(*port)?
345            }
346            Protocol::Udp(port) => {
347                w.write_all(encode::u32(UDP, &mut buf))?;
348                w.write_u16::<BigEndian>(*port)?
349            }
350            Protocol::Dccp(port) => {
351                w.write_all(encode::u32(DCCP, &mut buf))?;
352                w.write_u16::<BigEndian>(*port)?
353            }
354            Protocol::Sctp(port) => {
355                w.write_all(encode::u32(SCTP, &mut buf))?;
356                w.write_u16::<BigEndian>(*port)?
357            }
358            Protocol::Dns(s) => {
359                w.write_all(encode::u32(DNS, &mut buf))?;
360                let bytes = s.as_bytes();
361                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
362                w.write_all(&bytes)?
363            }
364            Protocol::Dns4(s) => {
365                w.write_all(encode::u32(DNS4, &mut buf))?;
366                let bytes = s.as_bytes();
367                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
368                w.write_all(&bytes)?
369            }
370            Protocol::Dns6(s) => {
371                w.write_all(encode::u32(DNS6, &mut buf))?;
372                let bytes = s.as_bytes();
373                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
374                w.write_all(&bytes)?
375            }
376            Protocol::Dnsaddr(s) => {
377                w.write_all(encode::u32(DNSADDR, &mut buf))?;
378                let bytes = s.as_bytes();
379                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
380                w.write_all(&bytes)?
381            }
382            Protocol::Unix(s) => {
383                w.write_all(encode::u32(UNIX, &mut buf))?;
384                let bytes = s.as_bytes();
385                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
386                w.write_all(&bytes)?
387            }
388            Protocol::P2p(multihash) => {
389                w.write_all(encode::u32(P2P, &mut buf))?;
390                let bytes = multihash.to_bytes();
391                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
392                w.write_all(&bytes)?
393            }
394            Protocol::Onion(addr, port) => {
395                w.write_all(encode::u32(ONION, &mut buf))?;
396                w.write_all(addr.as_ref())?;
397                w.write_u16::<BigEndian>(*port)?
398            }
399            Protocol::Onion3(addr) => {
400                w.write_all(encode::u32(ONION3, &mut buf))?;
401                w.write_all(addr.hash().as_ref())?;
402                w.write_u16::<BigEndian>(addr.port())?
403            }
404            Protocol::Quic => w.write_all(encode::u32(QUIC, &mut buf))?,
405            Protocol::Utp => w.write_all(encode::u32(UTP, &mut buf))?,
406            Protocol::Udt => w.write_all(encode::u32(UDT, &mut buf))?,
407            Protocol::Http => w.write_all(encode::u32(HTTP, &mut buf))?,
408            Protocol::Https => w.write_all(encode::u32(HTTPS, &mut buf))?,
409            Protocol::Ws(ref s) if s == "/" => w.write_all(encode::u32(WS, &mut buf))?,
410            Protocol::Ws(s) => {
411                w.write_all(encode::u32(WS_WITH_PATH, &mut buf))?;
412                let bytes = s.as_bytes();
413                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
414                w.write_all(&bytes)?
415            },
416            Protocol::Wss(ref s) if s == "/" => w.write_all(encode::u32(WSS, &mut buf))?,
417            Protocol::Wss(s) => {
418                w.write_all(encode::u32(WSS_WITH_PATH, &mut buf))?;
419                let bytes = s.as_bytes();
420                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
421                w.write_all(&bytes)?
422            },
423            Protocol::P2pWebSocketStar => w.write_all(encode::u32(P2P_WEBSOCKET_STAR, &mut buf))?,
424            Protocol::P2pWebRtcStar => w.write_all(encode::u32(P2P_WEBRTC_STAR, &mut buf))?,
425            Protocol::P2pWebRtcDirect => w.write_all(encode::u32(P2P_WEBRTC_DIRECT, &mut buf))?,
426            Protocol::P2pCircuit => w.write_all(encode::u32(P2P_CIRCUIT, &mut buf))?,
427            Protocol::Memory(port) => {
428                w.write_all(encode::u32(MEMORY, &mut buf))?;
429                w.write_u64::<BigEndian>(*port)?
430            }
431        }
432        Ok(())
433    }
434
435    /// Turn this `Protocol` into one that owns its data, thus being valid for any lifetime.
436    pub fn acquire<'b>(self) -> Protocol<'b> {
437        use self::Protocol::*;
438        match self {
439            Dccp(a) => Dccp(a),
440            Dns(cow) => Dns(Cow::Owned(cow.into_owned())),
441            Dns4(cow) => Dns4(Cow::Owned(cow.into_owned())),
442            Dns6(cow) => Dns6(Cow::Owned(cow.into_owned())),
443            Dnsaddr(cow) => Dnsaddr(Cow::Owned(cow.into_owned())),
444            Http => Http,
445            Https => Https,
446            Ip4(a) => Ip4(a),
447            Ip6(a) => Ip6(a),
448            P2pWebRtcDirect => P2pWebRtcDirect,
449            P2pWebRtcStar => P2pWebRtcStar,
450            P2pWebSocketStar => P2pWebSocketStar,
451            Memory(a) => Memory(a),
452            Onion(addr, port) => Onion(Cow::Owned(addr.into_owned()), port),
453            Onion3(addr) => Onion3(addr.acquire()),
454            P2p(a) => P2p(a),
455            P2pCircuit => P2pCircuit,
456            Quic => Quic,
457            Sctp(a) => Sctp(a),
458            Tcp(a) => Tcp(a),
459            Udp(a) => Udp(a),
460            Udt => Udt,
461            Unix(cow) => Unix(Cow::Owned(cow.into_owned())),
462            Utp => Utp,
463            Ws(cow) => Ws(Cow::Owned(cow.into_owned())),
464            Wss(cow) => Wss(Cow::Owned(cow.into_owned())),
465        }
466    }
467}
468
469impl<'a> fmt::Display for Protocol<'a> {
470    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
471        use self::Protocol::*;
472        match self {
473            Dccp(port) => write!(f, "/dccp/{}", port),
474            Dns(s) => write!(f, "/dns/{}", s),
475            Dns4(s) => write!(f, "/dns4/{}", s),
476            Dns6(s) => write!(f, "/dns6/{}", s),
477            Dnsaddr(s) => write!(f, "/dnsaddr/{}", s),
478            Http => f.write_str("/http"),
479            Https => f.write_str("/https"),
480            Ip4(addr) => write!(f, "/ip4/{}", addr),
481            Ip6(addr) => write!(f, "/ip6/{}", addr),
482            P2pWebRtcDirect => f.write_str("/p2p-webrtc-direct"),
483            P2pWebRtcStar => f.write_str("/p2p-webrtc-star"),
484            P2pWebSocketStar => f.write_str("/p2p-websocket-star"),
485            Memory(port) => write!(f, "/memory/{}", port),
486            Onion(addr, port) => {
487                let s = BASE32.encode(addr.as_ref());
488                write!(f, "/onion/{}:{}", s.to_lowercase(), port)
489            }
490            Onion3(addr ) => {
491                let s = BASE32.encode(addr.hash());
492                write!(f, "/onion3/{}:{}", s.to_lowercase(), addr.port())
493            }
494            P2p(c) => write!(f, "/p2p/{}", bs58::encode(c.to_bytes()).into_string()),
495            P2pCircuit => f.write_str("/p2p-circuit"),
496            Quic => f.write_str("/quic"),
497            Sctp(port) => write!(f, "/sctp/{}", port),
498            Tcp(port) => write!(f, "/tcp/{}", port),
499            Udp(port) => write!(f, "/udp/{}", port),
500            Udt => f.write_str("/udt"),
501            Unix(s) => write!(f, "/unix/{}", s),
502            Utp => f.write_str("/utp"),
503            Ws(ref s) if s == "/" => f.write_str("/ws"),
504            Ws(s) => {
505                let encoded = percent_encoding::percent_encode(s.as_bytes(), PATH_SEGMENT_ENCODE_SET);
506                write!(f, "/x-parity-ws/{}", encoded)
507            },
508            Wss(ref s) if s == "/" => f.write_str("/wss"),
509            Wss(s) => {
510                let encoded = percent_encoding::percent_encode(s.as_bytes(), PATH_SEGMENT_ENCODE_SET);
511                write!(f, "/x-parity-wss/{}", encoded)
512            },
513        }
514    }
515}
516
517impl<'a> From<IpAddr> for Protocol<'a> {
518    #[inline]
519    fn from(addr: IpAddr) -> Self {
520        match addr {
521            IpAddr::V4(addr) => Protocol::Ip4(addr),
522            IpAddr::V6(addr) => Protocol::Ip6(addr),
523        }
524    }
525}
526
527impl<'a> From<Ipv4Addr> for Protocol<'a> {
528    #[inline]
529    fn from(addr: Ipv4Addr) -> Self {
530        Protocol::Ip4(addr)
531    }
532}
533
534impl<'a> From<Ipv6Addr> for Protocol<'a> {
535    #[inline]
536    fn from(addr: Ipv6Addr) -> Self {
537        Protocol::Ip6(addr)
538    }
539}
540
541macro_rules! read_onion_impl {
542    ($name:ident, $len:expr, $encoded_len:expr) => {
543        fn $name(s: &str) -> Result<([u8; $len], u16)> {
544            let mut parts = s.split(':');
545
546            // address part (without ".onion")
547            let b32 = parts.next().ok_or(Error::InvalidMultiaddr)?;
548            if b32.len() != $encoded_len {
549                return Err(Error::InvalidMultiaddr)
550            }
551
552            // port number
553            let port = parts.next()
554                .ok_or(Error::InvalidMultiaddr)
555                .and_then(|p| str::parse(p).map_err(From::from))?;
556
557            // port == 0 is not valid for onion
558            if port == 0 {
559                return Err(Error::InvalidMultiaddr);
560            }
561
562            // nothing else expected
563            if parts.next().is_some() {
564                return Err(Error::InvalidMultiaddr)
565            }
566
567            if $len != BASE32.decode_len(b32.len()).map_err(|_| Error::InvalidMultiaddr)? {
568                return Err(Error::InvalidMultiaddr)
569            }
570
571            let mut buf = [0u8; $len];
572            BASE32.decode_mut(b32.as_bytes(), &mut buf).map_err(|_| Error::InvalidMultiaddr)?;
573
574            Ok((buf, port))
575        }
576    }
577}
578
579// Parse a version 2 onion address and return its binary representation.
580//
581// Format: <base-32 address> ":" <port number>
582read_onion_impl!(read_onion, 10, 16);
583// Parse a version 3 onion address and return its binary representation.
584//
585// Format: <base-32 address> ":" <port number>
586read_onion_impl!(read_onion3, 35, 56);