diem_types/network_address/
mod.rs

1// Copyright (c) The Diem Core Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4// Copyright 2021 Conflux Foundation. All rights reserved.
5// Conflux is free software and distributed under GNU General Public License.
6// See http://www.gnu.org/licenses/
7
8use crate::{
9    account_address::AccountAddress,
10    network_address::encrypted::{EncNetworkAddress, Key, KeyVersion},
11};
12use diem_crypto::{
13    traits::{CryptoMaterialError, ValidCryptoMaterialStringExt},
14    x25519,
15};
16#[cfg(any(test, feature = "fuzzing"))]
17use proptest::{collection::vec, prelude::*};
18#[cfg(any(test, feature = "fuzzing"))]
19use proptest_derive::Arbitrary;
20use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
21use std::{
22    convert::{Into, TryFrom},
23    fmt,
24    iter::IntoIterator,
25    net::{self, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs},
26    num,
27    str::FromStr,
28    string::ToString,
29};
30use thiserror::Error;
31
32pub mod encrypted;
33
34const MAX_DNS_NAME_SIZE: usize = 255;
35
36/// ## Overview
37///
38/// Diem `NetworkAddress` is a compact, efficient, self-describing and
39/// future-proof network address represented as a stack of protocols.
40/// Essentially libp2p's [multiaddr] but using [`bcs`] to describe the binary
41/// format.
42///
43/// Most validators will advertise a network address like:
44///
45/// `/dns/example.com/tcp/6180/ln-noise-ik/<x25519-pubkey>/ln-handshake/1`
46///
47/// Unpacking, the above effectively means:
48///
49/// 1. Resolve the DNS name "example.com" to an ip address, `addr`.
50/// 2. Open a TCP connection to `(addr, 6180)`.
51/// 3. Perform a Noise IK handshake and assume the peer's static pubkey is
52///    `<x25519-pubkey>`. After this step, we will have a secure, authenticated
53///    connection with the peer.
54/// 4. Perform a DiemNet version negotiation handshake (version 1).
55///
56/// ## Self-describing, Upgradable
57///
58/// One key concept behind `NetworkAddress` is that it is fully self-describing,
59/// which allows us to easily "pre-negotiate" protocols while also allowing for
60/// future upgrades. For example, it is generally unsafe to negotiate a secure
61/// transport in-band. Instead, with `NetworkAddress` we can advertise (via
62/// discovery) the specific secure transport protocol and public key that we
63/// support (and even advertise multiple incompatible versions). When a peer
64/// wishes to establish a connection with us, they already know which secure
65/// transport protocol to use; in this sense, the secure transport protocol is
66/// "pre-negotiated" by the dialier selecting which advertised protocol to use.
67///
68/// Each network address is encoded with the length of the encoded
69/// `NetworkAddress` and then the serialized protocol slices to allow for
70/// transparent upgradeability. For example, if the current software cannot
71/// decode a `NetworkAddress` within a `Vec<NetworkAddress>` it can still decode
72/// the underlying `Vec<u8>` and retrieve the remaining `Vec<NetworkAddress>`.
73///
74/// ## Transport
75///
76/// In addition, `NetworkAddress` is integrated with the DiemNet concept of a
77/// [`Transport`], which takes a `NetworkAddress` when dialing and peels off
78/// [`Protocol`]s to establish a connection and perform initial handshakes.
79/// Similarly, the [`Transport`] takes `NetworkAddress` to listen on, which
80/// tells it what protocols to expect on the socket.
81///
82/// ## Example
83///
84/// An example of a serialized `NetworkAddress`:
85///
86/// ```rust
87/// // human-readable format:
88/// //
89/// //   "/ip4/10.0.0.16/tcp/80"
90/// //
91/// // serialized NetworkAddress:
92/// //
93/// //      [ 09 02 00 0a 00 00 10 05 80 00 ]
94/// //          \  \  \  \           \  \
95/// //           \  \  \  \           \  '-- u16 tcp port
96/// //            \  \  \  \           '-- uvarint protocol id for /tcp
97/// //             \  \  \  '-- u32 ipv4 address
98/// //              \  \  '-- uvarint protocol id for /ip4
99/// //               \  '-- uvarint number of protocols
100/// //                '-- length of encoded network address
101///
102/// use bcs;
103/// use diem_types::network_address::NetworkAddress;
104/// use std::{convert::TryFrom, str::FromStr};
105///
106/// let addr = NetworkAddress::from_str("/ip4/10.0.0.16/tcp/80").unwrap();
107/// let actual_ser_addr = bcs::to_bytes(&addr).unwrap();
108///
109/// let expected_ser_addr: Vec<u8> = [9, 2, 0, 10, 0, 0, 16, 5, 80, 0].to_vec();
110///
111/// assert_eq!(expected_ser_addr, actual_ser_addr);
112/// ```
113///
114/// [multiaddr]: https://multiformats.io/multiaddr/
115/// [`Transport`]: ../netcore/transport/trait.Transport.html
116#[derive(Clone, Eq, Hash, PartialEq)]
117pub struct NetworkAddress(Vec<Protocol>);
118
119/// A single protocol in the [`NetworkAddress`] protocol stack.
120#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
121#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
122pub enum Protocol {
123    Ip4(Ipv4Addr),
124    Ip6(Ipv6Addr),
125    Dns(DnsName),
126    Dns4(DnsName),
127    Dns6(DnsName),
128    Tcp(u16),
129    Memory(u16),
130    // human-readable x25519::PublicKey is lower-case hex encoded
131    NoiseIK(x25519::PublicKey),
132    // TODO(philiphayes): use actual handshake::MessagingProtocolVersion. we
133    // probably need to move network wire into its own crate to avoid circular
134    // dependency b/w network and types.
135    Handshake(u8),
136}
137
138/// A minimally parsed DNS name. We don't really do any checking other than
139/// enforcing:
140///
141/// 1. it is not an empty string
142/// 2. it is not larger than 255 bytes
143/// 3. it does not contain any forward slash '/' characters
144///
145/// From the [DNS name syntax RFC](https://tools.ietf.org/html/rfc2181#page-13),
146/// the standard rules are:
147///
148/// 1. the total size <= 255 bytes
149/// 2. each label <= 63 bytes
150/// 3. any binary string is valid
151///
152/// So the restrictions we're adding are (1) no '/' characters and (2) the name
153/// is a valid unicode string. We do this because '/' characters are already our
154/// protocol delimiter and Rust's [`std::net::ToSocketAddrs`] API requires a
155/// `&str`.
156#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize)]
157pub struct DnsName(String);
158
159/// Possible errors when parsing a human-readable [`NetworkAddress`].
160#[derive(Error, Debug)]
161pub enum ParseError {
162    #[error("unknown protocol type: '{0}'")]
163    UnknownProtocolType(String),
164
165    #[error("unexpected end of protocol string")]
166    UnexpectedEnd,
167
168    #[error("error parsing ip4/ip6 address: {0}")]
169    ParseAddrError(#[from] net::AddrParseError),
170
171    #[error("error parsing integer: {0}")]
172    ParseIntError(#[from] num::ParseIntError),
173
174    #[error("error parsing x25519 public key: {0}")]
175    ParseX25519PubkeyError(#[from] CryptoMaterialError),
176
177    #[error("network address cannot be empty")]
178    EmptyProtocolString,
179
180    #[error("protocol string must start with '/'")]
181    InvalidProtocolString,
182
183    #[error("dns name cannot be empty")]
184    EmptyDnsNameString,
185
186    #[error("dns name cannot contain '/' characters")]
187    InvalidDnsNameCharacter,
188
189    #[error("dns name is too long: len: {0} bytes, max len: 255 bytes")]
190    DnsNameTooLong(usize),
191
192    #[error("error decrypting network address")]
193    DecryptError,
194
195    #[error("bcs error: {0}")]
196    BCSError(#[from] bcs::Error),
197}
198
199#[derive(Error, Debug)]
200#[error("network address cannot be empty")]
201pub struct EmptyError;
202
203////////////////////
204// NetworkAddress //
205////////////////////
206
207impl NetworkAddress {
208    fn new(protocols: Vec<Protocol>) -> Self { Self(protocols) }
209
210    pub fn as_slice(&self) -> &[Protocol] { self.0.as_slice() }
211
212    pub fn push(mut self, proto: Protocol) -> Self {
213        self.0.push(proto);
214        self
215    }
216
217    pub fn extend_from_slice(mut self, protos: &[Protocol]) -> Self {
218        self.0.extend_from_slice(protos);
219        self
220    }
221
222    /// See [`EncNetworkAddress::encrypt`].
223    pub fn encrypt(
224        self, shared_val_netaddr_key: &Key, key_version: KeyVersion,
225        account: &AccountAddress, seq_num: u64, addr_idx: u32,
226    ) -> Result<EncNetworkAddress, ParseError> {
227        EncNetworkAddress::encrypt(
228            self,
229            shared_val_netaddr_key,
230            key_version,
231            account,
232            seq_num,
233            addr_idx,
234        )
235    }
236
237    /// Given a base `NetworkAddress`, append production protocols and
238    /// return the modified `NetworkAddress`.
239    ///
240    /// ### Example
241    ///
242    /// ```rust
243    /// use diem_crypto::{traits::ValidCryptoMaterialStringExt, x25519};
244    /// use diem_types::network_address::NetworkAddress;
245    /// use std::str::FromStr;
246    ///
247    /// let pubkey_str = "080e287879c918794170e258bfaddd75acac5b3e350419044655e4983a487120";
248    /// let pubkey = x25519::PublicKey::from_encoded_string(pubkey_str).unwrap();
249    /// let addr = NetworkAddress::from_str("/dns/example.com/tcp/6180").unwrap();
250    /// let addr = addr.append_prod_protos(pubkey, 0);
251    /// assert_eq!(
252    ///     addr.to_string(),
253    ///     "/dns/example.com/tcp/6180/ln-noise-ik/080e287879c918794170e258bfaddd75acac5b3e350419044655e4983a487120/ln-handshake/0",
254    /// );
255    /// ```
256    // TODO(philiphayes): use handshake version enum
257    pub fn append_prod_protos(
258        self, network_pubkey: x25519::PublicKey, handshake_version: u8,
259    ) -> Self {
260        self.push(Protocol::NoiseIK(network_pubkey))
261            .push(Protocol::Handshake(handshake_version))
262    }
263
264    /// Check that a `NetworkAddress` looks like a typical DiemNet address with
265    /// associated protocols.
266    ///
267    /// "typical" DiemNet addresses begin with a transport protocol:
268    ///
269    /// `"/ip4/<addr>/tcp/<port>"` or
270    /// `"/ip6/<addr>/tcp/<port>"` or
271    /// `"/dns4/<domain>/tcp/<port>"` or
272    /// `"/dns6/<domain>/tcp/<port>"` or
273    /// `"/dns/<domain>/tcp/<port>"` or
274    /// cfg!(test) `"/memory/<port>"`
275    ///
276    /// followed by transport upgrade handshake protocols:
277    ///
278    /// `"/ln-noise-ik/<pubkey>/ln-handshake/<version>"`
279    ///
280    /// ### Example
281    ///
282    /// ```rust
283    /// use diem_types::network_address::NetworkAddress;
284    /// use std::str::FromStr;
285    ///
286    /// let addr_str = "/ip4/1.2.3.4/tcp/6180/ln-noise-ik/080e287879c918794170e258bfaddd75acac5b3e350419044655e4983a487120/ln-handshake/0";
287    /// let addr = NetworkAddress::from_str(addr_str).unwrap();
288    /// assert!(addr.is_diemnet_addr());
289    /// ```
290    pub fn is_diemnet_addr(&self) -> bool {
291        parse_diemnet_protos(self.as_slice()).is_some()
292    }
293
294    /// Retrieves the IP address from the network address
295    pub fn find_ip_addr(&self) -> Option<IpAddr> {
296        self.0.iter().find_map(|proto| match proto {
297            Protocol::Ip4(addr) => Some(IpAddr::V4(*addr)),
298            Protocol::Ip6(addr) => Some(IpAddr::V6(*addr)),
299            _ => None,
300        })
301    }
302
303    /// A temporary, hacky function to parse out the first
304    /// `/ln-noise-ik/<pubkey>` from a `NetworkAddress`. We can remove this
305    /// soon, when we move to the interim "monolithic" transport model.
306    pub fn find_noise_proto(&self) -> Option<x25519::PublicKey> {
307        self.0.iter().find_map(|proto| match proto {
308            Protocol::NoiseIK(pubkey) => Some(*pubkey),
309            _ => None,
310        })
311    }
312
313    /// A function to rotate public keys for `NoiseIK` protocols
314    pub fn rotate_noise_public_key(
315        &mut self, to_replace: &x25519::PublicKey,
316        new_public_key: &x25519::PublicKey,
317    ) {
318        for protocol in self.0.iter_mut() {
319            // Replace the public key in any Noise protocols that match the key
320            if let Protocol::NoiseIK(public_key) = protocol {
321                if public_key == to_replace {
322                    *protocol = Protocol::NoiseIK(*new_public_key);
323                }
324            }
325        }
326    }
327
328    #[cfg(any(test, feature = "fuzzing"))]
329    pub fn mock() -> Self { NetworkAddress::new(vec![Protocol::Memory(1234)]) }
330}
331
332impl IntoIterator for NetworkAddress {
333    type IntoIter = std::vec::IntoIter<Self::Item>;
334    type Item = Protocol;
335
336    fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
337}
338
339impl FromStr for NetworkAddress {
340    type Err = ParseError;
341
342    fn from_str(s: &str) -> Result<Self, Self::Err> {
343        if s.is_empty() {
344            return Err(ParseError::EmptyProtocolString);
345        }
346
347        let mut protocols = Vec::new();
348        let mut parts_iter = s.split('/');
349
350        // the first character must be '/'
351        if parts_iter.next() != Some("") {
352            return Err(ParseError::InvalidProtocolString);
353        }
354
355        // parse all `Protocol`s
356        while let Some(protocol_type) = parts_iter.next() {
357            protocols.push(Protocol::parse(protocol_type, &mut parts_iter)?);
358        }
359
360        Ok(NetworkAddress::new(protocols))
361    }
362}
363
364impl ToSocketAddrs for NetworkAddress {
365    type Iter = std::vec::IntoIter<SocketAddr>;
366
367    fn to_socket_addrs(&self) -> Result<Self::Iter, std::io::Error> {
368        if let Some(((ipaddr, port), _)) = parse_ip_tcp(self.as_slice()) {
369            Ok(vec![SocketAddr::new(ipaddr, port)].into_iter())
370        } else if let Some(((ip_filter, dns_name, port), _)) =
371            parse_dns_tcp(self.as_slice())
372        {
373            format!("{}:{}", dns_name, port).to_socket_addrs().map(|v| {
374                v.filter(|addr| ip_filter.matches(addr.ip()))
375                    .collect::<Vec<_>>()
376                    .into_iter()
377            })
378        } else {
379            Ok(vec![].into_iter())
380        }
381    }
382}
383
384impl TryFrom<Vec<Protocol>> for NetworkAddress {
385    type Error = EmptyError;
386
387    fn try_from(value: Vec<Protocol>) -> Result<Self, Self::Error> {
388        if value.is_empty() {
389            Err(EmptyError)
390        } else {
391            Ok(NetworkAddress::new(value))
392        }
393    }
394}
395
396impl From<Protocol> for NetworkAddress {
397    fn from(proto: Protocol) -> NetworkAddress {
398        NetworkAddress::new(vec![proto])
399    }
400}
401
402impl From<SocketAddr> for NetworkAddress {
403    fn from(sockaddr: SocketAddr) -> NetworkAddress {
404        let ip_proto = Protocol::from(sockaddr.ip());
405        let tcp_proto = Protocol::Tcp(sockaddr.port());
406        NetworkAddress::new(vec![ip_proto, tcp_proto])
407    }
408}
409
410impl fmt::Display for NetworkAddress {
411    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
412        for protocol in self.0.iter() {
413            protocol.fmt(f)?;
414        }
415        Ok(())
416    }
417}
418
419impl fmt::Debug for NetworkAddress {
420    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
421        fmt::Display::fmt(self, f)
422    }
423}
424
425impl Serialize for NetworkAddress {
426    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
427    where S: Serializer {
428        if serializer.is_human_readable() {
429            serializer.serialize_str(&self.to_string())
430        } else {
431            #[derive(Serialize)]
432            #[serde(rename = "NetworkAddress")]
433            struct Wrapper<'a>(#[serde(with = "serde_bytes")] &'a [u8]);
434
435            bcs::to_bytes(&self.as_slice())
436                .map_err(serde::ser::Error::custom)
437                .and_then(|v| Wrapper(&v).serialize(serializer))
438        }
439    }
440}
441
442impl<'de> Deserialize<'de> for NetworkAddress {
443    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
444    where D: Deserializer<'de> {
445        if deserializer.is_human_readable() {
446            let s = <String>::deserialize(deserializer)?;
447            NetworkAddress::from_str(s.as_str()).map_err(de::Error::custom)
448        } else {
449            #[derive(Deserialize)]
450            #[serde(rename = "NetworkAddress")]
451            struct Wrapper(#[serde(with = "serde_bytes")] Vec<u8>);
452
453            Wrapper::deserialize(deserializer)
454                .and_then(|v| bcs::from_bytes(&v.0).map_err(de::Error::custom))
455                .and_then(|v: Vec<Protocol>| {
456                    NetworkAddress::try_from(v).map_err(de::Error::custom)
457                })
458        }
459    }
460}
461
462#[cfg(any(test, feature = "fuzzing"))]
463impl Arbitrary for NetworkAddress {
464    type Parameters = ();
465    type Strategy = BoxedStrategy<Self>;
466
467    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
468        vec(any::<Protocol>(), 1..10)
469            .prop_map(NetworkAddress::new)
470            .boxed()
471    }
472}
473
474#[cfg(any(test, feature = "fuzzing"))]
475pub fn arb_diemnet_addr() -> impl Strategy<Value = NetworkAddress> {
476    let arb_transport_protos = prop_oneof![
477        any::<u16>().prop_map(|port| vec![Protocol::Memory(port)]),
478        any::<(Ipv4Addr, u16)>().prop_map(|(addr, port)| vec![
479            Protocol::Ip4(addr),
480            Protocol::Tcp(port)
481        ]),
482        any::<(Ipv6Addr, u16)>().prop_map(|(addr, port)| vec![
483            Protocol::Ip6(addr),
484            Protocol::Tcp(port)
485        ]),
486        any::<(DnsName, u16)>().prop_map(|(name, port)| vec![
487            Protocol::Dns(name),
488            Protocol::Tcp(port)
489        ]),
490        any::<(DnsName, u16)>().prop_map(|(name, port)| vec![
491            Protocol::Dns4(name),
492            Protocol::Tcp(port)
493        ]),
494        any::<(DnsName, u16)>().prop_map(|(name, port)| vec![
495            Protocol::Dns6(name),
496            Protocol::Tcp(port)
497        ]),
498    ];
499    let arb_diemnet_protos =
500        any::<(x25519::PublicKey, u8)>().prop_map(|(pubkey, hs)| {
501            vec![Protocol::NoiseIK(pubkey), Protocol::Handshake(hs)]
502        });
503
504    (arb_transport_protos, arb_diemnet_protos).prop_map(
505        |(mut transport_protos, mut diemnet_protos)| {
506            transport_protos.append(&mut diemnet_protos);
507            NetworkAddress::new(transport_protos)
508        },
509    )
510}
511
512//////////////
513// Protocol //
514//////////////
515
516impl fmt::Display for Protocol {
517    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
518        use self::Protocol::*;
519        match self {
520            Ip4(addr) => write!(f, "/ip4/{}", addr),
521            Ip6(addr) => write!(f, "/ip6/{}", addr),
522            Dns(domain) => write!(f, "/dns/{}", domain),
523            Dns4(domain) => write!(f, "/dns4/{}", domain),
524            Dns6(domain) => write!(f, "/dns6/{}", domain),
525            Tcp(port) => write!(f, "/tcp/{}", port),
526            Memory(port) => write!(f, "/memory/{}", port),
527            NoiseIK(pubkey) => write!(
528                f,
529                "/ln-noise-ik/{}",
530                pubkey
531                    .to_encoded_string()
532                    .expect("ValidCryptoMaterialStringExt::to_encoded_string is infallible")
533            ),
534            Handshake(version) => write!(f, "/ln-handshake/{}", version),
535        }
536    }
537}
538
539fn parse_one<'a, T>(
540    args: &mut impl Iterator<Item = &'a str>,
541) -> Result<T, ParseError>
542where
543    T: FromStr,
544    T::Err: Into<ParseError>,
545{
546    let next_arg = args.next().ok_or(ParseError::UnexpectedEnd)?;
547    next_arg.parse().map_err(Into::into)
548}
549
550impl Protocol {
551    fn parse<'a>(
552        protocol_type: &str, args: &mut impl Iterator<Item = &'a str>,
553    ) -> Result<Protocol, ParseError> {
554        let protocol = match protocol_type {
555            "ip4" => Protocol::Ip4(parse_one(args)?),
556            "ip6" => Protocol::Ip6(parse_one(args)?),
557            "dns" => Protocol::Dns(parse_one(args)?),
558            "dns4" => Protocol::Dns4(parse_one(args)?),
559            "dns6" => Protocol::Dns6(parse_one(args)?),
560            "tcp" => Protocol::Tcp(parse_one(args)?),
561            "memory" => Protocol::Memory(parse_one(args)?),
562            "ln-noise-ik" => {
563                Protocol::NoiseIK(x25519::PublicKey::from_encoded_string(
564                    args.next().ok_or(ParseError::UnexpectedEnd)?,
565                )?)
566            }
567            "ln-handshake" => Protocol::Handshake(parse_one(args)?),
568            unknown => {
569                return Err(ParseError::UnknownProtocolType(
570                    unknown.to_string(),
571                ))
572            }
573        };
574        Ok(protocol)
575    }
576}
577
578impl From<IpAddr> for Protocol {
579    fn from(addr: IpAddr) -> Protocol {
580        match addr {
581            IpAddr::V4(addr) => Protocol::Ip4(addr),
582            IpAddr::V6(addr) => Protocol::Ip6(addr),
583        }
584    }
585}
586
587/////////////
588// DnsName //
589/////////////
590
591impl DnsName {
592    fn validate(s: &str) -> Result<(), ParseError> {
593        if s.is_empty() {
594            Err(ParseError::EmptyDnsNameString)
595        } else if s.as_bytes().len() > MAX_DNS_NAME_SIZE {
596            Err(ParseError::DnsNameTooLong(s.as_bytes().len()))
597        } else if s.contains('/') {
598            Err(ParseError::InvalidDnsNameCharacter)
599        } else {
600            Ok(())
601        }
602    }
603}
604
605impl From<DnsName> for String {
606    fn from(dns_name: DnsName) -> String { dns_name.0 }
607}
608
609impl AsRef<str> for DnsName {
610    fn as_ref(&self) -> &str { self.0.as_ref() }
611}
612
613impl TryFrom<String> for DnsName {
614    type Error = ParseError;
615
616    fn try_from(s: String) -> Result<Self, Self::Error> {
617        DnsName::validate(s.as_str()).map(|_| DnsName(s))
618    }
619}
620
621impl FromStr for DnsName {
622    type Err = ParseError;
623
624    fn from_str(s: &str) -> Result<Self, Self::Err> {
625        DnsName::validate(s).map(|_| DnsName(s.to_owned()))
626    }
627}
628
629impl fmt::Display for DnsName {
630    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) }
631}
632
633impl<'de> Deserialize<'de> for DnsName {
634    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
635    where D: Deserializer<'de> {
636        #[derive(Deserialize)]
637        #[serde(rename = "DnsName")]
638        struct DeserializeWrapper(String);
639
640        let wrapper = DeserializeWrapper::deserialize(deserializer)?;
641        let name = DnsName::try_from(wrapper.0).map_err(de::Error::custom)?;
642        Ok(name)
643    }
644}
645
646#[cfg(any(test, feature = "fuzzing"))]
647impl Arbitrary for DnsName {
648    type Parameters = ();
649    type Strategy = BoxedStrategy<Self>;
650
651    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
652        // generate arbitrary unicode strings
653        // + without '/'
654        // + without control characters (so we can print them easily)
655        // + between 1-255 bytes in length
656        r"[^/\pC]{1,255}"
657            // need this filter b/c the number of unicode characters does not
658            // necessarily equal the number of bytes.
659            .prop_filter_map("string too long", |s| {
660                if s.as_bytes().len() > MAX_DNS_NAME_SIZE {
661                    None
662                } else {
663                    Some(DnsName(s))
664                }
665            })
666            .boxed()
667    }
668}
669
670/////////////
671// Parsing //
672/////////////
673
674/// parse the `&[Protocol]` into the `"/memory/<port>"` prefix and unparsed
675/// `&[Protocol]` suffix.
676pub fn parse_memory(protos: &[Protocol]) -> Option<(u16, &[Protocol])> {
677    protos
678        .split_first()
679        .and_then(|(first, suffix)| match first {
680            Protocol::Memory(port) => Some((*port, suffix)),
681            _ => None,
682        })
683}
684
685/// parse the `&[Protocol]` into the `"/ip4/<addr>/tcp/<port>"` or
686/// `"/ip6/<addr>/tcp/<port>"` prefix and unparsed `&[Protocol]` suffix.
687pub fn parse_ip_tcp(
688    protos: &[Protocol],
689) -> Option<((IpAddr, u16), &[Protocol])> {
690    use Protocol::*;
691
692    if protos.len() < 2 {
693        return None;
694    }
695
696    let (prefix, suffix) = protos.split_at(2);
697    match prefix {
698        [Ip4(ip), Tcp(port)] => Some(((IpAddr::V4(*ip), *port), suffix)),
699        [Ip6(ip), Tcp(port)] => Some(((IpAddr::V6(*ip), *port), suffix)),
700        _ => None,
701    }
702}
703
704#[derive(Copy, Clone, Debug, Eq, PartialEq)]
705pub enum IpFilter {
706    Any,
707    OnlyIp4,
708    OnlyIp6,
709}
710
711impl IpFilter {
712    pub fn matches(&self, ipaddr: IpAddr) -> bool {
713        match self {
714            IpFilter::Any => true,
715            IpFilter::OnlyIp4 => ipaddr.is_ipv4(),
716            IpFilter::OnlyIp6 => ipaddr.is_ipv6(),
717        }
718    }
719}
720
721/// parse the `&[Protocol]` into the `"/dns/<domain>/tcp/<port>"`,
722/// `"/dns4/<domain>/tcp/<port>"`, or `"/dns6/<domain>/tcp/<port>"` prefix and
723/// unparsed `&[Protocol]` suffix.
724pub fn parse_dns_tcp(
725    protos: &[Protocol],
726) -> Option<((IpFilter, &DnsName, u16), &[Protocol])> {
727    use Protocol::*;
728
729    if protos.len() < 2 {
730        return None;
731    }
732
733    let (prefix, suffix) = protos.split_at(2);
734    match prefix {
735        [Dns(name), Tcp(port)] => Some(((IpFilter::Any, name, *port), suffix)),
736        [Dns4(name), Tcp(port)] => {
737            Some(((IpFilter::OnlyIp4, name, *port), suffix))
738        }
739        [Dns6(name), Tcp(port)] => {
740            Some(((IpFilter::OnlyIp6, name, *port), suffix))
741        }
742        _ => None,
743    }
744}
745
746pub fn parse_tcp(protos: &[Protocol]) -> Option<((String, u16), &[Protocol])> {
747    use Protocol::*;
748
749    if protos.len() < 2 {
750        return None;
751    }
752
753    let (prefix, suffix) = protos.split_at(2);
754    match prefix {
755        [Ip4(ip), Tcp(port)] => Some(((ip.to_string(), *port), suffix)),
756        [Ip6(ip), Tcp(port)] => Some(((ip.to_string(), *port), suffix)),
757        [Dns(name), Tcp(port)] => Some(((name.to_string(), *port), suffix)),
758        [Dns4(name), Tcp(port)] => Some(((name.to_string(), *port), suffix)),
759        [Dns6(name), Tcp(port)] => Some(((name.to_string(), *port), suffix)),
760        _ => None,
761    }
762}
763
764/// parse the `&[Protocol]` into the `"/ln-noise-ik/<pubkey>"` prefix and
765/// unparsed `&[Protocol]` suffix.
766pub fn parse_noise_ik(
767    protos: &[Protocol],
768) -> Option<(&x25519::PublicKey, &[Protocol])> {
769    match protos.split_first() {
770        Some((Protocol::NoiseIK(pubkey), suffix)) => Some((pubkey, suffix)),
771        _ => None,
772    }
773}
774
775/// parse the `&[Protocol]` into the `"/ln-handshake/<version>"` prefix and
776/// unparsed `&[Protocol]` suffix.
777pub fn parse_handshake(protos: &[Protocol]) -> Option<(u8, &[Protocol])> {
778    match protos.split_first() {
779        Some((Protocol::Handshake(version), suffix)) => {
780            Some((*version, suffix))
781        }
782        _ => None,
783    }
784}
785
786/// parse canonical diemnet protocols
787///
788/// See: [`NetworkAddress::is_diemnet_addr`]
789fn parse_diemnet_protos(protos: &[Protocol]) -> Option<&[Protocol]> {
790    // parse base transport layer
791    // ---
792    // parse_ip_tcp
793    // <or> parse_dns_tcp
794    // <or> cfg!(test) parse_memory
795
796    let transport_suffix = parse_ip_tcp(protos)
797        .map(|x| x.1)
798        .or_else(|| parse_dns_tcp(protos).map(|x| x.1))
799        .or_else(|| {
800            if cfg!(test) {
801                parse_memory(protos).map(|x| x.1)
802            } else {
803                None
804            }
805        })?;
806
807    // parse authentication layer
808    // ---
809    // parse_noise_ik
810
811    let auth_suffix = parse_noise_ik(transport_suffix).map(|x| x.1)?;
812
813    // parse handshake layer
814
815    let handshake_suffix = parse_handshake(auth_suffix).map(|x| x.1)?;
816
817    // ensure no trailing protos after handshake
818
819    if handshake_suffix.is_empty() {
820        Some(protos)
821    } else {
822        None
823    }
824}
825
826///////////
827// Tests //
828///////////
829
830#[cfg(test)]
831mod test {
832    use super::*;
833    use anyhow::format_err;
834    use bcs::test_helpers::assert_canonical_encode_decode;
835
836    #[test]
837    fn test_network_address_display() {
838        use super::Protocol::*;
839        let addr = NetworkAddress::new(vec![Memory(1234), Handshake(0)]);
840        assert_eq!("/memory/1234/ln-handshake/0", addr.to_string());
841    }
842
843    #[test]
844    fn test_network_address_parse_success() {
845        use super::Protocol::*;
846
847        let pubkey_str =
848            "080e287879c918794170e258bfaddd75acac5b3e350419044655e4983a487120";
849        let pubkey =
850            x25519::PublicKey::from_encoded_string(pubkey_str).unwrap();
851        let noise_addr_str = format!(
852            "/dns/example.com/tcp/1234/ln-noise-ik/{}/ln-handshake/5",
853            pubkey_str
854        );
855
856        let test_cases = [
857            (
858                "/memory/1234/ln-handshake/0",
859                vec![Memory(1234), Handshake(0)],
860            ),
861            (
862                "/ip4/12.34.56.78/tcp/1234/ln-handshake/123",
863                vec![
864                    Ip4(Ipv4Addr::new(12, 34, 56, 78)),
865                    Tcp(1234),
866                    Handshake(123),
867                ],
868            ),
869            (
870                "/ip6/::1/tcp/0",
871                vec![Ip6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), Tcp(0)],
872            ),
873            (
874                "/ip6/dead:beef::c0de/tcp/8080",
875                vec![
876                    Ip6(Ipv6Addr::new(0xdead, 0xbeef, 0, 0, 0, 0, 0, 0xc0de)),
877                    Tcp(8080),
878                ],
879            ),
880            (
881                "/dns/example.com/tcp/80",
882                vec![Dns(DnsName("example.com".to_owned())), Tcp(80)],
883            ),
884            (
885                &noise_addr_str,
886                vec![
887                    Dns(DnsName("example.com".to_owned())),
888                    Tcp(1234),
889                    NoiseIK(pubkey),
890                    Handshake(5),
891                ],
892            ),
893        ];
894
895        for (addr_str, expected_address) in &test_cases {
896            let actual_address = NetworkAddress::from_str(addr_str)
897                .map_err(|err| {
898                    format_err!(
899                        "failed to parse: input: '{}', err: {}",
900                        addr_str,
901                        err
902                    )
903                })
904                .unwrap();
905            let expected_address =
906                NetworkAddress::new(expected_address.clone());
907            assert_eq!(actual_address, expected_address);
908        }
909    }
910
911    #[test]
912    fn test_network_address_parse_fail() {
913        let test_cases = [
914            "",
915            "/",
916            "/foobar",
917            "/tcp",
918            "tcp/1234",
919            "/tcp/1234/",
920            "/tcp/1234/foobar/5",
921            "/tcp/99999",
922            "/ip4/1.1.1",
923            "/ip4/1.1.1.1.",
924            "/ip4/1.1.1.1.1",
925            "/ip4/1.1.1.999.1",
926        ];
927
928        for &addr_str in &test_cases {
929            if let Ok(addr) = NetworkAddress::from_str(addr_str) {
930                panic!(
931                    "parsing should fail: input: '{}', output: '{}'",
932                    addr_str, addr
933                );
934            }
935        }
936    }
937
938    #[test]
939    fn test_parse_memory() {
940        let addr = NetworkAddress::from_str("/memory/123").unwrap();
941        let expected_suffix: &[Protocol] = &[];
942        assert_eq!(
943            parse_memory(addr.as_slice()).unwrap(),
944            (123, expected_suffix)
945        );
946
947        let addr = NetworkAddress::from_str("/memory/123/tcp/999").unwrap();
948        let expected_suffix: &[Protocol] = &[Protocol::Tcp(999)];
949        assert_eq!(
950            parse_memory(addr.as_slice()).unwrap(),
951            (123, expected_suffix)
952        );
953
954        let addr = NetworkAddress::from_str("/tcp/999/memory/123").unwrap();
955        assert_eq!(None, parse_memory(addr.as_slice()));
956    }
957
958    #[test]
959    fn test_parse_ip_tcp() {
960        let addr = NetworkAddress::from_str("/ip4/1.2.3.4/tcp/123").unwrap();
961        let expected_suffix: &[Protocol] = &[];
962        assert_eq!(
963            parse_ip_tcp(addr.as_slice()).unwrap(),
964            ((IpAddr::from_str("1.2.3.4").unwrap(), 123), expected_suffix)
965        );
966
967        let addr = NetworkAddress::from_str("/ip6/::1/tcp/123").unwrap();
968        let expected_suffix: &[Protocol] = &[];
969        assert_eq!(
970            parse_ip_tcp(addr.as_slice()).unwrap(),
971            ((IpAddr::from_str("::1").unwrap(), 123), expected_suffix)
972        );
973
974        let addr =
975            NetworkAddress::from_str("/ip6/::1/tcp/123/memory/999").unwrap();
976        let expected_suffix: &[Protocol] = &[Protocol::Memory(999)];
977        assert_eq!(
978            parse_ip_tcp(addr.as_slice()).unwrap(),
979            ((IpAddr::from_str("::1").unwrap(), 123), expected_suffix)
980        );
981
982        let addr = NetworkAddress::from_str("/tcp/999/memory/123").unwrap();
983        assert_eq!(None, parse_ip_tcp(addr.as_slice()));
984    }
985
986    #[test]
987    fn test_parse_dns_tcp() {
988        let dns_name = DnsName::from_str("example.com").unwrap();
989        let addr =
990            NetworkAddress::from_str("/dns/example.com/tcp/123").unwrap();
991        let expected_suffix: &[Protocol] = &[];
992        assert_eq!(
993            parse_dns_tcp(addr.as_slice()).unwrap(),
994            ((IpFilter::Any, &dns_name, 123), expected_suffix)
995        );
996
997        let addr =
998            NetworkAddress::from_str("/dns4/example.com/tcp/123").unwrap();
999        let expected_suffix: &[Protocol] = &[];
1000        assert_eq!(
1001            parse_dns_tcp(addr.as_slice()).unwrap(),
1002            ((IpFilter::OnlyIp4, &dns_name, 123), expected_suffix)
1003        );
1004
1005        let addr =
1006            NetworkAddress::from_str("/dns6/example.com/tcp/123").unwrap();
1007        let expected_suffix: &[Protocol] = &[];
1008        assert_eq!(
1009            parse_dns_tcp(addr.as_slice()).unwrap(),
1010            ((IpFilter::OnlyIp6, &dns_name, 123), expected_suffix)
1011        );
1012
1013        let addr =
1014            NetworkAddress::from_str("/dns/example.com/tcp/123/memory/44")
1015                .unwrap();
1016        let expected_suffix: &[Protocol] = &[Protocol::Memory(44)];
1017        assert_eq!(
1018            parse_dns_tcp(addr.as_slice()).unwrap(),
1019            ((IpFilter::Any, &dns_name, 123), expected_suffix)
1020        );
1021
1022        let addr = NetworkAddress::from_str("/tcp/999/memory/123").unwrap();
1023        assert_eq!(None, parse_dns_tcp(addr.as_slice()));
1024    }
1025
1026    #[test]
1027    fn test_parse_noise_ik() {
1028        let pubkey_str =
1029            "080e287879c918794170e258bfaddd75acac5b3e350419044655e4983a487120";
1030        let pubkey =
1031            x25519::PublicKey::from_encoded_string(pubkey_str).unwrap();
1032        let addr =
1033            NetworkAddress::from_str(&format!("/ln-noise-ik/{}", pubkey_str))
1034                .unwrap();
1035        let expected_suffix: &[Protocol] = &[];
1036        assert_eq!(
1037            parse_noise_ik(addr.as_slice()).unwrap(),
1038            (&pubkey, expected_suffix)
1039        );
1040
1041        let addr = NetworkAddress::from_str(&format!(
1042            "/ln-noise-ik/{}/tcp/999",
1043            pubkey_str
1044        ))
1045        .unwrap();
1046        let expected_suffix: &[Protocol] = &[Protocol::Tcp(999)];
1047        assert_eq!(
1048            parse_noise_ik(addr.as_slice()).unwrap(),
1049            (&pubkey, expected_suffix)
1050        );
1051
1052        let addr = NetworkAddress::from_str("/tcp/999/memory/123").unwrap();
1053        assert_eq!(None, parse_noise_ik(addr.as_slice()));
1054    }
1055
1056    #[test]
1057    fn test_parse_handshake() {
1058        let addr = NetworkAddress::from_str("/ln-handshake/0").unwrap();
1059        let expected_suffix: &[Protocol] = &[];
1060        assert_eq!(
1061            parse_handshake(addr.as_slice()).unwrap(),
1062            (0, expected_suffix),
1063        );
1064
1065        let addr = NetworkAddress::from_str("/ln-handshake/0/tcp/999").unwrap();
1066        let expected_suffix: &[Protocol] = &[Protocol::Tcp(999)];
1067        assert_eq!(
1068            parse_handshake(addr.as_slice()).unwrap(),
1069            (0, expected_suffix),
1070        );
1071
1072        let addr = NetworkAddress::from_str("/tcp/999/memory/123").unwrap();
1073        assert_eq!(None, parse_handshake(addr.as_slice()));
1074    }
1075
1076    proptest! {
1077        #[test]
1078        fn test_network_address_canonical_serialization(addr in any::<NetworkAddress>()) {
1079            assert_canonical_encode_decode(addr);
1080        }
1081
1082        #[test]
1083        fn test_network_address_display_roundtrip(addr in any::<NetworkAddress>()) {
1084            let addr_str = addr.to_string();
1085            let addr_parsed = NetworkAddress::from_str(&addr_str).unwrap();
1086            assert_eq!(addr, addr_parsed);
1087        }
1088
1089        #[test]
1090        fn test_is_diemnet_addr(addr in arb_diemnet_addr()) {
1091            assert!(addr.is_diemnet_addr(), "addr.is_diemnet_addr() = false; addr: '{}'", addr);
1092        }
1093
1094        #[test]
1095        fn test_is_not_diemnet_addr_with_trailing(
1096            addr in arb_diemnet_addr(),
1097            addr_suffix in any::<NetworkAddress>(),
1098        ) {
1099            // A valid DiemNet addr w/ unexpected trailing protocols should not parse.
1100            let addr = addr.extend_from_slice(addr_suffix.as_slice());
1101            assert!(!addr.is_diemnet_addr(), "addr.is_diemnet_addr() = true; addr: '{}'", addr);
1102        }
1103    }
1104}