smoldot_light/platform/
address_parse.rs1use smoldot::libp2p::multiaddr::{Multiaddr, Protocol};
19
20use super::{Address, ConnectionType, MultiStreamAddress};
21use core::{
22 net::{IpAddr, Ipv4Addr, Ipv6Addr},
23 str,
24};
25
26pub enum AddressOrMultiStreamAddress<'a> {
27 Address(Address<'a>),
28 MultiStreamAddress(MultiStreamAddress<'a>),
29}
30
31impl<'a> From<&'a AddressOrMultiStreamAddress<'a>> for ConnectionType {
32 fn from(address: &'a AddressOrMultiStreamAddress<'a>) -> ConnectionType {
33 match address {
34 AddressOrMultiStreamAddress::Address(a) => ConnectionType::from(a),
35 AddressOrMultiStreamAddress::MultiStreamAddress(a) => ConnectionType::from(a),
36 }
37 }
38}
39
40pub fn multiaddr_to_address(multiaddr: &Multiaddr) -> Result<AddressOrMultiStreamAddress, Error> {
42 let mut iter = multiaddr.iter().fuse();
43
44 let proto1 = iter.next().ok_or(Error::UnknownCombination)?;
45 let proto2 = iter.next().ok_or(Error::UnknownCombination)?;
46 let proto3 = iter.next();
47 let proto4 = iter.next();
48
49 if iter.next().is_some() {
50 return Err(Error::UnknownCombination);
51 }
52
53 Ok(match (proto1, proto2, proto3, proto4) {
54 (Protocol::Ip4(ip), Protocol::Tcp(port), None, None) => {
55 AddressOrMultiStreamAddress::Address(Address::TcpIp {
56 ip: IpAddr::V4(Ipv4Addr::from(ip)),
57 port,
58 })
59 }
60 (Protocol::Ip6(ip), Protocol::Tcp(port), None, None) => {
61 AddressOrMultiStreamAddress::Address(Address::TcpIp {
62 ip: IpAddr::V6(Ipv6Addr::from(ip)),
63 port,
64 })
65 }
66 (
67 Protocol::Dns(addr) | Protocol::Dns4(addr) | Protocol::Dns6(addr),
68 Protocol::Tcp(port),
69 None,
70 None,
71 ) => AddressOrMultiStreamAddress::Address(Address::TcpDns {
72 hostname: str::from_utf8(addr.into_bytes()).map_err(Error::NonUtf8DomainName)?,
73 port,
74 }),
75 (Protocol::Ip4(ip), Protocol::Tcp(port), Some(Protocol::Ws), None) => {
76 AddressOrMultiStreamAddress::Address(Address::WebSocketIp {
77 ip: IpAddr::V4(Ipv4Addr::from(ip)),
78 port,
79 })
80 }
81 (Protocol::Ip6(ip), Protocol::Tcp(port), Some(Protocol::Ws), None) => {
82 AddressOrMultiStreamAddress::Address(Address::WebSocketIp {
83 ip: IpAddr::V6(Ipv6Addr::from(ip)),
84 port,
85 })
86 }
87 (
88 Protocol::Dns(addr) | Protocol::Dns4(addr) | Protocol::Dns6(addr),
89 Protocol::Tcp(port),
90 Some(Protocol::Ws),
91 None,
92 ) => AddressOrMultiStreamAddress::Address(Address::WebSocketDns {
93 hostname: str::from_utf8(addr.into_bytes()).map_err(Error::NonUtf8DomainName)?,
94 port,
95 secure: false,
96 }),
97 (
98 Protocol::Dns(addr) | Protocol::Dns4(addr) | Protocol::Dns6(addr),
99 Protocol::Tcp(port),
100 Some(Protocol::Wss),
101 None,
102 )
103 | (
104 Protocol::Dns(addr) | Protocol::Dns4(addr) | Protocol::Dns6(addr),
105 Protocol::Tcp(port),
106 Some(Protocol::Tls),
107 Some(Protocol::Ws),
108 ) => AddressOrMultiStreamAddress::Address(Address::WebSocketDns {
109 hostname: str::from_utf8(addr.into_bytes()).map_err(Error::NonUtf8DomainName)?,
110 port,
111 secure: true,
112 }),
113
114 (
115 Protocol::Ip4(ip),
116 Protocol::Udp(port),
117 Some(Protocol::WebRtcDirect),
118 Some(Protocol::Certhash(multihash)),
119 ) => {
120 if multihash.hash_algorithm_code() != 0x12 {
121 return Err(Error::NonSha256Certhash);
122 }
123 let Ok(remote_certificate_sha256) = <&[u8; 32]>::try_from(multihash.data_ref()) else {
124 return Err(Error::InvalidMultihashLength);
125 };
126 AddressOrMultiStreamAddress::MultiStreamAddress(MultiStreamAddress::WebRtc {
127 ip: IpAddr::V4(Ipv4Addr::from(ip)),
128 port,
129 remote_certificate_sha256,
130 })
131 }
132
133 (
134 Protocol::Ip6(ip),
135 Protocol::Udp(port),
136 Some(Protocol::WebRtcDirect),
137 Some(Protocol::Certhash(multihash)),
138 ) => {
139 if multihash.hash_algorithm_code() != 0x12 {
140 return Err(Error::NonSha256Certhash);
141 }
142 let Ok(remote_certificate_sha256) = <&[u8; 32]>::try_from(multihash.data_ref()) else {
143 return Err(Error::InvalidMultihashLength);
144 };
145 AddressOrMultiStreamAddress::MultiStreamAddress(MultiStreamAddress::WebRtc {
146 ip: IpAddr::V6(Ipv6Addr::from(ip)),
147 port,
148 remote_certificate_sha256,
149 })
150 }
151
152 _ => return Err(Error::UnknownCombination),
153 })
154}
155
156#[derive(Debug, Clone, derive_more::Display, derive_more::Error)]
157pub enum Error {
158 UnknownCombination,
160
161 NonUtf8DomainName(str::Utf8Error),
169
170 NonSha256Certhash,
173
174 InvalidMultihashLength,
176}