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
16const 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; const IP4: u32 = 4;
27const IP6: u32 = 41;
28const P2P_WEBRTC_DIRECT: u32 = 276; const P2P_WEBRTC_STAR: u32 = 275; const WEBRTC_DIRECT: u32 = 280;
31const CERTHASH: u32 = 466;
32const P2P_WEBSOCKET_STAR: u32 = 479; const 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; const WSS: u32 = 478; const WSS_WITH_PATH: u32 = 4780; const IP6ZONE: u32 = 42;
54const IPCIDR: u32 = 43;
55const GARLIC64: u32 = 446;
57const GARLIC32: u32 = 447;
58const SNI: u32 = 449;
59const P2P_STARDUST: u32 = 277; const WEBRTC: u32 = 281;
61
62type 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#[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 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 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 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 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 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 let b32 = parts.next().ok_or(Error::InvalidMultiaddr)?;
794 if b32.len() != $encoded_len {
795 return Err(Error::InvalidMultiaddr);
796 }
797
798 let port = parts
800 .next()
801 .ok_or(Error::InvalidMultiaddr)
802 .and_then(|p| str::parse(p).map_err(From::from))?;
803
804 if port == 0 {
806 return Err(Error::InvalidMultiaddr);
807 }
808
809 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
832read_onion_impl!(read_onion, 10, 16);
836read_onion_impl!(read_onion3, 35, 56);