|
| 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 | + |
1 | 9 | use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
2 | 10 |
|
3 | 11 | use bytes::Buf;
|
4 | 12 | use thiserror::Error;
|
5 | 13 |
|
6 | 14 | use cuprate_epee_encoding::{epee_object, EpeeObjectBuilder};
|
| 15 | +use cuprate_types::AddressType; |
7 | 16 |
|
8 | 17 | use crate::NetworkAddress;
|
9 | 18 |
|
| 19 | +use super::OnionAddr; |
| 20 | + |
| 21 | +//---------------------------------------------------------------------------------------------------- Network address construction |
| 22 | + |
10 | 23 | #[derive(Default)]
|
| 24 | +/// A serialized network address being communicated to or from a peer. |
11 | 25 | pub struct TaggedNetworkAddress {
|
12 |
| - ty: Option<u8>, |
| 26 | + /// Type of the network address (used later for conversion) |
| 27 | + ty: Option<AddressType>, |
| 28 | + /// All possible fields for a network address |
13 | 29 | addr: Option<AllFieldsNetworkAddress>,
|
14 | 30 | }
|
15 | 31 |
|
16 | 32 | epee_object!(
|
17 | 33 | TaggedNetworkAddress,
|
18 |
| - ty("type"): Option<u8>, |
| 34 | + ty("type"): Option<AddressType>, |
19 | 35 | addr: Option<AllFieldsNetworkAddress>,
|
20 | 36 | );
|
21 | 37 |
|
@@ -75,53 +91,85 @@ impl From<NetworkAddress> for TaggedNetworkAddress {
|
75 | 91 | match value {
|
76 | 92 | NetworkAddress::Clear(addr) => match addr {
|
77 | 93 | SocketAddr::V4(addr) => Self {
|
78 |
| - ty: Some(1), |
| 94 | + ty: Some(AddressType::Ipv4), |
79 | 95 | addr: Some(AllFieldsNetworkAddress {
|
80 | 96 | m_ip: Some(u32::from_le_bytes(addr.ip().octets())),
|
81 | 97 | m_port: Some(addr.port()),
|
82 | 98 | addr: None,
|
| 99 | + host: None, |
| 100 | + port: None, |
83 | 101 | }),
|
84 | 102 | },
|
85 | 103 | SocketAddr::V6(addr) => Self {
|
86 |
| - ty: Some(2), |
| 104 | + ty: Some(AddressType::Ipv6), |
87 | 105 | addr: Some(AllFieldsNetworkAddress {
|
88 | 106 | addr: Some(addr.ip().octets()),
|
89 | 107 | m_port: Some(addr.port()),
|
90 | 108 | m_ip: None,
|
| 109 | + host: None, |
| 110 | + port: None, |
91 | 111 | }),
|
92 | 112 | },
|
93 | 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 | + }, |
94 | 124 | }
|
95 | 125 | }
|
96 | 126 | }
|
97 | 127 |
|
98 | 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. |
99 | 132 | struct AllFieldsNetworkAddress {
|
| 133 | + /// IPv4 address |
100 | 134 | m_ip: Option<u32>,
|
| 135 | + /// IP port field |
101 | 136 | m_port: Option<u16>,
|
| 137 | + |
| 138 | + /// IPv6 address |
102 | 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>, |
103 | 145 | }
|
104 | 146 |
|
105 | 147 | epee_object!(
|
106 | 148 | AllFieldsNetworkAddress,
|
107 | 149 | m_ip: Option<u32>,
|
108 | 150 | m_port: Option<u16>,
|
109 | 151 | addr: Option<[u8; 16]>,
|
| 152 | + host: Option<String>, |
| 153 | + port: Option<u16>, |
110 | 154 | );
|
111 | 155 |
|
112 | 156 | impl AllFieldsNetworkAddress {
|
113 |
| - fn try_into_network_address(self, ty: u8) -> Option<NetworkAddress> { |
| 157 | + fn try_into_network_address(self, ty: AddressType) -> Option<NetworkAddress> { |
114 | 158 | Some(match ty {
|
115 |
| - 1 => NetworkAddress::from(SocketAddrV4::new( |
| 159 | + AddressType::Ipv4 => NetworkAddress::from(SocketAddrV4::new( |
116 | 160 | Ipv4Addr::from(self.m_ip?.to_le_bytes()),
|
117 | 161 | self.m_port?,
|
118 | 162 | )),
|
119 |
| - 2 => NetworkAddress::from(SocketAddrV6::new( |
| 163 | + AddressType::Ipv6 => NetworkAddress::from(SocketAddrV6::new( |
120 | 164 | Ipv6Addr::from(self.addr?),
|
121 | 165 | self.m_port?,
|
122 | 166 | 0,
|
123 | 167 | 0,
|
124 | 168 | )),
|
| 169 | + AddressType::Tor => { |
| 170 | + NetworkAddress::from(OnionAddr::new(self.host?.as_str(), self.port?).ok()?) |
| 171 | + } |
| 172 | + // Invalid |
125 | 173 | _ => return None,
|
126 | 174 | })
|
127 | 175 | }
|
|
0 commit comments