node: Improve Tor configuration flexibility
*Breaking change* The `tor` configuration field is no longer supported. Users must remove that field from their config. Allows for a mixed mode, where regular addresses bypass the Tor proxy, while onion addresses go through it. When `onion.mode` is set to "forward", Tor connections are fowarded to the global proxy, and if it isn't set, to the OS's DNS resolution. For mixed mode, a global proxy simply isn't set, so that IP/DNS is not proxied.
This commit is contained in:
parent
cb2cbf014a
commit
ca7db1620c
|
|
@ -29,7 +29,6 @@ $ rad config
|
|||
"db": {
|
||||
"journalMode": "rollback"
|
||||
},
|
||||
"tor": null,
|
||||
"network": "main",
|
||||
"log": "INFO",
|
||||
"relay": "auto",
|
||||
|
|
|
|||
|
|
@ -90,7 +90,6 @@ mod routes {
|
|||
"connect": [],
|
||||
"externalAddresses": [],
|
||||
"db": { "journalMode": "rollback" },
|
||||
"tor": null,
|
||||
"network": "main",
|
||||
"log": "INFO",
|
||||
"relay": "auto",
|
||||
|
|
|
|||
|
|
@ -1232,7 +1232,7 @@ where
|
|||
}
|
||||
Entry::Vacant(e) => {
|
||||
if let HostName::Ip(ip) = addr.host {
|
||||
if !ip.is_loopback() && !self.config.is_proxy_ip(ip) {
|
||||
if !address::is_local(&ip) {
|
||||
if let Err(e) =
|
||||
self.db
|
||||
.addresses_mut()
|
||||
|
|
@ -2335,8 +2335,8 @@ where
|
|||
.map(|ka| (peer.nid, ka))
|
||||
})
|
||||
.filter(|(_, ka)| match AddressType::from(&ka.addr) {
|
||||
// Only consider Tor addresses if Tor is configured.
|
||||
AddressType::Onion => self.config.tor.is_some(),
|
||||
// Only consider onion addresses if configured.
|
||||
AddressType::Onion => self.config.onion.is_some(),
|
||||
AddressType::Dns | AddressType::Ipv4 | AddressType::Ipv6 => true,
|
||||
})
|
||||
.take(wanted)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use netservices::{NetConnection, NetReader, NetWriter};
|
|||
use reactor::{ResourceId, ResourceType, Timestamp};
|
||||
|
||||
use radicle::collections::RandomMap;
|
||||
use radicle::node::config::TorConfig;
|
||||
use radicle::node::config::AddressConfig;
|
||||
use radicle::node::NodeId;
|
||||
use radicle::storage::WriteStorage;
|
||||
|
||||
|
|
@ -1071,30 +1071,28 @@ pub fn dial<G: Signer + Ecdh<Pk = NodeId>>(
|
|||
signer: G,
|
||||
config: &service::Config,
|
||||
) -> io::Result<WireSession<G>> {
|
||||
let inet_addr: NetAddr<InetHost> = match config.tor {
|
||||
// In Tor proxy mode, simply specify the proxy address for all connections,
|
||||
// since we'll be routing all connections through the proxy.
|
||||
Some(TorConfig::Proxy { address: proxy }) => proxy.into(),
|
||||
// In transparent Tor mode, we treat `.onion` addresses as regular DNS names.
|
||||
Some(TorConfig::Transparent) => {
|
||||
let host = match &remote_addr.host {
|
||||
HostName::Ip(ip) => InetHost::Ip(*ip),
|
||||
HostName::Dns(dns) => InetHost::Dns(dns.clone()),
|
||||
HostName::Tor(onion) => InetHost::Dns(onion.to_string()),
|
||||
_ => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
"unsupported remote address type",
|
||||
))
|
||||
let inet_addr: NetAddr<InetHost> = match &remote_addr.host {
|
||||
HostName::Ip(ip) => NetAddr::new(InetHost::Ip(*ip), remote_addr.port),
|
||||
HostName::Dns(dns) => NetAddr::new(InetHost::Dns(dns.clone()), remote_addr.port),
|
||||
HostName::Tor(onion) => match config.onion {
|
||||
// In Tor proxy mode, simply specify the proxy address.
|
||||
Some(AddressConfig::Proxy { address }) => address.into(),
|
||||
// In "forward" mode, if a global proxy is set, we use that, otherwise
|
||||
// we treat `.onion` addresses as regular DNS names.
|
||||
Some(AddressConfig::Forward) => {
|
||||
if let Some(proxy) = config.proxy {
|
||||
proxy.into()
|
||||
} else {
|
||||
NetAddr::new(InetHost::Dns(onion.to_string()), remote_addr.port)
|
||||
}
|
||||
};
|
||||
NetAddr::new(host, remote_addr.port)
|
||||
}
|
||||
// Without any Tor configuration, refuse to connect to a `.onion` address.
|
||||
None => {
|
||||
let host = match &remote_addr.host {
|
||||
HostName::Ip(ip) => InetHost::Ip(*ip),
|
||||
HostName::Dns(dns) => InetHost::Dns(dns.clone()),
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
"no configuration found for .onion addresses",
|
||||
));
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
|
|
@ -1102,11 +1100,8 @@ pub fn dial<G: Signer + Ecdh<Pk = NodeId>>(
|
|||
))
|
||||
}
|
||||
};
|
||||
NetAddr::new(host, remote_addr.port)
|
||||
}
|
||||
};
|
||||
// Whether to tunnel regular connections through the proxy.
|
||||
let force_proxy = matches!(config.tor, Some(TorConfig::Proxy { .. }));
|
||||
let force_proxy = config.proxy.is_some();
|
||||
// Nb. This timeout is currently not used by the underlying library due to the
|
||||
// `socket2` library not supporting non-blocking connect with timeout.
|
||||
let connection = net::TcpStream::connect_nonblocking(inet_addr, DEFAULT_DIAL_TIMEOUT)?;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use localtime::LocalDuration;
|
|||
|
||||
use crate::node;
|
||||
use crate::node::policy::{Policy, Scope};
|
||||
use crate::node::{address, db, Address, Alias, NodeId};
|
||||
use crate::node::{db, Address, Alias, NodeId};
|
||||
|
||||
/// Target number of peers to maintain connections to.
|
||||
pub const TARGET_OUTBOUND_PEERS: usize = 8;
|
||||
|
|
@ -247,17 +247,18 @@ pub enum Relay {
|
|||
Auto,
|
||||
}
|
||||
|
||||
/// Tor configuration.
|
||||
/// Proxy configuration.
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase", tag = "mode")]
|
||||
pub enum TorConfig {
|
||||
/// Connect via SOCKS5 proxy.
|
||||
pub enum AddressConfig {
|
||||
/// Proxy connections to this address type.
|
||||
Proxy {
|
||||
/// Tor proxy address.
|
||||
/// Proxy address.
|
||||
address: net::SocketAddr,
|
||||
},
|
||||
/// Treat Tor onion addresses as DNS names.
|
||||
Transparent,
|
||||
/// Forward address to the next layer. Either this is the global proxy,
|
||||
/// or the operating system, via DNS.
|
||||
Forward,
|
||||
}
|
||||
|
||||
/// Database configuration.
|
||||
|
|
@ -290,9 +291,12 @@ pub struct Config {
|
|||
/// Database config.
|
||||
#[serde(default)]
|
||||
pub db: DbConfig,
|
||||
/// Tor configuration.
|
||||
#[serde(default)]
|
||||
pub tor: Option<TorConfig>,
|
||||
/// Global proxy.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub proxy: Option<net::SocketAddr>,
|
||||
/// Onion address config.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub onion: Option<AddressConfig>,
|
||||
/// Peer-to-peer network.
|
||||
#[serde(default)]
|
||||
pub network: Network,
|
||||
|
|
@ -334,7 +338,8 @@ impl Config {
|
|||
external_addresses: vec![],
|
||||
db: DbConfig::default(),
|
||||
network: Network::default(),
|
||||
tor: None,
|
||||
proxy: None,
|
||||
onion: None,
|
||||
relay: Relay::default(),
|
||||
limits: Limits::default(),
|
||||
workers: DEFAULT_WORKERS,
|
||||
|
|
@ -359,15 +364,6 @@ impl Config {
|
|||
self.peer(id).is_some()
|
||||
}
|
||||
|
||||
/// Check if the given IP address is our proxy.
|
||||
pub fn is_proxy_ip(&self, ip: net::IpAddr) -> bool {
|
||||
match self.tor {
|
||||
None => false,
|
||||
Some(TorConfig::Proxy { address }) => address.ip() == ip,
|
||||
Some(TorConfig::Transparent) => address::is_local(&ip),
|
||||
}
|
||||
}
|
||||
|
||||
/// Are we a relay node? This determines what we do with gossip messages from other peers.
|
||||
pub fn is_relay(&self) -> bool {
|
||||
match self.relay {
|
||||
|
|
|
|||
Loading…
Reference in New Issue