sc_network_types/multiaddr/
protocol.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19use crate::multihash::Multihash;
20use libp2p_identity::PeerId;
21use litep2p::types::multiaddr::Protocol as LiteP2pProtocol;
22use multiaddr::Protocol as LibP2pProtocol;
23use std::{
24	borrow::Cow,
25	fmt::{self, Debug, Display},
26	net::{IpAddr, Ipv4Addr, Ipv6Addr},
27};
28
29// Log target for this file.
30const LOG_TARGET: &str = "sub-libp2p";
31
32/// [`Protocol`] describes all possible multiaddress protocols.
33#[derive(PartialEq, Eq, Clone, Debug)]
34pub enum Protocol<'a> {
35	Dccp(u16),
36	Dns(Cow<'a, str>),
37	Dns4(Cow<'a, str>),
38	Dns6(Cow<'a, str>),
39	Dnsaddr(Cow<'a, str>),
40	Http,
41	Https,
42	Ip4(Ipv4Addr),
43	Ip6(Ipv6Addr),
44	P2pWebRtcDirect,
45	P2pWebRtcStar,
46	WebRTC,
47	Certhash(Multihash),
48	P2pWebSocketStar,
49	/// Contains the "port" to contact. Similar to TCP or UDP, 0 means "assign me a port".
50	Memory(u64),
51	Onion(Cow<'a, [u8; 10]>, u16),
52	Onion3(Cow<'a, [u8; 35]>, u16),
53	P2p(Multihash),
54	P2pCircuit,
55	Quic,
56	QuicV1,
57	Sctp(u16),
58	Tcp(u16),
59	Tls,
60	Noise,
61	Udp(u16),
62	Udt,
63	Unix(Cow<'a, str>),
64	Utp,
65	Ws(Cow<'a, str>),
66	Wss(Cow<'a, str>),
67}
68
69impl<'a> Display for Protocol<'a> {
70	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71		let protocol = LiteP2pProtocol::from(self.clone());
72		Display::fmt(&protocol, f)
73	}
74}
75
76impl<'a> From<IpAddr> for Protocol<'a> {
77	#[inline]
78	fn from(addr: IpAddr) -> Self {
79		match addr {
80			IpAddr::V4(addr) => Protocol::Ip4(addr),
81			IpAddr::V6(addr) => Protocol::Ip6(addr),
82		}
83	}
84}
85
86impl<'a> From<Ipv4Addr> for Protocol<'a> {
87	#[inline]
88	fn from(addr: Ipv4Addr) -> Self {
89		Protocol::Ip4(addr)
90	}
91}
92
93impl<'a> From<Ipv6Addr> for Protocol<'a> {
94	#[inline]
95	fn from(addr: Ipv6Addr) -> Self {
96		Protocol::Ip6(addr)
97	}
98}
99
100impl<'a> From<LiteP2pProtocol<'a>> for Protocol<'a> {
101	fn from(protocol: LiteP2pProtocol<'a>) -> Self {
102		match protocol {
103			LiteP2pProtocol::Dccp(port) => Protocol::Dccp(port),
104			LiteP2pProtocol::Dns(str) => Protocol::Dns(str),
105			LiteP2pProtocol::Dns4(str) => Protocol::Dns4(str),
106			LiteP2pProtocol::Dns6(str) => Protocol::Dns6(str),
107			LiteP2pProtocol::Dnsaddr(str) => Protocol::Dnsaddr(str),
108			LiteP2pProtocol::Http => Protocol::Http,
109			LiteP2pProtocol::Https => Protocol::Https,
110			LiteP2pProtocol::Ip4(ipv4_addr) => Protocol::Ip4(ipv4_addr),
111			LiteP2pProtocol::Ip6(ipv6_addr) => Protocol::Ip6(ipv6_addr),
112			LiteP2pProtocol::P2pWebRtcDirect => Protocol::P2pWebRtcDirect,
113			LiteP2pProtocol::P2pWebRtcStar => Protocol::P2pWebRtcStar,
114			LiteP2pProtocol::WebRTC => Protocol::WebRTC,
115			LiteP2pProtocol::Certhash(multihash) => Protocol::Certhash(multihash.into()),
116			LiteP2pProtocol::P2pWebSocketStar => Protocol::P2pWebSocketStar,
117			LiteP2pProtocol::Memory(port) => Protocol::Memory(port),
118			LiteP2pProtocol::Onion(str, port) => Protocol::Onion(str, port),
119			LiteP2pProtocol::Onion3(addr) =>
120				Protocol::Onion3(Cow::Owned(*addr.hash()), addr.port()),
121			LiteP2pProtocol::P2p(multihash) => Protocol::P2p(multihash.into()),
122			LiteP2pProtocol::P2pCircuit => Protocol::P2pCircuit,
123			LiteP2pProtocol::Quic => Protocol::Quic,
124			LiteP2pProtocol::QuicV1 => Protocol::QuicV1,
125			LiteP2pProtocol::Sctp(port) => Protocol::Sctp(port),
126			LiteP2pProtocol::Tcp(port) => Protocol::Tcp(port),
127			LiteP2pProtocol::Tls => Protocol::Tls,
128			LiteP2pProtocol::Noise => Protocol::Noise,
129			LiteP2pProtocol::Udp(port) => Protocol::Udp(port),
130			LiteP2pProtocol::Udt => Protocol::Udt,
131			LiteP2pProtocol::Unix(str) => Protocol::Unix(str),
132			LiteP2pProtocol::Utp => Protocol::Utp,
133			LiteP2pProtocol::Ws(str) => Protocol::Ws(str),
134			LiteP2pProtocol::Wss(str) => Protocol::Wss(str),
135		}
136	}
137}
138
139impl<'a> From<Protocol<'a>> for LiteP2pProtocol<'a> {
140	fn from(protocol: Protocol<'a>) -> Self {
141		match protocol {
142			Protocol::Dccp(port) => LiteP2pProtocol::Dccp(port),
143			Protocol::Dns(str) => LiteP2pProtocol::Dns(str),
144			Protocol::Dns4(str) => LiteP2pProtocol::Dns4(str),
145			Protocol::Dns6(str) => LiteP2pProtocol::Dns6(str),
146			Protocol::Dnsaddr(str) => LiteP2pProtocol::Dnsaddr(str),
147			Protocol::Http => LiteP2pProtocol::Http,
148			Protocol::Https => LiteP2pProtocol::Https,
149			Protocol::Ip4(ipv4_addr) => LiteP2pProtocol::Ip4(ipv4_addr),
150			Protocol::Ip6(ipv6_addr) => LiteP2pProtocol::Ip6(ipv6_addr),
151			Protocol::P2pWebRtcDirect => LiteP2pProtocol::P2pWebRtcDirect,
152			Protocol::P2pWebRtcStar => LiteP2pProtocol::P2pWebRtcStar,
153			Protocol::WebRTC => LiteP2pProtocol::WebRTC,
154			Protocol::Certhash(multihash) => LiteP2pProtocol::Certhash(multihash.into()),
155			Protocol::P2pWebSocketStar => LiteP2pProtocol::P2pWebSocketStar,
156			Protocol::Memory(port) => LiteP2pProtocol::Memory(port),
157			Protocol::Onion(str, port) => LiteP2pProtocol::Onion(str, port),
158			Protocol::Onion3(str, port) => LiteP2pProtocol::Onion3((str.into_owned(), port).into()),
159			Protocol::P2p(multihash) => LiteP2pProtocol::P2p(multihash.into()),
160			Protocol::P2pCircuit => LiteP2pProtocol::P2pCircuit,
161			Protocol::Quic => LiteP2pProtocol::Quic,
162			Protocol::QuicV1 => LiteP2pProtocol::QuicV1,
163			Protocol::Sctp(port) => LiteP2pProtocol::Sctp(port),
164			Protocol::Tcp(port) => LiteP2pProtocol::Tcp(port),
165			Protocol::Tls => LiteP2pProtocol::Tls,
166			Protocol::Noise => LiteP2pProtocol::Noise,
167			Protocol::Udp(port) => LiteP2pProtocol::Udp(port),
168			Protocol::Udt => LiteP2pProtocol::Udt,
169			Protocol::Unix(str) => LiteP2pProtocol::Unix(str),
170			Protocol::Utp => LiteP2pProtocol::Utp,
171			Protocol::Ws(str) => LiteP2pProtocol::Ws(str),
172			Protocol::Wss(str) => LiteP2pProtocol::Wss(str),
173		}
174	}
175}
176
177impl<'a> From<LibP2pProtocol<'a>> for Protocol<'a> {
178	fn from(protocol: LibP2pProtocol<'a>) -> Self {
179		match protocol {
180			LibP2pProtocol::Dccp(port) => Protocol::Dccp(port),
181			LibP2pProtocol::Dns(str) => Protocol::Dns(str),
182			LibP2pProtocol::Dns4(str) => Protocol::Dns4(str),
183			LibP2pProtocol::Dns6(str) => Protocol::Dns6(str),
184			LibP2pProtocol::Dnsaddr(str) => Protocol::Dnsaddr(str),
185			LibP2pProtocol::Http => Protocol::Http,
186			LibP2pProtocol::Https => Protocol::Https,
187			LibP2pProtocol::Ip4(ipv4_addr) => Protocol::Ip4(ipv4_addr),
188			LibP2pProtocol::Ip6(ipv6_addr) => Protocol::Ip6(ipv6_addr),
189			LibP2pProtocol::P2pWebRtcDirect => Protocol::P2pWebRtcDirect,
190			LibP2pProtocol::P2pWebRtcStar => Protocol::P2pWebRtcStar,
191			LibP2pProtocol::Certhash(multihash) => Protocol::Certhash(multihash.into()),
192			LibP2pProtocol::P2pWebSocketStar => Protocol::P2pWebSocketStar,
193			LibP2pProtocol::Memory(port) => Protocol::Memory(port),
194			LibP2pProtocol::Onion(str, port) => Protocol::Onion(str, port),
195			LibP2pProtocol::Onion3(addr) => Protocol::Onion3(Cow::Owned(*addr.hash()), addr.port()),
196			LibP2pProtocol::P2p(peer_id) => Protocol::P2p((*peer_id.as_ref()).into()),
197			LibP2pProtocol::P2pCircuit => Protocol::P2pCircuit,
198			LibP2pProtocol::Quic => Protocol::Quic,
199			LibP2pProtocol::QuicV1 => Protocol::QuicV1,
200			LibP2pProtocol::Sctp(port) => Protocol::Sctp(port),
201			LibP2pProtocol::Tcp(port) => Protocol::Tcp(port),
202			LibP2pProtocol::Tls => Protocol::Tls,
203			LibP2pProtocol::Noise => Protocol::Noise,
204			LibP2pProtocol::Udp(port) => Protocol::Udp(port),
205			LibP2pProtocol::Udt => Protocol::Udt,
206			LibP2pProtocol::Unix(str) => Protocol::Unix(str),
207			LibP2pProtocol::Utp => Protocol::Utp,
208			LibP2pProtocol::Ws(str) => Protocol::Ws(str),
209			LibP2pProtocol::Wss(str) => Protocol::Wss(str),
210			protocol => {
211				log::error!(
212					target: LOG_TARGET,
213					"Got unsupported multiaddr protocol '{}'",
214					protocol.tag(),
215				);
216				// Strictly speaking, this conversion is incorrect. But making protocol conversion
217				// fallible would significantly complicate the client code. As DCCP transport is not
218				// used by substrate, this conversion should be safe.
219				// Also, as of `multiaddr-18.1`, all enum variants are actually covered.
220				Protocol::Dccp(0)
221			},
222		}
223	}
224}
225
226impl<'a> From<Protocol<'a>> for LibP2pProtocol<'a> {
227	fn from(protocol: Protocol<'a>) -> Self {
228		match protocol {
229			Protocol::Dccp(port) => LibP2pProtocol::Dccp(port),
230			Protocol::Dns(str) => LibP2pProtocol::Dns(str),
231			Protocol::Dns4(str) => LibP2pProtocol::Dns4(str),
232			Protocol::Dns6(str) => LibP2pProtocol::Dns6(str),
233			Protocol::Dnsaddr(str) => LibP2pProtocol::Dnsaddr(str),
234			Protocol::Http => LibP2pProtocol::Http,
235			Protocol::Https => LibP2pProtocol::Https,
236			Protocol::Ip4(ipv4_addr) => LibP2pProtocol::Ip4(ipv4_addr),
237			Protocol::Ip6(ipv6_addr) => LibP2pProtocol::Ip6(ipv6_addr),
238			Protocol::P2pWebRtcDirect => LibP2pProtocol::P2pWebRtcDirect,
239			Protocol::P2pWebRtcStar => LibP2pProtocol::P2pWebRtcStar,
240			// Protocol #280 is called `WebRTC` in multiaddr-17.0 and `WebRTCDirect` in
241			// multiaddr-18.1.
242			Protocol::WebRTC => LibP2pProtocol::WebRTCDirect,
243			Protocol::Certhash(multihash) => LibP2pProtocol::Certhash(multihash.into()),
244			Protocol::P2pWebSocketStar => LibP2pProtocol::P2pWebSocketStar,
245			Protocol::Memory(port) => LibP2pProtocol::Memory(port),
246			Protocol::Onion(str, port) => LibP2pProtocol::Onion(str, port),
247			Protocol::Onion3(str, port) => LibP2pProtocol::Onion3((str.into_owned(), port).into()),
248			Protocol::P2p(multihash) =>
249				LibP2pProtocol::P2p(PeerId::from_multihash(multihash.into()).unwrap_or_else(|_| {
250					// This is better than making conversion fallible and complicating the
251					// client code.
252					log::error!(
253						target: LOG_TARGET,
254						"Received multiaddr with p2p multihash which is not a valid \
255						 peer_id. Replacing with random peer_id."
256					);
257					PeerId::random()
258				})),
259			Protocol::P2pCircuit => LibP2pProtocol::P2pCircuit,
260			Protocol::Quic => LibP2pProtocol::Quic,
261			Protocol::QuicV1 => LibP2pProtocol::QuicV1,
262			Protocol::Sctp(port) => LibP2pProtocol::Sctp(port),
263			Protocol::Tcp(port) => LibP2pProtocol::Tcp(port),
264			Protocol::Tls => LibP2pProtocol::Tls,
265			Protocol::Noise => LibP2pProtocol::Noise,
266			Protocol::Udp(port) => LibP2pProtocol::Udp(port),
267			Protocol::Udt => LibP2pProtocol::Udt,
268			Protocol::Unix(str) => LibP2pProtocol::Unix(str),
269			Protocol::Utp => LibP2pProtocol::Utp,
270			Protocol::Ws(str) => LibP2pProtocol::Ws(str),
271			Protocol::Wss(str) => LibP2pProtocol::Wss(str),
272		}
273	}
274}