Skip to content

Commit 392653c

Browse files
Define Tor Zone, add onion addressing and more (#481)
* Define Tor Zone, add onion addressing, extend AddressBook, adapt `handle_timed_sync_request`, changes in cuprated + some cleanup In `cuprated`: - Added `Z: NetworkZone` as a generic requirement for `address_book_config`. Now takes the optional node address in argument. - Added `tor_net_seed_nodes` fn for obtaining tor seed nodes. - Added `CrossNetworkInternalPeerId::Tor(_)` variant and `From<InternalPeerId<OnionAddr>>` In `cuprate-wire`: - Added `src/network_address/onion_addr.rs` implementing `OnionAddr` type used by `Tor` network zone. - Implemented parsing, formatting, conversion and validation of `OnionAddr`. - Implemented 2 validation tests and 2 parsing tests for `OnionAddr`. - Documented and cleaned up `src/network_address/epee_builder.rs`. - Changed `u8` `type` field of `TaggedNetworkAddress` to `AddressType` enum equivalent to monerod's `address_type`. - Added additional `host` and `port` fields to `AllFieldedNetworkAddress` collection type. - Added `NetworkAddress:Tor` variant and added conversion to related functions. In `cuprate-address-book`: - Added `our_own_addr: Z::Addr` field to AddressBookConfig. This adds a `Z: NetworkZone` requirement to `AddressBookConfig`. - Adapted code to the new generic requirement. - Implemented handling of new `AddressBookRequest::OwnAddress` for querying the node self specified address for the zone. In `cuprate-p2p`: - If `Z::BROADCAST_OUR_OWN_ADDR` = `true`, `handle_timed_sync_request` will insert the node's address to the peerlist being sent. In `cuprate-p2p-core`: - Removed `#[async_trait::async_trait]` attribute to `impl NetworkZone for *`. - Added `AddressBookRequest::OwnAddress` and `AddressBookResponse::OwnAddress(Option<Z::Addr>)`. - Defined new `Tor` `NetworkZone` * fmt * fix typo and fmt * final edits? * fix test * forgor
1 parent 640ac1b commit 392653c

File tree

23 files changed

+488
-46
lines changed

23 files changed

+488
-46
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

binaries/cuprated/src/config.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -219,11 +219,11 @@ impl Config {
219219
gray_peers_percent: self.p2p.clear_net.gray_peers_percent,
220220
p2p_port: self.p2p.clear_net.p2p_port,
221221
rpc_port: self.rpc.restricted.port_for_p2p(),
222-
address_book_config: self
223-
.p2p
224-
.clear_net
225-
.address_book_config
226-
.address_book_config(&self.fs.cache_directory, self.network),
222+
address_book_config: self.p2p.clear_net.address_book_config.address_book_config(
223+
&self.fs.cache_directory,
224+
self.network,
225+
None,
226+
),
227227
}
228228
}
229229

