cuprate_wire/network_address/
epee_builder.rs

1//! Address epee serialization
2//!
3//! Addresses needs to be serialized into a specific format before being sent to other peers.
4//! This module is handling this particular construction.
5//!
6
7//---------------------------------------------------------------------------------------------------- Imports
8
9use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
10
11use bytes::Buf;
12use thiserror::Error;
13
14use cuprate_epee_encoding::{epee_object, EpeeObjectBuilder};
15use cuprate_types::AddressType;
16
17use crate::NetworkAddress;
18
19use super::OnionAddr;
20
21//---------------------------------------------------------------------------------------------------- Network address construction
22
23#[derive(Default)]
24/// A serialized network address being communicated to or from a peer.
25pub struct TaggedNetworkAddress {
26    /// Type of the network address (used later for conversion)
27    ty: Option<AddressType>,
28    /// All possible fields for a network address
29    addr: Option<AllFieldsNetworkAddress>,
30}
31
32epee_object!(
33    TaggedNetworkAddress,
34    ty("type"): Option<AddressType>,
35    addr: Option<AllFieldsNetworkAddress>,
36);
37
38impl EpeeObjectBuilder<NetworkAddress> for TaggedNetworkAddress {
39    fn add_field<B: Buf>(&mut self, name: &str, b: &mut B) -> cuprate_epee_encoding::Result<bool> {
40        match name {
41            "type" => {
42                if self
43                    .ty
44                    .replace(cuprate_epee_encoding::read_epee_value(b)?)
45                    .is_some()
46                {
47                    return Err(cuprate_epee_encoding::Error::Format(
48                        "Duplicate field in data.",
49                    ));
50                }
51                Ok(true)
52            }
53            "addr" => {
54                if std::mem::replace(&mut self.addr, cuprate_epee_encoding::read_epee_value(b)?)
55                    .is_some()
56                {
57                    return Err(cuprate_epee_encoding::Error::Format(
58                        "Duplicate field in data.",
59                    ));
60                }
61                Ok(true)
62            }
63            _ => Ok(false),
64        }
65    }
66
67    fn finish(self) -> cuprate_epee_encoding::Result<NetworkAddress> {
68        self.try_into()
69            .map_err(|_| cuprate_epee_encoding::Error::Value("Invalid network address".to_string()))
70    }
71}
72
73#[derive(Error, Debug)]
74#[error("Invalid network address")]
75pub struct InvalidNetworkAddress;
76
77impl TryFrom<TaggedNetworkAddress> for NetworkAddress {
78    type Error = InvalidNetworkAddress;
79
80    fn try_from(value: TaggedNetworkAddress) -> Result<Self, Self::Error> {
81        value
82            .addr
83            .ok_or(InvalidNetworkAddress)?
84            .try_into_network_address(value.ty.ok_or(InvalidNetworkAddress)?)
85            .ok_or(InvalidNetworkAddress)
86    }
87}
88
89impl From<NetworkAddress> for TaggedNetworkAddress {
90    fn from(value: NetworkAddress) -> Self {
91        match value {
92            NetworkAddress::Clear(addr) => match addr {
93                SocketAddr::V4(addr) => Self {
94                    ty: Some(AddressType::Ipv4),
95                    addr: Some(AllFieldsNetworkAddress {
96                        m_ip: Some(u32::from_le_bytes(addr.ip().octets())),
97                        m_port: Some(addr.port()),
98                        addr: None,
99                        host: None,
100                        port: None,
101                    }),
102                },
103                SocketAddr::V6(addr) => Self {
104                    ty: Some(AddressType::Ipv6),
105                    addr: Some(AllFieldsNetworkAddress {
106                        addr: Some(addr.ip().octets()),
107                        m_port: Some(addr.port()),
108                        m_ip: None,
109                        host: None,
110                        port: None,
111                    }),
112                },
113            },
114            NetworkAddress::Tor(onion_addr) => Self {
115                ty: Some(AddressType::Tor),
116                addr: Some(AllFieldsNetworkAddress {
117                    m_ip: None,
118                    m_port: None,
119                    addr: None,
120                    host: Some(onion_addr.addr_string()),
121                    port: Some(onion_addr.port()),
122                }),
123            },
124        }
125    }
126}
127
128#[derive(Default)]
129/// There are no ordering guarantees in epee format and as such all potential fields can be collected during deserialization.
130/// The [`AllFieldsNetworkAddress`] is containing, as its name suggest, all optional field describing an address , as if it
131/// could be of any type.
132struct AllFieldsNetworkAddress {
133    /// IPv4 address
134    m_ip: Option<u32>,
135    /// IP port field
136    m_port: Option<u16>,
137
138    /// IPv6 address
139    addr: Option<[u8; 16]>,
140
141    /// Alternative network domain name (<domain>.onion or <domain>.i2p)
142    host: Option<String>,
143    /// Alternative network virtual port
144    port: Option<u16>,
145}
146
147epee_object!(
148    AllFieldsNetworkAddress,
149    m_ip: Option<u32>,
150    m_port: Option<u16>,
151    addr: Option<[u8; 16]>,
152    host: Option<String>,
153    port: Option<u16>,
154);
155
156impl AllFieldsNetworkAddress {
157    fn try_into_network_address(self, ty: AddressType) -> Option<NetworkAddress> {
158        Some(match ty {
159            AddressType::Ipv4 => NetworkAddress::from(SocketAddrV4::new(
160                Ipv4Addr::from(self.m_ip?.to_le_bytes()),
161                self.m_port?,
162            )),
163            AddressType::Ipv6 => NetworkAddress::from(SocketAddrV6::new(
164                Ipv6Addr::from(self.addr?),
165                self.m_port?,
166                0,
167                0,
168            )),
169            AddressType::Tor => {
170                NetworkAddress::from(OnionAddr::new(self.host?.as_str(), self.port?).ok()?)
171            }
172            // Invalid
173            _ => return None,
174        })
175    }
176}