Migrate to std::future, async/await (#165)

* Socks5 library, main tcp relay implementation migrated with async/await

* UDP relay local migrated to async/await

* UDP relay server migrated to async/await

* Migrated UDP DNS to async/await, follows tokio-process

* Removed unused uses, add dyn keyword for TraitObjects

* [#151] Uses dl.google.com/generate_204 to check connection latency

* Make sslocal/ssserver TCP relay work successfully, disabled UDP and DNS relay temporary

* Handshake before performing actual read & write

* Wraps timeout logic into a Connection<S> struct

* Make UDP relay work again

* Local uses copy directly

* Completely removed unused ssdns

* Fixed test

* Uses tokio::main macro for main entrance

* Fixed a missing use in local.rs

* Updated travis openssl to 1.1.0L

* Windows signal

* Migrated tokio 0.2 release with std::future support

fix #173

* fixed windows monitor build

* Uses tokio on crates.io

* ctrl_c is a Future

* Run tests with single tokio runtime

* Uses spawn_blocking only with threaded runtime

* Killing all detached Tasks if server is exited

* Updated version to v1.8.0

* Removed unused pin-project

* Uses dns resolver built in tokio

* Explicitly uses threaded scheduler by default

* Reverted, it is threaded scheduler by default

* Updated bytes to v0.5

* Updated many dependencies

* Add a tunnel app (#175)

It can be used to benchmark.

Usage:
sstunnel -v -s 127.0.0.1:8488 -m plain -k password -b 127.0.0.1:1090 -f 127.0.0.1:5201

"-f xxx" : the target/forwad address xxx

* Removed unused remote-dns config field (ssdns is removed)

* Separated TCP local tunneling to its own module

* Implements FromStr for Address

* Fixed typo

* Add tunnel unit test

* Updated tokio to v0.2.2, fixed basic scheduler bug

* Removed Connection, uses try_timeout instead. Revert back to use 8K buffer

* Revert "Removed Connection, uses try_timeout instead. Revert back to use 8K buffer"

This reverts commit 82f698e520.

* Uses Delay instead of Timeout

* Delay doesnt return io::Result

* Revert "Delay doesnt return io::Result"

This reverts commit 74dc294d16.

* Fixed bug, Connection timeout should be shared between read & write operations
This commit is contained in:
Y. T. CHUNG
2019-12-01 12:20:39 +08:00
committed by GitHub
parent 39c5446524
commit a3b33f2614
56 changed files with 3809 additions and 4743 deletions
+31 -31
View File
@@ -1,45 +1,45 @@
sudo: false
language: rust
matrix:
include:
- os: windows
rust: stable
include:
- os: windows
rust: stable
- os: osx
rust: stable
- os: osx
rust: stable
- os: linux
rust: stable
- os: linux
rust: beta
- os: linux
rust: nightly
- os: linux
rust: stable
- os: linux
rust: beta
- os: linux
rust: nightly
env:
- RUSTFLAGS="-Ctarget-feature=+aes,+ssse3" RUSTDOCFLAGS="-Ctarget-feature=+aes,+ssse3" RUST_BACKTRACE=1
- RUSTFLAGS="-Ctarget-feature=+aes,+ssse3" RUSTDOCFLAGS="-Ctarget-feature=+aes,+ssse3" RUST_BACKTRACE=1
addons:
apt:
packages:
- libssl-dev
apt:
packages:
- libssl-dev
install:
#- wget https://github.com/jedisct1/libsodium/releases/download/1.0.16/libsodium-1.0.16.tar.gz
#- tar xvfz libsodium-1.0.16.tar.gz
#- cd libsodium-1.0.16 && ./configure --prefix=$HOME/installed_libsodium && make && make install && cd ..
#- export PKG_CONFIG_PATH=$HOME/installed_libsodium/lib/pkgconfig:$PKG_CONFIG_PATH
#- export LD_LIBRARY_PATH=$HOME/installed_libsodium/lib:$LD_LIBRARY_PATH
- export SODIUM_BUILD_STATIC=yes
#- wget https://github.com/jedisct1/libsodium/releases/download/1.0.16/libsodium-1.0.16.tar.gz
#- tar xvfz libsodium-1.0.16.tar.gz
#- cd libsodium-1.0.16 && ./configure --prefix=$HOME/installed_libsodium && make && make install && cd ..
#- export PKG_CONFIG_PATH=$HOME/installed_libsodium/lib/pkgconfig:$PKG_CONFIG_PATH
#- export LD_LIBRARY_PATH=$HOME/installed_libsodium/lib:$LD_LIBRARY_PATH
- export SODIUM_BUILD_STATIC=yes
# Install OpenSSL on Windows
- if [ "${TRAVIS_OS_NAME}" = "windows" ]; then
curl -O http://slproweb.com/download/Win64OpenSSL-1_1_0k.exe;
cmd.exe /C 'Win64OpenSSL-1_1_0k.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL"';
export OPENSSL_LIB_DIR=/c/OpenSSL/lib;
export OPENSSL_INCLUDE_DIR=/c/OpenSSL/include;
export OPENSSL_DIR=/c/OpenSSL/bin;
fi
# Install OpenSSL on Windows
- if [ "${TRAVIS_OS_NAME}" = "windows" ]; then
curl -O http://slproweb.com/download/Win64OpenSSL-1_1_0L.exe;
cmd.exe /C 'Win64OpenSSL-1_1_0L.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL"';
export OPENSSL_LIB_DIR=/c/OpenSSL/lib;
export OPENSSL_INCLUDE_DIR=/c/OpenSSL/include;
export OPENSSL_DIR=/c/OpenSSL/bin;
fi
script:
- cargo build
- cargo test --no-fail-fast --features miscreant
- cargo build
- cargo test --no-fail-fast --features miscreant
Generated
+1008 -846
View File
File diff suppressed because it is too large Load Diff
+24 -29
View File
@@ -1,6 +1,6 @@
[package]
name = "shadowsocks-rust"
version = "1.7.2"
version = "1.8.0"
authors = ["Y. T. CHUNG <zonyitoo@gmail.com>"]
description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls."
repository = "https://github.com/zonyitoo/shadowsocks-rust"
@@ -21,12 +21,12 @@ name = "ssserver"
path = "src/bin/server.rs"
[[bin]]
name = "ssurl"
path = "src/bin/ssurl.rs"
name = "sstunnel"
path = "src/bin/tunnel.rs"
[[bin]]
name = "ssdns"
path = "src/bin/ssdns.rs"
name = "ssurl"
path = "src/bin/ssurl.rs"
[profile.release]
lto = true
@@ -39,41 +39,36 @@ aes-cfb = ["openssl"]
aes-ctr = ["openssl"]
camellia-cfb = ["openssl"]
single-threaded = []
trust-dns = ["trust-dns-resolver"]
[dependencies]
log = "0.4"
byteorder = "1.3"
rand = "0.7"
time = "0.1"
clap = "2.33"
env_logger = "0.6"
env_logger = "0.7"
openssl = { version = "0.10", optional = true }
libc = "0.2"
futures = "0.1"
tokio-io = "0.1"
tokio = "0.1"
tokio = { version = "0.2", features = ["full"] }
futures = "0.3"
json5 = "0.2"
base64 = "0.10"
bytes = "0.4"
ring = "0.14"
base64 = "0.11"
bytes = "0.5"
byteorder = "1"
ring = "0.16"
md-5 = "0.8"
digest = "0.8"
typenum = "1.10"
qrcode = { version = "0.10", default-features = false }
serde_urlencoded = "0.5"
typenum = "1.11"
qrcode = { version = "0.11", default-features = false }
serde_urlencoded = "0.6"
serde = { version = "1.0", features = ["derive"] }
url = "2.0"
url = "2.1"
byte_string = "1.0"
libsodium-ffi = { version = "0.1", optional = true }
# libsodium-ffi = { version = "0.1", optional = true }
libsodium-ffi = { git = "https://github.com/zonyitoo/libsodium-ffi", optional = true }
miscreant = { version = "0.4", optional = true }
lru-cache = "0.1"
dns-parser = "0.8"
trust-dns-resolver = { version = "0.11", features = ["dns-over-rustls", "dns-over-https-rustls"] }
spin = { version = "0.5", default-features = false }
tokio-process = "0.2"
[target.'cfg(unix)'.dependencies]
tokio-signal = "0.2"
[target.'cfg(windows)'.dependencies]
tokio-signal = "0.2"
# trust-dns-resolver = { version = "0.11", features = ["dns-over-rustls", "dns-over-https-rustls"] }
trust-dns-resolver = { git = "https://github.com/bluejekyll/trust-dns", features = ["dns-over-rustls", "dns-over-https-rustls"], optional = true }
hkdf = "0.8"
hmac = "0.7"
sha-1 = "0.8"
+12 -47
View File
@@ -4,22 +4,23 @@
//! or you could specify a configuration file. The format of configuration file is defined
//! in mod `config`.
use std::{io::Result as IoResult, net::SocketAddr, process};
use clap::{App, Arg};
use futures::{future::Either, Future};
use futures::{
future::{self, Either},
FutureExt,
};
use log::{debug, error, info};
#[cfg(feature = "single-threaded")]
use tokio::runtime::current_thread::Runtime;
#[cfg(not(feature = "single-threaded"))]
use tokio::runtime::Runtime;
use std::net::SocketAddr;
use tokio;
use shadowsocks::{plugin::PluginConfig, run_local, Config, ConfigType, Mode, ServerAddr, ServerConfig};
mod logging;
mod monitor;
fn main() {
#[cfg_attr(feature = "single-threaded", tokio::main(basic_scheduler))]
#[cfg_attr(not(feature = "single-threaded"), tokio::main)]
async fn main() {
let matches = App::new("shadowsocks")
.version(shadowsocks::VERSION)
.about("A fast tunnel proxy that helps you bypass firewalls.")
@@ -207,47 +208,11 @@ fn main() {
debug!("Config: {:?}", config);
match launch_server(config) {
Ok(()) => {}
Err(err) => {
error!("Server exited unexpectly with error: {}", err);
process::exit(1);
}
}
}
#[cfg(feature = "single-threaded")]
fn launch_server(config: Config) -> IoResult<()> {
let mut runtime = Runtime::new().expect("Creating runtime");
let abort_signal = monitor::create_signal_monitor();
let result = runtime.block_on(run_local(config).select2(abort_signal));
match result {
match future::select(run_local(config).boxed(), abort_signal.boxed()).await {
// Server future resolved without an error. This should never happen.
Ok(Either::A(_)) => panic!("Server exited unexpectly"),
// Server future resolved with an error.
Err(Either::A((err, _))) => Err(err),
Either::Left(_) => panic!("Server exited unexpectly"),
// The abort signal future resolved. Means we should just exit.
Ok(Either::B(..)) | Err(Either::B(..)) => Ok(()),
}
}
#[cfg(not(feature = "single-threaded"))]
fn launch_server(config: Config) -> IoResult<()> {
let mut runtime = Runtime::new().expect("Creating runtime");
let abort_signal = monitor::create_signal_monitor();
let result = runtime.block_on(run_local(config).select2(abort_signal));
runtime.shutdown_now().wait().unwrap();
match result {
// Server future resolved without an error. This should never happen.
Ok(Either::A(_)) => panic!("Server exited unexpectly"),
// Server future resolved with an error.
Err(Either::A((err, _))) => Err(err),
// The abort signal future resolved. Means we should just exit.
Ok(Either::B(..)) | Err(Either::B(..)) => Ok(()),
Either::Right(_) => (),
}
}
+3 -4
View File
@@ -1,9 +1,8 @@
use std::env;
use std::io::{self, Write};
use env_logger::{fmt::Formatter, Builder};
use log::{LevelFilter, Record};
use std::{
env,
io::{self, Write},
};
pub fn init(without_time: bool, debug_level: u64, bin_name: &str) {
let mut log_builder = Builder::new();
+3 -3
View File
@@ -1,8 +1,8 @@
use futures::{self, Future};
use futures;
use std::io;
pub fn create_signal_monitor() -> impl Future<Item = (), Error = io::Error> + Send {
pub async fn create_signal_monitor() -> io::Result<()> {
// FIXME: What can I do ...
// Blocks forever
futures::empty::<(), io::Error>()
futures::empty::<(), io::Error>().await
}
+14 -29
View File
@@ -1,34 +1,19 @@
use futures::{Future, Stream};
use libc;
use log::{error, info};
use futures::future::{self, Either, FutureExt};
use log::info;
use std::io;
use tokio_signal::unix::Signal;
use tokio::signal::unix::{signal, SignalKind};
pub fn create_signal_monitor() -> impl Future<Item = (), Error = io::Error> + Send {
pub async fn create_signal_monitor() -> io::Result<()> {
// Future resolving to two signal streams. Can fail if setting up signal monitoring fails
let signals_future = Signal::new(libc::SIGTERM).join(Signal::new(libc::SIGINT));
let mut sigterm = signal(SignalKind::terminate())?;
let mut sigint = signal(SignalKind::interrupt())?;
signals_future
// The future resolved into our two streams of signals
.and_then(|(sigterms, sigints)| {
// Stream of all signals we care about
let signals = sigterms.select(sigints);
// Take only the first signal in the stream and log that it was triggered
signals.take(1).for_each(|signal| {
let signal_name = match signal {
libc::SIGTERM => "SIGTERM",
libc::SIGINT => "SIGINT",
_ => unreachable!(),
};
info!("Received {}, exiting", signal_name);
Ok(())
}).map_err(|error| {
error!("Error while listening on process signals: {:?}", error);
error
})
})
.map_err(|error| {
error!("Failed to set up process signal monitoring: {:?}", error);
error
})
let signal_name = match future::select(sigterm.recv().boxed(), sigint.recv().boxed()).await {
Either::Left(..) => "SIGTERM",
Either::Right(..) => "SIGINT",
};
info!("Received {}, exiting", signal_name);
Ok(())
}
+15 -31
View File
@@ -1,35 +1,19 @@
use futures::{self, Future, Stream};
use log::{error, info};
use futures::future::{self, Either, FutureExt};
use futures::StreamExt;
use log::info;
use std::io;
use tokio_signal::windows::Event;
use tokio::signal::{ctrl_c, windows::ctrl_break};
pub fn create_signal_monitor() -> impl Future<Item = (), Error = io::Error> + Send {
// Must be wrapped with a future, because when `Event` is being created, it will spawn
// a task into the current executor. So if there is no current running executor, thread
// will panic.
let events = futures::lazy(|| {
Event::ctrl_c()
.join(Event::ctrl_break())
.and_then(|(c_signals, break_signals)| {
// Stream of all signals we care about
let signals = c_signals.select(break_signals);
// Take only the first signal in the stream and log that it was triggered
signals
.take(1)
.for_each(|()| {
info!("Received shutdown signal, exiting");
Ok(())
})
.map_err(|error| {
error!("Error while listening on process signals: {:?}", error);
error
})
})
.map_err(|error| {
error!("Failed to set up process signal monitoring: {:?}", error);
error
})
});
pub async fn create_signal_monitor() -> io::Result<()> {
let cc = ctrl_c();
let cb = ctrl_break()?;
events
let signal_name = match future::select(cc.boxed(), cb.into_future().boxed()).await {
Either::Left(..) => "CTRL-C",
Either::Right(..) => "CTRL-BREAK",
};
info!("Received {}, exiting", signal_name);
Ok(())
}
+11 -47
View File
@@ -7,22 +7,22 @@
//! *It should be notice that the extented configuration file is not suitable for the server
//! side.*
use std::{io::Result as IoResult, process};
use clap::{App, Arg};
use futures::{future::Either, Future};
use futures::{
future::{self, Either},
FutureExt,
};
use log::{debug, error, info};
#[cfg(feature = "single-threaded")]
use tokio::runtime::current_thread::Runtime;
#[cfg(not(feature = "single-threaded"))]
use tokio::runtime::Runtime;
use tokio;
use shadowsocks::{plugin::PluginConfig, run_server, Config, ConfigType, Mode, ServerAddr, ServerConfig};
mod logging;
mod monitor;
fn main() {
#[cfg_attr(feature = "single-threaded", tokio::main(basic_scheduler))]
#[cfg_attr(not(feature = "single-threaded"), tokio::main)]
async fn main() {
let matches = App::new("shadowsocks")
.version(shadowsocks::VERSION)
.about("A fast tunnel proxy that helps you bypass firewalls.")
@@ -191,47 +191,11 @@ fn main() {
debug!("Config: {:?}", config);
match launch_server(config) {
Ok(()) => {}
Err(err) => {
error!("Server exited unexpectly with error: {}", err);
process::exit(1);
}
}
}
#[cfg(not(feature = "single-threaded"))]
fn launch_server(config: Config) -> IoResult<()> {
let mut runtime = Runtime::new().expect("Creating runtime");
let abort_signal = monitor::create_signal_monitor();
let result = runtime.block_on(run_server(config).select2(abort_signal));
runtime.shutdown_now().wait().unwrap();
match result {
match future::select(run_server(config).boxed(), abort_signal.boxed()).await {
// Server future resolved without an error. This should never happen.
Ok(Either::A(_)) => panic!("Server exited unexpectly"),
// Server future resolved with an error.
Err(Either::A((err, _))) => Err(err),
Either::Left(_) => panic!("Server exited unexpectly"),
// The abort signal future resolved. Means we should just exit.
Ok(Either::B(..)) | Err(Either::B(..)) => Ok(()),
}
}
#[cfg(feature = "single-threaded")]
fn launch_server(config: Config) -> IoResult<()> {
let mut runtime = Runtime::new().expect("Creating runtime");
let abort_signal = monitor::create_signal_monitor();
let result = runtime.block_on(run_server(config).select2(abort_signal));
match result {
// Server future resolved without an error. This should never happen.
Ok(Either::A(_)) => panic!("Server exited unexpectly"),
// Server future resolved with an error.
Err(Either::A((err, _))) => Err(err),
// The abort signal future resolved. Means we should just exit.
Ok(Either::B(..)) | Err(Either::B(..)) => Ok(()),
Either::Right(_) => (),
}
}
+86 -27
View File
@@ -1,26 +1,39 @@
//! DNS over shadowsocks
use std::net::SocketAddr;
//! This is a binary running in the local 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`.
use clap::{App, Arg};
use futures::Future;
use futures::{
future::{self, Either},
FutureExt,
};
use log::{debug, error, info};
use tokio::runtime::Runtime;
use std::net::SocketAddr;
use tokio;
use shadowsocks::{run_dns, Config, ConfigType, ServerAddr, ServerConfig};
use shadowsocks::plugin::PluginConfig;
use shadowsocks::relay::socks5::Address;
use shadowsocks::{run_local, Config, ConfigType, Mode, ServerAddr, ServerConfig};
mod logging;
mod monitor;
fn main() {
let matches = App::new("ssdns")
#[cfg_attr(feature = "single-threaded", tokio::main(basic_scheduler))]
#[cfg_attr(not(feature = "single-threaded"), tokio::main)]
async fn main() {
let matches = App::new("shadowsocks")
.version(shadowsocks::VERSION)
.about("A DNS proxy that helps you bypass firewalls.")
.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("UDP_ONLY").short("u").help("Server mode UDP_ONLY"))
.arg(Arg::with_name("TCP_AND_UDP").short("U").help("Server mode TCP_AND_UDP"))
.arg(
Arg::with_name("CONFIG")
.short("c")
@@ -42,6 +55,13 @@ fn main() {
.takes_value(true)
.help("Local address, listen only to this address if specified"),
)
.arg(
Arg::with_name("FORWARD_ADDR")
.short("f")
.long("foward-addr")
.takes_value(true)
.help("Forward address, forward to this address"),
)
.arg(
Arg::with_name("PASSWORD")
.short("k")
@@ -56,6 +76,18 @@ fn main() {
.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")
@@ -68,17 +100,17 @@ fn main() {
.help("Server address in SIP002 URL"),
)
.arg(
Arg::with_name("REMOTE_DNS")
.long("remote-dns")
.takes_value(true)
.help("Remote DNS server, default is 8.8.8.8:53"),
Arg::with_name("NO_DELAY")
.long("no-delay")
.takes_value(false)
.help("Set no-delay option for socket"),
)
.get_matches();
let without_time = matches.is_present("LOG_WITHOUT_TIME");
let debug_level = matches.occurrences_of("VERBOSE");
logging::init(without_time, debug_level, "ssdns");
logging::init(without_time, debug_level, "sslocal");
let mut has_provided_config = false;
@@ -153,22 +185,49 @@ fn main() {
return;
}
if let Some(dns) = matches.value_of("REMOTE_DNS") {
let dns_addr = dns
.parse::<SocketAddr>()
.expect("`remote-dns` is not a valid SocketAddr, must be IP:Port");
config.remote_dns = Some(dns_addr);
if let Some(url) = matches.value_of("FORWARD_ADDR") {
let forward_addr = url.parse::<Address>().expect("Failed to parse `url`");
config.forward = Some(forward_addr);
}
info!("ShadowSocks DNS {}", shadowsocks::VERSION);
if matches.is_present("UDP_ONLY") {
if config.mode.enable_tcp() {
config.mode = Mode::TcpAndUdp;
} else {
config.mode = Mode::UdpOnly;
}
}
if matches.is_present("TCP_AND_UDP") {
config.mode = Mode::TcpAndUdp;
}
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_dns(config));
runtime.shutdown_now().wait().unwrap();
panic!("Server exited unexpectly with result: {:?}", result);
let abort_signal = monitor::create_signal_monitor();
match future::select(run_local(config).boxed(), abort_signal.boxed()).await {
// Server future resolved without an error. This should never happen.
Either::Left(_) => panic!("Server exited unexpectly"),
// The abort signal future resolved. Means we should just exit.
Either::Right(_) => (),
}
}
+30 -46
View File
@@ -41,32 +41,33 @@
//!
//! These defined server will be used with a load balancing algorithm.
use std::{
collections::HashSet,
convert::From,
default::Default,
error,
fmt::{self, Debug, Display, Formatter},
fs::OpenOptions,
io::Read,
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
option::Option,
path::Path,
str::FromStr,
string::ToString,
time::Duration,
};
use std::collections::HashSet;
use std::convert::From;
use std::default::Default;
use std::error;
use std::fmt::{self, Debug, Display, Formatter};
use std::fs::OpenOptions;
use std::io::Read;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::option::Option;
use std::path::Path;
use std::str::FromStr;
use std::string::ToString;
use std::time::Duration;
use base64::{decode_config, encode_config, URL_SAFE_NO_PAD};
use bytes::Bytes;
use json5;
use log::{error, trace};
use log::error;
use serde::{Deserialize, Serialize};
use serde_urlencoded;
#[cfg(feature = "trust-dns")]
use trust_dns_resolver::config::{NameServerConfigGroup, ResolverConfig};
use url::{self, Url};
use crate::{crypto::cipher::CipherType, plugin::PluginConfig};
use crate::crypto::cipher::CipherType;
use crate::plugin::PluginConfig;
use crate::relay::socks5::Address;
#[derive(Serialize, Deserialize, Debug, Default)]
struct SSConfig {
@@ -97,8 +98,6 @@ struct SSConfig {
#[serde(skip_serializing_if = "Option::is_none")]
dns: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
remote_dns: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
mode: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
no_delay: Option<bool>,
@@ -220,7 +219,6 @@ impl ServerConfig {
plugin: Option<PluginConfig>,
) -> ServerConfig {
let enc_key = method.bytes_to_key(pwd.as_bytes());
trace!("Initialize config with pwd: {:?}, key: {:?}", pwd, enc_key);
ServerConfig {
addr,
password: pwd,
@@ -461,9 +459,9 @@ impl error::Error for UrlParseError {
}
}
fn cause(&self) -> Option<&error::Error> {
fn cause(&self) -> Option<&dyn error::Error> {
match *self {
UrlParseError::ParseError(ref err) => Some(err as &error::Error),
UrlParseError::ParseError(ref err) => Some(err as &dyn error::Error),
UrlParseError::InvalidScheme => None,
UrlParseError::InvalidUserInfo => None,
UrlParseError::MissingHost => None,
@@ -540,9 +538,9 @@ impl FromStr for Mode {
pub struct Config {
pub server: Vec<ServerConfig>,
pub local: Option<ClientConfig>,
pub forward: Option<Address>,
pub forbidden_ip: HashSet<IpAddr>,
pub dns: Option<String>,
pub remote_dns: Option<SocketAddr>,
pub mode: Mode,
pub no_delay: bool,
pub manager_address: Option<ServerAddr>,
@@ -600,9 +598,9 @@ impl Config {
Config {
server: Vec::new(),
local: None,
forward: None,
forbidden_ip: HashSet::new(),
dns: None,
remote_dns: None,
mode: Mode::TcpOnly,
no_delay: false,
manager_address: None,
@@ -761,20 +759,6 @@ impl Config {
// DNS
nconfig.dns = config.dns;
if let Some(rdns) = config.remote_dns {
match rdns.parse::<SocketAddr>() {
Ok(r) => nconfig.remote_dns = Some(r),
Err(..) => {
let e = Error::new(
ErrorKind::Malformed,
"malformed `remote_dns`, which must be a valid SocketAddr",
None,
);
return Err(e);
}
}
}
// Mode
if let Some(m) = config.mode {
match m.parse::<Mode>() {
@@ -810,6 +794,7 @@ impl Config {
Config::load_from_str(&content[..], config_type)
}
#[cfg(feature = "trust-dns")]
pub fn get_dns_config(&self) -> Option<ResolverConfig> {
self.dns.as_ref().and_then(|ds| {
match &ds[..] {
@@ -843,11 +828,14 @@ impl Config {
})
}
pub fn get_remote_dns(&self) -> SocketAddr {
match self.remote_dns {
None => SocketAddr::from(SocketAddrV4::new(Ipv4Addr::new(8, 8, 8, 8), 53)),
Some(ip) => ip,
/// Check if there are any plugin are enabled with servers
pub fn has_server_plugins(&self) -> bool {
for server in &self.server {
if server.plugin().is_some() {
return true;
}
}
false
}
}
@@ -922,10 +910,6 @@ impl fmt::Display for Config {
jconf.dns = Some(dns.to_string());
}
if let Some(ref remote_dns) = self.remote_dns {
jconf.remote_dns = Some(remote_dns.to_string());
}
write!(f, "{}", json5::to_string(&jconf).unwrap())
}
}
+62 -28
View File
@@ -1,59 +1,93 @@
//! Shadowsocks Server Context
use std::{
net::SocketAddr,
sync::{Arc, Mutex, MutexGuard},
time::Instant,
};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use lru_cache::LruCache;
#[cfg(futures = "trust-dns")]
use trust_dns_resolver::AsyncResolver;
use crate::{config::Config, relay::dns_resolver::create_resolver};
use crate::config::Config;
type DnsQueryCache = LruCache<u16, (SocketAddr, Instant)>;
#[cfg(futures = "trust-dns")]
use crate::relay::dns_resolver::create_resolver;
#[derive(Clone)]
pub struct Context {
config: Config,
pub struct SharedServerState {
#[cfg(futures = "trust-dns")]
dns_resolver: Arc<AsyncResolver>,
dns_query_cache: Option<Arc<Mutex<DnsQueryCache>>>,
server_running: Arc<AtomicBool>,
}
impl SharedServerState {
#[allow(unused_variables)]
pub fn new(config: &Config) -> SharedServerState {
SharedServerState {
#[cfg(futures = "trust-dns")]
dns_resolver: Arc::new(create_resolver(config.get_dns_config())),
server_running: Arc::new(AtomicBool::new(true)),
}
}
/// Check if the server is still in running state
pub fn server_running(&self) -> bool {
self.server_running.load(Ordering::Acquire)
}
/// Stops the server, kills all detached running tasks
pub fn server_stopped(&self) {
self.server_running.store(false, Ordering::Release)
}
/// Get the global shared resolver
#[cfg(futures = "trust-dns")]
pub fn dns_resolver(&self) -> &AsyncResolver {
&*self.dns_resolver
}
}
/// Shared basic configuration for the whole server
pub struct Context {
config: Config,
server_state: SharedServerState,
}
/// Unique context thw whole server
pub type SharedContext = Arc<Context>;
impl Context {
pub fn new(config: Config) -> Context {
let resolver = create_resolver(config.get_dns_config());
Context {
config,
dns_resolver: Arc::new(resolver),
dns_query_cache: None,
}
pub fn new(config: Config, server_state: SharedServerState) -> Context {
Context { config, server_state }
}
pub fn new_dns(config: Config) -> Context {
let resolver = create_resolver(config.get_dns_config());
Context {
config,
dns_resolver: Arc::new(resolver),
dns_query_cache: Some(Arc::new(Mutex::new(LruCache::new(1024)))),
}
pub fn new_shared(config: Config, server_state: SharedServerState) -> SharedContext {
SharedContext::new(Context::new(config, server_state))
}
/// Config for TCP server
pub fn config(&self) -> &Config {
&self.config
}
/// Mutable Config for TCP server
///
/// NOTE: Only for launching plugins
pub fn config_mut(&mut self) -> &mut Config {
&mut self.config
}
/// Get the global shared resolver
#[cfg(futures = "trust-dns")]
pub fn dns_resolver(&self) -> &AsyncResolver {
&*self.dns_resolver
self.server_state.dns_resolver()
}
pub fn dns_query_cache(&self) -> MutexGuard<DnsQueryCache> {
self.dns_query_cache.as_ref().unwrap().lock().unwrap()
/// Check if the server is still in running state
pub fn server_running(&self) -> bool {
self.server_state.server_running()
}
/// Stops the server, kills all detached running tasks
pub fn server_stopped(&self) {
self.server_state.server_stopped()
}
}
+4 -3
View File
@@ -9,7 +9,8 @@ use crate::crypto::siv::MiscreantCipher;
use crate::crypto::sodium::SodiumAeadCipher;
use bytes::{Bytes, BytesMut};
use ring::{digest::SHA1, hkdf, hmac::SigningKey};
use hkdf::Hkdf;
use sha1::Sha1;
/// Encryptor API for AEAD ciphers
pub trait AeadEncryptor {
@@ -110,14 +111,14 @@ const SUBKEY_INFO: &[u8] = b"ss-subkey";
pub fn make_skey(t: CipherType, key: &[u8], salt: &[u8]) -> Bytes {
assert!(t.category() == CipherCategory::Aead);
let salt = SigningKey::new(&SHA1, salt);
let hkdf = Hkdf::<Sha1>::new(Some(salt), key);
let mut skey = BytesMut::with_capacity(key.len());
unsafe {
skey.set_len(key.len());
}
hkdf::extract_and_expand(&salt, key, SUBKEY_INFO, &mut skey);
hkdf.expand(SUBKEY_INFO, &mut skey).unwrap();
skey.freeze()
}
+7 -7
View File
@@ -1,7 +1,7 @@
//! Message digest algorithm
use md5::Md5;
use ring::digest::{Context, SHA1, SHA1_OUTPUT_LEN};
use sha1::Sha1;
use bytes::BufMut;
@@ -32,14 +32,14 @@ pub enum DigestType {
pub fn with_type(t: DigestType) -> DigestVariant {
match t {
DigestType::Md5 => DigestVariant::Md5(Md5::default()),
DigestType::Sha1 | DigestType::Sha => DigestVariant::Sha1(Context::new(&SHA1)),
DigestType::Sha1 | DigestType::Sha => DigestVariant::Sha1(Sha1::default()),
}
}
/// Variant of supported digest
pub enum DigestVariant {
Md5(Md5),
Sha1(Context),
Sha1(Sha1),
}
impl Digest for DigestVariant {
@@ -48,7 +48,7 @@ impl Digest for DigestVariant {
match *self {
DigestVariant::Md5(ref mut d) => d.input(data),
DigestVariant::Sha1(ref mut d) => d.update(data),
DigestVariant::Sha1(ref mut d) => d.input(data),
}
}
@@ -57,7 +57,7 @@ impl Digest for DigestVariant {
match *self {
DigestVariant::Md5(ref d) => buf.put(&*d.clone().result()),
DigestVariant::Sha1(ref d) => buf.put(d.clone().finish().as_ref()),
DigestVariant::Sha1(ref d) => buf.put(&*d.clone().result()),
}
}
@@ -67,14 +67,14 @@ impl Digest for DigestVariant {
match *self {
DigestVariant::Md5(_) => <Md5 as FixedOutput>::OutputSize::to_usize(),
DigestVariant::Sha1(_) => SHA1_OUTPUT_LEN,
DigestVariant::Sha1(_) => <Md5 as FixedOutput>::OutputSize::to_usize(),
}
}
fn reset(&mut self) {
match *self {
DigestVariant::Md5(ref mut d) => d.clone_from(&Md5::default()),
DigestVariant::Sha1(ref mut d) => d.clone_from(&Context::new(&SHA1)),
DigestVariant::Sha1(ref mut d) => d.clone_from(&Sha1::default()),
}
}
}
+2 -2
View File
@@ -10,12 +10,12 @@ use bytes::BufMut;
pub struct DummyCipher;
impl StreamCipher for DummyCipher {
fn update(&mut self, data: &[u8], out: &mut BufMut) -> CipherResult<()> {
fn update(&mut self, data: &[u8], out: &mut dyn BufMut) -> CipherResult<()> {
out.put_slice(data);
Ok(())
}
fn finalize(&mut self, _: &mut BufMut) -> CipherResult<()> {
fn finalize(&mut self, _: &mut dyn BufMut) -> CipherResult<()> {
Ok(())
}
+4 -4
View File
@@ -109,7 +109,7 @@ impl OpenSSLCrypto {
}
/// Update data
pub fn update(&mut self, data: &[u8], out: &mut BufMut) -> CipherResult<()> {
pub fn update(&mut self, data: &[u8], out: &mut dyn BufMut) -> CipherResult<()> {
let least_reserved = data.len() + self.cipher.block_size();
let mut buf = BytesMut::with_capacity(least_reserved); // NOTE: len() is 0 now!
unsafe {
@@ -122,7 +122,7 @@ impl OpenSSLCrypto {
}
/// Generate the final block
pub fn finalize(&mut self, out: &mut BufMut) -> CipherResult<()> {
pub fn finalize(&mut self, out: &mut dyn BufMut) -> CipherResult<()> {
let least_reserved = self.cipher.block_size();
let mut buf = BytesMut::with_capacity(least_reserved); // NOTE: len() is 0 now!
unsafe {
@@ -185,11 +185,11 @@ impl OpenSSLCipher {
unsafe impl Send for OpenSSLCipher {}
impl StreamCipher for OpenSSLCipher {
fn update(&mut self, data: &[u8], out: &mut BufMut) -> CipherResult<()> {
fn update(&mut self, data: &[u8], out: &mut dyn BufMut) -> CipherResult<()> {
self.worker.update(data, out)
}
fn finalize(&mut self, out: &mut BufMut) -> CipherResult<()> {
fn finalize(&mut self, out: &mut dyn BufMut) -> CipherResult<()> {
self.worker.finalize(out)
}
+2 -2
View File
@@ -28,11 +28,11 @@ impl Rc4Md5Cipher {
}
impl StreamCipher for Rc4Md5Cipher {
fn update(&mut self, data: &[u8], out: &mut BufMut) -> CipherResult<()> {
fn update(&mut self, data: &[u8], out: &mut dyn BufMut) -> CipherResult<()> {
self.crypto.update(data, out)
}
fn finalize(&mut self, out: &mut BufMut) -> CipherResult<()> {
fn finalize(&mut self, out: &mut dyn BufMut) -> CipherResult<()> {
self.crypto.finalize(out)
}
+58 -84
View File
@@ -1,9 +1,11 @@
//! Cipher defined with Ring
use std::{mem, ptr};
use ring::aead::{
open_in_place, seal_in_place, Aad, Nonce, OpeningKey, SealingKey, AES_128_GCM, AES_256_GCM, CHACHA20_POLY1305,
use ring::{
aead::{
Aad, Algorithm, Nonce, NonceSequence, OpeningKey, SealingKey, UnboundKey, AES_128_GCM, AES_256_GCM,
CHACHA20_POLY1305, NONCE_LEN,
},
error::Unspecified,
};
use crate::crypto::{
@@ -13,13 +15,33 @@ use crate::crypto::{
};
use byte_string::ByteStr;
use bytes::{BufMut, Bytes, BytesMut};
use bytes::{BufMut, BytesMut};
use log::error;
/// AEAD ciphers provided by Ring
pub enum RingAeadCryptoVariant {
Seal(SealingKey, Bytes),
Open(OpeningKey, Bytes),
Seal(SealingKey<RingAeadNonceSequence>),
Open(OpeningKey<RingAeadNonceSequence>),
}
pub struct RingAeadNonceSequence {
nonce: [u8; NONCE_LEN],
}
impl RingAeadNonceSequence {
fn new() -> RingAeadNonceSequence {
RingAeadNonceSequence {
nonce: [0u8; NONCE_LEN],
}
}
}
impl NonceSequence for RingAeadNonceSequence {
fn advance(&mut self) -> Result<Nonce, Unspecified> {
let nonce = Nonce::assume_unique_for_key(self.nonce);
increase_nonce(&mut self.nonce);
Ok(nonce)
}
}
/// AEAD Cipher context
@@ -28,8 +50,6 @@ pub enum RingAeadCryptoVariant {
pub struct RingAeadCipher {
cipher: RingAeadCryptoVariant,
cipher_type: CipherType,
key: Bytes,
nonce: BytesMut,
}
impl RingAeadCipher {
@@ -37,57 +57,34 @@ impl RingAeadCipher {
pub fn new(t: CipherType, key: &[u8], salt: &[u8], is_seal: bool) -> RingAeadCipher {
// TODO: Check if salt is duplicated
let nonce_size = t.iv_size();
let mut nonce = BytesMut::with_capacity(nonce_size);
unsafe {
nonce.set_len(nonce_size);
ptr::write_bytes(nonce.as_mut_ptr(), 0, nonce_size);
}
// Nonce is 12 bytes
assert_eq!(t.iv_size(), NONCE_LEN);
let skey = make_skey(t, key, salt);
let cipher = RingAeadCipher::new_variant(t, &skey, &nonce, is_seal);
RingAeadCipher {
cipher,
cipher_type: t,
key: skey,
nonce,
}
let cipher = RingAeadCipher::new_variant(t, &skey, is_seal);
RingAeadCipher { cipher, cipher_type: t }
}
fn new_variant(t: CipherType, key: &[u8], nonce: &[u8], is_seal: bool) -> RingAeadCryptoVariant {
macro_rules! seal_or_open {
($item:ident, $key:ident, $crypt:ident) => {
RingAeadCryptoVariant::$item($key::new(&$crypt, key).unwrap(), Bytes::from(nonce))
};
($crypt:ident) => {
if is_seal {
seal_or_open!(Seal, SealingKey, $crypt)
} else {
seal_or_open!(Open, OpeningKey, $crypt)
}
};
}
fn new_variant(t: CipherType, key: &[u8], is_seal: bool) -> RingAeadCryptoVariant {
match t {
CipherType::Aes128Gcm => seal_or_open!(AES_128_GCM),
CipherType::Aes256Gcm => seal_or_open!(AES_256_GCM),
CipherType::ChaCha20IetfPoly1305 => seal_or_open!(CHACHA20_POLY1305),
CipherType::Aes128Gcm => RingAeadCipher::new_crypt(&AES_128_GCM, key, is_seal),
CipherType::Aes256Gcm => RingAeadCipher::new_crypt(&AES_256_GCM, key, is_seal),
CipherType::ChaCha20IetfPoly1305 => RingAeadCipher::new_crypt(&CHACHA20_POLY1305, key, is_seal),
_ => panic!("unsupported cipher in ring {:?}", t),
}
}
fn increase_nonce(&mut self) {
increase_nonce(&mut self.nonce);
}
#[inline]
fn new_crypt(algorithm: &'static Algorithm, key: &[u8], is_seal: bool) -> RingAeadCryptoVariant {
use ring::aead::BoundKey;
fn reset(&mut self) {
self.increase_nonce();
let is_seal = match self.cipher {
RingAeadCryptoVariant::Seal(..) => true,
RingAeadCryptoVariant::Open(..) => false,
};
let var = RingAeadCipher::new_variant(self.cipher_type, &self.key, &self.nonce, is_seal);
mem::replace(&mut self.cipher, var);
let unbound_key = UnboundKey::new(algorithm, key).unwrap();
if is_seal {
RingAeadCryptoVariant::Seal(SealingKey::new(unbound_key, RingAeadNonceSequence::new()))
} else {
RingAeadCryptoVariant::Open(OpeningKey::new(unbound_key, RingAeadNonceSequence::new()))
}
}
}
@@ -99,26 +96,14 @@ impl AeadEncryptor for RingAeadCipher {
let mut buf = BytesMut::with_capacity(output.len());
buf.put_slice(input);
unsafe {
buf.set_len(output.len());
}
if let RingAeadCryptoVariant::Seal(ref key, ref nonce) = self.cipher {
seal_in_place(
key,
Nonce::try_assume_unique_for_key(nonce).expect("AEAD cipher nonce length not match"),
Aad::empty(),
&mut buf,
tag_len,
)
.unwrap();
if let RingAeadCryptoVariant::Seal(ref mut key) = self.cipher {
key.seal_in_place_append_tag(Aad::empty(), &mut buf).unwrap();
} else {
unreachable!("encrypt is called on a non-seal cipher");
}
output.copy_from_slice(&buf);
self.reset();
output.copy_from_slice(&buf[..buf_len]);
}
}
@@ -130,36 +115,25 @@ impl AeadDecryptor for RingAeadCipher {
let mut buf = BytesMut::with_capacity(input.len());
buf.put_slice(input);
let r = if let RingAeadCryptoVariant::Open(ref key, ref nonce) = self.cipher {
match open_in_place(
key,
Nonce::try_assume_unique_for_key(nonce).expect("AEAD cipher nonce length not match"),
Aad::empty(),
0,
&mut buf,
) {
if let RingAeadCryptoVariant::Open(ref mut key) = self.cipher {
match key.open_in_place(Aad::empty(), &mut buf) {
Ok(obuf) => {
output.copy_from_slice(obuf);
Ok(())
}
Err(err) => {
Err(..) => {
error!(
"AEAD decrypt failed, nonce={:?}, input={:?}, tag={:?}, err: {:?}",
ByteStr::new(nonce),
ByteStr::new(&input[..tag_len]),
ByteStr::new(&input[tag_len..]),
err
"AEAD decrypt failed, input={:?}, tag={:?}, opening: {:?}",
ByteStr::new(&input[..output.len()]),
ByteStr::new(&input[output.len()..]),
key,
);
Err(Error::AeadDecryptFailed)
}
}
} else {
unreachable!("decrypt is called on a non-open cipher");
};
self.reset();
r
}
}
}
+10 -13
View File
@@ -1,9 +1,6 @@
//! Cipher defined with libsodium
use std::{
ptr,
sync::{Once, ONCE_INIT},
};
use std::{ptr, sync::Once};
use bytes::{BufMut, Bytes, BytesMut};
@@ -20,7 +17,7 @@ use crate::crypto::{
AeadDecryptor, AeadEncryptor, CipherResult, CipherType, StreamCipher,
};
static SODIUM_INIT_FLAG: Once = ONCE_INIT;
static SODIUM_INIT_FLAG: Once = Once::new();
/// Cipher provided by `libsodium`
pub struct SodiumStreamCipher {
@@ -56,7 +53,7 @@ impl SodiumStreamCipher {
self.counter % SODIUM_BLOCK_SIZE
}
fn process(&mut self, data: &[u8], out: &mut BufMut) -> CipherResult<()> {
fn process(&mut self, data: &[u8], out: &mut dyn BufMut) -> CipherResult<()> {
let padding = self.padding_len();
let mut plain_text = vec![0u8; data.len() + padding];
@@ -88,12 +85,12 @@ fn crypto_stream_xor_ic<B: BufMut>(
data: &[u8],
out: &mut B,
) -> CipherResult<()> {
assert!(data.len() <= unsafe { out.bytes_mut().len() });
assert!(data.len() <= out.bytes_mut().len());
let ret = unsafe {
match t {
CipherType::ChaCha20 => crypto_stream_chacha20_xor_ic(
out.bytes_mut().as_mut_ptr(),
out.bytes_mut().as_mut_ptr() as *mut u8,
data.as_ptr(),
data.len() as c_ulonglong,
iv.as_ptr(),
@@ -101,7 +98,7 @@ fn crypto_stream_xor_ic<B: BufMut>(
key.as_ptr(),
),
CipherType::ChaCha20Ietf => crypto_stream_chacha20_ietf_xor_ic(
out.bytes_mut().as_mut_ptr(),
out.bytes_mut().as_mut_ptr() as *mut u8,
data.as_ptr(),
data.len() as c_ulonglong,
iv.as_ptr(),
@@ -109,7 +106,7 @@ fn crypto_stream_xor_ic<B: BufMut>(
key.as_ptr(),
),
CipherType::Salsa20 => crypto_stream_salsa20_xor_ic(
out.bytes_mut().as_mut_ptr(),
out.bytes_mut().as_mut_ptr() as *mut u8,
data.as_ptr(),
data.len() as c_ulonglong,
iv.as_ptr(),
@@ -117,7 +114,7 @@ fn crypto_stream_xor_ic<B: BufMut>(
key.as_ptr(),
),
CipherType::XSalsa20 => crypto_stream_xsalsa20_xor_ic(
out.bytes_mut().as_mut_ptr(),
out.bytes_mut().as_mut_ptr() as *mut u8,
data.as_ptr(),
data.len() as c_ulonglong,
iv.as_ptr(),
@@ -140,11 +137,11 @@ fn crypto_stream_xor_ic<B: BufMut>(
}
impl StreamCipher for SodiumStreamCipher {
fn update(&mut self, data: &[u8], out: &mut BufMut) -> CipherResult<()> {
fn update(&mut self, data: &[u8], out: &mut dyn BufMut) -> CipherResult<()> {
self.process(data, out)
}
fn finalize(&mut self, _: &mut BufMut) -> CipherResult<()> {
fn finalize(&mut self, _: &mut dyn BufMut) -> CipherResult<()> {
Ok(())
}
+2 -2
View File
@@ -18,8 +18,8 @@ use bytes::BufMut;
/// The `update` method could be called multiple times, and the `finalize` method will
/// encrypt the last block
pub trait StreamCipher {
fn update(&mut self, data: &[u8], out: &mut BufMut) -> CipherResult<()>;
fn finalize(&mut self, out: &mut BufMut) -> CipherResult<()>;
fn update(&mut self, data: &[u8], out: &mut dyn BufMut) -> CipherResult<()>;
fn finalize(&mut self, out: &mut dyn BufMut) -> CipherResult<()>;
fn buffer_size(&self, data: &[u8]) -> usize;
}
+3 -3
View File
@@ -56,7 +56,7 @@ impl TableCipher {
}
}
fn process(&mut self, data: &[u8], out: &mut BufMut) -> CipherResult<()> {
fn process(&mut self, data: &[u8], out: &mut dyn BufMut) -> CipherResult<()> {
let mut buf = BytesMut::with_capacity(self.buffer_size(data));
unsafe {
buf.set_len(self.buffer_size(data)); // Set length
@@ -70,11 +70,11 @@ impl TableCipher {
}
impl StreamCipher for TableCipher {
fn update(&mut self, data: &[u8], out: &mut BufMut) -> CipherResult<()> {
fn update(&mut self, data: &[u8], out: &mut dyn BufMut) -> CipherResult<()> {
self.process(data, out)
}
fn finalize(&mut self, _: &mut BufMut) -> CipherResult<()> {
fn finalize(&mut self, _: &mut dyn BufMut) -> CipherResult<()> {
Ok(())
}
+3 -1
View File
@@ -75,9 +75,11 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub use self::{
config::{ClientConfig, Config, ConfigType, Mode, ServerAddr, ServerConfig},
relay::{dns::run as run_dns, local::run as run_local, server::run as run_server, tcprelay::client::Socks5Client},
relay::{local::run as run_local, server::run as run_server, tcprelay::client::Socks5Client},
};
// relay::{dns::run as run_dns},
pub mod config;
mod context;
pub mod crypto;
+58 -51
View File
@@ -13,13 +13,13 @@
//! ```
use crate::config::{Config, ServerAddr};
use futures::{stream::futures_unordered, Future, Stream};
use futures::stream::{FuturesUnordered, StreamExt};
use log::{error, info};
use std::{
io,
net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener},
};
use tokio_process::{Child, CommandExt};
use tokio::process::Child;
mod obfs_proxy;
mod ss_plugin;
@@ -38,71 +38,78 @@ pub enum PluginMode {
Client,
}
/// Launch plugins in config. Returns a future that completes when any plugin terminates
/// or there were an error in watching the subprocess. Returns `None` if no plugins
/// were launched.
pub fn launch_plugins(
config: &mut Config,
mode: PluginMode,
) -> io::Result<Option<impl Future<Item = (), Error = io::Error>>> {
let mut plugins = Vec::new();
/// Started plugins' subprocesses carrier
pub struct Plugins {
plugins: FuturesUnordered<Child>,
}
for svr in &mut config.server {
let mut svr_addr_opt = None;
impl Plugins {
/// Launch plugins in configuration.
///
/// Will modify servers' listen addresses to plugins' listen addresses.
pub fn launch_plugins(config: &mut Config, mode: PluginMode) -> io::Result<Plugins> {
let plugins = FuturesUnordered::new();
if let Some(c) = svr.plugin() {
let loop_ip = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
let local_addr = SocketAddr::new(loop_ip, get_local_port()?);
for svr in &mut config.server {
let mut svr_addr_opt = None;
let svr_addr = match start_plugin(c, svr.addr(), &local_addr, mode) {
Err(err) => {
error!("Failed to start plugin \"{}\", err: {}", c.plugin, err);
return Err(err);
if let Some(c) = svr.plugin() {
let loop_ip = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
let local_addr = SocketAddr::new(loop_ip, get_local_port()?);
let svr_addr = match start_plugin(c, svr.addr(), &local_addr, mode) {
Err(err) => {
error!("Failed to start plugin \"{}\", err: {}", c.plugin, err);
return Err(err);
}
Ok(process) => {
let svr_addr = ServerAddr::SocketAddr(local_addr);
plugins.push(process);
// Replace addr with plugin
svr_addr
}
};
match mode {
PluginMode::Client => info!("Started plugin \"{}\" on {} <-> {}", c.plugin, local_addr, svr.addr()),
PluginMode::Server => info!("Started plugin \"{}\" on {} <-> {}", c.plugin, svr.addr(), local_addr),
}
Ok(process) => {
let svr_addr = ServerAddr::SocketAddr(local_addr);
plugins.push(process);
// Replace addr with plugin
svr_addr
}
};
match mode {
PluginMode::Client => info!("Started plugin \"{}\" on {} <-> {}", c.plugin, local_addr, svr.addr()),
PluginMode::Server => info!("Started plugin \"{}\" on {} <-> {}", c.plugin, svr.addr(), local_addr),
svr_addr_opt = Some(svr_addr); // Fuck borrow checker
}
svr_addr_opt = Some(svr_addr); // Fuck borrow checker
if let Some(svr_addr) = svr_addr_opt {
svr.set_plugin_addr(svr_addr);
}
}
if let Some(svr_addr) = svr_addr_opt {
svr.set_plugin_addr(svr_addr);
if plugins.is_empty() {
panic!("Didn't find any plugins to start");
}
Ok(Plugins { plugins })
}
if plugins.is_empty() {
Ok(None)
} else {
/// Returns a future that completes when any plugin terminates or there were an error in watching the subprocess.
pub async fn into_future(self) -> io::Result<()> {
// Turn the vector of `Child` futures into a single future that
// completes with an error if any of them exits or waiting for it
// fails. When this future completes, the remaining `Child`ren will be
// dropped and as a result the rest of the plugins will be killed
// automatically.
let plugins_future =
futures_unordered(plugins)
.into_future()
.then(|first_plugin_result| match first_plugin_result {
Ok((first_plugin_exit_status, _)) => {
let msg = format!("Plugin exited unexpectedly with {}", first_plugin_exit_status.unwrap());
Err(io::Error::new(io::ErrorKind::Other, msg))
}
Err((first_plugin_error, _)) => {
error!("Error while waiting for plugin subprocess: {}", first_plugin_error);
Err(first_plugin_error)
}
});
Ok(Some(plugins_future))
match self.plugins.into_future().await {
(Some(Ok(first_plugin_exit_status)), _) => {
let msg = format!("Plugin exited unexpectedly with {}", first_plugin_exit_status);
Err(io::Error::new(io::ErrorKind::Other, msg))
}
(Some(Err(first_plugin_error)), _) => {
error!("Error while waiting for plugin subprocess: {}", first_plugin_error);
Err(first_plugin_error)
}
_ => unreachable!(),
}
}
}
@@ -112,7 +119,7 @@ fn start_plugin(plugin: &PluginConfig, remote: &ServerAddr, local: &SocketAddr,
} else {
ss_plugin::plugin_cmd(plugin, remote, local, mode)
};
cmd.spawn_async()
cmd.spawn()
}
fn get_local_port() -> io::Result<u16> {
+2 -4
View File
@@ -1,9 +1,7 @@
use super::{PluginConfig, PluginMode};
use crate::config::ServerAddr;
use std::{
net::SocketAddr,
process::{Command, Stdio},
};
use std::{net::SocketAddr, process::Stdio};
use tokio::process::Command;
/// For obfsproxy, we use standalone mode for now.
/// Managed mode needs to use SOCKS5 proxy as forwarder, which is not supported
+2 -4
View File
@@ -1,10 +1,8 @@
use super::{PluginConfig, PluginMode};
use crate::config::ServerAddr;
use log::trace;
use std::{
net::SocketAddr,
process::{Command, Stdio},
};
use std::{net::SocketAddr, process::Stdio};
use tokio::process::Command;
pub fn plugin_cmd(plugin: &PluginConfig, remote: &ServerAddr, local: &SocketAddr, _mode: PluginMode) -> Command {
trace!("Start plugin \"{:?}\" remote: {}, local: {}", plugin, remote, local);
-16
View File
@@ -1,16 +0,0 @@
//! DNS relay
use std::io;
use futures::{self, Future};
use crate::{
config::Config,
context::{Context, SharedContext},
relay::udprelay::dns::run as run_udp,
};
/// DNS Relay server running under local environment.
pub fn run(config: Config) -> impl Future<Item = (), Error = io::Error> + Send {
futures::lazy(move || run_udp(SharedContext::new(Context::new_dns(config))))
}
+6
View File
@@ -0,0 +1,6 @@
//! Asynchronous DNS resolver
mod trust_dns_resolver;
pub use self::trust_dns_resolver::create_resolver;
pub use self::trust_dns_resolver::resolve;
@@ -0,0 +1,77 @@
use std::io::{self, ErrorKind};
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use log::{debug, error};
use crate::context::SharedContext;
/// Resolve address to IP
#[cfg(not(feature = "single-threaded"))]
pub async fn resolve(
context: SharedContext,
addr: &str,
port: u16,
check_forbidden: bool,
) -> io::Result<Vec<SocketAddr>> {
use tokio::task::spawn_blocking;
let addr = addr.to_owned();
spawn_blocking(move || {
let mut vaddr = Vec::new();
for addr in (addr.as_str(), port).to_socket_addrs()? {
let ip = addr.ip();
if check_forbidden {
let forbidden_ip = &context.config().forbidden_ip;
if forbidden_ip.contains(&ip) {
debug!("Resolved {} => {}, which is skipped by forbidden_ip", addr, ip);
continue;
}
}
vaddr.push(addr);
}
if vaddr.is_empty() {
error!("Failed to resolve {}:{}, all IPs are filtered", addr, port);
let err = io::Error::new(ErrorKind::Other, "resolved to empty address, all IPs are filtered");
Err(err)
} else {
debug!("Resolved {}:{} => {:?}", addr, port, vaddr);
Ok(vaddr)
}
})
.await?
}
/// Resolve address to IP
#[cfg(feature = "single-threaded")]
pub async fn resolve(
context: SharedContext,
addr: &str,
port: u16,
check_forbidden: bool,
) -> io::Result<Vec<SocketAddr>> {
let mut vaddr = Vec::new();
for addr in (addr, port).to_socket_addrs()? {
let ip = addr.ip();
if check_forbidden {
let forbidden_ip = &context.config().forbidden_ip;
if forbidden_ip.contains(&ip) {
debug!("Resolved {} => {}, which is skipped by forbidden_ip", addr, ip);
continue;
}
}
vaddr.push(addr);
}
if vaddr.is_empty() {
error!("Failed to resolve {}:{}, all IPs are filtered", addr, port);
let err = io::Error::new(ErrorKind::Other, "resolved to empty address, all IPs are filtered");
Err(err)
} else {
debug!("Resolved {}:{} => {:?}", addr, port, vaddr);
Ok(vaddr)
}
}
@@ -5,7 +5,7 @@ use std::{
net::SocketAddr,
};
use futures::Future;
use log::{debug, error, trace};
use tokio;
use trust_dns_resolver::{config::ResolverConfig, AsyncResolver};
@@ -18,11 +18,22 @@ pub fn create_resolver(dns: Option<ResolverConfig>) -> AsyncResolver {
{
if let Some(conf) = dns {
use trust_dns_resolver::config::ResolverOpts;
trace!(
"Initializing DNS resolver with config {:?} opts {:?}",
conf,
ResolverOpts::default()
);
AsyncResolver::new(conf, ResolverOpts::default())
} else {
use trust_dns_resolver::system_conf::read_system_conf;
// use the system resolver configuration
let (config, opts) = read_system_conf().expect("Failed to read global dns sysconf");
trace!(
"Initializing DNS resolver with system-config {:?} opts {:?}",
config,
opts
);
AsyncResolver::new(config, opts)
}
}
@@ -34,9 +45,19 @@ pub fn create_resolver(dns: Option<ResolverConfig>) -> AsyncResolver {
use trust_dns_resolver::config::{ResolverConfig, ResolverOpts};
if let Some(conf) = dns {
trace!(
"Initializing DNS resolver with config {:?} opts {:?}",
conf,
ResolverOpts::default()
);
AsyncResolver::new(conf, ResolverOpts::default())
} else {
// Get a new resolver with the google nameservers as the upstream recursive resolvers
trace!(
"Initializing DNS resolver with google-config {:?} opts {:?}",
ResolverConfig::google(),
ResolverOpts::default()
);
AsyncResolver::new(ResolverConfig::google(), ResolverOpts::default())
}
}
@@ -48,17 +69,15 @@ pub fn create_resolver(dns: Option<ResolverConfig>) -> AsyncResolver {
resolver
}
fn inner_resolve(
async fn inner_resolve(
context: SharedContext,
addr: &str,
port: u16,
check_forbidden: bool,
) -> impl Future<Item = Vec<SocketAddr>, Error = io::Error> + Send {
// let owned_addr = addr.to_owned();
let cloned_context = context.clone();
context.dns_resolver().lookup_ip(addr).then(move |r| match r {
) -> io::Result<Vec<SocketAddr>> {
match context.dns_resolver().lookup_ip(addr).await {
Err(err) => {
// error!("Failed to resolve {}, err: {}", owned_addr, err);
error!("Failed to resolve {}:{}, err: {}", addr, port, err);
Err(io::Error::new(
io::ErrorKind::Other,
format!("dns resolve error: {}", err),
@@ -68,9 +87,9 @@ fn inner_resolve(
let mut vaddr = Vec::new();
for ip in lookup_result.iter() {
if check_forbidden {
let forbidden_ip = &cloned_context.config().forbidden_ip;
let forbidden_ip = &context.config().forbidden_ip;
if forbidden_ip.contains(&ip) {
// debug!("Resolved {} => {}, which is skipped by forbidden_ip", owned_addr, ip);
debug!("Resolved {} => {}, which is skipped by forbidden_ip", addr, ip);
continue;
}
}
@@ -78,26 +97,23 @@ fn inner_resolve(
}
if vaddr.is_empty() {
let err = io::Error::new(
ErrorKind::Other,
// format!("resolved {} to empty address, all IPs are filtered", owned_addr),
"resolved to empty address, all IPs are filtered",
);
error!("Failed to resolve {}:{}, all IPs are filtered", addr, port);
let err = io::Error::new(ErrorKind::Other, "resolved to empty address, all IPs are filtered");
Err(err)
} else {
// debug!("Resolved {} => {:?}", owned_addr, vaddr);
debug!("Resolved {}:{} => {:?}", addr, port, vaddr);
Ok(vaddr)
}
}
})
}
}
/// Resolve address to IP
pub fn resolve(
pub async fn resolve(
context: SharedContext,
addr: &str,
port: u16,
check_forbidden: bool,
) -> impl Future<Item = Vec<SocketAddr>, Error = io::Error> + Send {
inner_resolve(context, addr, port, check_forbidden)
) -> io::Result<Vec<SocketAddr>> {
inner_resolve(context, addr, port, check_forbidden).await
}
+94 -99
View File
@@ -5,22 +5,19 @@ use std::{
atomic::{AtomicU64, AtomicUsize, Ordering},
Arc, Mutex,
},
time::{Duration, Instant},
};
use crate::{
config::ServerConfig,
context::SharedContext,
relay::tcprelay::EncryptedWrite,
relay::{loadbalancing::server::LoadBalancer, socks5::Address, tcprelay::client::ServerClient},
};
use futures::{Future, Stream};
use log::{debug, error, info};
use tokio::{
self,
io::read_exact,
timer::{Interval, Timeout},
io::{AsyncReadExt, AsyncWriteExt},
time::{self, Duration, Instant},
};
struct Server {
@@ -137,26 +134,22 @@ impl Inner {
tokio::spawn(
// Check every DEFAULT_CHECK_INTERVAL_SEC seconds
Interval::new(
Instant::now() + Duration::from_secs(DEFAULT_CHECK_INTERVAL_SEC),
Duration::from_secs(DEFAULT_CHECK_INTERVAL_SEC),
)
.for_each(move |_| {
let sc = sc.clone();
let lat = latency.clone();
async move {
// Wait until the server is ready (plugins are started)
time::delay_for(Duration::from_secs(DEFAULT_CHECK_INTERVAL_SEC)).await;
Inner::check_delay(sc.clone(), context.clone()).then(move |res| {
let score = match res {
Ok(d) => lat.push(d),
Err(..) => lat.push(DEFAULT_CHECK_TIMEOUT_SEC * 2 * 1000), // Penalty
let mut interval = time::interval(Duration::from_secs(DEFAULT_CHECK_INTERVAL_SEC));
while context.server_running() {
interval.tick().await;
let score = match Inner::check_delay(sc.clone(), context.clone()).await {
Ok(d) => latency.push(d),
Err(..) => latency.push(DEFAULT_CHECK_TIMEOUT_SEC * 2 * 1000), // Penalty
};
debug!("updated remote server {} (score: {})", sc.config.addr(), score);
sc.score.store(score, Ordering::Release);
Ok(())
})
})
.map_err(|_| ()),
}
},
);
}
@@ -166,52 +159,54 @@ impl Inner {
}
}
fn check_delay(sc: Arc<Server>, context: SharedContext) -> impl Future<Item = u64, Error = io::Error> {
static GET_BODY: &[u8] = b"GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: close\r\nAccept: */*\r\n\r\n";
async fn check_request(sc: Arc<ServerConfig>, context: SharedContext) -> io::Result<()> {
static GET_BODY: &[u8] =
b"GET /generate_204 HTTP/1.1\r\nHost: dl.google.com\r\nConnection: close\r\nAccept: */*\r\n\r\n";
let addr = Address::DomainNameAddress("www.example.com".to_owned(), 80);
let addr = Address::DomainNameAddress("dl.google.com".to_owned(), 80);
let ServerClient { mut stream } = ServerClient::connect(context, &addr, sc).await?;
stream.write_all(GET_BODY).await?;
stream.flush().await?;
let mut buf = [0u8; 1];
stream.read_exact(&mut buf).await?;
Ok(())
}
async fn check_delay(sc: Arc<Server>, context: SharedContext) -> io::Result<u64> {
let start = Instant::now();
// Send HTTP GET and read the first byte
let fut = ServerClient::connect(context, addr, sc.config.clone()).and_then(|ServerClient { r, w }| {
w.write_all(GET_BODY)
.and_then(|(mut w, _)| w.flush())
.and_then(move |_| read_exact(r, [0u8, 1]))
});
let timeout = Duration::from_secs(DEFAULT_CHECK_TIMEOUT_SEC);
let res = time::timeout(timeout, Inner::check_request(sc.config.clone(), context.clone())).await;
Timeout::new(fut, Duration::from_secs(DEFAULT_CHECK_TIMEOUT_SEC)).then(move |res| {
let elapsed = Instant::now() - start;
let elapsed = elapsed.as_secs() * 1000 + u64::from(elapsed.subsec_millis()); // Converted to ms
match res {
Ok(..) => {
// Got the result ... record its time
debug!("checked remote server {} latency with {} ms", sc.config.addr(), elapsed);
Ok(elapsed)
}
Err(err) => {
match err.into_inner() {
Some(err) => {
error!("failed to check server {}, error: {}", sc.config.addr(), err);
// NOTE: connection / handshake error, server is down
Err(err)
}
None => {
// Timeout
debug!(
"checked remote server {} latency timeout, elapsed {} ms",
sc.config.addr(),
elapsed
);
// NOTE: timeout is still available, but server is too slow
Ok(elapsed)
}
}
}
let elapsed = Instant::now() - start;
let elapsed = elapsed.as_secs() * 1000 + u64::from(elapsed.subsec_millis()); // Converted to ms
match res {
Ok(Ok(..)) => {
// Got the result ... record its time
debug!("checked remote server {} latency with {} ms", sc.config.addr(), elapsed);
Ok(elapsed)
}
})
Ok(Err(err)) => {
error!("failed to check server {}, error: {}", sc.config.addr(), err);
// NOTE: connection / handshake error, server is down
Err(err)
}
Err(..) => {
// Timeout
debug!(
"checked remote server {} latency timeout, elapsed {} ms",
sc.config.addr(),
elapsed
);
// NOTE: timeout is still available, but server is too slow
Ok(elapsed)
}
}
}
fn best_idx(&self) -> usize {
@@ -234,54 +229,54 @@ pub struct PingBalancer {
impl PingBalancer {
pub fn new(context: SharedContext) -> PingBalancer {
let inner = Arc::new(Inner::new(context));
let inner = Arc::new(Inner::new(context.clone()));
let inner_cloned = inner.clone();
tokio::spawn(
Interval::new(
Instant::now() + Duration::from_secs(2),
Duration::from_secs(DEFAULT_CHECK_INTERVAL_SEC),
)
.for_each(move |_| {
let inner = inner_cloned.clone();
if inner.servers.len() > 1 {
let cloned_inner = inner.clone();
tokio::spawn(async move {
let inner = cloned_inner;
if inner.servers.is_empty() {
panic!("No server");
}
// Wait until the server is ready (plugins are started)
time::delay_for(Duration::from_secs(2)).await;
// Choose the best one
let mut svr_idx = 0;
let mut interval = time::interval(Duration::from_secs(DEFAULT_CHECK_INTERVAL_SEC));
for (idx, svr) in inner.servers.iter().enumerate() {
let choosen_svr = &inner.servers[svr_idx];
if svr.score() < choosen_svr.score() {
svr_idx = idx;
while context.server_running() {
interval.tick().await;
assert!(!inner.servers.is_empty());
// Choose the best one
let mut svr_idx = 0;
for (idx, svr) in inner.servers.iter().enumerate() {
let choosen_svr = &inner.servers[svr_idx];
if svr.score() < choosen_svr.score() {
svr_idx = idx;
}
}
}
let choosen_svr = &inner.servers[svr_idx];
debug!(
"chosen the best server {} (score: {})",
choosen_svr.config.addr(),
choosen_svr.score()
);
if inner.best_idx() != svr_idx {
info!(
"switched server from {} (score: {}) to {} (score: {})",
inner.best_server().config.addr(),
inner.best_server().score(),
let choosen_svr = &inner.servers[svr_idx];
debug!(
"chosen the best server {} (score: {})",
choosen_svr.config.addr(),
choosen_svr.score(),
choosen_svr.score()
);
if inner.best_idx() != svr_idx {
info!(
"switched server from {} (score: {}) to {} (score: {})",
inner.best_server().config.addr(),
inner.best_server().score(),
choosen_svr.config.addr(),
choosen_svr.score(),
);
}
inner.set_best_idx(svr_idx);
}
inner.set_best_idx(svr_idx);
Ok(())
})
.map_err(|_| ()),
);
});
}
PingBalancer { inner }
}
+33 -51
View File
@@ -2,67 +2,49 @@
use std::io;
use futures::{stream::futures_unordered, Future, Stream};
use futures::{future::select_all, FutureExt};
use log::error;
use crate::{
config::Config,
context::{Context, SharedContext},
plugin::{launch_plugins, PluginMode},
relay::{boxed_future, tcprelay::local::run as run_tcp, udprelay::local::run as run_udp},
context::{Context, SharedServerState},
plugin::{PluginMode, Plugins},
relay::{tcprelay::local::run as run_tcp, udprelay::local::run as run_udp},
};
/// Relay server running under local environment.
///
/// ```no_run
/// use shadowsocks::{
/// config::{Config, ConfigType, ServerConfig},
/// crypto::CipherType,
/// relay::local::run,
/// };
///
/// use tokio::prelude::*;
///
/// let mut config = Config::new(ConfigType::Local);
/// config.local = Some("127.0.0.1:1080".parse().unwrap());
/// config.server = vec![ServerConfig::basic(
/// "127.0.0.1:8388".parse().unwrap(),
/// "server-password".to_string(),
/// CipherType::Aes256Cfb,
/// )];
/// let fut = run(config);
/// tokio::run(fut.map_err(|err| panic!("Server run failed with error {}", err)));
/// ```
pub fn run(config: Config) -> impl Future<Item = (), Error = io::Error> + Send {
futures::lazy(move || {
let mut context = Context::new(config);
pub async fn run(mut config: Config) -> io::Result<()> {
// Create a context containing a DNS resolver and server running state flag.
let state = SharedServerState::new(&config);
let mut vf = Vec::new();
let mut vf = Vec::new();
if context.config().mode.enable_udp() {
// Clone config here, because the config for TCP relay will be modified
// after plugins started
let udp_context = SharedContext::new(context.clone());
if config.mode.enable_udp() {
// Clone config here, because the config for TCP relay will be modified
// after plugins started.
// But DNS resolver and running state flag is still shared.
let udp_context = Context::new_shared(config.clone(), state.clone());
// Run UDP relay before starting plugins
// Because plugins doesn't support UDP relay
let udp_fut = run_udp(udp_context);
vf.push(boxed_future(udp_fut));
}
// Run UDP relay before starting plugins
// Because plugins doesn't support UDP relay
let udp_fut = run_udp(udp_context);
vf.push(udp_fut.boxed());
}
if let Some(plugins) =
launch_plugins(context.config_mut(), PluginMode::Client).expect("Failed to launch plugins")
{
vf.push(boxed_future(plugins));
}
if config.has_server_plugins() {
let plugins = Plugins::launch_plugins(&mut config, PluginMode::Client)?;
vf.push(plugins.into_future().boxed());
}
let tcp_fut = run_tcp(SharedContext::new(context));
let tcp_fut = run_tcp(Context::new_shared(config, state.clone()));
vf.push(tcp_fut.boxed());
vf.push(boxed_future(tcp_fut));
futures_unordered(vf).into_future().then(|res| -> io::Result<()> {
match res {
Ok(..) => Ok(()),
Err((err, ..)) => Err(err),
}
})
})
let (res, ..) = select_all(vf.into_iter()).await;
error!("One of TCP servers exited unexpectly, result: {:?}", res);
// Tells all detached tasks to exit
state.server_stopped();
Err(io::Error::new(io::ErrorKind::Other, "server exited unexpectly"))
}
+3 -12
View File
@@ -1,20 +1,11 @@
//! Relay server in local and server side implementations.
use futures::Future;
pub mod dns;
#[cfg(feature = "trust-dns")]
pub(crate) mod dns_resolver;
mod loadbalancing;
pub(crate) mod loadbalancing;
pub mod local;
pub mod server;
pub mod socks5;
pub mod tcprelay;
pub mod udprelay;
mod utils;
pub fn boxed_future<T, E, F>(f: F) -> Box<Future<Item = T, Error = E> + Send + 'static>
where
F: Future<Item = T, Error = E> + Send + 'static,
{
Box::new(f)
}
pub(crate) mod utils;
+33 -52
View File
@@ -2,69 +2,50 @@
use std::io;
use futures::{stream::futures_unordered, Future, Stream};
use futures::future::{select_all, FutureExt};
use log::error;
use crate::{
config::Config,
context::{Context, SharedContext},
plugin::{launch_plugins, PluginMode},
relay::{boxed_future, tcprelay::server::run as run_tcp, udprelay::server::run as run_udp},
context::{Context, SharedServerState},
plugin::{PluginMode, Plugins},
relay::{tcprelay::server::run as run_tcp, udprelay::server::run as run_udp},
};
/// Relay server running on server side.
///
/// ```no_run
/// use shadowsocks::{
/// config::{Config, ConfigType, ServerConfig},
/// crypto::CipherType,
/// relay::server::run,
/// };
///
/// use tokio::prelude::*;
///
/// let mut config = Config::new(ConfigType::Server);
/// config.server = vec![ServerConfig::basic(
/// "127.0.0.1:8388".parse().unwrap(),
/// "server-password".to_string(),
/// CipherType::Aes256Cfb,
/// )];
///
/// let fut = run(config);
/// tokio::run(fut.map_err(|err| panic!("Server run failed with error {}", err)));
/// ```
pub fn run(config: Config) -> impl Future<Item = (), Error = io::Error> + Send {
futures::lazy(move || {
let mut context = Context::new(config);
pub async fn run(mut config: Config) -> io::Result<()> {
// Create a context containing a DNS resolver and server running state flag.
let state = SharedServerState::new(&config);
let mut vf = Vec::new();
let mut vf = Vec::new();
if context.config().mode.enable_udp() {
// Clone config here, because the config for TCP relay will be modified
// after plugins started
let udp_context = SharedContext::new(context.clone());
if config.mode.enable_udp() {
// Clone config here, because the config for TCP relay will be modified
// after plugins started
let udp_context = Context::new_shared(config.clone(), state.clone());
// Run UDP relay before starting plugins
// Because plugins doesn't support UDP relay
let udp_fut = run_udp(udp_context);
vf.push(boxed_future(udp_fut));
// Run UDP relay before starting plugins
// Because plugins doesn't support UDP relay
let udp_fut = run_udp(udp_context);
vf.push(udp_fut.boxed());
}
if config.mode.enable_tcp() {
if config.has_server_plugins() {
let plugins = Plugins::launch_plugins(&mut config, PluginMode::Client)?;
vf.push(plugins.into_future().boxed());
}
if context.config().mode.enable_tcp() {
if let Some(plugins) =
launch_plugins(context.config_mut(), PluginMode::Server).expect("Failed to launch plugins")
{
vf.push(boxed_future(plugins));
}
let tcp_fut = run_tcp(Context::new_shared(config, state.clone()));
vf.push(tcp_fut.boxed());
}
let tcp_fut = run_tcp(SharedContext::new(context));
vf.push(boxed_future(tcp_fut));
}
let (res, ..) = select_all(vf.into_iter()).await;
error!("One of TCP servers exited unexpectly, result: {:?}", res);
futures_unordered(vf).into_future().then(|res| -> io::Result<()> {
match res {
Ok(..) => Ok(()),
Err((err, ..)) => Err(err),
}
})
})
// Tells all detached tasks to exit
state.server_stopped();
Err(io::Error::new(io::ErrorKind::Other, "server exited unexpectly"))
}
+201 -307
View File
@@ -2,27 +2,24 @@
//!
//! Implements [SOCKS Protocol Version 5](https://www.ietf.org/rfc/rfc1928.txt) proxy protocol
use std::{
convert::From,
error,
fmt::{self, Debug, Formatter},
io::{self, Cursor, Read, Write},
net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs},
u8, vec,
};
use std::convert::From;
use std::error;
use std::fmt::{self, Debug, Formatter};
use std::io::{self, Cursor};
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
use std::str::FromStr;
use std::u8;
use std::vec;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use bytes::{BufMut, Bytes, BytesMut, IntoBuf};
use futures::{try_ready, Async, Future, Poll};
use bytes::buf::BufExt;
use bytes::{Buf, BufMut, BytesMut};
use log::error;
use tokio_io::{io::read_exact, try_nb, AsyncRead, AsyncWrite};
use tokio::prelude::*;
pub use self::consts::{
SOCKS5_AUTH_METHOD_GSSAPI, SOCKS5_AUTH_METHOD_NONE, SOCKS5_AUTH_METHOD_NOT_ACCEPTABLE, SOCKS5_AUTH_METHOD_PASSWORD,
};
use super::utils::{write_bytes, WriteBytes};
#[rustfmt::skip]
mod consts {
pub const SOCKS5_VERSION: u8 = 0x05;
@@ -192,7 +189,7 @@ impl error::Error for Error {
&self.message[..]
}
fn cause(&self) -> Option<&error::Error> {
fn cause(&self) -> Option<&dyn error::Error> {
None
}
}
@@ -219,17 +216,84 @@ pub enum Address {
}
impl Address {
#[inline]
pub fn read_from<R: AsyncRead>(stream: R) -> ReadAddress<R> {
ReadAddress::new(stream)
pub async fn read_from<R>(stream: &mut R) -> Result<Address, Error>
where
R: AsyncRead + Unpin,
{
let mut addr_type_buf = [0u8; 1];
let _ = stream.read_exact(&mut addr_type_buf).await?;
let addr_type = addr_type_buf[0];
match addr_type {
consts::SOCKS5_ADDR_TYPE_IPV4 => {
let mut buf = BytesMut::with_capacity(6);
buf.resize(6, 0);
let _ = stream.read_exact(&mut buf).await?;
let mut cursor = buf.to_bytes();
let v4addr = Ipv4Addr::new(cursor.get_u8(), cursor.get_u8(), cursor.get_u8(), cursor.get_u8());
let port = cursor.get_u16();
Ok(Address::SocketAddress(SocketAddr::V4(SocketAddrV4::new(v4addr, port))))
}
consts::SOCKS5_ADDR_TYPE_IPV6 => {
let mut buf = [0u8; 18];
let _ = stream.read_exact(&mut buf).await?;
let mut cursor = Cursor::new(&buf);
let v6addr = Ipv6Addr::new(
cursor.get_u16(),
cursor.get_u16(),
cursor.get_u16(),
cursor.get_u16(),
cursor.get_u16(),
cursor.get_u16(),
cursor.get_u16(),
cursor.get_u16(),
);
let port = cursor.get_u16();
Ok(Address::SocketAddress(SocketAddr::V6(SocketAddrV6::new(
v6addr, port, 0, 0,
))))
}
consts::SOCKS5_ADDR_TYPE_DOMAIN_NAME => {
let mut length_buf = [0u8; 1];
let _ = stream.read_exact(&mut length_buf).await?;
let length = length_buf[0] as usize;
// Len(Domain) + Len(Port)
let buf_length = length + 2;
let mut buf = BytesMut::with_capacity(buf_length);
buf.resize(buf_length, 0);
let _ = stream.read_exact(&mut buf).await?;
let mut cursor = buf.to_bytes();
let mut raw_addr = Vec::with_capacity(length);
raw_addr.put(&mut BufExt::take(&mut cursor, length));
let addr = match String::from_utf8(raw_addr) {
Ok(addr) => addr,
Err(..) => return Err(Error::new(Reply::GeneralFailure, "Invalid address encoding")),
};
let port = cursor.get_u16();
Ok(Address::DomainNameAddress(addr, port))
}
_ => {
error!("Invalid address type {}", addr_type);
Err(Error::new(Reply::AddressTypeNotSupported, "Not supported address type"))
}
}
}
/// Writes to writer
#[inline]
pub fn write_to<W: AsyncWrite>(self, writer: W) -> WriteBytes<W, Bytes> {
pub async fn write_to<W>(&self, writer: &mut W) -> io::Result<()>
where
W: AsyncWrite + Unpin,
{
let mut buf = BytesMut::with_capacity(self.serialized_len());
self.write_to_buf(&mut buf);
write_bytes(writer, buf.freeze())
writer.write_all(&buf).await
}
/// Writes to buffer
@@ -287,215 +351,42 @@ impl From<(String, u16)> for Address {
}
}
pub struct ReadAddress<R>
where
R: AsyncRead,
{
reader: Option<R>,
state: ReadAddressState,
buf: Option<BytesMut>,
already_read: usize,
}
/// Parse `Address` error
#[derive(Debug)]
pub struct AddressError;
enum ReadAddressState {
Type,
Ipv4,
Ipv6,
DomainNameLength,
DomainName,
}
impl FromStr for Address {
type Err = AddressError;
impl<R> Future for ReadAddress<R>
where
R: AsyncRead,
{
type Error = Error;
type Item = (R, Address);
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
debug_assert!(self.reader.is_some());
loop {
match self.state {
ReadAddressState::Type => {
try_ready!(self.read_addr_type());
fn from_str(s: &str) -> Result<Address, AddressError> {
match s.parse::<SocketAddr>() {
Ok(addr) => Ok(Address::SocketAddress(addr)),
Err(..) => {
let mut sp = s.split(':');
match (sp.next(), sp.next()) {
(Some(dn), Some(port)) => match port.parse::<u16>() {
Ok(port) => Ok(Address::DomainNameAddress(dn.to_owned(), port)),
Err(..) => Err(AddressError),
},
_ => Err(AddressError),
}
ReadAddressState::Ipv4 => {
let addr = try_ready!(self.read_ipv4());
let reader = self.reader.take().unwrap();
return Ok((reader, addr).into());
}
ReadAddressState::Ipv6 => {
let addr = try_ready!(self.read_ipv6());
let reader = self.reader.take().unwrap();
return Ok((reader, addr).into());
}
ReadAddressState::DomainNameLength => {
try_ready!(self.read_domain_name_length());
}
ReadAddressState::DomainName => {
let addr = try_ready!(self.read_domain_name());
let reader = self.reader.take().unwrap();
return Ok((reader, addr).into());
}
};
}
}
}
impl<R> ReadAddress<R>
where
R: AsyncRead,
{
fn new(r: R) -> ReadAddress<R> {
ReadAddress {
reader: Some(r),
state: ReadAddressState::Type,
buf: None,
already_read: 0,
}
}
fn read_addr_type(&mut self) -> Poll<(), Error> {
let addr_type = try_nb!(self.reader.as_mut().unwrap().read_u8());
match addr_type {
consts::SOCKS5_ADDR_TYPE_IPV4 => {
self.state = ReadAddressState::Ipv4;
self.alloc_buf(6);
}
consts::SOCKS5_ADDR_TYPE_IPV6 => {
self.state = ReadAddressState::Ipv6;
self.alloc_buf(18);
}
consts::SOCKS5_ADDR_TYPE_DOMAIN_NAME => {
self.state = ReadAddressState::DomainNameLength;
}
_ => {
error!("Invalid address type {}", addr_type);
return Err(Error::new(Reply::AddressTypeNotSupported, "Not supported address type"));
}
};
Ok(Async::Ready(()))
}
fn read_ipv4(&mut self) -> Poll<Address, Error> {
try_ready!(self.read_data());
let mut stream: Cursor<Bytes> = self.freeze_buf().into_buf();
let v4addr = Ipv4Addr::new(
stream.read_u8()?,
stream.read_u8()?,
stream.read_u8()?,
stream.read_u8()?,
);
let port = stream.read_u16::<BigEndian>()?;
let addr = Address::SocketAddress(SocketAddr::V4(SocketAddrV4::new(v4addr, port)));
Ok(Async::Ready(addr))
}
fn read_ipv6(&mut self) -> Poll<Address, Error> {
try_ready!(self.read_data());
let mut stream: Cursor<Bytes> = self.freeze_buf().into_buf();
let v6addr = Ipv6Addr::new(
stream.read_u16::<BigEndian>()?,
stream.read_u16::<BigEndian>()?,
stream.read_u16::<BigEndian>()?,
stream.read_u16::<BigEndian>()?,
stream.read_u16::<BigEndian>()?,
stream.read_u16::<BigEndian>()?,
stream.read_u16::<BigEndian>()?,
stream.read_u16::<BigEndian>()?,
);
let port = stream.read_u16::<BigEndian>()?;
let addr = Address::SocketAddress(SocketAddr::V6(SocketAddrV6::new(v6addr, port, 0, 0)));
Ok(Async::Ready(addr))
}
fn read_domain_name_length(&mut self) -> Poll<(), Error> {
let length = try_nb!(self.reader.as_mut().unwrap().read_u8());
self.state = ReadAddressState::DomainName;
self.alloc_buf(length as usize + 2);
Ok(Async::Ready(()))
}
fn read_domain_name(&mut self) -> Poll<Address, Error> {
try_ready!(self.read_data());
let buf = self.freeze_buf();
let addr_len = buf.len() - 2;
let mut stream: Cursor<Bytes> = buf.into_buf();
let mut raw_addr = Vec::with_capacity(addr_len);
unsafe {
raw_addr.set_len(addr_len);
}
stream.read_exact(&mut raw_addr)?;
let addr = match String::from_utf8(raw_addr) {
Ok(addr) => addr,
Err(..) => return Err(Error::new(Reply::GeneralFailure, "Invalid address encoding")),
};
let port = stream.read_u16::<BigEndian>()?;
let addr = Address::DomainNameAddress(addr, port);
Ok(Async::Ready(addr))
}
fn alloc_buf(&mut self, size: usize) {
let mut buf = BytesMut::with_capacity(size);
unsafe {
buf.set_len(size);
}
self.buf = Some(buf);
}
fn read_data(&mut self) -> Poll<(), io::Error> {
let buf = self.buf.as_mut().unwrap();
while self.already_read < buf.len() {
match self.reader.as_mut().unwrap().read(&mut buf[self.already_read..]) {
Ok(0) => {
let err = io::Error::new(io::ErrorKind::Other, "Unexpected EOF");
return Err(err);
}
Ok(n) => self.already_read += n,
Err(err) => return Err(err),
}
}
Ok(Async::Ready(()))
}
fn freeze_buf(&mut self) -> Bytes {
let buf = self.buf.take().unwrap();
buf.freeze()
}
}
fn write_ipv4_address<B: BufMut>(addr: &SocketAddrV4, buf: &mut B) {
let mut dbuf = [0u8; 1 + 4 + 2];
{
let mut cur = Cursor::new(&mut dbuf[..]);
let _ = cur.write_u8(consts::SOCKS5_ADDR_TYPE_IPV4); // Address type
let _ = cur.write_all(&addr.ip().octets()); // Ipv4 bytes
let _ = cur.write_u16::<BigEndian>(addr.port());
}
buf.put_slice(&dbuf[..]);
buf.put_u8(consts::SOCKS5_ADDR_TYPE_IPV4); // Address type
buf.put_slice(&addr.ip().octets()); // Ipv4 bytes
buf.put_u16(addr.port()); // Port
}
fn write_ipv6_address<B: BufMut>(addr: &SocketAddrV6, buf: &mut B) {
let mut dbuf = [0u8; 1 + 16 + 2];
{
let mut cur = Cursor::new(&mut dbuf[..]);
let _ = cur.write_u8(consts::SOCKS5_ADDR_TYPE_IPV6);
for seg in &addr.ip().segments() {
let _ = cur.write_u16::<BigEndian>(*seg);
}
let _ = cur.write_u16::<BigEndian>(addr.port());
buf.put_u8(consts::SOCKS5_ADDR_TYPE_IPV6); // Address type
for seg in &addr.ip().segments() {
buf.put_u16(*seg); // Ipv6 bytes
}
buf.put_slice(&dbuf[..]);
buf.put_u16(addr.port()); // Port
}
fn write_domain_name_address<B: BufMut>(dnaddr: &str, port: u16, buf: &mut B) {
@@ -504,7 +395,7 @@ fn write_domain_name_address<B: BufMut>(dnaddr: &str, port: u16, buf: &mut B) {
buf.put_u8(consts::SOCKS5_ADDR_TYPE_DOMAIN_NAME);
buf.put_u8(dnaddr.len() as u8);
buf.put_slice(dnaddr[..].as_bytes());
buf.put_u16_be(port);
buf.put_u16(port);
}
fn write_socket_address<B: BufMut>(addr: &SocketAddr, buf: &mut B) {
@@ -557,42 +448,38 @@ impl TcpRequestHeader {
}
/// Read from a reader
pub fn read_from<R>(r: R) -> impl Future<Item = (R, TcpRequestHeader), Error = Error> + Send
pub async fn read_from<R>(r: &mut R) -> Result<TcpRequestHeader, Error>
where
R: AsyncRead + Send + 'static,
R: AsyncRead + Unpin,
{
read_exact(r, [0u8; 3])
.map_err(From::from)
.and_then(|(r, buf)| {
let ver = buf[0];
if ver != consts::SOCKS5_VERSION {
return Err(Error::new(Reply::ConnectionRefused, "Unsupported Socks version"));
}
let mut buf = [0u8; 3];
let _ = r.read_exact(&mut buf).await?;
let cmd = buf[1];
let command = match Command::from_u8(cmd) {
Some(c) => c,
None => {
return Err(Error::new(Reply::CommandNotSupported, "Unsupported command"));
}
};
let ver = buf[0];
if ver != consts::SOCKS5_VERSION {
return Err(Error::new(Reply::ConnectionRefused, "Unsupported Socks version"));
}
Ok((r, command))
})
.and_then(|(r, command)| {
Address::read_from(r).map(move |(conn, address)| {
let header = TcpRequestHeader { command, address };
let cmd = buf[1];
let command = match Command::from_u8(cmd) {
Some(c) => c,
None => {
return Err(Error::new(Reply::CommandNotSupported, "Unsupported command"));
}
};
(conn, header)
})
})
let address = Address::read_from(r).await?;
Ok(TcpRequestHeader { command, address })
}
/// Write data into a writer
pub fn write_to<W: AsyncWrite>(self, w: W) -> WriteBytes<W, Bytes> {
pub async fn write_to<W>(&self, w: &mut W) -> io::Result<()>
where
W: AsyncWrite + Unpin,
{
let mut buf = BytesMut::with_capacity(self.serialized_len());
self.write_to_buf(&mut buf);
write_bytes(w, buf.freeze())
w.write_all(&buf).await
}
/// Writes to buffer
@@ -637,39 +524,36 @@ impl TcpResponseHeader {
}
/// Read from a reader
pub fn read_from<R>(r: R) -> impl Future<Item = (R, TcpResponseHeader), Error = Error> + Send
pub async fn read_from<R>(r: &mut R) -> Result<TcpResponseHeader, Error>
where
R: AsyncRead + Send + 'static,
R: AsyncRead + Unpin,
{
read_exact(r, [0u8; 3])
.map_err(From::from)
.and_then(|(r, buf)| {
let ver = buf[0];
let reply_code = buf[1];
let mut buf = [0u8; 3];
let _ = r.read_exact(&mut buf).await?;
if ver != consts::SOCKS5_VERSION {
return Err(Error::new(Reply::ConnectionRefused, "Unsupported Socks version"));
}
let ver = buf[0];
let reply_code = buf[1];
Ok((r, reply_code))
})
.and_then(|(r, reply_code)| {
Address::read_from(r).map(move |(r, address)| {
let rep = TcpResponseHeader {
reply: Reply::from_u8(reply_code),
address,
};
if ver != consts::SOCKS5_VERSION {
return Err(Error::new(Reply::ConnectionRefused, "Unsupported Socks version"));
}
(r, rep)
})
})
let address = Address::read_from(r).await?;
Ok(TcpResponseHeader {
reply: Reply::from_u8(reply_code),
address,
})
}
/// Write to a writer
pub fn write_to<W: AsyncWrite>(self, w: W) -> WriteBytes<W, Bytes> {
pub async fn write_to<W>(&self, w: &mut W) -> io::Result<()>
where
W: AsyncWrite + Unpin,
{
let mut buf = BytesMut::with_capacity(self.serialized_len());
self.write_to_buf(&mut buf);
write_bytes(w, buf.freeze())
w.write_all(&buf).await
}
/// Writes to buffer
@@ -707,30 +591,34 @@ impl HandshakeRequest {
}
/// Read from a reader
pub fn read_from<R>(r: R) -> impl Future<Item = (R, HandshakeRequest), Error = io::Error>
pub async fn read_from<R>(r: &mut R) -> io::Result<HandshakeRequest>
where
R: AsyncRead + Send + 'static,
R: AsyncRead + Unpin,
{
read_exact(r, [0u8, 0u8])
.and_then(|(r, buf)| {
let ver = buf[0];
let nmet = buf[1];
let mut buf = [0u8; 2];
let _ = r.read_exact(&mut buf).await?;
if ver != consts::SOCKS5_VERSION {
return Err(io::Error::new(io::ErrorKind::Other, "Invalid Socks5 version"));
}
let ver = buf[0];
let nmet = buf[1];
Ok((r, nmet))
})
.and_then(|(r, nmet)| read_exact(r, vec![0u8; nmet as usize]))
.and_then(|(r, methods)| Ok((r, HandshakeRequest { methods })))
if ver != consts::SOCKS5_VERSION {
return Err(io::Error::new(io::ErrorKind::Other, "Invalid Socks5 version"));
}
let mut methods = vec![0u8; nmet as usize];
let _ = r.read_exact(&mut methods).await?;
Ok(HandshakeRequest { methods })
}
/// Write to a writer
pub fn write_to<W: AsyncWrite>(self, w: W) -> WriteBytes<W, Bytes> {
pub async fn write_to<W>(&self, w: &mut W) -> io::Result<()>
where
W: AsyncWrite + Unpin,
{
let mut buf = BytesMut::with_capacity(self.serialized_len());
self.write_to_buf(&mut buf);
write_bytes(w, buf.freeze())
w.write_all(&buf).await
}
/// Write to buffer
@@ -767,36 +655,40 @@ impl HandshakeResponse {
}
/// Read from a reader
pub fn read_from<R>(r: R) -> impl Future<Item = (R, HandshakeResponse), Error = io::Error>
pub async fn read_from<R>(r: &mut R) -> io::Result<HandshakeResponse>
where
R: AsyncRead + Send + 'static,
R: AsyncRead + Unpin,
{
read_exact(r, [0u8, 0u8]).and_then(|(r, buf)| {
let ver = buf[0];
let met = buf[1];
let mut buf = [0u8; 2];
let _ = r.read_exact(&mut buf).await?;
if ver != consts::SOCKS5_VERSION {
Err(io::Error::new(io::ErrorKind::Other, "Invalid Socks5 version"))
} else {
Ok((r, HandshakeResponse { chosen_method: met }))
}
})
let ver = buf[0];
let met = buf[1];
if ver != consts::SOCKS5_VERSION {
Err(io::Error::new(io::ErrorKind::Other, "Invalid Socks5 version"))
} else {
Ok(HandshakeResponse { chosen_method: met })
}
}
/// Write to a writer
pub fn write_to<W: AsyncWrite>(self, w: W) -> WriteBytes<W, Bytes> {
pub async fn write_to<W>(self, w: &mut W) -> io::Result<()>
where
W: AsyncWrite + Unpin,
{
let mut buf = BytesMut::with_capacity(self.serialized_len());
self.write_to_buf(&mut buf);
write_bytes(w, buf.freeze())
w.write_all(&buf).await
}
/// Write to buffer
pub fn write_to_buf<B: BufMut>(&self, buf: &mut B) {
pub fn write_to_buf<B: BufMut>(self, buf: &mut B) {
buf.put_slice(&[consts::SOCKS5_VERSION, self.chosen_method]);
}
/// Length in bytes
pub fn serialized_len(&self) -> usize {
pub fn serialized_len(self) -> usize {
2
}
}
@@ -827,24 +719,26 @@ impl UdpAssociateHeader {
}
/// Read from a reader
pub fn read_from<R>(r: R) -> impl Future<Item = (R, UdpAssociateHeader), Error = Error> + Send
pub async fn read_from<R>(r: &mut R) -> Result<UdpAssociateHeader, Error>
where
R: AsyncRead + Send + 'static,
R: AsyncRead + Unpin,
{
read_exact(r, [0u8; 3]).map_err(From::from).and_then(|(r, buf)| {
let frag = buf[2];
Address::read_from(r).map(move |(r, address)| {
let h = UdpAssociateHeader::new(frag, address);
(r, h)
})
})
let mut buf = [0u8; 3];
let _ = r.read_exact(&mut buf).await?;
let frag = buf[2];
let address = Address::read_from(r).await?;
Ok(UdpAssociateHeader::new(frag, address))
}
/// Write to a writer
pub fn write_to<W: AsyncWrite>(self, w: W) -> WriteBytes<W, Bytes> {
pub async fn write_to<W>(&self, w: &mut W) -> io::Result<()>
where
W: AsyncWrite + Unpin,
{
let mut buf = BytesMut::with_capacity(self.serialized_len());
self.write_to_buf(&mut buf);
write_bytes(w, buf.freeze())
w.write_all(&buf).await
}
/// Write to buffer
+181 -219
View File
@@ -33,295 +33,257 @@
//! ```
use std::{
cmp,
io::{self, BufRead, Read},
cmp, io,
marker::Unpin,
pin::Pin,
slice,
task::{Context, Poll},
u16,
};
use byteorder::{BigEndian, ByteOrder};
use bytes::{BufMut, BytesMut};
use log::error;
use tokio_io::{AsyncRead, AsyncWrite};
use futures::ready;
use tokio::prelude::*;
use crate::crypto::{self, BoxAeadDecryptor, BoxAeadEncryptor, CipherType};
use super::{DecryptedRead, EncryptedWrite, BUFFER_SIZE};
use super::BUFFER_SIZE;
/// AEAD packet payload must be smaller than 0x3FFF
const MAX_PACKET_SIZE: usize = 0x3FFF;
enum ReadingStep {
#[derive(Debug)]
enum DecryptReadStep {
Length,
DataAndTag(usize),
Done,
Data(usize),
}
/// Reader wrapper that will decrypt data automatically
pub struct DecryptedReader<R>
where
R: AsyncRead,
{
reader: R,
pub struct DecryptedReader {
buffer: BytesMut,
data: BytesMut,
cipher: BoxAeadDecryptor,
pos: usize,
sent_final: bool,
tag_size: usize,
read_step: ReadingStep,
steps: DecryptReadStep,
got_final: bool,
}
impl<R> DecryptedReader<R>
where
R: AsyncRead,
{
pub fn new(r: R, t: CipherType, key: &[u8], nounce: &[u8]) -> DecryptedReader<R> {
impl DecryptedReader {
pub fn new(t: CipherType, key: &[u8], nonce: &[u8]) -> DecryptedReader {
DecryptedReader {
reader: r,
buffer: BytesMut::with_capacity(BUFFER_SIZE),
data: BytesMut::with_capacity(BUFFER_SIZE),
cipher: crypto::new_aead_decryptor(t, key, nounce),
cipher: crypto::new_aead_decryptor(t, key, nonce),
pos: 0,
sent_final: false,
tag_size: t.tag_size(),
read_step: ReadingStep::Length,
steps: DecryptReadStep::Length,
got_final: false,
}
}
pub fn get_ref(&self) -> &R {
&self.reader
}
/// Gets a mutable reference to the underlying reader.
///
/// # Warning
///
/// It is inadvisable to read directly from or write directly to the
/// underlying reader.
pub fn get_mut(&mut self) -> &mut R {
&mut self.reader
}
/// Unwraps this `DecryptedReader`, returning the underlying reader.
///
/// The internal buffer is flushed before returning the reader. Any leftover
/// data in the read buffer is lost.
pub fn into_inner(self) -> R {
self.reader
}
fn read_exact(&mut self, expect_length: usize, ignore_final: bool) -> io::Result<()> {
let mut incoming = [0u8; BUFFER_SIZE];
self.buffer.reserve(expect_length);
while self.buffer.len() < expect_length {
let remain = expect_length - self.buffer.len();
let rlen = cmp::min(remain, incoming.len());
match self.reader.read(&mut incoming[..rlen]) {
Ok(0) => {
if ignore_final && self.buffer.is_empty() {
self.sent_final = true;
return Ok(());
}
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "unexpected eof"));
}
Ok(n) => self.buffer.put_slice(&incoming[..n]),
Err(e) => return Err(e),
}
}
Ok(())
}
fn read_length(&mut self) -> io::Result<()> {
let expect_length = 2 + self.tag_size;
self.read_exact(expect_length, true)?;
if !self.sent_final {
// Ok, read length finished
{
let len = {
let mut len_buf = [0u8; 2];
self.cipher.decrypt(&self.buffer[..], &mut len_buf)?;
BigEndian::read_u16(&len_buf) as usize
};
if len > MAX_PACKET_SIZE {
use std::io::{Error, ErrorKind};
error!(
"AEAD packet size must be <= {}, but received length {}",
MAX_PACKET_SIZE, len
);
let err = Error::new(
ErrorKind::InvalidData,
format!(
"AEAD packet size must be <= {}, but received length {}",
MAX_PACKET_SIZE, len
),
);
return Err(err);
}
self.read_step = ReadingStep::DataAndTag(len);
}
self.buffer.clear();
}
Ok(())
}
fn read_data(&mut self, dlen: usize) -> io::Result<()> {
let expect_length = dlen + self.tag_size;
self.read_exact(expect_length, false)?;
if !self.sent_final {
{
// Ok, got data
self.data.clear();
self.data.reserve(dlen);
unsafe {
self.data.set_len(dlen); // Decrypted data has exactly the same length
}
self.cipher.decrypt(&self.buffer[..], &mut *self.data)?;
}
self.read_step = ReadingStep::Done;
self.buffer.clear();
}
Ok(())
}
fn read_some(&mut self) -> io::Result<()> {
while !self.sent_final {
match self.read_step {
ReadingStep::Length => self.read_length()?,
ReadingStep::DataAndTag(dlen) => {
self.read_data(dlen)?;
break; // Read finished! Break out
}
ReadingStep::Done => {
self.read_step = ReadingStep::Length;
self.data.clear();
}
}
}
Ok(())
}
}
impl<R> BufRead for DecryptedReader<R>
where
R: AsyncRead,
{
fn fill_buf(&mut self) -> io::Result<&[u8]> {
pub fn poll_read_decrypted<R>(
&mut self,
ctx: &mut Context<'_>,
r: &mut R,
dst: &mut [u8],
) -> Poll<io::Result<usize>>
where
R: AsyncRead + Unpin,
{
while self.pos >= self.data.len() {
if self.sent_final {
return Ok(&[]);
// Already received EOF
if self.got_final {
return Poll::Ready(Ok(0));
}
self.read_some()?;
if let ReadingStep::Done = self.read_step {
self.pos = 0;
// Refill buffer
match self.steps {
DecryptReadStep::Length => ready!(self.poll_read_decrypted_length(ctx, r))?,
DecryptReadStep::Data(len) => ready!(self.poll_read_decrypted_data(ctx, r, len))?,
}
}
Ok(&self.data[self.pos..])
let remaining_len = self.data.len() - self.pos;
let n = cmp::min(dst.len(), remaining_len);
(&mut dst[..n]).copy_from_slice(&self.data[self.pos..self.pos + n]);
self.pos += n;
Poll::Ready(Ok(n))
}
fn consume(&mut self, amt: usize) {
self.pos = cmp::min(self.pos + amt, self.data.len());
}
}
fn poll_read_decrypted_length<R>(&mut self, ctx: &mut Context<'_>, r: &mut R) -> Poll<io::Result<()>>
where
R: AsyncRead + Unpin,
{
let buf_len = 2 + self.tag_size;
ready!(self.poll_read_exact(ctx, r, buf_len, true))?;
if self.got_final {
return Poll::Ready(Ok(()));
}
impl<R> Read for DecryptedReader<R>
where
R: AsyncRead,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let nread = {
let mut available = self.fill_buf()?;
available.read(buf)?
// Done reading, decrypt it
let len = {
let mut len_buf = [0u8; 2];
self.cipher.decrypt(&self.buffer[..], &mut len_buf)?;
BigEndian::read_u16(&len_buf) as usize
};
self.consume(nread);
Ok(nread)
// Clear buffer before overwriting it
self.buffer.clear();
self.data.clear();
self.pos = 0;
// Next step, read data
self.steps = DecryptReadStep::Data(len);
self.buffer.reserve(len + self.tag_size);
self.data.reserve(len);
Poll::Ready(Ok(()))
}
fn poll_read_decrypted_data<R>(&mut self, ctx: &mut Context<'_>, r: &mut R, size: usize) -> Poll<io::Result<()>>
where
R: AsyncRead + Unpin,
{
let buf_len = size + self.tag_size;
ready!(self.poll_read_exact(ctx, r, buf_len, false))?;
// Done reading data, decrypt it
unsafe {
// It has enough space, I am sure about that
let buffer = slice::from_raw_parts_mut(self.data.bytes_mut().as_mut_ptr() as *mut u8, size);
self.cipher.decrypt(&self.buffer[..], buffer)?;
// Move forward the pointer
self.data.advance_mut(size);
}
// Clear buffer before overwriting it
self.buffer.clear();
// Reset read position
self.pos = 0;
// Next step, read length
self.steps = DecryptReadStep::Length;
self.buffer.reserve(2 + self.tag_size);
Poll::Ready(Ok(()))
}
fn poll_read_exact<R>(
&mut self,
ctx: &mut Context<'_>,
r: &mut R,
size: usize,
allow_eof: bool,
) -> Poll<io::Result<()>>
where
R: AsyncRead + Unpin,
{
while self.buffer.len() < size {
let remaining = size - self.buffer.len();
unsafe {
// It has enough space, I am sure about that
let buffer = slice::from_raw_parts_mut(self.buffer.bytes_mut().as_mut_ptr() as *mut u8, remaining);
let n = ready!(Pin::new(&mut *r).poll_read(ctx, buffer))?;
if n == 0 {
if self.buffer.is_empty() && allow_eof && !self.got_final {
// Read nothing
self.got_final = true;
return Poll::Ready(Ok(()));
} else {
use std::io::ErrorKind;
return Poll::Ready(Err(ErrorKind::UnexpectedEof.into()));
}
}
self.buffer.advance_mut(n);
}
}
Poll::Ready(Ok(()))
}
}
impl<R> DecryptedRead for DecryptedReader<R>
where
R: AsyncRead,
{
fn buffer_size(&self, data: &[u8]) -> usize {
2 + self.tag_size // len and len_tag
+ data.len() + self.tag_size // data and data_tag
}
enum EncryptWriteStep {
Nothing,
Writing(BytesMut, usize),
}
impl<R> AsyncRead for DecryptedReader<R> where R: AsyncRead {}
/// Writer wrapper that will encrypt data automatically
pub struct EncryptedWriter<W>
where
W: AsyncWrite,
{
writer: W,
pub struct EncryptedWriter {
cipher: BoxAeadEncryptor,
tag_size: usize,
steps: EncryptWriteStep,
}
impl<W> EncryptedWriter<W>
where
W: AsyncWrite,
{
impl EncryptedWriter {
/// Creates a new EncryptedWriter
pub fn new(w: W, t: CipherType, key: &[u8], nonce: &[u8]) -> EncryptedWriter<W> {
pub fn new(t: CipherType, key: &[u8], nonce: &[u8]) -> EncryptedWriter {
EncryptedWriter {
writer: w,
cipher: crypto::new_aead_encryptor(t, key, nonce),
tag_size: t.tag_size(),
steps: EncryptWriteStep::Nothing,
}
}
}
impl<W> EncryptedWrite for EncryptedWriter<W>
where
W: AsyncWrite,
{
fn write_raw(&mut self, data: &[u8]) -> io::Result<usize> {
self.writer.write(data)
pub fn poll_write_encrypted<W>(&mut self, ctx: &mut Context<'_>, w: &mut W, data: &[u8]) -> Poll<io::Result<usize>>
where
W: AsyncWrite + Unpin,
{
ready!(self.poll_write_all_encrypted(ctx, w, data))?;
Poll::Ready(Ok(data.len()))
}
fn flush(&mut self) -> io::Result<()> {
self.writer.flush()
}
fn encrypt<B: BufMut>(&mut self, data: &[u8], buf: &mut B) -> io::Result<()> {
pub fn poll_write_all_encrypted<W>(&mut self, ctx: &mut Context<'_>, w: &mut W, data: &[u8]) -> Poll<io::Result<()>>
where
W: AsyncWrite + Unpin,
{
// Data.Len is a 16-bit big-endian integer indicating the length of Data. It should be smaller than 0x3FFF.
assert!(
data.len() <= MAX_PACKET_SIZE,
"Buffer size too large, AEAD encryption protocol requires buffer to be smaller than 0x3FFF"
);
let output_length = self.buffer_size(data);
let data_length = data.len() as u16;
loop {
match self.steps {
EncryptWriteStep::Nothing => {
let output_length = self.buffer_size(data);
let data_length = data.len() as u16;
let mut data_len_buf = [0u8; 2];
BigEndian::write_u16(&mut data_len_buf, data_length);
let mut buf = BytesMut::with_capacity(output_length);
let output_length_size = 2 + self.tag_size;
self.cipher
.encrypt(&data_len_buf, unsafe { &mut buf.bytes_mut()[..output_length_size] });
self.cipher
.encrypt(data, unsafe { &mut buf.bytes_mut()[output_length_size..output_length] });
let mut data_len_buf = [0u8; 2];
BigEndian::write_u16(&mut data_len_buf, data_length);
unsafe {
buf.advance_mut(output_length);
unsafe {
let b = slice::from_raw_parts_mut(buf.bytes_mut().as_mut_ptr() as *mut u8, output_length);
let output_length_size = 2 + self.tag_size;
self.cipher.encrypt(&data_len_buf, &mut b[..output_length_size]);
self.cipher.encrypt(data, &mut b[output_length_size..output_length]);
buf.advance_mut(output_length);
}
self.steps = EncryptWriteStep::Writing(buf, 0);
}
EncryptWriteStep::Writing(ref mut buf, ref mut pos) => {
while *pos < buf.len() {
let n = ready!(Pin::new(&mut *w).poll_write(ctx, &buf[*pos..]))?;
if n == 0 {
use std::io::ErrorKind;
return Poll::Ready(Err(ErrorKind::UnexpectedEof.into()));
}
*pos += n;
}
self.steps = EncryptWriteStep::Nothing;
return Poll::Ready(Ok(()));
}
}
}
Ok(())
}
fn buffer_size(&self, data: &[u8]) -> usize {
+90 -103
View File
@@ -1,20 +1,21 @@
//! TCP relay client implementation
use std::{
io::{self, Read, Write},
io,
net::SocketAddr,
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
use futures::{self, Async, Future, Poll};
use log::trace;
use tokio::net::TcpStream;
use tokio_io::{io::flush, AsyncRead, AsyncWrite};
use tokio::{net::TcpStream, prelude::*};
use crate::relay::socks5::{
self, Address, Command, HandshakeRequest, HandshakeResponse, Reply, TcpRequestHeader, TcpResponseHeader,
};
use super::{CryptoStream, STcpStream};
use crate::{config::ServerConfig, context::SharedContext};
/// Socks5 proxy client
@@ -24,131 +25,117 @@ pub struct Socks5Client {
impl Socks5Client {
/// Connects to `addr` via `proxy`
pub fn connect<A>(addr: A, proxy: SocketAddr) -> impl Future<Item = Socks5Client, Error = io::Error> + Send
pub async fn connect<A>(addr: A, proxy: &SocketAddr) -> io::Result<Socks5Client>
where
Address: From<A>,
A: Send + 'static,
{
futures::lazy(move || TcpStream::connect(&proxy))
.and_then(move |s| {
// 1. Handshake
let hs = HandshakeRequest::new(vec![socks5::SOCKS5_AUTH_METHOD_NONE]);
trace!("Client connected, going to send handshake: {:?}", hs);
let mut s = TcpStream::connect(proxy).await?;
hs.write_to(s)
.and_then(flush)
.and_then(HandshakeResponse::read_from)
.and_then(|(s, rsp)| {
trace!("Got handshake response: {:?}", rsp);
assert_eq!(rsp.chosen_method, socks5::SOCKS5_AUTH_METHOD_NONE);
Ok(s)
})
})
.and_then(move |s| {
// 2. Send request header
let h = TcpRequestHeader::new(Command::TcpConnect, From::from(addr));
trace!("Going to connect, req: {:?}", h);
h.write_to(s)
.and_then(flush)
.and_then(|s| TcpResponseHeader::read_from(s).map_err(From::from))
.and_then(|(s, rsp)| {
trace!("Got response: {:?}", rsp);
match rsp.reply {
Reply::Succeeded => Ok(s),
r => {
let err = io::Error::new(io::ErrorKind::Other, format!("{}", r));
Err(err)
}
}
})
})
.map(|s| Socks5Client { stream: s })
// 1. Handshake
let hs = HandshakeRequest::new(vec![socks5::SOCKS5_AUTH_METHOD_NONE]);
trace!("Client connected, going to send handshake: {:?}", hs);
hs.write_to(&mut s).await?;
s.flush().await?;
let hsp = HandshakeResponse::read_from(&mut s).await?;
trace!("Got handshake response: {:?}", hsp);
assert_eq!(hsp.chosen_method, socks5::SOCKS5_AUTH_METHOD_NONE);
// 2. Send request header
let h = TcpRequestHeader::new(Command::TcpConnect, From::from(addr));
trace!("Going to connect, req: {:?}", h);
h.write_to(&mut s).await?;
s.flush().await?;
let hp = TcpResponseHeader::read_from(&mut s).await?;
trace!("Got response: {:?}", hp);
match hp.reply {
Reply::Succeeded => (),
r => {
let err = io::Error::new(io::ErrorKind::Other, format!("{}", r));
return Err(err);
}
}
Ok(Socks5Client { stream: s })
}
/// UDP Associate `addr` via `proxy`
pub fn udp_associate<A>(
addr: A,
proxy: SocketAddr,
) -> impl Future<Item = (Socks5Client, Address), Error = io::Error> + Send
pub async fn udp_associate<A>(addr: A, proxy: &SocketAddr) -> io::Result<(Socks5Client, Address)>
where
Address: From<A>,
A: Send + 'static,
{
futures::lazy(move || TcpStream::connect(&proxy))
.and_then(move |s| {
// 1. Handshake
let hs = HandshakeRequest::new(vec![socks5::SOCKS5_AUTH_METHOD_NONE]);
trace!("Client connected, going to send handshake: {:?}", hs);
let mut s = TcpStream::connect(proxy).await?;
hs.write_to(s)
.and_then(flush)
.and_then(HandshakeResponse::read_from)
.and_then(|(s, rsp)| {
trace!("Got handshake response: {:?}", rsp);
assert_eq!(rsp.chosen_method, socks5::SOCKS5_AUTH_METHOD_NONE);
Ok(s)
})
})
.and_then(move |s| {
// 2. Send request header
let h = TcpRequestHeader::new(Command::UdpAssociate, From::from(addr));
trace!("Going to connect, req: {:?}", h);
h.write_to(s)
.and_then(flush)
.and_then(|s| TcpResponseHeader::read_from(s).map_err(From::from))
.and_then(|(s, rsp)| {
trace!("Got response: {:?}", rsp);
match rsp.reply {
Reply::Succeeded => Ok((s, rsp.address)),
r => {
let err = io::Error::new(io::ErrorKind::Other, format!("{}", r));
Err(err)
}
}
})
})
.map(|(s, a)| (Socks5Client { stream: s }, a))
// 1. Handshake
let hs = HandshakeRequest::new(vec![socks5::SOCKS5_AUTH_METHOD_NONE]);
trace!("Client connected, going to send handshake: {:?}", hs);
hs.write_to(&mut s).await?;
s.flush().await?;
let hsp = HandshakeResponse::read_from(&mut s).await?;
trace!("Got handshake response: {:?}", hsp);
assert_eq!(hsp.chosen_method, socks5::SOCKS5_AUTH_METHOD_NONE);
// 2. Send request header
let h = TcpRequestHeader::new(Command::UdpAssociate, From::from(addr));
trace!("Going to connect, req: {:?}", h);
h.write_to(&mut s).await?;
s.flush().await?;
let hp = TcpResponseHeader::read_from(&mut s).await?;
trace!("Got response: {:?}", hp);
match hp.reply {
Reply::Succeeded => (),
r => {
let err = io::Error::new(io::ErrorKind::Other, format!("{}", r));
return Err(err);
}
}
Ok((Socks5Client { stream: s }, hp.address))
}
}
impl Read for Socks5Client {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.stream.read(buf)
impl AsyncRead for Socks5Client {
fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context, buf: &mut [u8]) -> Poll<Result<usize, io::Error>> {
Pin::new(&mut self.stream).poll_read(cx, buf)
}
}
impl Write for Socks5Client {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.stream.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.stream.flush()
}
}
impl AsyncRead for Socks5Client {}
impl AsyncWrite for Socks5Client {
fn shutdown(&mut self) -> Poll<(), io::Error> {
// FIXME: Finalize the internal cipher
Ok(Async::Ready(()))
fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<Result<usize, io::Error>> {
Pin::new(&mut self.stream).poll_write(cx, buf)
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), io::Error>> {
Pin::new(&mut self.stream).poll_flush(cx)
}
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), io::Error>> {
Pin::new(&mut self.stream).poll_shutdown(cx)
}
}
pub(crate) struct ServerClient {
pub r: super::DecryptedHalf<TcpStream>,
pub w: super::EncryptedHalf<TcpStream>,
pub stream: CryptoStream<STcpStream>,
}
impl ServerClient {
pub(crate) fn connect(
pub(crate) async fn connect(
context: SharedContext,
addr: Address,
addr: &Address,
svr_cfg: Arc<ServerConfig>,
) -> impl Future<Item = ServerClient, Error = io::Error> {
super::connect_proxy_server(context, svr_cfg.clone())
.and_then(|svr_s| super::proxy_server_handshake(svr_s, svr_cfg, addr))
.and_then(|(svr_r, svr_w)| svr_r.join(svr_w))
.map(|(r, w)| ServerClient { r, w })
) -> io::Result<ServerClient> {
let stream = super::connect_proxy_server(context, svr_cfg.clone()).await?;
Ok(ServerClient {
stream: super::proxy_server_handshake(stream, svr_cfg, addr).await?,
})
}
}
+45 -45
View File
@@ -4,7 +4,7 @@ use std::{
io,
net::SocketAddr,
sync::{
atomic::{AtomicBool, AtomicUsize, Ordering},
atomic::{AtomicUsize, Ordering},
Arc,
},
time::Duration,
@@ -13,19 +13,16 @@ use std::{
use crate::{
config::{ServerAddr, ServerConfig},
context::SharedContext,
relay::{boxed_future, dns_resolver::resolve},
};
use futures::{future, Future, Stream};
use log::debug;
use tokio::{self, net::UdpSocket, timer::Interval};
use tokio::{self, net::UdpSocket, time};
/// TCP Relay Server Context
pub struct TcpServerContext {
tx: AtomicUsize,
rx: AtomicUsize,
context: SharedContext,
stop_flag: Arc<AtomicBool>,
svr_cfg: Arc<ServerConfig>,
}
@@ -36,34 +33,28 @@ pub type SharedTcpServerContext = Arc<TcpServerContext>;
impl TcpServerContext {
/// Create a new server context
pub fn new(context: SharedContext, svr_cfg: Arc<ServerConfig>) -> SharedTcpServerContext {
let stop_flag = Arc::new(AtomicBool::new(false));
let ctx = TcpServerContext {
tx: AtomicUsize::new(0),
rx: AtomicUsize::new(0),
context,
stop_flag: stop_flag.clone(),
svr_cfg,
};
let ctx = Arc::new(ctx);
if ctx.context.config().manager_address.is_some() {
let ctx2 = ctx.clone();
let ctx = ctx.clone();
tokio::spawn(async move {
let mut interval = time::interval(UPDATE_INTERVAL);
while ctx.context.server_running() {
interval.tick().await;
let fut = Interval::new_interval(UPDATE_INTERVAL)
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("timer error: {}", e)))
.for_each(move |_| {
let ctx = ctx2.clone();
if stop_flag.load(Ordering::Acquire) {
// Finished
Err(io::Error::new(io::ErrorKind::Other, "server terminated"))
} else {
tokio::spawn(ctx.stat_interval().map_err(|_| ()));
Ok(())
}
});
tokio::spawn(fut.map_err(|_| ()));
let ctx = ctx.clone();
tokio::spawn(async move {
let _ = ctx.stat_interval().await;
});
}
});
}
ctx
@@ -85,32 +76,41 @@ impl TcpServerContext {
self.rx.fetch_add(x, Ordering::Release);
}
fn stat_interval(&self) -> impl Future<Item = (), Error = io::Error> + Send {
let addr_fut = match self.context.config().manager_address {
Some(ServerAddr::SocketAddr(ref addr)) => boxed_future(future::ok(*addr)),
Some(ServerAddr::DomainName(ref domain, ref port)) => {
let fut = resolve(self.context.clone(), &domain[..], *port, false).map(|vec_ipaddr| vec_ipaddr[0]);
boxed_future(fut)
}
None => unreachable!(),
};
async fn stat_interval(&self) -> io::Result<()> {
let svr_cfg = self.svr_cfg.clone();
let transmission = self.tx.load(Ordering::Acquire) + self.rx.load(Ordering::Acquire);
addr_fut
.and_then(move |addr| {
let any_addr = "0.0.0.0:0".parse::<SocketAddr>().unwrap();
UdpSocket::bind(&any_addr).map(move |socket| (socket, addr))
})
.and_then(move |(socket, addr)| {
let payload = format!("stat: {{\"{}\": {}}}", svr_cfg.addr().port(), transmission);
debug!("Sending Tcp Relay to {}, payload: {}", addr, payload);
socket.send_dgram(payload, &addr).map(|_| ())
})
}
let any_addr = "0.0.0.0:0".parse::<SocketAddr>().unwrap();
let mut socket = UdpSocket::bind(&any_addr).await?;
pub fn close(&self) {
self.stop_flag.store(true, Ordering::Release)
let payload = format!("stat: {{\"{}\": {}}}", svr_cfg.addr().port(), transmission);
let maddr = self
.context
.config()
.manager_address
.as_ref()
.expect("manager_address must not be None");
debug!("Sending Tcp Relay to {}, payload: {}", maddr, payload);
match maddr {
ServerAddr::SocketAddr(ref addr) => {
socket.send_to(payload.as_ref(), addr).await?;
}
#[cfg(feature = "trust-dns")]
ServerAddr::DomainName(ref domain, ref port) => {
use crate::relay::dns_resolver::resolve;
let addrs = resolve(self.context.clone(), &domain[..], *port, false).await?;
socket.send_to(payload.as_ref(), addrs[0]).await?;
}
#[cfg(not(feature = "trust-dns"))]
ServerAddr::DomainName(ref domain, ref port) => {
socket.send_to(payload.as_ref(), (domain.as_str(), *port)).await?;
}
}
Ok(())
}
}
+196 -392
View File
@@ -1,450 +1,254 @@
//! IO facilities for TCP relay
use std::{
io::{self, BufRead, Read},
mem,
time::{Duration, Instant},
io,
marker::{PhantomData, Unpin},
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
use bytes::{BufMut, BytesMut};
use futures::{Async, Future, Poll};
use tokio::timer::Delay;
use tokio_io::{
io::{copy, Copy},
try_nb, AsyncRead, AsyncWrite,
};
use byte_string::ByteStr;
use bytes::Bytes;
use futures::ready;
use log::trace;
use tokio::prelude::*;
use super::{
utils::{copy_timeout, copy_timeout_opt, CopyTimeout, CopyTimeoutOpt},
BUFFER_SIZE,
aead::{DecryptedReader as AeadDecryptedReader, EncryptedWriter as AeadEncryptedWriter},
stream::{DecryptedReader as StreamDecryptedReader, EncryptedWriter as StreamEncryptedWriter},
};
static DUMMY_BUFFER: [u8; BUFFER_SIZE] = [0u8; BUFFER_SIZE];
use crate::{config::ServerConfig, crypto::CipherCategory};
/// Reader to read data from ShadowSocks protocol
///
/// This trait requires `BufRead`, because obviously this reader has to contain a buffer inside,
/// which stores the decrypted data.
pub trait DecryptedRead: BufRead + AsyncRead {
/// Decrypt buffer size
fn buffer_size(&self, data: &[u8]) -> usize;
/// Copies all data to `w`
fn copy<W>(self, w: W) -> Copy<Self, W>
where
Self: Sized,
W: AsyncWrite,
{
copy(self, w)
}
/// Copies all data to `w`, return `TimedOut` if timeout reaches
fn copy_timeout<W>(self, w: W, timeout: Duration) -> CopyTimeout<Self, W>
where
Self: Sized,
W: AsyncWrite,
{
copy_timeout(self, w, timeout)
}
/// The same as `copy_timeout`, but has optional `timeout`
fn copy_timeout_opt<W>(self, w: W, timeout: Option<Duration>) -> CopyTimeoutOpt<Self, W>
where
Self: Sized,
W: AsyncWrite,
{
copy_timeout_opt(self, w, timeout)
}
enum DecryptedReader {
Aead(AeadDecryptedReader),
Stream(StreamDecryptedReader),
}
/// Writer that encrypt data and write it as ShadowSocks protocol
///
/// The writer cannot implement `io::Write`, because you cannot ensure that you can write all the data in a batch
/// in non-blocking I/O environment.
pub trait EncryptedWrite {
/// Writes raw bytes directly to the writer
fn write_raw(&mut self, data: &[u8]) -> io::Result<usize>;
/// Flush the writer
fn flush(&mut self) -> io::Result<()>;
/// Encrypt data into buffer for writing
fn encrypt<B: BufMut>(&mut self, data: &[u8], buf: &mut B) -> io::Result<()>;
/// Encrypt buffer size
fn buffer_size(&self, data: &[u8]) -> usize;
/// Encrypt data in `buf` and write all to the writer
fn write_all<B: AsRef<[u8]>>(self, buf: B) -> EncryptedWriteAll<Self, B>
where
Self: Sized,
{
EncryptedWriteAll::new(self, buf)
}
/// Copies all data from `r`
fn copy<R: Read>(self, r: R) -> EncryptedCopy<R, Self>
where
Self: Sized,
{
EncryptedCopy::new(r, self)
}
/// Copies all data from `r` with timeout
fn copy_timeout<R: Read>(self, r: R, timeout: Duration) -> EncryptedCopyTimeout<R, Self>
where
Self: Sized,
{
EncryptedCopyTimeout::new(r, self, timeout)
}
/// Copies all data from `r` with optional timeout
fn copy_timeout_opt<R: Read>(self, r: R, timeout: Option<Duration>) -> EncryptedCopyOpt<R, Self>
where
Self: Sized,
{
match timeout {
Some(t) => EncryptedCopyOpt::CopyTimeout(self.copy_timeout(r, t)),
None => EncryptedCopyOpt::Copy(self.copy(r)),
}
}
enum EncryptedWriter {
Aead(AeadEncryptedWriter),
Stream(StreamEncryptedWriter),
}
/// Write all data encrypted
pub enum EncryptedWriteAll<W, B>
where
W: EncryptedWrite,
B: AsRef<[u8]>,
{
Writing {
writer: W,
buf: B,
pos: usize,
enc_buf: BytesMut,
encrypted: bool,
},
Empty,
enum ReadStatus {
WaitIv(Vec<u8>, usize),
Established,
}
impl<W, B> EncryptedWriteAll<W, B>
where
W: EncryptedWrite,
B: AsRef<[u8]>,
{
fn new(w: W, buf: B) -> EncryptedWriteAll<W, B> {
let buffer_size = w.buffer_size(&DUMMY_BUFFER);
EncryptedWriteAll::Writing {
writer: w,
buf,
pos: 0,
enc_buf: BytesMut::with_capacity(buffer_size),
encrypted: false,
}
}
enum WriteStatus {
SendIv(Bytes, usize),
Established,
}
impl<W, B> Future for EncryptedWriteAll<W, B>
where
W: EncryptedWrite,
B: AsRef<[u8]>,
{
type Error = io::Error;
type Item = (W, B);
pub struct CryptoStream<S> {
stream: S,
dec: Option<DecryptedReader>,
enc: Option<EncryptedWriter>,
svr_cfg: Arc<ServerConfig>,
read_status: ReadStatus,
write_status: WriteStatus,
}
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match *self {
EncryptedWriteAll::Empty => panic!("poll after EncryptedWriteAll finished"),
EncryptedWriteAll::Writing {
ref mut writer,
ref buf,
ref mut pos,
ref mut enc_buf,
ref mut encrypted,
} => {
if !*encrypted {
*encrypted = true;
impl<S: Unpin> Unpin for CryptoStream<S> {}
// Ensure buffer has enough space
let buffer_len = writer.buffer_size(buf.as_ref());
enc_buf.reserve(buffer_len);
impl<S> CryptoStream<S> {
pub fn new(stream: S, svr_cfg: Arc<ServerConfig>) -> CryptoStream<S> {
let method = svr_cfg.method();
let prev_len = match method.category() {
CipherCategory::Stream => method.iv_size(),
CipherCategory::Aead => method.salt_size(),
};
writer.encrypt(buf.as_ref(), enc_buf)?;
}
while *pos < enc_buf.len() {
let n = try_nb!(writer.write_raw(&enc_buf[*pos..]));
*pos += n;
if n == 0 {
let err = io::Error::new(io::ErrorKind::Other, "zero-length write");
return Err(err);
}
}
let local_iv = match method.category() {
CipherCategory::Stream => {
let local_iv = method.gen_init_vec();
trace!("Generated Stream cipher IV {:?}", local_iv);
local_iv
}
}
CipherCategory::Aead => {
let local_salt = method.gen_salt();
trace!("Generated AEAD cipher salt {:?}", local_salt);
local_salt
}
};
match mem::replace(self, EncryptedWriteAll::Empty) {
EncryptedWriteAll::Writing { writer, buf, .. } => Ok((writer, buf).into()),
EncryptedWriteAll::Empty => unreachable!(),
CryptoStream {
stream,
dec: None,
enc: None,
svr_cfg,
read_status: ReadStatus::WaitIv(vec![0u8; prev_len], 0usize),
write_status: WriteStatus::SendIv(local_iv, 0usize),
}
}
}
/// Encrypted copy
pub struct EncryptedCopy<R, W>
impl<S> CryptoStream<S>
where
R: Read,
W: EncryptedWrite,
S: AsyncRead + Unpin,
{
reader: Option<R>,
writer: Option<W>,
read_done: bool,
amt: u64,
pos: usize,
cap: usize,
buf: BytesMut,
}
impl<R, W> EncryptedCopy<R, W>
where
R: Read,
W: EncryptedWrite,
{
fn new(r: R, w: W) -> EncryptedCopy<R, W> {
let buffer_size = w.buffer_size(&DUMMY_BUFFER);
EncryptedCopy {
reader: Some(r),
writer: Some(w),
read_done: false,
amt: 0,
pos: 0,
cap: 0,
buf: BytesMut::with_capacity(buffer_size),
}
}
}
impl<R, W> Future for EncryptedCopy<R, W>
where
R: Read,
W: EncryptedWrite,
{
type Error = io::Error;
type Item = (u64, R, W);
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let mut local_buf = [0u8; BUFFER_SIZE];
loop {
// If our buffer is empty, then we need to read some data to
// continue.
if self.pos == self.cap && !self.read_done {
let n = try_nb!(self.reader.as_mut().unwrap().read(&mut local_buf[..]));
self.buf.clear();
fn poll_read_handshake(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
if let ReadStatus::WaitIv(ref mut buf, ref mut pos) = self.read_status {
while *pos < buf.len() {
let n = ready!(Pin::new(&mut self.stream).poll_read(cx, &mut buf[*pos..]))?;
if n == 0 {
self.read_done = true;
} else {
let data = &local_buf[..n];
// Ensure we have enough space
let buffer_len = self.writer.as_mut().unwrap().buffer_size(data);
self.buf.reserve(buffer_len);
self.writer.as_mut().unwrap().encrypt(data, &mut self.buf)?;
use std::io::ErrorKind;
return Poll::Ready(Err(ErrorKind::UnexpectedEof.into()));
}
self.pos = 0;
self.cap = self.buf.len();
*pos += n;
}
// If our buffer has some data, let's write it out!
while self.pos < self.cap {
let i = try_nb!(self.writer.as_mut().unwrap().write_raw(&self.buf[self.pos..self.cap]));
self.pos += i;
self.amt += i as u64;
}
let method = self.svr_cfg.method();
let dec = match method.category() {
CipherCategory::Stream => {
trace!("Got Stream cipher IV {:?}", ByteStr::new(&buf));
DecryptedReader::Stream(StreamDecryptedReader::new(method, self.svr_cfg.key(), &buf))
}
CipherCategory::Aead => {
trace!("Got AEAD cipher salt {:?}", ByteStr::new(&buf));
DecryptedReader::Aead(AeadDecryptedReader::new(method, self.svr_cfg.key(), &buf))
}
};
// If we've written al the data and we've seen EOF, flush out the
// data and finish the transfer.
// done with the entire transfer.
if self.pos == self.cap && self.read_done {
try_nb!(self.writer.as_mut().unwrap().flush());
return Ok((self.amt, self.reader.take().unwrap(), self.writer.take().unwrap()).into());
}
self.dec = Some(dec);
self.read_status = ReadStatus::Established;
}
Poll::Ready(Ok(()))
}
fn priv_poll_read(mut self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
ready!(self.poll_read_handshake(ctx))?;
let stream = unsafe { &mut *(&mut self.stream as *mut _) };
match *self.dec.as_mut().unwrap() {
DecryptedReader::Aead(ref mut r) => r.poll_read_decrypted(ctx, stream, buf),
DecryptedReader::Stream(ref mut r) => r.poll_read_decrypted(ctx, stream, buf),
}
}
}
/// Encrypted copy
pub struct EncryptedCopyTimeout<R, W>
impl<S> CryptoStream<S>
where
R: Read,
W: EncryptedWrite,
S: AsyncWrite + Unpin,
{
reader: Option<R>,
writer: Option<W>,
read_done: bool,
amt: u64,
pos: usize,
cap: usize,
timeout: Duration,
timer: Option<Delay>,
read_buf: [u8; BUFFER_SIZE],
write_buf: BytesMut,
}
impl<R, W> EncryptedCopyTimeout<R, W>
where
R: Read,
W: EncryptedWrite,
{
fn new(r: R, w: W, dur: Duration) -> EncryptedCopyTimeout<R, W> {
let buffer_size = w.buffer_size(&DUMMY_BUFFER);
EncryptedCopyTimeout {
reader: Some(r),
writer: Some(w),
read_done: false,
amt: 0,
pos: 0,
cap: 0,
timeout: dur,
timer: None,
read_buf: [0u8; BUFFER_SIZE],
write_buf: BytesMut::with_capacity(buffer_size),
}
}
fn try_poll_timeout(&mut self) -> io::Result<()> {
match self.timer.as_mut() {
None => Ok(()),
Some(t) => match t.poll() {
Err(err) => panic!("Failed to poll on timer, err: {}", err),
Ok(Async::Ready(..)) => Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")),
Ok(Async::NotReady) => Ok(()),
},
}
}
fn clear_timer(&mut self) {
let _ = self.timer.take();
}
fn read_or_set_timeout(&mut self) -> io::Result<usize> {
// First, return if timeout
self.try_poll_timeout()?;
// Then, unset the previous timeout
self.clear_timer();
self.write_buf.clear();
match self.reader.as_mut().unwrap().read(&mut self.read_buf) {
Ok(0) => {
self.cap = 0;
self.pos = 0;
Ok(0)
}
Ok(n) => {
let data = &self.read_buf[..n];
// Ensoure we have enough space
let buffer_len = self.writer.as_mut().unwrap().buffer_size(data);
self.write_buf.reserve(buffer_len);
self.writer.as_mut().unwrap().encrypt(data, &mut self.write_buf)?;
self.cap = self.write_buf.len();
self.pos = 0;
Ok(n)
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
self.timer = Some(Delay::new(Instant::now() + self.timeout));
}
Err(e)
}
}
}
fn write_or_set_timeout(&mut self) -> io::Result<usize> {
// First, return if timeout
self.try_poll_timeout()?;
// Then, unset the previous timeout
self.clear_timer();
match self
.writer
.as_mut()
.unwrap()
.write_raw(&self.write_buf[self.pos..self.cap])
{
Ok(n) => {
self.pos += n;
Ok(n)
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
self.timer = Some(Delay::new(Instant::now() + self.timeout));
}
Err(e)
}
}
}
}
impl<R, W> Future for EncryptedCopyTimeout<R, W>
where
R: Read,
W: EncryptedWrite,
{
type Error = io::Error;
type Item = (u64, R, W);
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
loop {
// If our buffer is empty, then we need to read some data to
// continue.
if self.pos == self.cap && !self.read_done {
let n = try_nb!(self.read_or_set_timeout());
fn poll_write_handshake(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
if let WriteStatus::SendIv(ref iv, ref mut pos) = self.write_status {
while *pos < iv.len() {
let n = ready!(Pin::new(&mut self.stream).poll_write(cx, &iv[*pos..]))?;
if n == 0 {
self.read_done = true;
use std::io::ErrorKind;
return Poll::Ready(Err(ErrorKind::UnexpectedEof.into()));
}
*pos += n;
}
// If our buffer has some data, let's write it out!
while self.pos < self.cap {
let i = try_nb!(self.write_or_set_timeout());
if i == 0 {
let err = io::Error::new(io::ErrorKind::WriteZero, "copied zero bytes into writer");
return Err(err);
let method = self.svr_cfg.method();
let enc = match method.category() {
CipherCategory::Stream => {
trace!("Sent Stream cipher IV {:?}", ByteStr::new(&iv));
EncryptedWriter::Stream(StreamEncryptedWriter::new(method, self.svr_cfg.key(), &iv))
}
self.amt += i as u64;
}
CipherCategory::Aead => {
trace!("Sent AEAD cipher salt {:?}", ByteStr::new(&iv));
EncryptedWriter::Aead(AeadEncryptedWriter::new(method, self.svr_cfg.key(), &iv))
}
};
// If we've written al the data and we've seen EOF, flush out the
// data and finish the transfer.
// done with the entire transfer.
if self.pos == self.cap && self.read_done {
try_nb!(self.writer.as_mut().unwrap().flush());
return Ok((self.amt, self.reader.take().unwrap(), self.writer.take().unwrap()).into());
}
self.enc = Some(enc);
self.write_status = WriteStatus::Established;
}
Poll::Ready(Ok(()))
}
fn priv_poll_write(mut self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
ready!(self.poll_write_handshake(ctx))?;
let stream = unsafe { &mut *(&mut self.stream as *mut _) };
match *self.enc.as_mut().unwrap() {
EncryptedWriter::Aead(ref mut w) => w.poll_write_encrypted(ctx, stream, buf),
EncryptedWriter::Stream(ref mut w) => w.poll_write_encrypted(ctx, stream, buf),
}
}
fn priv_poll_flush(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
AsyncWrite::poll_flush(Pin::new(&mut self.stream), ctx)
}
fn priv_poll_shutdown(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
AsyncWrite::poll_shutdown(Pin::new(&mut self.stream), ctx)
}
}
/// Work for both timeout or no timeout
pub enum EncryptedCopyOpt<R, W>
impl<S> CryptoStream<S>
where
R: Read,
W: EncryptedWrite,
S: AsyncRead + AsyncWrite + Unpin,
{
Copy(EncryptedCopy<R, W>),
CopyTimeout(EncryptedCopyTimeout<R, W>),
pub fn split(&mut self) -> (CryptoStreamReadHalf<'_, S>, CryptoStreamWriteHalf<'_, S>) {
let p = self as *mut _;
(
CryptoStreamReadHalf(p, PhantomData),
CryptoStreamWriteHalf(p, PhantomData),
)
}
}
impl<R, W> Future for EncryptedCopyOpt<R, W>
impl<S> AsyncRead for CryptoStream<S>
where
R: Read,
W: EncryptedWrite,
S: AsyncRead + Unpin,
{
type Error = io::Error;
type Item = (u64, R, W);
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match *self {
EncryptedCopyOpt::Copy(ref mut c) => c.poll(),
EncryptedCopyOpt::CopyTimeout(ref mut c) => c.poll(),
}
fn poll_read(self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
self.priv_poll_read(ctx, buf)
}
}
impl<S> AsyncWrite for CryptoStream<S>
where
S: AsyncWrite + Unpin,
{
fn poll_write(self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
self.priv_poll_write(ctx, buf)
}
fn poll_flush(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.priv_poll_flush(ctx)
}
fn poll_shutdown(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.priv_poll_shutdown(ctx)
}
}
pub struct CryptoStreamReadHalf<'a, S: 'a>(*mut CryptoStream<S>, PhantomData<&'a S>);
unsafe impl<'a, S: Send + 'a> Send for CryptoStreamReadHalf<'a, S> {}
impl<'a, S: AsyncRead + Unpin + 'a> AsyncRead for CryptoStreamReadHalf<'a, S> {
fn poll_read(mut self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
let stream = unsafe { &mut *self.0 };
Pin::new(stream).priv_poll_read(ctx, buf)
}
}
pub struct CryptoStreamWriteHalf<'a, S: 'a>(*mut CryptoStream<S>, PhantomData<&'a S>);
unsafe impl<'a, S: Send + 'a> Send for CryptoStreamWriteHalf<'a, S> {}
impl<'a, S: AsyncWrite + Unpin + 'a> AsyncWrite for CryptoStreamWriteHalf<'a, S> {
fn poll_write(mut self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
let stream = unsafe { &mut *self.0 };
Pin::new(stream).priv_poll_write(ctx, buf)
}
fn poll_flush(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
let stream = unsafe { &mut *self.0 };
Pin::new(stream).priv_poll_flush(ctx)
}
fn poll_shutdown(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
let stream = unsafe { &mut *self.0 };
Pin::new(stream).priv_poll_shutdown(ctx)
}
}
+6 -5
View File
@@ -2,12 +2,13 @@
use std::io;
use futures::Future;
use super::socks5_local;
use super::{socks5_local, tunnel_local};
use crate::context::SharedContext;
/// Starts a TCP local server
pub fn run(context: SharedContext) -> impl Future<Item = (), Error = io::Error> + Send {
socks5_local::run(context)
pub async fn run(context: SharedContext) -> io::Result<()> {
match context.config().forward {
Some(..) => tunnel_local::run(context).await,
None => socks5_local::run(context).await,
}
}
+203 -489
View File
@@ -1,40 +1,30 @@
//! Relay for TCP implementation
use std::{
io::{self, BufRead, Read, Write},
iter::{IntoIterator, Iterator},
mem,
net::SocketAddr,
sync::Arc,
time::Duration,
};
// Allow for futures
// Maybe removed in the future
#![allow(clippy::unnecessary_mut_passed)]
use crate::{
config::{ConfigType, ServerAddr, ServerConfig},
context::SharedContext,
crypto::CipherCategory,
relay::{boxed_future, dns_resolver::resolve, socks5::Address},
};
use std::io;
use std::marker::Unpin;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use std::time::Duration;
use byte_string::ByteStr;
use bytes::{BufMut, BytesMut};
use futures::{self, Async, Future, Poll};
use log::{error, trace};
use tokio::{
net::{tcp::ConnectFuture, TcpStream},
timer::Timeout,
};
use tokio_io::{
io::{read_exact, write_all, ReadHalf, WriteHalf},
try_nb, AsyncRead, AsyncWrite,
};
use crate::config::{ConfigType, ServerAddr, ServerConfig};
use crate::context::SharedContext;
use crate::relay::socks5::Address;
use crate::relay::utils::try_timeout;
pub use self::crypto_io::{DecryptedRead, EncryptedWrite};
use self::{
aead::{DecryptedReader as AeadDecryptedReader, EncryptedWriter as AeadEncryptedWriter},
stream::{DecryptedReader as StreamDecryptedReader, EncryptedWriter as StreamEncryptedWriter},
};
use bytes::BytesMut;
use futures::future::FusedFuture;
use futures::{ready, select, Future};
use log::trace;
use tokio::io::{ReadHalf, WriteHalf};
use tokio::net::TcpStream;
use tokio::prelude::*;
use tokio::time::{self, Delay};
mod aead;
pub mod client;
@@ -45,224 +35,144 @@ mod monitor;
pub mod server;
mod socks5_local;
mod stream;
mod tunnel_local;
mod utils;
pub use self::crypto_io::CryptoStream;
const BUFFER_SIZE: usize = 8 * 1024; // 8K buffer
// /// Directions in the tunnel
// #[derive(Debug, Copy, Clone)]
// pub enum TunnelDirection {
// /// Client -> Server
// Client2Server,
// /// Client <- Server
// Server2Client,
// }
type TcpReadHalf<S /* : Read + Write + AsyncRead + AsyncWrite + Send */> = ReadHalf<S>;
type TcpWriteHalf<S /* : Read + Write + AsyncRead + AsyncWrite + Send */> = WriteHalf<S>;
/// `ReadHalf `of `TcpStream` with decryption
pub enum DecryptedHalf<S>
where
S: Read + Write + AsyncRead + AsyncWrite + Send,
{
Stream(StreamDecryptedReader<TcpReadHalf<S>>),
Aead(AeadDecryptedReader<TcpReadHalf<S>>),
/// Shadowsocks' Connection
///
/// The only feature: Supports timeout
pub struct Connection<S> {
// Actual connection socket
stream: S,
// Timer instance
// Read and Write operations shares the same timer
timer: Option<Delay>,
// User defined server timeout
timeout: Option<Duration>,
}
macro_rules! ref_half_do {
($self:expr,$t:ident,$m:ident$(,$p:expr)*) => {
match *$self {
$t::Stream(ref d) => d.$m($($p),*),
$t::Aead(ref d) => d.$m($($p),*),
impl<S> Connection<S> {
pub fn new(stream: S, timeout: Option<Duration>) -> Connection<S> {
Connection {
stream,
timer: None,
timeout,
}
}
}
macro_rules! mut_half_do {
($self:expr,$t:ident,$m:ident$(,$p:expr)*) => {
match *$self {
$t::Stream(ref mut d) => d.$m($($p),*),
$t::Aead(ref mut d) => d.$m($($p),*),
}
}
}
impl<S> Read for DecryptedHalf<S>
where
S: Read + Write + AsyncRead + AsyncWrite + Send,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
mut_half_do!(self, DecryptedHalf, read, buf)
}
}
impl<S> DecryptedRead for DecryptedHalf<S>
where
S: Read + Write + AsyncRead + AsyncWrite + Send,
{
fn buffer_size(&self, data: &[u8]) -> usize {
ref_half_do!(self, DecryptedHalf, buffer_size, data)
}
}
impl<S> AsyncRead for DecryptedHalf<S> where S: Read + Write + AsyncRead + AsyncWrite + Send {}
impl<S> BufRead for DecryptedHalf<S>
where
S: Read + Write + AsyncRead + AsyncWrite + Send,
{
fn fill_buf(&mut self) -> io::Result<&[u8]> {
mut_half_do!(self, DecryptedHalf, fill_buf)
}
fn consume(&mut self, amt: usize) {
mut_half_do!(self, DecryptedHalf, consume, amt)
}
}
impl<S> From<StreamDecryptedReader<TcpReadHalf<S>>> for DecryptedHalf<S>
where
S: Read + Write + AsyncRead + AsyncWrite + Send,
{
fn from(r: StreamDecryptedReader<TcpReadHalf<S>>) -> DecryptedHalf<S> {
DecryptedHalf::Stream(r)
}
}
impl<S> From<AeadDecryptedReader<TcpReadHalf<S>>> for DecryptedHalf<S>
where
S: Read + Write + AsyncRead + AsyncWrite + Send,
{
fn from(r: AeadDecryptedReader<TcpReadHalf<S>>) -> DecryptedHalf<S> {
DecryptedHalf::Aead(r)
}
}
/// `WriteHalf` of `TcpStream` with encryption
pub enum EncryptedHalf<S>
where
S: Read + Write + AsyncRead + AsyncWrite + Send,
{
Stream(StreamEncryptedWriter<TcpWriteHalf<S>>),
Aead(AeadEncryptedWriter<TcpWriteHalf<S>>),
}
impl<S> EncryptedWrite for EncryptedHalf<S>
where
S: Read + Write + AsyncRead + AsyncWrite + Send,
{
fn write_raw(&mut self, data: &[u8]) -> io::Result<usize> {
mut_half_do!(self, EncryptedHalf, write_raw, data)
}
fn flush(&mut self) -> io::Result<()> {
mut_half_do!(self, EncryptedHalf, flush)
}
fn encrypt<B: BufMut>(&mut self, data: &[u8], buf: &mut B) -> io::Result<()> {
mut_half_do!(self, EncryptedHalf, encrypt, data, buf)
}
fn buffer_size(&self, data: &[u8]) -> usize {
ref_half_do!(self, EncryptedHalf, buffer_size, data)
}
}
impl<S> From<StreamEncryptedWriter<TcpWriteHalf<S>>> for EncryptedHalf<S>
where
S: Read + Write + AsyncRead + AsyncWrite + Send,
{
fn from(d: StreamEncryptedWriter<TcpWriteHalf<S>>) -> EncryptedHalf<S> {
EncryptedHalf::Stream(d)
}
}
impl<S> From<AeadEncryptedWriter<TcpWriteHalf<S>>> for EncryptedHalf<S>
where
S: Read + Write + AsyncRead + AsyncWrite + Send,
{
fn from(d: AeadEncryptedWriter<TcpWriteHalf<S>>) -> EncryptedHalf<S> {
EncryptedHalf::Aead(d)
}
}
/// Try to connect every IPs one by one
enum TcpStreamConnect<I: Iterator<Item = SocketAddr>> {
Empty,
Connect {
last_err: Option<io::Error>,
addr_iter: I,
opt_stream_new: Option<(ConnectFuture, SocketAddr)>,
},
}
impl<I: Iterator<Item = SocketAddr>> TcpStreamConnect<I> {
fn new(iter: I) -> TcpStreamConnect<I> {
TcpStreamConnect::Connect {
last_err: None,
addr_iter: iter,
opt_stream_new: None,
}
}
}
impl<I: Iterator<Item = SocketAddr>> Future for TcpStreamConnect<I> {
type Error = io::Error;
type Item = TcpStream;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
fn make_timeout_error() -> io::Error {
use std::io::ErrorKind;
ErrorKind::TimedOut.into()
}
match *self {
TcpStreamConnect::Empty => unreachable!(),
TcpStreamConnect::Connect {
ref mut last_err,
ref mut addr_iter,
ref mut opt_stream_new,
} => {
loop {
// 1. Poll before doing anything else
if let Some((ref mut stream_new, ref addr)) = *opt_stream_new {
match stream_new.poll() {
Ok(Async::Ready(stream)) => return Ok(Async::Ready(stream)),
Ok(Async::NotReady) => return Ok(Async::NotReady),
Err(ref err) if err.kind() == ErrorKind::WouldBlock => return Ok(Async::NotReady),
Err(err) => {
error!("Failed to connect {}: {}", addr, err);
*last_err = Some(err);
}
}
}
match addr_iter.next() {
None => break,
Some(addr) => {
*opt_stream_new = Some((TcpStream::connect(&addr), addr));
}
}
fn poll_timeout(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
loop {
if let Some(ref mut timer) = self.timer {
ready!(Pin::new(timer).poll(cx));
// FIXME: Clear self.timer or not?
return Poll::Ready(Err(Connection::<S>::make_timeout_error()));
} else {
match self.timeout {
Some(timeout) => self.timer = Some(time::delay_for(timeout)),
None => break,
}
}
}
Poll::Ready(Ok(()))
}
match mem::replace(self, TcpStreamConnect::Empty) {
TcpStreamConnect::Empty => unreachable!(),
TcpStreamConnect::Connect { last_err, .. } => match last_err {
None => {
let err = io::Error::new(ErrorKind::Other, "connect TCP without any addresses");
Err(err)
}
Some(err) => Err(err),
},
fn cancel_timeout(&mut self) {
let _ = self.timer.take();
}
}
impl<S> Connection<S>
where
S: AsyncRead + AsyncWrite + Unpin,
{
pub fn split(self) -> (ReadHalf<Connection<S>>, WriteHalf<Connection<S>>) {
use tokio::io::split;
split(self)
}
}
impl<S> Deref for Connection<S> {
type Target = S;
fn deref(&self) -> &Self::Target {
&self.stream
}
}
impl<S> DerefMut for Connection<S> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.stream
}
}
impl<S: Unpin> Unpin for Connection<S> {}
impl<S> AsyncRead for Connection<S>
where
S: AsyncRead + Unpin,
{
fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
match Pin::new(&mut self.stream).poll_read(cx, buf) {
Poll::Ready(r) => {
self.cancel_timeout();
Poll::Ready(r)
}
Poll::Pending => {
ready!(self.poll_timeout(cx))?;
Poll::Pending
}
}
}
}
fn connect_proxy_server(
context: SharedContext,
svr_cfg: Arc<ServerConfig>,
) -> impl Future<Item = TcpStream, Error = io::Error> + Send {
impl<S> AsyncWrite for Connection<S>
where
S: AsyncWrite + Unpin,
{
fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
match Pin::new(&mut self.stream).poll_write(cx, buf) {
Poll::Ready(r) => {
self.cancel_timeout();
Poll::Ready(r)
}
Poll::Pending => {
ready!(self.poll_timeout(cx))?;
Poll::Pending
}
}
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
match Pin::new(&mut self.stream).poll_flush(cx) {
Poll::Ready(r) => {
self.cancel_timeout();
Poll::Ready(r)
}
Poll::Pending => {
ready!(self.poll_timeout(cx))?;
Poll::Pending
}
}
}
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut self.stream).poll_shutdown(cx)
}
}
pub type STcpStream = Connection<TcpStream>;
/// Connect to proxy server with `ServerConfig`
async fn connect_proxy_server(context: SharedContext, svr_cfg: Arc<ServerConfig>) -> io::Result<STcpStream> {
let timeout = svr_cfg.timeout();
let svr_addr = match context.config().config_type {
@@ -273,286 +183,90 @@ fn connect_proxy_server(
trace!("Connecting to proxy {:?}, timeout: {:?}", svr_addr, timeout);
match svr_addr {
ServerAddr::SocketAddr(ref addr) => {
let fut = try_timeout(TcpStream::connect(addr), timeout);
boxed_future(fut)
let stream = try_timeout(TcpStream::connect(addr), timeout).await?;
Ok(STcpStream::new(stream, timeout))
}
#[cfg(feature = "trust-dns")]
ServerAddr::DomainName(ref domain, port) => {
let fut = {
try_timeout(resolve(context, &domain[..], *port, false), timeout).and_then(move |vec_ipaddr| {
let fut = TcpStreamConnect::new(vec_ipaddr.into_iter());
try_timeout(fut, timeout)
})
};
boxed_future(fut)
use crate::relay::dns_resolver::resolve;
use log::error;
let vec_ipaddr = try_timeout(resolve(context, &domain[..], *port, false), timeout).await?;
assert!(!vec_ipaddr.is_empty());
let mut last_err: Option<io::Error> = None;
for addr in &vec_ipaddr {
match try_timeout(TcpStream::connect(addr), timeout).await {
Ok(s) => return Ok(STcpStream::new(s, timeout)),
Err(e) => {
error!(
"Failed to connect {}:{}, resolved address {}, try another (err: {})",
domain, port, addr, e
);
last_err = Some(e);
}
}
}
let err = last_err.unwrap();
error!(
"Failed to connect {}:{}, tried all addresses but still failed (last err: {})",
domain, port, err
);
Err(err)
}
#[cfg(not(feature = "trust-dns"))]
ServerAddr::DomainName(ref domain, port) => {
let stream = try_timeout(TcpStream::connect((domain.as_str(), *port)), timeout).await?;
Ok(STcpStream::new(stream, timeout))
}
}
}
/// Handshake logic for ShadowSocks Client
pub fn proxy_server_handshake<S>(
remote_stream: S,
pub async fn proxy_server_handshake(
remote_stream: STcpStream,
svr_cfg: Arc<ServerConfig>,
relay_addr: Address,
) -> impl Future<
Item = (
impl Future<Item = DecryptedHalf<S>, Error = io::Error> + Send,
impl Future<Item = EncryptedHalf<S>, Error = io::Error> + Send,
),
Error = io::Error,
> + Send
where
S: Read + Write + AsyncRead + AsyncWrite + Send + 'static,
{
let timeout = svr_cfg.timeout();
proxy_handshake(remote_stream, svr_cfg).and_then(move |(r_fut, w_fut)| {
let w_fut = w_fut.and_then(move |enc_w| {
// Send relay address to remote
let mut buf = BytesMut::with_capacity(relay_addr.serialized_len());
relay_addr.write_to_buf(&mut buf);
relay_addr: &Address,
) -> io::Result<CryptoStream<STcpStream>> {
let mut stream = CryptoStream::new(remote_stream, svr_cfg.clone());
trace!(
"Got encrypt stream and going to send addr: {:?}, buf: {:?}",
relay_addr,
buf
);
trace!("Got encrypt stream and going to send addr: {:?}", relay_addr);
try_timeout(enc_w.write_all(buf), timeout).map(|(w, _)| w)
});
// Send relay address to remote
let mut addr_buf = BytesMut::with_capacity(relay_addr.serialized_len());
relay_addr.write_to_buf(&mut addr_buf);
stream.write_all(&addr_buf).await?;
Ok((r_fut, w_fut))
})
}
/// ShadowSocks Client-Server handshake protocol
/// Exchange cipher IV and creates stream wrapper
pub fn proxy_handshake<S>(
remote_stream: S,
svr_cfg: Arc<ServerConfig>,
) -> impl Future<
Item = (
impl Future<Item = DecryptedHalf<S>, Error = io::Error> + Send,
impl Future<Item = EncryptedHalf<S>, Error = io::Error> + Send,
),
Error = io::Error,
> + Send
where
S: Read + Write + AsyncRead + AsyncWrite + Send + 'static,
{
futures::lazy(|| Ok(remote_stream.split())).and_then(move |(r, w)| {
let timeout = svr_cfg.timeout();
let svr_cfg_cloned = svr_cfg.clone();
let enc = {
// Encrypt data to remote server
// Send initialize vector to remote and create encryptor
let method = svr_cfg.method();
let prev_buf = match method.category() {
CipherCategory::Stream => {
let local_iv = method.gen_init_vec();
trace!("Going to send initialize vector: {:?}", local_iv);
local_iv
}
CipherCategory::Aead => {
let local_salt = method.gen_salt();
trace!("Going to send salt: {:?}", local_salt);
local_salt
}
};
try_timeout(write_all(w, prev_buf), timeout).and_then(move |(w, prev_buf)| {
match svr_cfg.method().category() {
CipherCategory::Stream => {
let local_iv = prev_buf;
let wtr = StreamEncryptedWriter::new(w, svr_cfg.method(), svr_cfg.key(), &local_iv);
Ok(From::from(wtr))
}
CipherCategory::Aead => {
let local_salt = prev_buf;
let wtr = AeadEncryptedWriter::new(w, svr_cfg.method(), svr_cfg.key(), &local_salt[..]);
Ok(From::from(wtr))
}
}
})
};
let dec = {
let svr_cfg = svr_cfg_cloned;
// Decrypt data from remote server
let method = svr_cfg.method();
let prev_len = match method.category() {
CipherCategory::Stream => method.iv_size(),
CipherCategory::Aead => method.salt_size(),
};
try_timeout(read_exact(r, vec![0u8; prev_len]), timeout).and_then(move |(r, remote_iv)| {
match svr_cfg.method().category() {
CipherCategory::Stream => {
trace!("Got initialize vector {:?}", ByteStr::new(&remote_iv));
let decrypt_stream = StreamDecryptedReader::new(r, svr_cfg.method(), svr_cfg.key(), &remote_iv);
Ok(From::from(decrypt_stream))
}
CipherCategory::Aead => {
trace!("Got salt {:?}", ByteStr::new(&remote_iv));
let dr = AeadDecryptedReader::new(r, svr_cfg.method(), svr_cfg.key(), &remote_iv);
Ok(From::from(dr))
}
}
})
};
Ok((dec, enc))
})
Ok(stream)
}
/// Establish tunnel between server and client
// pub fn tunnel<CF, CFI, SF, SFI>(addr: Address, c2s: CF, s2c: SF) -> impl Future<Item = (), Error = io::Error> + Send
pub fn tunnel<CF, CFI, SF, SFI>(c2s: CF, s2c: SF) -> impl Future<Item = (), Error = io::Error> + Send
pub async fn tunnel<CF, CFI, SF, SFI>(mut c2s: CF, mut s2c: SF) -> io::Result<()>
where
CF: Future<Item = CFI, Error = io::Error> + Send + 'static,
SF: Future<Item = SFI, Error = io::Error> + Send + 'static,
CF: Future<Output = io::Result<CFI>> + Unpin + FusedFuture,
SF: Future<Output = io::Result<SFI>> + Unpin + FusedFuture,
{
c2s.map(|_| ()).select(s2c.map(|_| ())).then(|r| match r {
Ok(..) => Ok(()),
Err((err, _)) => Err(err),
})
// let addr = Arc::new(addr);
// let cloned_addr = addr.clone();
// let c2s = c2s.then(move |res| {
// match res {
// Ok(..) => {
// // Continue reading response from remote server
// trace!("Relay {} client -> server is finished", cloned_addr);
// Ok(TunnelDirection::Client2Server)
// }
// Err(err) => {
// error!("Relay {} client -> server aborted: {}", cloned_addr, err);
// Err(err)
// }
// }
// });
// let cloned_addr = addr.clone();
// let s2c = s2c.then(move |res| match res {
// Ok(..) => {
// trace!("Relay {} client <- server is finished", cloned_addr);
// Ok(TunnelDirection::Server2Client)
// }
// Err(err) => {
// error!("Relay {} client <- server aborted: {}", cloned_addr, err);
// Err(err)
// }
// });
// c2s.select(s2c)
// .and_then(move |(dir, _)| {
// match dir {
// TunnelDirection::Server2Client => trace!("Relay {} client <- server is closed, abort connection", addr),
// TunnelDirection::Client2Server => trace!("Relay {} server -> client is closed, abort connection", addr),
// }
// Ok(())
// })
// .map_err(|(err, _)| err)
}
/// Read until EOF, and ignore
pub enum IgnoreUntilEnd<R: Read> {
Pending { r: R, amt: u64 },
Empty,
}
impl<R: Read> Future for IgnoreUntilEnd<R> {
type Error = io::Error;
type Item = u64;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match *self {
IgnoreUntilEnd::Empty => panic!("poll IgnoreUntilEnd after it is finished"),
IgnoreUntilEnd::Pending { ref mut r, ref mut amt } => {
let mut buf = [0u8; 4096];
loop {
let n = try_nb!(r.read(&mut buf));
*amt += n as u64;
if n == 0 {
break;
}
}
}
}
match mem::replace(self, IgnoreUntilEnd::Empty) {
IgnoreUntilEnd::Pending { amt, .. } => Ok(amt.into()),
IgnoreUntilEnd::Empty => unreachable!(),
}
select! {
r1 = c2s => r1.map(|_| ()),
r2 = s2c => r2.map(|_| ()),
}
}
/// Ignore all data from the reader
pub fn ignore_until_end<R: Read>(r: R) -> IgnoreUntilEnd<R> {
IgnoreUntilEnd::Pending { r, amt: 0 }
}
pub enum TimeoutFuture<T, F>
pub async fn ignore_until_end<R>(r: &mut R) -> io::Result<u64>
where
T: 'static,
F: Future<Item = T, Error = io::Error> + Send + 'static,
R: AsyncRead + Unpin,
{
Direct(F),
Wait(Timeout<F>),
}
impl<T, F> Future for TimeoutFuture<T, F>
where
T: 'static,
F: Future<Item = T, Error = io::Error> + Send + 'static,
{
type Error = io::Error;
type Item = T;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match *self {
TimeoutFuture::Direct(ref mut f) => f.poll(),
TimeoutFuture::Wait(ref mut f) => match f.poll() {
Ok(Async::NotReady) => Ok(Async::NotReady),
Ok(Async::Ready(x)) => Ok(Async::Ready(x)),
Err(err) => match err.into_inner() {
Some(e) => Err(e),
None => Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")),
},
},
let mut buf = [0u8; BUFFER_SIZE];
let mut amt = 0u64;
loop {
let n = r.read(&mut buf).await?;
if n == 0 {
break;
}
amt += n as u64;
}
Ok(amt)
}
fn try_timeout<T, F>(fut: F, dur: Option<Duration>) -> impl Future<Item = T, Error = io::Error> + Send
where
F: Future<Item = T, Error = io::Error> + Send + 'static,
T: 'static,
{
use tokio::prelude::*;
match dur {
Some(dur) => TimeoutFuture::Wait(fut.timeout(dur)),
None => TimeoutFuture::Direct(fut),
}
}
// fn io_timeout<T, F>(fut: F, dur: Duration) -> impl Future<Item = T, Error = io::Error> + Send
// where
// F: Future<Item = T, Error = io::Error> + Send + 'static,
// T: 'static,
// {
// use tokio::prelude::*;
// TimeoutFuture::Wait(fut.timeout(dur))
// }
+40 -33
View File
@@ -1,67 +1,74 @@
//! Server traffic monitor
use std::{
io::{self, Read, Write},
io,
marker::Unpin,
ops::{Deref, DerefMut},
pin::Pin,
task::{Context, Poll},
};
use tokio::{
io::{AsyncRead, AsyncWrite},
net::TcpStream,
prelude::Async,
};
use tokio::io::{AsyncRead, AsyncWrite};
use super::context::SharedTcpServerContext;
pub struct TcpMonStream {
stream: TcpStream,
pub struct TcpMonStream<S> {
stream: S,
context: SharedTcpServerContext,
}
impl TcpMonStream {
pub fn new(c: SharedTcpServerContext, s: TcpStream) -> TcpMonStream {
impl<S> TcpMonStream<S> {
pub fn new(c: SharedTcpServerContext, s: S) -> TcpMonStream<S> {
TcpMonStream { stream: s, context: c }
}
}
impl Read for TcpMonStream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let n = self.stream.read(buf)?;
impl<S> AsyncRead for TcpMonStream<S>
where
S: AsyncRead + Unpin,
{
fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
let n = match Pin::new(&mut self.stream).poll_read(cx, buf)? {
Poll::Ready(n) => n,
Poll::Pending => return Poll::Pending,
};
self.context.incr_rx(n);
Ok(n)
Poll::Ready(Ok(n))
}
}
impl Write for TcpMonStream {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let n = self.stream.write(buf)?;
impl<S> AsyncWrite for TcpMonStream<S>
where
S: AsyncWrite + Unpin,
{
fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
let n = match Pin::new(&mut self.stream).poll_write(cx, buf)? {
Poll::Ready(n) => n,
Poll::Pending => return Poll::Pending,
};
self.context.incr_tx(n);
Ok(n)
Poll::Ready(Ok(n))
}
fn flush(&mut self) -> io::Result<()> {
self.stream.flush()
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut self.stream).poll_flush(cx)
}
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut self.stream).poll_shutdown(cx)
}
}
impl AsyncRead for TcpMonStream {}
impl<S> Deref for TcpMonStream<S> {
type Target = S;
impl AsyncWrite for TcpMonStream {
fn shutdown(&mut self) -> Result<Async<()>, io::Error> {
AsyncWrite::shutdown(&mut self.stream)
}
}
impl Deref for TcpMonStream {
type Target = TcpStream;
fn deref(&self) -> &TcpStream {
fn deref(&self) -> &Self::Target {
&self.stream
}
}
impl DerefMut for TcpMonStream {
fn deref_mut(&mut self) -> &mut TcpStream {
impl<S> DerefMut for TcpMonStream<S> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.stream
}
}
+179 -229
View File
@@ -1,197 +1,33 @@
//! Relay for TCP server that running on the server side
use std::{
io::{self, ErrorKind},
net::SocketAddr,
sync::Arc,
time::Duration,
};
use std::{io, net::SocketAddr, sync::Arc};
use crate::relay::{
boxed_future,
dns_resolver::resolve,
socks5::Address,
tcprelay::crypto_io::{DecryptedRead, EncryptedWrite},
};
use crate::relay::socks5::Address;
use crate::context::SharedContext;
use futures::{
self,
stream::{futures_unordered, Stream},
Future,
future::{self, Either},
stream::{FuturesUnordered, StreamExt},
};
use log::{debug, error, info, trace};
use tokio::{
self,
net::{TcpListener, TcpStream},
};
use tokio_io::{
io::{ReadHalf, WriteHalf},
AsyncRead,
};
use super::{
context::{SharedTcpServerContext, TcpServerContext},
monitor::TcpMonStream,
proxy_handshake, try_timeout, tunnel, DecryptedHalf, EncryptedHalf, TcpStreamConnect,
CryptoStream, STcpStream,
};
/// Context for doing handshake with client
pub struct TcpRelayClientHandshake {
s: TcpMonStream,
#[allow(clippy::cognitive_complexity)]
async fn handle_client(
svr_context: SharedTcpServerContext,
}
impl TcpRelayClientHandshake {
#[inline]
fn error_handshake(peer_addr: SocketAddr) -> io::Error {
io::Error::new(
ErrorKind::Other,
format!(
"failed to decode Address, may be wrong method or key, peer: {}",
peer_addr
),
)
}
/// Doing handshake with client
pub fn handshake(
self,
) -> impl Future<
Item = TcpRelayClientPending<
impl Future<Item = EncryptedHalf<TcpMonStream>, Error = io::Error> + Send + 'static,
>,
Error = io::Error,
> + Send {
let TcpRelayClientHandshake { s, svr_context } = self;
futures::lazy(move || s.peer_addr().map(|p| (s, p))).and_then(|(s, peer_addr)| {
debug!("Handshaking with peer {}", peer_addr);
let timeout = svr_context.svr_cfg().timeout();
proxy_handshake(s, svr_context.svr_cfg().clone()).and_then(move |(r_fut, w_fut)| {
r_fut
.and_then(move |r| {
let fut =
Address::read_from(r).map_err(move |_| TcpRelayClientHandshake::error_handshake(peer_addr));
try_timeout(fut, timeout)
})
.map(move |(r, addr)| TcpRelayClientPending {
r,
addr,
w: w_fut,
timeout,
svr_context,
})
})
})
}
}
/// Context for connecting remote
pub struct TcpRelayClientPending<E>
where
E: Future<Item = EncryptedHalf<TcpMonStream>, Error = io::Error> + Send + 'static,
{
r: DecryptedHalf<TcpMonStream>,
addr: Address,
w: E,
timeout: Option<Duration>,
svr_context: SharedTcpServerContext,
}
/// Connect to the remote server
#[inline]
fn connect_remote(
context: SharedContext,
addr: Address,
timeout: Option<Duration>,
) -> impl Future<Item = TcpStream, Error = io::Error> + Send {
debug!("Connecting to remote {}", addr);
match addr {
Address::SocketAddress(saddr) => {
if context.config().forbidden_ip.contains(&saddr.ip()) {
let err = io::Error::new(
ErrorKind::Other,
format!("{} is forbidden, failed to connect {}", saddr.ip(), saddr),
);
return boxed_future(futures::done(Err(err)));
}
let conn = TcpStream::connect(&saddr);
let fut = try_timeout(conn, timeout);
boxed_future(fut)
}
Address::DomainNameAddress(dname, port) => {
let fut = {
try_timeout(resolve(context, dname.as_str(), port, true), timeout).and_then(move |addrs| {
let conn = TcpStreamConnect::new(addrs.into_iter());
try_timeout(conn, timeout)
})
};
boxed_future(fut)
}
}
}
impl<E> TcpRelayClientPending<E>
where
E: Future<Item = EncryptedHalf<TcpMonStream>, Error = io::Error> + Send + 'static,
{
/// Connect to the remote server
pub fn connect(
self,
) -> impl Future<
Item = TcpRelayClientConnected<
impl Future<Item = EncryptedHalf<TcpMonStream>, Error = io::Error> + Send + 'static,
>,
Error = io::Error,
> + Send {
let client_pair = (self.r, self.w);
let timeout = self.timeout;
connect_remote(self.svr_context.context().clone(), self.addr, self.timeout).map(move |stream| {
TcpRelayClientConnected {
server: stream.split(),
client: client_pair,
timeout,
}
})
}
}
/// Context for extablishing tunnel
pub struct TcpRelayClientConnected<E>
where
E: Future<Item = EncryptedHalf<TcpMonStream>, Error = io::Error> + Send + 'static,
{
server: (ReadHalf<TcpStream>, WriteHalf<TcpStream>),
client: (DecryptedHalf<TcpMonStream>, E),
timeout: Option<Duration>,
}
impl<E> TcpRelayClientConnected<E>
where
E: Future<Item = EncryptedHalf<TcpMonStream>, Error = io::Error> + Send + 'static,
{
/// Establish tunnel
#[inline]
pub fn tunnel(self) -> impl Future<Item = (), Error = io::Error> + Send {
let (svr_r, svr_w) = self.server;
let (r, w_fut) = self.client;
let timeout = self.timeout;
tunnel(
r.copy_timeout_opt(svr_w, self.timeout),
w_fut.and_then(move |w| w.copy_timeout_opt(svr_r, timeout)),
)
}
}
fn handle_client(svr_context: SharedTcpServerContext, socket: TcpStream) -> impl Future<Item = (), Error = ()> + Send {
let socket = TcpMonStream::new(svr_context.clone(), socket);
socket: TcpStream,
peer_addr: SocketAddr,
) -> io::Result<()> {
if let Err(err) = socket.set_keepalive(svr_context.svr_cfg().timeout()) {
error!("Failed to set keep alive: {:?}", err);
}
@@ -202,39 +38,167 @@ fn handle_client(svr_context: SharedTcpServerContext, socket: TcpStream) -> impl
}
}
futures::lazy(move || match socket.peer_addr() {
Ok(addr) => Ok((socket, addr)),
trace!(
"Got connection addr: {} with proxy server: {:?}",
peer_addr,
svr_context.svr_cfg()
);
let stream = TcpMonStream::new(
svr_context.clone(),
STcpStream::new(socket, svr_context.svr_cfg().timeout()),
);
// Do server-client handshake
// Perform encryption IV exchange
let mut stream = CryptoStream::new(stream, svr_context.svr_cfg().clone());
// Read remote Address
let remote_addr = match Address::read_from(&mut stream).await {
Ok(o) => o,
Err(err) => {
error!("Failed to get peer_addr after accept: {}", err);
Err(())
error!(
"Failed to decode Address, may be wrong method or key, peer {}",
peer_addr
);
return Err(From::from(err));
}
})
.and_then(move |(socket, addr)| {
trace!("Got connection, addr: {}", addr);
trace!("Picked proxy server: {:?}", svr_context.svr_cfg());
};
let client = TcpRelayClientHandshake { s: socket, svr_context };
debug!("Relay {} <-> {} establishing", peer_addr, remote_addr);
client
.handshake()
.and_then(TcpRelayClientPending::connect)
.and_then(TcpRelayClientConnected::tunnel)
.map_err(move |err| {
error!("Failed to handle client ({}): {}", addr, err);
})
})
let context = svr_context.context();
let mut remote_stream = match remote_addr {
Address::SocketAddress(ref saddr) => {
if context.config().forbidden_ip.contains(&saddr.ip()) {
error!("{} is forbidden, failed to connect {}", saddr.ip(), saddr);
let err = io::Error::new(
io::ErrorKind::Other,
format!("{} is forbidden, failed to connect {}", saddr.ip(), saddr),
);
return Err(err);
}
match TcpStream::connect(saddr).await {
Ok(s) => {
debug!("Connected to remote {}", saddr);
s
}
Err(err) => {
error!("Failed to connect remote {}, {}", saddr, err);
return Err(err);
}
}
}
#[cfg(feature = "trust-dns")]
Address::DomainNameAddress(ref dname, port) => {
use crate::relay::dns_resolver::resolve;
let addrs = match resolve(context.clone(), dname.as_str(), port, true).await {
Ok(r) => r,
Err(err) => {
error!("Failed to resolve {}, {}", dname, err);
return Err(err);
}
};
let mut last_err: Option<io::Error> = None;
let mut stream_opt = None;
for addr in &addrs {
match TcpStream::connect(addr).await {
Ok(s) => stream_opt = Some(s),
Err(err) => {
error!(
"Failed to connect remote {}:{} (resolved: {}), {}, try others",
dname, port, addr, err
);
last_err = Some(err);
}
}
}
match stream_opt {
Some(s) => {
debug!("Connected to remote {}:{}", dname, port);
s
}
None => {
let err = last_err.unwrap();
error!("Failed to connect remote {}:{}, {}", dname, port, err);
return Err(io::Error::new(io::ErrorKind::Other, err));
}
}
}
#[cfg(not(feature = "trust-dns"))]
Address::DomainNameAddress(ref dname, port) => {
let s = match TcpStream::connect((dname.as_str(), port)).await {
Ok(s) => {
debug!("Connected to remote {}:{}", dname, port);
s
}
Err(err) => {
error!("Failed to connect remote {}:{}, {}", dname, port, err);
return Err(err);
}
};
// Still need to check forbidden IPs
let forbidden_ip = &context.config().forbidden_ip;
if !forbidden_ip.is_empty() {
let peer_addr = s.peer_addr()?;
if forbidden_ip.contains(&peer_addr.ip()) {
error!("{} is forbidden, failed to connect {}", peer_addr.ip(), peer_addr);
let err = io::Error::new(
io::ErrorKind::Other,
format!("{} is forbidden, failed to connect {}", peer_addr.ip(), peer_addr),
);
return Err(err);
}
}
s
}
};
debug!("Relay {} <-> {} established", peer_addr, remote_addr);
let (mut cr, mut cw) = stream.split();
let (mut sr, mut sw) = remote_stream.split();
use tokio::io::copy;
// CLIENT -> SERVER
let rhalf = copy(&mut cr, &mut sw);
// CLIENT <- SERVER
let whalf = copy(&mut sr, &mut cw);
match future::select(rhalf, whalf).await {
Either::Left((Ok(_), _)) => trace!("Relay {} -> {} closed", peer_addr, remote_addr),
Either::Left((Err(err), _)) => trace!("Relay {} -> {} closed with error {:?}", peer_addr, remote_addr, err),
Either::Right((Ok(_), _)) => trace!("Relay {} <- {} closed", peer_addr, remote_addr),
Either::Right((Err(err), _)) => trace!("Relay {} <- {} closed with error {:?}", peer_addr, remote_addr, err),
}
debug!("Relay {} <-> {} closing", peer_addr, remote_addr);
Ok(())
}
/// Runs the server
pub fn run(context: SharedContext) -> impl Future<Item = (), Error = io::Error> + Send {
let mut vec_fut = Vec::with_capacity(context.config().server.len());
pub async fn run(context: SharedContext) -> io::Result<()> {
let vec_fut = FuturesUnordered::new();
for svr_cfg in &context.config().server {
let listener = {
let mut listener = {
let addr = svr_cfg.plugin_addr().as_ref().unwrap_or_else(|| svr_cfg.addr());
let addr = addr.listen_addr();
let listener = TcpListener::bind(&addr).unwrap_or_else(|err| panic!("Failed to listen, {}", err));
let listener = TcpListener::bind(&addr)
.await
.unwrap_or_else(|err| panic!("Failed to listen, {}", err));
info!("ShadowSocks TCP Listening on {}", addr);
listener
@@ -244,44 +208,30 @@ pub fn run(context: SharedContext) -> impl Future<Item = (), Error = io::Error>
let context = context.clone();
let svr_context = TcpServerContext::new(context.clone(), svr_cfg.clone());
struct CloseGuard(SharedTcpServerContext);
impl Drop for CloseGuard {
fn drop(&mut self) {
self.0.close();
vec_fut.push(async move {
loop {
match listener.accept().await {
Ok((socket, peer_addr)) => {
let svr_context = svr_context.clone();
tokio::spawn(async move {
let _ = handle_client(svr_context, socket, peer_addr).await;
});
}
Err(err) => {
error!("Server run failed: {}", err);
break;
}
}
}
}
let close_guard = CloseGuard(svr_context.clone());
let listening = listener
.incoming()
.for_each(move |socket| {
let svr_context = svr_context.clone();
tokio::spawn(handle_client(svr_context, socket));
Ok(())
})
.map_err(|err| {
error!("Server run failed: {}", err);
err
})
.then(move |r| {
// Close the context to ensure reporting Future is terminated
drop(close_guard);
r
});
vec_fut.push(boxed_future(listening));
});
}
futures_unordered(vec_fut).into_future().then(|res| match res {
Ok(..) => {
error!("One of TCP servers exited unexpectly without error");
match vec_fut.into_future().await.0 {
Some(()) => {
error!("One of TCP servers exited unexpectly");
let err = io::Error::new(io::ErrorKind::Other, "server exited unexpectly");
Err(err)
}
Err((err, ..)) => {
error!("One of TCP servers exited unexpectly with error {}", err);
Err(err)
}
})
None => unreachable!(),
}
}
+188 -162
View File
@@ -2,28 +2,25 @@
use std::{io, net::SocketAddr, sync::Arc};
use futures::{self, stream::Stream, Future};
use futures::future::{self, Either};
use log::{debug, error, info, trace, warn};
use tokio::{
self,
net::{TcpListener, TcpStream},
};
use tokio_io::{
io::{flush, ReadHalf, WriteHalf},
AsyncRead,
net::{
tcp::{ReadHalf, WriteHalf},
TcpListener, TcpStream,
},
prelude::*,
};
use crate::{config::ServerConfig, context::SharedContext};
use crate::relay::{
boxed_future,
loadbalancing::server::{LoadBalancer, PingBalancer},
socks5::{self, Address, HandshakeRequest, HandshakeResponse, TcpRequestHeader, TcpResponseHeader},
tcprelay::crypto_io::{DecryptedRead, EncryptedWrite},
};
use super::{ignore_until_end, try_timeout, tunnel};
use super::ignore_until_end;
#[derive(Debug, Clone)]
struct UdpConfig {
@@ -31,62 +28,95 @@ struct UdpConfig {
client_addr: SocketAddr,
}
fn handle_socks5_connect(
async fn handle_socks5_connect<'a>(
context: SharedContext,
(r, w): (ReadHalf<TcpStream>, WriteHalf<TcpStream>),
(mut r, mut w): (ReadHalf<'a>, WriteHalf<'a>),
client_addr: SocketAddr,
addr: Address,
local_addr: SocketAddr,
addr: &Address,
svr_cfg: Arc<ServerConfig>,
) -> impl Future<Item = (), Error = io::Error> + Send {
let timeout = svr_cfg.timeout();
super::connect_proxy_server(context, svr_cfg.clone())
.then(move |res| {
let (header, r) = match res {
Ok(svr_s) => {
trace!("Proxy server connected");
) -> io::Result<()> {
let svr_s = match super::connect_proxy_server(context, svr_cfg.clone()).await {
Ok(svr_s) => {
trace!("Proxy server connected, {:?}", svr_cfg);
// Tell the client that we are ready
let header = TcpResponseHeader::new(socks5::Reply::Succeeded, Address::SocketAddress(client_addr));
(header, Ok(svr_s))
}
Err(err) => {
use crate::relay::socks5::Reply;
use std::io::ErrorKind;
error!("Failed to connect remote server, err: {}", err);
let reply = match err.kind() {
ErrorKind::ConnectionRefused => Reply::ConnectionRefused,
ErrorKind::ConnectionAborted => Reply::HostUnreachable,
_ => Reply::NetworkUnreachable,
};
let header = TcpResponseHeader::new(reply, Address::SocketAddress(client_addr));
(header, Err(err))
}
};
// Tell the client that we are ready
let header = TcpResponseHeader::new(socks5::Reply::Succeeded, Address::SocketAddress(local_addr));
header.write_to(&mut w).await?;
w.flush().await?;
trace!("Sent header: {:?}", header);
try_timeout(header.write_to(w).and_then(flush), timeout).and_then(|w| match r {
Ok(svr_s) => Ok((svr_s, w)),
Err(err) => Err(err),
})
})
.and_then(move |(svr_s, w)| {
let timeout = svr_cfg.timeout();
super::proxy_server_handshake(svr_s, svr_cfg, addr).and_then(move |(svr_r, svr_w)| {
let rhalf = svr_r.and_then(move |svr_r| svr_r.copy_timeout_opt(w, timeout));
let whalf = svr_w.and_then(move |svr_w| svr_w.copy_timeout_opt(r, timeout));
tunnel(whalf, rhalf)
})
})
svr_s
}
Err(err) => {
use crate::relay::socks5::Reply;
use std::io::ErrorKind;
error!("Failed to connect remote server, err: {}", err);
let reply = match err.kind() {
ErrorKind::ConnectionRefused => Reply::ConnectionRefused,
ErrorKind::ConnectionAborted => Reply::HostUnreachable,
_ => Reply::NetworkUnreachable,
};
let header = TcpResponseHeader::new(reply, Address::SocketAddress(local_addr));
header.write_to(&mut w).await?;
w.flush().await?;
return Err(err);
}
};
let mut svr_s = super::proxy_server_handshake(svr_s, svr_cfg.clone(), addr).await?;
let (mut svr_r, mut svr_w) = svr_s.split();
use tokio::io::copy;
let rhalf = copy(&mut r, &mut svr_w);
let whalf = copy(&mut svr_r, &mut w);
debug!(
"CONNECT relay established {} <-> {} ({})",
client_addr,
svr_cfg.addr(),
addr
);
match future::select(rhalf, whalf).await {
Either::Left((Ok(..), _)) => trace!("CONNECT relay {} -> {} ({}) closed", client_addr, svr_cfg.addr(), addr),
Either::Left((Err(err), _)) => trace!(
"CONNECT relay {} -> {} ({}) closed with error {:?}",
client_addr,
svr_cfg.addr(),
err,
addr,
),
Either::Right((Ok(..), _)) => trace!("CONNECT relay {} <- {} ({}) closed", client_addr, svr_cfg.addr(), addr),
Either::Right((Err(err), _)) => trace!(
"CONNECT relay {} <- {} ({}) closed with error {:?}",
client_addr,
svr_cfg.addr(),
err,
addr,
),
}
debug!(
"CONNECT relay {} <-> {} ({}) closing",
client_addr,
svr_cfg.addr(),
addr
);
Ok(())
}
fn handle_socks5_client(
#[allow(clippy::cognitive_complexity)]
async fn handle_socks5_client(
context: SharedContext,
s: TcpStream,
mut s: TcpStream,
conf: Arc<ServerConfig>,
udp_conf: UdpConfig,
) -> io::Result<()> {
@@ -101,120 +131,108 @@ fn handle_socks5_client(
}
let client_addr = s.peer_addr()?;
let cloned_client_addr = client_addr;
let fut = futures::lazy(|| Ok(s.split()))
.and_then(|(r, w)| {
// Socks5 handshakes
HandshakeRequest::read_from(r).and_then(move |(r, req)| {
trace!("Socks5 {:?}", req);
let local_addr = s.local_addr()?;
let (resp, res) = if !req.methods.contains(&socks5::SOCKS5_AUTH_METHOD_NONE) {
let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NOT_ACCEPTABLE);
warn!("Currently shadowsocks-rust does not support authentication");
(
resp,
Err(io::Error::new(
io::ErrorKind::Other,
"Currently shadowsocks-rust does not support authentication",
)),
)
} else {
// Reply to client
let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NONE);
trace!("Reply handshake {:?}", resp);
(resp, Ok(()))
};
let (mut r, mut w) = s.split();
resp.write_to(w).and_then(flush).and_then(move |w| match res {
Ok(..) => Ok((r, w)),
Err(err) => Err(err),
})
})
})
.and_then(move |(r, w)| {
// Fetch headers
TcpRequestHeader::read_from(r).then(move |res| match res {
Ok((r, h)) => boxed_future(futures::finished((r, w, h))),
Err(err) => {
error!("Failed to get TcpRequestHeader: {}", err);
let fut = TcpResponseHeader::new(err.reply, Address::SocketAddress(client_addr))
.write_to(w)
.then(|_| Err(From::from(err)));
boxed_future(fut)
}
})
})
.and_then(move |(r, w, header)| {
trace!("Socks5 {:?}", header);
let handshake_req = HandshakeRequest::read_from(&mut r).await?;
let addr = header.address;
match header.command {
socks5::Command::TcpConnect => {
let enable_tcp = context.config().mode.enable_tcp();
if enable_tcp {
debug!("CONNECT {}", addr);
let fut = handle_socks5_connect(context, (r, w), cloned_client_addr, addr.clone(), conf)
.map_err(move |err| {
io::Error::new(err.kind(), format!("CONNECT {} failed with error \"{}\"", addr, err))
});
boxed_future(fut)
} else {
warn!("CONNECT is not enabled");
let fut = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr)
.write_to(w)
.map(|_| ());
boxed_future(fut)
}
}
socks5::Command::TcpBind => {
warn!("BIND is not supported");
let fut = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr)
.write_to(w)
.map(|_| ());
boxed_future(fut)
}
socks5::Command::UdpAssociate => {
if udp_conf.enable_udp {
debug!("UDP ASSOCIATE {}", addr);
let fut = TcpResponseHeader::new(socks5::Reply::Succeeded, From::from(udp_conf.client_addr))
.write_to(w)
.and_then(flush)
.and_then(|_| {
// Hold the connection until it ends by its own
ignore_until_end(r).map(|_| ())
});
// Socks5 handshakes
trace!("Socks5 {:?}", handshake_req);
boxed_future(fut)
} else {
warn!("UDP ASSOCIATE is not enabled");
let fut = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr)
.write_to(w)
.map(|_| ());
boxed_future(fut)
}
}
}
});
let (handshake_resp, res) = if !handshake_req.methods.contains(&socks5::SOCKS5_AUTH_METHOD_NONE) {
let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NOT_ACCEPTABLE);
warn!("Currently shadowsocks-rust does not support authentication");
(
resp,
Err(io::Error::new(
io::ErrorKind::Other,
"Currently shadowsocks-rust does not support authentication",
)),
)
} else {
// Reply to client
let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NONE);
trace!("Reply handshake {:?}", resp);
(resp, Ok(()))
};
tokio::spawn(fut.then(|res| match res {
Ok(..) => Ok(()),
handshake_resp.write_to(&mut w).await?;
w.flush().await?;
res?;
// Fetch headers
let header = match TcpRequestHeader::read_from(&mut r).await {
Ok(h) => h,
Err(err) => {
if err.kind() != io::ErrorKind::BrokenPipe {
error!("Socks5 client: {}", err);
}
Err(())
error!("Failed to get TcpRequestHeader: {}", err);
let rh = TcpResponseHeader::new(err.reply, Address::SocketAddress(client_addr));
rh.write_to(&mut w).await?;
return Err(From::from(err));
}
}));
};
Ok(())
trace!("Socks5 {:?}", header);
let addr = header.address;
match header.command {
socks5::Command::TcpConnect => {
let enable_tcp = context.config().mode.enable_tcp();
if enable_tcp {
debug!("CONNECT {}", addr);
match handle_socks5_connect(context, (r, w), client_addr, local_addr, &addr, conf).await {
Ok(..) => Ok(()),
Err(err) => Err(io::Error::new(
err.kind(),
format!("CONNECT {} failed with error \"{}\"", addr, err),
)),
}
} else {
warn!("CONNECT is not enabled");
let rh = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr);
rh.write_to(&mut w).await?;
Ok(())
}
}
socks5::Command::TcpBind => {
warn!("BIND is not supported");
let rh = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr);
rh.write_to(&mut w).await?;
Ok(())
}
socks5::Command::UdpAssociate => {
if udp_conf.enable_udp {
debug!("UDP ASSOCIATE {}", addr);
let rh = TcpResponseHeader::new(socks5::Reply::Succeeded, From::from(udp_conf.client_addr));
rh.write_to(&mut w).await?;
w.flush().await?;
// Hold the connection until it ends by its own
ignore_until_end(&mut r).await?;
Ok(())
} else {
warn!("UDP ASSOCIATE is not enabled");
let rh = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr);
rh.write_to(&mut w).await?;
Ok(())
}
}
}
}
/// Starts a TCP local server with Socks5 proxy protocol
pub fn run(context: SharedContext) -> impl Future<Item = (), Error = io::Error> + Send {
pub async fn run(context: SharedContext) -> io::Result<()> {
let local_addr = *context.config().local.as_ref().expect("Missing local config");
let listener =
TcpListener::bind(&local_addr).unwrap_or_else(|err| panic!("Failed to listen on {}, {}", local_addr, err));
let mut listener = TcpListener::bind(&local_addr)
.await
.unwrap_or_else(|err| panic!("Failed to listen on {}, {}", local_addr, err));
let actual_local_addr = listener.local_addr().expect("Could not determine port bound to");
@@ -226,12 +244,20 @@ pub fn run(context: SharedContext) -> impl Future<Item = (), Error = io::Error>
};
let mut servers = PingBalancer::new(context.clone());
listener.incoming().for_each(move |socket| {
loop {
let (socket, peer_addr) = listener.accept().await?;
let server_cfg = servers.pick_server();
trace!("Got connection, addr: {}", socket.peer_addr()?);
trace!("Got connection, addr: {}", peer_addr);
trace!("Picked proxy server: {:?}", server_cfg);
handle_socks5_client(context.clone(), socket, server_cfg, udp_conf.clone())
})
let context = context.clone();
let udp_conf = udp_conf.clone();
tokio::spawn(async move {
if let Err(err) = handle_socks5_client(context, socket, server_cfg, udp_conf).await {
error!("Socks5 client {}", err);
}
});
}
}
+98 -142
View File
@@ -1,159 +1,145 @@
//! Stream protocol implementation
use std::{
cmp,
io::{self, BufRead, Read},
cmp, io,
marker::Unpin,
pin::Pin,
task::{Context, Poll},
};
use crate::crypto::{new_stream, BoxStreamCipher, CipherType, CryptoMode};
use bytes::{BufMut, BytesMut};
use tokio_io::{AsyncRead, AsyncWrite};
use futures::ready;
use tokio::prelude::*;
use super::{DecryptedRead, EncryptedWrite, BUFFER_SIZE};
use super::BUFFER_SIZE;
const DUMMY_BUFFER: [u8; BUFFER_SIZE] = [0u8; BUFFER_SIZE];
/// Reader wrapper that will decrypt data automatically
pub struct DecryptedReader<R>
where
R: AsyncRead,
{
reader: R,
pub struct DecryptedReader {
buffer: BytesMut,
cipher: BoxStreamCipher,
pos: usize,
sent_final: bool,
got_final: bool,
incoming_buffer: Vec<u8>,
}
impl<R> DecryptedReader<R>
where
R: AsyncRead,
{
pub fn new(r: R, t: CipherType, key: &[u8], iv: &[u8]) -> DecryptedReader<R> {
impl DecryptedReader {
pub fn new(t: CipherType, key: &[u8], iv: &[u8]) -> DecryptedReader {
let cipher = new_stream(t, key, iv, CryptoMode::Decrypt);
let buffer_size = cipher.buffer_size(&DUMMY_BUFFER);
DecryptedReader {
reader: r,
buffer: BytesMut::with_capacity(buffer_size),
cipher,
pos: 0,
sent_final: false,
got_final: false,
incoming_buffer: vec![0u8; BUFFER_SIZE],
}
}
pub fn get_ref(&self) -> &R {
&self.reader
}
/// Gets a mutable reference to the underlying reader.
///
/// # Warning
///
/// It is inadvisable to read directly from or write directly to the
/// underlying reader.
pub fn get_mut(&mut self) -> &mut R {
&mut self.reader
}
/// Unwraps this `DecryptedReader`, returning the underlying reader.
///
/// The internal buffer is flushed before returning the reader. Any leftover
/// data in the read buffer is lost.
pub fn into_inner(self) -> R {
self.reader
}
}
impl<R> BufRead for DecryptedReader<R>
where
R: AsyncRead,
{
fn fill_buf(&mut self) -> io::Result<&[u8]> {
pub fn poll_read_decrypted<R>(
&mut self,
ctx: &mut Context<'_>,
r: &mut R,
dst: &mut [u8],
) -> Poll<io::Result<usize>>
where
R: AsyncRead + Unpin,
{
while self.pos >= self.buffer.len() {
if self.sent_final {
return Ok(&[]);
if self.got_final {
return Poll::Ready(Ok(0));
}
let mut incoming = [0u8; BUFFER_SIZE];
let n = ready!(Pin::new(&mut *r).poll_read(ctx, &mut self.incoming_buffer))?;
// Reset pointers
self.buffer.clear();
match self.reader.read(&mut incoming) {
Ok(0) => {
// Ensure we have enough space
let buffer_len = self.buffer_size(&[]);
self.buffer.reserve(buffer_len);
// EOF
self.cipher.finalize(&mut self.buffer)?;
self.sent_final = true;
}
Ok(l) => {
let data = &incoming[..l];
// Ensure we have enough space
let buffer_len = self.buffer_size(data);
self.buffer.reserve(buffer_len);
self.cipher.update(data, &mut self.buffer)?;
}
Err(err) => {
return Err(err);
}
}
self.pos = 0;
if n == 0 {
// Finialize block
self.buffer.reserve(self.buffer_size(&[]));
self.cipher.finalize(&mut self.buffer)?;
self.got_final = true;
} else {
let data = &self.incoming_buffer[..n];
// Ensure we have enough space
let buffer_len = self.buffer_size(data);
self.buffer.reserve(buffer_len);
self.cipher.update(data, &mut self.buffer)?;
}
}
Ok(&self.buffer[self.pos..])
let remaining_len = self.buffer.len() - self.pos;
let n = cmp::min(dst.len(), remaining_len);
(&mut dst[..n]).copy_from_slice(&self.buffer[self.pos..self.pos + n]);
self.pos += n;
Poll::Ready(Ok(n))
}
fn consume(&mut self, amt: usize) {
self.pos = cmp::min(self.pos + amt, self.buffer.len());
}
}
impl<R> Read for DecryptedReader<R>
where
R: AsyncRead,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let nread = {
let mut available = self.fill_buf()?;
available.read(buf)?
};
self.consume(nread);
Ok(nread)
}
}
impl<R> DecryptedRead for DecryptedReader<R>
where
R: AsyncRead,
{
fn buffer_size(&self, data: &[u8]) -> usize {
self.cipher.buffer_size(data)
}
}
impl<R> AsyncRead for DecryptedReader<R> where R: AsyncRead {}
/// Writer wrapper that will encrypt data automatically
pub struct EncryptedWriter<W>
where
W: AsyncWrite,
{
writer: W,
cipher: BoxStreamCipher,
enum EncryptWriteStep {
Nothing,
Writing(BytesMut, usize),
}
impl<W> EncryptedWriter<W>
where
W: AsyncWrite,
{
/// Writer wrapper that will encrypt data automatically
pub struct EncryptedWriter {
cipher: BoxStreamCipher,
steps: EncryptWriteStep,
}
impl EncryptedWriter {
/// Creates a new EncryptedWriter
pub fn new(w: W, t: CipherType, key: &[u8], iv: &[u8]) -> EncryptedWriter<W> {
pub fn new(t: CipherType, key: &[u8], iv: &[u8]) -> EncryptedWriter {
EncryptedWriter {
writer: w,
cipher: new_stream(t, key, iv, CryptoMode::Encrypt),
steps: EncryptWriteStep::Nothing,
}
}
pub fn poll_write_encrypted<W>(&mut self, ctx: &mut Context<'_>, w: &mut W, data: &[u8]) -> Poll<io::Result<usize>>
where
W: AsyncWrite + Unpin,
{
ready!(self.poll_write_all_encrypted(ctx, w, data))?;
Poll::Ready(Ok(data.len()))
}
pub fn poll_write_all_encrypted<W>(&mut self, ctx: &mut Context<'_>, w: &mut W, data: &[u8]) -> Poll<io::Result<()>>
where
W: AsyncWrite + Unpin,
{
// FIXME: How about finalize?
loop {
match self.steps {
EncryptWriteStep::Nothing => {
let mut buf = BytesMut::with_capacity(self.buffer_size(data));
self.cipher_update(data, &mut buf)?;
self.steps = EncryptWriteStep::Writing(buf, 0);
}
EncryptWriteStep::Writing(ref mut buf, ref mut pos) => {
while *pos < buf.len() {
let n = ready!(Pin::new(&mut *w).poll_write(ctx, &buf[*pos..]))?;
if n == 0 {
use std::io::ErrorKind;
return Poll::Ready(Err(ErrorKind::UnexpectedEof.into()));
}
*pos += n;
}
self.steps = EncryptWriteStep::Nothing;
return Poll::Ready(Ok(()));
}
}
}
}
@@ -161,40 +147,10 @@ where
self.cipher.update(data, buf).map_err(From::from)
}
#[allow(dead_code)]
fn cipher_finalize<B: BufMut>(&mut self, buf: &mut B) -> io::Result<()> {
self.cipher.finalize(buf).map_err(From::from)
}
}
impl<W> Drop for EncryptedWriter<W>
where
W: AsyncWrite,
{
fn drop(&mut self) {
let mut buf = Vec::new();
if let Ok(..) = self.cipher_finalize(&mut buf) {
if !buf.is_empty() {
let _ = self.write_raw(&buf);
}
}
}
}
impl<W> EncryptedWrite for EncryptedWriter<W>
where
W: AsyncWrite,
{
fn write_raw(&mut self, data: &[u8]) -> io::Result<usize> {
self.writer.write(data)
}
fn flush(&mut self) -> io::Result<()> {
self.writer.flush()
}
fn encrypt<B: BufMut>(&mut self, data: &[u8], buf: &mut B) -> io::Result<()> {
self.cipher_update(data, buf)
}
fn buffer_size(&self, data: &[u8]) -> usize {
self.cipher.buffer_size(data)
+129
View File
@@ -0,0 +1,129 @@
//! Local server that establish a TCP tunnel with server
use std::io;
use std::net::SocketAddr;
use std::sync::Arc;
use futures::future::{self, Either};
use log::{debug, error, info, trace};
use tokio::net::{TcpListener, TcpStream};
use crate::config::ServerConfig;
use crate::context::SharedContext;
use crate::relay::loadbalancing::server::{LoadBalancer, PingBalancer};
use crate::relay::socks5::Address;
/// Established Client Tunnel
///
/// This method must be called after handshaking with client (for example, socks5 handshaking)
async fn establish_client_tcp_tunnel<'a>(
context: SharedContext,
mut s: TcpStream,
client_addr: SocketAddr,
addr: &Address,
svr_cfg: Arc<ServerConfig>,
) -> io::Result<()> {
let svr_s = match super::connect_proxy_server(context, svr_cfg.clone()).await {
Ok(svr_s) => {
trace!("Proxy server connected, {:?}", svr_cfg);
svr_s
}
Err(err) => {
// Just close the connection.
return Err(err);
}
};
let mut svr_s = super::proxy_server_handshake(svr_s, svr_cfg.clone(), addr).await?;
let (mut svr_r, mut svr_w) = svr_s.split();
let (mut r, mut w) = s.split();
use tokio::io::copy;
let rhalf = copy(&mut r, &mut svr_w);
let whalf = copy(&mut svr_r, &mut w);
debug!(
"TUNNEL relay established {} <-> {} ({})",
client_addr,
svr_cfg.addr(),
addr
);
match future::select(rhalf, whalf).await {
Either::Left((Ok(..), _)) => trace!("TUNNEL relay {} -> {} ({}) closed", client_addr, svr_cfg.addr(), addr),
Either::Left((Err(err), _)) => trace!(
"TUNNEL relay {} -> {} ({}) closed with error {:?}",
client_addr,
svr_cfg.addr(),
err,
addr,
),
Either::Right((Ok(..), _)) => trace!("TUNNEL relay {} <- {} ({}) closed", client_addr, svr_cfg.addr(), addr),
Either::Right((Err(err), _)) => trace!(
"TUNNEL relay {} <- {} ({}) closed with error {:?}",
client_addr,
svr_cfg.addr(),
err,
addr
),
}
debug!("TUNNEL relay {} <-> {} ({}) closing", client_addr, svr_cfg.addr(), addr);
Ok(())
}
async fn handle_tunnel_client(context: SharedContext, s: TcpStream, conf: Arc<ServerConfig>) -> io::Result<()> {
if let Err(err) = s.set_keepalive(conf.timeout()) {
error!("Failed to set keep alive: {:?}", err);
}
if context.config().no_delay {
if let Err(err) = s.set_nodelay(true) {
error!("Failed to set no delay: {:?}", err);
}
}
let client_addr = s.peer_addr()?;
// forward must not be None, it is already checked in local.rs
let target_addr = context.config().forward.as_ref().unwrap();
establish_client_tcp_tunnel(context.clone(), s, client_addr, target_addr, conf).await
}
pub async fn run(context: SharedContext) -> io::Result<()> {
assert!(
context.config().mode.enable_tcp(),
"You must enable TCP relay for tunneling"
);
let local_addr = *context.config().local.as_ref().expect("Missing local config");
let mut listener = TcpListener::bind(&local_addr)
.await
.unwrap_or_else(|err| panic!("Failed to listen on {}, {}", local_addr, err));
let actual_local_addr = listener.local_addr().expect("Could not determine port bound to");
info!("ShadowSocks TCP Tunnel Listening on {}", actual_local_addr);
let mut servers = PingBalancer::new(context.clone());
loop {
let (socket, peer_addr) = listener.accept().await?;
let server_cfg = servers.pick_server();
trace!("Got connection, addr: {}", peer_addr);
trace!("Picked proxy server: {:?}", server_cfg);
let context = context.clone();
tokio::spawn(async move {
if let Err(err) = handle_tunnel_client(context, socket, server_cfg).await {
error!("Socks5 client {}", err);
}
});
}
}
-181
View File
@@ -1,182 +1 @@
//! Utility functions
use std::{
io,
time::{Duration, Instant},
};
use futures::{Async, Future, Poll};
use tokio::timer::Delay;
use tokio_io::{
io::{copy, Copy},
try_nb, AsyncRead, AsyncWrite,
};
use super::BUFFER_SIZE;
/// Copies all data from `r` to `w`, abort if timeout reaches
pub fn copy_timeout<R, W>(r: R, w: W, dur: Duration) -> CopyTimeout<R, W>
where
R: AsyncRead,
W: AsyncWrite,
{
CopyTimeout::new(r, w, dur)
}
/// Copies all data from `r` to `w`, abort if timeout reaches
pub struct CopyTimeout<R, W>
where
R: AsyncRead,
W: AsyncWrite,
{
r: Option<R>,
w: Option<W>,
timeout: Duration,
amt: u64,
timer: Option<Delay>,
buf: [u8; BUFFER_SIZE],
pos: usize,
cap: usize,
}
impl<R, W> CopyTimeout<R, W>
where
R: AsyncRead,
W: AsyncWrite,
{
fn new(r: R, w: W, timeout: Duration) -> CopyTimeout<R, W> {
CopyTimeout {
r: Some(r),
w: Some(w),
timeout,
amt: 0,
timer: None,
buf: [0u8; BUFFER_SIZE],
pos: 0,
cap: 0,
}
}
fn try_poll_timeout(&mut self) -> io::Result<()> {
match self.timer.as_mut() {
None => Ok(()),
Some(t) => match t.poll() {
Err(err) => panic!("Failed to poll on timer, err: {}", err),
Ok(Async::Ready(..)) => Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")),
Ok(Async::NotReady) => Ok(()),
},
}
}
fn clear_timer(&mut self) {
let _ = self.timer.take();
}
fn read_or_set_timeout(&mut self) -> io::Result<usize> {
// First, return if timeout
self.try_poll_timeout()?;
// Then, unset the previous timeout
self.clear_timer();
match self.r.as_mut().unwrap().read(&mut self.buf) {
Ok(n) => Ok(n),
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
self.timer = Some(Delay::new(Instant::now() + self.timeout));
}
Err(e)
}
}
}
fn write_or_set_timeout(&mut self, beg: usize, end: usize) -> io::Result<usize> {
// First, return if timeout
self.try_poll_timeout()?;
// Then, unset the previous timeout
self.clear_timer();
match self.w.as_mut().unwrap().write(&self.buf[beg..end]) {
Ok(n) => Ok(n),
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
self.timer = Some(Delay::new(Instant::now() + self.timeout));
}
Err(e)
}
}
}
}
impl<R, W> Future for CopyTimeout<R, W>
where
R: AsyncRead,
W: AsyncWrite,
{
type Error = io::Error;
type Item = (u64, R, W);
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
loop {
if self.pos == self.cap {
let n = try_nb!(self.read_or_set_timeout());
if n == 0 {
// If we've written all the data and we've seen EOF, flush out the
// data and finish the transfer.
// done with the entire transfer.
try_nb!(self.w.as_mut().unwrap().flush());
return Ok((self.amt, self.r.take().unwrap(), self.w.take().unwrap()).into());
}
self.pos = 0;
self.cap = n;
// Clear it before write
self.clear_timer();
}
// If our buffer has some data, let's write it out!
while self.pos < self.cap {
let (pos, cap) = (self.pos, self.cap);
let i = try_nb!(self.write_or_set_timeout(pos, cap));
self.pos += i;
self.amt += i as u64;
}
// Clear it before read
self.clear_timer();
}
}
}
/// Copies all data from `r` to `w` with optional timeout param
pub fn copy_timeout_opt<R, W>(r: R, w: W, dur: Option<Duration>) -> CopyTimeoutOpt<R, W>
where
R: AsyncRead,
W: AsyncWrite,
{
match dur {
Some(d) => CopyTimeoutOpt::CopyTimeout(copy_timeout(r, w, d)),
None => CopyTimeoutOpt::Copy(copy(r, w)),
}
}
/// Copies all data from `R` to `W`
pub enum CopyTimeoutOpt<R: AsyncRead, W: AsyncWrite> {
Copy(Copy<R, W>),
CopyTimeout(CopyTimeout<R, W>),
}
impl<R: AsyncRead, W: AsyncWrite> Future for CopyTimeoutOpt<R, W> {
type Error = io::Error;
type Item = (u64, R, W);
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match *self {
CopyTimeoutOpt::CopyTimeout(ref mut c) => c.poll(),
CopyTimeoutOpt::Copy(ref mut c) => c.poll(),
}
}
}
+49 -25
View File
@@ -21,81 +21,105 @@
//! ```
use std::io;
use std::slice;
use byte_string::ByteStr;
use bytes::{BufMut, BytesMut};
use log::trace;
use crate::crypto::{self, CipherCategory, CipherType, CryptoMode};
/// Encrypt payload into ShadowSocks UDP encrypted packet
pub fn encrypt_payload(t: CipherType, key: &[u8], payload: &[u8]) -> io::Result<Vec<u8>> {
pub fn encrypt_payload(t: CipherType, key: &[u8], payload: &[u8], dst: &mut BytesMut) -> io::Result<()> {
match t.category() {
CipherCategory::Stream => encrypt_payload_stream(t, key, payload),
CipherCategory::Aead => encrypt_payload_aead(t, key, payload),
CipherCategory::Stream => encrypt_payload_stream(t, key, payload, dst),
CipherCategory::Aead => encrypt_payload_aead(t, key, payload, dst),
}
}
fn encrypt_payload_stream(t: CipherType, key: &[u8], payload: &[u8]) -> io::Result<Vec<u8>> {
fn encrypt_payload_stream(t: CipherType, key: &[u8], payload: &[u8], dst: &mut BytesMut) -> io::Result<()> {
let iv = t.gen_init_vec();
let mut cipher = crypto::new_stream(t, key, &iv, CryptoMode::Encrypt);
let mut send_payload = Vec::with_capacity(iv.len() + payload.len());
send_payload.extend_from_slice(&iv);
cipher.update(&payload[..], &mut send_payload)?;
cipher.finalize(&mut send_payload)?;
Ok(send_payload)
trace!("UDP packet generated stream iv {:?}", ByteStr::new(&iv));
dst.reserve(iv.len() + payload.len());
// First of all, IV
dst.put_slice(&iv);
// Encrypted data
cipher.update(&payload[..], dst)?;
cipher.finalize(dst)?;
Ok(())
}
fn encrypt_payload_aead(t: CipherType, key: &[u8], payload: &[u8]) -> io::Result<Vec<u8>> {
fn encrypt_payload_aead(t: CipherType, key: &[u8], payload: &[u8], dst: &mut BytesMut) -> io::Result<()> {
let salt = t.gen_salt();
let tag_size = t.tag_size();
let mut cipher = crypto::new_aead_encryptor(t, key, &salt);
let mut send_payload = Vec::with_capacity(salt.len() + payload.len() + tag_size);
send_payload.extend_from_slice(&salt);
let start_pos = send_payload.len();
send_payload.resize(start_pos + payload.len() + tag_size, 0);
trace!("UDP packet generated AEAD salt {:?}", ByteStr::new(&salt));
cipher.encrypt(payload, &mut send_payload[start_pos..]);
dst.reserve(salt.len() + payload.len() + tag_size);
Ok(send_payload)
// First of all, salt
dst.put_slice(&salt);
// Encrypted data
unsafe {
let remaining = dst.bytes_mut();
let b = slice::from_raw_parts_mut(remaining.as_mut_ptr() as *mut u8, remaining.len());
cipher.encrypt(payload, b);
dst.advance_mut(payload.len() + tag_size);
}
Ok(())
}
/// Decrypt payload from ShadowSocks UDP encrypted packet
pub fn decrypt_payload(t: CipherType, key: &[u8], payload: &[u8]) -> io::Result<Vec<u8>> {
pub fn decrypt_payload(t: CipherType, key: &[u8], payload: &[u8]) -> io::Result<Option<Vec<u8>>> {
match t.category() {
CipherCategory::Stream => decrypt_payload_stream(t, key, payload),
CipherCategory::Aead => decrypt_payload_aead(t, key, payload),
}
}
fn decrypt_payload_stream(t: CipherType, key: &[u8], payload: &[u8]) -> io::Result<Vec<u8>> {
fn decrypt_payload_stream(t: CipherType, key: &[u8], payload: &[u8]) -> io::Result<Option<Vec<u8>>> {
let iv_size = t.iv_size();
if payload.len() < iv_size {
let err = io::Error::new(io::ErrorKind::Other, "udp packet too short");
return Err(err);
return Ok(None);
}
let iv = &payload[..iv_size];
let data = &payload[iv_size..];
trace!("UDP packet got stream IV {:?}", ByteStr::new(iv));
let mut cipher = crypto::new_stream(t, key, iv, CryptoMode::Decrypt);
let mut recv_payload = Vec::with_capacity(data.len());
cipher.update(data, &mut recv_payload)?;
cipher.finalize(&mut recv_payload)?;
Ok(recv_payload)
Ok(Some(recv_payload))
}
fn decrypt_payload_aead(t: CipherType, key: &[u8], payload: &[u8]) -> io::Result<Vec<u8>> {
fn decrypt_payload_aead(t: CipherType, key: &[u8], payload: &[u8]) -> io::Result<Option<Vec<u8>>> {
let tag_size = t.tag_size();
let salt_size = t.salt_size();
if payload.len() < tag_size + salt_size {
let err = io::Error::new(io::ErrorKind::Other, "udp packet too short");
return Err(err);
return Ok(None);
}
let salt = &payload[..salt_size];
let data = &payload[salt_size..];
trace!("UDP packet got AEAD salt {:?}", ByteStr::new(salt));
let data_length = payload.len() - tag_size - salt_size;
let mut cipher = crypto::new_aead_decryptor(t, key, salt);
@@ -103,5 +127,5 @@ fn decrypt_payload_aead(t: CipherType, key: &[u8], payload: &[u8]) -> io::Result
let mut recv_payload = vec![0u8; data_length];
cipher.decrypt(data, &mut recv_payload)?;
Ok(recv_payload)
Ok(Some(recv_payload))
}
-205
View File
@@ -1,205 +0,0 @@
//! UDP DNS relay
use std::{
io::{self, Cursor},
net::{IpAddr, Ipv4Addr, SocketAddr},
sync::{Arc, Mutex},
time::Instant,
};
use dns_parser::Packet;
use futures::{self, future::join_all, stream::futures_unordered, Future, Stream};
use log::{error, info, trace};
use tokio::{self, net::UdpSocket};
use super::{
crypto_io::{decrypt_payload, encrypt_payload},
PacketStream, SendDgramRc, SharedUdpSocket,
};
use crate::{
config::{ServerAddr, ServerConfig},
context::SharedContext,
relay::{boxed_future, dns_resolver::resolve, socks5::Address},
};
/// Starts a UDP DNS server
pub fn run(context: SharedContext) -> impl Future<Item = (), Error = io::Error> + Send {
let local_addr = *context.config().local.as_ref().unwrap();
futures::lazy(move || {
info!("ShadowSocks UDP DNS Listening on {}", local_addr);
UdpSocket::bind(&local_addr)
})
.and_then(move |l| listen(context, l))
}
fn listen(context: SharedContext, l: UdpSocket) -> impl Future<Item = (), Error = io::Error> + Send {
assert!(!context.config().server.is_empty());
let mut svr_fut = Vec::with_capacity(context.config().server.len());
for svr in &context.config().server {
match *svr.addr() {
ServerAddr::SocketAddr(ref addr) => {
svr_fut.push(boxed_future(futures::finished::<_, io::Error>(vec![*addr])));
}
ServerAddr::DomainName(ref dom, ref port) => {
svr_fut.push(boxed_future(resolve(context.clone(), &*dom, *port, false)));
}
}
}
let cloned_context = context.clone();
join_all(svr_fut)
.and_then(move |svr_addrs| {
let mut u = Vec::with_capacity(svr_addrs.len());
for (idx, svr_addr) in svr_addrs.into_iter().enumerate() {
let local_addr = SocketAddr::new(IpAddr::from(Ipv4Addr::new(0, 0, 0, 0)), 0);
let s = UdpSocket::bind(&local_addr)?;
let svr_cfg = Arc::new(cloned_context.config().server[idx].clone());
u.push((Arc::new(Mutex::new(s)), svr_cfg, svr_addr[0]));
}
Ok(u)
})
.and_then(move |vec_servers| {
let mut f = Vec::with_capacity(1 + vec_servers.len());
let l = Arc::new(Mutex::new(l));
f.push(boxed_future(handle_l2r(
context.clone(),
l.clone(),
vec_servers.clone(),
)));
for (svr, cfg, _) in vec_servers {
f.push(boxed_future(handle_r2l(context.clone(), l.clone(), svr, cfg)))
}
futures_unordered(f).into_future().then(|res| match res {
Ok(..) => {
error!("One of DNS servers exited unexpectly without error");
let err = io::Error::new(io::ErrorKind::Other, "server exited unexpectly");
Err(err)
}
Err((err, ..)) => {
error!("One of DNS servers exited unexpectly with error {}", err);
Err(err)
}
})
})
}
fn handle_l2r(
context: SharedContext,
l: SharedUdpSocket,
server: Vec<(SharedUdpSocket, Arc<ServerConfig>, SocketAddr)>,
) -> impl Future<Item = (), Error = io::Error> + Send {
assert!(!server.is_empty());
let mut server_idx: usize = 0;
let server = Arc::new(server);
PacketStream::new(l).for_each(move |(payload, src)| {
let server = server.clone();
let context = context.clone();
let context2 = context.clone();
let pkt_fut = futures::lazy(move || {
let pkt = Packet::parse(&payload[..]).map_err(|err| {
error!("Failed to parse DNS payload, err: {}", err);
io::Error::new(io::ErrorKind::Other, "parse DNS packet failed")
})?;
let (ref socket, ref svr_cfg, svr_addr) = server[server_idx % server.len()];
let (ni, _) = server_idx.overflowing_add(1);
server_idx = ni;
trace!("DNS {} -> {} packet: {:?}", src, svr_cfg.addr(), pkt);
let mut buf = Vec::new();
Address::SocketAddress(context.config().get_remote_dns()).write_to_buf(&mut buf);
buf.extend_from_slice(&payload);
let socket = socket.clone();
let id = pkt.header.id;
encrypt_payload(svr_cfg.method(), svr_cfg.key(), &buf)
.map(move |send_payload| (socket, svr_addr, send_payload, id))
})
.and_then(move |(socket, svr_addr, send_payload, id)| {
SendDgramRc::new(socket, send_payload, svr_addr).map(move |_| {
context2.dns_query_cache().insert(id, (src, Instant::now()));
})
});
tokio::spawn(pkt_fut.then(|res| match res {
Ok(..) => Ok(()),
Err(err) => {
error!("Failed to handle local -> remote packet, err: {}", err);
Err(())
}
}));
Ok(())
})
}
fn handle_r2l(
context: SharedContext,
l: SharedUdpSocket,
r: SharedUdpSocket,
svr_cfg: Arc<ServerConfig>,
) -> impl Future<Item = (), Error = io::Error> + Send {
PacketStream::new(r).for_each(move |(payload, src)| {
let l = l.clone();
let svr_cfg = svr_cfg.clone();
let context = context.clone();
let pkt_fut = futures::lazy(move || decrypt_payload(svr_cfg.method(), svr_cfg.key(), &payload))
.and_then(move |payload| Address::read_from(Cursor::new(payload)).map_err(From::from))
.and_then(move |(cur, ..)| {
let pos = cur.position() as usize;
let payload = cur.into_inner();
let pkt = Packet::parse(&payload[pos..]).map_err(|err| {
error!("Failed to parse DNS payload, err: {}", err);
io::Error::new(io::ErrorKind::Other, "parse DNS packet failed")
})?;
let payload = payload[pos..].to_vec();
let mut cache = context.dns_query_cache();
match cache.remove(&pkt.header.id) {
Some((cli_addr, start_time)) => {
trace!(
"DNS {} <- {} elapsed: {:?} packet: {:?}",
cli_addr,
src,
Instant::now() - start_time,
pkt,
);
Ok(Some((cli_addr, payload)))
}
None => {
error!(
"DNS received packet id={} opcode={:?} but found no local endpoint",
pkt.header.id, pkt.header.opcode
);
Ok(None)
}
}
})
.and_then(move |opt| match opt {
Some((cli_addr, payload)) => {
let f = SendDgramRc::new(l, payload, cli_addr).map(|_| ());
boxed_future(f)
}
None => boxed_future(futures::finished(())),
});
tokio::spawn(pkt_fut.then(|res| match res {
Ok(..) => Ok(()),
Err(err) => {
error!("Failed to handle local <- remote packet, err: {}", err);
Err(())
}
}));
Ok(())
})
}
+161 -146
View File
@@ -3,178 +3,193 @@
use std::{
io::{self, Cursor, ErrorKind, Read},
net::{IpAddr, Ipv4Addr, SocketAddr},
sync::{Arc, Mutex},
sync::Arc,
time::Duration,
};
use futures::{self, Future, Stream};
use log::{debug, error, info};
use tokio::{self, net::UdpSocket, util::FutureExt};
use bytes::BytesMut;
use log::{debug, error, info, warn};
use tokio::{self, net::UdpSocket, sync::mpsc};
use crate::{
config::{ServerAddr, ServerConfig},
context::SharedContext,
relay::{
boxed_future,
dns_resolver::resolve,
loadbalancing::server::{LoadBalancer, RoundRobin},
socks5::{Address, UdpAssociateHeader},
utils::try_timeout,
},
};
use super::{
crypto_io::{decrypt_payload, encrypt_payload},
PacketStream, SendDgramRc, MAXIMUM_UDP_PAYLOAD_SIZE,
MAXIMUM_UDP_PAYLOAD_SIZE,
};
/// Resolves server address to SocketAddr
fn resolve_server_addr(
#[allow(unused_variables)] // `context` is only used if trust-dns is enabled
async fn udp_associate(
context: SharedContext,
svr_cfg: Arc<ServerConfig>,
) -> impl Future<Item = SocketAddr, Error = io::Error> + Send {
match *svr_cfg.addr() {
// Return directly if it is a SocketAddr
ServerAddr::SocketAddr(ref addr) => boxed_future(futures::finished(*addr)),
// Resolve domain name to SocketAddr
pkt: Vec<u8>,
src: SocketAddr,
) -> io::Result<Vec<u8>> {
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(5);
// PKT = UdpAssociateHeader + PAYLOAD
let mut cur = Cursor::new(pkt);
let header = UdpAssociateHeader::read_from(&mut cur).await?;
if header.frag != 0 {
error!("Received UDP associate with frag != 0, which is not supported by ShadowSocks");
let err = io::Error::new(ErrorKind::Other, "unsupported UDP fragmentation");
return Err(err);
}
let addr = header.address;
// The remaining is PAYLOAD
let mut payload = Vec::new();
Read::read_to_end(&mut cur, &mut payload)?;
// Binds to 0.0.0.0:0 (let system choose a random port)
// FIXME: Create a UdpSocket for every UDP associate requests
let local_addr = SocketAddr::new(IpAddr::from(Ipv4Addr::new(0, 0, 0, 0)), 0);
let mut remote_udp = UdpSocket::bind(&local_addr).await?;
// CLIENT -> SERVER protocol: ADDRESS + PAYLOAD
let mut send_buf = Vec::new();
addr.write_to_buf(&mut send_buf);
send_buf.extend_from_slice(&payload);
debug!(
"UDP ASSOCIATE {} -> {}, payload length {} bytes",
src,
addr,
payload.len()
);
let timeout = svr_cfg.udp_timeout().unwrap_or(DEFAULT_TIMEOUT);
// Write to remote socket CLIENT -> SERVER
let mut encrypt_buf = BytesMut::new();
encrypt_payload(svr_cfg.method(), svr_cfg.key(), &send_buf, &mut encrypt_buf)?;
let send_n = match *svr_cfg.addr() {
ServerAddr::SocketAddr(ref addr) => try_timeout(remote_udp.send_to(&encrypt_buf, addr), Some(timeout)).await?,
#[cfg(feature = "trust-dns")]
ServerAddr::DomainName(ref dname, port) => {
let fut = resolve(context, dname, port, false).map(move |vec_ipaddr| {
assert!(!vec_ipaddr.is_empty());
vec_ipaddr[0]
});
boxed_future(fut)
use crate::relay::dns_resolver::resolve;
let vec_ipaddr = resolve(context, dname, port, false).await?;
assert!(!vec_ipaddr.is_empty());
try_timeout(remote_udp.send_to(&encrypt_buf, &vec_ipaddr[0]), Some(timeout)).await?
}
#[cfg(not(feature = "trust-dns"))]
ServerAddr::DomainName(ref dname, port) => {
try_timeout(remote_udp.send_to(&encrypt_buf, (dname.as_str(), port)), Some(timeout)).await?
}
};
if send_n != encrypt_buf.len() {
warn!(
"Sent packet length {}, but expected length {}",
send_n,
encrypt_buf.len()
);
}
// Waiting for response from server SERVER -> CLIENT
// Packet length is limited by MAXIMUM_UDP_PAYLOAD_SIZE, excess bytes will be discarded.
let mut recv_buf = [0u8; MAXIMUM_UDP_PAYLOAD_SIZE];
let recv_n = try_timeout(remote_udp.recv(&mut recv_buf), Some(timeout)).await?;
let decrypt_buf = match decrypt_payload(svr_cfg.method(), svr_cfg.key(), &recv_buf[..recv_n])? {
None => {
error!("UDP packet too short, received length {}", recv_n);
let err = io::Error::new(io::ErrorKind::InvalidData, "packet too short");
return Err(err);
}
Some(b) => b,
};
// SERVER -> CLIENT protocol: ADDRESS + PAYLOAD
let mut cur = Cursor::new(decrypt_buf);
// FIXME: Address is ignored. Maybe useful in the future if we uses one common UdpSocket for communicate with remote server
let _ = Address::read_from(&mut cur).await?;
let payload_len = cur.get_ref().len() - cur.position() as usize;
debug!(
"UDP ASSOCIATE {} <- {}, payload length {} bytes",
src, addr, payload_len
);
let mut data = Vec::new();
UdpAssociateHeader::new(0, Address::SocketAddress(src)).write_to_buf(&mut data);
// Copy payload directly
Read::read_to_end(&mut cur, &mut data)?;
Ok(data)
}
async fn listen(context: SharedContext, l: UdpSocket) -> io::Result<()> {
let mut balancer = RoundRobin::new(context.config());
let (mut r, mut w) = l.split();
let mut pkt_buf = [0u8; MAXIMUM_UDP_PAYLOAD_SIZE];
// FIXME: Channel size 1024?
let (tx, mut rx) = mpsc::channel::<(SocketAddr, Vec<u8>)>(1024);
tokio::spawn(async move {
while let Some((src, pkt)) = rx.recv().await {
if let Err(err) = w.send_to(&pkt, &src).await {
error!("UDP packet send failed, err: {:?}", err);
break;
}
}
// FIXME: How to stop the outer listener Future?
});
loop {
let (recv_len, src) = r.recv_from(&mut pkt_buf).await?;
// Packet length is limited by MAXIMUM_UDP_PAYLOAD_SIZE, excess bytes will be discarded.
// Copy bytes, because udp_associate runs in another tokio Task
let pkt = pkt_buf[..recv_len].to_vec();
let svr_cfg = balancer.pick_server();
let context = context.clone();
let svr_cfg = svr_cfg.clone();
let mut tx = tx.clone();
let assoc = async move {
match udp_associate(context, svr_cfg, pkt, src).await {
Ok(pkt) => {
if let Err(..) = tx.send((src, pkt)).await {
error!("UDP packet channel closed");
}
}
Err(err) => {
error!("Error occurs in UDP relay: {}", err);
}
}
};
tokio::spawn(assoc);
}
}
fn listen(context: SharedContext, l: UdpSocket) -> impl Future<Item = (), Error = io::Error> + Send {
let socket = Arc::new(Mutex::new(l));
let mut balancer = RoundRobin::new(context.config());
PacketStream::new(socket.clone()).for_each(move |(pkt, src)| {
let svr_cfg = balancer.pick_server();
let svr_cfg_cloned = svr_cfg.clone();
let svr_cfg_cloned_cloned = svr_cfg.clone();
let socket = socket.clone();
let context = context.clone();
let timeout = *svr_cfg.udp_timeout();
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(5);
let rel = futures::lazy(|| UdpAssociateHeader::read_from(Cursor::new(pkt)))
.map_err(From::from)
.and_then(|(cur, header)| {
if header.frag != 0 {
error!("Received UDP associate with frag != 0, which is not supported by ShadowSocks");
let err = io::Error::new(ErrorKind::Other, "unsupported UDP fragmentation");
Err(err)
} else {
Ok((cur, header.address))
}
})
.and_then(|(mut cur, addr)| {
let svr_cfg = svr_cfg_cloned_cloned;
let mut payload = Vec::new();
cur.read_to_end(&mut payload).unwrap();
resolve_server_addr(context, svr_cfg)
.and_then(|remote_addr| {
let local_addr = SocketAddr::new(IpAddr::from(Ipv4Addr::new(0, 0, 0, 0)), 0);
UdpSocket::bind(&local_addr).map(|remote_udp| (remote_udp, remote_addr))
})
.map(|(remote_udp, remote_addr)| (remote_udp, remote_addr, payload, addr))
})
.and_then(move |(remote_udp, remote_addr, payload, addr)| {
let mut buf = Vec::new();
addr.write_to_buf(&mut buf);
buf.extend_from_slice(&payload);
encrypt_payload(svr_cfg.method(), svr_cfg.key(), &buf)
.map(|payload| (remote_udp, remote_addr, payload, addr))
})
.and_then(move |(remote_udp, remote_addr, payload, addr)| {
debug!(
"UDP ASSOCIATE {} -> {}, payload length {} bytes",
src,
addr,
payload.len()
);
let to = timeout.unwrap_or(DEFAULT_TIMEOUT);
let caddr = addr.clone();
remote_udp
.send_dgram(payload, &remote_addr)
.timeout(to)
.map_err(move |err| match err.into_inner() {
Some(e) => e,
None => {
error!(
"Udp associate sending datagram {} -> {} timed out in {:?}",
src, caddr, to
);
io::Error::new(io::ErrorKind::TimedOut, "udp send timed out")
}
})
.map(|(remote_udp, _)| (remote_udp, addr))
})
.and_then(move |(remote_udp, addr)| {
let buf = vec![0u8; MAXIMUM_UDP_PAYLOAD_SIZE];
let to = timeout.unwrap_or(DEFAULT_TIMEOUT);
let caddr = addr.clone();
remote_udp
.recv_dgram(buf)
.timeout(to)
.map_err(move |err| match err.into_inner() {
Some(e) => e,
None => {
error!(
"Udp associate waiting datagram {} <- {} timed out in {:?}",
src, caddr, to
);
io::Error::new(io::ErrorKind::TimedOut, "udp recv timed out")
}
})
.and_then(move |(_remote_udp, buf, n, _from)| {
let svr_cfg = svr_cfg_cloned;
decrypt_payload(svr_cfg.method(), svr_cfg.key(), &buf[..n])
})
.map(|payload| (payload, addr))
})
.and_then(move |(payload, addr)| {
Address::read_from(Cursor::new(payload))
.map_err(From::from)
.map(|(cur, ..)| (cur, addr))
})
.and_then(move |(mut cur, addr)| {
let payload_len = cur.get_ref().len() - cur.position() as usize;
debug!(
"UDP ASSOCIATE {} <- {}, payload length {} bytes",
src, addr, payload_len
);
let mut data = Vec::new();
UdpAssociateHeader::new(0, Address::SocketAddress(src)).write_to_buf(&mut data);
cur.read_to_end(&mut data).unwrap();
SendDgramRc::new(socket, data, src)
})
.map(|_| ());
tokio::spawn(rel.map_err(|err| {
error!("Error occurs in UDP relay: {}", err);
}));
Ok(())
})
}
/// Starts a UDP local server
pub fn run(context: SharedContext) -> impl Future<Item = (), Error = io::Error> + Send {
pub async fn run(context: SharedContext) -> io::Result<()> {
let local_addr = *context.config().local.as_ref().unwrap();
futures::lazy(move || {
info!("ShadowSocks UDP Listening on {}", local_addr);
let listener = UdpSocket::bind(&local_addr).await?;
info!("ShadowSocks UDP listening on {}", local_addr);
UdpSocket::bind(&local_addr)
})
.and_then(move |l| listen(context, l))
listen(context, listener).await
}
-82
View File
@@ -37,17 +37,6 @@
//! | Fixed | Variable |
//! +-------+--------------+
use std::{
io, mem,
net::SocketAddr,
sync::{Arc, Mutex},
};
use tokio::net::UdpSocket;
use futures::{try_ready, Async, Future, Poll, Stream};
pub mod dns;
pub mod local;
pub mod server;
@@ -59,74 +48,3 @@ mod crypto_io;
/// Socks5 UDP ASSOCIATE packet size. The only thing I can find is
/// [here](http://support.microsoft.com/kb/822061/)*
pub const MAXIMUM_UDP_PAYLOAD_SIZE: usize = 65536;
type SharedUdpSocket = Arc<Mutex<UdpSocket>>;
/// UDP `recv_from` stream
pub struct PacketStream {
udp: SharedUdpSocket,
buf: [u8; MAXIMUM_UDP_PAYLOAD_SIZE],
}
impl PacketStream {
/// Creates a new `PacketStream`
pub fn new(udp: SharedUdpSocket) -> PacketStream {
PacketStream {
udp,
buf: [0u8; MAXIMUM_UDP_PAYLOAD_SIZE],
}
}
}
impl Stream for PacketStream {
type Error = io::Error;
type Item = (Vec<u8>, SocketAddr);
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
let (n, addr) = try_ready!(self.udp.lock().unwrap().poll_recv_from(&mut self.buf));
Ok(Async::Ready(Some((self.buf[..n].to_vec(), addr))))
}
}
enum SendDgramStat<B: AsRef<[u8]>> {
Pending {
udp: SharedUdpSocket,
buf: B,
addr: SocketAddr,
},
Empty,
}
/// Send datagram with `Rc<UdpSocket>`
pub struct SendDgramRc<B: AsRef<[u8]>> {
stat: SendDgramStat<B>,
}
impl<B: AsRef<[u8]>> SendDgramRc<B> {
pub fn new(udp: SharedUdpSocket, buf: B, addr: SocketAddr) -> SendDgramRc<B> {
SendDgramRc {
stat: SendDgramStat::Pending { udp, buf, addr },
}
}
}
impl<B: AsRef<[u8]>> Future for SendDgramRc<B> {
type Error = io::Error;
type Item = (SharedUdpSocket, usize, B);
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let n = match self.stat {
SendDgramStat::Pending {
ref udp,
ref buf,
ref addr,
} => try_ready!(udp.lock().unwrap().poll_send_to(buf.as_ref(), addr)),
SendDgramStat::Empty => unreachable!(),
};
match mem::replace(&mut self.stat, SendDgramStat::Empty) {
SendDgramStat::Pending { udp, buf, .. } => Ok(Async::Ready((udp, n, buf))),
SendDgramStat::Empty => unreachable!(),
}
}
}
+146 -126
View File
@@ -1,163 +1,183 @@
//! UDP relay proxy server
use std::{
io::{self, Cursor, ErrorKind},
io::{self, Cursor},
net::{IpAddr, Ipv4Addr, SocketAddr},
sync::{Arc, Mutex},
sync::Arc,
time::Duration,
};
use futures::{self, stream::futures_unordered, Future, Stream};
use bytes::BytesMut;
use futures::{self, stream::FuturesUnordered, StreamExt};
use log::{debug, error, info};
use tokio::{self, net::UdpSocket, util::FutureExt};
use tokio::{self, net::UdpSocket, sync::mpsc};
use crate::{
config::ServerConfig,
context::SharedContext,
relay::{boxed_future, dns_resolver::resolve, socks5::Address},
relay::{socks5::Address, utils::try_timeout},
};
use super::{
crypto_io::{decrypt_payload, encrypt_payload},
PacketStream, SendDgramRc, MAXIMUM_UDP_PAYLOAD_SIZE,
MAXIMUM_UDP_PAYLOAD_SIZE,
};
fn resolve_remote_addr(
#[allow(unused_variables)] // `context` is only used if trust-dns is enabled
async fn udp_associate(
context: SharedContext,
addr: Address,
) -> impl Future<Item = SocketAddr, Error = io::Error> + Send {
match addr {
Address::SocketAddress(s) => {
if context.config().forbidden_ip.contains(&s.ip()) {
let err = io::Error::new(
ErrorKind::Other,
format!("{} is forbidden, failed to connect {}", s.ip(), s),
);
return boxed_future(futures::done(Err(err)));
svr_cfg: Arc<ServerConfig>,
decrypted_pkt: Vec<u8>,
src: SocketAddr,
) -> io::Result<Vec<u8>> {
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(5);
// CLIENT -> SERVER protocol: ADDRESS + PAYLOAD
let mut cur = Cursor::new(decrypted_pkt);
let addr = Address::read_from(&mut cur).await?;
// Take out internal buffer for optimizing one byte copy
let header_len = cur.position() as usize;
let decrypted_pkt = cur.into_inner();
let body = &decrypted_pkt[header_len..];
debug!("UDP ASSOCIATE {} -> {}, payload length {} bytes", src, addr, body.len());
// FIXME: Create one UdpSocket for one associate
let local_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
let mut remote_udp = UdpSocket::bind(&local_addr).await?;
let timeout = svr_cfg.udp_timeout().unwrap_or(DEFAULT_TIMEOUT);
// Writes body to remote
let send_len = match addr {
Address::SocketAddress(ref remote_addr) => {
try_timeout(remote_udp.send_to(&body, remote_addr), Some(timeout)).await?
}
#[cfg(feature = "trust-dns")]
Address::DomainNameAddress(ref dname, port) => {
use crate::relay::dns_resolver::resolve;
let vec_ipaddr = resolve(context, dname, port, false).await?;
assert!(!vec_ipaddr.is_empty());
try_timeout(remote_udp.send_to(&body, &vec_ipaddr[0]), Some(timeout)).await?
}
#[cfg(not(feature = "trust-dns"))]
Address::DomainNameAddress(ref dname, port) => {
try_timeout(remote_udp.send_to(&body, (dname.as_str(), port)), Some(timeout)).await?
}
};
assert_eq!(body.len(), send_len);
// Waiting for response from server SERVER -> CLIENT
// Packet length is limited by MAXIMUM_UDP_PAYLOAD_SIZE, excess bytes will be discarded.
let mut remote_buf = [0u8; MAXIMUM_UDP_PAYLOAD_SIZE];
let remote_recv_len = try_timeout(remote_udp.recv(&mut remote_buf), Some(timeout)).await?;
// Making response packet, SERVER -> CLIENT: ADDRESS + PAYLOAD
let mut send_buf = Vec::new();
addr.write_to_buf(&mut send_buf);
send_buf.extend_from_slice(&remote_buf[..remote_recv_len]);
debug!(
"UDP ASSOCIATE {} <- {}, payload length {} bytes",
src,
addr,
send_buf.len()
);
Ok(send_buf)
}
async fn listen(context: SharedContext, svr_cfg: Arc<ServerConfig>) -> io::Result<()> {
let listen_addr = *svr_cfg.addr().listen_addr();
info!("ShadowSocks UDP listening on {}", listen_addr);
let listener = UdpSocket::bind(&listen_addr).await?;
let (mut r, mut w) = listener.split();
let svr_cfg_cloned = svr_cfg.clone();
// FIXME: Channel size 1024?
let (tx, mut rx) = mpsc::channel::<(SocketAddr, Vec<u8>)>(1024);
tokio::spawn(async move {
let svr_cfg = svr_cfg_cloned;
while let Some((src, pkt)) = rx.recv().await {
// Encrypts
let mut response_pkt = BytesMut::new();
if let Err(err) = encrypt_payload(svr_cfg.method(), svr_cfg.key(), &pkt, &mut response_pkt) {
error!("UDP packet encrypt failed, err: {:?}", err);
continue;
}
boxed_future(futures::finished(s))
}
Address::DomainNameAddress(dname, port) => {
let fut = resolve(context, &dname, port, true).map(move |vec_ipaddr| {
assert!(!vec_ipaddr.is_empty());
vec_ipaddr[0]
});
boxed_future(fut)
if let Err(err) = w.send_to(&response_pkt, &src).await {
error!("UDP packet send failed, err: {:?}", err);
break;
}
}
// FIXME: How to stop the outer listener Future?
});
let mut pkt_buf = [0u8; MAXIMUM_UDP_PAYLOAD_SIZE];
loop {
let (recv_len, src) = r.recv_from(&mut pkt_buf).await?;
// Packet length is limited by MAXIMUM_UDP_PAYLOAD_SIZE, excess bytes will be discarded.
let pkt = &pkt_buf[..recv_len];
// First of all, decrypt payload CLIENT -> SERVER
let decrypted_pkt = match decrypt_payload(svr_cfg.method(), svr_cfg.key(), pkt) {
Ok(Some(pkt)) => pkt,
Ok(None) => {
error!("Failed to decrypt pkt in UDP relay, packet too short");
continue;
}
Err(err) => {
error!("Failed to decrypt pkt in UDP relay: {}", err);
continue;
}
};
let context = context.clone();
let svr_cfg = svr_cfg.clone();
let mut tx = tx.clone();
tokio::spawn(async move {
match udp_associate(context, svr_cfg, decrypted_pkt, src).await {
Ok(pkt) => {
if let Err(..) = tx.send((src, pkt)).await {
error!("UDP packet channel closed");
}
}
Err(err) => {
error!("Error occurs in UDP relay: {}", err);
}
}
});
}
}
fn listen(context: SharedContext, svr_cfg: Arc<ServerConfig>) -> impl Future<Item = (), Error = io::Error> + Send {
let listen_addr = *svr_cfg.addr().listen_addr();
info!("ShadowSocks UDP listening on {}", listen_addr);
futures::lazy(move || UdpSocket::bind(&listen_addr)).and_then(move |socket| {
let socket = Arc::new(Mutex::new(socket));
PacketStream::new(socket.clone()).for_each(move |(pkt, src)| {
let svr_cfg = svr_cfg.clone();
let svr_cfg_cloned = svr_cfg.clone();
let socket = socket.clone();
let context = context.clone();
let timeout = svr_cfg.timeout();
let rel = futures::lazy(move || decrypt_payload(svr_cfg.method(), svr_cfg.key(), &pkt))
.and_then(move |payload| {
// Read Address in the front (ShadowSocks protocol)
Address::read_from(Cursor::new(payload))
.map_err(From::from)
.and_then(move |(r, addr)| {
let header_len = r.position() as usize;
let mut payload = r.into_inner();
payload.drain(..header_len);
let body = payload;
debug!("UDP ASSOCIATE {} -> {}, payload length {} bytes", src, addr, body.len());
Ok((addr, body))
})
.and_then(|(addr, body)| {
let local_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
UdpSocket::bind(&local_addr).map(|remote_udp| (remote_udp, addr, body))
})
.and_then(|(remote_udp, addr, body)| {
resolve_remote_addr(context, addr.clone())
.and_then(|addr| remote_udp.send_dgram(body, &addr))
.map(|(remote_udp, _)| (remote_udp, addr))
})
})
.and_then(move |(remote_udp, addr)| {
let buf = vec![0u8; MAXIMUM_UDP_PAYLOAD_SIZE];
let to = timeout.unwrap_or(Duration::from_secs(5));
let caddr = addr.clone();
remote_udp
.recv_dgram(buf)
.timeout(to)
.map_err(move |err| match err.into_inner() {
Some(e) => e,
None => {
error!(
"Udp associate waiting datagram {} -> {} timed out in {:?}",
src, caddr, to
);
io::Error::new(io::ErrorKind::TimedOut, "udp recv timed out")
}
})
.and_then(|(_remote_udp, buf, n, _from)| {
let svr_cfg = svr_cfg_cloned;
let mut send_buf = Vec::new();
addr.write_to_buf(&mut send_buf);
send_buf.extend_from_slice(&buf[..n]);
encrypt_payload(svr_cfg.method(), svr_cfg.key(), &send_buf).map(|buf| (buf, addr))
})
})
.and_then(move |(buf, addr)| {
debug!("UDP ASSOCIATE {} <- {}, payload length {} bytes", src, addr, buf.len());
let to = timeout.unwrap_or(Duration::from_secs(5));
let caddr = addr.clone();
SendDgramRc::new(socket, buf, src)
.timeout(to)
.map_err(move |err| match err.into_inner() {
Some(e) => e,
None => {
error!(
"Udp associate sending datagram {} <- {} timed out in {:?}",
src, caddr, to
);
io::Error::new(io::ErrorKind::TimedOut, "udp send timed out")
}
})
})
.map(|_| ());
tokio::spawn(rel.map_err(|err| {
error!("Udp relay error: {}", err);
}));
Ok(())
})
})
}
/// Starts a UDP relay server
pub fn run(context: SharedContext) -> impl Future<Item = (), Error = io::Error> + Send {
let mut vec_fut = Vec::new();
pub async fn run(context: SharedContext) -> io::Result<()> {
let vec_fut = FuturesUnordered::new();
for svr in &context.config().server {
let svr_cfg = Arc::new(svr.clone());
let svr_fut = listen(context.clone(), svr_cfg);
vec_fut.push(boxed_future(svr_fut));
vec_fut.push(svr_fut);
}
futures_unordered(vec_fut).into_future().then(|res| match res {
Ok(..) => {
error!("One of UDP servers exited unexpectly without error");
match vec_fut.into_future().await.0 {
Some(res) => {
error!("One of TCP servers exited unexpectly, result: {:?}", res);
let err = io::Error::new(io::ErrorKind::Other, "server exited unexpectly");
Err(err)
}
Err((err, ..)) => {
error!("One of UDP servers exited unexpectly with error {}", err);
Err(err)
}
})
None => unreachable!(),
}
}
+10 -41
View File
@@ -1,47 +1,16 @@
use std::io;
use std::future::Future;
use std::{io, time::Duration};
use futures::{try_ready, Async, Future, Poll};
use tokio_io::{
io::{write_all, WriteAll},
AsyncWrite,
};
use tokio::time;
/// Write all bytes without returning the internal bytes buffer
pub struct WriteBytes<W, B>
pub async fn try_timeout<T, E, F>(fut: F, timeout: Option<Duration>) -> io::Result<T>
where
W: AsyncWrite,
B: AsRef<[u8]>,
F: Future<Output = Result<T, E>>,
io::Error: From<E>,
{
inner: WriteAll<W, B>,
}
impl<W, B> WriteBytes<W, B>
where
W: AsyncWrite,
B: AsRef<[u8]>,
{
fn new(writer: W, bytes: B) -> WriteBytes<W, B> {
WriteBytes {
inner: write_all(writer, bytes),
}
match timeout {
Some(t) => time::timeout(t, fut).await?,
None => fut.await,
}
}
impl<W, B> Future for WriteBytes<W, B>
where
W: AsyncWrite,
B: AsRef<[u8]>,
{
type Error = io::Error;
type Item = W;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let (w, _) = try_ready!(self.inner.poll());
Ok(Async::Ready(w))
}
}
/// Write all bytes without returning the internal bytes buffer
pub fn write_bytes<W: AsyncWrite, B: AsRef<[u8]>>(w: W, b: B) -> WriteBytes<W, B> {
WriteBytes::new(w, b)
.map_err(From::from)
}
-84
View File
@@ -1,84 +0,0 @@
use std::{
collections::HashSet,
net::{SocketAddr, UdpSocket},
thread,
time::Duration,
};
use dns_parser::{Builder, Packet, QueryClass, QueryType};
use log::trace;
use shadowsocks::{
config::{Config, ConfigType},
run_dns, run_server,
};
use tokio::runtime::current_thread::Runtime;
const CONFIG: &str = r#"{
"server": "127.0.0.1",
"server_port": 8988,
"local_port": 5030,
"local_address": "127.0.0.1",
"password": "abc",
"timeout": 20,
"method": "aes-256-gcm",
"mode": "tcp_and_udp",
"remote_dns": "114.114.114.114:53"
}"#;
#[test]
fn dns_relay() {
let _ = env_logger::try_init();
let server_cfg = Config::load_from_str(CONFIG, ConfigType::Server).unwrap();
let dns_cfg = Config::load_from_str(CONFIG, ConfigType::Local).unwrap();
trace!("Server: {:?}", server_cfg);
trace!("Client: {:?}", dns_cfg);
thread::spawn(move || {
let mut runtime = Runtime::new().expect("Failed to create Runtime");
runtime.block_on(run_server(server_cfg)).unwrap();
});
thread::spawn(move || {
let mut runtime = Runtime::new().expect("Failed to create Runtime");
runtime.block_on(run_dns(dns_cfg)).unwrap();
});
thread::sleep(Duration::from_secs(1));
let dns_addr = "127.0.0.1:5030".parse::<SocketAddr>().unwrap();
let local_addr = "0.0.0.0:0".parse::<SocketAddr>().unwrap();
let local = UdpSocket::bind(&local_addr).unwrap();
local.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
local.set_write_timeout(Some(Duration::from_secs(5))).unwrap();
const LOOP_ROUND: usize = 10;
let mut sent_id = HashSet::<u16, _>::with_capacity(LOOP_ROUND);
for _ in 0..LOOP_ROUND {
let mut id = rand::random::<u16>();
while let Some(..) = sent_id.get(&id) {
id = rand::random::<u16>();
}
sent_id.insert(id);
let mut builder = Builder::new_query(id, false);
builder.add_question("www.example.com", false, QueryType::A, QueryClass::IN);
let payload = builder.build().unwrap();
local.send_to(&payload, &dns_addr).unwrap();
trace!("DNS SENT {:?}", payload);
let mut buf = [0u8; 65535];
let (len, _) = local.recv_from(&mut buf).unwrap();
let packet = Packet::parse(&buf[..len]).unwrap();
trace!("DNS GOT {:?}", packet);
assert_eq!(packet.header.id, id);
}
}
+38 -54
View File
@@ -1,12 +1,7 @@
use std::{
net::{SocketAddr, ToSocketAddrs},
thread,
time::Duration,
};
use std::net::{SocketAddr, ToSocketAddrs};
use futures::Future;
use tokio::runtime::current_thread::Runtime;
use tokio_io::io::{flush, read_to_end, write_all};
use tokio::prelude::*;
use tokio::time::{self, Duration};
use shadowsocks::{
config::{Config, ConfigType, Mode, ServerConfig},
@@ -52,27 +47,19 @@ impl Socks5TestServer {
&self.local_addr
}
pub fn run(&self) {
pub async fn run(&self) {
let svr_cfg = self.svr_config.clone();
thread::spawn(move || {
let mut runtime = Runtime::new().expect("Failed to create Runtime");
let fut = run_server(svr_cfg);
runtime.block_on(fut).expect("Failed to run Server");
});
tokio::spawn(run_server(svr_cfg));
let client_cfg = self.cli_config.clone();
thread::spawn(move || {
let mut runtime = Runtime::new().expect("Failed to create Runtime");
let fut = run_local(client_cfg);
runtime.block_on(fut).expect("Failed to run Local");
});
tokio::spawn(run_local(client_cfg));
thread::sleep(Duration::from_secs(1));
time::delay_for(Duration::from_secs(1)).await;
}
}
#[test]
fn socks5_relay_stream() {
#[tokio::test]
async fn socks5_relay_stream() {
let _ = env_logger::try_init();
const SERVER_ADDR: &str = "127.0.0.1:8100";
@@ -82,29 +69,27 @@ fn socks5_relay_stream() {
const METHOD: CipherType = CipherType::Aes256Cfb;
let svr = Socks5TestServer::new(SERVER_ADDR, LOCAL_ADDR, PASSWORD, METHOD, false);
svr.run();
svr.run().await;
let c = Socks5Client::connect(
let mut c = Socks5Client::connect(
Address::DomainNameAddress("www.example.com".to_owned(), 80),
*svr.client_addr(),
);
svr.client_addr(),
)
.await
.unwrap();
let fut = c.and_then(|c| {
let req = b"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n";
write_all(c, req.to_vec())
.and_then(|(c, _)| flush(c))
.and_then(|c| read_to_end(c, Vec::new()))
.map(|(_, buf)| {
println!("Got reply from server: {}", String::from_utf8(buf).unwrap());
})
});
let req = b"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n";
c.write_all(req).await.unwrap();
c.flush().await.unwrap();
let mut runtime = Runtime::new().expect("Failed to create Runtime");
runtime.block_on(fut).unwrap();
let mut buf = Vec::new();
c.read_to_end(&mut buf).await.unwrap();
println!("Got reply from server: {}", String::from_utf8(buf).unwrap());
}
#[test]
fn socks5_relay_aead() {
#[tokio::test]
async fn socks5_relay_aead() {
let _ = env_logger::try_init();
const SERVER_ADDR: &str = "127.0.0.1:8110";
@@ -114,22 +99,21 @@ fn socks5_relay_aead() {
const METHOD: CipherType = CipherType::Aes256Gcm;
let svr = Socks5TestServer::new(SERVER_ADDR, LOCAL_ADDR, PASSWORD, METHOD, false);
svr.run();
svr.run().await;
let c = Socks5Client::connect(
let mut c = Socks5Client::connect(
Address::DomainNameAddress("www.example.com".to_owned(), 80),
*svr.client_addr(),
);
let fut = c.and_then(|c| {
let req = b"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n";
write_all(c, req.to_vec())
.and_then(|(c, _)| flush(c))
.and_then(|c| read_to_end(c, Vec::new()))
.map(|(_, buf)| {
println!("Got reply from server: {}", String::from_utf8(buf).unwrap());
})
});
svr.client_addr(),
)
.await
.unwrap();
let mut runtime = Runtime::new().expect("Failed to create Runtime");
runtime.block_on(fut).unwrap();
let req = b"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n";
c.write_all(req).await.unwrap();
c.flush().await.unwrap();
let mut buf = Vec::new();
c.read_to_end(&mut buf).await.unwrap();
println!("Got reply from server: {}", String::from_utf8(buf).unwrap());
}
+57
View File
@@ -0,0 +1,57 @@
use env_logger;
use tokio;
use tokio::net::TcpStream;
use tokio::prelude::*;
use tokio::time::{self, Duration};
use shadowsocks::config::{Config, ConfigType};
use shadowsocks::relay::socks5::Address;
use shadowsocks::{run_local, run_server};
#[tokio::test]
async fn tcp_tunnel() {
let _ = env_logger::try_init();
let mut local_config = Config::load_from_str(
r#"{
"local_port": 9110,
"local_address": "127.0.0.1",
"server": "127.0.0.1",
"server_port": 9120,
"password": "password",
"method": "aes-256-gcm"
}"#,
ConfigType::Local,
)
.unwrap();
local_config.forward = Some("www.example.com:80".parse::<Address>().unwrap());
let server_config = Config::load_from_str(
r#"{
"server": "127.0.0.1",
"server_port": 9120,
"password": "password",
"method": "aes-256-gcm"
}"#,
ConfigType::Server,
)
.unwrap();
tokio::spawn(run_local(local_config));
tokio::spawn(run_server(server_config));
time::delay_for(Duration::from_secs(1)).await;
// Connect it directly, because it is now established a TCP tunnel with www.example.com
let mut stream = TcpStream::connect("127.0.0.1:9110").await.unwrap();
let req = b"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n";
stream.write_all(req).await.unwrap();
stream.flush().await.unwrap();
let mut buf = Vec::new();
stream.read_to_end(&mut buf).await.unwrap();
println!("Got reply from server: {}", String::from_utf8(buf).unwrap());
}
+55 -76
View File
@@ -1,17 +1,14 @@
#![cfg_attr(clippy, allow(blacklisted_name))]
use std::{
io::Cursor,
io::{self, Cursor},
net::SocketAddr,
sync::{Arc, Barrier},
thread,
time::Duration,
};
use bytes::{BufMut, BytesMut};
use futures::Future;
use tokio::runtime::current_thread::Runtime;
use tokio_io::io::read_to_end;
use log::debug;
use tokio::prelude::*;
use tokio::time::{self, Duration};
use shadowsocks::{
config::{Config, ConfigType, Mode, ServerConfig},
@@ -59,88 +56,67 @@ fn get_client_addr() -> SocketAddr {
LOCAL_ADDR.parse().unwrap()
}
fn start_server(bar: Arc<Barrier>) {
thread::spawn(move || {
let mut runtime = Runtime::new().expect("Failed to create Runtime");
fn start_server() {
tokio::spawn(run_server(get_svr_config()));
}
let fut = run_server(get_svr_config());
bar.wait();
runtime.block_on(fut).expect("Failed to run Server");
fn start_local() {
tokio::spawn(run_local(get_cli_config()));
}
fn start_udp_echo_server() {
use tokio::net::UdpSocket;
tokio::spawn(async {
let mut l = UdpSocket::bind(UDP_ECHO_SERVER_ADDR).await.unwrap();
debug!("UDP echo server started {}", UDP_ECHO_SERVER_ADDR);
let mut buf = vec![0u8; 65536];
let (amt, src) = l.recv_from(&mut buf).await.unwrap();
debug!("UDP echo received {} bytes from {}", amt, src);
l.send_to(&buf[..amt], &src).await.unwrap();
debug!("UDP echo sent {} bytes to {}", amt, src);
});
}
fn start_local(bar: Arc<Barrier>) {
thread::spawn(move || {
let mut runtime = Runtime::new().expect("Failed to create Runtime");
fn start_udp_request_holder(addr: Address) {
tokio::spawn(async move {
let (mut c, addr) = Socks5Client::udp_associate(addr, &get_client_addr()).await?;
assert_eq!(addr, Address::SocketAddress(LOCAL_ADDR.parse().unwrap()));
let fut = run_local(get_cli_config());
bar.wait();
runtime.block_on(fut).expect("Failed to run Local");
debug!("TCP sent UDP associate {} request", addr);
// Holds it forever
let mut buf = Vec::new();
c.read_to_end(&mut buf).await?;
io::Result::Ok(())
});
}
fn start_udp_echo_server(bar: Arc<Barrier>) {
use std::net::UdpSocket;
thread::spawn(move || {
let l = UdpSocket::bind(UDP_ECHO_SERVER_ADDR).unwrap();
bar.wait();
let mut buf = [0u8; 65536];
let (amt, src) = l.recv_from(&mut buf).unwrap();
l.send_to(&buf[..amt], &src).unwrap();
});
}
fn start_udp_request_holder(bar: Arc<Barrier>, addr: Address) {
thread::spawn(move || {
let mut runtime = Runtime::new().expect("Failed to create Runtime");
let c = Socks5Client::udp_associate(addr, get_client_addr());
let fut = c.and_then(|(c, addr)| {
assert_eq!(addr, Address::SocketAddress(LOCAL_ADDR.parse().unwrap()));
// Holds it forever
read_to_end(c, Vec::new()).map(|_| ())
});
bar.wait();
runtime.block_on(fut).expect("Failed to run UDP socks5 client");
});
}
#[test]
fn udp_relay() {
use std::net::UdpSocket;
#[tokio::test]
async fn udp_relay() {
use tokio::net::UdpSocket;
let _ = env_logger::try_init();
let remote_addr = Address::SocketAddress(UDP_ECHO_SERVER_ADDR.parse().unwrap());
let bar = Arc::new(Barrier::new(4));
start_server();
start_local();
start_server(bar.clone());
start_local(bar.clone());
start_udp_echo_server(bar.clone());
bar.wait();
start_udp_echo_server();
// Wait until all server starts
thread::sleep(Duration::from_secs(1));
time::delay_for(Duration::from_secs(1)).await;
let bar = Arc::new(Barrier::new(2));
start_udp_request_holder(remote_addr.clone());
start_udp_request_holder(bar.clone(), remote_addr.clone());
bar.wait();
let l = UdpSocket::bind(UDP_LOCAL_ADDR).unwrap();
l.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
l.set_write_timeout(Some(Duration::from_secs(5))).unwrap();
let mut l = UdpSocket::bind(UDP_LOCAL_ADDR).await.unwrap();
let header = UdpAssociateHeader::new(0, remote_addr);
let mut buf = BytesMut::with_capacity(header.serialized_len());
@@ -152,14 +128,17 @@ fn udp_relay() {
buf.put_slice(payload);
let local_addr = LOCAL_ADDR.parse::<SocketAddr>().unwrap();
l.send_to(&buf[..], &local_addr).unwrap();
l.send_to(&buf[..], &local_addr).await.unwrap();
let mut buf = [0u8; 65536];
let (amt, _) = l.recv_from(&mut buf).unwrap();
let mut buf = vec![0u8; 65536];
let (amt, _) = time::timeout(Duration::from_secs(5), l.recv_from(&mut buf))
.await
.unwrap()
.unwrap();
println!("Received buf size={} {:?}", amt, &buf[..amt]);
let cur = Cursor::new(buf[..amt].to_vec());
let (cur, header) = UdpAssociateHeader::read_from(cur).wait().expect("Invalid UDP header");
let mut cur = Cursor::new(buf[..amt].to_vec());
let header = UdpAssociateHeader::read_from(&mut cur).await.unwrap();
println!("{:?}", header);
let header_len = cur.position() as usize;
let buf = cur.into_inner();