1use std::{fs, path::Path};
4
5use clap::Parser;
6use serde::{Deserialize, Serialize};
7use trojan_core::defaults;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct Config {
11 pub server: ServerConfig,
12 pub tls: TlsConfig,
13 pub auth: AuthConfig,
14 #[serde(default)]
15 pub websocket: WebSocketConfig,
16 #[serde(default)]
17 pub metrics: MetricsConfig,
18 #[serde(default)]
19 pub logging: LoggingConfig,
20 #[serde(default)]
21 pub analytics: AnalyticsConfig,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct ServerConfig {
26 pub listen: String,
27 pub fallback: String,
28 #[serde(default = "default_tcp_timeout_secs")]
29 pub tcp_idle_timeout_secs: u64,
30 #[serde(default = "default_udp_timeout_secs")]
31 pub udp_timeout_secs: u64,
32 #[serde(default = "default_max_udp_payload")]
33 pub max_udp_payload: usize,
34 #[serde(default = "default_max_udp_buffer_bytes")]
35 pub max_udp_buffer_bytes: usize,
36 #[serde(default = "default_max_header_bytes")]
37 pub max_header_bytes: usize,
38 #[serde(default)]
40 pub max_connections: Option<usize>,
41 #[serde(default)]
43 pub rate_limit: Option<RateLimitConfig>,
44 #[serde(default)]
46 pub fallback_pool: Option<FallbackPoolConfig>,
47 #[serde(default)]
49 pub resource_limits: Option<ResourceLimitsConfig>,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct FallbackPoolConfig {
60 #[serde(default = "default_pool_max_idle")]
62 pub max_idle: usize,
63 #[serde(default = "default_pool_max_age_secs")]
65 pub max_age_secs: u64,
66 #[serde(default = "default_pool_fill_batch")]
68 pub fill_batch: usize,
69 #[serde(default = "default_pool_fill_delay_ms")]
71 pub fill_delay_ms: u64,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct ResourceLimitsConfig {
77 #[serde(default = "default_relay_buffer_size")]
79 pub relay_buffer_size: usize,
80 #[serde(default)]
82 pub tcp_send_buffer: usize,
83 #[serde(default)]
85 pub tcp_recv_buffer: usize,
86 #[serde(default = "default_connection_backlog")]
88 pub connection_backlog: u32,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct RateLimitConfig {
94 #[serde(default = "default_rate_limit_max_connections")]
96 pub max_connections_per_ip: u32,
97 #[serde(default = "default_rate_limit_window_secs")]
99 pub window_secs: u64,
100 #[serde(default = "default_rate_limit_cleanup_secs")]
102 pub cleanup_interval_secs: u64,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct TlsConfig {
107 pub cert: String,
109 pub key: String,
111 #[serde(default)]
113 pub alpn: Vec<String>,
114 #[serde(default = "default_min_tls_version")]
116 pub min_version: String,
117 #[serde(default = "default_max_tls_version")]
119 pub max_version: String,
120 #[serde(default)]
123 pub client_ca: Option<String>,
124 #[serde(default)]
127 pub cipher_suites: Vec<String>,
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize, Default)]
131pub struct WebSocketConfig {
132 #[serde(default = "default_ws_enabled")]
133 pub enabled: bool,
134 #[serde(default = "default_ws_mode")]
135 pub mode: String,
136 #[serde(default = "default_ws_path")]
137 pub path: String,
138 #[serde(default)]
139 pub host: Option<String>,
140 #[serde(default)]
141 pub listen: Option<String>,
142 #[serde(default = "default_ws_max_frame_bytes")]
143 pub max_frame_bytes: usize,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct AuthConfig {
148 pub passwords: Vec<String>,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize, Default)]
152pub struct MetricsConfig {
153 pub listen: Option<String>,
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize, Default)]
157pub struct LoggingConfig {
158 pub level: Option<String>,
160 pub format: Option<String>,
162 pub output: Option<String>,
164 #[serde(default)]
166 pub filters: std::collections::HashMap<String, String>,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize, Default)]
175pub struct AnalyticsConfig {
176 #[serde(default)]
178 pub enabled: bool,
179
180 #[serde(default)]
182 pub clickhouse: Option<ClickHouseConfig>,
183
184 #[serde(default)]
186 pub buffer: AnalyticsBufferConfig,
187
188 #[serde(default)]
190 pub sampling: AnalyticsSamplingConfig,
191
192 #[serde(default)]
194 pub privacy: AnalyticsPrivacyConfig,
195
196 #[serde(default)]
198 pub server_id: Option<String>,
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize)]
203pub struct ClickHouseConfig {
204 pub url: String,
206
207 #[serde(default = "default_analytics_database")]
209 pub database: String,
210
211 #[serde(default = "default_analytics_table")]
213 pub table: String,
214
215 #[serde(default)]
217 pub username: Option<String>,
218
219 #[serde(default)]
221 pub password: Option<String>,
222
223 #[serde(default = "default_analytics_connect_timeout")]
225 pub connect_timeout_secs: u64,
226
227 #[serde(default = "default_analytics_write_timeout")]
229 pub write_timeout_secs: u64,
230}
231
232#[derive(Debug, Clone, Serialize, Deserialize)]
234pub struct AnalyticsBufferConfig {
235 #[serde(default = "default_analytics_buffer_size")]
237 pub size: usize,
238
239 #[serde(default = "default_analytics_flush_interval")]
241 pub flush_interval_secs: u64,
242
243 #[serde(default = "default_analytics_batch_size")]
245 pub batch_size: usize,
246
247 #[serde(default)]
249 pub fallback_path: Option<String>,
250}
251
252impl Default for AnalyticsBufferConfig {
253 fn default() -> Self {
254 Self {
255 size: default_analytics_buffer_size(),
256 flush_interval_secs: default_analytics_flush_interval(),
257 batch_size: default_analytics_batch_size(),
258 fallback_path: None,
259 }
260 }
261}
262
263#[derive(Debug, Clone, Serialize, Deserialize)]
265pub struct AnalyticsSamplingConfig {
266 #[serde(default = "default_analytics_sample_rate")]
268 pub rate: f64,
269
270 #[serde(default)]
272 pub always_record_users: Vec<String>,
273}
274
275impl Default for AnalyticsSamplingConfig {
276 fn default() -> Self {
277 Self {
278 rate: default_analytics_sample_rate(),
279 always_record_users: Vec::new(),
280 }
281 }
282}
283
284#[derive(Debug, Clone, Serialize, Deserialize)]
286pub struct AnalyticsPrivacyConfig {
287 #[serde(default = "default_true")]
289 pub record_peer_ip: bool,
290
291 #[serde(default)]
293 pub full_user_id: bool,
294
295 #[serde(default = "default_analytics_user_id_prefix_len")]
297 pub user_id_prefix_len: usize,
298
299 #[serde(default = "default_true")]
301 pub record_sni: bool,
302}
303
304impl Default for AnalyticsPrivacyConfig {
305 fn default() -> Self {
306 Self {
307 record_peer_ip: true,
308 full_user_id: false,
309 user_id_prefix_len: default_analytics_user_id_prefix_len(),
310 record_sni: true,
311 }
312 }
313}
314
315fn default_analytics_database() -> String {
317 "trojan".to_string()
318}
319
320fn default_analytics_table() -> String {
321 "connections".to_string()
322}
323
324fn default_analytics_buffer_size() -> usize {
325 10000
326}
327
328fn default_analytics_flush_interval() -> u64 {
329 5
330}
331
332fn default_analytics_batch_size() -> usize {
333 1000
334}
335
336fn default_analytics_sample_rate() -> f64 {
337 1.0
338}
339
340fn default_analytics_user_id_prefix_len() -> usize {
341 8
342}
343
344fn default_analytics_connect_timeout() -> u64 {
345 10
346}
347
348fn default_analytics_write_timeout() -> u64 {
349 30
350}
351
352fn default_true() -> bool {
353 true
354}
355
356#[derive(Debug, Clone, Parser, Default)]
357pub struct CliOverrides {
358 #[arg(long)]
360 pub listen: Option<String>,
361 #[arg(long)]
363 pub fallback: Option<String>,
364 #[arg(long)]
366 pub tls_cert: Option<String>,
367 #[arg(long)]
369 pub tls_key: Option<String>,
370 #[arg(long, num_args = 1.., value_delimiter = ',')]
372 pub alpn: Option<Vec<String>>,
373 #[arg(long, num_args = 1.., value_delimiter = ',')]
375 pub password: Option<Vec<String>>,
376 #[arg(long)]
378 pub tcp_idle_timeout_secs: Option<u64>,
379 #[arg(long)]
381 pub udp_timeout_secs: Option<u64>,
382 #[arg(long)]
384 pub max_header_bytes: Option<usize>,
385 #[arg(long)]
387 pub max_udp_payload: Option<usize>,
388 #[arg(long)]
390 pub max_udp_buffer_bytes: Option<usize>,
391 #[arg(long)]
393 pub max_connections: Option<usize>,
394 #[arg(long)]
396 pub metrics_listen: Option<String>,
397 #[arg(long)]
399 pub log_level: Option<String>,
400 #[arg(long)]
402 pub rate_limit_max_per_ip: Option<u32>,
403 #[arg(long)]
405 pub rate_limit_window_secs: Option<u64>,
406 #[arg(long)]
408 pub tls_min_version: Option<String>,
409 #[arg(long)]
411 pub tls_max_version: Option<String>,
412 #[arg(long)]
414 pub tls_client_ca: Option<String>,
415 #[arg(long)]
417 pub relay_buffer_size: Option<usize>,
418 #[arg(long)]
420 pub tcp_send_buffer: Option<usize>,
421 #[arg(long)]
423 pub tcp_recv_buffer: Option<usize>,
424 #[arg(long)]
426 pub connection_backlog: Option<u32>,
427 #[arg(long)]
429 pub ws_enabled: Option<bool>,
430 #[arg(long)]
432 pub ws_mode: Option<String>,
433 #[arg(long)]
435 pub ws_path: Option<String>,
436 #[arg(long)]
438 pub ws_host: Option<String>,
439 #[arg(long)]
441 pub ws_listen: Option<String>,
442 #[arg(long)]
444 pub ws_max_frame_bytes: Option<usize>,
445}
446
447#[derive(Debug, thiserror::Error)]
448pub enum ConfigError {
449 #[error("io: {0}")]
450 Io(#[from] std::io::Error),
451 #[error("json: {0}")]
452 Json(#[from] serde_json::Error),
453 #[error("yaml: {0}")]
454 Yaml(#[from] serde_yaml::Error),
455 #[error("toml: {0}")]
456 Toml(#[from] toml::de::Error),
457 #[error("unsupported config format")]
458 UnsupportedFormat,
459 #[error("validation: {0}")]
460 Validation(String),
461}
462
463pub fn load_config(path: impl AsRef<Path>) -> Result<Config, ConfigError> {
464 let path = path.as_ref();
465 let data = fs::read_to_string(path)?;
466 match path.extension().and_then(|s| s.to_str()).unwrap_or("") {
467 "json" => Ok(serde_json::from_str(&data)?),
468 "yaml" | "yml" => Ok(serde_yaml::from_str(&data)?),
469 "toml" => Ok(toml::from_str(&data)?),
470 _ => Err(ConfigError::UnsupportedFormat),
471 }
472}
473
474pub fn apply_overrides(config: &mut Config, overrides: &CliOverrides) {
475 if let Some(v) = &overrides.listen {
476 config.server.listen = v.clone();
477 }
478 if let Some(v) = &overrides.fallback {
479 config.server.fallback = v.clone();
480 }
481 if let Some(v) = overrides.tcp_idle_timeout_secs {
482 config.server.tcp_idle_timeout_secs = v;
483 }
484 if let Some(v) = overrides.udp_timeout_secs {
485 config.server.udp_timeout_secs = v;
486 }
487 if let Some(v) = overrides.max_header_bytes {
488 config.server.max_header_bytes = v;
489 }
490 if let Some(v) = overrides.max_udp_payload {
491 config.server.max_udp_payload = v;
492 }
493 if let Some(v) = overrides.max_udp_buffer_bytes {
494 config.server.max_udp_buffer_bytes = v;
495 }
496 if let Some(v) = overrides.max_connections {
497 config.server.max_connections = if v == 0 { None } else { Some(v) };
498 }
499 if let Some(v) = &overrides.tls_cert {
500 config.tls.cert = v.clone();
501 }
502 if let Some(v) = &overrides.tls_key {
503 config.tls.key = v.clone();
504 }
505 if let Some(v) = &overrides.alpn {
506 config.tls.alpn = v.clone();
507 }
508 if let Some(v) = &overrides.password {
509 config.auth.passwords = v.clone();
510 }
511 if let Some(v) = &overrides.metrics_listen {
512 config.metrics.listen = Some(v.clone());
513 }
514 if let Some(v) = &overrides.log_level {
515 config.logging.level = Some(v.clone());
516 }
517 if let Some(max) = overrides.rate_limit_max_per_ip {
519 if max == 0 {
520 config.server.rate_limit = None;
521 } else {
522 let rl = config
523 .server
524 .rate_limit
525 .get_or_insert_with(|| RateLimitConfig {
526 max_connections_per_ip: default_rate_limit_max_connections(),
527 window_secs: default_rate_limit_window_secs(),
528 cleanup_interval_secs: default_rate_limit_cleanup_secs(),
529 });
530 rl.max_connections_per_ip = max;
531 }
532 }
533 if let Some(window) = overrides.rate_limit_window_secs
534 && let Some(ref mut rl) = config.server.rate_limit
535 {
536 rl.window_secs = window;
537 }
538 if let Some(v) = &overrides.tls_min_version {
540 config.tls.min_version = v.clone();
541 }
542 if let Some(v) = &overrides.tls_max_version {
543 config.tls.max_version = v.clone();
544 }
545 if let Some(v) = &overrides.tls_client_ca {
546 config.tls.client_ca = Some(v.clone());
547 }
548 if overrides.relay_buffer_size.is_some()
550 || overrides.tcp_send_buffer.is_some()
551 || overrides.tcp_recv_buffer.is_some()
552 || overrides.connection_backlog.is_some()
553 {
554 let rl = config
555 .server
556 .resource_limits
557 .get_or_insert_with(|| ResourceLimitsConfig {
558 relay_buffer_size: default_relay_buffer_size(),
559 tcp_send_buffer: 0,
560 tcp_recv_buffer: 0,
561 connection_backlog: default_connection_backlog(),
562 });
563 if let Some(v) = overrides.relay_buffer_size {
564 rl.relay_buffer_size = v;
565 }
566 if let Some(v) = overrides.tcp_send_buffer {
567 rl.tcp_send_buffer = v;
568 }
569 if let Some(v) = overrides.tcp_recv_buffer {
570 rl.tcp_recv_buffer = v;
571 }
572 if let Some(v) = overrides.connection_backlog {
573 rl.connection_backlog = v;
574 }
575 }
576 if let Some(v) = overrides.ws_enabled {
577 config.websocket.enabled = v;
578 }
579 if let Some(v) = &overrides.ws_mode {
580 config.websocket.mode = v.clone();
581 }
582 if let Some(v) = &overrides.ws_path {
583 config.websocket.path = v.clone();
584 }
585 if let Some(v) = &overrides.ws_host {
586 config.websocket.host = Some(v.clone());
587 }
588 if let Some(v) = &overrides.ws_listen {
589 config.websocket.listen = Some(v.clone());
590 }
591 if let Some(v) = overrides.ws_max_frame_bytes {
592 config.websocket.max_frame_bytes = v;
593 }
594}
595
596pub fn validate_config(config: &Config) -> Result<(), ConfigError> {
597 if config.server.listen.trim().is_empty() {
598 return Err(ConfigError::Validation("server.listen is empty".into()));
599 }
600 if config.server.fallback.trim().is_empty() {
601 return Err(ConfigError::Validation("server.fallback is empty".into()));
602 }
603 if config.tls.cert.trim().is_empty() {
604 return Err(ConfigError::Validation("tls.cert is empty".into()));
605 }
606 if config.tls.key.trim().is_empty() {
607 return Err(ConfigError::Validation("tls.key is empty".into()));
608 }
609 if config.auth.passwords.is_empty() {
610 return Err(ConfigError::Validation("auth.passwords is empty".into()));
611 }
612 if config.server.tcp_idle_timeout_secs == 0 {
613 return Err(ConfigError::Validation(
614 "server.tcp_idle_timeout_secs must be > 0".into(),
615 ));
616 }
617 if config.server.udp_timeout_secs == 0 {
618 return Err(ConfigError::Validation(
619 "server.udp_timeout_secs must be > 0".into(),
620 ));
621 }
622 if config.server.max_header_bytes < min_header_bytes() {
623 return Err(ConfigError::Validation(format!(
624 "server.max_header_bytes too small (min {})",
625 min_header_bytes()
626 )));
627 }
628 if config.server.max_udp_payload == 0 || config.server.max_udp_payload > u16::MAX as usize {
629 return Err(ConfigError::Validation(
630 "server.max_udp_payload must be 1..=65535".into(),
631 ));
632 }
633 if config.server.max_udp_buffer_bytes == 0 {
634 return Err(ConfigError::Validation(
635 "server.max_udp_buffer_bytes must be > 0".into(),
636 ));
637 }
638 if config.server.max_udp_buffer_bytes < config.server.max_udp_payload + 8 {
639 return Err(ConfigError::Validation(
640 "server.max_udp_buffer_bytes must be >= max_udp_payload + 8".into(),
641 ));
642 }
643 let valid_versions = ["tls12", "tls13"];
645 if !valid_versions.contains(&config.tls.min_version.as_str()) {
646 return Err(ConfigError::Validation(format!(
647 "tls.min_version must be one of: {:?}",
648 valid_versions
649 )));
650 }
651 if !valid_versions.contains(&config.tls.max_version.as_str()) {
652 return Err(ConfigError::Validation(format!(
653 "tls.max_version must be one of: {:?}",
654 valid_versions
655 )));
656 }
657 let min_ord = if config.tls.min_version == "tls13" {
659 1
660 } else {
661 0
662 };
663 let max_ord = if config.tls.max_version == "tls13" {
664 1
665 } else {
666 0
667 };
668 if min_ord > max_ord {
669 return Err(ConfigError::Validation(
670 "tls.min_version cannot be greater than tls.max_version".into(),
671 ));
672 }
673 if let Some(ref rl) = config.server.resource_limits {
675 if rl.relay_buffer_size < 1024 {
676 return Err(ConfigError::Validation(
677 "resource_limits.relay_buffer_size must be >= 1024".into(),
678 ));
679 }
680 if rl.relay_buffer_size > 1024 * 1024 {
681 return Err(ConfigError::Validation(
682 "resource_limits.relay_buffer_size must be <= 1MB".into(),
683 ));
684 }
685 if rl.connection_backlog == 0 {
686 return Err(ConfigError::Validation(
687 "resource_limits.connection_backlog must be > 0".into(),
688 ));
689 }
690 }
691 if let Some(ref pool) = config.server.fallback_pool {
692 if pool.max_idle == 0 {
693 return Err(ConfigError::Validation(
694 "fallback_pool.max_idle must be > 0".into(),
695 ));
696 }
697 if pool.max_age_secs == 0 {
698 return Err(ConfigError::Validation(
699 "fallback_pool.max_age_secs must be > 0".into(),
700 ));
701 }
702 if pool.fill_batch == 0 || pool.fill_batch > pool.max_idle {
703 return Err(ConfigError::Validation(
704 "fallback_pool.fill_batch must be 1..=max_idle".into(),
705 ));
706 }
707 }
708 if config.websocket.mode != "mixed" && config.websocket.mode != "split" {
709 return Err(ConfigError::Validation(
710 "websocket.mode must be 'mixed' or 'split'".into(),
711 ));
712 }
713 if config.websocket.path.is_empty() {
714 return Err(ConfigError::Validation("websocket.path is empty".into()));
715 }
716 if config.websocket.enabled
717 && config.websocket.mode == "split"
718 && config.websocket.listen.as_deref().unwrap_or("").is_empty()
719 {
720 return Err(ConfigError::Validation(
721 "websocket.listen is required in split mode".into(),
722 ));
723 }
724 Ok(())
725}
726
727macro_rules! default_fns {
733 ($($fn_name:ident => $const_name:ident : $ty:ty),* $(,)?) => {
735 $(
736 fn $fn_name() -> $ty {
737 defaults::$const_name
738 }
739 )*
740 };
741}
742
743macro_rules! default_string_fns {
745 ($($fn_name:ident => $const_name:ident),* $(,)?) => {
746 $(
747 fn $fn_name() -> String {
748 defaults::$const_name.to_string()
749 }
750 )*
751 };
752}
753
754default_fns! {
755 default_udp_timeout_secs => DEFAULT_UDP_TIMEOUT_SECS: u64,
756 default_tcp_timeout_secs => DEFAULT_TCP_TIMEOUT_SECS: u64,
757 default_max_udp_payload => DEFAULT_MAX_UDP_PAYLOAD: usize,
758 default_max_udp_buffer_bytes => DEFAULT_MAX_UDP_BUFFER_BYTES: usize,
759 default_max_header_bytes => DEFAULT_MAX_HEADER_BYTES: usize,
760 min_header_bytes => MIN_HEADER_BYTES: usize,
761 default_rate_limit_max_connections => DEFAULT_RATE_LIMIT_MAX_CONNECTIONS: u32,
762 default_rate_limit_window_secs => DEFAULT_RATE_LIMIT_WINDOW_SECS: u64,
763 default_rate_limit_cleanup_secs => DEFAULT_RATE_LIMIT_CLEANUP_SECS: u64,
764 default_pool_max_idle => DEFAULT_POOL_MAX_IDLE: usize,
765 default_pool_max_age_secs => DEFAULT_POOL_MAX_AGE_SECS: u64,
766 default_pool_fill_batch => DEFAULT_POOL_FILL_BATCH: usize,
767 default_pool_fill_delay_ms => DEFAULT_POOL_FILL_DELAY_MS: u64,
768 default_relay_buffer_size => DEFAULT_RELAY_BUFFER_SIZE: usize,
769 default_connection_backlog => DEFAULT_CONNECTION_BACKLOG: u32,
770 default_ws_enabled => DEFAULT_WS_ENABLED: bool,
771 default_ws_max_frame_bytes => DEFAULT_WS_MAX_FRAME_BYTES: usize,
772}
773
774default_string_fns! {
775 default_min_tls_version => DEFAULT_TLS_MIN_VERSION,
776 default_max_tls_version => DEFAULT_TLS_MAX_VERSION,
777 default_ws_mode => DEFAULT_WS_MODE,
778 default_ws_path => DEFAULT_WS_PATH,
779}