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 Display for Protocol<'_> {
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 From<IpAddr> for Protocol<'_> {
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 From<Ipv4Addr> for Protocol<'_> {
87	#[inline]
88	fn from(addr: Ipv4Addr) -> Self {
89		Protocol::Ip4(addr)
90	}
91}
92
93impl From<Ipv6Addr> for Protocol<'_> {
94	#[inline]
95	fn from(addr: Ipv6Addr) -> Self {
96		Protocol::Ip6(addr)
97	}
98}
99
100impl<'a> From<LibP2pProtocol<'a>> for Protocol<'a> {
101	fn from(protocol: LibP2pProtocol<'a>) -> Self {
102		match protocol {
103			LibP2pProtocol::Dccp(port) => Protocol::Dccp(port),
104			LibP2pProtocol::Dns(str) => Protocol::Dns(str),
105			LibP2pProtocol::Dns4(str) => Protocol::Dns4(str),
106			LibP2pProtocol::Dns6(str) => Protocol::Dns6(str),
107			LibP2pProtocol::Dnsaddr(str) => Protocol::Dnsaddr(str),
108			LibP2pProtocol::Http => Protocol::Http,
109			LibP2pProtocol::Https => Protocol::Https,
110			LibP2pProtocol::Ip4(ipv4_addr) => Protocol::Ip4(ipv4_addr),
111			LibP2pProtocol::Ip6(ipv6_addr) => Protocol::Ip6(ipv6_addr),
112			LibP2pProtocol::P2pWebRtcDirect => Protocol::P2pWebRtcDirect,
113			LibP2pProtocol::P2pWebRtcStar => Protocol::P2pWebRtcStar,
114			LibP2pProtocol::Certhash(multihash) => Protocol::Certhash(multihash.into()),
115			LibP2pProtocol::P2pWebSocketStar => Protocol::P2pWebSocketStar,
116			LibP2pProtocol::Memory(port) => Protocol::Memory(port),
117			LibP2pProtocol::Onion(str, port) => Protocol::Onion(str, port),
118			LibP2pProtocol::Onion3(addr) => Protocol::Onion3(Cow::Owned(*addr.hash()), addr.port()),
119			LibP2pProtocol::P2p(peer_id) => Protocol::P2p((*peer_id.as_ref()).into()),
120			LibP2pProtocol::P2pCircuit => Protocol::P2pCircuit,
121			LibP2pProtocol::Quic => Protocol::Quic,
122			LibP2pProtocol::QuicV1 => Protocol::QuicV1,
123			LibP2pProtocol::Sctp(port) => Protocol::Sctp(port),
124			LibP2pProtocol::Tcp(port) => Protocol::Tcp(port),
125			LibP2pProtocol::Tls => Protocol::Tls,
126			LibP2pProtocol::Noise => Protocol::Noise,
127			LibP2pProtocol::Udp(port) => Protocol::Udp(port),
128			LibP2pProtocol::Udt => Protocol::Udt,
129			LibP2pProtocol::Unix(str) => Protocol::Unix(str),
130			LibP2pProtocol::Utp => Protocol::Utp,
131			LibP2pProtocol::Ws(str) => Protocol::Ws(str),
132			LibP2pProtocol::Wss(str) => Protocol::Wss(str),
133			protocol => {
134				log::error!(
135					target: LOG_TARGET,
136					"Got unsupported multiaddr protocol '{}'",
137					protocol.tag(),
138				);
139				// Strictly speaking, this conversion is incorrect. But making protocol conversion
140				// fallible would significantly complicate the client code. As DCCP transport is not
141				// used by substrate, this conversion should be safe.
142				// Also, as of `multiaddr-18.1`, all enum variants are actually covered.
143				Protocol::Dccp(0)
144			},
145		}
146	}
147}
148
149impl<'a> From<Protocol<'a>> for LibP2pProtocol<'a> {
150	fn from(protocol: Protocol<'a>) -> Self {
151		match protocol {
152			Protocol::Dccp(port) => LibP2pProtocol::Dccp(port),
153			Protocol::Dns(str) => LibP2pProtocol::Dns(str),
154			Protocol::Dns4(str) => LibP2pProtocol::Dns4(str),
155			Protocol::Dns6(str) => LibP2pProtocol::Dns6(str),
156			Protocol::Dnsaddr(str) => LibP2pProtocol::Dnsaddr(str),
157			Protocol::Http => LibP2pProtocol::Http,
158			Protocol::Https => LibP2pProtocol::Https,
159			Protocol::Ip4(ipv4_addr) => LibP2pProtocol::Ip4(ipv4_addr),
160			Protocol::Ip6(ipv6_addr) => LibP2pProtocol::Ip6(ipv6_addr),
161			Protocol::P2pWebRtcDirect => LibP2pProtocol::P2pWebRtcDirect,
162			Protocol::P2pWebRtcStar => LibP2pProtocol::P2pWebRtcStar,
163			// Protocol #280 is called `WebRTC` in multiaddr-17.0 and `WebRTCDirect` in
164			// multiaddr-18.1.
165			Protocol::WebRTC => LibP2pProtocol::WebRTCDirect,
166			Protocol::Certhash(multihash) => LibP2pProtocol::Certhash(multihash.into()),
167			Protocol::P2pWebSocketStar => LibP2pProtocol::P2pWebSocketStar,
168			Protocol::Memory(port) => LibP2pProtocol::Memory(port),
169			Protocol::Onion(str, port) => LibP2pProtocol::Onion(str, port),
170			Protocol::Onion3(str, port) => LibP2pProtocol::Onion3((str.into_owned(), port).into()),
171			Protocol::P2p(multihash) => {
172				LibP2pProtocol::P2p(PeerId::from_multihash(multihash.into()).unwrap_or_else(|_| {
173					// This is better than making conversion fallible and complicating the
174					// client code.
175					log::error!(
176						target: LOG_TARGET,
177						"Received multiaddr with p2p multihash which is not a valid \
178						 peer_id. Replacing with random peer_id."
179					);
180					PeerId::random()
181				}))
182			},
183			Protocol::P2pCircuit => LibP2pProtocol::P2pCircuit,
184			Protocol::Quic => LibP2pProtocol::Quic,
185			Protocol::QuicV1 => LibP2pProtocol::QuicV1,
186			Protocol::Sctp(port) => LibP2pProtocol::Sctp(port),
187			Protocol::Tcp(port) => LibP2pProtocol::Tcp(port),
188			Protocol::Tls => LibP2pProtocol::Tls,
189			Protocol::Noise => LibP2pProtocol::Noise,
190			Protocol::Udp(port) => LibP2pProtocol::Udp(port),
191			Protocol::Udt => LibP2pProtocol::Udt,
192			Protocol::Unix(str) => LibP2pProtocol::Unix(str),
193			Protocol::Utp => LibP2pProtocol::Utp,
194			Protocol::Ws(str) => LibP2pProtocol::Ws(str),
195			Protocol::Wss(str) => LibP2pProtocol::Wss(str),
196		}
197	}
198}