first commit, have a runnable tcpserver

This commit is contained in:
Y. T. Chung
2014-10-15 19:01:34 +08:00
commit 17c72b9175
11 changed files with 418 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
/target
+23
View File
@@ -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"
+19
View File
@@ -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.
+86
View File
@@ -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();
}
+81
View File
@@ -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)
}
+90
View File
@@ -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))
}
}
+4
View File
@@ -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
View File
@@ -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;
+13
View File
@@ -0,0 +1,13 @@
pub trait Relay {
fn run(&mut self);
}
pub enum Stage {
StageInit,
StageHello,
StageUdpAssoc,
StageDns,
StageReply,
StageStream,
}
+86
View File
@@ -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
}
}
View File