mirror of
https://github.com/shadowsocks/shadowsocks-rust.git
synced 2026-11-06 16:14:11 +00:00
first commit, have a runnable tcpserver
This commit is contained in:
@@ -0,0 +1 @@
|
||||
/target
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
[package]
|
||||
|
||||
name = "shadowsocks-rust"
|
||||
version = "0.0.1"
|
||||
authors = ["Y. T. Chung <zonyitoo@gmail.com>"]
|
||||
|
||||
[lib]
|
||||
|
||||
name = "shadowsocks"
|
||||
|
||||
[[bin]]
|
||||
|
||||
name = "sslocal"
|
||||
path = "src/bin/local.rs"
|
||||
|
||||
[[bin]]
|
||||
|
||||
name = "ssserver"
|
||||
path = "src/bin/server.rs"
|
||||
|
||||
[dependencies.rust-crypto]
|
||||
|
||||
git = "https://github.com/DaGenix/rust-crypto.git"
|
||||
@@ -0,0 +1,19 @@
|
||||
# shadowsocks-rust
|
||||
|
||||
This is a port of [shadowsocks](https://github.com/clowwindy/shadowsocks).
|
||||
|
||||
shadowsocks is a fast tunnel proxy that helps you bypass firewalls.
|
||||
|
||||
*Currently developing and testing with rust-0.12-dev*
|
||||
|
||||
## Usage
|
||||
|
||||
Build with [Cargo](http://doc.crates.io):
|
||||
|
||||
```bash
|
||||
cargo build
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
Still under developing and waiting for the final release of rust-1.0.
|
||||
@@ -0,0 +1,86 @@
|
||||
#![feature(phase)]
|
||||
|
||||
extern crate getopts;
|
||||
extern crate shadowsocks;
|
||||
#[phase(plugin, link)]
|
||||
extern crate log;
|
||||
|
||||
use getopts::{optopt, optflag, getopts, usage};
|
||||
use std::os;
|
||||
|
||||
use shadowsocks::config::Config;
|
||||
use shadowsocks::tcprelay::TcpRelayLocal;
|
||||
use shadowsocks::relay::Relay;
|
||||
|
||||
fn main() {
|
||||
let opts = [
|
||||
optflag("v", "version", "print version"),
|
||||
optflag("h", "help", "print this message"),
|
||||
optopt("c", "config", "specify config file", "config.json"),
|
||||
optopt("s", "server-addr", "server address", ""),
|
||||
optopt("b", "local-addr", "local address, listen only to this address if specified", ""),
|
||||
optopt("k", "password", "password", ""),
|
||||
optopt("p", "server-port", "server port", ""),
|
||||
optopt("l", "local-port", "local socks5 proxy port", ""),
|
||||
optopt("m", "encrypt-method", "entryption method", "aes-256-cfb"),
|
||||
optflag("d", "debug", "print debug message"),
|
||||
];
|
||||
|
||||
let matches = getopts(os::args().tail(), opts).unwrap();
|
||||
|
||||
if matches.opt_present("h") {
|
||||
println!("{}", usage(format!("Usage: {} [options]", os::args()[0]).as_slice(),
|
||||
opts));
|
||||
return;
|
||||
}
|
||||
|
||||
if matches.opt_present("v") {
|
||||
println!("{}", shadowsocks::VERSION);
|
||||
return;
|
||||
}
|
||||
|
||||
let mut config: Config;
|
||||
|
||||
if matches.opt_present("c") {
|
||||
config = Config::load_from_file(matches.opt_str("c")
|
||||
.unwrap().as_slice())
|
||||
} else {
|
||||
config = Config::new()
|
||||
}
|
||||
|
||||
if matches.opt_present("s") {
|
||||
let server_ip = matches.opt_str("s").unwrap();
|
||||
config.server = server_ip;
|
||||
}
|
||||
if matches.opt_present("b") {
|
||||
let local_ip = matches.opt_str("b").unwrap();
|
||||
config.local = local_ip;
|
||||
}
|
||||
if matches.opt_present("k") {
|
||||
let passwd = matches.opt_str("k").unwrap();
|
||||
config.password = passwd;
|
||||
}
|
||||
if matches.opt_present("p") {
|
||||
let server_port = matches.opt_str("p").unwrap();
|
||||
config.server_port = from_str(server_port.as_slice()).unwrap();
|
||||
}
|
||||
if matches.opt_present("l") {
|
||||
let local_port = matches.opt_str("l").unwrap();
|
||||
config.local_port = from_str(local_port.as_slice()).unwrap();
|
||||
}
|
||||
if matches.opt_present("m") {
|
||||
let mut encrypt_meth = matches.opt_str("m").unwrap();
|
||||
if encrypt_meth.as_slice() == "" {
|
||||
encrypt_meth = "aes-256-cfb".to_string();
|
||||
}
|
||||
|
||||
config.method = encrypt_meth;
|
||||
}
|
||||
|
||||
info!("ShadowSocks {}", shadowsocks::VERSION);
|
||||
|
||||
println!("{}", config)
|
||||
|
||||
let mut tcp_server = TcpRelayLocal::new(&config);
|
||||
tcp_server.run();
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
#![feature(phase)]
|
||||
|
||||
extern crate getopts;
|
||||
extern crate shadowsocks;
|
||||
#[phase(plugin, link)]
|
||||
extern crate log;
|
||||
|
||||
use getopts::{optopt, optflag, getopts, usage};
|
||||
use std::os;
|
||||
|
||||
use shadowsocks::config::Config;
|
||||
|
||||
fn main() {
|
||||
let opts = [
|
||||
optflag("v", "version", "print version"),
|
||||
optflag("h", "help", "print this message"),
|
||||
optopt("c", "config", "specify config file", "config.json"),
|
||||
optopt("s", "server-addr", "server address", ""),
|
||||
optopt("b", "local-addr", "local address, listen only to this address if specified", ""),
|
||||
optopt("k", "password", "password", ""),
|
||||
optopt("p", "server-port", "server port", ""),
|
||||
optopt("l", "local-port", "local socks5 proxy port", ""),
|
||||
optopt("m", "encrypt-method", "entryption method", "aes-256-cfb"),
|
||||
optflag("d", "debug", "print debug message"),
|
||||
];
|
||||
|
||||
let matches = getopts(os::args().tail(), opts).unwrap();
|
||||
|
||||
if matches.opt_present("h") {
|
||||
println!("{}", usage(format!("Usage: {} [options]", os::args()[0]).as_slice(),
|
||||
opts));
|
||||
return;
|
||||
}
|
||||
|
||||
if matches.opt_present("v") {
|
||||
println!("{}", shadowsocks::VERSION);
|
||||
return;
|
||||
}
|
||||
|
||||
let mut config: Config;
|
||||
|
||||
if matches.opt_present("c") {
|
||||
config = Config::load_from_file(matches.opt_str("c")
|
||||
.unwrap().as_slice())
|
||||
} else {
|
||||
config = Config::new()
|
||||
}
|
||||
|
||||
if matches.opt_present("s") {
|
||||
let server_ip = matches.opt_str("s").unwrap();
|
||||
config.server = server_ip;
|
||||
}
|
||||
if matches.opt_present("b") {
|
||||
let local_ip = matches.opt_str("b").unwrap();
|
||||
config.local = local_ip;
|
||||
}
|
||||
if matches.opt_present("k") {
|
||||
let passwd = matches.opt_str("k").unwrap();
|
||||
config.password = passwd;
|
||||
}
|
||||
if matches.opt_present("p") {
|
||||
let server_port = matches.opt_str("p").unwrap();
|
||||
config.server_port = from_str(server_port.as_slice()).unwrap();
|
||||
}
|
||||
if matches.opt_present("l") {
|
||||
let local_port = matches.opt_str("l").unwrap();
|
||||
config.local_port = from_str(local_port.as_slice()).unwrap();
|
||||
}
|
||||
if matches.opt_present("m") {
|
||||
let mut encrypt_meth = matches.opt_str("m").unwrap();
|
||||
if encrypt_meth.as_slice() == "" {
|
||||
encrypt_meth = "aes-256-cfb".to_string();
|
||||
}
|
||||
|
||||
config.method = encrypt_meth;
|
||||
}
|
||||
|
||||
info!("ShadowSocks {}", shadowsocks::VERSION);
|
||||
|
||||
println!("{}", config)
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
extern crate serialize;
|
||||
|
||||
use serialize::{Decodable, Encodable};
|
||||
use serialize::json;
|
||||
use std::io::{File, Read, Open};
|
||||
|
||||
use std::to_string::ToString;
|
||||
use std::fmt::{Show, Formatter, mod};
|
||||
|
||||
use std::option::Option;
|
||||
|
||||
#[deriving(Encodable, Clone)]
|
||||
pub struct Config {
|
||||
pub server: String,
|
||||
pub local: String,
|
||||
pub server_port: u16,
|
||||
pub local_port: u16,
|
||||
pub password: String,
|
||||
pub method: String,
|
||||
pub timeout: Option<u64>,
|
||||
pub fast_open: bool,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new() -> Config {
|
||||
Config{
|
||||
server: "127.0.0.1".to_string(),
|
||||
local: "127.0.0.1".to_string(),
|
||||
server_port: 8000,
|
||||
local_port: 8000,
|
||||
password: "".to_string(),
|
||||
method: "aes-256-cfb".to_string(),
|
||||
timeout: None,
|
||||
fast_open: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_json_object(o: &json::JsonObject) -> Config {
|
||||
let mut config = Config::new();
|
||||
|
||||
for (key, value) in o.iter() {
|
||||
match key.as_slice() {
|
||||
"server" => {
|
||||
config.server = value.as_string().unwrap().to_string();
|
||||
},
|
||||
"server_port" => {
|
||||
config.server_port = value.as_i64().unwrap() as u16;
|
||||
},
|
||||
"local_port" => {
|
||||
config.local_port = value.as_i64().unwrap() as u16;
|
||||
},
|
||||
"password" => {
|
||||
config.password = value.as_string().unwrap().to_string();
|
||||
},
|
||||
"method" => {
|
||||
config.method = value.as_string().unwrap().to_string();
|
||||
},
|
||||
"timeout" => {
|
||||
config.timeout = Some(value.as_i64().unwrap() as u64);
|
||||
},
|
||||
"fast_open" => {
|
||||
config.fast_open = value.as_boolean().unwrap();
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
config
|
||||
}
|
||||
|
||||
pub fn load_from_str(s: &str) -> Config {
|
||||
let object = json::from_str(s).unwrap();
|
||||
let json_object = object.as_object().unwrap();
|
||||
Config::parse_json_object(json_object)
|
||||
}
|
||||
|
||||
pub fn load_from_file(filename: &str) -> Config {
|
||||
let reader = &mut File::open_mode(&Path::new(filename), Open, Read).unwrap();
|
||||
|
||||
let object = json::from_reader(reader).unwrap();
|
||||
let json_object = object.as_object().unwrap();
|
||||
Config::parse_json_object(json_object)
|
||||
}
|
||||
}
|
||||
|
||||
impl Show for Config {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}", json::encode(self))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
extern crate "rust-crypto" as crypto;
|
||||
|
||||
pub const AES_128_CFB: &'static str = "aes-128-cfb";
|
||||
pub const AES_256_CFB: &'static str = "aes-256-cfb";
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
#![crate_type="lib"]
|
||||
#![crate_name="shadowsocks"]
|
||||
#![feature(phase)]
|
||||
|
||||
extern crate serialize;
|
||||
#[phase(plugin, link)]
|
||||
extern crate log;
|
||||
|
||||
pub const VERSION: &'static str = "0.0.1";
|
||||
|
||||
pub mod config;
|
||||
pub mod relay;
|
||||
pub mod tcprelay;
|
||||
pub mod udprelay;
|
||||
pub mod crypto;
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
pub trait Relay {
|
||||
fn run(&mut self);
|
||||
}
|
||||
|
||||
pub enum Stage {
|
||||
StageInit,
|
||||
StageHello,
|
||||
StageUdpAssoc,
|
||||
StageDns,
|
||||
StageReply,
|
||||
StageStream,
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
extern crate log;
|
||||
|
||||
// mod relay;
|
||||
use relay::Relay;
|
||||
use relay::Stage;
|
||||
use relay::{StageInit, StageHello, StageUdpAssoc, StageDns, StageReply, StageStream};
|
||||
|
||||
// mod config;
|
||||
use config::Config;
|
||||
|
||||
use std::io::TcpListener;
|
||||
use std::io::{Acceptor, Listener};
|
||||
use std::io::net::tcp::TcpAcceptor;
|
||||
use std::io::{TimedOut, EndOfFile};
|
||||
|
||||
use std::str;
|
||||
|
||||
pub struct TcpRelayLocal {
|
||||
acceptor: TcpAcceptor,
|
||||
stage: Stage,
|
||||
timeout: Option<u64>,
|
||||
}
|
||||
|
||||
impl TcpRelayLocal {
|
||||
pub fn new(c: &Config) -> TcpRelayLocal {
|
||||
let mut acceptor = TcpListener::bind(c.local.as_slice(), c.local_port).unwrap().listen().unwrap();
|
||||
|
||||
TcpRelayLocal {
|
||||
acceptor: acceptor,
|
||||
stage: StageInit,
|
||||
timeout: c.timeout,
|
||||
}
|
||||
}
|
||||
|
||||
fn accept_loop(&mut self) {
|
||||
loop {
|
||||
match self.acceptor.accept() {
|
||||
Ok(mut stream) => spawn(proc() {
|
||||
info!("Client {} connected", stream.socket_name().unwrap());
|
||||
|
||||
loop {
|
||||
let mut buf = [0u8, .. 10240];
|
||||
match stream.read(buf) {
|
||||
Ok(len) => {
|
||||
println!("Len: {}", len)
|
||||
|
||||
let s = buf.slice_to(len);
|
||||
println!("Received: {}", str::from_utf8(s).unwrap());
|
||||
stream.write(s).unwrap()
|
||||
},
|
||||
Err(err) => {
|
||||
if err.kind == EndOfFile {
|
||||
break
|
||||
}
|
||||
error!("Err: {}", err);
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info!("Client {} disconnected", stream.socket_name().unwrap());
|
||||
|
||||
drop(stream)
|
||||
}),
|
||||
Err(e) => {
|
||||
fail!(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Relay for TcpRelayLocal {
|
||||
fn run(&mut self) {
|
||||
self.accept_loop()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TcpRelayServer;
|
||||
|
||||
impl TcpRelayServer {
|
||||
pub fn new() -> TcpRelayServer {
|
||||
TcpRelayServer
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user