node: Explicit default for `AddressConfig`
The intent to drop outgoing connections is modeled as `Option::None` which is brittle and easy to miss. Extend `enum AddressConfig` with a variant that is more explicit.
This commit is contained in:
parent
fb1808395e
commit
10a82958ca
|
|
@ -247,14 +247,7 @@ $ rad config schema
|
||||||
},
|
},
|
||||||
"onion": {
|
"onion": {
|
||||||
"description": "Onion address config.",
|
"description": "Onion address config.",
|
||||||
"anyOf": [
|
"$ref": "#/$defs/AddressConfig"
|
||||||
{
|
|
||||||
"$ref": "#/$defs/AddressConfig"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"network": {
|
"network": {
|
||||||
"description": "Peer-to-peer network.",
|
"description": "Peer-to-peer network.",
|
||||||
|
|
@ -410,6 +403,19 @@ $ rad config schema
|
||||||
"required": [
|
"required": [
|
||||||
"mode"
|
"mode"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Drop connections to this address type.",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"mode": {
|
||||||
|
"type": "string",
|
||||||
|
"const": "drop"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"mode"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1096,10 +1096,10 @@ pub fn dial<G: Ecdh<Pk = NodeId>>(
|
||||||
(HostName::Tor(onion), proxy) => match config.onion {
|
(HostName::Tor(onion), proxy) => match config.onion {
|
||||||
// In onion proxy mode, simply use the configured proxy address.
|
// In onion proxy mode, simply use the configured proxy address.
|
||||||
// This takes precedence over any global proxy.
|
// This takes precedence over any global proxy.
|
||||||
Some(AddressConfig::Proxy { address }) => address.into(),
|
AddressConfig::Proxy { address } => address.into(),
|
||||||
// In "forward" mode, if a global proxy is set, we use that, otherwise
|
// In "forward" mode, if a global proxy is set, we use that, otherwise
|
||||||
// we treat `.onion` addresses as regular DNS names.
|
// we treat `.onion` addresses as regular DNS names.
|
||||||
Some(AddressConfig::Forward) => {
|
AddressConfig::Forward => {
|
||||||
if let Some(proxy) = proxy {
|
if let Some(proxy) = proxy {
|
||||||
proxy.into()
|
proxy.into()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1107,7 +1107,7 @@ pub fn dial<G: Ecdh<Pk = NodeId>>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If onion address support isn't configured, refuse to connect.
|
// If onion address support isn't configured, refuse to connect.
|
||||||
None => {
|
AddressConfig::Drop => {
|
||||||
return Err(io::Error::new(
|
return Err(io::Error::new(
|
||||||
io::ErrorKind::Unsupported,
|
io::ErrorKind::Unsupported,
|
||||||
"no configuration found for .onion addresses",
|
"no configuration found for .onion addresses",
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ use radicle::node;
|
||||||
use radicle::node::address;
|
use radicle::node::address;
|
||||||
use radicle::node::address::Store as _;
|
use radicle::node::address::Store as _;
|
||||||
use radicle::node::address::{AddressBook, AddressType, KnownAddress};
|
use radicle::node::address::{AddressBook, AddressType, KnownAddress};
|
||||||
|
#[cfg(feature = "tor")]
|
||||||
|
use radicle::node::config::AddressConfig;
|
||||||
use radicle::node::config::{PeerConfig, RateLimit};
|
use radicle::node::config::{PeerConfig, RateLimit};
|
||||||
use radicle::node::device::Device;
|
use radicle::node::device::Device;
|
||||||
use radicle::node::refs::Store as _;
|
use radicle::node::refs::Store as _;
|
||||||
|
|
@ -2656,7 +2658,7 @@ where
|
||||||
match AddressType::from(address) {
|
match AddressType::from(address) {
|
||||||
// Only consider onion addresses if configured.
|
// Only consider onion addresses if configured.
|
||||||
#[cfg(feature = "tor")]
|
#[cfg(feature = "tor")]
|
||||||
AddressType::Onion => self.config.onion.is_some(),
|
AddressType::Onion => self.config.onion != AddressConfig::Drop,
|
||||||
AddressType::Dns | AddressType::Ipv4 | AddressType::Ipv6 => true,
|
AddressType::Dns | AddressType::Ipv4 | AddressType::Ipv6 => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -355,7 +355,7 @@ pub enum Relay {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Proxy configuration.
|
/// Proxy configuration.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Copy, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase", tag = "mode")]
|
#[serde(rename_all = "camelCase", tag = "mode")]
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
#[cfg(feature = "tor")]
|
#[cfg(feature = "tor")]
|
||||||
|
|
@ -368,6 +368,9 @@ pub enum AddressConfig {
|
||||||
/// Forward address to the next layer. Either this is the global proxy,
|
/// Forward address to the next layer. Either this is the global proxy,
|
||||||
/// or the operating system, via DNS.
|
/// or the operating system, via DNS.
|
||||||
Forward,
|
Forward,
|
||||||
|
/// Drop connections to this address type.
|
||||||
|
#[default]
|
||||||
|
Drop,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default seeding policy. Applies when no repository policies for the given repo are found.
|
/// Default seeding policy. Applies when no repository policies for the given repo are found.
|
||||||
|
|
@ -546,8 +549,12 @@ pub struct Config {
|
||||||
pub proxy: Option<net::SocketAddr>,
|
pub proxy: Option<net::SocketAddr>,
|
||||||
/// Onion address config.
|
/// Onion address config.
|
||||||
#[cfg(feature = "tor")]
|
#[cfg(feature = "tor")]
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(
|
||||||
pub onion: Option<AddressConfig>,
|
default,
|
||||||
|
skip_serializing_if = "crate::serde_ext::is_default",
|
||||||
|
deserialize_with = "crate::serde_ext::null_to_default"
|
||||||
|
)]
|
||||||
|
pub onion: AddressConfig,
|
||||||
/// Peer-to-peer network.
|
/// Peer-to-peer network.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub network: Network,
|
pub network: Network,
|
||||||
|
|
@ -603,7 +610,7 @@ impl Config {
|
||||||
network: Network::default(),
|
network: Network::default(),
|
||||||
proxy: None,
|
proxy: None,
|
||||||
#[cfg(feature = "tor")]
|
#[cfg(feature = "tor")]
|
||||||
onion: None,
|
onion: AddressConfig::Drop,
|
||||||
relay: Relay::default(),
|
relay: Relay::default(),
|
||||||
limits: Limits::default(),
|
limits: Limits::default(),
|
||||||
workers: Workers::default(),
|
workers: Workers::default(),
|
||||||
|
|
@ -944,4 +951,27 @@ mod test {
|
||||||
crate::storage::refs::FeatureLevel::Parent
|
crate::storage::refs::FeatureLevel::Parent
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "tor")]
|
||||||
|
#[test]
|
||||||
|
fn onion_absent() {
|
||||||
|
let actual: super::Config = serde_json::from_value(json!({
|
||||||
|
"alias": "radicle",
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(super::AddressConfig::Drop, actual.onion);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "tor")]
|
||||||
|
#[test]
|
||||||
|
fn onion_null() {
|
||||||
|
// Backwards compatibility: Prior versions allowed to set `onion` to `null`,
|
||||||
|
// which should be treated the same as the default, i.e. `Drop`.
|
||||||
|
let actual: super::Config = serde_json::from_value(json!({
|
||||||
|
"alias": "radicle",
|
||||||
|
"onion": null,
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(super::AddressConfig::Drop, actual.onion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue