manycastr/orchestrator/
config.rs1use crate::ALL_WORKERS;
2use crate::custom_module::manycastr::{Address, ProtocolType};
3use crate::custom_module::parse_src_address;
4use log::info;
5use std::collections::{HashMap, HashSet};
6use std::fmt;
7use std::fmt::Display;
8use std::fs;
9use std::path::Path;
10use std::sync::{Arc, Mutex};
11
12#[derive(Debug, Clone)]
14pub struct AllowedOrigin {
15 pub src: Address,
17 pub protocols: Option<Vec<ProtocolType>>,
19}
20
21impl AllowedOrigin {
22 pub fn allows(&self, p_type: ProtocolType) -> bool {
24 self.protocols
25 .as_ref()
26 .is_none_or(|protocols| protocols.contains(&p_type))
27 }
28}
29
30impl Display for AllowedOrigin {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 match &self.protocols {
34 None => write!(f, "{} (all)", self.src),
35 Some(protocols) => {
36 let protocols: Vec<&str> = protocols.iter().map(|p| p.as_str()).collect();
37 write!(f, "{} ({})", self.src, protocols.join("|"))
38 }
39 }
40 }
41}
42
43pub fn load_allowed_origins(origins_path: &String) -> Vec<AllowedOrigin> {
59 if !Path::new(origins_path).exists() {
60 panic!("[Orchestrator] Origins file {origins_path} not found!");
61 }
62
63 let content =
64 fs::read_to_string(origins_path).expect("[Orchestrator] Could not read the origins file.");
65
66 let mut allowed_origins = Vec::new();
67
68 for (i, line) in content.lines().enumerate() {
69 let line_number = i + 1;
70
71 let trimmed_line = line.trim();
72
73 if trimmed_line.is_empty() || trimmed_line.starts_with('#') {
75 continue;
76 }
77
78 let mut parts = trimmed_line.split(',').map(str::trim);
80 let src = parse_src_address(parts.next().unwrap());
81
82 let protocol_tokens: Vec<&str> = parts.collect();
83 if protocol_tokens.is_empty() {
84 panic!(
85 "[Orchestrator] Error on line {line_number}: Malformed entry. Expected 'src_addr, protocol[, protocol...]' ('all' allows all protocols), found '{line}'"
86 );
87 }
88
89 let protocols = if protocol_tokens
91 .iter()
92 .any(|p| p.eq_ignore_ascii_case("all"))
93 {
94 None
95 } else {
96 Some(
97 protocol_tokens
98 .iter()
99 .map(|p| {
100 ProtocolType::from_str(p).unwrap_or_else(|| {
101 panic!(
102 "[Orchestrator] Error on line {line_number}: Unknown protocol '{p}'. Expected icmp, dns, tcp, chaos, or all."
103 )
104 })
105 })
106 .collect(),
107 )
108 };
109
110 allowed_origins.push(AllowedOrigin { src, protocols });
111 }
112
113 if allowed_origins.is_empty() {
114 panic!("[Orchestrator] No origin rules found in {origins_path}");
115 }
116
117 info!(
118 "[Orchestrator] {} allowed origins loaded.",
119 allowed_origins.len()
120 );
121
122 allowed_origins
123}
124
125pub fn load_worker_config(config_path: &String) -> (Arc<Mutex<u32>>, Option<HashMap<String, u32>>) {
140 if !Path::new(config_path).exists() {
141 panic!("[Orchestrator] Configuration file {config_path} not found!");
142 }
143
144 let config_content = fs::read_to_string(config_path)
145 .expect("[Orchestrator] Could not read the configuration file.");
146
147 let mut hosts = HashMap::new();
148 let mut used_ids = HashSet::new();
149
150 for (i, line) in config_content.lines().enumerate() {
151 let line_number = i + 1;
152
153 let trimmed_line = line.trim();
154
155 if trimmed_line.is_empty() || trimmed_line.starts_with('#') {
157 continue;
158 }
159
160 let parts: Vec<&str> = trimmed_line.split(',').collect();
162 if parts.len() != 2 {
163 panic!(
164 "[Orchestrator] Error on line {line_number}: Malformed entry. Expected 'hostname,id', found '{line}'"
165 );
166 }
167
168 let hostname = parts[0].trim().to_string();
169 let id = match parts[1].trim().parse::<u32>() {
170 Ok(val) => val,
171 Err(_) => {
172 panic!(
173 "[Orchestrator] Error on line {line_number}: Invalid ID '{}'. ID must be an integer.",
174 parts[1].trim()
175 );
176 }
177 };
178
179 if hosts.contains_key(&hostname) {
181 panic!(
182 "[Orchestrator] Error on line {line_number}: Duplicate hostname '{hostname}' found. Hostnames must be unique."
183 );
184 }
185
186 if !used_ids.insert(id) {
188 panic!(
189 "[Orchestrator] Error on line {line_number}: Duplicate ID '{id}' found. IDs must be unique."
190 );
191 }
192
193 if id == ALL_WORKERS {
195 panic!(
196 "[Orchestrator] Error on line {line_number}: ID '{id}' is reserved for special purposes. Please use a different ID."
197 );
198 }
199
200 hosts.insert(hostname, id);
201 }
202
203 info!("[Orchestrator] {} hosts loaded.", hosts.len());
204
205 let current_worker_id = hosts.values().max().map_or(1, |&max_id| max_id + 1);
207
208 (Arc::new(Mutex::new(current_worker_id)), Some(hosts))
209}