tor-netdir: Update tests to parse the descriptor, make test consensus lifetime configurable.

Signed-off-by: Gabriela Moldovan <gabi@torproject.org>
This commit is contained in:
Gabriela Moldovan 2023-04-26 18:25:05 +01:00
parent c6fccbbb01
commit 30983c764f
No known key found for this signature in database
GPG Key ID: 3946E0ADE72BAC99
6 changed files with 93 additions and 26 deletions

2
Cargo.lock generated
View File

@ -4165,6 +4165,7 @@ dependencies = [
"educe", "educe",
"either", "either",
"futures", "futures",
"humantime 2.1.0",
"itertools", "itertools",
"postage", "postage",
"rand_core 0.6.4", "rand_core 0.6.4",
@ -4190,6 +4191,7 @@ dependencies = [
"tor-persist", "tor-persist",
"tor-proto", "tor-proto",
"tor-rtcompat", "tor-rtcompat",
"tor-rtmock",
"tracing", "tracing",
"tracing-test", "tracing-test",
] ]

View File

@ -43,7 +43,7 @@ fn some_interesting_netdir<'v, V>(values: V) -> Arc<NetDir>
where where
V: IntoIterator<Item = (&'v str, i32)>, V: IntoIterator<Item = (&'v str, i32)>,
{ {
tor_netdir::testnet::construct_custom_netdir_with_params(|_, _| {}, values) tor_netdir::testnet::construct_custom_netdir_with_params(|_, _| {}, values, None)
.unwrap() .unwrap()
.unwrap_if_sufficient() .unwrap_if_sufficient()
.unwrap() .unwrap()
@ -100,6 +100,7 @@ fn padding_parameters_calculation() {
tor_netdir::testnet::construct_custom_netdir_with_params( tor_netdir::testnet::construct_custom_netdir_with_params(
|_, _| {}, |_, _| {},
values.iter().cloned(), values.iter().cloned(),
None,
) )
.unwrap() .unwrap()
.unwrap_if_sufficient() .unwrap_if_sufficient()

View File

@ -43,6 +43,7 @@ tor-rtcompat = { version = "0.9.0", path = "../tor-rtcompat" }
tracing = "0.1.36" tracing = "0.1.36"
[dev-dependencies] [dev-dependencies]
humantime = "2"
tokio-crate = { package = "tokio", version = "1.7", features = ["full"] } tokio-crate = { package = "tokio", version = "1.7", features = ["full"] }
tor-async-utils = { path = "../tor-async-utils", version = "0.1.0" } tor-async-utils = { path = "../tor-async-utils", version = "0.1.0" }
tor-chanmgr = { path = "../tor-chanmgr", version = "0.9.0" } tor-chanmgr = { path = "../tor-chanmgr", version = "0.9.0" }
@ -52,4 +53,5 @@ tor-netdir = { path = "../tor-netdir", version = "0.9.0", features = ["testing"]
tor-netdoc = { path = "../tor-netdoc", version = "0.7.0", features = ["testing"] } tor-netdoc = { path = "../tor-netdoc", version = "0.7.0", features = ["testing"] }
tor-persist = { path = "../tor-persist", version = "0.7.0", features = ["testing"] } tor-persist = { path = "../tor-persist", version = "0.7.0", features = ["testing"] }
tor-rtcompat = { path = "../tor-rtcompat", version = "0.9.0", features = ["tokio", "native-tls"] } tor-rtcompat = { path = "../tor-rtcompat", version = "0.9.0", features = ["tokio", "native-tls"] }
tor-rtmock = { path = "../tor-rtmock", version = "0.8.0" }
tracing-test = "0.2" tracing-test = "0.2"

View File

@ -441,11 +441,13 @@ mod test {
use super::*; use super::*;
use crate::*; use crate::*;
use futures::FutureExt as _; use futures::FutureExt as _;
use std::panic::AssertUnwindSafe; use std::{iter, panic::AssertUnwindSafe};
use tokio_crate as tokio; use tokio_crate as tokio;
use tor_async_utils::JoinReadWrite; use tor_async_utils::JoinReadWrite;
use tor_netdoc::doc::hsdesc::test_data; use tor_llcrypto::pk::curve25519;
use tor_rtcompat::tokio::TokioNativeTlsRuntime; use tor_netdoc::doc::{hsdesc::test_data, netstatus::Lifetime};
use tor_rtcompat::{tokio::TokioNativeTlsRuntime, CompoundRuntime};
use tor_rtmock::time::MockSleepProvider;
use tracing_test::traced_test; use tracing_test::traced_test;
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -512,15 +514,43 @@ mod test {
#[traced_test] #[traced_test]
#[tokio::test] #[tokio::test]
async fn test_connect() { async fn test_connect() {
let netdir = tor_netdir::testnet::construct_netdir(); let valid_after = humantime::parse_rfc3339("2023-02-09T12:00:00Z").unwrap();
let fresh_until = valid_after + humantime::parse_duration("1 hours").unwrap();
let valid_until = valid_after + humantime::parse_duration("24 hours").unwrap();
let lifetime = Lifetime::new(valid_after, fresh_until, valid_until).unwrap();
let netdir = tor_netdir::testnet::construct_custom_netdir_with_params(
tor_netdir::testnet::simple_net_func,
iter::empty::<(&str, _)>(),
Some(lifetime),
)
.expect("failed to build default testing netdir");
let netdir = Arc::new(netdir.unwrap_if_sufficient().unwrap()); let netdir = Arc::new(netdir.unwrap_if_sufficient().unwrap());
let runtime = TokioNativeTlsRuntime::current().unwrap(); let runtime = TokioNativeTlsRuntime::current().unwrap();
let now = humantime::parse_rfc3339("2023-02-09T12:00:00Z").unwrap();
let mock_sp = MockSleepProvider::new(now);
let runtime = CompoundRuntime::new(
runtime.clone(),
mock_sp,
runtime.clone(),
runtime.clone(),
runtime,
);
let time_period = netdir.hs_time_period();
let mglobal = Arc::new(Mutex::new(MocksGlobal::default())); let mglobal = Arc::new(Mutex::new(MocksGlobal::default()));
let mocks = Mocks { mglobal, id: () }; let mocks = Mocks { mglobal, id: () };
// From C Tor src/test/test_hs_common.c test_build_address // From C Tor src/test/test_hs_common.c test_build_address
let hsid = test_data::TEST_HSID_2.into(); let hsid = test_data::TEST_HSID_2.into();
let mut data = Data::default(); let mut data = Data::default();
let pk = curve25519::PublicKey::from(test_data::TEST_PUBKEY_2).into();
let sk = curve25519::StaticSecret::from(test_data::TEST_SECKEY_2).into();
let mut secret_keys_builder = HsClientSecretKeysBuilder::default();
secret_keys_builder.ks_hsc_desc_enc(sk);
let secret_keys = secret_keys_builder.build().unwrap();
let _got = AssertUnwindSafe( let _got = AssertUnwindSafe(
Context::new( Context::new(
&runtime, &runtime,
@ -528,7 +558,7 @@ mod test {
netdir, netdir,
hsid, hsid,
&mut data, &mut data,
HsClientSecretKeys::default(), secret_keys,
mocks.clone(), mocks.clone(),
) )
.unwrap() .unwrap()
@ -537,11 +567,31 @@ mod test {
.catch_unwind() // TODO HS remove this and the AssertUnwindSafe .catch_unwind() // TODO HS remove this and the AssertUnwindSafe
.await; .await;
let (hs_blind_id_key, subcredential) = HsIdKey::try_from(hsid)
.unwrap()
.compute_blinded_key(time_period)
.unwrap();
let hs_blind_id = hs_blind_id_key.id();
// TODO hs: make the tests pass again let sk = curve25519::StaticSecret::from(test_data::TEST_SECKEY_2).into();
//let mglobal = mocks.mglobal.lock().unwrap();
//assert_eq!(mglobal.hsdirs_asked.len(), 1); let hsdesc = HsDesc::parse_decrypt_validate(
//assert_eq!(mglobal.got_desc, Some(test_data::TEST_DATA_2.to_string())); test_data::TEST_DATA_2,
&hs_blind_id,
now,
&subcredential,
Some((&pk, &sk)),
)
.unwrap();
let mglobal = mocks.mglobal.lock().unwrap();
assert_eq!(mglobal.hsdirs_asked.len(), 1);
// TODO hs: here and in other places, consider implementing PartialEq instead, or creating
// an assert_dbg_eq macro (which would be part of a test_helpers crate or something)
assert_eq!(
format!("{:?}", mglobal.got_desc),
format!("{:?}", Some(hsdesc))
);
// TODO hs check the circuit in got is the one we gave out // TODO hs check the circuit in got is the one we gave out
} }

View File

@ -841,7 +841,7 @@ impl NetDir {
/// ///
/// (Does not return unusable relays.) /// (Does not return unusable relays.)
/// ///
/// ///
/// Note that a `None` answer is not always permanent: if a microdescriptor /// Note that a `None` answer is not always permanent: if a microdescriptor
/// is subsequently added for a relay with this ID, the ID may become usable /// is subsequently added for a relay with this ID, the ID may become usable
/// even if it was not usable before. /// even if it was not usable before.
@ -1828,13 +1828,16 @@ mod test {
#[test] #[test]
fn relay_funcs() { fn relay_funcs() {
let (consensus, microdescs) = construct_custom_network(|pos, nb| { let (consensus, microdescs) = construct_custom_network(
if pos == 15 { |pos, nb| {
nb.rs.add_or_port("[f0f0::30]:9001".parse().unwrap()); if pos == 15 {
} else if pos == 20 { nb.rs.add_or_port("[f0f0::30]:9001".parse().unwrap());
nb.rs.add_or_port("[f0f0::3131]:9001".parse().unwrap()); } else if pos == 20 {
} nb.rs.add_or_port("[f0f0::3131]:9001".parse().unwrap());
}) }
},
None,
)
.unwrap(); .unwrap();
let subnet_config = SubnetConfig::default(); let subnet_config = SubnetConfig::default();
let mut dir = PartialNetDir::new(consensus, None); let mut dir = PartialNetDir::new(consensus, None);

View File

@ -46,7 +46,7 @@ pub struct NodeBuilders {
} }
/// Helper: a customization function that does nothing. /// Helper: a customization function that does nothing.
fn simple_net_func(_idx: usize, _nb: &mut NodeBuilders) {} pub fn simple_net_func(_idx: usize, _nb: &mut NodeBuilders) {}
/// As [`construct_network()`], but return a [`PartialNetDir`]. /// As [`construct_network()`], but return a [`PartialNetDir`].
pub fn construct_netdir() -> PartialNetDir { pub fn construct_netdir() -> PartialNetDir {
@ -58,13 +58,14 @@ pub fn construct_netdir() -> PartialNetDir {
pub fn construct_custom_netdir_with_params<F, P, PK>( pub fn construct_custom_netdir_with_params<F, P, PK>(
func: F, func: F,
params: P, params: P,
lifetime: Option<Lifetime>,
) -> BuildResult<PartialNetDir> ) -> BuildResult<PartialNetDir>
where where
F: FnMut(usize, &mut NodeBuilders), F: FnMut(usize, &mut NodeBuilders),
P: IntoIterator<Item = (PK, i32)>, P: IntoIterator<Item = (PK, i32)>,
PK: Into<String>, PK: Into<String>,
{ {
let (consensus, microdescs) = construct_custom_network(func)?; let (consensus, microdescs) = construct_custom_network(func, lifetime)?;
let mut dir = PartialNetDir::new(consensus, Some(&params.into_iter().collect())); let mut dir = PartialNetDir::new(consensus, Some(&params.into_iter().collect()));
for md in microdescs { for md in microdescs {
dir.add_microdesc(md); dir.add_microdesc(md);
@ -78,13 +79,13 @@ pub fn construct_custom_netdir<F>(func: F) -> BuildResult<PartialNetDir>
where where
F: FnMut(usize, &mut NodeBuilders), F: FnMut(usize, &mut NodeBuilders),
{ {
construct_custom_netdir_with_params(func, iter::empty::<(&str, _)>()) construct_custom_netdir_with_params(func, iter::empty::<(&str, _)>(), None)
} }
/// As [`construct_custom_network`], but do not require a /// As [`construct_custom_network`], but do not require a
/// customization function. /// customization function.
pub fn construct_network() -> BuildResult<(MdConsensus, Vec<Microdesc>)> { pub fn construct_network() -> BuildResult<(MdConsensus, Vec<Microdesc>)> {
construct_custom_network(simple_net_func) construct_custom_network(simple_net_func, None)
} }
/// Build a fake network with enough information to enable some basic /// Build a fake network with enough information to enable some basic
@ -140,7 +141,10 @@ pub fn construct_network() -> BuildResult<(MdConsensus, Vec<Microdesc>)> {
/// Instead, refactor this function so that it takes a /// Instead, refactor this function so that it takes a
/// description of what kind of network to build, and then builds it from /// description of what kind of network to build, and then builds it from
/// that description. /// that description.
pub fn construct_custom_network<F>(mut func: F) -> BuildResult<(MdConsensus, Vec<Microdesc>)> pub fn construct_custom_network<F>(
mut func: F,
lifetime: Option<Lifetime>,
) -> BuildResult<(MdConsensus, Vec<Microdesc>)>
where where
F: FnMut(usize, &mut NodeBuilders), F: FnMut(usize, &mut NodeBuilders),
{ {
@ -153,11 +157,16 @@ where
f | RelayFlags::EXIT | RelayFlags::GUARD, f | RelayFlags::EXIT | RelayFlags::GUARD,
]; ];
let now = SystemTime::now(); let lifetime = lifetime.map(Ok).unwrap_or_else(|| {
let one_day = Duration::new(86400, 0); let now = SystemTime::now();
let one_day = Duration::new(86400, 0);
Lifetime::new(now, now + one_day / 2, now + one_day)
})?;
let mut bld = MdConsensus::builder(); let mut bld = MdConsensus::builder();
bld.consensus_method(34) bld.consensus_method(34)
.lifetime(Lifetime::new(now, now + one_day / 2, now + one_day)?) .lifetime(lifetime)
.param("bwweightscale", 1) .param("bwweightscale", 1)
.weights("".parse()?); .weights("".parse()?);