Skip to content

Commit

Permalink
default configuration file (config.json) for Windows, Linux, macOS
Browse files Browse the repository at this point in the history
- $XDG_CONFIG_PATH/shadowsocks-rust/config.json
- $HOME/.config/shadowsocks-rust/config.json
- {FOLDERID_RoamingAppData}\shadowsocks\shadowsocks-rust\config\config.json
- $HOME/Library/Application Support/org.shadowsocks.shadowsocks-rust/config.json

fixes #688
  • Loading branch information
zonyitoo committed Nov 25, 2021
1 parent 05d1b07 commit fa3a2a8
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 18 deletions.
58 changes: 54 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ cfg-if = "1"
qrcode = { version = "0.12", default-features = false }
exitcode = "1"
build-time = "0.1"
directories = "4.0"
xdg = "2.4"

futures = "0.3"
tokio = { version = "1", features = ["rt", "signal"] }
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ Related Projects:

* `local-dns` - Allow using dns protocol for `sslocal`, serves as a DNS server proxying queries to local or remote DNS servers by ACL rules

* `local-tun` - [TUN](https://en.wikipedia.org/wiki/TUN/TAP) interface support for `sslocal`

* `stream-cipher` - Enable deprecated stream ciphers. WARN: stream ciphers are UNSAFE!

* `aead-cipher-extra` - Enable non-standard AEAD ciphers
Expand Down
41 changes: 41 additions & 0 deletions bin/common/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use directories::ProjectDirs;
use std::path::{Path, PathBuf};

/// Default configuration file path
pub fn get_default_config_path() -> Option<PathBuf> {
// System standard directories
if let Some(project_dirs) = ProjectDirs::from("org", "shadowsocks", "shadowsocks-rust") {
// Linux: $XDG_CONFIG_HOME/shadowsocks-rust/config.json
// $HOME/.config/shadowsocks-rust/config.json
// macOS: $HOME/Library/Application Support/org.shadowsocks.shadowsocks-rust/config.json
// Windows: {FOLDERID_RoamingAppData}/shadowsocks/shadowsocks-rust/config/config.json

let mut config_path = project_dirs.config_dir().to_path_buf();
config_path.push("config.json");

if config_path.exists() {
return Some(config_path);
}
}

// UNIX systems, XDG Base Directory
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
#[cfg(unix)]
if let Ok(base_directories) = xdg::BaseDirectories::with_prefix("shadowsocks-rust") {
// $XDG_CONFIG_HOME/shadowsocks-rust/config.json
// for dir in $XDG_CONFIG_DIRS; $dir/shadowsocks-rust/config.json
if let Some(config_path) = base_directories.find_config_file("config.json") {
return Some(config_path);
}
}

// UNIX global configuration file
if cfg!(unix) {
let global_config_path = Path::new("/etc/shadowsocks-rust/config.json");
if global_config_path.exists() {
return Some(global_config_path.to_path_buf());
}
}

None
}
1 change: 1 addition & 0 deletions bin/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod daemonize;
pub mod logging;
pub mod monitor;
pub mod validator;
pub mod config;

pub const EXIT_CODE_SERVER_EXIT_UNEXPECTEDLY: i32 = exitcode::SOFTWARE;
pub const EXIT_CODE_SERVER_ABORTED: i32 = exitcode::SOFTWARE;
Expand Down
16 changes: 12 additions & 4 deletions bin/sslocal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fn main() {
(version: VERSION)
(about: "A fast tunnel proxy that helps you bypass firewalls.")

(@arg CONFIG: -c --config +takes_value required_unless("SERVER_CONFIG") "Shadowsocks configuration file (https://shadowsocks.org/en/config/quick-guide.html)")
(@arg CONFIG: -c --config +takes_value "Shadowsocks configuration file (https://shadowsocks.org/en/config/quick-guide.html)")

(@arg LOCAL_ADDR: -b --("local-addr") +takes_value {validator::validate_server_addr} "Local address, listen only to this address if specified")
(@arg UDP_ONLY: -u conflicts_with[TCP_AND_UDP] requires[LOCAL_ADDR] "Server mode UDP_ONLY")
Expand Down Expand Up @@ -207,11 +207,19 @@ fn main() {
}
}

let mut config = match matches.value_of("CONFIG") {
Some(cpath) => match Config::load_from_file(cpath, ConfigType::Local) {
let config_path_opt = matches.value_of("CONFIG").map(|c| PathBuf::from(c)).or_else(|| {
if !matches.is_present("SERVER_CONFIG") {
common::config::get_default_config_path()
} else {
None
}
});

let mut config = match config_path_opt {
Some(cpath) => match Config::load_from_file(&cpath, ConfigType::Local) {
Ok(cfg) => cfg,
Err(err) => {
eprintln!("loading config \"{}\", {}", cpath, err);
eprintln!("loading config \"{}\", {}", cpath.display(), err);
process::exit(common::EXIT_CODE_LOAD_CONFIG_FAILURE);
}
},
Expand Down
18 changes: 13 additions & 5 deletions bin/ssmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//! *It should be notice that the extended configuration file is not suitable for the server
//! side.*
use std::{net::IpAddr, process, time::Duration};
use std::{net::IpAddr, path::PathBuf, process, time::Duration};

use clap::{clap_app, Arg};
use futures::future::{self, Either};
Expand Down Expand Up @@ -44,7 +44,7 @@ fn main() {
(@arg UDP_ONLY: -u conflicts_with[TCP_AND_UDP] "Server mode UDP_ONLY")
(@arg TCP_AND_UDP: -U conflicts_with[UDP_ONLY] "Server mode TCP_AND_UDP")

(@arg CONFIG: -c --config +takes_value required_unless("MANAGER_ADDR")
(@arg CONFIG: -c --config +takes_value
"Shadowsocks configuration file (https://shadowsocks.org/en/config/quick-guide.html), \
the only required fields are \"manager_address\" and \"manager_port\". \
Servers defined will be created when process is started.")
Expand Down Expand Up @@ -136,11 +136,19 @@ fn main() {
}
}

let mut config = match matches.value_of("CONFIG") {
Some(cpath) => match Config::load_from_file(cpath, ConfigType::Manager) {
let config_path_opt = matches.value_of("CONFIG").map(|c| PathBuf::from(c)).or_else(|| {
if !matches.is_present("MANAGER_ADDR") {
common::config::get_default_config_path()
} else {
None
}
});

let mut config = match config_path_opt {
Some(cpath) => match Config::load_from_file(&cpath, ConfigType::Manager) {
Ok(cfg) => cfg,
Err(err) => {
eprintln!("loading config \"{}\", {}", cpath, err);
eprintln!("loading config \"{}\", {}", cpath.display(), err);
process::exit(common::EXIT_CODE_LOAD_CONFIG_FAILURE);
}
},
Expand Down
18 changes: 13 additions & 5 deletions bin/ssserver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//! *It should be notice that the extended configuration file is not suitable for the server
//! side.*
use std::{net::IpAddr, process, time::Duration};
use std::{net::IpAddr, path::PathBuf, process, time::Duration};

use clap::{clap_app, Arg};
use futures::future::{self, Either};
Expand Down Expand Up @@ -41,7 +41,7 @@ fn main() {
(version: VERSION)
(about: "A fast tunnel proxy that helps you bypass firewalls.")

(@arg CONFIG: -c --config +takes_value required_unless("SERVER_ADDR") "Shadowsocks configuration file (https://shadowsocks.org/en/config/quick-guide.html)")
(@arg CONFIG: -c --config +takes_value "Shadowsocks configuration file (https://shadowsocks.org/en/config/quick-guide.html)")

(@arg OUTBOUND_BIND_ADDR: -b --("outbound-bind-addr") +takes_value alias("bind-addr") {validator::validate_ip_addr} "Bind address, outbound socket will bind this address")
(@arg OUTBOUND_BIND_INTERFACE: --("outbound-bind-interface") +takes_value "Set SO_BINDTODEVICE / IP_BOUND_IF / IP_UNICAST_IF option for outbound socket")
Expand Down Expand Up @@ -131,11 +131,19 @@ fn main() {
}
}

let mut config = match matches.value_of("CONFIG") {
Some(cpath) => match Config::load_from_file(cpath, ConfigType::Server) {
let config_path_opt = matches.value_of("CONFIG").map(|c| PathBuf::from(c)).or_else(|| {
if !matches.is_present("SERVER_ADDR") {
common::config::get_default_config_path()
} else {
None
}
});

let mut config = match config_path_opt {
Some(cpath) => match Config::load_from_file(&cpath, ConfigType::Server) {
Ok(cfg) => cfg,
Err(err) => {
eprintln!("loading config \"{}\", {}", cpath, err);
eprintln!("loading config \"{}\", {}", cpath.display(), err);
process::exit(common::EXIT_CODE_LOAD_CONFIG_FAILURE);
}
},
Expand Down

0 comments on commit fa3a2a8

Please sign in to comment.