1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
//! Code to construct paths to a directory for non-anonymous downloads
use super::*;
use crate::{DirInfo, Error};
use tor_netdir::{Relay, WeightRole};
use rand::seq::SliceRandom;
/// A PathBuilder that can connect to a directory.
#[non_exhaustive]
pub struct DirPathBuilder {}
impl Default for DirPathBuilder {
fn default() -> Self {
Self::new()
}
}
impl DirPathBuilder {
/// Create a new DirPathBuilder.
pub fn new() -> Self {
DirPathBuilder {}
}
/// Try to create and return a path corresponding to the requirements of
/// this builder.
pub fn pick_path<'a, R: Rng>(&self, rng: &mut R, netdir: DirInfo<'a>) -> Result<TorPath<'a>> {
// TODO: this will need to learn about directory guards.
match netdir {
DirInfo::Fallbacks(f) => {
let relay = f.choose(rng);
if let Some(r) = relay {
return Ok(TorPath::new_fallback_one_hop(r));
}
}
DirInfo::Directory(netdir) => {
let relay = netdir.pick_relay(rng, WeightRole::BeginDir, Relay::is_dir_cache);
if let Some(r) = relay {
return Ok(TorPath::new_one_hop(r));
}
}
}
Err(Error::NoRelays(
"No relays found for use as directory cache".into(),
))
}
}
#[cfg(test)]
mod test {
use super::*;
use tor_netdir::testnet;
#[test]
fn dirpath_relay() {
let netdir = testnet::construct_netdir();
let mut rng = rand::thread_rng();
let dirinfo = (&netdir).into();
for _ in 0..1000 {
let p = DirPathBuilder::default().pick_path(&mut rng, dirinfo);
let p = p.unwrap();
assert!(p.exit_relay().is_none());
assert_eq!(p.len(), 1);
assert_same_path_when_owned(&p);
if let crate::path::TorPathInner::OneHop(r) = p.inner {
assert!(r.is_dir_cache());
} else {
panic!("Generated the wrong kind of path.");
}
}
}
#[test]
fn dirpath_fallback() {
let fb = vec![
FallbackDir::builder()
.rsa_identity([0x01; 20].into())
.ed_identity([0x01; 32].into())
.orport("127.0.0.1:9000".parse().unwrap())
.build()
.unwrap(),
FallbackDir::builder()
.rsa_identity([0x03; 20].into())
.ed_identity([0x03; 32].into())
.orport("127.0.0.1:9003".parse().unwrap())
.build()
.unwrap(),
];
let dirinfo = (&fb[..]).into();
let mut rng = rand::thread_rng();
for _ in 0..10 {
let p = DirPathBuilder::default().pick_path(&mut rng, dirinfo);
let p = p.unwrap();
assert!(p.exit_relay().is_none());
assert_eq!(p.len(), 1);
assert_same_path_when_owned(&p);
if let crate::path::TorPathInner::FallbackOneHop(f) = p.inner {
assert!(std::ptr::eq(f, &fb[0]) || std::ptr::eq(f, &fb[1]));
} else {
panic!("Generated the wrong kind of path.");
}
}
}
#[test]
fn dirpath_no_fallbacks() {
let fb = vec![];
let dirinfo = DirInfo::Fallbacks(&fb[..]);
let mut rng = rand::thread_rng();
let err = DirPathBuilder::default().pick_path(&mut rng, dirinfo);
assert!(matches!(err, Err(Error::NoRelays(_))));
}
}
|