Skip to main content

trojan_config/
lib.rs

1//! Configuration loading and CLI definitions.
2
3use 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    /// Maximum concurrent connections (None = unlimited)
39    #[serde(default)]
40    pub max_connections: Option<usize>,
41    /// Per-IP rate limiting configuration
42    #[serde(default)]
43    pub rate_limit: Option<RateLimitConfig>,
44    /// Fallback connection pool configuration
45    #[serde(default)]
46    pub fallback_pool: Option<FallbackPoolConfig>,
47    /// Resource limits configuration
48    #[serde(default)]
49    pub resource_limits: Option<ResourceLimitsConfig>,
50    /// TCP socket options
51    #[serde(default)]
52    pub tcp: TcpConfig,
53}
54
55/// TCP socket configuration options.
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct TcpConfig {
58    /// Disable Nagle's algorithm (TCP_NODELAY) for lower latency.
59    #[serde(default = "default_tcp_no_delay")]
60    pub no_delay: bool,
61    /// TCP Keep-Alive interval in seconds (0 = disabled).
62    #[serde(default = "default_tcp_keepalive_secs")]
63    pub keepalive_secs: u64,
64    /// Enable SO_REUSEPORT for multi-process load balancing.
65    #[serde(default = "default_tcp_reuse_port")]
66    pub reuse_port: bool,
67    /// Enable TCP Fast Open (requires kernel support).
68    #[serde(default = "default_tcp_fast_open")]
69    pub fast_open: bool,
70    /// TCP Fast Open queue length (server-side).
71    #[serde(default = "default_tcp_fast_open_qlen")]
72    pub fast_open_qlen: u32,
73}
74
75impl Default for TcpConfig {
76    fn default() -> Self {
77        Self {
78            no_delay: default_tcp_no_delay(),
79            keepalive_secs: default_tcp_keepalive_secs(),
80            reuse_port: default_tcp_reuse_port(),
81            fast_open: default_tcp_fast_open(),
82            fast_open_qlen: default_tcp_fast_open_qlen(),
83        }
84    }
85}
86
87/// Configuration for fallback connection warm pool.
88///
89/// Warm pool semantics:
90/// - Pre-connects up to `max_idle` fresh connections in the background.
91/// - Connections are handed out once and NOT returned to the pool.
92/// - Pool is periodically refilled.
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct FallbackPoolConfig {
95    /// Maximum idle connections to keep in pool.
96    #[serde(default = "default_pool_max_idle")]
97    pub max_idle: usize,
98    /// Maximum age of pooled connections in seconds.
99    #[serde(default = "default_pool_max_age_secs")]
100    pub max_age_secs: u64,
101    /// Warm-fill batch size per cycle (1..=max_idle).
102    #[serde(default = "default_pool_fill_batch")]
103    pub fill_batch: usize,
104    /// Delay (ms) between each connection attempt within a batch.
105    #[serde(default = "default_pool_fill_delay_ms")]
106    pub fill_delay_ms: u64,
107}
108
109/// Configuration for resource limits.
110#[derive(Debug, Clone, Serialize, Deserialize)]
111pub struct ResourceLimitsConfig {
112    /// Buffer size for TCP relay (bytes).
113    #[serde(default = "default_relay_buffer_size")]
114    pub relay_buffer_size: usize,
115    /// TCP socket send buffer size (SO_SNDBUF). If 0, uses OS default.
116    #[serde(default)]
117    pub tcp_send_buffer: usize,
118    /// TCP socket receive buffer size (SO_RCVBUF). If 0, uses OS default.
119    #[serde(default)]
120    pub tcp_recv_buffer: usize,
121    /// TCP listener backlog (pending connections queue size).
122    #[serde(default = "default_connection_backlog")]
123    pub connection_backlog: u32,
124}
125
126/// Rate limiting configuration for per-IP connection throttling.
127#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct RateLimitConfig {
129    /// Maximum new connections per IP within the time window.
130    #[serde(default = "default_rate_limit_max_connections")]
131    pub max_connections_per_ip: u32,
132    /// Time window in seconds for rate limiting.
133    #[serde(default = "default_rate_limit_window_secs")]
134    pub window_secs: u64,
135    /// Cleanup interval in seconds for expired entries.
136    #[serde(default = "default_rate_limit_cleanup_secs")]
137    pub cleanup_interval_secs: u64,
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct TlsConfig {
142    /// Server certificate file path (PEM format).
143    pub cert: String,
144    /// Server private key file path (PEM format).
145    pub key: String,
146    /// ALPN protocols to advertise.
147    #[serde(default)]
148    pub alpn: Vec<String>,
149    /// Minimum TLS version (tls12, tls13). Default: tls12
150    #[serde(default = "default_min_tls_version")]
151    pub min_version: String,
152    /// Maximum TLS version (tls12, tls13). Default: tls13
153    #[serde(default = "default_max_tls_version")]
154    pub max_version: String,
155    /// Path to CA certificate for client authentication (mTLS).
156    /// If set, client certificates will be required and verified.
157    #[serde(default)]
158    pub client_ca: Option<String>,
159    /// Cipher suites to use. If empty, uses rustls defaults.
160    /// Example: ["TLS13_AES_256_GCM_SHA384", "TLS13_CHACHA20_POLY1305_SHA256"]
161    #[serde(default)]
162    pub cipher_suites: Vec<String>,
163}
164
165#[derive(Debug, Clone, Serialize, Deserialize, Default)]
166pub struct WebSocketConfig {
167    #[serde(default = "default_ws_enabled")]
168    pub enabled: bool,
169    #[serde(default = "default_ws_mode")]
170    pub mode: String,
171    #[serde(default = "default_ws_path")]
172    pub path: String,
173    #[serde(default)]
174    pub host: Option<String>,
175    #[serde(default)]
176    pub listen: Option<String>,
177    #[serde(default = "default_ws_max_frame_bytes")]
178    pub max_frame_bytes: usize,
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
182pub struct AuthConfig {
183    pub passwords: Vec<String>,
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize, Default)]
187pub struct MetricsConfig {
188    pub listen: Option<String>,
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize, Default)]
192pub struct LoggingConfig {
193    /// Log level (trace, debug, info, warn, error).
194    pub level: Option<String>,
195    /// Log format: json, pretty, or compact. Default: pretty.
196    pub format: Option<String>,
197    /// Output target: stdout or stderr. Default: stderr.
198    pub output: Option<String>,
199    /// Per-module log level filters (e.g., {"trojan_auth": "debug", "rustls": "warn"}).
200    #[serde(default)]
201    pub filters: std::collections::HashMap<String, String>,
202}
203
204// ============================================================================
205// Analytics Configuration
206// ============================================================================
207
208/// Analytics configuration for connection event collection.
209#[derive(Debug, Clone, Serialize, Deserialize, Default)]
210pub struct AnalyticsConfig {
211    /// Whether analytics is enabled (runtime switch).
212    #[serde(default)]
213    pub enabled: bool,
214
215    /// ClickHouse configuration.
216    #[serde(default)]
217    pub clickhouse: Option<ClickHouseConfig>,
218
219    /// Buffer configuration.
220    #[serde(default)]
221    pub buffer: AnalyticsBufferConfig,
222
223    /// Sampling configuration.
224    #[serde(default)]
225    pub sampling: AnalyticsSamplingConfig,
226
227    /// Privacy configuration.
228    #[serde(default)]
229    pub privacy: AnalyticsPrivacyConfig,
230
231    /// Server identifier for multi-instance deployments.
232    #[serde(default)]
233    pub server_id: Option<String>,
234}
235
236/// ClickHouse connection configuration.
237#[derive(Debug, Clone, Serialize, Deserialize)]
238pub struct ClickHouseConfig {
239    /// ClickHouse URL (e.g., "http://localhost:8123").
240    pub url: String,
241
242    /// Database name.
243    #[serde(default = "default_analytics_database")]
244    pub database: String,
245
246    /// Table name.
247    #[serde(default = "default_analytics_table")]
248    pub table: String,
249
250    /// Username (optional).
251    #[serde(default)]
252    pub username: Option<String>,
253
254    /// Password (optional).
255    #[serde(default)]
256    pub password: Option<String>,
257
258    /// Connection timeout in seconds.
259    #[serde(default = "default_analytics_connect_timeout")]
260    pub connect_timeout_secs: u64,
261
262    /// Write timeout in seconds.
263    #[serde(default = "default_analytics_write_timeout")]
264    pub write_timeout_secs: u64,
265}
266
267/// Buffer configuration for event batching.
268#[derive(Debug, Clone, Serialize, Deserialize)]
269pub struct AnalyticsBufferConfig {
270    /// Maximum number of events to buffer in memory.
271    #[serde(default = "default_analytics_buffer_size")]
272    pub size: usize,
273
274    /// Flush interval in seconds.
275    #[serde(default = "default_analytics_flush_interval")]
276    pub flush_interval_secs: u64,
277
278    /// Batch size for writes.
279    #[serde(default = "default_analytics_batch_size")]
280    pub batch_size: usize,
281
282    /// Fallback file path for failed writes.
283    #[serde(default)]
284    pub fallback_path: Option<String>,
285}
286
287impl Default for AnalyticsBufferConfig {
288    fn default() -> Self {
289        Self {
290            size: default_analytics_buffer_size(),
291            flush_interval_secs: default_analytics_flush_interval(),
292            batch_size: default_analytics_batch_size(),
293            fallback_path: None,
294        }
295    }
296}
297
298/// Sampling configuration for high-traffic scenarios.
299#[derive(Debug, Clone, Serialize, Deserialize)]
300pub struct AnalyticsSamplingConfig {
301    /// Sampling rate (0.0 - 1.0, where 1.0 = 100%).
302    #[serde(default = "default_analytics_sample_rate")]
303    pub rate: f64,
304
305    /// Users to always record (not affected by sampling).
306    #[serde(default)]
307    pub always_record_users: Vec<String>,
308}
309
310impl Default for AnalyticsSamplingConfig {
311    fn default() -> Self {
312        Self {
313            rate: default_analytics_sample_rate(),
314            always_record_users: Vec::new(),
315        }
316    }
317}
318
319/// Privacy configuration for data collection.
320#[derive(Debug, Clone, Serialize, Deserialize)]
321pub struct AnalyticsPrivacyConfig {
322    /// Whether to record client IP addresses.
323    #[serde(default = "default_true")]
324    pub record_peer_ip: bool,
325
326    /// Whether to record full user ID (false = prefix only).
327    #[serde(default)]
328    pub full_user_id: bool,
329
330    /// User ID prefix length when full_user_id is false.
331    #[serde(default = "default_analytics_user_id_prefix_len")]
332    pub user_id_prefix_len: usize,
333
334    /// Whether to record SNI.
335    #[serde(default = "default_true")]
336    pub record_sni: bool,
337}
338
339impl Default for AnalyticsPrivacyConfig {
340    fn default() -> Self {
341        Self {
342            record_peer_ip: true,
343            full_user_id: false,
344            user_id_prefix_len: default_analytics_user_id_prefix_len(),
345            record_sni: true,
346        }
347    }
348}
349
350// Analytics default value functions
351fn default_analytics_database() -> String {
352    "trojan".to_string()
353}
354
355fn default_analytics_table() -> String {
356    "connections".to_string()
357}
358
359fn default_analytics_buffer_size() -> usize {
360    10000
361}
362
363fn default_analytics_flush_interval() -> u64 {
364    5
365}
366
367fn default_analytics_batch_size() -> usize {
368    1000
369}
370
371fn default_analytics_sample_rate() -> f64 {
372    1.0
373}
374
375fn default_analytics_user_id_prefix_len() -> usize {
376    8
377}
378
379fn default_analytics_connect_timeout() -> u64 {
380    10
381}
382
383fn default_analytics_write_timeout() -> u64 {
384    30
385}
386
387fn default_true() -> bool {
388    true
389}
390
391#[derive(Debug, Clone, Parser, Default)]
392pub struct CliOverrides {
393    /// Override server listen address, e.g. 0.0.0.0:443
394    #[arg(long)]
395    pub listen: Option<String>,
396    /// Override fallback backend address, e.g. 127.0.0.1:80
397    #[arg(long)]
398    pub fallback: Option<String>,
399    /// Override TLS cert path
400    #[arg(long)]
401    pub tls_cert: Option<String>,
402    /// Override TLS key path
403    #[arg(long)]
404    pub tls_key: Option<String>,
405    /// Override ALPN list (repeatable or comma-separated)
406    #[arg(long, num_args = 1.., value_delimiter = ',')]
407    pub alpn: Option<Vec<String>>,
408    /// Override password list (repeatable or comma-separated)
409    #[arg(long, num_args = 1.., value_delimiter = ',')]
410    pub password: Option<Vec<String>>,
411    /// Override TCP idle timeout (seconds)
412    #[arg(long)]
413    pub tcp_idle_timeout_secs: Option<u64>,
414    /// Override UDP idle timeout (seconds)
415    #[arg(long)]
416    pub udp_timeout_secs: Option<u64>,
417    /// Override maximum Trojan header bytes
418    #[arg(long)]
419    pub max_header_bytes: Option<usize>,
420    /// Override maximum UDP payload size
421    #[arg(long)]
422    pub max_udp_payload: Option<usize>,
423    /// Override maximum UDP buffer bytes
424    #[arg(long)]
425    pub max_udp_buffer_bytes: Option<usize>,
426    /// Override maximum concurrent connections (0 = unlimited)
427    #[arg(long)]
428    pub max_connections: Option<usize>,
429    /// Override metrics listen address
430    #[arg(long)]
431    pub metrics_listen: Option<String>,
432    /// Override log level (trace/debug/info/warn/error)
433    #[arg(long)]
434    pub log_level: Option<String>,
435    /// Enable rate limiting with max connections per IP (0 = disabled)
436    #[arg(long)]
437    pub rate_limit_max_per_ip: Option<u32>,
438    /// Rate limit time window in seconds
439    #[arg(long)]
440    pub rate_limit_window_secs: Option<u64>,
441    /// Minimum TLS version (tls12, tls13)
442    #[arg(long)]
443    pub tls_min_version: Option<String>,
444    /// Maximum TLS version (tls12, tls13)
445    #[arg(long)]
446    pub tls_max_version: Option<String>,
447    /// Path to CA certificate for client authentication (mTLS)
448    #[arg(long)]
449    pub tls_client_ca: Option<String>,
450    /// Buffer size for TCP relay (bytes)
451    #[arg(long)]
452    pub relay_buffer_size: Option<usize>,
453    /// TCP socket send buffer size (SO_SNDBUF, 0 = OS default)
454    #[arg(long)]
455    pub tcp_send_buffer: Option<usize>,
456    /// TCP socket receive buffer size (SO_RCVBUF, 0 = OS default)
457    #[arg(long)]
458    pub tcp_recv_buffer: Option<usize>,
459    /// TCP listener backlog size
460    #[arg(long)]
461    pub connection_backlog: Option<u32>,
462    /// Enable WebSocket transport (default true)
463    #[arg(long)]
464    pub ws_enabled: Option<bool>,
465    /// WebSocket mode: mixed | split
466    #[arg(long)]
467    pub ws_mode: Option<String>,
468    /// WebSocket path
469    #[arg(long)]
470    pub ws_path: Option<String>,
471    /// WebSocket host (optional)
472    #[arg(long)]
473    pub ws_host: Option<String>,
474    /// WebSocket listen address for split mode
475    #[arg(long)]
476    pub ws_listen: Option<String>,
477    /// WebSocket max frame bytes
478    #[arg(long)]
479    pub ws_max_frame_bytes: Option<usize>,
480    /// Disable TCP_NODELAY (enable Nagle's algorithm)
481    #[arg(long)]
482    pub tcp_no_delay: Option<bool>,
483    /// TCP Keep-Alive interval in seconds (0 = disabled)
484    #[arg(long)]
485    pub tcp_keepalive_secs: Option<u64>,
486    /// Enable SO_REUSEPORT for multi-process load balancing
487    #[arg(long)]
488    pub tcp_reuse_port: Option<bool>,
489    /// Enable TCP Fast Open (requires kernel support)
490    #[arg(long)]
491    pub tcp_fast_open: Option<bool>,
492    /// TCP Fast Open queue length
493    #[arg(long)]
494    pub tcp_fast_open_qlen: Option<u32>,
495}
496
497#[derive(Debug, thiserror::Error)]
498pub enum ConfigError {
499    #[error("io: {0}")]
500    Io(#[from] std::io::Error),
501    #[error("json: {0}")]
502    Json(#[from] serde_json::Error),
503    #[error("yaml: {0}")]
504    Yaml(#[from] serde_yaml::Error),
505    #[error("toml: {0}")]
506    Toml(#[from] toml::de::Error),
507    #[error("unsupported config format")]
508    UnsupportedFormat,
509    #[error("validation: {0}")]
510    Validation(String),
511}
512
513pub fn load_config(path: impl AsRef<Path>) -> Result<Config, ConfigError> {
514    let path = path.as_ref();
515    let data = fs::read_to_string(path)?;
516    match path.extension().and_then(|s| s.to_str()).unwrap_or("") {
517        "json" => Ok(serde_json::from_str(&data)?),
518        "yaml" | "yml" => Ok(serde_yaml::from_str(&data)?),
519        "toml" => Ok(toml::from_str(&data)?),
520        _ => Err(ConfigError::UnsupportedFormat),
521    }
522}
523
524pub fn apply_overrides(config: &mut Config, overrides: &CliOverrides) {
525    if let Some(v) = &overrides.listen {
526        config.server.listen = v.clone();
527    }
528    if let Some(v) = &overrides.fallback {
529        config.server.fallback = v.clone();
530    }
531    if let Some(v) = overrides.tcp_idle_timeout_secs {
532        config.server.tcp_idle_timeout_secs = v;
533    }
534    if let Some(v) = overrides.udp_timeout_secs {
535        config.server.udp_timeout_secs = v;
536    }
537    if let Some(v) = overrides.max_header_bytes {
538        config.server.max_header_bytes = v;
539    }
540    if let Some(v) = overrides.max_udp_payload {
541        config.server.max_udp_payload = v;
542    }
543    if let Some(v) = overrides.max_udp_buffer_bytes {
544        config.server.max_udp_buffer_bytes = v;
545    }
546    if let Some(v) = overrides.max_connections {
547        config.server.max_connections = if v == 0 { None } else { Some(v) };
548    }
549    if let Some(v) = &overrides.tls_cert {
550        config.tls.cert = v.clone();
551    }
552    if let Some(v) = &overrides.tls_key {
553        config.tls.key = v.clone();
554    }
555    if let Some(v) = &overrides.alpn {
556        config.tls.alpn = v.clone();
557    }
558    if let Some(v) = &overrides.password {
559        config.auth.passwords = v.clone();
560    }
561    if let Some(v) = &overrides.metrics_listen {
562        config.metrics.listen = Some(v.clone());
563    }
564    if let Some(v) = &overrides.log_level {
565        config.logging.level = Some(v.clone());
566    }
567    // Rate limiting: 0 disables, > 0 enables with that limit
568    if let Some(max) = overrides.rate_limit_max_per_ip {
569        if max == 0 {
570            config.server.rate_limit = None;
571        } else {
572            let rl = config
573                .server
574                .rate_limit
575                .get_or_insert_with(|| RateLimitConfig {
576                    max_connections_per_ip: default_rate_limit_max_connections(),
577                    window_secs: default_rate_limit_window_secs(),
578                    cleanup_interval_secs: default_rate_limit_cleanup_secs(),
579                });
580            rl.max_connections_per_ip = max;
581        }
582    }
583    if let Some(window) = overrides.rate_limit_window_secs
584        && let Some(ref mut rl) = config.server.rate_limit
585    {
586        rl.window_secs = window;
587    }
588    // TLS version overrides
589    if let Some(v) = &overrides.tls_min_version {
590        config.tls.min_version = v.clone();
591    }
592    if let Some(v) = &overrides.tls_max_version {
593        config.tls.max_version = v.clone();
594    }
595    if let Some(v) = &overrides.tls_client_ca {
596        config.tls.client_ca = Some(v.clone());
597    }
598    // Resource limits
599    if overrides.relay_buffer_size.is_some()
600        || overrides.tcp_send_buffer.is_some()
601        || overrides.tcp_recv_buffer.is_some()
602        || overrides.connection_backlog.is_some()
603    {
604        let rl = config
605            .server
606            .resource_limits
607            .get_or_insert_with(|| ResourceLimitsConfig {
608                relay_buffer_size: default_relay_buffer_size(),
609                tcp_send_buffer: 0,
610                tcp_recv_buffer: 0,
611                connection_backlog: default_connection_backlog(),
612            });
613        if let Some(v) = overrides.relay_buffer_size {
614            rl.relay_buffer_size = v;
615        }
616        if let Some(v) = overrides.tcp_send_buffer {
617            rl.tcp_send_buffer = v;
618        }
619        if let Some(v) = overrides.tcp_recv_buffer {
620            rl.tcp_recv_buffer = v;
621        }
622        if let Some(v) = overrides.connection_backlog {
623            rl.connection_backlog = v;
624        }
625    }
626    if let Some(v) = overrides.ws_enabled {
627        config.websocket.enabled = v;
628    }
629    if let Some(v) = &overrides.ws_mode {
630        config.websocket.mode = v.clone();
631    }
632    if let Some(v) = &overrides.ws_path {
633        config.websocket.path = v.clone();
634    }
635    if let Some(v) = &overrides.ws_host {
636        config.websocket.host = Some(v.clone());
637    }
638    if let Some(v) = &overrides.ws_listen {
639        config.websocket.listen = Some(v.clone());
640    }
641    if let Some(v) = overrides.ws_max_frame_bytes {
642        config.websocket.max_frame_bytes = v;
643    }
644    // TCP socket options
645    if let Some(v) = overrides.tcp_no_delay {
646        config.server.tcp.no_delay = v;
647    }
648    if let Some(v) = overrides.tcp_keepalive_secs {
649        config.server.tcp.keepalive_secs = v;
650    }
651    if let Some(v) = overrides.tcp_reuse_port {
652        config.server.tcp.reuse_port = v;
653    }
654    if let Some(v) = overrides.tcp_fast_open {
655        config.server.tcp.fast_open = v;
656    }
657    if let Some(v) = overrides.tcp_fast_open_qlen {
658        config.server.tcp.fast_open_qlen = v;
659    }
660}
661
662pub fn validate_config(config: &Config) -> Result<(), ConfigError> {
663    if config.server.listen.trim().is_empty() {
664        return Err(ConfigError::Validation("server.listen is empty".into()));
665    }
666    if config.server.fallback.trim().is_empty() {
667        return Err(ConfigError::Validation("server.fallback is empty".into()));
668    }
669    if config.tls.cert.trim().is_empty() {
670        return Err(ConfigError::Validation("tls.cert is empty".into()));
671    }
672    if config.tls.key.trim().is_empty() {
673        return Err(ConfigError::Validation("tls.key is empty".into()));
674    }
675    if config.auth.passwords.is_empty() {
676        return Err(ConfigError::Validation("auth.passwords is empty".into()));
677    }
678    if config.server.tcp_idle_timeout_secs == 0 {
679        return Err(ConfigError::Validation(
680            "server.tcp_idle_timeout_secs must be > 0".into(),
681        ));
682    }
683    if config.server.udp_timeout_secs == 0 {
684        return Err(ConfigError::Validation(
685            "server.udp_timeout_secs must be > 0".into(),
686        ));
687    }
688    if config.server.max_header_bytes < min_header_bytes() {
689        return Err(ConfigError::Validation(format!(
690            "server.max_header_bytes too small (min {})",
691            min_header_bytes()
692        )));
693    }
694    if config.server.max_udp_payload == 0 || config.server.max_udp_payload > u16::MAX as usize {
695        return Err(ConfigError::Validation(
696            "server.max_udp_payload must be 1..=65535".into(),
697        ));
698    }
699    if config.server.max_udp_buffer_bytes == 0 {
700        return Err(ConfigError::Validation(
701            "server.max_udp_buffer_bytes must be > 0".into(),
702        ));
703    }
704    if config.server.max_udp_buffer_bytes < config.server.max_udp_payload + 8 {
705        return Err(ConfigError::Validation(
706            "server.max_udp_buffer_bytes must be >= max_udp_payload + 8".into(),
707        ));
708    }
709    // Validate TLS versions
710    let valid_versions = ["tls12", "tls13"];
711    if !valid_versions.contains(&config.tls.min_version.as_str()) {
712        return Err(ConfigError::Validation(format!(
713            "tls.min_version must be one of: {:?}",
714            valid_versions
715        )));
716    }
717    if !valid_versions.contains(&config.tls.max_version.as_str()) {
718        return Err(ConfigError::Validation(format!(
719            "tls.max_version must be one of: {:?}",
720            valid_versions
721        )));
722    }
723    // tls13 > tls12
724    let min_ord = if config.tls.min_version == "tls13" {
725        1
726    } else {
727        0
728    };
729    let max_ord = if config.tls.max_version == "tls13" {
730        1
731    } else {
732        0
733    };
734    if min_ord > max_ord {
735        return Err(ConfigError::Validation(
736            "tls.min_version cannot be greater than tls.max_version".into(),
737        ));
738    }
739    // Validate resource limits
740    if let Some(ref rl) = config.server.resource_limits {
741        if rl.relay_buffer_size < 1024 {
742            return Err(ConfigError::Validation(
743                "resource_limits.relay_buffer_size must be >= 1024".into(),
744            ));
745        }
746        if rl.relay_buffer_size > 1024 * 1024 {
747            return Err(ConfigError::Validation(
748                "resource_limits.relay_buffer_size must be <= 1MB".into(),
749            ));
750        }
751        if rl.connection_backlog == 0 {
752            return Err(ConfigError::Validation(
753                "resource_limits.connection_backlog must be > 0".into(),
754            ));
755        }
756    }
757    if let Some(ref pool) = config.server.fallback_pool {
758        if pool.max_idle == 0 {
759            return Err(ConfigError::Validation(
760                "fallback_pool.max_idle must be > 0".into(),
761            ));
762        }
763        if pool.max_age_secs == 0 {
764            return Err(ConfigError::Validation(
765                "fallback_pool.max_age_secs must be > 0".into(),
766            ));
767        }
768        if pool.fill_batch == 0 || pool.fill_batch > pool.max_idle {
769            return Err(ConfigError::Validation(
770                "fallback_pool.fill_batch must be 1..=max_idle".into(),
771            ));
772        }
773    }
774    if config.websocket.mode != "mixed" && config.websocket.mode != "split" {
775        return Err(ConfigError::Validation(
776            "websocket.mode must be 'mixed' or 'split'".into(),
777        ));
778    }
779    if config.websocket.path.is_empty() {
780        return Err(ConfigError::Validation("websocket.path is empty".into()));
781    }
782    if config.websocket.enabled
783        && config.websocket.mode == "split"
784        && config.websocket.listen.as_deref().unwrap_or("").is_empty()
785    {
786        return Err(ConfigError::Validation(
787            "websocket.listen is required in split mode".into(),
788        ));
789    }
790    Ok(())
791}
792
793// ============================================================================
794// Default Value Functions (for serde)
795// ============================================================================
796
797/// Generate default value functions that forward to trojan_core::defaults constants.
798macro_rules! default_fns {
799    // For Copy types (integers, bool, etc.)
800    ($($fn_name:ident => $const_name:ident : $ty:ty),* $(,)?) => {
801        $(
802            fn $fn_name() -> $ty {
803                defaults::$const_name
804            }
805        )*
806    };
807}
808
809/// Generate default value functions that return String from &str constants.
810macro_rules! default_string_fns {
811    ($($fn_name:ident => $const_name:ident),* $(,)?) => {
812        $(
813            fn $fn_name() -> String {
814                defaults::$const_name.to_string()
815            }
816        )*
817    };
818}
819
820default_fns! {
821    default_udp_timeout_secs      => DEFAULT_UDP_TIMEOUT_SECS: u64,
822    default_tcp_timeout_secs      => DEFAULT_TCP_TIMEOUT_SECS: u64,
823    default_max_udp_payload       => DEFAULT_MAX_UDP_PAYLOAD: usize,
824    default_max_udp_buffer_bytes  => DEFAULT_MAX_UDP_BUFFER_BYTES: usize,
825    default_max_header_bytes      => DEFAULT_MAX_HEADER_BYTES: usize,
826    min_header_bytes              => MIN_HEADER_BYTES: usize,
827    default_rate_limit_max_connections => DEFAULT_RATE_LIMIT_MAX_CONNECTIONS: u32,
828    default_rate_limit_window_secs     => DEFAULT_RATE_LIMIT_WINDOW_SECS: u64,
829    default_rate_limit_cleanup_secs    => DEFAULT_RATE_LIMIT_CLEANUP_SECS: u64,
830    default_pool_max_idle         => DEFAULT_POOL_MAX_IDLE: usize,
831    default_pool_max_age_secs     => DEFAULT_POOL_MAX_AGE_SECS: u64,
832    default_pool_fill_batch       => DEFAULT_POOL_FILL_BATCH: usize,
833    default_pool_fill_delay_ms    => DEFAULT_POOL_FILL_DELAY_MS: u64,
834    default_relay_buffer_size     => DEFAULT_RELAY_BUFFER_SIZE: usize,
835    default_connection_backlog    => DEFAULT_CONNECTION_BACKLOG: u32,
836    default_ws_enabled            => DEFAULT_WS_ENABLED: bool,
837    default_ws_max_frame_bytes    => DEFAULT_WS_MAX_FRAME_BYTES: usize,
838    // TCP socket options
839    default_tcp_no_delay          => DEFAULT_TCP_NO_DELAY: bool,
840    default_tcp_keepalive_secs    => DEFAULT_TCP_KEEPALIVE_SECS: u64,
841    default_tcp_reuse_port        => DEFAULT_TCP_REUSE_PORT: bool,
842    default_tcp_fast_open         => DEFAULT_TCP_FAST_OPEN: bool,
843    default_tcp_fast_open_qlen    => DEFAULT_TCP_FAST_OPEN_QLEN: u32,
844}
845
846default_string_fns! {
847    default_min_tls_version => DEFAULT_TLS_MIN_VERSION,
848    default_max_tls_version => DEFAULT_TLS_MAX_VERSION,
849    default_ws_mode         => DEFAULT_WS_MODE,
850    default_ws_path         => DEFAULT_WS_PATH,
851}