1use zeroize::Zeroize;
8
9use eggress_core::ProtocolId;
10use eggress_routing::scheduler::SchedulerKind;
11use eggress_routing::UpstreamGroupId;
12
13#[derive(Clone)]
15pub struct CompiledReverseServerTls {
16 pub cert_pem: Vec<u8>,
17 pub key_pem: Vec<u8>,
18 pub client_ca_pem: Option<Vec<u8>>,
19 pub require_client_cert: bool,
20}
21
22impl std::fmt::Debug for CompiledReverseServerTls {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 f.debug_struct("CompiledReverseServerTls")
25 .field("has_cert", &!self.cert_pem.is_empty())
26 .field("has_key", &!self.key_pem.is_empty())
27 .field("has_client_ca", &self.client_ca_pem.is_some())
28 .field("require_client_cert", &self.require_client_cert)
29 .finish()
30 }
31}
32
33impl Drop for CompiledReverseServerTls {
34 fn drop(&mut self) {
35 self.key_pem.zeroize();
36 if let Some(ref mut ca) = self.client_ca_pem {
37 ca.zeroize();
38 }
39 }
40}
41
42#[derive(Clone)]
44pub struct CompiledReverseClientTls {
45 pub ca_pem: Option<Vec<u8>>,
46 pub server_name: String,
47 pub client_cert_pem: Option<Vec<u8>>,
48 pub client_key_pem: Option<Vec<u8>>,
49}
50
51impl std::fmt::Debug for CompiledReverseClientTls {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 f.debug_struct("CompiledReverseClientTls")
54 .field("has_ca", &self.ca_pem.is_some())
55 .field("server_name", &self.server_name)
56 .field("has_client_cert", &self.client_cert_pem.is_some())
57 .field("has_client_key", &self.client_key_pem.is_some())
58 .finish()
59 }
60}
61
62impl Drop for CompiledReverseClientTls {
63 fn drop(&mut self) {
64 if let Some(ref mut key) = self.client_key_pem {
65 key.zeroize();
66 }
67 }
68}
69
70#[derive(Clone)]
72pub struct CompiledReverseServerConfig {
73 pub id: String,
74 pub control_bind: std::net::SocketAddr,
75 pub external_bind: std::net::SocketAddr,
76 pub auth_username: Option<String>,
77 pub auth_password: Option<String>,
78 pub max_control_connections: u32,
79 pub read_timeout_ms: u64,
80 pub allow_bind: Option<Vec<std::net::SocketAddr>>,
81 pub max_listeners_per_client: u32,
82 pub max_streams_per_listener: u32,
83 pub max_pending_external: u32,
84 pub pproxy_compat: bool,
85 pub tls: Option<CompiledReverseServerTls>,
86}
87
88impl std::fmt::Debug for CompiledReverseServerConfig {
89 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 f.debug_struct("CompiledReverseServerConfig")
93 .field("id", &self.id)
94 .field("control_bind", &self.control_bind)
95 .field("external_bind", &self.external_bind)
96 .field("auth_username", &self.auth_username)
97 .field("auth_password", &"****")
98 .field("max_control_connections", &self.max_control_connections)
99 .field("read_timeout_ms", &self.read_timeout_ms)
100 .field("allow_bind", &self.allow_bind)
101 .field("max_listeners_per_client", &self.max_listeners_per_client)
102 .field("max_streams_per_listener", &self.max_streams_per_listener)
103 .field("max_pending_external", &self.max_pending_external)
104 .field("pproxy_compat", &self.pproxy_compat)
105 .field("tls", &self.tls)
106 .finish()
107 }
108}
109
110impl Drop for CompiledReverseServerConfig {
111 fn drop(&mut self) {
112 if let Some(password) = &mut self.auth_password {
113 password.zeroize();
114 }
115 }
116}
117
118#[derive(Clone)]
120pub struct CompiledReverseClientConfig {
121 pub id: String,
122 pub server_addr: std::net::SocketAddr,
123 pub server_chain: Option<eggress_uri::ProxyChainSpec>,
124 pub auth_username: Option<String>,
125 pub auth_password: Option<String>,
126 pub reconnect_initial_ms: u64,
127 pub reconnect_max_ms: u64,
128 pub default_target_host: Option<String>,
129 pub default_target_port: Option<u16>,
130 pub read_timeout_ms: u64,
131 pub drain_grace_ms: u64,
132 pub parallel_connections: u32,
133 pub pproxy_compat: bool,
134 pub tls: Option<CompiledReverseClientTls>,
135}
136
137impl std::fmt::Debug for CompiledReverseClientConfig {
138 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139 f.debug_struct("CompiledReverseClientConfig")
141 .field("id", &self.id)
142 .field("server_addr", &self.server_addr)
143 .field("server_chain", &self.server_chain)
144 .field("auth_username", &self.auth_username)
145 .field("auth_password", &"****")
146 .field("reconnect_initial_ms", &self.reconnect_initial_ms)
147 .field("reconnect_max_ms", &self.reconnect_max_ms)
148 .field("default_target_host", &self.default_target_host)
149 .field("default_target_port", &self.default_target_port)
150 .field("read_timeout_ms", &self.read_timeout_ms)
151 .field("drain_grace_ms", &self.drain_grace_ms)
152 .field("parallel_connections", &self.parallel_connections)
153 .field("pproxy_compat", &self.pproxy_compat)
154 .field("tls", &self.tls)
155 .finish()
156 }
157}
158
159impl Drop for CompiledReverseClientConfig {
160 fn drop(&mut self) {
161 if let Some(password) = &mut self.auth_password {
162 password.zeroize();
163 }
164 }
165}
166
167#[derive(Debug, Clone)]
168pub struct RuntimeConfig {
169 pub process: ProcessConfig,
170 pub timeouts: TimeoutConfig,
171 pub listeners: Vec<ListenerConfig>,
172 pub upstreams: Vec<UpstreamConfig>,
173 pub groups: Vec<UpstreamGroupConfig>,
174 pub rules: Vec<eggress_routing::CompiledRule>,
175 pub default_action: eggress_routing::RouteActionSpec,
176 pub admin: Option<AdminConfig>,
177 pub reverse_servers: Vec<CompiledReverseServerConfig>,
178 pub reverse_clients: Vec<CompiledReverseClientConfig>,
179}
180
181#[derive(Debug, Clone)]
182pub struct ProcessConfig {
183 pub log_format: String,
184 pub log_level: String,
185 pub shutdown_grace: std::time::Duration,
186}
187
188impl Default for ProcessConfig {
189 fn default() -> Self {
190 Self {
191 log_format: "text".to_string(),
192 log_level: "info".to_string(),
193 shutdown_grace: std::time::Duration::from_secs(30),
194 }
195 }
196}
197
198#[derive(Debug, Clone, PartialEq, Eq)]
199pub struct TimeoutConfig {
200 pub handshake: std::time::Duration,
201 pub connect: std::time::Duration,
202}
203
204impl Default for TimeoutConfig {
205 fn default() -> Self {
206 Self {
207 handshake: std::time::Duration::from_secs(10),
208 connect: std::time::Duration::from_secs(30),
209 }
210 }
211}
212
213#[derive(Debug, Clone)]
215pub struct CompiledTransparentConfig {
216 pub enabled: bool,
217 pub protocol: String,
218}
219
220impl Default for CompiledTransparentConfig {
221 fn default() -> Self {
222 Self {
223 enabled: false,
224 protocol: "redir".to_string(),
225 }
226 }
227}
228
229#[derive(Debug, Clone)]
231pub struct CompiledUnixListenerConfig {
232 pub path: std::path::PathBuf,
233 pub unlink_existing: bool,
234 pub mode: u32,
235}
236
237#[derive(Debug, Clone)]
239pub struct CompiledListenerUdpConfig {
240 pub mode: eggress_udp::UdpMode,
241 pub enabled: bool,
242 pub bind: std::net::SocketAddr,
243 pub advertise: Option<std::net::IpAddr>,
244 pub idle_timeout: std::time::Duration,
245 pub target_idle_timeout: std::time::Duration,
246 pub max_associations: usize,
247 pub max_targets_per_association: usize,
248 pub max_datagram_size: usize,
249 pub client_pin: bool,
250 pub allow_private_egress: bool,
251 pub max_associations_global: usize,
252 pub fixed_target: Option<eggress_core::TargetAddr>,
253 pub upstream_connect_timeout: std::time::Duration,
254 pub upstream_udp_bind: std::net::SocketAddr,
255}
256
257impl Default for CompiledListenerUdpConfig {
258 fn default() -> Self {
259 Self {
260 mode: eggress_udp::UdpMode::Socks5UdpAssociate,
261 enabled: true,
262 bind: "127.0.0.1:0".parse().unwrap(),
263 advertise: None,
264 idle_timeout: std::time::Duration::from_secs(60),
265 target_idle_timeout: std::time::Duration::from_secs(30),
266 max_associations: 1024,
267 max_targets_per_association: 64,
268 max_datagram_size: 65535,
269 client_pin: true,
270 allow_private_egress: true,
271 max_associations_global: 1024,
272 fixed_target: None,
273 upstream_connect_timeout: std::time::Duration::from_secs(10),
274 upstream_udp_bind: "127.0.0.1:0".parse().unwrap(),
275 }
276 }
277}
278
279#[derive(Debug, Clone)]
280pub struct ListenerConfig {
281 pub name: String,
282 pub bind: String,
283 pub protocols: Vec<ProtocolId>,
284 pub reuse_port: Option<bool>,
285 pub connection_limit: Option<u32>,
286 pub auth: Option<crate::model::AuthConfig>,
287 pub udp: Option<CompiledListenerUdpConfig>,
288 pub tls: Option<CompiledListenerTlsConfig>,
289 pub shadowsocks: Option<crate::model::ShadowsocksListenerConfig>,
290 pub trojan: Option<crate::model::ListenerTrojanConfig>,
291 pub transparent: Option<CompiledTransparentConfig>,
292 pub unix: Option<CompiledUnixListenerConfig>,
293 pub fixed_target: Option<eggress_core::TargetAddr>,
294 pub local_bind: Option<String>,
295}
296
297#[derive(Debug, Clone)]
299pub struct CompiledListenerTlsConfig {
300 pub cert_pem: Vec<u8>,
301 pub key_pem: Vec<u8>,
302 pub alpn: Vec<Vec<u8>>,
303}
304
305#[derive(Debug, Clone)]
306pub struct CompiledH2Config {
307 pub max_concurrent_streams: u32,
308 pub pool_size: u32,
309 pub idle_timeout: std::time::Duration,
310 pub keepalive_interval: std::time::Duration,
311 pub keepalive_timeout: std::time::Duration,
312 pub stream_receive_window: u32,
313 pub connection_receive_window: u32,
314 pub max_frame_size: u32,
315 pub max_header_list_size: u32,
316}
317
318impl Default for CompiledH2Config {
319 fn default() -> Self {
320 Self {
321 max_concurrent_streams: 100,
322 pool_size: 4,
323 idle_timeout: std::time::Duration::from_secs(60),
324 keepalive_interval: std::time::Duration::from_secs(30),
325 keepalive_timeout: std::time::Duration::from_secs(10),
326 stream_receive_window: 65535,
327 connection_receive_window: 65535,
328 max_frame_size: 16384,
329 max_header_list_size: 65535,
330 }
331 }
332}
333
334#[derive(Debug, Clone)]
335pub struct UpstreamConfig {
336 pub id: String,
337 pub chain: eggress_uri::ProxyChainSpec,
338 pub health: eggress_routing::health::HealthConfig,
339 pub h2: Option<CompiledH2Config>,
340}
341
342#[derive(Debug, Clone)]
343pub struct UpstreamGroupConfig {
344 pub id: UpstreamGroupId,
345 pub scheduler: SchedulerKind,
346 pub members: Vec<String>,
347 pub fallback: GroupFallback,
348}
349
350#[derive(Debug, Clone, Copy, PartialEq, Eq)]
351pub enum GroupFallback {
352 Reject,
353 Direct,
354 UseUnhealthy,
355}
356
357#[derive(Debug, Clone)]
358pub struct PacConfig {
359 pub path: String,
360 pub proxy_directive: String,
361 pub direct_fallback: bool,
362 pub direct_hosts: Vec<String>,
363 pub direct_suffixes: Vec<String>,
364}
365
366#[derive(Debug, Clone)]
367pub struct StaticRoute {
368 pub path: String,
369 pub content_type: String,
370 pub body: String,
371}
372
373#[derive(Debug, Clone)]
374pub struct AdminConfig {
375 pub bind: String,
376 pub enabled: bool,
377 pub metrics: bool,
378 pub auth: Option<AdminAuthConfig>,
379 pub pac: Option<PacConfig>,
380 pub static_content: Vec<StaticRoute>,
381}
382
383#[derive(Clone)]
384pub struct AdminAuthConfig {
385 pub bearer_token: Option<String>,
386 pub basic_username: Option<String>,
387 pub basic_password: Option<String>,
388}
389
390impl std::fmt::Debug for AdminAuthConfig {
391 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
392 f.debug_struct("AdminAuthConfig")
395 .field("bearer_token", &"****")
396 .field("basic_username", &self.basic_username)
397 .field("basic_password", &"****")
398 .finish()
399 }
400}
401
402impl Drop for AdminAuthConfig {
403 fn drop(&mut self) {
404 if let Some(token) = &mut self.bearer_token {
405 token.zeroize();
406 }
407 if let Some(password) = &mut self.basic_password {
408 password.zeroize();
409 }
410 }
411}