binaries/cuprated/src/config/p2p.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::{
2+
marker::PhantomData,
23
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
34
path::Path,
45
time::Duration,
@@ -10,8 +11,9 @@ use cuprate_helper::{fs::address_book_path, network::Network};
1011
use cuprate_p2p::config::TransportConfig;
1112
use cuprate_p2p_core::{
1213
transports::{Tcp, TcpServerConfig},
13-
ClearNet, Transport,
14+
ClearNet, NetworkZone, Transport,
1415
};
16+
use cuprate_wire::OnionAddr;
1517

1618
use super::macros::config_struct;
1719

@@ -266,16 +268,23 @@ impl Default for AddressBookConfig {
266268

267269
impl AddressBookConfig {
268270
/// Returns the [`cuprate_address_book::AddressBookConfig`].
269-
pub fn address_book_config(
271+
pub fn address_book_config<Z: NetworkZone>(
270272
&self,
271273
cache_dir: &Path,
272274
network: Network,
273-
) -> cuprate_address_book::AddressBookConfig {
275+
our_own_address: Option<Z::Addr>,
276+
) -> cuprate_address_book::AddressBookConfig<Z> {
277+
assert!(
278+
!Z::BROADCAST_OWN_ADDR && our_own_address.is_some(),
279+
"This network DO NOT take an incoming address."
280+
);
281+
274282
cuprate_address_book::AddressBookConfig {
275283
max_white_list_length: self.max_white_list_length,
276284
max_gray_list_length: self.max_gray_list_length,
277285
peer_store_directory: address_book_path(cache_dir, network),
278286
peer_save_period: self.peer_save_period,
287+
our_own_address,
279288
}
280289
}
281290
}
@@ -317,3 +326,25 @@ pub fn clear_net_seed_nodes(network: Network) -> Vec<SocketAddr> {
317326
.collect::<Result<_, _>>()
318327
.unwrap()
319328
}
329+
330+
/// Seed nodes for `Tor`.
331+
pub fn tor_net_seed_nodes(network: Network) -> Vec<OnionAddr> {
332+
let seeds = match network {
333+
Network::Mainnet => [
334+
"zbjkbsxc5munw3qusl7j2hpcmikhqocdf4pqhnhtpzw5nt5jrmofptid.onion:18083",
335+
"qz43zul2x56jexzoqgkx2trzwcfnr6l3hbtfcfx54g4r3eahy3bssjyd.onion:18083",
336+
"plowsof3t5hogddwabaeiyrno25efmzfxyro2vligremt7sxpsclfaid.onion:18083",
337+
"plowsoffjexmxalw73tkjmf422gq6575fc7vicuu4javzn2ynnte6tyd.onion:18083",
338+
"plowsofe6cleftfmk2raiw5h2x66atrik3nja4bfd3zrfa2hdlgworad.onion:18083",
339+
"aclc4e2jhhtr44guufbnwk5bzwhaecinax4yip4wr4tjn27sjsfg6zqd.onion:18083",
340+
]
341+
.as_slice(),
342+
Network::Stagenet | Network::Testnet => [].as_slice(),
343+
};
344+
345+
seeds
346+
.iter()
347+
.map(|s| s.parse())
348+
.collect::<Result<_, _>>()
349+
.unwrap()
350+
}
Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
use std::net::SocketAddr;
22

3-
use cuprate_p2p_core::{client::InternalPeerID, ClearNet, NetworkZone};
3+
use cuprate_p2p_core::{client::InternalPeerID, ClearNet, NetworkZone, Tor};
4+
use cuprate_wire::OnionAddr;
45

56
/// An identifier for a P2P peer on any network.
67
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
78
pub enum CrossNetworkInternalPeerId {
89
/// A clear-net peer.
910
ClearNet(InternalPeerID<<ClearNet as NetworkZone>::Addr>),
11+
/// A Tor onion peer.
12+
Tor(InternalPeerID<<Tor as NetworkZone>::Addr>),
1013
}
1114

12-
impl From<InternalPeerID<<ClearNet as NetworkZone>::Addr>> for CrossNetworkInternalPeerId {
13-
fn from(addr: InternalPeerID<<ClearNet as NetworkZone>::Addr>) -> Self {
15+
impl From<InternalPeerID<SocketAddr>> for CrossNetworkInternalPeerId {
16+
fn from(addr: InternalPeerID<SocketAddr>) -> Self {
1417
Self::ClearNet(addr)
1518
}
1619
}
20+
21+
impl From<InternalPeerID<OnionAddr>> for CrossNetworkInternalPeerId {
22+
fn from(addr: InternalPeerID<OnionAddr>) -> Self {
23+
Self::Tor(addr)
24+
}
25+
}

net/wire/Cargo.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ cuprate-fixed-bytes = { workspace = true }
1717
cuprate-types = { workspace = true, default-features = false, features = ["epee"] }
1818
cuprate-helper = { workspace = true, default-features = false, features = ["map"] }
1919

20-
bitflags = { workspace = true, features = ["std"] }
21-
bytes = { workspace = true, features = ["std"] }
22-
thiserror = { workspace = true }
20+
bitflags = { workspace = true, features = ["std"] }
21+
bytes = { workspace = true, features = ["std"] }
22+
thiserror = { workspace = true }
2323

2424
arbitrary = { workspace = true, features = ["derive"], optional = true }
2525

2626
[dev-dependencies]
27-
hex = { workspace = true, features = ["std"]}
27+
hex = { workspace = true, features = ["std"]}
28+
proptest = { workspace = true }
2829

2930
[lints]
3031
workspace = true

net/wire/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub mod network_address;
2626
pub mod p2p;
2727

2828
pub use cuprate_levin::BucketError;
29-
pub use network_address::{NetZone, NetworkAddress};
29+
pub use network_address::{NetZone, NetworkAddress, OnionAddr};
3030
pub use p2p::*;
3131

3232
// re-export.

net/wire/src/network_address.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ use cuprate_epee_encoding::EpeeObject;
2626
mod epee_builder;
2727
use epee_builder::*;
2828

29+
mod onion_addr;
30+
pub use onion_addr::*;
31+
2932
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
3033
pub enum NetZone {
3134
Public,
@@ -38,6 +41,7 @@ pub enum NetZone {
3841
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
3942
pub enum NetworkAddress {
4043
Clear(SocketAddr),
44+
Tor(OnionAddr),
4145
}
4246

4347
impl EpeeObject for NetworkAddress {
@@ -56,6 +60,7 @@ impl NetworkAddress {
5660
pub const fn get_zone(&self) -> NetZone {
5761
match self {
5862
Self::Clear(_) => NetZone::Public,
63+
Self::Tor(_) => NetZone::Tor,
5964
}
6065
}
6166

@@ -72,6 +77,7 @@ impl NetworkAddress {
7277
pub const fn port(&self) -> u16 {
7378
match self {
7479
Self::Clear(ip) => ip.port(),
80+
Self::Tor(addr) => addr.port(),
7581
}
7682
}
7783
}
@@ -106,7 +112,7 @@ impl TryFrom<NetworkAddress> for SocketAddr {
106112
fn try_from(value: NetworkAddress) -> Result<Self, Self::Error> {
107113
match value {
108114
NetworkAddress::Clear(addr) => Ok(addr),
109-
//_ => Err(NetworkAddressIncorrectZone)
115+
NetworkAddress::Tor(_) => Err(NetworkAddressIncorrectZone),
110116
}
111117
}
112118
}

net/wire/src/network_address/epee_builder.rs

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,37 @@
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+
19
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
210

311
use bytes::Buf;
412
use thiserror::Error;
513

614
use cuprate_epee_encoding::{epee_object, EpeeObjectBuilder};
15+
use cuprate_types::AddressType;
716

817
use crate::NetworkAddress;
918

19+
use super::OnionAddr;
20+
21+
//---------------------------------------------------------------------------------------------------- Network address construction
22+
1023
#[derive(Default)]
24+
/// A serialized network address being communicated to or from a peer.
1125
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
1329
addr: Option<AllFieldsNetworkAddress>,
1430
}
1531

1632
epee_object!(
1733
TaggedNetworkAddress,
18-
ty("type"): Option<u8>,
34+
ty("type"): Option<AddressType>,
1935
addr: Option<AllFieldsNetworkAddress>,
2036
);
2137

@@ -75,53 +91,85 @@ impl From<NetworkAddress> for TaggedNetworkAddress {
7591
match value {
7692
NetworkAddress::Clear(addr) => match addr {
7793
SocketAddr::V4(addr) => Self {
78-
ty: Some(1),
94+
ty: Some(AddressType::Ipv4),
7995
addr: Some(AllFieldsNetworkAddress {
8096
m_ip: Some(u32::from_le_bytes(addr.ip().octets())),
8197
m_port: Some(addr.port()),
8298
addr: None,
99+
host: None,
100+
port: None,
83101
}),
84102
},
85103
SocketAddr::V6(addr) => Self {
86-
ty: Some(2),
104+
ty: Some(AddressType::Ipv6),
87105
addr: Some(AllFieldsNetworkAddress {
88106
addr: Some(addr.ip().octets()),
89107
m_port: Some(addr.port()),
90108
m_ip: None,
109+
host: None,
110+
port: None,
91111
}),
92112
},
93113
},
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+
},
94124
}
95125
}
96126
}
97127

98128
#[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.
99132
struct AllFieldsNetworkAddress {
133+
/// IPv4 address
100134
m_ip: Option<u32>,
135+
/// IP port field
101136
m_port: Option<u16>,
137+
138+
/// IPv6 address
102139
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>,
103145
}
104146

105147
epee_object!(
106148
AllFieldsNetworkAddress,
107149
m_ip: Option<u32>,
108150
m_port: Option<u16>,
109151
addr: Option<[u8; 16]>,
152+
host: Option<String>,
153+
port: Option<u16>,
110154
);
111155

112156
impl AllFieldsNetworkAddress {
113-
fn try_into_network_address(self, ty: u8) -> Option<NetworkAddress> {
157+
fn try_into_network_address(self, ty: AddressType) -> Option<NetworkAddress> {
114158
Some(match ty {
115-
1 => NetworkAddress::from(SocketAddrV4::new(
159+
AddressType::Ipv4 => NetworkAddress::from(SocketAddrV4::new(
116160
Ipv4Addr::from(self.m_ip?.to_le_bytes()),
117161
self.m_port?,
118162
)),
119-
2 => NetworkAddress::from(SocketAddrV6::new(
163+
AddressType::Ipv6 => NetworkAddress::from(SocketAddrV6::new(
120164
Ipv6Addr::from(self.addr?),
121165
self.m_port?,
122166
0,
123167
0,
124168
)),
169+
AddressType::Tor => {
170+
NetworkAddress::from(OnionAddr::new(self.host?.as_str(), self.port?).ok()?)
171+
}
172+
// Invalid
125173
_ => return None,
126174
})
127175
}

0 commit comments

Comments
 (0)