multiaddr/
protocol.rs

1use crate::onion_addr::Onion3Addr;
2use crate::{Error, PeerId, Result};
3use arrayref::array_ref;
4use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
5use data_encoding::BASE32;
6use std::{
7    borrow::Cow,
8    convert::From,
9    fmt,
10    io::{Cursor, Write},
11    net::{IpAddr, Ipv4Addr, Ipv6Addr},
12    str::{self, FromStr},
13};
14use unsigned_varint::{decode, encode};
15
16// All the values are obtained by converting hexadecimal protocol codes to u32.
17// Protocols as well as their corresponding codes are defined in
18// https://github.com/multiformats/multiaddr/blob/master/protocols.csv .
19const DCCP: u32 = 33;
20const DNS: u32 = 53;
21const DNS4: u32 = 54;
22const DNS6: u32 = 55;
23const DNSADDR: u32 = 56;
24const HTTP: u32 = 480;
25const HTTPS: u32 = 443; // Deprecated - alias for /tls/http
26const IP4: u32 = 4;
27const IP6: u32 = 41;
28const P2P_WEBRTC_DIRECT: u32 = 276; // Deprecated
29const P2P_WEBRTC_STAR: u32 = 275; // Deprecated
30const WEBRTC_DIRECT: u32 = 280;
31const CERTHASH: u32 = 466;
32const P2P_WEBSOCKET_STAR: u32 = 479; // Deprecated
33const MEMORY: u32 = 777;
34const ONION: u32 = 444;
35const ONION3: u32 = 445;
36const P2P: u32 = 421;
37const P2P_CIRCUIT: u32 = 290;
38const QUIC: u32 = 460;
39const QUIC_V1: u32 = 461;
40const SCTP: u32 = 132;
41const TCP: u32 = 6;
42const TLS: u32 = 448;
43const NOISE: u32 = 454;
44const UDP: u32 = 273;
45const UDT: u32 = 301;
46const UNIX: u32 = 400;
47const UTP: u32 = 302;
48const WEBTRANSPORT: u32 = 465;
49const WS: u32 = 477;
50const WS_WITH_PATH: u32 = 4770; // Note: not standard
51const WSS: u32 = 478; // Deprecated - alias for /tls/ws
52const WSS_WITH_PATH: u32 = 4780; // Note: not standard
53const IP6ZONE: u32 = 42;
54const IPCIDR: u32 = 43;
55// const IPFS: u32 = 421; // Deprecated
56const GARLIC64: u32 = 446;
57const GARLIC32: u32 = 447;
58const SNI: u32 = 449;
59const P2P_STARDUST: u32 = 277; // Deprecated
60const WEBRTC: u32 = 281;
61
62/// Type-alias for how multi-addresses use `Multihash`.
63///
64/// The `64` defines the allocation size for the digest within the `Multihash`.
65/// This allows us to use hashes such as SHA512.
66/// In case protocols like `/certhash` ever support hashes larger than that, we will need to update this size here (which will be a breaking change!).
67type Multihash = multihash::Multihash<64>;
68
69const PATH_SEGMENT_ENCODE_SET: &percent_encoding::AsciiSet = &percent_encoding::CONTROLS
70    .add(b'%')
71    .add(b'/')
72    .add(b'`')
73    .add(b'?')
74    .add(b'{')
75    .add(b'}')
76    .add(b' ')
77    .add(b'"')
78    .add(b'#')
79    .add(b'<')
80    .add(b'>');
81
82/// `Protocol` describes all possible multiaddress protocols.
83///
84/// For `Unix`, `Ws` and `Wss` we use `&str` instead of `Path` to allow
85/// cross-platform usage of `Protocol` since encoding `Paths` to bytes is
86/// platform-specific. This means that the actual validation of paths needs to
87/// happen separately.
88#[derive(PartialEq, Eq, Clone, Debug)]
89#[non_exhaustive]
90pub enum Protocol<'a> {
91    Dccp(u16),
92    Dns(Cow<'a, str>),
93    Dns4(Cow<'a, str>),
94    Dns6(Cow<'a, str>),
95    Dnsaddr(Cow<'a, str>),
96    Http,
97    Https,
98    Ip4(Ipv4Addr),
99    Ip6(Ipv6Addr),
100    P2pWebRtcDirect,
101    P2pWebRtcStar,
102    WebRTCDirect,
103    Certhash(Multihash),
104    P2pWebSocketStar,
105    /// Contains the "port" to contact. Similar to TCP or UDP, 0 means "assign me a port".
106    Memory(u64),
107    Onion(Cow<'a, [u8; 10]>, u16),
108    Onion3(Onion3Addr<'a>),
109    P2p(PeerId),
110    P2pCircuit,
111    Quic,
112    QuicV1,
113    Sctp(u16),
114    Tcp(u16),
115    Tls,
116    Noise,
117    Udp(u16),
118    Udt,
119    Unix(Cow<'a, str>),
120    Utp,
121    WebTransport,
122    Ws(Cow<'a, str>),
123    Wss(Cow<'a, str>),
124    Ip6zone(Cow<'a, str>),
125    Ipcidr(u8),
126    Garlic64(Cow<'a, [u8]>),
127    Garlic32(Cow<'a, [u8]>),
128    Sni(Cow<'a, str>),
129    P2pStardust,
130    WebRTC,
131}
132
133impl<'a> Protocol<'a> {
134    /// Parse a protocol value from the given iterator of string slices.
135    ///
136    /// The parsing only consumes the minimum amount of string slices necessary to
137    /// produce a well-formed protocol. The same iterator can thus be used to parse
138    /// a sequence of protocols in succession. It is up to client code to check
139    /// that iteration has finished whenever appropriate.
140    pub fn from_str_parts<I>(mut iter: I) -> Result<Self>
141    where
142        I: Iterator<Item = &'a str>,
143    {
144        match iter.next().ok_or(Error::InvalidProtocolString)? {
145            "ip4" => {
146                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
147                Ok(Protocol::Ip4(Ipv4Addr::from_str(s)?))
148            }
149            "tcp" => {
150                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
151                Ok(Protocol::Tcp(s.parse()?))
152            }
153            "tls" => Ok(Protocol::Tls),
154            "noise" => Ok(Protocol::Noise),
155            "udp" => {
156                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
157                Ok(Protocol::Udp(s.parse()?))
158            }
159            "dccp" => {
160                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
161                Ok(Protocol::Dccp(s.parse()?))
162            }
163            "ip6" => {
164                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
165                Ok(Protocol::Ip6(Ipv6Addr::from_str(s)?))
166            }
167            "dns" => {
168                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
169                Ok(Protocol::Dns(Cow::Borrowed(s)))
170            }
171            "dns4" => {
172                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
173                Ok(Protocol::Dns4(Cow::Borrowed(s)))
174            }
175            "dns6" => {
176                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
177                Ok(Protocol::Dns6(Cow::Borrowed(s)))
178            }
179            "dnsaddr" => {
180                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
181                Ok(Protocol::Dnsaddr(Cow::Borrowed(s)))
182            }
183            "sctp" => {
184                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
185                Ok(Protocol::Sctp(s.parse()?))
186            }
187            "udt" => Ok(Protocol::Udt),
188            "utp" => Ok(Protocol::Utp),
189            "unix" => {
190                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
191                Ok(Protocol::Unix(Cow::Borrowed(s)))
192            }
193            "p2p" | "ipfs" => {
194                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
195                let decoded = multibase::Base::Base58Btc.decode(s)?;
196                let peer_id =
197                    PeerId::from_bytes(&decoded).map_err(|e| Error::ParsingError(Box::new(e)))?;
198                Ok(Protocol::P2p(peer_id))
199            }
200            "http" => Ok(Protocol::Http),
201            "https" => Ok(Protocol::Https),
202            "onion" => iter
203                .next()
204                .ok_or(Error::InvalidProtocolString)
205                .and_then(|s| read_onion(&s.to_uppercase()))
206                .map(|(a, p)| Protocol::Onion(Cow::Owned(a), p)),
207            "onion3" => iter
208                .next()
209                .ok_or(Error::InvalidProtocolString)
210                .and_then(|s| read_onion3(&s.to_uppercase()))
211                .map(|(a, p)| Protocol::Onion3((a, p).into())),
212            "quic" => Ok(Protocol::Quic),
213            "quic-v1" => Ok(Protocol::QuicV1),
214            "webtransport" => Ok(Protocol::WebTransport),
215            "ws" => Ok(Protocol::Ws(Cow::Borrowed("/"))),
216            "wss" => Ok(Protocol::Wss(Cow::Borrowed("/"))),
217            "x-parity-ws" => {
218                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
219                let decoded = percent_encoding::percent_decode(s.as_bytes()).decode_utf8()?;
220                Ok(Protocol::Ws(decoded))
221            }
222            "x-parity-wss" => {
223                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
224                let decoded = percent_encoding::percent_decode(s.as_bytes()).decode_utf8()?;
225                Ok(Protocol::Wss(decoded))
226            }
227            "p2p-websocket-star" => Ok(Protocol::P2pWebSocketStar),
228            "p2p-webrtc-star" => Ok(Protocol::P2pWebRtcStar),
229            "webrtc-direct" => Ok(Protocol::WebRTCDirect),
230            "certhash" => {
231                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
232                let (_base, decoded) = multibase::decode(s)?;
233                Ok(Protocol::Certhash(Multihash::from_bytes(&decoded)?))
234            }
235            "p2p-webrtc-direct" => Ok(Protocol::P2pWebRtcDirect),
236            "p2p-circuit" => Ok(Protocol::P2pCircuit),
237            "memory" => {
238                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
239                Ok(Protocol::Memory(s.parse()?))
240            }
241            "ip6zone" => {
242                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
243                Ok(Protocol::Ip6zone(Cow::Borrowed(s)))
244            }
245            "ipcidr" => {
246                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
247                Ok(Protocol::Ipcidr(s.parse()?))
248            }
249            "garlic64" => {
250                let s = iter
251                    .next()
252                    .ok_or(Error::InvalidProtocolString)?
253                    .replace('-', "+")
254                    .replace('~', "/");
255
256                if s.len() < 516 || s.len() > 616 {
257                    return Err(Error::InvalidProtocolString);
258                }
259
260                let decoded = multibase::Base::Base64.decode(s)?;
261                Ok(Protocol::Garlic64(Cow::from(decoded)))
262            }
263            "garlic32" => {
264                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
265
266                if s.len() < 55 && s.len() != 52 {
267                    return Err(Error::InvalidProtocolString);
268                }
269
270                let decoded = multibase::Base::Base32Lower.decode(s)?;
271                Ok(Protocol::Garlic32(Cow::from(decoded)))
272            }
273            "sni" => {
274                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
275                Ok(Protocol::Sni(Cow::Borrowed(s)))
276            }
277            "p2p-stardust" => Ok(Protocol::P2pStardust),
278            "webrtc" => Ok(Protocol::WebRTC),
279            unknown => Err(Error::UnknownProtocolString(unknown.to_string())),
280        }
281    }
282
283    /// Parse a single `Protocol` value from its byte slice representation,
284    /// returning the protocol as well as the remaining byte slice.
285    pub fn from_bytes(input: &'a [u8]) -> Result<(Self, &'a [u8])> {
286        fn split_at(n: usize, input: &[u8]) -> Result<(&[u8], &[u8])> {
287            if input.len() < n {
288                return Err(Error::DataLessThanLen);
289            }
290            Ok(input.split_at(n))
291        }
292        let (id, input) = decode::u32(input)?;
293        match id {
294            DCCP => {
295                let (data, rest) = split_at(2, input)?;
296                let mut rdr = Cursor::new(data);
297                let num = rdr.read_u16::<BigEndian>()?;
298                Ok((Protocol::Dccp(num), rest))
299            }
300            DNS => {
301                let (n, input) = decode::usize(input)?;
302                let (data, rest) = split_at(n, input)?;
303                Ok((Protocol::Dns(Cow::Borrowed(str::from_utf8(data)?)), rest))
304            }
305            DNS4 => {
306                let (n, input) = decode::usize(input)?;
307                let (data, rest) = split_at(n, input)?;
308                Ok((Protocol::Dns4(Cow::Borrowed(str::from_utf8(data)?)), rest))
309            }
310            DNS6 => {
311                let (n, input) = decode::usize(input)?;
312                let (data, rest) = split_at(n, input)?;
313                Ok((Protocol::Dns6(Cow::Borrowed(str::from_utf8(data)?)), rest))
314            }
315            DNSADDR => {
316                let (n, input) = decode::usize(input)?;
317                let (data, rest) = split_at(n, input)?;
318                Ok((
319                    Protocol::Dnsaddr(Cow::Borrowed(str::from_utf8(data)?)),
320                    rest,
321                ))
322            }
323            HTTP => Ok((Protocol::Http, input)),
324            HTTPS => Ok((Protocol::Https, input)),
325            IP4 => {
326                let (data, rest) = split_at(4, input)?;
327                Ok((
328                    Protocol::Ip4(Ipv4Addr::new(data[0], data[1], data[2], data[3])),
329                    rest,
330                ))
331            }
332            IP6 => {
333                let (data, rest) = split_at(16, input)?;
334                let mut rdr = Cursor::new(data);
335                let mut seg = [0_u16; 8];
336
337                for x in seg.iter_mut() {
338                    *x = rdr.read_u16::<BigEndian>()?;
339                }
340
341                let addr = Ipv6Addr::new(
342                    seg[0], seg[1], seg[2], seg[3], seg[4], seg[5], seg[6], seg[7],
343                );
344
345                Ok((Protocol::Ip6(addr), rest))
346            }
347            P2P_WEBRTC_DIRECT => Ok((Protocol::P2pWebRtcDirect, input)),
348            P2P_WEBRTC_STAR => Ok((Protocol::P2pWebRtcStar, input)),
349            WEBRTC_DIRECT => Ok((Protocol::WebRTCDirect, input)),
350            CERTHASH => {
351                let (n, input) = decode::usize(input)?;
352                let (data, rest) = split_at(n, input)?;
353                Ok((Protocol::Certhash(Multihash::from_bytes(data)?), rest))
354            }
355            P2P_WEBSOCKET_STAR => Ok((Protocol::P2pWebSocketStar, input)),
356            MEMORY => {
357                let (data, rest) = split_at(8, input)?;
358                let mut rdr = Cursor::new(data);
359                let num = rdr.read_u64::<BigEndian>()?;
360                Ok((Protocol::Memory(num), rest))
361            }
362            ONION => {
363                let (data, rest) = split_at(12, input)?;
364                let port = BigEndian::read_u16(&data[10..]);
365                Ok((
366                    Protocol::Onion(Cow::Borrowed(array_ref!(data, 0, 10)), port),
367                    rest,
368                ))
369            }
370            ONION3 => {
371                let (data, rest) = split_at(37, input)?;
372                let port = BigEndian::read_u16(&data[35..]);
373                Ok((
374                    Protocol::Onion3((array_ref!(data, 0, 35), port).into()),
375                    rest,
376                ))
377            }
378            P2P => {
379                let (n, input) = decode::usize(input)?;
380                let (data, rest) = split_at(n, input)?;
381                Ok((
382                    Protocol::P2p(
383                        PeerId::from_bytes(data).map_err(|e| Error::ParsingError(Box::new(e)))?,
384                    ),
385                    rest,
386                ))
387            }
388            P2P_CIRCUIT => Ok((Protocol::P2pCircuit, input)),
389            QUIC => Ok((Protocol::Quic, input)),
390            QUIC_V1 => Ok((Protocol::QuicV1, input)),
391            SCTP => {
392                let (data, rest) = split_at(2, input)?;
393                let mut rdr = Cursor::new(data);
394                let num = rdr.read_u16::<BigEndian>()?;
395                Ok((Protocol::Sctp(num), rest))
396            }
397            TCP => {
398                let (data, rest) = split_at(2, input)?;
399                let mut rdr = Cursor::new(data);
400                let num = rdr.read_u16::<BigEndian>()?;
401                Ok((Protocol::Tcp(num), rest))
402            }
403            TLS => Ok((Protocol::Tls, input)),
404            NOISE => Ok((Protocol::Noise, input)),
405            UDP => {
406                let (data, rest) = split_at(2, input)?;
407                let mut rdr = Cursor::new(data);
408                let num = rdr.read_u16::<BigEndian>()?;
409                Ok((Protocol::Udp(num), rest))
410            }
411            UDT => Ok((Protocol::Udt, input)),
412            UNIX => {
413                let (n, input) = decode::usize(input)?;
414                let (data, rest) = split_at(n, input)?;
415                Ok((Protocol::Unix(Cow::Borrowed(str::from_utf8(data)?)), rest))
416            }
417            UTP => Ok((Protocol::Utp, input)),
418            WEBTRANSPORT => Ok((Protocol::WebTransport, input)),
419            WS => Ok((Protocol::Ws(Cow::Borrowed("/")), input)),
420            WS_WITH_PATH => {
421                let (n, input) = decode::usize(input)?;
422                let (data, rest) = split_at(n, input)?;
423                Ok((Protocol::Ws(Cow::Borrowed(str::from_utf8(data)?)), rest))
424            }
425            WSS => Ok((Protocol::Wss(Cow::Borrowed("/")), input)),
426            WSS_WITH_PATH => {
427                let (n, input) = decode::usize(input)?;
428                let (data, rest) = split_at(n, input)?;
429                Ok((Protocol::Wss(Cow::Borrowed(str::from_utf8(data)?)), rest))
430            }
431            IP6ZONE => {
432                let (n, input) = decode::usize(input)?;
433                let (data, rest) = split_at(n, input)?;
434                Ok((
435                    Protocol::Ip6zone(Cow::Borrowed(str::from_utf8(data)?)),
436                    rest,
437                ))
438            }
439            IPCIDR => {
440                let (data, rest) = split_at(1, input)?;
441                Ok((Protocol::Ipcidr(data[0]), rest))
442            }
443            GARLIC64 => {
444                let (n, input) = decode::usize(input)?;
445                let (data, rest) = split_at(n, input)?;
446                Ok((Protocol::Garlic64(Cow::Borrowed(data)), rest))
447            }
448            GARLIC32 => {
449                let (n, input) = decode::usize(input)?;
450                let (data, rest) = split_at(n, input)?;
451                Ok((Protocol::Garlic32(Cow::Borrowed(data)), rest))
452            }
453            SNI => {
454                let (n, input) = decode::usize(input)?;
455                let (data, rest) = split_at(n, input)?;
456                Ok((Protocol::Sni(Cow::Borrowed(str::from_utf8(data)?)), rest))
457            }
458            P2P_STARDUST => Ok((Protocol::P2pStardust, input)),
459            WEBRTC => Ok((Protocol::WebRTC, input)),
460            _ => Err(Error::UnknownProtocolId(id)),
461        }
462    }
463
464    /// Encode this protocol by writing its binary representation into
465    /// the given `Write` impl.
466    pub fn write_bytes<W: Write>(&self, w: &mut W) -> Result<()> {
467        let mut buf = encode::u32_buffer();
468        match self {
469            Protocol::Ip4(addr) => {
470                w.write_all(encode::u32(IP4, &mut buf))?;
471                w.write_all(&addr.octets())?
472            }
473            Protocol::Ip6(addr) => {
474                w.write_all(encode::u32(IP6, &mut buf))?;
475                for &segment in &addr.segments() {
476                    w.write_u16::<BigEndian>(segment)?
477                }
478            }
479            Protocol::Tcp(port) => {
480                w.write_all(encode::u32(TCP, &mut buf))?;
481                w.write_u16::<BigEndian>(*port)?
482            }
483            Protocol::Tls => w.write_all(encode::u32(TLS, &mut buf))?,
484            Protocol::Noise => w.write_all(encode::u32(NOISE, &mut buf))?,
485            Protocol::Udp(port) => {
486                w.write_all(encode::u32(UDP, &mut buf))?;
487                w.write_u16::<BigEndian>(*port)?
488            }
489            Protocol::Dccp(port) => {
490                w.write_all(encode::u32(DCCP, &mut buf))?;
491                w.write_u16::<BigEndian>(*port)?
492            }
493            Protocol::Sctp(port) => {
494                w.write_all(encode::u32(SCTP, &mut buf))?;
495                w.write_u16::<BigEndian>(*port)?
496            }
497            Protocol::Dns(s) => {
498                w.write_all(encode::u32(DNS, &mut buf))?;
499                let bytes = s.as_bytes();
500                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
501                w.write_all(bytes)?
502            }
503            Protocol::Dns4(s) => {
504                w.write_all(encode::u32(DNS4, &mut buf))?;
505                let bytes = s.as_bytes();
506                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
507                w.write_all(bytes)?
508            }
509            Protocol::Dns6(s) => {
510                w.write_all(encode::u32(DNS6, &mut buf))?;
511                let bytes = s.as_bytes();
512                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
513                w.write_all(bytes)?
514            }
515            Protocol::Dnsaddr(s) => {
516                w.write_all(encode::u32(DNSADDR, &mut buf))?;
517                let bytes = s.as_bytes();
518                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
519                w.write_all(bytes)?
520            }
521            Protocol::Unix(s) => {
522                w.write_all(encode::u32(UNIX, &mut buf))?;
523                let bytes = s.as_bytes();
524                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
525                w.write_all(bytes)?
526            }
527            Protocol::P2p(peer_id) => {
528                w.write_all(encode::u32(P2P, &mut buf))?;
529                let bytes = peer_id.to_bytes();
530                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
531                w.write_all(&bytes)?
532            }
533            Protocol::Onion(addr, port) => {
534                w.write_all(encode::u32(ONION, &mut buf))?;
535                w.write_all(addr.as_ref())?;
536                w.write_u16::<BigEndian>(*port)?
537            }
538            Protocol::Onion3(addr) => {
539                w.write_all(encode::u32(ONION3, &mut buf))?;
540                w.write_all(addr.hash().as_ref())?;
541                w.write_u16::<BigEndian>(addr.port())?
542            }
543            Protocol::Quic => w.write_all(encode::u32(QUIC, &mut buf))?,
544            Protocol::QuicV1 => w.write_all(encode::u32(QUIC_V1, &mut buf))?,
545            Protocol::Utp => w.write_all(encode::u32(UTP, &mut buf))?,
546            Protocol::Udt => w.write_all(encode::u32(UDT, &mut buf))?,
547            Protocol::Http => w.write_all(encode::u32(HTTP, &mut buf))?,
548            Protocol::Https => w.write_all(encode::u32(HTTPS, &mut buf))?,
549            Protocol::WebTransport => w.write_all(encode::u32(WEBTRANSPORT, &mut buf))?,
550            Protocol::Ws(ref s) if s == "/" => w.write_all(encode::u32(WS, &mut buf))?,
551            Protocol::Ws(s) => {
552                w.write_all(encode::u32(WS_WITH_PATH, &mut buf))?;
553                let bytes = s.as_bytes();
554                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
555                w.write_all(bytes)?
556            }
557            Protocol::Wss(ref s) if s == "/" => w.write_all(encode::u32(WSS, &mut buf))?,
558            Protocol::Wss(s) => {
559                w.write_all(encode::u32(WSS_WITH_PATH, &mut buf))?;
560                let bytes = s.as_bytes();
561                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
562                w.write_all(bytes)?
563            }
564            Protocol::P2pWebSocketStar => w.write_all(encode::u32(P2P_WEBSOCKET_STAR, &mut buf))?,
565            Protocol::P2pWebRtcStar => w.write_all(encode::u32(P2P_WEBRTC_STAR, &mut buf))?,
566            Protocol::WebRTCDirect => w.write_all(encode::u32(WEBRTC_DIRECT, &mut buf))?,
567            Protocol::Certhash(hash) => {
568                w.write_all(encode::u32(CERTHASH, &mut buf))?;
569                let bytes = hash.to_bytes();
570                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
571                w.write_all(&bytes)?
572            }
573            Protocol::P2pWebRtcDirect => w.write_all(encode::u32(P2P_WEBRTC_DIRECT, &mut buf))?,
574            Protocol::P2pCircuit => w.write_all(encode::u32(P2P_CIRCUIT, &mut buf))?,
575            Protocol::Memory(port) => {
576                w.write_all(encode::u32(MEMORY, &mut buf))?;
577                w.write_u64::<BigEndian>(*port)?
578            }
579            Protocol::Ip6zone(zone_id) => {
580                w.write_all(encode::u32(IP6ZONE, &mut buf))?;
581                let bytes = zone_id.as_bytes();
582                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
583                w.write_all(bytes)?
584            }
585            Protocol::Ipcidr(mask) => {
586                w.write_all(encode::u32(IPCIDR, &mut buf))?;
587                w.write_u8(*mask)?
588            }
589            Protocol::Garlic64(addr) => {
590                w.write_all(encode::u32(GARLIC64, &mut buf))?;
591                w.write_all(encode::usize(addr.len(), &mut encode::usize_buffer()))?;
592                w.write_all(addr)?
593            }
594            Protocol::Garlic32(addr) => {
595                w.write_all(encode::u32(GARLIC32, &mut buf))?;
596                w.write_all(encode::usize(addr.len(), &mut encode::usize_buffer()))?;
597                w.write_all(addr)?
598            }
599            Protocol::Sni(s) => {
600                w.write_all(encode::u32(SNI, &mut buf))?;
601                let bytes = s.as_bytes();
602                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
603                w.write_all(bytes)?
604            }
605            Protocol::P2pStardust => w.write_all(encode::u32(P2P_STARDUST, &mut buf))?,
606            Protocol::WebRTC => w.write_all(encode::u32(WEBRTC, &mut buf))?,
607        }
608        Ok(())
609    }
610
611    /// Turn this `Protocol` into one that owns its data, thus being valid for any lifetime.
612    pub fn acquire<'b>(self) -> Protocol<'b> {
613        use self::Protocol::*;
614        match self {
615            Dccp(a) => Dccp(a),
616            Dns(cow) => Dns(Cow::Owned(cow.into_owned())),
617            Dns4(cow) => Dns4(Cow::Owned(cow.into_owned())),
618            Dns6(cow) => Dns6(Cow::Owned(cow.into_owned())),
619            Dnsaddr(cow) => Dnsaddr(Cow::Owned(cow.into_owned())),
620            Http => Http,
621            Https => Https,
622            Ip4(a) => Ip4(a),
623            Ip6(a) => Ip6(a),
624            P2pWebRtcDirect => P2pWebRtcDirect,
625            P2pWebRtcStar => P2pWebRtcStar,
626            WebRTCDirect => WebRTCDirect,
627            Certhash(hash) => Certhash(hash),
628            P2pWebSocketStar => P2pWebSocketStar,
629            Memory(a) => Memory(a),
630            Onion(addr, port) => Onion(Cow::Owned(addr.into_owned()), port),
631            Onion3(addr) => Onion3(addr.acquire()),
632            P2p(a) => P2p(a),
633            P2pCircuit => P2pCircuit,
634            Quic => Quic,
635            QuicV1 => QuicV1,
636            Sctp(a) => Sctp(a),
637            Tcp(a) => Tcp(a),
638            Tls => Tls,
639            Noise => Noise,
640            Udp(a) => Udp(a),
641            Udt => Udt,
642            Unix(cow) => Unix(Cow::Owned(cow.into_owned())),
643            Utp => Utp,
644            WebTransport => WebTransport,
645            Ws(cow) => Ws(Cow::Owned(cow.into_owned())),
646            Wss(cow) => Wss(Cow::Owned(cow.into_owned())),
647            Ip6zone(cow) => Ip6zone(Cow::Owned(cow.into_owned())),
648            Ipcidr(mask) => Ipcidr(mask),
649            Garlic64(addr) => Garlic64(Cow::Owned(addr.into_owned())),
650            Garlic32(addr) => Garlic32(Cow::Owned(addr.into_owned())),
651            Sni(cow) => Sni(Cow::Owned(cow.into_owned())),
652            P2pStardust => P2pStardust,
653            WebRTC => WebRTC,
654        }
655    }
656
657    pub fn tag(&self) -> &'static str {
658        use self::Protocol::*;
659        match self {
660            Dccp(_) => "dccp",
661            Dns(_) => "dns",
662            Dns4(_) => "dns4",
663            Dns6(_) => "dns6",
664            Dnsaddr(_) => "dnsaddr",
665            Http => "http",
666            Https => "https",
667            Ip4(_) => "ip4",
668            Ip6(_) => "ip6",
669            P2pWebRtcDirect => "p2p-webrtc-direct",
670            P2pWebRtcStar => "p2p-webrtc-star",
671            WebRTCDirect => "webrtc-direct",
672            Certhash(_) => "certhash",
673            P2pWebSocketStar => "p2p-websocket-star",
674            Memory(_) => "memory",
675            Onion(_, _) => "onion",
676            Onion3(_) => "onion3",
677            P2p(_) => "p2p",
678            P2pCircuit => "p2p-circuit",
679            Quic => "quic",
680            QuicV1 => "quic-v1",
681            Sctp(_) => "sctp",
682            Tcp(_) => "tcp",
683            Tls => "tls",
684            Noise => "noise",
685            Udp(_) => "udp",
686            Udt => "udt",
687            Unix(_) => "unix",
688            Utp => "utp",
689            WebTransport => "webtransport",
690            Ws(ref s) if s == "/" => "ws",
691            Ws(_) => "x-parity-ws",
692            Wss(ref s) if s == "/" => "wss",
693            Wss(_) => "x-parity-wss",
694            Ip6zone(_) => "ip6zone",
695            Ipcidr(_) => "ipcidr",
696            Garlic64(_) => "garlic64",
697            Garlic32(_) => "garlic32",
698            Sni(_) => "sni",
699            P2pStardust => "p2p-stardust",
700            WebRTC => "webrtc",
701        }
702    }
703}
704
705impl<'a> fmt::Display for Protocol<'a> {
706    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
707        use self::Protocol::*;
708        write!(f, "/{}", self.tag())?;
709        match self {
710            Dccp(port) => write!(f, "/{port}"),
711            Dns(s) => write!(f, "/{s}"),
712            Dns4(s) => write!(f, "/{s}"),
713            Dns6(s) => write!(f, "/{s}"),
714            Dnsaddr(s) => write!(f, "/{s}"),
715            Ip4(addr) => write!(f, "/{addr}"),
716            Ip6(addr) => write!(f, "/{addr}"),
717            Certhash(hash) => write!(
718                f,
719                "/{}",
720                multibase::encode(multibase::Base::Base64Url, hash.to_bytes())
721            ),
722            Memory(port) => write!(f, "/{port}"),
723            Onion(addr, port) => {
724                let s = BASE32.encode(addr.as_ref());
725                write!(f, "/{}:{}", s.to_lowercase(), port)
726            }
727            Onion3(addr) => {
728                let s = BASE32.encode(addr.hash());
729                write!(f, "/{}:{}", s.to_lowercase(), addr.port())
730            }
731            P2p(c) => write!(f, "/{}", multibase::Base::Base58Btc.encode(c.to_bytes())),
732            Sctp(port) => write!(f, "/{port}"),
733            Tcp(port) => write!(f, "/{port}"),
734            Udp(port) => write!(f, "/{port}"),
735            Unix(s) => write!(f, "/{s}"),
736            Ws(s) if s != "/" => {
737                let encoded =
738                    percent_encoding::percent_encode(s.as_bytes(), PATH_SEGMENT_ENCODE_SET);
739                write!(f, "/{encoded}")
740            }
741            Wss(s) if s != "/" => {
742                let encoded =
743                    percent_encoding::percent_encode(s.as_bytes(), PATH_SEGMENT_ENCODE_SET);
744                write!(f, "/{encoded}")
745            }
746            Ip6zone(zone) => write!(f, "/{zone}"),
747            Ipcidr(mask) => write!(f, "/{mask}"),
748            Garlic64(addr) => write!(
749                f,
750                "/{}",
751                multibase::Base::Base64
752                    .encode(addr)
753                    .replace('+', "-")
754                    .replace('/', "~")
755            ),
756            Garlic32(addr) => write!(f, "/{}", multibase::Base::Base32Lower.encode(addr)),
757            Sni(s) => write!(f, "/{s}"),
758            _ => Ok(()),
759        }
760    }
761}
762
763impl<'a> From<IpAddr> for Protocol<'a> {
764    #[inline]
765    fn from(addr: IpAddr) -> Self {
766        match addr {
767            IpAddr::V4(addr) => Protocol::Ip4(addr),
768            IpAddr::V6(addr) => Protocol::Ip6(addr),
769        }
770    }
771}
772
773impl<'a> From<Ipv4Addr> for Protocol<'a> {
774    #[inline]
775    fn from(addr: Ipv4Addr) -> Self {
776        Protocol::Ip4(addr)
777    }
778}
779
780impl<'a> From<Ipv6Addr> for Protocol<'a> {
781    #[inline]
782    fn from(addr: Ipv6Addr) -> Self {
783        Protocol::Ip6(addr)
784    }
785}
786
787macro_rules! read_onion_impl {
788    ($name:ident, $len:expr, $encoded_len:expr) => {
789        fn $name(s: &str) -> Result<([u8; $len], u16)> {
790            let mut parts = s.split(':');
791
792            // address part (without ".onion")
793            let b32 = parts.next().ok_or(Error::InvalidMultiaddr)?;
794            if b32.len() != $encoded_len {
795                return Err(Error::InvalidMultiaddr);
796            }
797
798            // port number
799            let port = parts
800                .next()
801                .ok_or(Error::InvalidMultiaddr)
802                .and_then(|p| str::parse(p).map_err(From::from))?;
803
804            // port == 0 is not valid for onion
805            if port == 0 {
806                return Err(Error::InvalidMultiaddr);
807            }
808
809            // nothing else expected
810            if parts.next().is_some() {
811                return Err(Error::InvalidMultiaddr);
812            }
813
814            if $len
815                != BASE32
816                    .decode_len(b32.len())
817                    .map_err(|_| Error::InvalidMultiaddr)?
818            {
819                return Err(Error::InvalidMultiaddr);
820            }
821
822            let mut buf = [0u8; $len];
823            BASE32
824                .decode_mut(b32.as_bytes(), &mut buf)
825                .map_err(|_| Error::InvalidMultiaddr)?;
826
827            Ok((buf, port))
828        }
829    };
830}
831
832// Parse a version 2 onion address and return its binary representation.
833//
834// Format: <base-32 address> ":" <port number>
835read_onion_impl!(read_onion, 10, 16);
836// Parse a version 3 onion address and return its binary representation.
837//
838// Format: <base-32 address> ":" <port number>
839read_onion_impl!(read_onion3, 35, 56);