mirror of
https://github.com/shadowsocks/shadowsocks-rust.git
synced 2026-02-09 01:59:16 +08:00
add a crypto mod, fix bugs
This commit is contained in:
@@ -18,6 +18,6 @@ path = "src/bin/local.rs"
|
||||
name = "ssserver"
|
||||
path = "src/bin/server.rs"
|
||||
|
||||
[dependencies.rust-crypto]
|
||||
# [dependencies.rust-crypto]
|
||||
|
||||
git = "https://github.com/DaGenix/rust-crypto.git"
|
||||
# git = "https://github.com/DaGenix/rust-crypto.git"
|
||||
|
||||
@@ -23,7 +23,6 @@ fn main() {
|
||||
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();
|
||||
@@ -39,14 +38,20 @@ fn main() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut config: Config;
|
||||
|
||||
if matches.opt_present("c") {
|
||||
config = Config::load_from_file(matches.opt_str("c")
|
||||
.unwrap().as_slice())
|
||||
let mut config = if matches.opt_present("c") {
|
||||
Config::load_from_file(matches.opt_str("c")
|
||||
.unwrap().as_slice()).unwrap()
|
||||
} else {
|
||||
config = Config::new()
|
||||
}
|
||||
match Config::load_from_file("config.json") {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
error!("Cannot find any `config.json` under current directory");
|
||||
println!("{}", usage(format!("Usage: {} [options]", os::args()[0]).as_slice(),
|
||||
opts));
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if matches.opt_present("s") {
|
||||
let server_ip = matches.opt_str("s").unwrap();
|
||||
@@ -79,8 +84,7 @@ fn main() {
|
||||
|
||||
info!("ShadowSocks {}", shadowsocks::VERSION);
|
||||
|
||||
println!("{}", config)
|
||||
debug!("Config: {}", config)
|
||||
|
||||
let mut tcp_server = TcpRelayLocal::new(&config);
|
||||
tcp_server.run();
|
||||
TcpRelayLocal::new(&config).run();
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ use getopts::{optopt, optflag, getopts, usage};
|
||||
use std::os;
|
||||
|
||||
use shadowsocks::config::Config;
|
||||
use shadowsocks::tcprelay::TcpRelayServer;
|
||||
use shadowsocks::relay::Relay;
|
||||
|
||||
fn main() {
|
||||
let opts = [
|
||||
@@ -21,7 +23,6 @@ fn main() {
|
||||
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();
|
||||
@@ -37,14 +38,18 @@ fn main() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut config: Config;
|
||||
|
||||
if matches.opt_present("c") {
|
||||
config = Config::load_from_file(matches.opt_str("c")
|
||||
.unwrap().as_slice())
|
||||
let mut config = if matches.opt_present("c") {
|
||||
Config::load_from_file(matches.opt_str("c")
|
||||
.unwrap().as_slice()).unwrap()
|
||||
} else {
|
||||
config = Config::new()
|
||||
}
|
||||
match Config::load_from_file("config.json") {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
error!("Cannot find any `config.json` under current directory");
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if matches.opt_present("s") {
|
||||
let server_ip = matches.opt_str("s").unwrap();
|
||||
@@ -77,5 +82,7 @@ fn main() {
|
||||
|
||||
info!("ShadowSocks {}", shadowsocks::VERSION);
|
||||
|
||||
println!("{}", config)
|
||||
debug!("Config: {}", config)
|
||||
|
||||
TcpRelayServer::new(&config).run();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
extern crate serialize;
|
||||
|
||||
use serialize::{Decodable, Encodable};
|
||||
use serialize::Encodable;
|
||||
use serialize::json;
|
||||
use std::io::{File, Read, Open};
|
||||
|
||||
@@ -29,56 +29,98 @@ impl Config {
|
||||
server_port: 8000,
|
||||
local_port: 8000,
|
||||
password: "".to_string(),
|
||||
method: "aes-256-cfb".to_string(),
|
||||
method: "aes-128-cfb".to_string(),
|
||||
timeout: None,
|
||||
fast_open: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_json_object(o: &json::JsonObject) -> Config {
|
||||
fn parse_json_object(o: &json::JsonObject) -> Option<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();
|
||||
config.server = match value.as_string() {
|
||||
Some(v) => v.to_string(),
|
||||
None => return None,
|
||||
};
|
||||
},
|
||||
"server_port" => {
|
||||
config.server_port = value.as_i64().unwrap() as u16;
|
||||
config.server_port = match value.as_i64() {
|
||||
Some(v) => v as u16,
|
||||
None => return None,
|
||||
};
|
||||
},
|
||||
"local_port" => {
|
||||
config.local_port = value.as_i64().unwrap() as u16;
|
||||
config.local_port = match value.as_i64() {
|
||||
Some(v) => v as u16,
|
||||
None => return None,
|
||||
};
|
||||
},
|
||||
"password" => {
|
||||
config.password = value.as_string().unwrap().to_string();
|
||||
config.password = match value.as_string() {
|
||||
Some(v) => v.to_string(),
|
||||
None => return None,
|
||||
};
|
||||
},
|
||||
"method" => {
|
||||
config.method = value.as_string().unwrap().to_string();
|
||||
config.method = match value.as_string() {
|
||||
Some(v) => v.to_string(),
|
||||
None => return None,
|
||||
};
|
||||
},
|
||||
"timeout" => {
|
||||
config.timeout = Some(value.as_i64().unwrap() as u64);
|
||||
config.timeout = match value.as_i64() {
|
||||
Some(v) => Some(v as u64),
|
||||
None => return None,
|
||||
};
|
||||
},
|
||||
"fast_open" => {
|
||||
config.fast_open = value.as_boolean().unwrap();
|
||||
config.fast_open = match value.as_boolean() {
|
||||
Some(v) => v,
|
||||
None => return None,
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
config
|
||||
Some(config)
|
||||
}
|
||||
|
||||
pub fn load_from_str(s: &str) -> Config {
|
||||
let object = json::from_str(s).unwrap();
|
||||
let json_object = object.as_object().unwrap();
|
||||
pub fn load_from_str(s: &str) -> Option<Config> {
|
||||
let object = match json::from_str(s) {
|
||||
Ok(obj) => { obj },
|
||||
Err(e) => return None,
|
||||
};
|
||||
|
||||
let json_object = match object.as_object() {
|
||||
Some(obj) => { obj },
|
||||
None => return None,
|
||||
};
|
||||
|
||||
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();
|
||||
pub fn load_from_file(filename: &str) -> Option<Config> {
|
||||
let mut readeropt = File::open_mode(&Path::new(filename), Open, Read);
|
||||
|
||||
let mut reader = match readeropt {
|
||||
Ok(ref mut r) => r,
|
||||
Err(..) => return None,
|
||||
};
|
||||
|
||||
let object = match json::from_reader(reader) {
|
||||
Ok(obj) => { obj },
|
||||
Err(..) => return None,
|
||||
};
|
||||
|
||||
let json_object = match object.as_object() {
|
||||
Some(obj) => obj,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
let object = json::from_reader(reader).unwrap();
|
||||
let json_object = object.as_object().unwrap();
|
||||
Config::parse_json_object(json_object)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
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";
|
||||
5
src/crypto/cipher.rs
Normal file
5
src/crypto/cipher.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
pub trait Cipher {
|
||||
fn encrypt(&self, data: &[u8]) -> Vec<u8>;
|
||||
fn decrypt(&self, data: &[u8]) -> Vec<u8>;
|
||||
}
|
||||
120
src/crypto/crypto.rs
Normal file
120
src/crypto/crypto.rs
Normal file
@@ -0,0 +1,120 @@
|
||||
extern crate libc;
|
||||
|
||||
use std::vec::Vec;
|
||||
|
||||
pub const CIPHER_AES_128_CFB: &'static str = "aes-128-cfb1";
|
||||
pub const CIPHER_AES_256_CFB: &'static str = "aes-256-cfb";
|
||||
|
||||
struct CipherDef(&'static str, int, int);
|
||||
|
||||
const Ciphers: [CipherDef, .. 2] = [
|
||||
CipherDef(CIPHER_AES_128_CFB, 16, 16),
|
||||
CipherDef(CIPHER_AES_256_CFB, 32, 16),
|
||||
];
|
||||
|
||||
pub enum CipherType {
|
||||
CipherAes128Cfb,
|
||||
CipherAes256Cfb,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
type EVP_CIPHER_CTX = *mut libc::c_void;
|
||||
#[allow(non_camel_case_types)]
|
||||
type EVP_CIPHER = *mut libc::c_void;
|
||||
|
||||
pub const CIPHER_MODE_ENCRYPT: libc::c_int = 1;
|
||||
pub const CIPHER_MODE_DECRYPT: libc::c_int = 0;
|
||||
|
||||
pub enum CipherMode {
|
||||
CipherModeEncrypt,
|
||||
CipherModeDecrypt,
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn cipher_type_from_str(type_string: &str) -> CipherType {
|
||||
match type_string {
|
||||
CIPHER_AES_128_CFB => CipherAes128Cfb,
|
||||
CIPHER_AES_256_CFB => CipherAes256Cfb,
|
||||
_ => fail!("Unknown cipher type"),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Crypto {
|
||||
cipher: EVP_CIPHER,
|
||||
cipher_ctx: EVP_CIPHER_CTX,
|
||||
}
|
||||
|
||||
impl Crypto {
|
||||
pub fn new(method: CipherType, key: &str, iv: &str, mode: CipherMode) -> Crypto {
|
||||
let cipher = unsafe {
|
||||
match method {
|
||||
CipherAes128Cfb => EVP_aes_128_cfb128(),
|
||||
CipherAes256Cfb => EVP_aes_256_cfb(),
|
||||
}
|
||||
};
|
||||
assert!(!cipher.is_null());
|
||||
let cipher_ctx = unsafe { EVP_CIPHER_CTX_new() };
|
||||
|
||||
let op = match mode {
|
||||
CipherModeEncrypt => 1,
|
||||
CipherModeDecrypt => 0
|
||||
};
|
||||
|
||||
unsafe {
|
||||
EVP_CipherInit(cipher_ctx, cipher,
|
||||
key.to_c_str().as_ptr(), iv.to_c_str().as_ptr(), op);
|
||||
}
|
||||
|
||||
Crypto {
|
||||
cipher: cipher,
|
||||
cipher_ctx: cipher_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&self, data: &[u8]) -> Vec<u8> {
|
||||
let pdata: *const u8 = data.as_ptr();
|
||||
let datalen: u32 = data.len() as u32;
|
||||
let mut reslen: u32 = datalen + (16 as u32);
|
||||
let preslen: *mut u32 = &mut reslen;
|
||||
let mut res = Vec::from_elem(reslen as uint, 0u8);
|
||||
let pres: *mut libc::c_uchar = res.as_mut_ptr();
|
||||
|
||||
unsafe {
|
||||
EVP_CipherUpdate(self.cipher_ctx, pres, preslen, pdata, datalen);
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub fn drop(&mut self) {
|
||||
unsafe {
|
||||
EVP_CIPHER_CTX_cleanup(self.cipher_ctx);
|
||||
EVP_CIPHER_CTX_free(self.cipher_ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Cipher {
|
||||
encryptor: Crypto,
|
||||
decryptor: Crypto,
|
||||
}
|
||||
|
||||
impl Cipher {
|
||||
fn new(method: CipherType, key: &str) -> Cipher {
|
||||
|
||||
}
|
||||
|
||||
pub fn encrypt(&self, data: &[u8]) -> Vec<u8> {
|
||||
|
||||
}
|
||||
|
||||
pub fn decrypt(&self, data: &[u8]) -> Vec<u8> {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encrypt_decrypt() {
|
||||
|
||||
}
|
||||
5
src/crypto/mod.rs
Normal file
5
src/crypto/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
extern crate libc;
|
||||
|
||||
pub mod cipher;
|
||||
pub mod openssl;
|
||||
|
||||
198
src/crypto/openssl.rs
Normal file
198
src/crypto/openssl.rs
Normal file
@@ -0,0 +1,198 @@
|
||||
extern crate libc;
|
||||
extern crate log;
|
||||
|
||||
use crypto::cipher::Cipher;
|
||||
|
||||
use std::str;
|
||||
use std::ptr;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
type EVP_CIPHER_CTX = *const libc::c_void;
|
||||
#[allow(non_camel_case_types)]
|
||||
type EVP_CIPHER = *mut libc::c_void;
|
||||
#[allow(non_camel_case_types)]
|
||||
type EVP_MD = *const libc::c_void;
|
||||
|
||||
const CIPHER_MODE_ENCRYPT: libc::c_int = 1;
|
||||
const CIPHER_MODE_DECRYPT: libc::c_int = 0;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[link(name="crypto")]
|
||||
extern {
|
||||
fn EVP_get_cipherbyname(name: *const libc::c_char) -> EVP_CIPHER;
|
||||
fn EVP_CIPHER_CTX_new() -> EVP_CIPHER_CTX;
|
||||
fn EVP_CIPHER_CTX_cleanup(ctx: EVP_CIPHER_CTX);
|
||||
fn EVP_CIPHER_CTX_free(ctx: EVP_CIPHER_CTX);
|
||||
|
||||
fn EVP_CipherInit(ctx: EVP_CIPHER_CTX, evp: EVP_CIPHER,
|
||||
key: *const libc::c_uchar, iv: *const libc::c_uchar, mode: libc::c_int) -> libc::c_int;
|
||||
fn EVP_CipherUpdate(ctx: EVP_CIPHER_CTX,
|
||||
outbuf: *mut libc::c_uchar, outlen: *mut libc::c_int,
|
||||
inbuf: *const libc::c_uchar, inlen: libc::c_int) -> libc::c_int;
|
||||
fn EVP_CipherFinal(ctx: EVP_CIPHER_CTX, res: *mut libc::c_uchar, len: *mut libc::c_int) -> libc::c_int;
|
||||
|
||||
fn EVP_BytesToKey(cipher: EVP_CIPHER, md: EVP_MD,
|
||||
salt: *const libc::c_uchar, data: *const libc::c_uchar, datal: libc::c_int,
|
||||
count: libc::c_int, key: *mut libc::c_uchar, iv: *mut libc::c_uchar) -> libc::c_int;
|
||||
|
||||
// Ciphers
|
||||
fn EVP_aes_128_cfb128() -> EVP_CIPHER;
|
||||
fn EVP_aes_192_cfb() -> EVP_CIPHER;
|
||||
fn EVP_aes_256_cfb() -> EVP_CIPHER;
|
||||
|
||||
// MD
|
||||
fn EVP_md5() -> EVP_MD;
|
||||
fn EVP_sha() -> EVP_MD;
|
||||
fn EVP_sha1() -> EVP_MD;
|
||||
|
||||
// Errors
|
||||
fn ERR_print_errors_fp(fp: libc::c_int);
|
||||
}
|
||||
|
||||
enum CryptoMode {
|
||||
CryptoModeDecrypt,
|
||||
CryptoModeEncrypt,
|
||||
}
|
||||
|
||||
enum CipherType {
|
||||
CipherTypeAes128Cfb,
|
||||
CipherTypeAes192Cfb,
|
||||
CipherTypeAes256Cfb,
|
||||
}
|
||||
|
||||
struct OpenSSLCrypto {
|
||||
evp_ctx: EVP_CIPHER_CTX,
|
||||
block_size: uint,
|
||||
// key_size: uint,
|
||||
}
|
||||
|
||||
impl OpenSSLCrypto {
|
||||
pub fn new(cipher_type: CipherType, key: &[u8], mode: CryptoMode) -> OpenSSLCrypto {
|
||||
let (ctx, _, block_size) = unsafe {
|
||||
let (cipher, key_size, block_size) = match cipher_type {
|
||||
CipherTypeAes128Cfb => (EVP_aes_128_cfb128(), 16, 16),
|
||||
CipherTypeAes192Cfb => (EVP_aes_192_cfb() , 24, 16),
|
||||
CipherTypeAes256Cfb => (EVP_aes_256_cfb() , 32, 16),
|
||||
};
|
||||
|
||||
let evp_ctx = EVP_CIPHER_CTX_new();
|
||||
|
||||
let mut pad_key: Vec<u8> = Vec::with_capacity(key_size);
|
||||
let mut pad_iv: Vec<u8> = Vec::with_capacity(block_size);
|
||||
|
||||
EVP_BytesToKey(cipher, EVP_md5(), ptr::null(), key.as_ptr(), key.len() as libc::c_int,
|
||||
1, pad_key.as_mut_ptr(), pad_iv.as_mut_ptr());
|
||||
|
||||
let op = match mode {
|
||||
CryptoModeEncrypt => 1 as libc::c_int,
|
||||
CryptoModeDecrypt => 0 as libc::c_int,
|
||||
};
|
||||
|
||||
if EVP_CipherInit(evp_ctx, cipher, pad_key.as_slice().as_ptr(),
|
||||
pad_iv.as_slice().as_ptr(), op) != 1 as libc::c_int {
|
||||
EVP_CIPHER_CTX_free(evp_ctx);
|
||||
fail!("EVP_CipherInit error");
|
||||
}
|
||||
|
||||
(evp_ctx, key_size, block_size)
|
||||
};
|
||||
|
||||
OpenSSLCrypto {
|
||||
evp_ctx: ctx,
|
||||
block_size: block_size,
|
||||
// key_size: key_size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cipher(&self, data: &[u8]) -> Vec<u8> {
|
||||
unsafe {
|
||||
let pdata: *const u8 = data.as_ptr();
|
||||
let datalen: libc::c_int = data.len() as libc::c_int;
|
||||
|
||||
let reslen: uint = datalen as uint + self.block_size;
|
||||
let mut res = Vec::from_elem(reslen, 0u8);
|
||||
|
||||
let mut len: libc::c_int = 0;
|
||||
let pres: *mut u8 = res.as_mut_ptr();
|
||||
|
||||
if EVP_CipherUpdate(self.evp_ctx,
|
||||
pres, &mut len,
|
||||
pdata, datalen) != 1 {
|
||||
drop(self);
|
||||
fail!("Failed on EVP_CipherUpdate");
|
||||
}
|
||||
|
||||
let mut total_length = len;
|
||||
if EVP_CipherFinal(self.evp_ctx, pres.offset(len as int), &mut len) != 1 {
|
||||
drop(self);
|
||||
fail!("Failed on EVP_CipherFinal");
|
||||
}
|
||||
|
||||
total_length += len;
|
||||
|
||||
res.truncate(total_length as uint);
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl Drop for OpenSSLCrypto {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
EVP_CIPHER_CTX_cleanup(self.evp_ctx);
|
||||
EVP_CIPHER_CTX_free(self.evp_ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct OpenSSLCipher {
|
||||
encryptor: OpenSSLCrypto,
|
||||
decryptor: OpenSSLCrypto,
|
||||
}
|
||||
|
||||
impl OpenSSLCipher {
|
||||
pub fn new(cipher_type: CipherType, key: &[u8]) -> OpenSSLCipher {
|
||||
let enc = OpenSSLCrypto::new(cipher_type, key, CryptoModeEncrypt);
|
||||
let dec = OpenSSLCrypto::new(cipher_type, key, CryptoModeDecrypt);
|
||||
|
||||
OpenSSLCipher {
|
||||
encryptor: enc,
|
||||
decryptor: dec,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Cipher for OpenSSLCipher {
|
||||
fn encrypt(&self, data: &[u8]) -> Vec<u8> {
|
||||
self.encryptor.cipher(data)
|
||||
}
|
||||
|
||||
fn decrypt(&self, data: &[u8]) -> Vec<u8> {
|
||||
self.decryptor.cipher(data)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_aes() {
|
||||
let message = "hello world";
|
||||
let key = "passwordhaha";
|
||||
|
||||
let types = [CipherTypeAes128Cfb, CipherTypeAes192Cfb, CipherTypeAes256Cfb];
|
||||
|
||||
for t in types.iter() {
|
||||
let cipher = OpenSSLCipher::new(*t, key.as_bytes());
|
||||
|
||||
let encrypted_msg = cipher.encrypt(message.as_bytes());
|
||||
debug!("ENC {}", encrypted_msg);
|
||||
|
||||
let decrypted_msg = cipher.decrypt(encrypted_msg.as_slice());
|
||||
debug!("DEC {}", str::from_utf8(decrypted_msg.as_slice()).unwrap());
|
||||
|
||||
assert!(message == str::from_utf8(decrypted_msg.as_slice()).unwrap());
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#![crate_type="lib"]
|
||||
#![crate_name="shadowsocks"]
|
||||
#![feature(phase)]
|
||||
#![feature(phase, unsafe_destructor)]
|
||||
|
||||
extern crate serialize;
|
||||
#[phase(plugin, link)]
|
||||
@@ -12,4 +12,4 @@ pub mod config;
|
||||
pub mod relay;
|
||||
pub mod tcprelay;
|
||||
pub mod udprelay;
|
||||
pub mod crypto;
|
||||
mod crypto;
|
||||
|
||||
10
src/relay.rs
10
src/relay.rs
@@ -11,3 +11,13 @@ pub enum Stage {
|
||||
StageReply,
|
||||
StageStream,
|
||||
}
|
||||
|
||||
pub const SOCK5_VERSION : u8 = 5;
|
||||
|
||||
pub const SOCK5_CMD_TCP_CONNECT : u8 = 1;
|
||||
pub const SOCK5_CMD_TCP_BIND : u8 = 2;
|
||||
pub const SOCK5_CMD_UDP_ASSOCIATE : u8 = 3;
|
||||
|
||||
pub const SOCK5_ADDR_MODE_IPV4 : u8 = 0x01;
|
||||
pub const SOCK5_ADDR_MODE_DOMAIN_NAME : u8 = 0x03;
|
||||
pub const SOCK5_ADDR_MODE_IPV6 : u8 = 0x04;
|
||||
|
||||
149
src/tcprelay.rs
149
src/tcprelay.rs
@@ -4,28 +4,121 @@ extern crate log;
|
||||
use relay::Relay;
|
||||
use relay::Stage;
|
||||
use relay::{StageInit, StageHello, StageUdpAssoc, StageDns, StageReply, StageStream};
|
||||
use relay;
|
||||
|
||||
// mod config;
|
||||
use config::Config;
|
||||
|
||||
use std::io::TcpListener;
|
||||
use std::io::{TcpListener};
|
||||
use std::io::{Acceptor, Listener};
|
||||
use std::io::net::tcp::TcpAcceptor;
|
||||
use std::io::net::tcp::{TcpAcceptor, TcpStream};
|
||||
use std::io::{TimedOut, EndOfFile};
|
||||
|
||||
use std::str;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct TcpRelayLocal {
|
||||
acceptor: TcpAcceptor,
|
||||
stage: Stage,
|
||||
config: Config,
|
||||
}
|
||||
|
||||
impl TcpRelayLocal {
|
||||
pub fn new(c: &Config) -> TcpRelayLocal {
|
||||
let acceptor = TcpListener::bind(c.local.as_slice(), c.local_port).unwrap().listen().unwrap();
|
||||
|
||||
TcpRelayLocal {
|
||||
acceptor: acceptor,
|
||||
stage: StageInit,
|
||||
config: c.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_hello(remote_stream: &mut TcpStream) {
|
||||
let buf = [relay::SOCK5_VERSION, 1, 1];
|
||||
debug!("Sent {} to server", buf.to_vec());
|
||||
remote_stream.write(buf);
|
||||
|
||||
let reply = remote_stream.read_exact(2).unwrap();
|
||||
|
||||
debug!("Recv {} from server", reply);
|
||||
|
||||
if reply[0] != relay::SOCK5_VERSION {
|
||||
fail!("Invalid sock5 version")
|
||||
}
|
||||
|
||||
let method_num = reply[1];
|
||||
|
||||
if method_num == 0xff {
|
||||
fail!("Server does not support the encrypt method");
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_auth(remote_stream: &mut TcpStream) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
impl Relay for TcpRelayLocal {
|
||||
fn run(&mut self) {
|
||||
let server_str_arc = Arc::new(self.config.server.clone());
|
||||
let server_port_arc = Arc::new(self.config.server_port.clone());
|
||||
let encrypt_password = Arc::new(self.config.password.clone());
|
||||
|
||||
loop {
|
||||
let server_str = server_str_arc.clone();
|
||||
let server_port = server_port_arc.clone();
|
||||
|
||||
match self.acceptor.accept() {
|
||||
Ok(mut stream) => spawn(proc() {
|
||||
info!("Client {} connected", stream.peer_name().unwrap());
|
||||
|
||||
let server = server_str.as_slice();
|
||||
|
||||
let mut remote_stream = TcpStream::connect(server, *server_port.deref()).unwrap();
|
||||
TcpRelayLocal::handle_hello(&mut remote_stream);
|
||||
TcpRelayLocal::handle_auth(&mut remote_stream);
|
||||
|
||||
loop {
|
||||
let mut buf = [0u8, .. 10240];
|
||||
match stream.read(buf) {
|
||||
Ok(len) => {
|
||||
let s = buf.slice_to(len);
|
||||
|
||||
remote_stream.write(s);
|
||||
},
|
||||
Err(err) => {
|
||||
if err.kind == EndOfFile {
|
||||
break
|
||||
}
|
||||
error!("Err: {}", err);
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info!("Client {} disconnected", stream.peer_name().unwrap());
|
||||
|
||||
drop(stream)
|
||||
}),
|
||||
Err(e) => {
|
||||
fail!(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TcpRelayServer {
|
||||
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();
|
||||
impl TcpRelayServer {
|
||||
pub fn new(c: &Config) -> TcpRelayServer {
|
||||
let acceptor = TcpListener::bind(c.server.as_slice(), c.server_port).unwrap().listen().unwrap();
|
||||
|
||||
TcpRelayLocal {
|
||||
TcpRelayServer {
|
||||
acceptor: acceptor,
|
||||
stage: StageInit,
|
||||
timeout: c.timeout,
|
||||
@@ -36,16 +129,16 @@ impl TcpRelayLocal {
|
||||
loop {
|
||||
match self.acceptor.accept() {
|
||||
Ok(mut stream) => spawn(proc() {
|
||||
info!("Client {} connected", stream.socket_name().unwrap());
|
||||
info!("Client {} connected", stream.peer_name().unwrap());
|
||||
|
||||
TcpRelayServer::handle_hello(&mut stream);
|
||||
|
||||
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());
|
||||
debug!("{} Received: {}", stream.peer_name().unwrap(), s);
|
||||
stream.write(s).unwrap()
|
||||
},
|
||||
Err(err) => {
|
||||
@@ -58,7 +151,7 @@ impl TcpRelayLocal {
|
||||
}
|
||||
}
|
||||
|
||||
info!("Client {} disconnected", stream.socket_name().unwrap());
|
||||
info!("Client {} disconnected", stream.peer_name().unwrap());
|
||||
|
||||
drop(stream)
|
||||
}),
|
||||
@@ -68,19 +161,31 @@ impl TcpRelayLocal {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_hello(stream: &mut TcpStream) {
|
||||
let first_two_bytes = stream.read_exact(2).unwrap();
|
||||
|
||||
if first_two_bytes[0] != relay::SOCK5_VERSION {
|
||||
fail!("Invalid sock5 version");
|
||||
} else if first_two_bytes[1] == 0 {
|
||||
fail!("Invalid sock5 method number");
|
||||
}
|
||||
|
||||
let methods = stream.read_exact(first_two_bytes[1] as uint);
|
||||
|
||||
for m in methods.iter() {
|
||||
// Choose
|
||||
}
|
||||
|
||||
let chosen_method = 1u8;
|
||||
|
||||
let buf = [relay::SOCK5_VERSION, chosen_method];
|
||||
stream.write(buf);
|
||||
}
|
||||
}
|
||||
|
||||
impl Relay for TcpRelayLocal {
|
||||
impl Relay for TcpRelayServer {
|
||||
fn run(&mut self) {
|
||||
self.accept_loop()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TcpRelayServer;
|
||||
|
||||
impl TcpRelayServer {
|
||||
pub fn new() -> TcpRelayServer {
|
||||
TcpRelayServer
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user