Coverage Report

Created: 2024-05-16 12:16

/__w/smoldot/smoldot/repo/light-base/src/platform/address_parse.rs
Line
Count
Source (jump to first uncovered line)
1
// Smoldot
2
// Copyright (C) 2023  Pierre Krieger
3
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
5
// This program is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
9
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
// GNU General Public License for more details.
14
15
// You should have received a copy of the GNU General Public License
16
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18
use smoldot::libp2p::multiaddr::{Multiaddr, Protocol};
19
20
use super::{Address, ConnectionType, MultiStreamAddress};
21
use core::{
22
    net::{IpAddr, Ipv4Addr, Ipv6Addr},
23
    str,
24
};
25
26
pub enum AddressOrMultiStreamAddress<'a> {
27
    Address(Address<'a>),
28
    MultiStreamAddress(MultiStreamAddress<'a>),
29
}
30
31
impl<'a> From<&'a AddressOrMultiStreamAddress<'a>> for ConnectionType {
32
0
    fn from(address: &'a AddressOrMultiStreamAddress<'a>) -> ConnectionType {
33
0
        match address {
34
0
            AddressOrMultiStreamAddress::Address(a) => ConnectionType::from(a),
35
0
            AddressOrMultiStreamAddress::MultiStreamAddress(a) => ConnectionType::from(a),
36
        }
37
0
    }
Unexecuted instantiation: _RNvXNtNtCsiGub1lfKphe_13smoldot_light8platform13address_parseNtB4_14ConnectionTypeINtNtCsaYZPK01V26L_4core7convert4FromRNtB2_27AddressOrMultiStreamAddressE4from
Unexecuted instantiation: _RNvXNtNtCsih6EgvAwZF2_13smoldot_light8platform13address_parseNtB4_14ConnectionTypeINtNtCsaYZPK01V26L_4core7convert4FromRNtB2_27AddressOrMultiStreamAddressE4from
38
}
39
40
/// Parses a [`Multiaddr`] into an [`Address`] or [`MultiStreamAddress`].
41
0
pub fn multiaddr_to_address(multiaddr: &Multiaddr) -> Result<AddressOrMultiStreamAddress, Error> {
42
0
    let mut iter = multiaddr.iter().fuse();
43
44
0
    let proto1 = iter.next().ok_or(Error::UnknownCombination)?;
45
0
    let proto2 = iter.next().ok_or(Error::UnknownCombination)?;
46
0
    let proto3 = iter.next();
47
0
    let proto4 = iter.next();
48
0
49
0
    if iter.next().is_some() {
50
0
        return Err(Error::UnknownCombination);
51
0
    }
52
0
53
0
    Ok(match (proto1, proto2, proto3, proto4) {
54
0
        (Protocol::Ip4(ip), Protocol::Tcp(port), None, None) => {
55
0
            AddressOrMultiStreamAddress::Address(Address::TcpIp {
56
0
                ip: IpAddr::V4(Ipv4Addr::from(ip)),
57
0
                port,
58
0
            })
59
        }
60
0
        (Protocol::Ip6(ip), Protocol::Tcp(port), None, None) => {
61
0
            AddressOrMultiStreamAddress::Address(Address::TcpIp {
62
0
                ip: IpAddr::V6(Ipv6Addr::from(ip)),
63
0
                port,
64
0
            })
65
        }
66
        (
67
0
            Protocol::Dns(addr) | Protocol::Dns4(addr) | Protocol::Dns6(addr),
68
0
            Protocol::Tcp(port),
69
            None,
70
            None,
71
        ) => AddressOrMultiStreamAddress::Address(Address::TcpDns {
72
0
            hostname: str::from_utf8(addr.into_bytes()).map_err(Error::NonUtf8DomainName)?,
73
0
            port,
74
        }),
75
0
        (Protocol::Ip4(ip), Protocol::Tcp(port), Some(Protocol::Ws), None) => {
76
0
            AddressOrMultiStreamAddress::Address(Address::WebSocketIp {
77
0
                ip: IpAddr::V4(Ipv4Addr::from(ip)),
78
0
                port,
79
0
            })
80
        }
81
0
        (Protocol::Ip6(ip), Protocol::Tcp(port), Some(Protocol::Ws), None) => {
82
0
            AddressOrMultiStreamAddress::Address(Address::WebSocketIp {
83
0
                ip: IpAddr::V6(Ipv6Addr::from(ip)),
84
0
                port,
85
0
            })
86
        }
87
        (
88
0
            Protocol::Dns(addr) | Protocol::Dns4(addr) | Protocol::Dns6(addr),
89
0
            Protocol::Tcp(port),
90
            Some(Protocol::Ws),
91
            None,
92
        ) => AddressOrMultiStreamAddress::Address(Address::WebSocketDns {
93
0
            hostname: str::from_utf8(addr.into_bytes()).map_err(Error::NonUtf8DomainName)?,
94
0
            port,
95
            secure: false,
96
        }),
97
        (
98
0
            Protocol::Dns(addr) | Protocol::Dns4(addr) | Protocol::Dns6(addr),
99
0
            Protocol::Tcp(port),
100
            Some(Protocol::Wss),
101
            None,
102
        )
103
        | (
104
0
            Protocol::Dns(addr) | Protocol::Dns4(addr) | Protocol::Dns6(addr),
105
0
            Protocol::Tcp(port),
106
            Some(Protocol::Tls),
107
            Some(Protocol::Ws),
108
        ) => AddressOrMultiStreamAddress::Address(Address::WebSocketDns {
109
0
            hostname: str::from_utf8(addr.into_bytes()).map_err(Error::NonUtf8DomainName)?,
110
0
            port,
111
            secure: true,
112
        }),
113
114
        (
115
0
            Protocol::Ip4(ip),
116
0
            Protocol::Udp(port),
117
0
            Some(Protocol::WebRtcDirect),
118
0
            Some(Protocol::Certhash(multihash)),
119
0
        ) => {
120
0
            if multihash.hash_algorithm_code() != 0x12 {
121
0
                return Err(Error::NonSha256Certhash);
122
0
            }
123
0
            let Ok(remote_certificate_sha256) = <&[u8; 32]>::try_from(multihash.data_ref()) else {
124
0
                return Err(Error::InvalidMultihashLength);
125
            };
126
0
            AddressOrMultiStreamAddress::MultiStreamAddress(MultiStreamAddress::WebRtc {
127
0
                ip: IpAddr::V4(Ipv4Addr::from(ip)),
128
0
                port,
129
0
                remote_certificate_sha256,
130
0
            })
131
        }
132
133
        (
134
0
            Protocol::Ip6(ip),
135
0
            Protocol::Udp(port),
136
0
            Some(Protocol::WebRtcDirect),
137
0
            Some(Protocol::Certhash(multihash)),
138
0
        ) => {
139
0
            if multihash.hash_algorithm_code() != 0x12 {
140
0
                return Err(Error::NonSha256Certhash);
141
0
            }
142
0
            let Ok(remote_certificate_sha256) = <&[u8; 32]>::try_from(multihash.data_ref()) else {
143
0
                return Err(Error::InvalidMultihashLength);
144
            };
145
0
            AddressOrMultiStreamAddress::MultiStreamAddress(MultiStreamAddress::WebRtc {
146
0
                ip: IpAddr::V6(Ipv6Addr::from(ip)),
147
0
                port,
148
0
                remote_certificate_sha256,
149
0
            })
150
        }
151
152
0
        _ => return Err(Error::UnknownCombination),
153
    })
154
0
}
Unexecuted instantiation: _RNvNtNtCsiGub1lfKphe_13smoldot_light8platform13address_parse20multiaddr_to_address
Unexecuted instantiation: _RNvNtNtCsih6EgvAwZF2_13smoldot_light8platform13address_parse20multiaddr_to_address
155
156
0
#[derive(Debug, Clone, derive_more::Display)]
Unexecuted instantiation: _RNvXs1_NtNtCsiGub1lfKphe_13smoldot_light8platform13address_parseNtB5_5ErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXs1_NtNtCsih6EgvAwZF2_13smoldot_light8platform13address_parseNtB5_5ErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
157
pub enum Error {
158
    /// Unknown combination of protocols.
159
    UnknownCombination,
160
161
    /// Multiaddress contains a domain name that isn't UTF-8.
162
    ///
163
    /// > **Note**: According to RFC2181 section 11, a domain name is not necessarily an UTF-8
164
    /// >           string. Any binary data can be used as a domain name, provided it follows
165
    /// >           a few restrictions (notably its length). However, in this context, we
166
    /// >           automatically consider as non-supported a multiaddress that contains a
167
    /// >           non-UTF-8 domain name, for the sake of simplicity.
168
    NonUtf8DomainName(str::Utf8Error),
169
170
    /// Multiaddr contains a `/certhash` components whose multihash isn't using SHA-256, but the
171
    /// rest of the multiaddr requires SHA-256.
172
    NonSha256Certhash,
173
174
    /// Multiaddr contains a multihash whose length doesn't match its hash algorithm.
175
    InvalidMultihashLength,
176
}