Files
shadowsocks-rust/src/bin/server.rs
T

265 lines
7.7 KiB
Rust

//! This is a binary running in the server environment
//!
//! You have to provide all needed configuration attributes via command line parameters,
//! or you could specify a configuration file. The format of configuration file is defined
//! in mod `config`.
//!
//! *It should be notice that the extented configuration file is not suitable for the server
//! side.*
extern crate clap;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate futures;
extern crate shadowsocks;
extern crate time;
extern crate tokio;
use std::{
env,
io::{self, Write},
};
use clap::{App, Arg};
use env_logger::{fmt::Formatter, Builder};
use futures::Future;
use log::{LevelFilter, Record};
use tokio::runtime::Runtime;
use shadowsocks::{plugin::PluginConfig, run_server, Config, ConfigType, Mode, ServerAddr, ServerConfig};
fn log_time(fmt: &mut Formatter, without_time: bool, record: &Record) -> io::Result<()> {
if without_time {
writeln!(fmt, "[{}] {}", record.level(), record.args())
} else {
writeln!(
fmt,
"[{}][{}] {}",
time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(),
record.level(),
record.args()
)
}
}
fn log_time_module(fmt: &mut Formatter, without_time: bool, record: &Record) -> io::Result<()> {
if without_time {
writeln!(
fmt,
"[{}] [{}] {}",
record.level(),
record.module_path().unwrap_or("*"),
record.args()
)
} else {
writeln!(
fmt,
"[{}][{}] [{}] {}",
time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(),
record.level(),
record.module_path().unwrap_or("*"),
record.args()
)
}
}
fn main() {
let matches = App::new("shadowsocks")
.version(shadowsocks::VERSION)
.about("A fast tunnel proxy that helps you bypass firewalls.")
.arg(
Arg::with_name("VERBOSE")
.short("v")
.multiple(true)
.help("Set the level of debug"),
)
.arg(
Arg::with_name("ENABLE_UDP")
.short("u")
.long("enable-udp")
.help("Enable UDP relay"),
)
.arg(
Arg::with_name("CONFIG")
.short("c")
.long("config")
.takes_value(true)
.help("Specify config file"),
)
.arg(
Arg::with_name("SERVER_ADDR")
.short("s")
.long("server-addr")
.takes_value(true)
.help("Server address"),
)
.arg(
Arg::with_name("PASSWORD")
.short("k")
.long("password")
.takes_value(true)
.help("Password"),
)
.arg(
Arg::with_name("ENCRYPT_METHOD")
.short("m")
.long("encrypt-method")
.takes_value(true)
.help("Encryption method"),
)
.arg(
Arg::with_name("PLUGIN")
.long("plugin")
.takes_value(true)
.help("Enable SIP003 plugin"),
)
.arg(
Arg::with_name("PLUGIN_OPT")
.long("plugin-opts")
.takes_value(true)
.help("Set SIP003 plugin options"),
)
.arg(
Arg::with_name("LOG_WITHOUT_TIME")
.long("log-without-time")
.help("Disable time in log"),
)
.arg(
Arg::with_name("NO_DELAY")
.long("no-delay")
.takes_value(false)
.help("Set no-delay option for socket"),
)
.get_matches();
let mut log_builder = Builder::new();
log_builder.filter(None, LevelFilter::Info);
let without_time = matches.is_present("LOG_WITHOUT_TIME");
let debug_level = matches.occurrences_of("VERBOSE");
match debug_level {
0 => {
// Default filter
log_builder.format(move |fmt, r| log_time(fmt, without_time, r));
}
1 => {
let log_builder = log_builder.format(move |fmt, r| log_time_module(fmt, without_time, r));
log_builder.filter(Some("ssserver"), LevelFilter::Debug);
}
2 => {
let log_builder = log_builder.format(move |fmt, r| log_time_module(fmt, without_time, r));
log_builder
.filter(Some("ssserver"), LevelFilter::Debug)
.filter(Some("shadowsocks"), LevelFilter::Debug);
}
3 => {
let log_builder = log_builder.format(move |fmt, r| log_time_module(fmt, without_time, r));
log_builder
.filter(Some("ssserver"), LevelFilter::Trace)
.filter(Some("shadowsocks"), LevelFilter::Trace);
}
_ => {
let log_builder = log_builder.format(move |fmt, r| log_time_module(fmt, without_time, r));
log_builder.filter(None, LevelFilter::Trace);
}
}
if let Ok(env_conf) = env::var("RUST_LOG") {
log_builder.parse(&env_conf);
}
log_builder.init();
let mut has_provided_config = false;
let mut config = match matches.value_of("CONFIG") {
Some(cpath) => match Config::load_from_file(cpath, ConfigType::Server) {
Ok(cfg) => {
has_provided_config = true;
cfg
}
Err(err) => {
error!("{:?}", err);
return;
}
},
None => Config::new(),
};
let has_provided_server_config = match (
matches.value_of("SERVER_ADDR"),
matches.value_of("PASSWORD"),
matches.value_of("ENCRYPT_METHOD"),
) {
(Some(svr_addr), Some(password), Some(method)) => {
let method = match method.parse() {
Ok(m) => m,
Err(err) => {
panic!("Does not support {:?} method: {:?}", method, err);
}
};
let sc = ServerConfig::new(
svr_addr.parse::<ServerAddr>().expect("Invalid server addr"),
password.to_owned(),
method,
None,
None,
);
config.server.push(sc);
true
}
(None, None, None) => {
// Does not provide server config
false
}
_ => {
panic!("`server-addr`, `method` and `password` should be provided together");
}
};
if !has_provided_config && !has_provided_server_config {
println!("You have to specify a configuration file or pass arguments from argument list");
println!("{}", matches.usage());
return;
}
if matches.is_present("ENABLE_UDP") {
if config.mode.enable_tcp() {
config.mode = Mode::TcpAndUdp;
} else {
config.mode = Mode::UdpOnly;
}
}
if matches.is_present("NO_DELAY") {
config.no_delay = true;
}
if let Some(p) = matches.value_of("PLUGIN") {
let plugin = PluginConfig {
plugin: p.to_owned(),
plugin_opt: matches.value_of("PLUGIN_OPT").map(ToOwned::to_owned),
};
// Overrides config in file
for svr in config.server.iter_mut() {
svr.set_plugin(plugin.clone());
}
};
info!("ShadowSocks {}", shadowsocks::VERSION);
debug!("Config: {:?}", config);
let mut runtime = Runtime::new().expect("Creating runtime");
let result = runtime.block_on(run_server(config));
runtime.shutdown_now().wait().unwrap();
panic!("Server exited unexpectly with result: {:?}", result);
}