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(
42 multiaddr: &'_ Multiaddr,
43) -> Result<AddressOrMultiStreamAddress<'_>, Error> {
44 let mut iter = multiaddr.iter().fuse();
45
46 let proto1 = iter.next().ok_or(Error::UnknownCombination)?;
47 let proto2 = iter.next().ok_or(Error::UnknownCombination)?;
48 let proto3 = iter.next();
49 let proto4 = iter.next();
50
51 if iter.next().is_some() {
52 return Err(Error::UnknownCombination);
53 }
54
55 Ok(match (proto1, proto2, proto3, proto4) {
56 (Protocol::Ip4(ip), Protocol::Tcp(port), None, None) => {
57 AddressOrMultiStreamAddress::Address(Address::TcpIp {
58 ip: IpAddr::V4(Ipv4Addr::from(ip)),
59 port,
60 })
61 }
62 (Protocol::Ip6(ip), Protocol::Tcp(port), None, None) => {
63 AddressOrMultiStreamAddress::Address(Address::TcpIp {
64 ip: IpAddr::V6(Ipv6Addr::from(ip)),
65 port,
66 })
67 }
68 (
69 Protocol::Dns(addr) | Protocol::Dns4(addr) | Protocol::Dns6(addr),
70 Protocol::Tcp(port),
71 None,
72 None,
73 ) => AddressOrMultiStreamAddress::Address(Address::TcpDns {
74 hostname: str::from_utf8(addr.into_bytes()).map_err(Error::NonUtf8DomainName)?,
75 port,
76 }),
77 (Protocol::Ip4(ip), Protocol::Tcp(port), Some(Protocol::Ws), None) => {
78 AddressOrMultiStreamAddress::Address(Address::WebSocketIp {
79 ip: IpAddr::V4(Ipv4Addr::from(ip)),
80 port,
81 })
82 }
83 (Protocol::Ip6(ip), Protocol::Tcp(port), Some(Protocol::Ws), None) => {
84 AddressOrMultiStreamAddress::Address(Address::WebSocketIp {
85 ip: IpAddr::V6(Ipv6Addr::from(ip)),
86 port,
87 })
88 }
89 (
90 Protocol::Dns(addr) | Protocol::Dns4(addr) | Protocol::Dns6(addr),
91 Protocol::Tcp(port),
92 Some(Protocol::Ws),
93 None,
94 ) => AddressOrMultiStreamAddress::Address(Address::WebSocketDns {
95 hostname: str::from_utf8(addr.into_bytes()).map_err(Error::NonUtf8DomainName)?,
96 port,
97 secure: false,
98 }),
99 (
100 Protocol::Dns(addr) | Protocol::Dns4(addr) | Protocol::Dns6(addr),
101 Protocol::Tcp(port),
102 Some(Protocol::Wss),
103 None,
104 )
105 | (
106 Protocol::Dns(addr) | Protocol::Dns4(addr) | Protocol::Dns6(addr),
107 Protocol::Tcp(port),
108 Some(Protocol::Tls),
109 Some(Protocol::Ws),
110 ) => AddressOrMultiStreamAddress::Address(Address::WebSocketDns {
111 hostname: str::from_utf8(addr.into_bytes()).map_err(Error::NonUtf8DomainName)?,
112 port,
113 secure: true,
114 }),
115
116 (
117 Protocol::Ip4(ip),
118 Protocol::Udp(port),
119 Some(Protocol::WebRtcDirect),
120 Some(Protocol::Certhash(multihash)),
121 ) => {
122 if multihash.hash_algorithm_code() != 0x12 {
123 return Err(Error::NonSha256Certhash);
124 }
125 let Ok(remote_certificate_sha256) = <&[u8; 32]>::try_from(multihash.data_ref()) else {
126 return Err(Error::InvalidMultihashLength);
127 };
128 AddressOrMultiStreamAddress::MultiStreamAddress(MultiStreamAddress::WebRtc {
129 ip: IpAddr::V4(Ipv4Addr::from(ip)),
130 port,
131 remote_certificate_sha256,
132 })
133 }
134
135 (
136 Protocol::Ip6(ip),
137 Protocol::Udp(port),
138 Some(Protocol::WebRtcDirect),
139 Some(Protocol::Certhash(multihash)),
140 ) => {
141 if multihash.hash_algorithm_code() != 0x12 {
142 return Err(Error::NonSha256Certhash);
143 }
144 let Ok(remote_certificate_sha256) = <&[u8; 32]>::try_from(multihash.data_ref()) else {
145 return Err(Error::InvalidMultihashLength);
146 };
147 AddressOrMultiStreamAddress::MultiStreamAddress(MultiStreamAddress::WebRtc {
148 ip: IpAddr::V6(Ipv6Addr::from(ip)),
149 port,
150 remote_certificate_sha256,
151 })
152 }
153
154 _ => return Err(Error::UnknownCombination),
155 })
156}
157
158#[derive(Debug, Clone, derive_more::Display, derive_more::Error)]
159pub enum Error {
160 UnknownCombination,
162
163 NonUtf8DomainName(str::Utf8Error),
171
172 NonSha256Certhash,
175
176 InvalidMultihashLength,
178}