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#[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 Memory(u64),
46 Onion3(Onion3Addr<'a>),
47 Udp(u16),
48 QuicV1,
49}
50
51impl<'a> Protocol<'a> {
52 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 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 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 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 let b32 = parts.next().ok_or(Error::InvalidMultiaddr)?;
354 if b32.len() != $encoded_len {
355 return Err(Error::InvalidMultiaddr);
356 }
357
358 let port = parts
360 .next()
361 .ok_or(Error::InvalidMultiaddr)
362 .and_then(|p| str::parse(p).map_err(From::from))?;
363
364 if port == 0 {
366 return Err(Error::InvalidMultiaddr);
367 }
368
369 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
392read_onion_impl!(read_onion3, 35, 56);