Small cleanups and tweaks to same_subnet code.

This commit is contained in:
Nick Mathewson 2021-08-05 15:16:03 -04:00
parent 3bc0a03848
commit e4baf164dd
2 changed files with 48 additions and 44 deletions

View File

@ -3,7 +3,7 @@
use super::TorPath;
use crate::{DirInfo, Error, Result, TargetPort};
use rand::Rng;
use tor_netdir::{CircuitConfig, NetDir, Relay, WeightRole};
use tor_netdir::{NetDir, Relay, SubnetConfig, WeightRole};
/// Internal representation of PathBuilder.
enum ExitPathBuilderInner<'a> {
@ -60,19 +60,19 @@ impl<'a> ExitPathBuilder<'a> {
DirInfo::Directory(d) => d,
};
// TODO: properly get circuit config
let circuit_config = CircuitConfig::default();
let subnet_config = SubnetConfig::default();
let exit = self.pick_exit(rng, netdir)?;
let middle = netdir
.pick_relay(rng, WeightRole::Middle, |r| {
r.can_be_in_same_circuit(&exit, &circuit_config)
relays_can_share_circuit(r, &exit, &subnet_config)
})
.ok_or_else(|| Error::NoRelays("No middle relay found".into()))?;
let entry = netdir
.pick_relay(rng, WeightRole::Guard, |r| {
r.can_be_in_same_circuit(&middle, &circuit_config)
&& r.can_be_in_same_circuit(&exit, &circuit_config)
relays_can_share_circuit(r, &middle, &subnet_config)
&& relays_can_share_circuit(r, &exit, &subnet_config)
})
.ok_or_else(|| Error::NoRelays("No entry relay found".into()))?;
@ -80,6 +80,15 @@ impl<'a> ExitPathBuilder<'a> {
}
}
/// Returns true if both relays can appear together in the same circuit.
fn relays_can_share_circuit(a: &Relay<'_>, b: &Relay<'_>, subnet_config: &SubnetConfig) -> bool {
// XXX: features missing from original implementation:
// - option NodeFamilySets
// see: src/feature/nodelist/nodelist.c:nodes_in_same_family()
!a.in_same_family(b) && !a.in_same_subnet(b, subnet_config)
}
#[cfg(test)]
mod test {
use super::*;
@ -101,10 +110,10 @@ mod test {
assert!(r1.ed_identity() != r3.ed_identity());
assert!(r2.ed_identity() != r3.ed_identity());
let circuit_config = CircuitConfig::default();
assert!(r1.can_be_in_same_circuit(r2, &circuit_config));
assert!(r1.can_be_in_same_circuit(r3, &circuit_config));
assert!(r2.can_be_in_same_circuit(r3, &circuit_config));
let subnet_config = SubnetConfig::default();
assert!(relays_can_share_circuit(r1, r2, &subnet_config));
assert!(relays_can_share_circuit(r1, r3, &subnet_config));
assert!(relays_can_share_circuit(r2, r3, &subnet_config));
}
#[test]

View File

@ -76,17 +76,20 @@ pub type Result<T> = std::result::Result<T, Error>;
use params::NetParameters;
/// The configuration for circuit creation.
/// Configuration for determining when two relays have addresses "too close" in
/// the network.
///
/// Used by [`Relay::in_same_subnet()`].
#[derive(Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct CircuitConfig {
pub struct SubnetConfig {
/// Consider IPv4 nodes in the same /x to be the same family.
subnets_family_v4: u8,
/// Consider IPv6 nodes in the same /x to be the same family.
subnets_family_v6: u8,
}
impl Default for CircuitConfig {
impl Default for SubnetConfig {
fn default() -> Self {
Self {
subnets_family_v4: 16,
@ -511,19 +514,14 @@ impl<'a> Relay<'a> {
.protovers()
.supports_known_subver(ProtoKind::DirCache, 2)
}
/// Returns true if both relays can appear together in the same circuit.
pub fn can_be_in_same_circuit<'b>(
&self,
other: &Relay<'b>,
circuit_config: &CircuitConfig,
) -> bool {
// XXX: features missing from original implementation:
// - option NodeFamilySets
// see: src/feature/nodelist/nodelist.c:nodes_in_same_family()
!self.in_same_family(other) && !self.same_subnet(other, circuit_config)
}
/// If two relays are on the same subnet.
pub fn same_subnet<'b>(&self, other: &Relay<'b>, circuit_config: &CircuitConfig) -> bool {
/// Return true if both relays are in the same subnet, as configured by
/// `subnet_config`.
///
/// Two relays are considered to be in the same subnet if they
/// have IPv4 addresses with the same `subnets_family_v4`-bit
/// prefix, or if they have IPv6 addresses with the same
/// `subnets_family_v6`-bit prefix.
pub fn in_same_subnet<'b>(&self, other: &Relay<'b>, subnet_config: &SubnetConfig) -> bool {
/// Do the two addresses share the same n leading bits?
fn addrs_equal(a: &SocketAddr, b: &SocketAddr, v4_bits: u8, v6_bits: u8) -> bool {
match (a.ip(), b.ip()) {
@ -546,19 +544,16 @@ impl<'a> Relay<'a> {
_ => false,
}
}
self.rs
.orport_addrs()
// TODO: get bit length from config
.any(|addr| {
other.rs.orport_addrs().any(|other| {
addrs_equal(
addr,
other,
circuit_config.subnets_family_v4,
circuit_config.subnets_family_v6,
)
})
self.rs.orport_addrs().any(|addr| {
other.rs.orport_addrs().any(|other| {
addrs_equal(
addr,
other,
subnet_config.subnets_family_v4,
subnet_config.subnets_family_v6,
)
})
})
}
/// Return true if both relays are in the same family.
///
@ -836,7 +831,7 @@ mod test {
#[test]
fn relay_funcs() {
let (consensus, microdescs) = construct_network();
let circuit_config = CircuitConfig::default();
let subnet_config = SubnetConfig::default();
let mut dir = PartialNetDir::new(consensus, None);
for md in microdescs.into_iter() {
let wanted = dir.add_microdesc(md.clone());
@ -879,11 +874,11 @@ mod test {
assert!(r2.in_same_family(&r2));
assert!(r2.in_same_family(&r3));
assert!(r0.same_subnet(&r10, &circuit_config));
assert!(r10.same_subnet(&r10, &circuit_config));
assert!(r0.same_subnet(&r0, &circuit_config));
assert!(r1.same_subnet(&r1, &circuit_config));
assert!(!r1.same_subnet(&r2, &circuit_config));
assert!(!r2.same_subnet(&r3, &circuit_config));
assert!(r0.in_same_subnet(&r10, &subnet_config));
assert!(r10.in_same_subnet(&r10, &subnet_config));
assert!(r0.in_same_subnet(&r0, &subnet_config));
assert!(r1.in_same_subnet(&r1, &subnet_config));
assert!(!r1.in_same_subnet(&r2, &subnet_config));
assert!(!r2.in_same_subnet(&r3, &subnet_config));
}
}