tor_dircommon/
fallback.rs1use base64ct::{Base64Unpadded, Encoding as _};
14use derive_builder::Builder;
15use tor_config::{ConfigBuildError, define_list_builder_helper};
16use tor_config::{define_list_builder_accessors, impl_standard_builder, list_builder::VecBuilder};
17use tor_llcrypto::pk::ed25519::Ed25519Identity;
18use tor_llcrypto::pk::rsa::RsaIdentity;
19
20use serde::{Deserialize, Serialize};
21use std::net::SocketAddr;
22
23#[derive(Debug, Clone, Builder, Eq, PartialEq)]
31#[builder(build_fn(private, name = "build_unvalidated", error = "ConfigBuildError"))]
32#[builder(derive(Debug, Serialize, Deserialize))]
33pub struct FallbackDir {
34 rsa_identity: RsaIdentity,
36 ed_identity: Ed25519Identity,
38 #[builder(sub_builder(fn_name = "build"), setter(custom))]
40 orports: Vec<SocketAddr>,
41}
42
43impl_standard_builder! { FallbackDir: !Default }
44
45define_list_builder_accessors! {
46 struct FallbackDirBuilder {
47 pub orports: [SocketAddr],
48 }
49}
50
51impl FallbackDirBuilder {
52 pub fn new() -> Self {
57 Self::default()
58 }
59 pub fn build(&self) -> std::result::Result<FallbackDir, ConfigBuildError> {
66 let built = self.build_unvalidated()?;
67 if built.orports.is_empty() {
68 return Err(ConfigBuildError::Invalid {
69 field: "orport".to_string(),
70 problem: "list was empty".to_string(),
71 });
72 }
73 Ok(built)
74 }
75}
76
77#[derive(Debug, Clone, Default, PartialEq, Eq)]
83pub struct FallbackList {
84 fallbacks: Vec<FallbackDir>,
86}
87
88impl<T: IntoIterator<Item = FallbackDir>> From<T> for FallbackList {
89 fn from(fallbacks: T) -> Self {
90 FallbackList {
91 fallbacks: fallbacks.into_iter().collect(),
92 }
93 }
94}
95
96define_list_builder_helper! {
97 pub struct FallbackListBuilder {
99 pub(crate) fallbacks: [FallbackDirBuilder],
100 }
101 built: FallbackList = FallbackList { fallbacks };
102 default = default_fallbacks();
103}
104
105impl FallbackList {
106 pub fn len(&self) -> usize {
108 self.fallbacks.len()
109 }
110 pub fn is_empty(&self) -> bool {
112 self.fallbacks.is_empty()
113 }
114 pub fn iter(&self) -> std::slice::Iter<'_, FallbackDir> {
116 self.fallbacks.iter()
117 }
118}
119
120pub(crate) fn default_fallbacks() -> Vec<FallbackDirBuilder> {
123 fn fallback(rsa: &str, ed: &str, ports: &[&str]) -> FallbackDirBuilder {
125 let rsa = RsaIdentity::from_hex(rsa).expect("Bad hex in built-in fallback list");
126 let ed = Base64Unpadded::decode_vec(ed).expect("Bad hex in built-in fallback list");
127 let ed = Ed25519Identity::from_bytes(&ed).expect("Wrong length in built-in fallback list");
128 let mut bld = FallbackDir::builder();
129 bld.rsa_identity(rsa).ed_identity(ed);
130
131 ports
132 .iter()
133 .map(|s| s.parse().expect("Bad socket address in fallbacklist"))
134 .for_each(|p| {
135 bld.orports().push(p);
136 });
137
138 bld
139 }
140 include!("../data/fallback_dirs.rs")
141}
142
143impl tor_linkspec::HasAddrs for FallbackDir {
144 fn addrs(&self) -> impl Iterator<Item = SocketAddr> {
145 self.orports.iter().copied()
146 }
147}
148impl tor_linkspec::HasRelayIdsLegacy for FallbackDir {
149 fn ed_identity(&self) -> &Ed25519Identity {
150 &self.ed_identity
151 }
152 fn rsa_identity(&self) -> &RsaIdentity {
153 &self.rsa_identity
154 }
155}
156
157impl tor_linkspec::DirectChanMethodsHelper for FallbackDir {}
158
159impl tor_linkspec::ChanTarget for FallbackDir {}