1use std::{
45 borrow::Cow,
46 convert::{From, Infallible},
47 default::Default,
48 env,
49 fmt::{self, Debug, Display, Formatter},
50 fs::OpenOptions,
51 io::Read,
52 net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
53 option::Option,
54 path::{Path, PathBuf},
55 str::FromStr,
56 string::ToString,
57 time::Duration,
58};
59
60use cfg_if::cfg_if;
61#[cfg(feature = "hickory-dns")]
62use hickory_resolver::config::{NameServerConfig, ResolverConfig};
63#[cfg(feature = "local-tun")]
64use ipnet::IpNet;
65#[cfg(feature = "local-fake-dns")]
66use ipnet::{Ipv4Net, Ipv6Net};
67use log::warn;
68use serde::{Deserialize, Serialize};
69#[cfg(any(feature = "local-tunnel", feature = "local-dns"))]
70use shadowsocks::relay::socks5::Address;
71use shadowsocks::{
72 config::{
73 ManagerAddr, Mode, ReplayAttackPolicy, ServerAddr, ServerConfig, ServerSource, ServerUser, ServerUserManager,
74 ServerWeight,
75 },
76 crypto::CipherKind,
77 plugin::PluginConfig,
78};
79
80use crate::acl::AccessControl;
81#[cfg(feature = "local-dns")]
82use crate::local::dns::NameServerAddr;
83#[cfg(feature = "local")]
84use crate::local::socks::config::Socks5AuthConfig;
85
86#[derive(Serialize, Deserialize, Debug)]
87#[serde(untagged)]
88enum SSDnsConfig {
89 Simple(String),
90 #[cfg(feature = "hickory-dns")]
91 HickoryDns(ResolverConfig),
92}
93
94#[derive(Serialize, Deserialize, Debug, Default)]
95struct SSSecurityConfig {
96 #[serde(skip_serializing_if = "Option::is_none")]
97 replay_attack: Option<SSSecurityReplayAttackConfig>,
98}
99
100#[derive(Serialize, Deserialize, Debug, Default)]
101struct SSSecurityReplayAttackConfig {
102 #[serde(skip_serializing_if = "Option::is_none")]
103 policy: Option<String>,
104}
105
106#[derive(Serialize, Deserialize, Debug, Default)]
107struct SSBalancerConfig {
108 #[serde(skip_serializing_if = "Option::is_none")]
109 max_server_rtt: Option<u64>,
110 #[serde(skip_serializing_if = "Option::is_none")]
111 check_interval: Option<u64>,
112 #[serde(skip_serializing_if = "Option::is_none")]
113 check_best_interval: Option<u64>,
114}
115
116#[derive(Serialize, Deserialize, Debug, Default)]
117struct SSConfig {
118 #[serde(skip_serializing_if = "Option::is_none")]
119 server: Option<String>,
120 #[serde(skip_serializing_if = "Option::is_none")]
121 server_port: Option<u16>,
122
123 #[serde(skip_serializing_if = "Option::is_none")]
124 local_address: Option<String>,
125 #[serde(skip_serializing_if = "Option::is_none")]
126 local_port: Option<u16>,
127
128 #[cfg(target_os = "macos")]
130 #[serde(skip_serializing_if = "Option::is_none")]
131 launchd_udp_socket_name: Option<String>,
132 #[cfg(target_os = "macos")]
133 #[serde(skip_serializing_if = "Option::is_none")]
134 launchd_tcp_socket_name: Option<String>,
135
136 #[serde(skip_serializing_if = "Option::is_none")]
137 protocol: Option<String>,
138
139 #[serde(skip_serializing_if = "Option::is_none")]
140 manager_address: Option<String>,
141 #[serde(skip_serializing_if = "Option::is_none")]
142 manager_port: Option<u16>,
143
144 #[serde(skip_serializing_if = "Option::is_none")]
145 password: Option<String>,
146 #[serde(skip_serializing_if = "Option::is_none")]
147 method: Option<String>,
148
149 #[serde(skip_serializing_if = "Option::is_none")]
150 plugin: Option<String>,
151 #[serde(skip_serializing_if = "Option::is_none")]
152 plugin_opts: Option<String>,
153 #[serde(skip_serializing_if = "Option::is_none")]
154 plugin_args: Option<Vec<String>>,
155 #[serde(skip_serializing_if = "Option::is_none")]
156 plugin_mode: Option<String>,
157
158 #[serde(skip_serializing_if = "Option::is_none")]
159 timeout: Option<u64>,
160
161 #[serde(skip_serializing_if = "Option::is_none")]
162 udp_timeout: Option<u64>,
163 #[serde(skip_serializing_if = "Option::is_none")]
164 udp_max_associations: Option<usize>,
165 #[serde(skip_serializing_if = "Option::is_none")]
166 udp_mtu: Option<usize>,
167
168 #[serde(skip_serializing_if = "Option::is_none", alias = "shadowsocks")]
169 servers: Option<Vec<SSServerExtConfig>>,
170
171 #[serde(skip_serializing_if = "Option::is_none")]
172 locals: Option<Vec<SSLocalExtConfig>>,
173
174 #[serde(skip_serializing_if = "Option::is_none")]
175 dns: Option<SSDnsConfig>,
176
177 #[serde(skip_serializing_if = "Option::is_none")]
178 dns_cache_size: Option<usize>,
179
180 #[serde(skip_serializing_if = "Option::is_none")]
181 mode: Option<String>,
182
183 #[serde(skip_serializing_if = "Option::is_none")]
184 no_delay: Option<bool>,
185
186 #[serde(skip_serializing_if = "Option::is_none")]
187 keep_alive: Option<u64>,
188
189 #[cfg(all(unix, not(target_os = "android")))]
190 #[serde(skip_serializing_if = "Option::is_none")]
191 nofile: Option<u64>,
192
193 #[serde(skip_serializing_if = "Option::is_none")]
194 ipv6_first: Option<bool>,
195 #[serde(skip_serializing_if = "Option::is_none")]
196 ipv6_only: Option<bool>,
197
198 #[serde(skip_serializing_if = "Option::is_none")]
199 fast_open: Option<bool>,
200
201 #[serde(skip_serializing_if = "Option::is_none")]
202 mptcp: Option<bool>,
203
204 #[serde(skip_serializing_if = "Option::is_none")]
205 #[cfg(any(target_os = "linux", target_os = "android"))]
206 outbound_fwmark: Option<u32>,
207
208 #[serde(skip_serializing_if = "Option::is_none")]
209 #[cfg(target_os = "freebsd")]
210 outbound_user_cookie: Option<u32>,
211
212 #[serde(skip_serializing_if = "Option::is_none")]
213 outbound_bind_addr: Option<String>,
214
215 #[serde(skip_serializing_if = "Option::is_none")]
216 outbound_bind_interface: Option<String>,
217
218 #[serde(skip_serializing_if = "Option::is_none")]
219 outbound_udp_allow_fragmentation: Option<bool>,
220
221 #[serde(skip_serializing_if = "Option::is_none")]
222 security: Option<SSSecurityConfig>,
223
224 #[serde(skip_serializing_if = "Option::is_none")]
225 balancer: Option<SSBalancerConfig>,
226
227 #[serde(skip_serializing_if = "Option::is_none")]
228 acl: Option<String>,
229
230 #[cfg(feature = "local-online-config")]
231 #[serde(skip_serializing_if = "Option::is_none")]
232 version: Option<u32>,
233
234 #[cfg(feature = "local-online-config")]
235 #[serde(skip_serializing_if = "Option::is_none")]
236 online_config: Option<SSOnlineConfig>,
237}
238
239#[derive(Serialize, Deserialize, Debug, Default)]
240struct SSLocalExtConfig {
241 #[serde(skip_serializing_if = "Option::is_none")]
242 local_address: Option<String>,
243 #[serde(skip_serializing_if = "Option::is_none")]
244 local_port: Option<u16>,
245
246 #[serde(skip_serializing_if = "Option::is_none")]
247 disabled: Option<bool>,
248
249 #[serde(skip_serializing_if = "Option::is_none")]
250 mode: Option<String>,
251
252 #[serde(skip_serializing_if = "Option::is_none")]
253 local_udp_address: Option<String>,
254 #[serde(skip_serializing_if = "Option::is_none")]
255 local_udp_port: Option<u16>,
256
257 #[serde(skip_serializing_if = "Option::is_none")]
258 protocol: Option<String>,
259
260 #[cfg(target_os = "macos")]
262 #[serde(skip_serializing_if = "Option::is_none")]
263 launchd_udp_socket_name: Option<String>,
264 #[cfg(target_os = "macos")]
265 #[serde(skip_serializing_if = "Option::is_none")]
266 launchd_tcp_socket_name: Option<String>,
267
268 #[cfg(feature = "local-redir")]
270 #[serde(skip_serializing_if = "Option::is_none")]
271 tcp_redir: Option<String>,
272 #[cfg(feature = "local-redir")]
274 #[serde(skip_serializing_if = "Option::is_none")]
275 udp_redir: Option<String>,
276
277 #[cfg(feature = "local-dns")]
281 #[serde(skip_serializing_if = "Option::is_none")]
282 local_dns_address: Option<String>,
283 #[cfg(feature = "local-dns")]
284 #[serde(skip_serializing_if = "Option::is_none")]
285 local_dns_port: Option<u16>,
286 #[cfg(feature = "local-dns")]
290 #[serde(skip_serializing_if = "Option::is_none")]
291 remote_dns_address: Option<String>,
292 #[cfg(feature = "local-dns")]
293 #[serde(skip_serializing_if = "Option::is_none")]
294 remote_dns_port: Option<u16>,
295 #[cfg(feature = "local-dns")]
296 #[serde(skip_serializing_if = "Option::is_none")]
297 client_cache_size: Option<usize>,
298
299 #[cfg(feature = "local-tunnel")]
301 #[serde(skip_serializing_if = "Option::is_none")]
302 forward_address: Option<String>,
303 #[cfg(feature = "local-tunnel")]
304 #[serde(skip_serializing_if = "Option::is_none")]
305 forward_port: Option<u16>,
306
307 #[cfg(feature = "local-tun")]
309 #[serde(skip_serializing_if = "Option::is_none")]
310 tun_interface_name: Option<String>,
311 #[cfg(feature = "local-tun")]
312 #[serde(skip_serializing_if = "Option::is_none")]
313 tun_interface_address: Option<String>,
314 #[cfg(feature = "local-tun")]
315 #[serde(skip_serializing_if = "Option::is_none")]
316 tun_interface_destination: Option<String>,
317 #[cfg(all(feature = "local-tun", unix))]
318 #[serde(skip_serializing_if = "Option::is_none")]
319 tun_device_fd_from_path: Option<String>,
320
321 #[cfg(feature = "local")]
323 #[serde(skip_serializing_if = "Option::is_none")]
324 socks5_auth_config_path: Option<String>,
325
326 #[cfg(feature = "local-fake-dns")]
328 #[serde(skip_serializing_if = "Option::is_none")]
329 pub fake_dns_record_expire_duration: Option<u64>,
330 #[cfg(feature = "local-fake-dns")]
331 #[serde(skip_serializing_if = "Option::is_none")]
332 pub fake_dns_ipv4_network: Option<String>,
333 #[cfg(feature = "local-fake-dns")]
334 #[serde(skip_serializing_if = "Option::is_none")]
335 pub fake_dns_ipv6_network: Option<String>,
336 #[cfg(feature = "local-fake-dns")]
337 #[serde(skip_serializing_if = "Option::is_none")]
338 pub fake_dns_database_path: Option<String>,
339
340 #[serde(skip_serializing_if = "Option::is_none")]
341 acl: Option<String>,
342}
343
344#[derive(Serialize, Deserialize, Debug)]
345struct SSServerUserConfig {
346 name: String,
347 password: String,
348}
349
350#[derive(Serialize, Deserialize, Debug)]
351struct SSServerExtConfig {
352 #[serde(alias = "address")]
356 server: String,
357 #[serde(alias = "port")]
358 server_port: u16,
359
360 #[serde(skip_serializing_if = "Option::is_none")]
361 password: Option<String>,
362 method: String,
363
364 #[serde(skip_serializing_if = "Option::is_none")]
365 users: Option<Vec<SSServerUserConfig>>,
366
367 #[serde(skip_serializing_if = "Option::is_none")]
368 disabled: Option<bool>,
369
370 #[serde(skip_serializing_if = "Option::is_none")]
371 plugin: Option<String>,
372 #[serde(skip_serializing_if = "Option::is_none")]
373 plugin_opts: Option<String>,
374 #[serde(skip_serializing_if = "Option::is_none")]
375 plugin_args: Option<Vec<String>>,
376 #[serde(skip_serializing_if = "Option::is_none")]
377 plugin_mode: Option<String>,
378
379 #[serde(skip_serializing_if = "Option::is_none")]
380 timeout: Option<u64>,
381
382 #[serde(skip_serializing_if = "Option::is_none", alias = "name")]
383 remarks: Option<String>,
384 #[serde(skip_serializing_if = "Option::is_none")]
385 id: Option<String>,
386
387 #[serde(skip_serializing_if = "Option::is_none")]
388 mode: Option<String>,
389
390 #[serde(skip_serializing_if = "Option::is_none")]
391 tcp_weight: Option<f32>,
392 #[serde(skip_serializing_if = "Option::is_none")]
393 udp_weight: Option<f32>,
394
395 #[serde(skip_serializing_if = "Option::is_none")]
396 acl: Option<String>,
397
398 #[serde(skip_serializing_if = "Option::is_none")]
399 #[cfg(any(target_os = "linux", target_os = "android"))]
400 outbound_fwmark: Option<u32>,
401
402 #[serde(skip_serializing_if = "Option::is_none")]
403 #[cfg(target_os = "freebsd")]
404 outbound_user_cookie: Option<u32>,
405
406 #[serde(skip_serializing_if = "Option::is_none")]
407 outbound_bind_addr: Option<IpAddr>,
408
409 #[serde(skip_serializing_if = "Option::is_none")]
410 outbound_bind_interface: Option<String>,
411
412 #[serde(skip_serializing_if = "Option::is_none")]
413 outbound_udp_allow_fragmentation: Option<bool>,
414}
415
416#[cfg(feature = "local-online-config")]
417#[derive(Serialize, Deserialize, Debug, Default)]
418struct SSOnlineConfig {
419 config_url: String,
420 #[serde(skip_serializing_if = "Option::is_none")]
421 update_interval: Option<u64>,
422 #[serde(skip_serializing_if = "Option::is_none")]
423 allowed_plugins: Option<Vec<String>>,
424}
425
426#[derive(Clone, Copy, Debug, Eq, PartialEq)]
428pub enum ConfigType {
429 Local,
431
432 Server,
434
435 Manager,
437
438 #[cfg(feature = "local-online-config")]
441 OnlineConfig,
442}
443
444impl ConfigType {
445 pub fn is_local(self) -> bool {
447 self == Self::Local
448 }
449
450 pub fn is_server(self) -> bool {
452 self == Self::Server
453 }
454
455 pub fn is_manager(self) -> bool {
457 self == Self::Manager
458 }
459
460 #[cfg(feature = "local-online-config")]
462 pub fn is_online_config(self) -> bool {
463 self == Self::OnlineConfig
464 }
465}
466
467cfg_if! {
468 if #[cfg(feature = "local-redir")] {
469 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
471 pub enum RedirType {
472 NotSupported,
474
475 #[cfg(any(target_os = "linux", target_os = "android"))]
481 Redirect,
482
483 #[cfg(any(target_os = "linux", target_os = "android"))]
487 TProxy,
488
489 #[cfg(any(
495 target_os = "freebsd",
496 target_os = "openbsd",
497 target_os = "macos",
498 target_os = "ios"
499 ))]
500 PacketFilter,
501
502 #[cfg(any(target_os = "freebsd", target_os = "macos", target_os = "ios"))]
508 IpFirewall,
509 }
510
511 impl RedirType {
512 cfg_if! {
513 if #[cfg(any(target_os = "linux", target_os = "android"))] {
514 pub const fn tcp_default() -> Self {
516 Self::Redirect
517 }
518
519 #[doc(hidden)]
521 pub fn tcp_available_types() -> &'static [&'static str] {
522 const AVAILABLE_TYPES: &[&str] = &[RedirType::Redirect.name(), RedirType::TProxy.name()];
523 AVAILABLE_TYPES
524 }
525
526 pub const fn udp_default() -> Self {
528 Self::TProxy
529 }
530
531 #[doc(hidden)]
533 pub fn udp_available_types() -> &'static [&'static str] {
534 const AVAILABLE_TYPES: &[&str] = &[RedirType::TProxy.name()];
535 AVAILABLE_TYPES
536 }
537 } else if #[cfg(any(target_os = "freebsd"))] {
538 pub fn tcp_default() -> RedirType {
540 RedirType::PacketFilter
541 }
542
543 #[doc(hidden)]
545 pub fn tcp_available_types() -> &'static [&'static str] {
546 const AVAILABLE_TYPES: &[&str] = &[RedirType::PacketFilter.name(), RedirType::IpFirewall.name()];
547 AVAILABLE_TYPES
548 }
549
550 pub fn udp_default() -> RedirType {
552 RedirType::PacketFilter
553 }
554
555 #[doc(hidden)]
557 pub const fn udp_available_types() -> &'static [&'static str] {
558 const AVAILABLE_TYPES: &[&str] = &[RedirType::PacketFilter.name(), RedirType::IpFirewall.name()];
559 AVAILABLE_TYPES
560 }
561 } else if #[cfg(target_os = "openbsd")] {
562 pub fn tcp_default() -> RedirType {
564 RedirType::PacketFilter
565 }
566
567 #[doc(hidden)]
569 pub fn tcp_available_types() -> &'static [&'static str] {
570 const AVAILABLE_TYPES: &[&str] = &[RedirType::PacketFilter.name()];
571 AVAILABLE_TYPES
572 }
573
574 pub fn udp_default() -> RedirType {
576 RedirType::PacketFilter
577 }
578
579 #[doc(hidden)]
581 pub const fn udp_available_types() -> &'static [&'static str] {
582 const AVAILABLE_TYPES: &[&str] = &[RedirType::PacketFilter.name()];
583 AVAILABLE_TYPES
584 }
585 } else if #[cfg(any(target_os = "macos", target_os = "ios"))] {
586 pub fn tcp_default() -> RedirType {
588 RedirType::PacketFilter
589 }
590
591 #[doc(hidden)]
593 pub const fn tcp_available_types() -> &'static [&'static str] {
594 const AVAILABLE_TYPES: &[&str] = &[RedirType::PacketFilter.name(), RedirType::IpFirewall.name()];
595 AVAILABLE_TYPES
596 }
597
598 pub fn udp_default() -> RedirType {
600 RedirType::PacketFilter
601 }
602
603 #[doc(hidden)]
605 pub const fn udp_available_types() -> &'static [&'static str] {
606 const AVAILABLE_TYPES: &[&str] = &[RedirType::PacketFilter.name()];
607 AVAILABLE_TYPES
608 }
609 } else {
610 pub fn tcp_default() -> RedirType {
612 RedirType::NotSupported
613 }
614
615 #[doc(hidden)]
617 pub const fn tcp_available_types() -> &'static [&'static str] {
618 const AVAILABLE_TYPES: &[&str] = &[];
619 AVAILABLE_TYPES
620 }
621
622 pub fn udp_default() -> RedirType {
624 RedirType::NotSupported
625 }
626
627 #[doc(hidden)]
629 pub const fn udp_available_types() -> &'static [&'static str] {
630 const AVAILABLE_TYPES: &[&str] = &[];
631 AVAILABLE_TYPES
632 }
633 }
634 }
635
636 pub fn is_supported(self) -> bool {
638 self != Self::NotSupported
639 }
640
641 pub const fn name(self) -> &'static str {
643 match self {
644 Self::NotSupported => "not_supported",
646
647 #[cfg(any(target_os = "linux", target_os = "android"))]
648 Self::Redirect => "redirect",
649
650 #[cfg(any(target_os = "linux", target_os = "android"))]
651 Self::TProxy => "tproxy",
652
653 #[cfg(any(
654 target_os = "freebsd",
655 target_os = "openbsd",
656 target_os = "macos",
657 target_os = "ios"
658 ))]
659 RedirType::PacketFilter => "pf",
660
661 #[cfg(any(target_os = "freebsd", target_os = "macos", target_os = "ios"))]
662 RedirType::IpFirewall => "ipfw",
663 }
664 }
665 }
666
667 impl Display for RedirType {
668 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
669 f.write_str(self.name())
670 }
671 }
672
673 #[derive(Debug)]
675 pub struct InvalidRedirType;
676
677 impl Display for InvalidRedirType {
678 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
679 f.write_str("invalid RedirType")
680 }
681 }
682
683 impl FromStr for RedirType {
684 type Err = InvalidRedirType;
685
686 fn from_str(s: &str) -> Result<Self, InvalidRedirType> {
687 match s {
688 #[cfg(any(target_os = "linux", target_os = "android"))]
689 "redirect" => Ok(Self::Redirect),
690
691 #[cfg(any(target_os = "linux", target_os = "android"))]
692 "tproxy" => Ok(Self::TProxy),
693
694 #[cfg(any(
695 target_os = "freebsd",
696 target_os = "openbsd",
697 target_os = "macos",
698 target_os = "ios",
699 ))]
700 "pf" => Ok(RedirType::PacketFilter),
701
702 #[cfg(any(
703 target_os = "freebsd",
704 target_os = "macos",
705 target_os = "ios",
706 ))]
707 "ipfw" => Ok(RedirType::IpFirewall),
708
709 _ => Err(InvalidRedirType),
710 }
711 }
712 }
713 }
714}
715
716#[derive(Clone, Debug)]
720pub enum ManagerServerHost {
721 Domain(String),
723 Ip(IpAddr),
725}
726
727impl Default for ManagerServerHost {
728 fn default() -> Self {
729 Self::Ip(Ipv4Addr::UNSPECIFIED.into())
730 }
731}
732
733impl FromStr for ManagerServerHost {
734 type Err = Infallible;
735
736 fn from_str(s: &str) -> Result<Self, Self::Err> {
737 match s.parse::<IpAddr>() {
738 Ok(s) => Ok(Self::Ip(s)),
739 Err(..) => Ok(Self::Domain(s.to_owned())),
740 }
741 }
742}
743
744#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
746pub enum ManagerServerMode {
747 #[default]
749 Builtin,
750
751 #[cfg(unix)]
753 Standalone,
754}
755
756#[derive(Debug, Clone, Copy)]
758pub struct ManagerServerModeError;
759
760impl Display for ManagerServerModeError {
761 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
762 f.write_str("invalid ManagerServerMode")
763 }
764}
765
766impl FromStr for ManagerServerMode {
767 type Err = ManagerServerModeError;
768
769 fn from_str(s: &str) -> Result<Self, Self::Err> {
770 match s {
771 "builtin" => Ok(Self::Builtin),
772 #[cfg(unix)]
773 "standalone" => Ok(Self::Standalone),
774 _ => Err(ManagerServerModeError),
775 }
776 }
777}
778
779impl Display for ManagerServerMode {
780 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
781 match *self {
782 Self::Builtin => f.write_str("builtin"),
783 #[cfg(unix)]
784 Self::Standalone => f.write_str("standalone"),
785 }
786 }
787}
788
789#[derive(Clone, Debug)]
791pub struct ManagerConfig {
792 pub addr: ManagerAddr,
794 pub method: Option<CipherKind>,
796 pub plugin: Option<PluginConfig>,
798 pub timeout: Option<Duration>,
800 pub server_host: ManagerServerHost,
804 pub mode: Mode,
806 pub server_mode: ManagerServerMode,
808 #[cfg(unix)]
810 pub server_program: String,
811 #[cfg(unix)]
813 pub server_working_directory: PathBuf,
814}
815
816impl ManagerConfig {
817 pub fn new(addr: ManagerAddr) -> Self {
819 Self {
820 addr,
821 method: None,
822 plugin: None,
823 timeout: None,
824 server_host: ManagerServerHost::default(),
825 mode: Mode::TcpOnly,
826 server_mode: ManagerServerMode::Builtin,
827 #[cfg(unix)]
828 server_program: "ssserver".to_owned(),
829 #[cfg(unix)]
830 server_working_directory: match std::env::current_dir() {
831 Ok(d) => d,
832 Err(..) => "/tmp/shadowsocks-manager".into(),
833 },
834 }
835 }
836}
837
838#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
840pub enum ProtocolType {
841 #[default]
842 Socks,
843 #[cfg(feature = "local-http")]
844 Http,
845 #[cfg(feature = "local-tunnel")]
846 Tunnel,
847 #[cfg(feature = "local-redir")]
848 Redir,
849 #[cfg(feature = "local-dns")]
850 Dns,
851 #[cfg(feature = "local-tun")]
852 Tun,
853 #[cfg(feature = "local-fake-dns")]
854 FakeDns,
855}
856
857impl ProtocolType {
858 pub fn as_str(&self) -> &'static str {
860 match *self {
861 Self::Socks => "socks",
862 #[cfg(feature = "local-http")]
863 Self::Http => "http",
864 #[cfg(feature = "local-tunnel")]
865 Self::Tunnel => "tunnel",
866 #[cfg(feature = "local-redir")]
867 Self::Redir => "redir",
868 #[cfg(feature = "local-dns")]
869 Self::Dns => "dns",
870 #[cfg(feature = "local-tun")]
871 Self::Tun => "tun",
872 #[cfg(feature = "local-fake-dns")]
873 Self::FakeDns => "fake-dns",
874 }
875 }
876
877 pub fn available_protocols() -> &'static [&'static str] {
879 &[
880 "socks",
881 #[cfg(feature = "local-http")]
882 "http",
883 #[cfg(feature = "local-tunnel")]
884 "tunnel",
885 #[cfg(feature = "local-redir")]
886 "redir",
887 #[cfg(feature = "local-dns")]
888 "dns",
889 #[cfg(feature = "local-tun")]
890 "tun",
891 #[cfg(feature = "local-fake-dns")]
892 "fake-dns",
893 ]
894 }
895}
896
897#[derive(Debug)]
899pub struct ProtocolTypeError;
900
901impl Display for ProtocolTypeError {
902 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
903 f.write_str("invalid ProtocolType")
904 }
905}
906
907impl FromStr for ProtocolType {
908 type Err = ProtocolTypeError;
909
910 fn from_str(s: &str) -> Result<Self, Self::Err> {
911 match s {
912 "socks" => Ok(Self::Socks),
913 #[cfg(feature = "local-http")]
914 "http" => Ok(Self::Http),
915 #[cfg(feature = "local-tunnel")]
916 "tunnel" => Ok(Self::Tunnel),
917 #[cfg(feature = "local-redir")]
918 "redir" => Ok(Self::Redir),
919 #[cfg(feature = "local-dns")]
920 "dns" => Ok(Self::Dns),
921 #[cfg(feature = "local-tun")]
922 "tun" => Ok(Self::Tun),
923 #[cfg(feature = "local-fake-dns")]
924 "fake-dns" => Ok(Self::FakeDns),
925 _ => Err(ProtocolTypeError),
926 }
927 }
928}
929
930#[derive(Clone, Debug)]
932pub struct LocalConfig {
933 pub addr: Option<ServerAddr>,
935
936 pub protocol: ProtocolType,
938
939 pub mode: Mode,
942
943 pub udp_addr: Option<ServerAddr>,
947
948 pub udp_associate_addr: Option<ServerAddr>,
950
951 #[cfg(feature = "local-tunnel")]
953 pub forward_addr: Option<Address>,
954
955 #[cfg(feature = "local-redir")]
957 pub tcp_redir: RedirType,
958 #[cfg(feature = "local-redir")]
960 pub udp_redir: RedirType,
961
962 #[cfg(feature = "local-dns")]
966 pub local_dns_addr: Option<NameServerAddr>,
967 #[cfg(feature = "local-dns")]
971 pub remote_dns_addr: Option<Address>,
972 #[cfg(feature = "local-dns")]
976 pub client_cache_size: Option<usize>,
977
978 #[cfg(feature = "local-tun")]
983 pub tun_interface_name: Option<String>,
984 #[cfg(feature = "local-tun")]
986 pub tun_interface_address: Option<IpNet>,
987 #[cfg(feature = "local-tun")]
989 pub tun_interface_destination: Option<IpNet>,
990 #[cfg(all(feature = "local-tun", unix))]
992 pub tun_device_fd: Option<std::os::unix::io::RawFd>,
993 #[cfg(all(feature = "local-tun", unix))]
995 pub tun_device_fd_from_path: Option<PathBuf>,
996
997 #[cfg(target_os = "macos")]
1014 pub launchd_tcp_socket_name: Option<String>,
1015 #[cfg(target_os = "macos")]
1032 pub launchd_udp_socket_name: Option<String>,
1033
1034 pub ipv6_only: bool,
1036
1037 #[cfg(feature = "local")]
1039 pub socks5_auth: Socks5AuthConfig,
1040
1041 #[cfg(feature = "local-fake-dns")]
1043 pub fake_dns_record_expire_duration: Option<Duration>,
1044 #[cfg(feature = "local-fake-dns")]
1046 pub fake_dns_ipv4_network: Option<Ipv4Net>,
1047 #[cfg(feature = "local-fake-dns")]
1049 pub fake_dns_ipv6_network: Option<Ipv6Net>,
1050 #[cfg(feature = "local-fake-dns")]
1052 pub fake_dns_database_path: Option<PathBuf>,
1053}
1054
1055impl LocalConfig {
1056 pub fn new(protocol: ProtocolType) -> Self {
1058 let mode = match protocol {
1061 #[cfg(feature = "local-dns")]
1062 ProtocolType::Dns => Mode::TcpAndUdp,
1063 _ => Mode::TcpOnly,
1064 };
1065
1066 Self {
1067 addr: None,
1068
1069 protocol,
1070
1071 mode,
1072 udp_addr: None,
1073 udp_associate_addr: None,
1074
1075 #[cfg(feature = "local-tunnel")]
1076 forward_addr: None,
1077
1078 #[cfg(feature = "local-redir")]
1079 tcp_redir: RedirType::tcp_default(),
1080 #[cfg(feature = "local-redir")]
1081 udp_redir: RedirType::udp_default(),
1082
1083 #[cfg(feature = "local-dns")]
1084 local_dns_addr: None,
1085 #[cfg(feature = "local-dns")]
1086 remote_dns_addr: None,
1087 #[cfg(feature = "local-dns")]
1088 client_cache_size: None,
1089
1090 #[cfg(feature = "local-tun")]
1091 tun_interface_name: None,
1092 #[cfg(feature = "local-tun")]
1093 tun_interface_address: None,
1094 #[cfg(feature = "local-tun")]
1095 tun_interface_destination: None,
1096 #[cfg(all(feature = "local-tun", unix))]
1097 tun_device_fd: None,
1098 #[cfg(all(feature = "local-tun", unix))]
1099 tun_device_fd_from_path: None,
1100
1101 #[cfg(target_os = "macos")]
1102 launchd_tcp_socket_name: None,
1103 #[cfg(target_os = "macos")]
1104 launchd_udp_socket_name: None,
1105
1106 ipv6_only: false,
1107
1108 #[cfg(feature = "local")]
1109 socks5_auth: Socks5AuthConfig::default(),
1110
1111 #[cfg(feature = "local-fake-dns")]
1112 fake_dns_record_expire_duration: None,
1113 #[cfg(feature = "local-fake-dns")]
1114 fake_dns_ipv4_network: None,
1115 #[cfg(feature = "local-fake-dns")]
1116 fake_dns_ipv6_network: None,
1117 #[cfg(feature = "local-fake-dns")]
1118 fake_dns_database_path: None,
1119 }
1120 }
1121
1122 pub fn new_with_addr(addr: ServerAddr, protocol: ProtocolType) -> Self {
1124 let mut config = Self::new(protocol);
1125 config.addr = Some(addr);
1126 config
1127 }
1128
1129 fn check_integrity(&self) -> Result<(), Error> {
1130 match self.protocol {
1131 #[cfg(feature = "local-tun")]
1132 ProtocolType::Tun => {}
1133
1134 _ => {
1135 if self.addr.is_none() {
1136 let err = Error::new(ErrorKind::MissingField, "missing `addr` in configuration", None);
1137 return Err(err);
1138 }
1139 }
1140 }
1141
1142 match self.protocol {
1143 #[cfg(feature = "local-dns")]
1144 ProtocolType::Dns => {
1145 if self.local_dns_addr.is_none() || self.remote_dns_addr.is_none() {
1146 let err = Error::new(
1147 ErrorKind::MissingField,
1148 "missing `local_dns_addr` or `remote_dns_addr` in configuration",
1149 None,
1150 );
1151 return Err(err);
1152 }
1153 }
1154 #[cfg(feature = "local-tunnel")]
1155 ProtocolType::Tunnel => {
1156 if self.forward_addr.is_none() {
1157 let err = Error::new(ErrorKind::MissingField, "missing `forward_addr` in configuration", None);
1158 return Err(err);
1159 }
1160 }
1161
1162 #[cfg(feature = "local-http")]
1163 ProtocolType::Http => {
1164 if !self.mode.enable_tcp() {
1165 let err = Error::new(ErrorKind::Invalid, "TCP mode have to be enabled for http", None);
1166 return Err(err);
1167 }
1168 }
1169
1170 _ => {}
1171 }
1172
1173 Ok(())
1174 }
1175
1176 pub fn is_basic(&self) -> bool {
1178 if self.protocol != ProtocolType::Socks || self.udp_addr.is_some() {
1179 return false;
1180 }
1181
1182 #[cfg(feature = "local-tunnel")]
1183 if self.forward_addr.is_some() {
1184 return false;
1185 }
1186
1187 #[cfg(feature = "local-redir")]
1188 if self.tcp_redir != RedirType::tcp_default() || self.udp_redir != RedirType::udp_default() {
1189 return false;
1190 }
1191
1192 #[cfg(feature = "local-dns")]
1193 if self.local_dns_addr.is_some() || self.remote_dns_addr.is_some() {
1194 return false;
1195 }
1196
1197 true
1198 }
1199}
1200
1201#[derive(Clone, Debug, Default)]
1202pub enum DnsConfig {
1203 #[default]
1204 System,
1205 #[cfg(feature = "hickory-dns")]
1206 HickoryDns(ResolverConfig),
1207 #[cfg(feature = "local-dns")]
1208 LocalDns(NameServerAddr),
1209}
1210
1211#[derive(Clone, Debug, Default)]
1213pub struct SecurityConfig {
1214 pub replay_attack: SecurityReplayAttackConfig,
1215}
1216
1217#[derive(Clone, Debug, Default)]
1218pub struct SecurityReplayAttackConfig {
1219 pub policy: ReplayAttackPolicy,
1220}
1221
1222#[derive(Clone, Debug, Default)]
1224pub struct BalancerConfig {
1225 pub max_server_rtt: Option<Duration>,
1227 pub check_interval: Option<Duration>,
1229 pub check_best_interval: Option<Duration>,
1231}
1232
1233#[cfg(feature = "local-flow-stat")]
1235#[derive(Debug, Clone)]
1236pub enum LocalFlowStatAddress {
1237 #[cfg(unix)]
1239 UnixStreamPath(PathBuf),
1240 TcpStreamAddr(SocketAddr),
1242}
1243
1244#[derive(Debug, Clone)]
1246pub struct ServerInstanceConfig {
1247 pub config: ServerConfig,
1249 pub acl: Option<AccessControl>,
1251 #[cfg(any(target_os = "linux", target_os = "android"))]
1253 pub outbound_fwmark: Option<u32>,
1254 #[cfg(target_os = "freebsd")]
1255 pub outbound_user_cookie: Option<u32>,
1256 pub outbound_bind_addr: Option<IpAddr>,
1257 pub outbound_bind_interface: Option<String>,
1258 pub outbound_udp_allow_fragmentation: Option<bool>,
1259}
1260
1261impl ServerInstanceConfig {
1262 pub fn with_server_config(config: ServerConfig) -> Self {
1264 Self {
1265 config,
1266 acl: None,
1267 #[cfg(any(target_os = "linux", target_os = "android"))]
1268 outbound_fwmark: None,
1269 #[cfg(target_os = "freebsd")]
1270 outbound_user_cookie: None,
1271 outbound_bind_addr: None,
1272 outbound_bind_interface: None,
1273 outbound_udp_allow_fragmentation: None,
1274 }
1275 }
1276}
1277
1278#[derive(Debug, Clone)]
1280pub struct LocalInstanceConfig {
1281 pub config: LocalConfig,
1283 pub acl: Option<AccessControl>,
1285}
1286
1287impl LocalInstanceConfig {
1288 pub fn with_local_config(config: LocalConfig) -> Self {
1290 Self { config, acl: None }
1291 }
1292}
1293
1294#[cfg(feature = "local-online-config")]
1297#[derive(Debug, Clone)]
1298pub struct OnlineConfig {
1299 pub config_url: String,
1301 pub update_interval: Option<Duration>,
1303 pub allowed_plugins: Option<Vec<String>>,
1305}
1306
1307#[derive(Clone, Debug)]
1309pub struct Config {
1310 pub server: Vec<ServerInstanceConfig>,
1312 pub local: Vec<LocalInstanceConfig>,
1314
1315 pub dns: DnsConfig,
1325 pub dns_cache_size: Option<usize>,
1326 pub ipv6_first: bool,
1330 pub ipv6_only: bool,
1332
1333 pub no_delay: bool,
1335 pub fast_open: bool,
1337 pub keep_alive: Option<Duration>,
1343 pub mptcp: bool,
1345
1346 #[cfg(all(unix, not(target_os = "android")))]
1348 pub nofile: Option<u64>,
1349
1350 #[cfg(any(target_os = "linux", target_os = "android"))]
1352 pub outbound_fwmark: Option<u32>,
1353 #[cfg(target_os = "freebsd")]
1355 pub outbound_user_cookie: Option<u32>,
1356 pub outbound_bind_interface: Option<String>,
1358 pub outbound_bind_addr: Option<IpAddr>,
1360 pub outbound_udp_allow_fragmentation: bool,
1362 #[cfg(target_os = "android")]
1364 pub outbound_vpn_protect_path: Option<PathBuf>,
1365
1366 pub inbound_send_buffer_size: Option<u32>,
1368 pub inbound_recv_buffer_size: Option<u32>,
1370 pub outbound_send_buffer_size: Option<u32>,
1372 pub outbound_recv_buffer_size: Option<u32>,
1374
1375 pub manager: Option<ManagerConfig>,
1377
1378 pub config_type: ConfigType,
1380
1381 pub udp_timeout: Option<Duration>,
1383 pub udp_max_associations: Option<usize>,
1385 pub udp_mtu: Option<usize>,
1389
1390 pub acl: Option<AccessControl>,
1394
1395 #[cfg(feature = "local-flow-stat")]
1397 pub local_stat_addr: Option<LocalFlowStatAddress>,
1398
1399 pub security: SecurityConfig,
1401
1402 pub balancer: BalancerConfig,
1404
1405 pub config_path: Option<PathBuf>,
1408
1409 #[cfg(feature = "local-online-config")]
1412 pub online_config: Option<OnlineConfig>,
1413}
1414
1415#[derive(Copy, Clone, Debug)]
1417pub enum ErrorKind {
1418 MissingField,
1420 Malformed,
1422 Invalid,
1424 JsonParsingError,
1426 IoError,
1428}
1429
1430pub struct Error {
1432 pub kind: ErrorKind,
1433 pub desc: &'static str,
1434 pub detail: Option<String>,
1435}
1436
1437impl Error {
1438 pub fn new(kind: ErrorKind, desc: &'static str, detail: Option<String>) -> Self {
1439 Self { kind, desc, detail }
1440 }
1441}
1442
1443impl std::error::Error for Error {
1444 fn description(&self) -> &str {
1445 self.desc
1446 }
1447}
1448
1449macro_rules! impl_from {
1450 ($error:ty, $kind:expr, $desc:expr) => {
1451 impl From<$error> for Error {
1452 fn from(err: $error) -> Self {
1453 Error::new($kind, $desc, Some(format!("{:?}", err)))
1454 }
1455 }
1456 };
1457}
1458
1459impl_from!(::std::io::Error, ErrorKind::IoError, "error while reading file");
1460impl_from!(json5::Error, ErrorKind::JsonParsingError, "json parse error");
1461impl_from!(serde_json::Error, ErrorKind::JsonParsingError, "json parse error");
1462
1463impl Debug for Error {
1464 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1465 match self.detail {
1466 None => write!(f, "{}", self.desc),
1467 Some(ref det) => write!(f, "{} {}", self.desc, det),
1468 }
1469 }
1470}
1471
1472impl Display for Error {
1473 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1474 match self.detail {
1475 None => f.write_str(self.desc),
1476 Some(ref d) => write!(f, "{}, {}", self.desc, d),
1477 }
1478 }
1479}
1480
1481impl Config {
1482 pub fn new(config_type: ConfigType) -> Self {
1484 Self {
1485 server: Vec::new(),
1486 local: Vec::new(),
1487
1488 dns: DnsConfig::default(),
1489 dns_cache_size: None,
1490 ipv6_first: false,
1491 ipv6_only: false,
1492
1493 no_delay: false,
1494 fast_open: false,
1495 keep_alive: None,
1496 mptcp: false,
1497
1498 #[cfg(all(unix, not(target_os = "android")))]
1499 nofile: None,
1500
1501 #[cfg(any(target_os = "linux", target_os = "android"))]
1502 outbound_fwmark: None,
1503 #[cfg(target_os = "freebsd")]
1504 outbound_user_cookie: None,
1505 outbound_bind_interface: None,
1506 outbound_bind_addr: None,
1507 outbound_udp_allow_fragmentation: false,
1508 #[cfg(target_os = "android")]
1509 outbound_vpn_protect_path: None,
1510
1511 inbound_send_buffer_size: None,
1512 inbound_recv_buffer_size: None,
1513 outbound_send_buffer_size: None,
1514 outbound_recv_buffer_size: None,
1515
1516 manager: None,
1517
1518 config_type,
1519
1520 udp_timeout: None,
1521 udp_max_associations: None,
1522 udp_mtu: None,
1523
1524 acl: None,
1525
1526 #[cfg(feature = "local-flow-stat")]
1527 local_stat_addr: None,
1528
1529 security: SecurityConfig::default(),
1530
1531 balancer: BalancerConfig::default(),
1532
1533 config_path: None,
1534
1535 #[cfg(feature = "local-online-config")]
1536 online_config: None,
1537 }
1538 }
1539
1540 fn load_from_ssconfig(config: SSConfig, config_type: ConfigType) -> Result<Self, Error> {
1541 let mut nconfig = Self::new(config_type);
1542
1543 #[inline]
1549 fn get_local_address(local_address: Option<String>, local_port: u16, ipv6_first: bool) -> ServerAddr {
1550 match local_address {
1551 Some(addr) => {
1552 match addr.parse::<IpAddr>() {
1553 Ok(ip) => ServerAddr::from(SocketAddr::new(ip, local_port)),
1554 Err(..) => {
1555 ServerAddr::from((addr, local_port))
1557 }
1558 }
1559 }
1560 None => {
1561 let ip = if ipv6_first {
1564 Ipv6Addr::LOCALHOST.into()
1565 } else {
1566 Ipv4Addr::LOCALHOST.into()
1567 };
1568
1569 ServerAddr::from(SocketAddr::new(ip, local_port))
1570 }
1571 }
1572 }
1573
1574 let mut global_mode = Mode::TcpOnly;
1576 if let Some(m) = config.mode {
1577 match m.parse::<Mode>() {
1578 Ok(xm) => global_mode = xm,
1579 Err(..) => {
1580 let e = Error::new(
1581 ErrorKind::Malformed,
1582 "malformed `mode`, must be one of `tcp_only`, `udp_only` and `tcp_and_udp`",
1583 None,
1584 );
1585 return Err(e);
1586 }
1587 }
1588 }
1589
1590 match config_type {
1591 ConfigType::Local => {
1592 if config.local_address.is_some() && config.local_port.unwrap_or(0) == 0 {
1594 let err = Error::new(ErrorKind::MissingField, "missing `local_port`", None);
1595 return Err(err);
1596 }
1597
1598 if let Some(local_port) = config.local_port {
1599 assert_ne!(local_port, 0);
1601
1602 let local_addr =
1603 get_local_address(config.local_address, local_port, config.ipv6_first.unwrap_or(false));
1604
1605 let mut local_config = LocalConfig::new(ProtocolType::Socks);
1607 local_config.addr = Some(local_addr);
1608 local_config.mode = global_mode;
1609 local_config.protocol = match config.protocol {
1610 None => ProtocolType::Socks,
1611 Some(p) => match p.parse::<ProtocolType>() {
1612 Ok(p) => p,
1613 Err(..) => {
1614 let err = Error::new(
1615 ErrorKind::Malformed,
1616 "`protocol` invalid",
1617 Some(format!("unrecognized protocol {p}")),
1618 );
1619 return Err(err);
1620 }
1621 },
1622 };
1623 #[cfg(target_os = "macos")]
1624 {
1625 local_config
1626 .launchd_tcp_socket_name
1627 .clone_from(&config.launchd_tcp_socket_name);
1628 local_config
1629 .launchd_udp_socket_name
1630 .clone_from(&config.launchd_udp_socket_name);
1631 }
1632
1633 let local_instance = LocalInstanceConfig {
1634 config: local_config,
1635 acl: None,
1636 };
1637
1638 nconfig.local.push(local_instance);
1639 }
1640
1641 if let Some(locals) = config.locals {
1644 for local in locals {
1645 if local.disabled.unwrap_or(false) {
1646 continue;
1647 }
1648
1649 let protocol = match local.protocol {
1650 None => ProtocolType::Socks,
1651 Some(p) => match p.parse::<ProtocolType>() {
1652 Ok(p) => p,
1653 Err(..) => {
1654 let err = Error::new(
1655 ErrorKind::Malformed,
1656 "`protocol` invalid",
1657 Some(format!("unrecognized protocol {p}")),
1658 );
1659 return Err(err);
1660 }
1661 },
1662 };
1663
1664 let mut local_config = LocalConfig::new(protocol);
1665
1666 if let Some(local_port) = local.local_port {
1667 if local_port == 0 {
1668 let err = Error::new(ErrorKind::Malformed, "`local_port` cannot be 0", None);
1669 return Err(err);
1670 }
1671
1672 let local_addr =
1673 get_local_address(local.local_address, local_port, config.ipv6_first.unwrap_or(false));
1674 local_config.addr = Some(local_addr);
1675 } else if local.local_address.is_some() {
1676 let err = Error::new(ErrorKind::Malformed, "missing `local_port`", None);
1677 return Err(err);
1678 }
1679
1680 if let Some(local_udp_port) = local.local_udp_port {
1681 if local_udp_port == 0 {
1682 let err = Error::new(ErrorKind::Malformed, "`local_udp_port` cannot be 0", None);
1683 return Err(err);
1684 }
1685
1686 let local_udp_addr = get_local_address(
1687 local.local_udp_address,
1688 local_udp_port,
1689 config.ipv6_first.unwrap_or(false),
1690 );
1691
1692 local_config.udp_addr = Some(local_udp_addr);
1693 }
1694
1695 #[cfg(target_os = "macos")]
1696 {
1697 local_config.launchd_tcp_socket_name = local.launchd_tcp_socket_name;
1698 local_config.launchd_udp_socket_name = local.launchd_udp_socket_name;
1699 }
1700
1701 match local.mode {
1702 Some(mode) => match mode.parse::<Mode>() {
1703 Ok(mode) => local_config.mode = mode,
1704 Err(..) => {
1705 let err = Error::new(ErrorKind::Malformed, "invalid `mode`", None);
1706 return Err(err);
1707 }
1708 },
1709 None => {
1710 let mode = match protocol {
1713 #[cfg(feature = "local-dns")]
1714 ProtocolType::Dns => Mode::TcpAndUdp,
1715 _ => global_mode,
1716 };
1717
1718 local_config.mode = mode;
1719 }
1720 }
1721
1722 #[cfg(feature = "local-tunnel")]
1723 if let Some(forward_address) = local.forward_address {
1724 let forward_port = match local.forward_port {
1725 None | Some(0) => {
1726 let err =
1727 Error::new(ErrorKind::Malformed, "`forward_port` cannot be missing or 0", None);
1728 return Err(err);
1729 }
1730 Some(p) => p,
1731 };
1732
1733 local_config.forward_addr = Some(match forward_address.parse::<IpAddr>() {
1734 Ok(ip) => Address::from(SocketAddr::new(ip, forward_port)),
1735 Err(..) => Address::from((forward_address, forward_port)),
1736 });
1737 }
1738
1739 #[cfg(feature = "local-redir")]
1740 if let Some(tcp_redir) = local.tcp_redir {
1741 match tcp_redir.parse::<RedirType>() {
1742 Ok(r) => local_config.tcp_redir = r,
1743 Err(..) => {
1744 let err = Error::new(ErrorKind::Malformed, "`tcp_redir` invalid", None);
1745 return Err(err);
1746 }
1747 }
1748 }
1749
1750 #[cfg(feature = "local-redir")]
1751 if let Some(udp_redir) = local.udp_redir {
1752 match udp_redir.parse::<RedirType>() {
1753 Ok(r) => local_config.udp_redir = r,
1754 Err(..) => {
1755 let err = Error::new(ErrorKind::Malformed, "`udp_redir` invalid", None);
1756 return Err(err);
1757 }
1758 }
1759 }
1760
1761 #[cfg(feature = "local-dns")]
1762 if let Some(local_dns_address) = local.local_dns_address {
1763 match local_dns_address.parse::<IpAddr>() {
1764 Ok(ip) => {
1765 local_config.local_dns_addr = Some(NameServerAddr::SocketAddr(SocketAddr::new(
1766 ip,
1767 local.local_dns_port.unwrap_or(53),
1768 )));
1769 }
1770 #[cfg(unix)]
1771 Err(..) => {
1772 local_config.local_dns_addr =
1773 Some(NameServerAddr::UnixSocketAddr(PathBuf::from(local_dns_address)));
1774 }
1775 #[cfg(not(unix))]
1776 Err(..) => {
1777 let err = Error::new(ErrorKind::Malformed, "`local_dns_address` invalid", None);
1778 return Err(err);
1779 }
1780 }
1781 }
1782
1783 #[cfg(feature = "local-dns")]
1784 if let Some(client_cache_size) = local.client_cache_size {
1785 local_config.client_cache_size = Some(client_cache_size);
1786 }
1787
1788 #[cfg(feature = "local-dns")]
1789 if let Some(remote_dns_address) = local.remote_dns_address {
1790 let remote_dns_port = local.remote_dns_port.unwrap_or(53);
1791 local_config.remote_dns_addr = Some(match remote_dns_address.parse::<IpAddr>() {
1792 Ok(ip) => Address::from(SocketAddr::new(ip, remote_dns_port)),
1793 Err(..) => Address::from((remote_dns_address, remote_dns_port)),
1794 });
1795 }
1796
1797 #[cfg(feature = "local-tun")]
1798 if let Some(tun_interface_address) = local.tun_interface_address {
1799 match tun_interface_address.parse::<IpNet>() {
1800 Ok(addr) => local_config.tun_interface_address = Some(addr),
1801 Err(..) => {
1802 let err = Error::new(ErrorKind::Malformed, "`tun_interface_address` invalid", None);
1803 return Err(err);
1804 }
1805 }
1806 }
1807
1808 #[cfg(feature = "local-tun")]
1809 if let Some(tun_interface_destination) = local.tun_interface_destination {
1810 match tun_interface_destination.parse::<IpNet>() {
1811 Ok(addr) => local_config.tun_interface_destination = Some(addr),
1812 Err(..) => {
1813 let err =
1814 Error::new(ErrorKind::Malformed, "`tun_interface_destination` invalid", None);
1815 return Err(err);
1816 }
1817 }
1818 }
1819
1820 #[cfg(feature = "local-tun")]
1821 if let Some(tun_interface_name) = local.tun_interface_name {
1822 local_config.tun_interface_name = Some(tun_interface_name);
1823 }
1824
1825 #[cfg(all(feature = "local-tun", unix))]
1826 if let Some(tun_device_fd_from_path) = local.tun_device_fd_from_path {
1827 local_config.tun_device_fd_from_path = Some(From::from(tun_device_fd_from_path));
1828 }
1829
1830 #[cfg(feature = "local")]
1831 if let Some(socks5_auth_config_path) = local.socks5_auth_config_path {
1832 local_config.socks5_auth = Socks5AuthConfig::load_from_file(&socks5_auth_config_path)?;
1833 }
1834
1835 #[cfg(feature = "local-fake-dns")]
1836 {
1837 if let Some(d) = local.fake_dns_record_expire_duration {
1838 local_config.fake_dns_record_expire_duration = Some(Duration::from_secs(d));
1839 }
1840 if let Some(n) = local.fake_dns_ipv4_network {
1841 match n.parse::<Ipv4Net>() {
1842 Ok(n) => local_config.fake_dns_ipv4_network = Some(n),
1843 Err(..) => {
1844 let err =
1845 Error::new(ErrorKind::Malformed, "invalid `fake_dns_ipv4_network`", None);
1846 return Err(err);
1847 }
1848 }
1849 }
1850 if let Some(n) = local.fake_dns_ipv6_network {
1851 match n.parse::<Ipv6Net>() {
1852 Ok(n) => local_config.fake_dns_ipv6_network = Some(n),
1853 Err(..) => {
1854 let err =
1855 Error::new(ErrorKind::Malformed, "invalid `fake_dns_ipv6_network`", None);
1856 return Err(err);
1857 }
1858 }
1859 }
1860 if let Some(p) = local.fake_dns_database_path {
1861 local_config.fake_dns_database_path = Some(p.into());
1862 }
1863 }
1864
1865 let mut local_instance = LocalInstanceConfig {
1866 config: local_config,
1867 acl: None,
1868 };
1869
1870 if let Some(acl_path) = local.acl {
1871 let acl = match AccessControl::load_from_file(&acl_path) {
1872 Ok(acl) => acl,
1873 Err(err) => {
1874 let err = Error::new(
1875 ErrorKind::Invalid,
1876 "acl loading failed",
1877 Some(format!("file {acl_path}, error: {err}")),
1878 );
1879 return Err(err);
1880 }
1881 };
1882 local_instance.acl = Some(acl);
1883 }
1884
1885 nconfig.local.push(local_instance);
1886 }
1887 }
1888 }
1889 ConfigType::Server | ConfigType::Manager => {
1890 }
1895 #[cfg(feature = "local-online-config")]
1896 ConfigType::OnlineConfig => {
1897 match config.version {
1900 Some(1) => {}
1901 Some(v) => {
1902 let err = Error::new(
1903 ErrorKind::Invalid,
1904 "invalid online config version",
1905 Some(format!("version: {v}")),
1906 );
1907 return Err(err);
1908 }
1909 None => {
1910 warn!(
1911 "OnlineConfig \"version\" is missing in the configuration, assuming it is a compatible version for this project"
1912 );
1913 }
1914 }
1915 }
1916 }
1917
1918 let server_source = match config_type {
1919 ConfigType::Local | ConfigType::Server | ConfigType::Manager => ServerSource::Configuration,
1920 #[cfg(feature = "local-online-config")]
1921 ConfigType::OnlineConfig => ServerSource::OnlineConfig,
1922 };
1923
1924 match (config.server, config.server_port, config.password, &config.method) {
1927 (Some(address), Some(port), pwd_opt, Some(m)) => {
1928 let addr = match address.parse::<Ipv4Addr>() {
1929 Ok(v4) => ServerAddr::SocketAddr(SocketAddr::V4(SocketAddrV4::new(v4, port))),
1930 Err(..) => match address.parse::<Ipv6Addr>() {
1931 Ok(v6) => ServerAddr::SocketAddr(SocketAddr::V6(SocketAddrV6::new(v6, port, 0, 0))),
1932 Err(..) => ServerAddr::DomainName(address, port),
1933 },
1934 };
1935
1936 let method = match m.parse::<CipherKind>() {
1937 Ok(m) => m,
1938 Err(..) => {
1939 let err = Error::new(
1940 ErrorKind::Invalid,
1941 "unsupported method",
1942 Some(format!("`{m}` is not a supported method")),
1943 );
1944 return Err(err);
1945 }
1946 };
1947
1948 let password = match pwd_opt {
1950 Some(ref pwd) => read_variable_field_value(pwd),
1951 None => {
1952 if method.is_none() {
1953 String::new().into()
1954 } else {
1955 let err = Error::new(
1956 ErrorKind::MissingField,
1957 "`password` is required",
1958 Some(format!("`password` is required for method {method}")),
1959 );
1960 return Err(err);
1961 }
1962 }
1963 };
1964
1965 let mut nsvr = match ServerConfig::new(addr, password, method) {
1966 Ok(svr) => svr,
1967 Err(serr) => {
1968 let err = Error::new(
1969 ErrorKind::Malformed,
1970 "server config create failed",
1971 Some(format!("{}", serr)),
1972 );
1973 return Err(err);
1974 }
1975 };
1976 nsvr.set_source(server_source);
1977 nsvr.set_mode(global_mode);
1978
1979 if let Some(ref p) = config.plugin {
1980 if !p.is_empty() {
1983 let plugin = PluginConfig {
1984 plugin: p.clone(),
1985 plugin_opts: config.plugin_opts.clone(),
1986 plugin_args: config.plugin_args.clone().unwrap_or_default(),
1987 plugin_mode: match config.plugin_mode {
1988 None => Mode::TcpOnly,
1989 Some(ref mode) => match mode.parse::<Mode>() {
1990 Ok(m) => m,
1991 Err(..) => {
1992 let e = Error::new(
1993 ErrorKind::Malformed,
1994 "malformed `plugin_mode`, must be one of `tcp_only`, `udp_only` and `tcp_and_udp`",
1995 None,
1996 );
1997 return Err(e);
1998 }
1999 },
2000 },
2001 };
2002 nsvr.set_plugin(plugin);
2003 }
2004 }
2005
2006 if let Some(timeout) = config.timeout.map(Duration::from_secs) {
2007 nsvr.set_timeout(timeout);
2008 }
2009
2010 nconfig.server.push(ServerInstanceConfig::with_server_config(nsvr));
2011 }
2012 (None, None, None, Some(_)) if config_type.is_manager() => {
2013 }
2015 (None, None, None, None) => (),
2016 _ => {
2017 let err = Error::new(
2018 ErrorKind::Malformed,
2019 "`server`, `server_port`, `method`, `password` must be provided together",
2020 None,
2021 );
2022 return Err(err);
2023 }
2024 }
2025
2026 if let Some(servers) = config.servers {
2028 for svr in servers {
2029 if svr.disabled.unwrap_or(false) {
2031 continue;
2032 }
2033
2034 let address = svr.server;
2035 let port = svr.server_port;
2036
2037 let addr = match address.parse::<Ipv4Addr>() {
2038 Ok(v4) => ServerAddr::SocketAddr(SocketAddr::V4(SocketAddrV4::new(v4, port))),
2039 Err(..) => match address.parse::<Ipv6Addr>() {
2040 Ok(v6) => ServerAddr::SocketAddr(SocketAddr::V6(SocketAddrV6::new(v6, port, 0, 0))),
2041 Err(..) => ServerAddr::DomainName(address, port),
2042 },
2043 };
2044
2045 let method = match svr.method.parse::<CipherKind>() {
2046 Ok(m) => m,
2047 Err(..) => {
2048 let err = Error::new(
2049 ErrorKind::Invalid,
2050 "unsupported method",
2051 Some(format!("`{}` is not a supported method", svr.method)),
2052 );
2053 return Err(err);
2054 }
2055 };
2056
2057 let password = match svr.password {
2059 Some(ref pwd) => read_variable_field_value(pwd),
2060 None => {
2061 if method.is_none() {
2062 String::new().into()
2063 } else {
2064 let err = Error::new(
2065 ErrorKind::MissingField,
2066 "`password` is required",
2067 Some(format!("`password` is required for method {method}")),
2068 );
2069 return Err(err);
2070 }
2071 }
2072 };
2073
2074 let mut nsvr = match ServerConfig::new(addr, password, method) {
2075 Ok(svr) => svr,
2076 Err(serr) => {
2077 let err = Error::new(
2078 ErrorKind::Malformed,
2079 "server config create failed",
2080 Some(format!("{}", serr)),
2081 );
2082 return Err(err);
2083 }
2084 };
2085 nsvr.set_source(server_source);
2086
2087 if let Some(users) = svr.users {
2089 let mut user_manager = ServerUserManager::new();
2090
2091 for user in users {
2092 let user = match ServerUser::with_encoded_key(user.name, &user.password) {
2093 Ok(u) => u,
2094 Err(..) => {
2095 let err = Error::new(
2096 ErrorKind::Malformed,
2097 "`users[].password` should be base64 encoded",
2098 None,
2099 );
2100 return Err(err);
2101 }
2102 };
2103
2104 user_manager.add_user(user);
2105 }
2106
2107 nsvr.set_user_manager(user_manager);
2108 }
2109
2110 match svr.mode {
2111 Some(mode) => match mode.parse::<Mode>() {
2112 Ok(mode) => nsvr.set_mode(mode),
2113 Err(..) => {
2114 let err = Error::new(ErrorKind::Invalid, "invalid `mode`", None);
2115 return Err(err);
2116 }
2117 },
2118 None => {
2119 if matches!(config_type, ConfigType::Server | ConfigType::Manager) {
2121 nsvr.set_mode(global_mode);
2122 }
2123 }
2124 }
2125
2126 if let Some(p) = svr.plugin {
2127 if !p.is_empty() {
2130 let plugin = PluginConfig {
2131 plugin: p,
2132 plugin_opts: svr.plugin_opts,
2133 plugin_args: svr.plugin_args.unwrap_or_default(),
2134 plugin_mode: match svr.plugin_mode {
2135 None => Mode::TcpOnly,
2136 Some(ref mode) => match mode.parse::<Mode>() {
2137 Ok(m) => m,
2138 Err(..) => {
2139 let e = Error::new(
2140 ErrorKind::Malformed,
2141 "malformed `plugin_mode`, must be one of `tcp_only`, `udp_only` and `tcp_and_udp`",
2142 None,
2143 );
2144 return Err(e);
2145 }
2146 },
2147 },
2148 };
2149 nsvr.set_plugin(plugin);
2150 }
2151 }
2152
2153 if let Some(timeout) = config.timeout.map(Duration::from_secs) {
2154 nsvr.set_timeout(timeout);
2155 }
2156
2157 if let Some(remarks) = svr.remarks {
2158 nsvr.set_remarks(remarks);
2159 }
2160
2161 if let Some(id) = svr.id {
2162 nsvr.set_id(id);
2163 }
2164
2165 if svr.tcp_weight.is_some() || svr.udp_weight.is_some() {
2166 let tcp_weight = svr.tcp_weight.unwrap_or(1.0);
2167 if !(0.0..=1.0).contains(&tcp_weight) {
2168 let err = Error::new(ErrorKind::Invalid, "invalid `tcp_weight`, must be in [0, 1]", None);
2169 return Err(err);
2170 }
2171 let udp_weight = svr.udp_weight.unwrap_or(1.0);
2172 if !(0.0..=1.0).contains(&udp_weight) {
2173 let err = Error::new(ErrorKind::Invalid, "invalid `udp_weight`, must be in [0, 1]", None);
2174 return Err(err);
2175 }
2176 let mut weight = ServerWeight::new();
2177 weight.set_tcp_weight(tcp_weight);
2178 weight.set_udp_weight(udp_weight);
2179 nsvr.set_weight(weight);
2180 }
2181
2182 let mut server_instance = ServerInstanceConfig::with_server_config(nsvr);
2183
2184 if let Some(acl_path) = svr.acl {
2185 let acl = match AccessControl::load_from_file(&acl_path) {
2186 Ok(acl) => acl,
2187 Err(err) => {
2188 let err = Error::new(
2189 ErrorKind::Invalid,
2190 "acl loading failed",
2191 Some(format!("file {acl_path}, error: {err}")),
2192 );
2193 return Err(err);
2194 }
2195 };
2196 server_instance.acl = Some(acl);
2197 }
2198
2199 #[cfg(any(target_os = "linux", target_os = "android"))]
2200 if let Some(outbound_fwmark) = svr.outbound_fwmark {
2201 server_instance.outbound_fwmark = Some(outbound_fwmark);
2202 }
2203
2204 #[cfg(target_os = "freebsd")]
2205 if let Some(outbound_user_cookie) = svr.outbound_user_cookie {
2206 server_instance.outbound_user_cookie = Some(outbound_user_cookie);
2207 }
2208
2209 if let Some(outbound_bind_addr) = svr.outbound_bind_addr {
2210 server_instance.outbound_bind_addr = Some(outbound_bind_addr);
2211 }
2212
2213 if let Some(ref outbound_bind_interface) = svr.outbound_bind_interface {
2214 server_instance.outbound_bind_interface = Some(outbound_bind_interface.clone());
2215 }
2216
2217 if let Some(outbound_udp_allow_fragmentation) = svr.outbound_udp_allow_fragmentation {
2218 server_instance.outbound_udp_allow_fragmentation = Some(outbound_udp_allow_fragmentation);
2219 }
2220
2221 nconfig.server.push(server_instance);
2222 }
2223 }
2224
2225 if let Some(timeout) = config.timeout {
2227 let timeout = Duration::from_secs(timeout);
2228 for inst in &mut nconfig.server {
2230 let svr = &mut inst.config;
2231 if svr.timeout().is_none() {
2232 svr.set_timeout(timeout);
2233 }
2234 }
2235 }
2236
2237 if let Some(ma) = config.manager_address {
2239 let manager = match config.manager_port {
2240 Some(port) => {
2241 match ma.parse::<IpAddr>() {
2242 Ok(ip) => ManagerAddr::from(SocketAddr::new(ip, port)),
2243 Err(..) => {
2244 ManagerAddr::from((ma, port))
2246 }
2247 }
2248 }
2249 #[cfg(unix)]
2250 None => ManagerAddr::from(PathBuf::from(ma)),
2251 #[cfg(not(unix))]
2252 None => {
2253 let e = Error::new(ErrorKind::MissingField, "missing `manager_port`", None);
2254 return Err(e);
2255 }
2256 };
2257
2258 let mut manager_config = ManagerConfig::new(manager);
2259 manager_config.mode = global_mode;
2260
2261 if let Some(ref m) = config.method {
2262 match m.parse::<CipherKind>() {
2263 Ok(method) => manager_config.method = Some(method),
2264 Err(..) => {
2265 let err = Error::new(
2266 ErrorKind::Invalid,
2267 "unsupported method",
2268 Some(format!("`{m}` is not a supported method")),
2269 );
2270 return Err(err);
2271 }
2272 }
2273 }
2274
2275 if let Some(p) = config.plugin {
2276 if !p.is_empty() {
2279 manager_config.plugin = Some(PluginConfig {
2280 plugin: p,
2281 plugin_opts: config.plugin_opts,
2282 plugin_args: config.plugin_args.unwrap_or_default(),
2283 plugin_mode: match config.plugin_mode {
2284 None => Mode::TcpOnly,
2285 Some(ref mode) => match mode.parse::<Mode>() {
2286 Ok(m) => m,
2287 Err(..) => {
2288 let e = Error::new(
2289 ErrorKind::Malformed,
2290 "malformed `plugin_mode`, must be one of `tcp_only`, `udp_only` and `tcp_and_udp`",
2291 None,
2292 );
2293 return Err(e);
2294 }
2295 },
2296 },
2297 });
2298 }
2299 }
2300
2301 nconfig.manager = Some(manager_config);
2302 }
2303
2304 {
2306 match config.dns {
2307 Some(SSDnsConfig::Simple(ds)) => nconfig.set_dns_formatted(&ds)?,
2308 #[cfg(feature = "hickory-dns")]
2309 Some(SSDnsConfig::HickoryDns(c)) => nconfig.dns = DnsConfig::HickoryDns(c),
2310 None => nconfig.dns = DnsConfig::System,
2311 }
2312 nconfig.dns_cache_size = config.dns_cache_size;
2313 }
2314
2315 if let Some(b) = config.no_delay {
2317 nconfig.no_delay = b;
2318 }
2319
2320 if let Some(b) = config.fast_open {
2322 nconfig.fast_open = b;
2323 }
2324
2325 if let Some(d) = config.keep_alive {
2327 nconfig.keep_alive = Some(Duration::from_secs(d));
2328 }
2329
2330 if let Some(b) = config.mptcp {
2332 nconfig.mptcp = b;
2333 }
2334
2335 nconfig.udp_timeout = config.udp_timeout.map(Duration::from_secs);
2337
2338 nconfig.udp_max_associations = config.udp_max_associations;
2340
2341 nconfig.udp_mtu = config.udp_mtu;
2343
2344 #[cfg(all(unix, not(target_os = "android")))]
2346 {
2347 nconfig.nofile = config.nofile;
2348 }
2349
2350 if let Some(f) = config.ipv6_first {
2352 nconfig.ipv6_first = f;
2353 }
2354
2355 if let Some(o) = config.ipv6_only {
2357 nconfig.ipv6_only = o;
2358 }
2359
2360 #[cfg(any(target_os = "linux", target_os = "android"))]
2362 if let Some(fwmark) = config.outbound_fwmark {
2363 nconfig.outbound_fwmark = Some(fwmark);
2364 }
2365
2366 #[cfg(target_os = "freebsd")]
2368 if let Some(user_cookie) = config.outbound_user_cookie {
2369 nconfig.outbound_user_cookie = Some(user_cookie);
2370 }
2371
2372 if let Some(bind_addr) = config.outbound_bind_addr {
2374 match bind_addr.parse::<IpAddr>() {
2375 Ok(b) => nconfig.outbound_bind_addr = Some(b),
2376 Err(..) => {
2377 let err = Error::new(ErrorKind::Invalid, "invalid outbound_bind_addr", None);
2378 return Err(err);
2379 }
2380 }
2381 }
2382
2383 nconfig.outbound_bind_interface = config.outbound_bind_interface;
2385
2386 if let Some(b) = config.outbound_udp_allow_fragmentation {
2387 nconfig.outbound_udp_allow_fragmentation = b;
2388 }
2389
2390 if let Some(sec) = config.security
2392 && let Some(replay_attack) = sec.replay_attack
2393 && let Some(policy) = replay_attack.policy {
2394 match policy.parse::<ReplayAttackPolicy>() {
2395 Ok(p) => nconfig.security.replay_attack.policy = p,
2396 Err(..) => {
2397 let err = Error::new(ErrorKind::Invalid, "invalid replay attack policy", None);
2398 return Err(err);
2399 }
2400 }
2401 }
2402
2403 if let Some(balancer) = config.balancer {
2404 nconfig.balancer = BalancerConfig {
2405 max_server_rtt: balancer.max_server_rtt.map(Duration::from_secs),
2406 check_interval: balancer.check_interval.map(Duration::from_secs),
2407 check_best_interval: balancer.check_best_interval.map(Duration::from_secs),
2408 };
2409 }
2410
2411 if let Some(acl_path) = config.acl {
2412 let acl = match AccessControl::load_from_file(&acl_path) {
2413 Ok(acl) => acl,
2414 Err(err) => {
2415 let err = Error::new(
2416 ErrorKind::Invalid,
2417 "acl loading failed",
2418 Some(format!("file {acl_path}, error: {err}")),
2419 );
2420 return Err(err);
2421 }
2422 };
2423 nconfig.acl = Some(acl);
2424 }
2425
2426 #[cfg(feature = "local-online-config")]
2427 if let Some(online_config) = config.online_config {
2428 nconfig.online_config = Some(OnlineConfig {
2429 config_url: online_config.config_url,
2430 update_interval: online_config.update_interval.map(Duration::from_secs),
2431 allowed_plugins: online_config.allowed_plugins,
2432 });
2433 }
2434
2435 Ok(nconfig)
2436 }
2437
2438 pub fn set_dns_formatted(&mut self, dns: &str) -> Result<(), Error> {
2443 self.dns = match dns {
2444 "system" => DnsConfig::System,
2445
2446 #[cfg(feature = "hickory-dns")]
2447 "google" => DnsConfig::HickoryDns(ResolverConfig::google()),
2448 #[cfg(all(feature = "hickory-dns", feature = "dns-over-tls"))]
2449 "google_tls" => DnsConfig::HickoryDns(ResolverConfig::google_tls()),
2450 #[cfg(all(feature = "hickory-dns", feature = "dns-over-https"))]
2451 "google_https" => DnsConfig::HickoryDns(ResolverConfig::google_https()),
2452 #[cfg(all(feature = "hickory-dns", feature = "dns-over-h3"))]
2453 "google_h3" => DnsConfig::HickoryDns(ResolverConfig::google_h3()),
2454
2455 #[cfg(feature = "hickory-dns")]
2456 "cloudflare" => DnsConfig::HickoryDns(ResolverConfig::cloudflare()),
2457 #[cfg(all(feature = "hickory-dns", feature = "dns-over-tls"))]
2458 "cloudflare_tls" => DnsConfig::HickoryDns(ResolverConfig::cloudflare_tls()),
2459 #[cfg(all(feature = "hickory-dns", feature = "dns-over-https"))]
2460 "cloudflare_https" => DnsConfig::HickoryDns(ResolverConfig::cloudflare_https()),
2461
2462 #[cfg(feature = "hickory-dns")]
2463 "quad9" => DnsConfig::HickoryDns(ResolverConfig::quad9()),
2464 #[cfg(all(feature = "hickory-dns", feature = "dns-over-tls"))]
2465 "quad9_tls" => DnsConfig::HickoryDns(ResolverConfig::quad9_tls()),
2466 #[cfg(all(feature = "hickory-dns", feature = "dns-over-https"))]
2467 "quad9_https" => DnsConfig::HickoryDns(ResolverConfig::quad9_https()),
2468
2469 nameservers => self.parse_dns_nameservers(nameservers)?,
2470 };
2471
2472 Ok(())
2473 }
2474
2475 #[cfg(any(feature = "hickory-dns", feature = "local-dns"))]
2476 fn parse_dns_nameservers(&mut self, nameservers: &str) -> Result<DnsConfig, Error> {
2477 use hickory_resolver::proto::xfer::Protocol;
2478
2479 #[cfg(all(unix, feature = "local-dns"))]
2480 if let Some(nameservers) = nameservers.strip_prefix("unix://") {
2481 return Ok(DnsConfig::LocalDns(NameServerAddr::UnixSocketAddr(PathBuf::from(
2485 nameservers,
2486 ))));
2487 }
2488
2489 enum DnsProtocol {
2490 Tcp,
2491 Udp,
2492 Both,
2493 }
2494
2495 impl DnsProtocol {
2496 fn enable_tcp(&self) -> bool {
2497 matches!(*self, Self::Tcp | Self::Both)
2498 }
2499
2500 fn enable_udp(&self) -> bool {
2501 matches!(*self, Self::Udp | Self::Both)
2502 }
2503 }
2504
2505 let mut protocol = DnsProtocol::Both;
2506
2507 let mut nameservers = nameservers;
2508 if nameservers.starts_with("tcp://") {
2509 protocol = DnsProtocol::Tcp;
2510 nameservers = &nameservers[6..];
2511 } else if nameservers.starts_with("udp://") {
2512 protocol = DnsProtocol::Udp;
2513 nameservers = &nameservers[6..];
2514 }
2515
2516 let mut c = ResolverConfig::new();
2528 for part in nameservers.split(',') {
2529 let socket_addr = if let Ok(socket_addr) = part.parse::<SocketAddr>() {
2530 socket_addr
2531 } else if let Ok(ipaddr) = part.parse::<IpAddr>() {
2532 SocketAddr::new(ipaddr, 53)
2533 } else {
2534 let e = Error::new(
2535 ErrorKind::Invalid,
2536 "invalid `dns` value, can only be [(tcp|udp)://]host[:port][,host[:port]]..., or unix:///path/to/dns, or predefined keys like \"google\", \"cloudflare\"",
2537 None,
2538 );
2539 return Err(e);
2540 };
2541
2542 if protocol.enable_udp() {
2543 let ns_config = NameServerConfig::new(socket_addr, Protocol::Udp);
2544 c.add_name_server(ns_config);
2545 }
2546 if protocol.enable_tcp() {
2547 let ns_config = NameServerConfig::new(socket_addr, Protocol::Tcp);
2548 c.add_name_server(ns_config);
2549 }
2550 }
2551
2552 Ok(if c.name_servers().is_empty() {
2553 DnsConfig::System
2554 } else {
2555 DnsConfig::HickoryDns(c)
2556 })
2557 }
2558
2559 #[cfg(not(any(feature = "hickory-dns", feature = "local-dns")))]
2560 fn parse_dns_nameservers(&mut self, _nameservers: &str) -> Result<DnsConfig, Error> {
2561 Ok(DnsConfig::System)
2562 }
2563
2564 pub fn load_from_str(s: &str, config_type: ConfigType) -> Result<Self, Error> {
2566 let c = json5::from_str::<SSConfig>(s)?;
2567 Self::load_from_ssconfig(c, config_type)
2568 }
2569
2570 pub fn load_from_json_str(s: &str, config_type: ConfigType) -> Result<Self, Error> {
2572 let c = serde_json::from_str::<SSConfig>(s)?;
2573 Self::load_from_ssconfig(c, config_type)
2574 }
2575
2576 pub fn load_from_file<P: AsRef<Path>>(filename: P, config_type: ConfigType) -> Result<Self, Error> {
2578 let filename = filename.as_ref();
2579
2580 let mut reader = OpenOptions::new().read(true).open(filename)?;
2581 let mut content = String::new();
2582 reader.read_to_string(&mut content)?;
2583
2584 let mut config = Self::load_from_str(&content[..], config_type)?;
2585
2586 config.config_path = Some(filename.to_owned());
2588
2589 Ok(config)
2590 }
2591
2592 pub fn has_server_plugins(&self) -> bool {
2594 for inst in &self.server {
2595 let server = &inst.config;
2596
2597 if server.plugin().is_some() {
2598 return true;
2599 }
2600 }
2601 false
2602 }
2603
2604 pub fn check_integrity(&self) -> Result<(), Error> {
2606 if self.config_type.is_local() {
2607 if self.local.is_empty() {
2608 let err = Error::new(
2609 ErrorKind::MissingField,
2610 "missing `locals` for client configuration",
2611 None,
2612 );
2613 return Err(err);
2614 }
2615
2616 for local_config in &self.local {
2617 local_config.config.check_integrity()?;
2618 }
2619
2620 if let Some(rtt) = self.balancer.max_server_rtt
2622 && rtt.as_secs() == 0 {
2623 let err = Error::new(ErrorKind::Invalid, "balancer.max_server_rtt must be > 0", None);
2624 return Err(err);
2625 }
2626
2627 if let Some(intv) = self.balancer.check_interval
2628 && intv.as_secs() == 0 {
2629 let err = Error::new(ErrorKind::Invalid, "balancer.check_interval must be > 0", None);
2630 return Err(err);
2631 }
2632 }
2633
2634 if self.config_type.is_server() && self.server.is_empty() {
2635 let err = Error::new(
2636 ErrorKind::MissingField,
2637 "missing any valid servers in configuration",
2638 None,
2639 );
2640 return Err(err);
2641 }
2642
2643 #[cfg(feature = "local-online-config")]
2644 if self.config_type.is_online_config() && self.server.is_empty() {
2645 let err = Error::new(
2646 ErrorKind::MissingField,
2647 "missing any valid servers in configuration",
2648 None,
2649 );
2650 return Err(err);
2651 }
2652
2653 if self.config_type.is_manager() && self.manager.is_none() {
2654 let err = Error::new(
2655 ErrorKind::MissingField,
2656 "missing `manager_addr` and `manager_port` in configuration",
2657 None,
2658 );
2659 return Err(err);
2660 }
2661
2662 for inst in &self.server {
2663 let server = &inst.config;
2664
2665 if let Some(plugin) = server.plugin()
2667 && plugin.plugin.trim().is_empty() {
2668 let err = Error::new(ErrorKind::Malformed, "`plugin` shouldn't be an empty string", None);
2669 return Err(err);
2670 }
2671
2672 match server.addr() {
2674 ServerAddr::SocketAddr(sa) => {
2675 if sa.port() == 0 {
2676 let err = Error::new(ErrorKind::Malformed, "`server_port` shouldn't be 0", None);
2677 return Err(err);
2678 }
2679
2680 if self.config_type.is_local() {
2681 let ip = sa.ip();
2683 if ip.is_unspecified() {
2684 let err = Error::new(
2685 ErrorKind::Malformed,
2686 "`server` shouldn't be an unspecified address (INADDR_ANY)",
2687 None,
2688 );
2689 return Err(err);
2690 }
2691 }
2692
2693 #[cfg(feature = "local-online-config")]
2694 if self.config_type.is_online_config() {
2695 let ip = sa.ip();
2697 if ip.is_unspecified() {
2698 let err = Error::new(
2699 ErrorKind::Malformed,
2700 "`server` shouldn't be an unspecified address (INADDR_ANY)",
2701 None,
2702 );
2703 return Err(err);
2704 }
2705 }
2706 }
2707 ServerAddr::DomainName(dn, port) => {
2708 if dn.is_empty() || *port == 0 {
2709 let err = Error::new(
2710 ErrorKind::Malformed,
2711 "`server` shouldn't be an empty string, `server_port` shouldn't be 0",
2712 None,
2713 );
2714 return Err(err);
2715 }
2716 }
2717 }
2718
2719 if let Some(user_manager) = server.user_manager() {
2721 #[cfg(feature = "aead-cipher-2022")]
2722 if server.method().is_aead_2022() {
2723 use shadowsocks::config::method_support_eih;
2724 if user_manager.user_count() > 0 && !method_support_eih(server.method()) {
2725 let err = Error::new(
2726 ErrorKind::Invalid,
2727 "server method doesn't support Extended Identity Header (EIH), remove `users`",
2728 Some(format!("method {}", server.method())),
2729 );
2730 return Err(err);
2731 }
2732 }
2733
2734 let key_len = server.method().key_len();
2735 for user in user_manager.users_iter() {
2736 if user.key().len() != key_len {
2737 let err = Error::new(
2738 ErrorKind::Malformed,
2739 "`users[].password` length must be exactly the same as method's key length",
2740 None,
2741 );
2742 return Err(err);
2743 }
2744 }
2745 }
2746 }
2747
2748 Ok(())
2749 }
2750}
2751
2752impl fmt::Display for Config {
2753 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2754 let mut jconf = SSConfig::default();
2757
2758 if !self.local.is_empty() {
2760 if self.local.len() == 1 && self.local[0].config.is_basic() {
2761 let local_instance = &self.local[0];
2762 let local = &local_instance.config;
2763 if let Some(ref a) = local.addr {
2764 jconf.local_address = Some(match a {
2765 ServerAddr::SocketAddr(sa) => sa.ip().to_string(),
2766 ServerAddr::DomainName(dm, ..) => dm.to_string(),
2767 });
2768 jconf.local_port = Some(match a {
2769 ServerAddr::SocketAddr(sa) => sa.port(),
2770 ServerAddr::DomainName(.., port) => *port,
2771 });
2772 }
2773
2774 #[cfg(target_os = "macos")]
2775 {
2776 jconf.launchd_tcp_socket_name.clone_from(&local.launchd_tcp_socket_name);
2777 jconf.launchd_udp_socket_name.clone_from(&local.launchd_udp_socket_name);
2778 }
2779
2780 if local.protocol != ProtocolType::Socks {
2781 jconf.protocol = Some(local.protocol.as_str().to_owned());
2782 }
2783
2784 if let Some(ref acl) = local_instance.acl {
2786 jconf.acl = Some(acl.file_path().to_str().unwrap().to_owned());
2787 }
2788 } else {
2789 let mut jlocals = Vec::with_capacity(self.local.len());
2790 for local_instance in &self.local {
2791 let local = &local_instance.config;
2792
2793 let jlocal = SSLocalExtConfig {
2794 local_address: local.addr.as_ref().map(|a| match a {
2795 ServerAddr::SocketAddr(sa) => sa.ip().to_string(),
2796 ServerAddr::DomainName(dm, ..) => dm.to_string(),
2797 }),
2798 local_port: local.addr.as_ref().map(|a| match a {
2799 ServerAddr::SocketAddr(sa) => sa.port(),
2800 ServerAddr::DomainName(.., port) => *port,
2801 }),
2802 disabled: None,
2803 local_udp_address: local.udp_addr.as_ref().map(|udp_addr| match udp_addr {
2804 ServerAddr::SocketAddr(sa) => sa.ip().to_string(),
2805 ServerAddr::DomainName(dm, ..) => dm.to_string(),
2806 }),
2807 local_udp_port: local.udp_addr.as_ref().map(|udp_addr| match udp_addr {
2808 ServerAddr::SocketAddr(sa) => sa.port(),
2809 ServerAddr::DomainName(.., port) => *port,
2810 }),
2811 mode: Some(local.mode.to_string()),
2812 protocol: match local.protocol {
2813 ProtocolType::Socks => None,
2814 #[allow(unreachable_patterns)]
2815 p => Some(p.as_str().to_owned()),
2816 },
2817 #[cfg(target_os = "macos")]
2818 launchd_tcp_socket_name: local.launchd_tcp_socket_name.clone(),
2819 #[cfg(target_os = "macos")]
2820 launchd_udp_socket_name: local.launchd_udp_socket_name.clone(),
2821 #[cfg(feature = "local-redir")]
2822 tcp_redir: if local.tcp_redir != RedirType::tcp_default() {
2823 Some(local.tcp_redir.to_string())
2824 } else {
2825 None
2826 },
2827 #[cfg(feature = "local-redir")]
2828 udp_redir: if local.udp_redir != RedirType::udp_default() {
2829 Some(local.udp_redir.to_string())
2830 } else {
2831 None
2832 },
2833 #[cfg(feature = "local-tunnel")]
2834 forward_address: match local.forward_addr {
2835 None => None,
2836 Some(ref forward_addr) => match forward_addr {
2837 Address::SocketAddress(sa) => Some(sa.ip().to_string()),
2838 Address::DomainNameAddress(dm, ..) => Some(dm.to_string()),
2839 },
2840 },
2841 #[cfg(feature = "local-tunnel")]
2842 forward_port: match local.forward_addr {
2843 None => None,
2844 Some(ref forward_addr) => match forward_addr {
2845 Address::SocketAddress(sa) => Some(sa.port()),
2846 Address::DomainNameAddress(.., port) => Some(*port),
2847 },
2848 },
2849 #[cfg(feature = "local-dns")]
2850 local_dns_address: match local.local_dns_addr {
2851 None => None,
2852 Some(ref local_dns_addr) => match local_dns_addr {
2853 NameServerAddr::SocketAddr(sa) => Some(sa.ip().to_string()),
2854 #[cfg(unix)]
2855 NameServerAddr::UnixSocketAddr(path) => {
2856 Some(path.to_str().expect("path is not utf-8").to_owned())
2857 }
2858 },
2859 },
2860 #[cfg(feature = "local-dns")]
2861 local_dns_port: match local.local_dns_addr {
2862 None => None,
2863 Some(ref local_dns_addr) => match local_dns_addr {
2864 NameServerAddr::SocketAddr(sa) => Some(sa.port()),
2865 #[cfg(unix)]
2866 NameServerAddr::UnixSocketAddr(..) => None,
2867 },
2868 },
2869 #[cfg(feature = "local-dns")]
2870 remote_dns_address: match local.remote_dns_addr {
2871 None => None,
2872 Some(ref remote_dns_addr) => match remote_dns_addr {
2873 Address::SocketAddress(sa) => Some(sa.ip().to_string()),
2874 Address::DomainNameAddress(dm, ..) => Some(dm.to_string()),
2875 },
2876 },
2877 #[cfg(feature = "local-dns")]
2878 remote_dns_port: match local.remote_dns_addr {
2879 None => None,
2880 Some(ref remote_dns_addr) => match remote_dns_addr {
2881 Address::SocketAddress(sa) => Some(sa.port()),
2882 Address::DomainNameAddress(.., port) => Some(*port),
2883 },
2884 },
2885 #[cfg(feature = "local-dns")]
2886 client_cache_size: local.client_cache_size,
2887 #[cfg(feature = "local-tun")]
2888 tun_interface_name: local.tun_interface_name.clone(),
2889 #[cfg(feature = "local-tun")]
2890 tun_interface_address: local.tun_interface_address.as_ref().map(ToString::to_string),
2891 #[cfg(feature = "local-tun")]
2892 tun_interface_destination: local.tun_interface_destination.as_ref().map(ToString::to_string),
2893 #[cfg(all(feature = "local-tun", unix))]
2894 tun_device_fd_from_path: local
2895 .tun_device_fd_from_path
2896 .as_ref()
2897 .map(|p| p.to_str().expect("tun_device_fd_from_path is not utf-8").to_owned()),
2898
2899 #[cfg(feature = "local")]
2900 socks5_auth_config_path: None,
2901
2902 #[cfg(feature = "local-fake-dns")]
2903 fake_dns_record_expire_duration: local.fake_dns_record_expire_duration.map(|d| d.as_secs()),
2904 #[cfg(feature = "local-fake-dns")]
2905 fake_dns_ipv4_network: local.fake_dns_ipv4_network.map(|n| n.to_string()),
2906 #[cfg(feature = "local-fake-dns")]
2907 fake_dns_ipv6_network: local.fake_dns_ipv6_network.map(|n| n.to_string()),
2908 #[cfg(feature = "local-fake-dns")]
2909 fake_dns_database_path: local
2910 .fake_dns_database_path
2911 .as_ref()
2912 .and_then(|n| n.to_str().map(ToOwned::to_owned)),
2913
2914 acl: local_instance
2915 .acl
2916 .as_ref()
2917 .and_then(|a| a.file_path().to_str().map(ToOwned::to_owned)),
2918 };
2919 jlocals.push(jlocal);
2920 }
2921 jconf.locals = Some(jlocals);
2922 }
2923 }
2924
2925 match self.server.len() {
2927 0 => {}
2928 1 if self.server[0].config.is_basic() => {
2930 let inst = &self.server[0];
2931 let svr = &inst.config;
2932
2933 jconf.server = Some(match *svr.addr() {
2934 ServerAddr::SocketAddr(ref sa) => sa.ip().to_string(),
2935 ServerAddr::DomainName(ref dm, ..) => dm.to_string(),
2936 });
2937 jconf.server_port = Some(match *svr.addr() {
2938 ServerAddr::SocketAddr(ref sa) => sa.port(),
2939 ServerAddr::DomainName(.., port) => port,
2940 });
2941 jconf.method = Some(svr.method().to_string());
2942 jconf.password = if svr.method().is_none() {
2943 None
2944 } else {
2945 Some(svr.password().to_string())
2946 };
2947 jconf.plugin = svr.plugin().map(|p| p.plugin.to_string());
2948 jconf.plugin_opts = svr.plugin().and_then(|p| p.plugin_opts.clone());
2949 jconf.plugin_args = svr.plugin().and_then(|p| {
2950 if p.plugin_args.is_empty() {
2951 None
2952 } else {
2953 Some(p.plugin_args.clone())
2954 }
2955 });
2956 jconf.plugin_mode = match svr.plugin() {
2957 None => None,
2958 Some(p) => match p.plugin_mode {
2959 Mode::TcpOnly => None,
2960 _ => Some(p.plugin_mode.to_string()),
2961 },
2962 };
2963 jconf.timeout = svr.timeout().map(|t| t.as_secs());
2964 jconf.mode = Some(svr.mode().to_string());
2965
2966 if let Some(ref acl) = inst.acl {
2967 jconf.acl = Some(acl.file_path().to_str().unwrap().to_owned());
2968 }
2969 }
2970 _ => {
2972 let mut vsvr = Vec::new();
2973
2974 for inst in &self.server {
2975 let svr = &inst.config;
2976
2977 vsvr.push(SSServerExtConfig {
2978 server: match *svr.addr() {
2979 ServerAddr::SocketAddr(ref sa) => sa.ip().to_string(),
2980 ServerAddr::DomainName(ref dm, ..) => dm.to_string(),
2981 },
2982 server_port: match *svr.addr() {
2983 ServerAddr::SocketAddr(ref sa) => sa.port(),
2984 ServerAddr::DomainName(.., port) => port,
2985 },
2986 password: if svr.method().is_none() {
2987 None
2988 } else {
2989 Some(svr.password().to_string())
2990 },
2991 method: svr.method().to_string(),
2992 users: svr.user_manager().map(|m| {
2993 let mut vu = Vec::new();
2994 for u in m.users_iter() {
2995 vu.push(SSServerUserConfig {
2996 name: u.name().to_owned(),
2997 password: u.encoded_key(),
2998 });
2999 }
3000 vu
3001 }),
3002 disabled: None,
3003 plugin: svr.plugin().map(|p| p.plugin.to_string()),
3004 plugin_opts: svr.plugin().and_then(|p| p.plugin_opts.clone()),
3005 plugin_args: svr.plugin().and_then(|p| {
3006 if p.plugin_args.is_empty() {
3007 None
3008 } else {
3009 Some(p.plugin_args.clone())
3010 }
3011 }),
3012 plugin_mode: match svr.plugin() {
3013 None => None,
3014 Some(p) => match p.plugin_mode {
3015 Mode::TcpOnly => None,
3016 _ => Some(p.plugin_mode.to_string()),
3017 },
3018 },
3019 timeout: svr.timeout().map(|t| t.as_secs()),
3020 remarks: svr.remarks().map(ToOwned::to_owned),
3021 id: svr.id().map(ToOwned::to_owned),
3022 mode: Some(svr.mode().to_string()),
3023 tcp_weight: if (svr.weight().tcp_weight() - 1.0).abs() > f32::EPSILON {
3024 Some(svr.weight().tcp_weight())
3025 } else {
3026 None
3027 },
3028 udp_weight: if (svr.weight().udp_weight() - 1.0).abs() > f32::EPSILON {
3029 Some(svr.weight().udp_weight())
3030 } else {
3031 None
3032 },
3033 acl: inst
3034 .acl
3035 .as_ref()
3036 .and_then(|a| a.file_path().to_str().map(ToOwned::to_owned)),
3037 #[cfg(any(target_os = "linux", target_os = "android"))]
3038 outbound_fwmark: inst.outbound_fwmark,
3039 #[cfg(target_os = "freebsd")]
3040 outbound_user_cookie: inst.outbound_user_cookie,
3041 outbound_bind_addr: inst.outbound_bind_addr,
3042 outbound_bind_interface: inst.outbound_bind_interface.clone(),
3043 outbound_udp_allow_fragmentation: inst.outbound_udp_allow_fragmentation,
3044 });
3045 }
3046
3047 jconf.servers = Some(vsvr);
3048 }
3049 }
3050
3051 if let Some(ref m) = self.manager {
3052 jconf.manager_address = Some(match m.addr {
3053 ManagerAddr::SocketAddr(ref saddr) => saddr.ip().to_string(),
3054 ManagerAddr::DomainName(ref dname, ..) => dname.clone(),
3055 #[cfg(unix)]
3056 ManagerAddr::UnixSocketAddr(ref path) => path.display().to_string(),
3057 });
3058
3059 jconf.manager_port = match m.addr {
3060 ManagerAddr::SocketAddr(ref saddr) => Some(saddr.port()),
3061 ManagerAddr::DomainName(.., port) => Some(port),
3062 #[cfg(unix)]
3063 ManagerAddr::UnixSocketAddr(..) => None,
3064 };
3065
3066 if jconf.mode.is_none() {
3067 jconf.mode = Some(m.mode.to_string());
3068 }
3069
3070 if jconf.method.is_none()
3071 && let Some(ref m) = m.method {
3072 jconf.method = Some(m.to_string());
3073 }
3074
3075 if jconf.plugin.is_none()
3076 && let Some(ref p) = m.plugin {
3077 jconf.plugin = Some(p.plugin.clone());
3078 if let Some(ref o) = p.plugin_opts {
3079 jconf.plugin_opts = Some(o.clone());
3080 }
3081 if !p.plugin_args.is_empty() {
3082 jconf.plugin_args = Some(p.plugin_args.clone());
3083 }
3084 }
3085 }
3086
3087 if self.no_delay {
3088 jconf.no_delay = Some(self.no_delay);
3089 }
3090
3091 if self.fast_open {
3092 jconf.fast_open = Some(self.fast_open);
3093 }
3094
3095 if let Some(keepalive) = self.keep_alive {
3096 jconf.keep_alive = Some(keepalive.as_secs());
3097 }
3098
3099 if self.mptcp {
3100 jconf.mptcp = Some(self.mptcp);
3101 }
3102
3103 match self.dns {
3104 DnsConfig::System => {}
3105 #[cfg(feature = "hickory-dns")]
3106 DnsConfig::HickoryDns(ref dns) => {
3107 jconf.dns = Some(SSDnsConfig::HickoryDns(dns.clone()));
3108 }
3109 #[cfg(feature = "local-dns")]
3110 DnsConfig::LocalDns(ref ns) => {
3111 jconf.dns = Some(SSDnsConfig::Simple(ns.to_string()));
3112 }
3113 }
3114
3115 jconf.udp_timeout = self.udp_timeout.map(|t| t.as_secs());
3116
3117 jconf.udp_max_associations = self.udp_max_associations;
3118
3119 jconf.udp_mtu = self.udp_mtu;
3120
3121 #[cfg(all(unix, not(target_os = "android")))]
3122 {
3123 jconf.nofile = self.nofile;
3124 }
3125
3126 if self.ipv6_first {
3127 jconf.ipv6_first = Some(self.ipv6_first);
3128 }
3129
3130 if self.ipv6_only {
3131 jconf.ipv6_only = Some(self.ipv6_only);
3132 }
3133
3134 #[cfg(any(target_os = "linux", target_os = "android"))]
3135 {
3136 jconf.outbound_fwmark = self.outbound_fwmark;
3137 }
3138
3139 #[cfg(target_os = "freebsd")]
3140 {
3141 jconf.outbound_user_cookie = self.outbound_user_cookie;
3142 }
3143
3144 jconf.outbound_bind_addr = self.outbound_bind_addr.map(|i| i.to_string());
3145 jconf.outbound_bind_interface.clone_from(&self.outbound_bind_interface);
3146 jconf.outbound_udp_allow_fragmentation = Some(self.outbound_udp_allow_fragmentation);
3147
3148 if self.security.replay_attack.policy != ReplayAttackPolicy::default() {
3150 jconf.security = Some(SSSecurityConfig {
3151 replay_attack: Some(SSSecurityReplayAttackConfig {
3152 policy: Some(self.security.replay_attack.policy.to_string()),
3153 }),
3154 });
3155 }
3156
3157 if self.balancer.max_server_rtt.is_some() || self.balancer.check_interval.is_some() {
3159 jconf.balancer = Some(SSBalancerConfig {
3160 max_server_rtt: self.balancer.max_server_rtt.as_ref().map(Duration::as_secs),
3161 check_interval: self.balancer.check_interval.as_ref().map(Duration::as_secs),
3162 check_best_interval: self.balancer.check_best_interval.as_ref().map(Duration::as_secs),
3163 });
3164 }
3165
3166 if let Some(ref acl) = self.acl {
3168 jconf.acl = Some(acl.file_path().to_str().unwrap().to_owned());
3169 }
3170
3171 #[cfg(feature = "local-online-config")]
3173 if let Some(ref online_config) = self.online_config {
3174 jconf.online_config = Some(SSOnlineConfig {
3175 config_url: online_config.config_url.clone(),
3176 update_interval: online_config.update_interval.as_ref().map(Duration::as_secs),
3177 allowed_plugins: online_config.allowed_plugins.clone(),
3178 });
3179 }
3180
3181 write!(f, "{}", json5::to_string(&jconf).unwrap())
3182 }
3183}
3184
3185pub fn read_variable_field_value(value: &str) -> Cow<'_, str> {
3190 if let Some(left_over) = value.strip_prefix("${")
3191 && let Some(var_name) = left_over.strip_suffix('}') {
3192 match env::var(var_name) {
3193 Ok(value) => return value.into(),
3194 Err(err) => {
3195 warn!(
3196 "couldn't read password from environment variable {}, error: {}",
3197 var_name, err
3198 );
3199 }
3200 }
3201 }
3202
3203 value.into()
3204}