1mod set;
14
15use base64ct::{Base64Unpadded, Encoding as _};
16use derive_builder::Builder;
17use tor_config::ConfigBuildError;
18use tor_config::{define_list_builder_accessors, impl_standard_builder, list_builder::VecBuilder};
19use tor_linkspec::{DirectChanMethodsHelper, OwnedChanTarget};
20use tor_llcrypto::pk::ed25519::Ed25519Identity;
21use tor_llcrypto::pk::rsa::RsaIdentity;
22
23use serde::{Deserialize, Serialize};
24use std::net::SocketAddr;
25
26use crate::dirstatus::DirStatus;
27pub(crate) use set::FallbackState;
28pub use set::{FallbackList, FallbackListBuilder};
29
30#[derive(Debug, Clone, Builder, Eq, PartialEq)]
38#[builder(build_fn(private, name = "build_unvalidated", error = "ConfigBuildError"))]
39#[builder(derive(Debug, Serialize, Deserialize))]
40pub struct FallbackDir {
41 rsa_identity: RsaIdentity,
43 ed_identity: Ed25519Identity,
45 #[builder(sub_builder(fn_name = "build"), setter(custom))]
47 orports: Vec<SocketAddr>,
48}
49
50impl_standard_builder! { FallbackDir: !Default }
51
52define_list_builder_accessors! {
53 struct FallbackDirBuilder {
54 pub orports: [SocketAddr],
55 }
56}
57
58impl FallbackDir {
59 pub fn as_guard(&self) -> crate::FirstHop {
61 crate::FirstHop {
62 sample: None,
63 inner: crate::FirstHopInner::Chan(OwnedChanTarget::from_chan_target(self)),
64 }
65 }
66}
67
68impl FallbackDirBuilder {
69 pub fn new() -> Self {
74 Self::default()
75 }
76 pub fn build(&self) -> std::result::Result<FallbackDir, ConfigBuildError> {
83 let built = self.build_unvalidated()?;
84 if built.orports.is_empty() {
85 return Err(ConfigBuildError::Invalid {
86 field: "orport".to_string(),
87 problem: "list was empty".to_string(),
88 });
89 }
90 Ok(built)
91 }
92}
93
94pub(crate) fn default_fallbacks() -> Vec<FallbackDirBuilder> {
97 fn fallback(rsa: &str, ed: &str, ports: &[&str]) -> FallbackDirBuilder {
99 let rsa = RsaIdentity::from_hex(rsa).expect("Bad hex in built-in fallback list");
100 let ed = Base64Unpadded::decode_vec(ed).expect("Bad hex in built-in fallback list");
101 let ed = Ed25519Identity::from_bytes(&ed).expect("Wrong length in built-in fallback list");
102 let mut bld = FallbackDir::builder();
103 bld.rsa_identity(rsa).ed_identity(ed);
104
105 ports
106 .iter()
107 .map(|s| s.parse().expect("Bad socket address in fallbacklist"))
108 .for_each(|p| {
109 bld.orports().push(p);
110 });
111
112 bld
113 }
114 include!("../data/fallback_dirs.rs")
115}
116
117impl tor_linkspec::HasAddrs for FallbackDir {
118 fn addrs(&self) -> &[SocketAddr] {
119 &self.orports[..]
120 }
121}
122impl tor_linkspec::HasRelayIdsLegacy for FallbackDir {
123 fn ed_identity(&self) -> &Ed25519Identity {
124 &self.ed_identity
125 }
126 fn rsa_identity(&self) -> &RsaIdentity {
127 &self.rsa_identity
128 }
129}
130
131impl DirectChanMethodsHelper for FallbackDir {}
132
133impl tor_linkspec::ChanTarget for FallbackDir {}