├── .gitignore ├── .rustfmt.toml ├── .travis.yml ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── README.md ├── appveyor.yml ├── build.sh ├── src ├── asyncdns.rs ├── bin │ └── main.rs ├── collections │ ├── holder.rs │ └── mod.rs ├── config │ ├── cmd.rs │ ├── mod.rs │ ├── proxy_config.rs │ ├── running_config.rs │ └── toml.rs ├── crypto │ ├── cipher.rs │ ├── crypto_lib.rs │ ├── encryptor.rs │ ├── error.rs │ ├── methods.rs │ ├── mod.rs │ └── openssl_lib.rs ├── error.rs ├── lib.rs ├── mode │ └── mod.rs ├── my_daemonize.rs ├── my_logger.rs ├── network.rs ├── relay │ ├── mod.rs │ ├── tcp_processor.rs │ ├── tcp_relay.rs │ ├── udp_processor.rs │ └── udp_relay.rs ├── socks5.rs └── util.rs └── tests ├── base_test.py ├── config ├── rs_local.toml ├── rs_local_ota.toml ├── rs_server.toml ├── ss.json └── ss_ota.json ├── config_tests.py ├── echo_server.py ├── encrypt.rs ├── test.sh ├── test_tcp.py └── test_udp.py /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | *.log 3 | *.pid 4 | .#* 5 | *.bk 6 | .cargo 7 | run.sh 8 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | fn_empty_single_line = false 2 | closure_block_indent_threshould = 0 3 | format_strings = false 4 | use_try_shorthand = true 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | - nightly 6 | 7 | os: 8 | - linux 9 | - osx 10 | 11 | matrix: 12 | allow_failures: 13 | - rust: beta 14 | - rust: nightly 15 | 16 | sudo: false 17 | cache: 18 | - cargo 19 | - pip 20 | before_script: 21 | - pip install --user nose PySocks shadowsocks 22 | - export PATH=$HOME/.local/bin:$HOME/.cargo/bin:$HOME/Library/Python/2.7/bin/:$PATH 23 | script: 24 | - cargo test 25 | - bash tests/test.sh 26 | after_failure: 27 | - cat /tmp/ssc.log 28 | - cat /tmp/sss.log 29 | 30 | notifications: 31 | email: 32 | on_failure: change 33 | on_success: change 34 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "shadowsocks" 3 | version = "0.6.2" 4 | authors = ["loggerhead "] 5 | license = "GPL-3.0" 6 | repository = "https://github.com/loggerhead/shadowsocks-rust" 7 | homepage = "https://github.com/loggerhead/shadowsocks-rust" 8 | description = """ 9 | My implemention of shadowsocks 10 | """ 11 | readme = "README.md" 12 | 13 | [[bin]] 14 | name = "sslocal" 15 | path = "src/bin/main.rs" 16 | required-features = ["sslocal"] 17 | 18 | [[bin]] 19 | name = "ssserver" 20 | path = "src/bin/main.rs" 21 | 22 | [dependencies] 23 | mio = "0.5" 24 | slog = { version = "~1.7", features = ["max_level_trace", "release_max_level_trace"] } 25 | slog-term = "~1.3" 26 | slog-stream = "~1.2" 27 | slog-scope = "0.2" 28 | fnv = "~1.0" 29 | clap = "~2.18" 30 | rand = "0.3" 31 | toml = "0.1" 32 | regex = "0.1" 33 | chrono = "0.2" 34 | try_opt = "0.1" 35 | byteorder = "0.5" 36 | lazy_static = "0.2" 37 | lru_time_cache = "0.5" 38 | rust-crypto = "0.2" 39 | rustc-serialize = "0.3" 40 | openssl = { version = "0.9", optional = true } 41 | clippy = { version = ">= 0.0.95", optional = true } 42 | 43 | [features] 44 | sslocal = [] 45 | disable-encrypt = [] 46 | 47 | [target.'cfg(unix)'.dependencies] 48 | sig = "~1.0.0" 49 | daemonize = "0.2" 50 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM scorpil/rust:stable 2 | ADD . . 3 | RUN cargo build --release \ 4 | && mv ./target/release/ssserver /usr/bin/ssserver 5 | 6 | ENTRYPOINT ["/usr/bin/ssserver"] 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # shadowsocks-rust 2 | [![Build Status](https://travis-ci.org/loggerhead/shadowsocks-rust.svg?branch=master)](https://travis-ci.org/loggerhead/shadowsocks-rust) 3 | [![Build status](https://ci.appveyor.com/api/projects/status/ti4hi7era48ltxq4?svg=true)](https://ci.appveyor.com/project/loggerhead/shadowsocks-rust) 4 | [![crate](https://img.shields.io/crates/v/shadowsocks.svg)](https://crates.io/crates/shadowsocks) 5 | 6 | A [rust](https://www.rust-lang.org) port of shadowsocks, based on [mio 0.5.x](https://crates.io/crates/mio). 7 | 8 | # Install 9 | ## Cargo 10 | 11 | ```bash 12 | cargo install shadowsocks 13 | ``` 14 | 15 | ## Script 16 | 17 | ```bash 18 | # uncomment to compile with OpenSSL support 19 | # export SS_FEATURES=openssl 20 | curl https://raw.githubusercontent.com/loggerhead/shadowsocks-rust/master/build.sh -sSf | sh 21 | ./sslocal --version 22 | ./ssserver --version 23 | ``` 24 | 25 | # Compare to Python Version 26 | ## Features 27 | 28 | | | Rust | Python (2.9.0) | 29 | | --------------------------- | :----------------: | :----------------------: | 30 | | TCP & UDP support | __√__ | __√__ | 31 | | TCP fast open | wait `mio` support | __√__ | 32 | | Destination IP blacklist | __X__ | __√__ | 33 | | One time auth | __√__ | __√__ | 34 | | Multiple encryption methods | __√__ | __√__ | 35 | | Async UDP support | __√__ | __X__ | 36 | | IPv6 support | untested | __√__ | 37 | | Windows compatible         |     buggy     | need install crypto libs | 38 | | Multiple servers support | __√__ | __X__ | 39 | 40 | # Encryption Methods 41 | ## Both python and rust version supported 42 | 43 | * aes-128-ctr 44 | * aes-192-ctr 45 | * aes-256-ctr 46 | * aes-128-cfb 47 | * aes-256-cfb 48 | * aes-128-cfb1 49 | * aes-256-cfb1 50 | * aes-128-cfb8 51 | * aes-256-cfb8 52 | * salsa20 53 | * chacha20 54 | * rc4 55 | 56 | ## Without OpenSSL 57 | * aes-128-ctr 58 | * aes-192-ctr 59 | * aes-256-ctr 60 | * rc4 61 | * hc128 62 | * salsa20 63 | * xsalsa20 64 | * chacha20 65 | * xchacha20 66 | * sosemanuk 67 | 68 | # TBD 69 | - [ ] test IPv6 70 | - [ ] fix very slow problem on windows (wait `mio` stable) 71 | - [ ] support TCP fast open 72 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | build: false 2 | 3 | environment: 4 | PYTHON: "C:\\Python27" 5 | PYTHON_VERSION: "2.7.12" 6 | PYTHON_ARCH: "32" 7 | 8 | matrix: 9 | - TARGET: x86_64-pc-windows-msvc 10 | 11 | install: 12 | - curl -sSf -o rustup-init.exe https://win.rustup.rs/ 13 | - rustup-init.exe -y --default-host %TARGET% 14 | - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin;%PYTHON%/Scripts/ 15 | - rustc -V 16 | - cargo -V 17 | - pip install nose PySocks 18 | 19 | test_script: 20 | - cargo test 21 | - cargo run --bin ssserver -- -h 22 | # - ps: mv target\debug\shadowsocks.exe ssserver.exe 23 | - cargo run --bin sslocal --features="sslocal" -- -h 24 | # - ps: mv target\debug\shadowsocks.exe sslocal.exe 25 | # - ssserver.exe -h 26 | # - sslocal.exe -h 27 | # - ps: Start-Process ssserver.exe -ArgumentList '-c tests\config\server_conf.toml --log-file ssserver.log' 28 | # - ps: Start-Process sslocal.exe -ArgumentList '-c tests\config\local_conf.toml --log-file sslocal.log' 29 | # - ps: Start-Process python -ArgumentList 'tests\echo_server.py' 30 | # - nosetests tests\test_tcp.py 31 | # - nosetests tests\test_udp.py 32 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | curl https://sh.rustup.rs -sSf | sh 3 | . $HOME/.cargo/env 4 | git clone https://github.com/loggerhead/shadowsocks-rust.git && cd shadowsocks-rust/ 5 | cargo build --release --features "$SS_FEATURES" && mv target/release/ssserver ../ssserver 6 | cargo build --release --features "sslocal $SS_FEATURES" && mv target/release/ssserver ../sslocal 7 | cd .. 8 | ./ssserver --version 9 | ./sslocal --version 10 | -------------------------------------------------------------------------------- /src/asyncdns.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::env; 3 | use std::convert::From; 4 | use std::str::FromStr; 5 | use std::io::Cursor; 6 | use std::net::{ToSocketAddrs, SocketAddr}; 7 | use std::path::PathBuf; 8 | use std::time::Duration; 9 | 10 | use rand; 11 | use lru_time_cache::LruCache; 12 | use mio::udp::UdpSocket; 13 | use mio::{Token, EventSet, EventLoop, PollOpt}; 14 | 15 | use error::{Result, SocketError}; 16 | use relay::Relay; 17 | use collections::{Set, Dict}; 18 | use network::{NetworkWriteBytes, NetworkReadBytes}; 19 | use network::{is_ipv4, is_ipv6, is_ip, is_hostname, slice2ip4, slice2ip6, pair2addr}; 20 | use util::{RcCell, handle_every_line, slice2string}; 21 | 22 | // All communications inside of the domain protocol are carried in a single 23 | // format called a message. The top level format of message is divided 24 | // into 5 sections (some of which are empty in certain cases) shown below: 25 | // 26 | // +---------------------+ 27 | // | Header | 28 | // +---------------------+ 29 | // | Question | the question for the name server 30 | // +---------------------+ 31 | // | Answer | RRs answering the question 32 | // +---------------------+ 33 | // | Authority | RRs pointing toward an authority 34 | // +---------------------+ 35 | // | Additional | RRs holding additional information 36 | // +---------------------+ 37 | // 38 | // The header section is always present. The header includes fields that 39 | // specify which of the remaining sections are present, and also specify 40 | // whether the message is a query or a response, a standard query or some 41 | // other opcode, etc. 42 | 43 | // The header section format: 44 | // 45 | // 1 1 1 1 1 1 46 | // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 47 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 48 | // | ID | 49 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 50 | // |QR| Opcode |AA|TC|RD|RA| Z | RCODE | 51 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 52 | // | QDCOUNT | 53 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 54 | // | ANCOUNT | 55 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 56 | // | NSCOUNT | 57 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 58 | // | ARCOUNT | 59 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 60 | #[derive(PartialEq, Eq, Hash, Clone, Debug)] 61 | pub struct HostIpPair(pub String, pub String); 62 | struct ResponseRecord(String, String, u16, u16); 63 | struct ResponseHeader(u16, u16, u16, u16, u16, u16, u16, u16, u16); 64 | 65 | const BUF_SIZE: usize = 1024; 66 | 67 | pub enum Error { 68 | Timeout, 69 | BufferEmpty, 70 | EmptyHostName, 71 | InvalidResponse, 72 | BuildRequestFailed, 73 | NoPreferredResponse, 74 | InvalidHost(String), 75 | UnknownHost(String), 76 | } 77 | 78 | impl fmt::Debug for Error { 79 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 80 | match *self { 81 | Error::Timeout => write!(f, "timeout"), 82 | Error::BufferEmpty => write!(f, "no buffered data available"), 83 | Error::EmptyHostName => write!(f, "empty hostname"), 84 | Error::InvalidResponse => write!(f, "invalid response"), 85 | Error::BuildRequestFailed => write!(f, "build dns request failed"), 86 | Error::NoPreferredResponse => write!(f, "no preferred response"), 87 | Error::InvalidHost(ref host) => write!(f, "invalid host {}", host), 88 | Error::UnknownHost(ref host) => write!(f, "unknown host {}", host), 89 | } 90 | } 91 | } 92 | 93 | pub trait Caller { 94 | fn get_id(&self) -> Token; 95 | fn handle_dns_resolved(&mut self, 96 | event_loop: &mut EventLoop, 97 | res: Result>); 98 | } 99 | 100 | struct DnsResponse { 101 | hostname: String, 102 | questions: Vec<(String, u16, u16)>, 103 | answers: Vec<(String, u16, u16)>, 104 | } 105 | 106 | impl fmt::Debug for DnsResponse { 107 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 108 | write!(f, "{}: {:?}", self.hostname, self.answers) 109 | } 110 | } 111 | 112 | impl DnsResponse { 113 | fn new() -> DnsResponse { 114 | DnsResponse { 115 | hostname: String::new(), 116 | questions: Vec::new(), 117 | answers: Vec::new(), 118 | } 119 | } 120 | } 121 | 122 | 123 | #[derive(Debug, Clone, Copy)] 124 | enum HostnameStatus { 125 | First, 126 | Second, 127 | } 128 | 129 | pub struct DnsResolver { 130 | prefer_ipv6: bool, 131 | token: Token, 132 | hosts: Dict, 133 | cache: LruCache, 134 | callers: Dict>, 135 | hostname_status: Dict, 136 | token_to_hostname: Dict, 137 | hostname_to_tokens: Dict>, 138 | sock: UdpSocket, 139 | servers: Vec, 140 | qtypes: Vec, 141 | receive_buf: Option>, 142 | } 143 | 144 | impl DnsResolver { 145 | pub fn new(token: Token, 146 | server_list: Option>, 147 | prefer_ipv6: bool) 148 | -> Result { 149 | // pre-define DNS server list 150 | let servers = match server_list { 151 | Some(servers) => servers, 152 | None => parse_resolv(prefer_ipv6), 153 | }; 154 | let (qtypes, addr) = if prefer_ipv6 { 155 | (vec![QType::AAAA, QType::A], "[::]:0") 156 | } else { 157 | (vec![QType::A, QType::AAAA], "0.0.0.0:0") 158 | }; 159 | let addr = SocketAddr::from_str(addr).map_err(|_| SocketError::InitSocketFailed)?; 160 | let sock = UdpSocket::bound(&addr).map_err(|_| SocketError::InitSocketFailed)?; 161 | let hosts = parse_hosts(prefer_ipv6); 162 | let cache_timeout = Duration::new(600, 0); 163 | 164 | Ok(DnsResolver { 165 | prefer_ipv6: prefer_ipv6, 166 | token: token, 167 | servers: servers, 168 | hosts: hosts, 169 | cache: LruCache::with_expiry_duration(cache_timeout), 170 | callers: Dict::default(), 171 | hostname_status: Dict::default(), 172 | token_to_hostname: Dict::default(), 173 | hostname_to_tokens: Dict::default(), 174 | sock: sock, 175 | qtypes: qtypes, 176 | receive_buf: Some(Vec::with_capacity(BUF_SIZE)), 177 | }) 178 | } 179 | 180 | pub fn add_caller(&mut self, caller: RcCell) { 181 | let token = caller.borrow().get_id(); 182 | self.callers.insert(token, caller); 183 | } 184 | 185 | pub fn remove_caller(&mut self, token: Token) -> bool { 186 | if let Some(hostname) = self.token_to_hostname.remove(&token) { 187 | self.hostname_to_tokens.get_mut(&hostname).map(|tokens| tokens.remove(&token)); 188 | if self.hostname_to_tokens.get(&hostname).unwrap().is_empty() { 189 | self.hostname_to_tokens.remove(&hostname); 190 | self.hostname_status.remove(&hostname); 191 | } 192 | } 193 | 194 | self.callers.remove(&token).is_some() 195 | } 196 | 197 | fn send_request(&self, hostname: String, qtype: u16) -> Result<()> { 198 | debug!("send dns query of {}", &hostname); 199 | for server in &self.servers { 200 | let addr = pair2addr(server, 53)?; 201 | let req = build_request(&hostname, qtype).ok_or(Error::BuildRequestFailed)?; 202 | self.sock.send_to(&req, &addr)?; 203 | } 204 | Ok(()) 205 | } 206 | 207 | fn receive_data_into_buf(&mut self) -> Result<()> { 208 | let mut res = Ok(()); 209 | let mut buf = self.receive_buf.take().unwrap(); 210 | 211 | new_fat_slice_from_vec!(buf_slice, buf); 212 | match self.sock.recv_from(buf_slice) { 213 | Ok(None) => {} 214 | Ok(Some((nread, _addr))) => unsafe { 215 | buf.set_len(nread); 216 | }, 217 | Err(e) => res = err_from!(e), 218 | } 219 | self.receive_buf = Some(buf); 220 | res 221 | } 222 | 223 | fn local_resolve(&mut self, hostname: &String) -> Result> { 224 | if hostname.is_empty() { 225 | err_from!(Error::EmptyHostName) 226 | } else if is_ip(hostname) { 227 | Ok(Some(HostIpPair(hostname.to_string(), hostname.to_string()))) 228 | } else if self.hosts.contains_key(hostname) { 229 | let ip = self.hosts[hostname].clone(); 230 | Ok(Some(HostIpPair(hostname.to_string(), ip))) 231 | } else if self.cache.contains_key(hostname) { 232 | let ip = self.cache.get_mut(hostname).unwrap(); 233 | Ok(Some(HostIpPair(hostname.to_string(), ip.clone()))) 234 | } else if !is_hostname(hostname) { 235 | err_from!(Error::InvalidHost(hostname.clone())) 236 | } else { 237 | Ok(None) 238 | } 239 | } 240 | 241 | pub fn block_resolve(&mut self, hostname: String) -> Result> { 242 | match self.local_resolve(&hostname) { 243 | Ok(None) => { 244 | let mut addr_v4 = None; 245 | let mut addr_v6 = None; 246 | 247 | for addr in (hostname.as_str(), 0).to_socket_addrs()? { 248 | match addr { 249 | SocketAddr::V4(addr) => { 250 | if addr_v4.is_none() { 251 | addr_v4 = Some(addr); 252 | } 253 | } 254 | SocketAddr::V6(addr) => { 255 | if addr_v6.is_none() { 256 | addr_v6 = Some(addr); 257 | } 258 | } 259 | } 260 | 261 | if self.prefer_ipv6 && addr_v6.is_some() { 262 | return Ok(Some(HostIpPair(hostname.to_string(), 263 | addr_v6.unwrap().ip().to_string()))); 264 | } 265 | if !self.prefer_ipv6 && addr_v4.is_some() { 266 | return Ok(Some(HostIpPair(hostname.to_string(), 267 | addr_v4.unwrap().ip().to_string()))); 268 | } 269 | } 270 | 271 | Ok(None) 272 | } 273 | res => res, 274 | } 275 | } 276 | 277 | // TODO: change to `&str` (wait `lru_time_cache` release the new version) 278 | pub fn resolve(&mut self, token: Token, hostname: String) -> Result> { 279 | match self.local_resolve(&hostname) { 280 | Ok(None) => { 281 | // if this is the first time that any caller query the hostname 282 | if !self.hostname_to_tokens.contains_key(&hostname) { 283 | self.hostname_status.insert(hostname.clone(), HostnameStatus::First); 284 | self.hostname_to_tokens.insert(hostname.clone(), Set::default()); 285 | } 286 | self.hostname_to_tokens.get_mut(&hostname).unwrap().insert(token); 287 | self.token_to_hostname.insert(token, hostname.clone()); 288 | 289 | self.send_request(hostname, self.qtypes[0])?; 290 | Ok(None) 291 | } 292 | res => res, 293 | } 294 | } 295 | 296 | fn call_callback(&mut self, event_loop: &mut EventLoop, hostname: String, ip: String) { 297 | self.hostname_status.remove(&hostname); 298 | if let Some(tokens) = self.hostname_to_tokens.remove(&hostname) { 299 | for token in &tokens { 300 | self.token_to_hostname.remove(token); 301 | 302 | let caller = self.callers.get_mut(token).unwrap(); 303 | if ip.is_empty() { 304 | caller.borrow_mut() 305 | .handle_dns_resolved(event_loop, 306 | err_from!(Error::UnknownHost(hostname.clone()))); 307 | } else { 308 | let hostname_ip = HostIpPair(hostname.clone(), ip.clone()); 309 | caller.borrow_mut().handle_dns_resolved(event_loop, Ok(Some(hostname_ip))); 310 | } 311 | } 312 | } 313 | } 314 | 315 | fn handle_recevied(&mut self) -> Result> { 316 | let mut res = err_from!(Error::BufferEmpty); 317 | let receive_buf = self.receive_buf.take().unwrap(); 318 | if receive_buf.is_empty() { 319 | return res; 320 | } 321 | 322 | if let Some(response) = parse_response(&receive_buf) { 323 | let mut ip = String::new(); 324 | for answer in &response.answers { 325 | if (answer.1 == QType::A || answer.1 == QType::AAAA) && answer.2 == QClass::IN { 326 | ip = answer.0.clone(); 327 | break; 328 | } 329 | } 330 | 331 | let hostname = response.hostname; 332 | let hostname_status = match self.hostname_status.get(&hostname) { 333 | Some(&HostnameStatus::First) => 1, 334 | Some(&HostnameStatus::Second) => 2, 335 | _ => 0, 336 | }; 337 | 338 | if ip.is_empty() && hostname_status == 1 { 339 | self.hostname_status.insert(hostname.clone(), HostnameStatus::Second); 340 | self.send_request(hostname, self.qtypes[1])?; 341 | res = Ok(None); 342 | } else if !ip.is_empty() { 343 | self.cache.insert(hostname.clone(), ip.clone()); 344 | res = Ok(Some(HostIpPair(hostname, ip))); 345 | } else if hostname_status == 2 { 346 | res = err_from!(Error::NoPreferredResponse); 347 | 348 | for question in response.questions { 349 | if question.1 == self.qtypes[1] { 350 | ip.clear(); 351 | res = Ok(Some(HostIpPair(hostname, ip))); 352 | break; 353 | } 354 | } 355 | } 356 | } else { 357 | res = err_from!(Error::InvalidResponse); 358 | } 359 | 360 | self.receive_buf = Some(receive_buf); 361 | res 362 | } 363 | 364 | fn do_register(&mut self, 365 | event_loop: &mut EventLoop, 366 | is_reregister: bool) 367 | -> Result<()> { 368 | let events = EventSet::readable(); 369 | let pollopts = PollOpt::edge() | PollOpt::oneshot(); 370 | 371 | if is_reregister { 372 | event_loop.reregister(&self.sock, self.token, events, pollopts) 373 | .map_err(From::from) 374 | } else { 375 | event_loop.register(&self.sock, self.token, events, pollopts).map_err(From::from) 376 | } 377 | } 378 | 379 | pub fn register(&mut self, event_loop: &mut EventLoop) -> Result<()> { 380 | self.do_register(event_loop, false) 381 | } 382 | 383 | fn reregister(&mut self, event_loop: &mut EventLoop) -> Result<()> { 384 | self.do_register(event_loop, true) 385 | } 386 | 387 | pub fn handle_events(&mut self, 388 | event_loop: &mut EventLoop, 389 | events: EventSet) 390 | -> Result<()> { 391 | if events.is_error() { 392 | error!("events error on DNS socket"); 393 | let _ = event_loop.deregister(&self.sock); 394 | self.register(event_loop)?; 395 | 396 | for caller in self.callers.values() { 397 | caller.borrow_mut() 398 | .handle_dns_resolved(event_loop, err_from!(SocketError::EventError)); 399 | } 400 | 401 | self.callers.clear(); 402 | self.hostname_status.clear(); 403 | self.token_to_hostname.clear(); 404 | self.hostname_to_tokens.clear(); 405 | err_from!(SocketError::EventError) 406 | } else { 407 | self.receive_data_into_buf()?; 408 | if let Ok(Some(HostIpPair(hostname, ip))) = self.handle_recevied() { 409 | self.call_callback(event_loop, hostname, ip); 410 | } 411 | self.reregister(event_loop) 412 | } 413 | } 414 | } 415 | 416 | // For detail, see page 7 of RFC 1035 417 | fn build_address(address: &str) -> Option> { 418 | let mut v = vec![]; 419 | let bytes = address.as_bytes(); 420 | for label in bytes.split(|ch| *ch == b'.') { 421 | match label.len() { 422 | 0 => continue, 423 | n if n > 63 => return None, 424 | n => { 425 | v.push(n as u8); 426 | v.extend_from_slice(label); 427 | } 428 | } 429 | } 430 | 431 | v.push(0); 432 | Some(v) 433 | } 434 | 435 | // For detail, see page 24 of RFC 1035 436 | fn build_request(address: &str, qtype: u16) -> Option> { 437 | let mut r = vec![]; 438 | // The header section: 439 | // 440 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 441 | // | random request_id | 442 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 443 | // | 0| 0 | 0| 0| 1| 0| 0 | 0 | 444 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 445 | // | 1 | 446 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 447 | // | 0 | 448 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 449 | // | 0 | 450 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 451 | // | 0 | 452 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 453 | let request_id = rand::random::(); 454 | 455 | pack!(u16, r, request_id); 456 | pack!(u8, r, 1); 457 | pack!(u8, r, 0); 458 | pack!(u16, r, 1); 459 | pack!(u16, r, 0); 460 | pack!(u16, r, 0); 461 | pack!(u16, r, 0); 462 | // address 463 | let addr = try_opt!(build_address(address)); 464 | r.extend(addr); 465 | // qtype and qclass 466 | pack!(u16, r, qtype); 467 | pack!(u16, r, QClass::IN); 468 | 469 | Some(r) 470 | } 471 | 472 | // RDATA: a variable length string of octets that describes the resource. 473 | // The format of this information varies according to the TYPE and CLASS 474 | // of the resource record. For example, the if the TYPE is A 475 | // and the CLASS is IN, the RDATA field is a 4 octet ARPA Internet address. 476 | fn parse_ip(addrtype: u16, data: &[u8], length: usize, offset: usize) -> Option { 477 | let ip_part = &data[offset..offset + length]; 478 | 479 | match addrtype { 480 | QType::A => slice2ip4(ip_part), 481 | QType::AAAA => slice2ip6(ip_part), 482 | QType::CNAME | QType::NS => Some(try_opt!(parse_name(data, offset as u16)).1), 483 | _ => slice2string(ip_part), 484 | } 485 | } 486 | 487 | // For detail, see page 29 of RFC 1035 488 | fn parse_name(data: &[u8], offset: u16) -> Option<(u16, String)> { 489 | let mut p = offset as usize; 490 | let mut l = data[p]; 491 | let mut labels: Vec = Vec::new(); 492 | 493 | while l > 0 { 494 | // if compressed 495 | if (l & 0b11000000) == 0b11000000 { 496 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 497 | // | 1 1| OFFSET | 498 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 499 | let mut tmp = Cursor::new(&data[p..p + 2]); 500 | let mut ptr = unpack!(u16, tmp); 501 | ptr &= 0x3FFF; 502 | let r = try_opt!(parse_name(data, ptr)); 503 | labels.push(r.1); 504 | p += 2; 505 | return Some((p as u16 - offset, labels.join("."))); 506 | } else { 507 | labels.push(try_opt!(slice2string(&data[(p + 1)..(p + 1 + l as usize)]))); 508 | p += 1 + l as usize; 509 | } 510 | 511 | l = data[p]; 512 | } 513 | 514 | Some((p as u16 + 1 - offset, labels.join("."))) 515 | } 516 | 517 | // For detail, see page 27, 28 of RFC 1035 518 | fn parse_record(data: &[u8], offset: u16, question: bool) -> Option<(u16, ResponseRecord)> { 519 | let (nlen, name) = try_opt!(parse_name(data, offset)); 520 | 521 | // The question section format: 522 | // 523 | // 1 1 1 1 1 1 524 | // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 525 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 526 | // | | 527 | // / QNAME / 528 | // / / 529 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 530 | // | QTYPE | 531 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 532 | // | QCLASS | 533 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 534 | if question { 535 | let bytes = &data[(offset + nlen) as usize..(offset + nlen + 4) as usize]; 536 | let mut record = Cursor::new(bytes); 537 | 538 | let record_type = unpack!(u16, record); 539 | let record_class = unpack!(u16, record); 540 | 541 | Some((nlen + 4, ResponseRecord(name, String::new(), record_type, record_class))) 542 | // 1 1 1 1 1 1 543 | // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 544 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 545 | // | | 546 | // / / 547 | // / NAME / 548 | // | | 549 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 550 | // | TYPE | 551 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 552 | // | CLASS | 553 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 554 | // | TTL | 555 | // | | 556 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 557 | // | RDLENGTH | 558 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| 559 | // / RDATA / 560 | // / / 561 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 562 | } else { 563 | let bytes = &data[(offset + nlen) as usize..(offset + nlen + 10) as usize]; 564 | let mut record = Cursor::new(bytes); 565 | 566 | let record_type = unpack!(u16, record); 567 | let record_class = unpack!(u16, record); 568 | let _record_ttl = unpack!(u32, record); 569 | let record_rdlength = unpack!(u16, record); 570 | 571 | // RDATA 572 | let ip = try_opt!(parse_ip(record_type, 573 | data, 574 | record_rdlength as usize, 575 | (offset + nlen + 10) as usize)); 576 | 577 | Some((nlen + 10 + record_rdlength, ResponseRecord(name, ip, record_type, record_class))) 578 | } 579 | } 580 | 581 | fn parse_header(data: &[u8]) -> Option { 582 | if data.len() < 12 { 583 | return None; 584 | } 585 | 586 | let mut header = Cursor::new(data); 587 | 588 | let id = unpack!(u16, header); 589 | let byte3 = unpack!(u8, header); 590 | let byte4 = unpack!(u8, header); 591 | let qdcount = unpack!(u16, header); 592 | let ancount = unpack!(u16, header); 593 | let nscount = unpack!(u16, header); 594 | let arcount = unpack!(u16, header); 595 | let qr = (byte3 & 0b10000000) as u16; 596 | let tc = (byte3 & 0b00000010) as u16; 597 | let ra = (byte4 & 0b00000010) as u16; 598 | let rcode = (byte4 & 0b00001111) as u16; 599 | 600 | Some(ResponseHeader(id, qr, tc, ra, rcode, qdcount, ancount, nscount, arcount)) 601 | } 602 | 603 | fn parse_records(data: &[u8], 604 | offset: u16, 605 | count: u16, 606 | question: bool) 607 | -> Option<(u16, Vec)> { 608 | let mut records: Vec = Vec::new(); 609 | let mut offset = offset; 610 | 611 | for _i in 0..count { 612 | let (len, record) = try_opt!(parse_record(data, offset, question)); 613 | offset += len; 614 | records.push(record); 615 | } 616 | 617 | Some((offset, records)) 618 | } 619 | 620 | fn parse_response(data: &[u8]) -> Option { 621 | if data.len() < 12 { 622 | return None; 623 | } 624 | 625 | parse_header(data).and_then(|header| { 626 | let ResponseHeader(_id, _qr, _tc, _ra, _rcode, qdcount, ancount, _nscount, _arcount) = 627 | header; 628 | 629 | let offset = 12u16; 630 | let (offset, qds) = try_opt!(parse_records(data, offset, qdcount, true)); 631 | let (_offset, ans) = try_opt!(parse_records(data, offset, ancount, false)); 632 | // We don't need to parse the authority records and the additional records 633 | let (_offset, _nss) = try_opt!(parse_records(data, _offset, _nscount, false)); 634 | let (_offset, _ars) = try_opt!(parse_records(data, _offset, _arcount, false)); 635 | 636 | let mut response = DnsResponse::new(); 637 | if !qds.is_empty() { 638 | response.hostname = qds[0].0.clone(); 639 | } 640 | for an in qds { 641 | response.questions.push((an.1, an.2, an.3)) 642 | } 643 | for an in ans { 644 | response.answers.push((an.1, an.2, an.3)) 645 | } 646 | 647 | Some(response) 648 | }) 649 | } 650 | 651 | fn parse_resolv(prefer_ipv6: bool) -> Vec { 652 | let mut servers = vec![]; 653 | 654 | let _ = handle_every_line("/etc/resolv.conf", 655 | &mut |line| { 656 | if line.starts_with("nameserver") { 657 | if let Some(ip) = line.split_whitespace().nth(1) { 658 | if (prefer_ipv6 && is_ipv6(ip)) || (!prefer_ipv6 && is_ipv4(ip)) { 659 | servers.push(ip.to_string()); 660 | } 661 | } 662 | } 663 | }); 664 | 665 | if servers.is_empty() { 666 | let dns_servers = if cfg!(feature = "sslocal") { 667 | vec!["114.114.114.114", "114.114.115.115"] 668 | } else { 669 | if prefer_ipv6 { 670 | vec!["2001:4860:4860::8888", "2001:4860:4860::8844"] 671 | } else { 672 | vec!["8.8.8.8", "8.8.4.4"] 673 | } 674 | }; 675 | 676 | servers = dns_servers.into_iter().map(|s| s.to_string()).collect(); 677 | } 678 | 679 | servers 680 | } 681 | 682 | 683 | fn parse_hosts(prefer_ipv6: bool) -> Dict { 684 | let mut hosts = Dict::default(); 685 | if prefer_ipv6 { 686 | hosts.insert("localhost".to_string(), "::1".to_string()); 687 | } else { 688 | hosts.insert("localhost".to_string(), "127.0.0.1".to_string()); 689 | } 690 | 691 | let hosts_path = if cfg!(target_family = "UNIX") { 692 | PathBuf::from("/etc/hosts") 693 | } else { 694 | let mut path = match env::var("WINDIR") { 695 | Ok(dir) => PathBuf::from(dir), 696 | _ => return hosts, 697 | }; 698 | path.push("/system32/drivers/etc/hosts"); 699 | path 700 | }; 701 | 702 | let _ = handle_every_line(&hosts_path, 703 | &mut |line| { 704 | let parts: Vec<&str> = line.split_whitespace().collect(); 705 | if !parts.is_empty() { 706 | let ip = parts[0]; 707 | if (prefer_ipv6 && is_ipv6(ip)) || (!prefer_ipv6 && is_ipv4(ip)) { 708 | for hostname in parts[1..].iter() { 709 | if !hostname.is_empty() { 710 | hosts.insert(hostname.to_string(), ip.to_string()); 711 | } 712 | } 713 | } 714 | } 715 | }); 716 | 717 | hosts 718 | } 719 | 720 | #[allow(dead_code, non_snake_case)] 721 | mod QType { 722 | pub const A: u16 = 1; 723 | pub const AAAA: u16 = 28; 724 | pub const CNAME: u16 = 5; 725 | pub const NS: u16 = 2; 726 | pub const ANY: u16 = 255; 727 | } 728 | 729 | #[allow(dead_code, non_snake_case)] 730 | mod QClass { 731 | pub const IN: u16 = 1; 732 | } 733 | 734 | 735 | #[cfg(test)] 736 | mod test { 737 | use mio::Token; 738 | 739 | use asyncdns; 740 | 741 | const IPV4_TESTS: [(&'static str, &'static str); 3] = [("8.8.8.8", "8.8.8.8"), 742 | ("localhost", "127.0.0.1"), 743 | ("localhost.loggerhead.me", 744 | "127.0.0.1")]; 745 | 746 | const IPV6_TESTS: [(&'static str, &'static str); 3] = [("2001:4860:4860::8888", 747 | "2001:4860:4860::8888"), 748 | ("localhost", "::1"), 749 | ("localhost.loggerhead.me", "::1")]; 750 | 751 | #[test] 752 | #[cfg_attr(rustfmt, rustfmt_skip)] 753 | fn parse_response() { 754 | let data: &[u8] = 755 | &[0x0d, 0x0d, 0x81, 0x80, 0x00, 0x01, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x05, 0x62, 756 | 0x61, 0x69, 0x64, 0x75, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 757 | 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x04, 0xb4, 0x95, 0x84, 758 | 0x2f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x04, 0xdc, 759 | 0xb5, 0x39, 0xd9, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 760 | 0x04, 0x6f, 0x0d, 0x65, 0xd0, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 761 | 0x36, 0x00, 0x04, 0x7b, 0x7d, 0x72, 0x90, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 762 | 0x01, 0x4f, 0x30, 0x00, 0x06, 0x03, 0x64, 0x6e, 0x73, 0xc0, 0x0c, 0xc0, 0x0c, 0x00, 763 | 0x02, 0x00, 0x01, 0x00, 0x01, 0x4f, 0x30, 0x00, 0x06, 0x03, 0x6e, 0x73, 0x37, 0xc0, 764 | 0x0c, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x4f, 0x30, 0x00, 0x06, 0x03, 765 | 0x6e, 0x73, 0x33, 0xc0, 0x0c, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x4f, 766 | 0x30, 0x00, 0x06, 0x03, 0x6e, 0x73, 0x34, 0xc0, 0x0c, 0xc0, 0x0c, 0x00, 0x02, 0x00, 767 | 0x01, 0x00, 0x01, 0x4f, 0x30, 0x00, 0x06, 0x03, 0x6e, 0x73, 0x32, 0xc0, 0x0c]; 768 | 769 | assert!(asyncdns::parse_response(data).is_some()); 770 | } 771 | 772 | fn test_block_resolve(ipv6: bool) { 773 | let tests = if ipv6 { IPV6_TESTS } else { IPV4_TESTS }; 774 | let mut resolver = asyncdns::DnsResolver::new(Token(0), None, ipv6).unwrap(); 775 | for &(hostname, ip) in &tests { 776 | match resolver.block_resolve(hostname.to_string()) { 777 | Ok(r) => { 778 | assert!(r.is_some()); 779 | let asyncdns::HostIpPair(_hostname, resolved_ip) = r.unwrap(); 780 | assert!(resolved_ip == ip); 781 | } 782 | Err(e) => { 783 | println!("block_resolve failed: {:?}", e); 784 | assert!(false); 785 | } 786 | } 787 | } 788 | } 789 | 790 | #[test] 791 | fn ipv4_block_resolve() { 792 | test_block_resolve(false); 793 | } 794 | 795 | // this test may failed if your computer is not a ipv6 host 796 | #[test] 797 | #[ignore] 798 | fn ipv6_block_resolve() { 799 | test_block_resolve(true); 800 | } 801 | } 802 | -------------------------------------------------------------------------------- /src/bin/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use(slog_log, slog_error)] 2 | extern crate slog; 3 | #[macro_use(error)] 4 | extern crate slog_scope; 5 | extern crate shadowsocks; 6 | 7 | use std::process::exit; 8 | use std::thread::spawn; 9 | 10 | use shadowsocks::my_logger; 11 | use shadowsocks::my_daemonize; 12 | use shadowsocks::config::CONFIG; 13 | use shadowsocks::relay::{TcpRelay, UdpRelay}; 14 | 15 | fn main() { 16 | my_daemonize::init(CONFIG.daemon, &CONFIG.pid_file); 17 | let _ = my_logger::init(CONFIG.log_level, CONFIG.log_file.as_ref()).map_err(|e| { 18 | println!("init logger failed: {}", e); 19 | exit(1); 20 | }); 21 | 22 | let childs = vec![spawn(|| { 23 | TcpRelay::new() 24 | .and_then(|r| r.run()) 25 | .unwrap_or_else(|e| error!("{:?}", e)) 26 | }), 27 | spawn(|| { 28 | UdpRelay::new() 29 | .and_then(|r| r.run()) 30 | .unwrap_or_else(|e| error!("{:?}", e)) 31 | })]; 32 | 33 | for child in childs { 34 | let _ = child.join(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/collections/holder.rs: -------------------------------------------------------------------------------- 1 | use std::iter::FromIterator; 2 | use std::ops::{Index, IndexMut}; 3 | 4 | use mio::Token; 5 | use rand::random; 6 | 7 | use super::Set; 8 | use super::Dict; 9 | 10 | const MAX_RAND_RETRY_TIMES: usize = 1000; 11 | 12 | pub struct Holder { 13 | items: Dict, 14 | exclusions: Set, 15 | } 16 | 17 | impl Holder { 18 | pub fn new() -> Holder { 19 | Holder { 20 | items: Dict::default(), 21 | exclusions: Set::default(), 22 | } 23 | } 24 | 25 | pub fn new_exclude_from(exclusions: Vec) -> Holder { 26 | Holder { 27 | items: Dict::default(), 28 | exclusions: Set::from_iter(exclusions), 29 | } 30 | } 31 | 32 | pub fn alloc_token(&mut self) -> Option { 33 | let mut i = 0; 34 | let mut token = Token(random::()); 35 | while self.exclusions.contains(&token) { 36 | token = Token(random::()); 37 | 38 | i += 1; 39 | if i > MAX_RAND_RETRY_TIMES { 40 | return None; 41 | } 42 | } 43 | self.exclusions.insert(token); 44 | Some(token) 45 | } 46 | 47 | pub fn contains(&self, token: Token) -> bool { 48 | self.items.contains_key(&token) 49 | } 50 | 51 | pub fn get(&self, token: Token) -> Option<&T> { 52 | self.items.get(&token) 53 | } 54 | 55 | pub fn get_mut(&mut self, token: Token) -> Option<&mut T> { 56 | self.items.get_mut(&token) 57 | } 58 | 59 | pub fn insert(&mut self, v: T) -> Option { 60 | let token = try_opt!(self.alloc_token()); 61 | self.items.insert(token, v); 62 | Some(token) 63 | } 64 | 65 | pub fn insert_with(&mut self, token: Token, v: T) { 66 | self.exclusions.insert(token); 67 | self.items.insert(token, v); 68 | } 69 | 70 | pub fn remove(&mut self, token: Token) -> Option { 71 | self.exclusions.remove(&token); 72 | self.items.remove(&token) 73 | } 74 | 75 | pub fn len(&self) -> usize { 76 | self.items.len() 77 | } 78 | 79 | pub fn is_empty(&self) -> bool { 80 | self.len() == 0 81 | } 82 | } 83 | 84 | impl Index for Holder { 85 | type Output = T; 86 | 87 | fn index(&self, index: Token) -> &T { 88 | match self.get(index) { 89 | Some(v) => v, 90 | _ => panic!("invalid index: {:?}", index), 91 | } 92 | } 93 | } 94 | 95 | impl IndexMut for Holder { 96 | fn index_mut(&mut self, index: Token) -> &mut T { 97 | match self.get_mut(index) { 98 | Some(v) => v, 99 | _ => panic!("invalid index: {:?}", index), 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/collections/mod.rs: -------------------------------------------------------------------------------- 1 | pub use self::holder::Holder; 2 | 3 | mod holder; 4 | 5 | use std::hash::BuildHasherDefault; 6 | use std::collections::{HashSet, HashMap}; 7 | 8 | use fnv::FnvHasher; 9 | 10 | pub type Set = HashSet>; 11 | pub type Dict = HashMap>; 12 | -------------------------------------------------------------------------------- /src/config/cmd.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use clap::{Arg, App, ArgMatches}; 4 | 5 | use super::{ConfigError, ConfigResult, ProxyConfig, Config}; 6 | 7 | // TODO: change to use macro when https://github.com/kbknapp/clap-rs/pull/731 decided 8 | pub fn parse_cmds<'a>() -> ArgMatches<'a> { 9 | lazy_static! { 10 | static ref CONFIG_HELP: String = format!("path to config file\n[default: {}]", 11 | Config::default_config_path().display()); 12 | static ref NAME: &'static str = if cfg!(feature = "sslocal") { 13 | "sslocal" 14 | } else { 15 | "ssserver" 16 | }; 17 | } 18 | 19 | let mut args = App::new(NAME.to_string()) 20 | .version("0.6.1") 21 | .arg(Arg::with_name("input") 22 | .help("parse config from base64 encoded input") 23 | .takes_value(true)) 24 | .arg(Arg::with_name("config") 25 | .short("c") 26 | .long("config") 27 | .value_name("file") 28 | .help(CONFIG_HELP.as_str()) 29 | .takes_value(true)) 30 | .arg(Arg::with_name("password") 31 | .short("k") 32 | .long("password") 33 | .value_name("str") 34 | .help("password") 35 | .takes_value(true)) 36 | .arg(Arg::with_name("method") 37 | .short("m") 38 | .long("method") 39 | .value_name("str") 40 | .help("encryption method")) 41 | .arg(Arg::with_name("timeout") 42 | .short("t") 43 | .long("timeout") 44 | .value_name("int") 45 | .help("timeout in seconds [default: 60]")) 46 | .arg(Arg::with_name("verbose") 47 | .short("v") 48 | .long("verbose") 49 | .multiple(true) 50 | .help("sets the level of verbosity")) 51 | .arg(Arg::with_name("quiet") 52 | .short("q") 53 | .long("quiet") 54 | .multiple(true) 55 | .help("quiet mode, only show warnings/errors")) 56 | .arg(Arg::with_name("log_file") 57 | .long("log-file") 58 | .value_name("file") 59 | .help("log file for daemon mode") 60 | .takes_value(true)) 61 | .arg(Arg::with_name("address") 62 | .short("a") 63 | .long("address") 64 | .value_name("str") 65 | .help("binding address")) 66 | .arg(Arg::with_name("port") 67 | .short("p") 68 | .long("port") 69 | .value_name("int") 70 | .help("bind port")) 71 | .arg(Arg::with_name("one_time_auth") 72 | .short("o") 73 | .long("one-time-auth") 74 | .help("enable one time auth")) 75 | .arg(Arg::with_name("prefer_ipv6") 76 | .long("prefer-ipv6") 77 | .help("priority use IPv6")); 78 | 79 | if cfg!(target_family = "unix") { 80 | args = args.arg(Arg::with_name("daemon") 81 | .short("d") 82 | .long("daemon") 83 | .help("daemon mode") 84 | .value_name("str") 85 | .takes_value(true) 86 | .possible_values(&["start", "stop", "restart", "none"])) 87 | .arg(Arg::with_name("pid_file") 88 | .long("pid-file") 89 | .value_name("file") 90 | .help("pid file for daemon mode") 91 | .takes_value(true)); 92 | } 93 | 94 | if cfg!(feature = "sslocal") { 95 | args = args.arg(Arg::with_name("server") 96 | .short("s") 97 | .long("server") 98 | .value_name("ip:port") 99 | .help("server address and port") 100 | .takes_value(true)) 101 | .arg(Arg::with_name("mode") 102 | .long("mode") 103 | .takes_value(true) 104 | .value_name("str") 105 | .help("the way to choose server") 106 | .possible_values(&["fast", "balance"])) 107 | .arg(Arg::with_name("add_server") 108 | .long("add-server") 109 | .value_name("str") 110 | .takes_value(true) 111 | .help("append base64 encoded server config")); 112 | } 113 | 114 | args.get_matches() 115 | } 116 | 117 | pub fn check_and_set_from_args(args: &ArgMatches, conf: &mut Config) -> ConfigResult<()> { 118 | macro_rules! try_set { 119 | ($set:ident, $name:expr, str) => { 120 | try_set!($set, args.value_of($name)) 121 | }; 122 | ($set:ident, $name:expr, bool) => { 123 | try_set!($set, Some(args.is_present($name))) 124 | }; 125 | ($set:ident, $name:expr, int) => {{ 126 | if let Some(v) = args.value_of($name) { 127 | match v.parse::() { 128 | Ok(v) => try_set!($set, Some(v)), 129 | Err(_) => return Err(ConfigError::InvalidNumber(v.to_string())), 130 | } 131 | } 132 | }}; 133 | ($set:ident, $name:expr, occurrences) => { 134 | try_set!($set, Some(args.occurrences_of($name) as i64)) 135 | }; 136 | ($set:ident, $val:expr) => { conf.$set($val)?; }; 137 | } 138 | 139 | try_set!(set_quiet, "quiet", occurrences); 140 | try_set!(set_verbose, "verbose", occurrences); 141 | try_set!(set_log_file, "log_file", str); 142 | try_set!(set_pid_file, "pid_file", str); 143 | try_set!(set_prefer_ipv6, "prefer_ipv6", bool); 144 | try_set!(set_daemon, "daemon", str); 145 | try_set!(set_mode, "mode", str); 146 | 147 | try_set!(set_address, "address", str); 148 | try_set!(set_port, "port", int); 149 | try_set!(set_method, "method", str); 150 | try_set!(set_password, "password", str); 151 | try_set!(set_timeout, "timeout", int); 152 | try_set!(set_one_time_auth, "one_time_auth", bool); 153 | 154 | Ok(()) 155 | } 156 | 157 | // `server` present in command line will override `servers`. 158 | pub fn check_and_set_server_from_args(args: &ArgMatches, conf: &mut Config) -> ConfigResult<()> { 159 | let password = args.value_of("password").ok_or(ConfigError::MissServerPassword)?; 160 | let method = args.value_of("method").ok_or(ConfigError::MissServerMethod)?; 161 | 162 | let server_address = args.value_of("server").unwrap(); 163 | let mut port_addr: Vec<&str> = server_address.rsplitn(2, ':').collect(); 164 | if port_addr.len() == 2 { 165 | let addr = port_addr.pop().unwrap(); 166 | let port = port_addr.pop().unwrap(); 167 | let port = port.parse::().map_err(|_| ConfigError::InvalidNumber(port.to_string()))?; 168 | 169 | let mut server_conf = ProxyConfig::default(); 170 | server_conf.set_address(Some(addr))?; 171 | server_conf.set_port(Some(port))?; 172 | 173 | server_conf.set_method(Some(method))?; 174 | server_conf.set_password(Some(password))?; 175 | server_conf.set_one_time_auth(Some(args.is_present("one_time_auth")))?; 176 | 177 | if let Some(t) = args.value_of("timeout") { 178 | let t = t.parse::().map_err(|_| ConfigError::InvalidNumber(t.to_string()))?; 179 | server_conf.set_timeout(Some(t))?; 180 | } 181 | 182 | conf.server_confs = Some(vec![Arc::new(server_conf)]); 183 | Ok(()) 184 | } else { 185 | Err(ConfigError::InvalidAddress(server_address.to_string())) 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/config/mod.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::sync::Arc; 3 | use std::net::{TcpStream, ToSocketAddrs}; 4 | use std::io::prelude::*; 5 | use std::process::{exit, Command}; 6 | use std::path::PathBuf; 7 | 8 | use my_daemonize; 9 | 10 | #[macro_use] 11 | mod toml; 12 | mod cmd; 13 | mod proxy_config; 14 | mod running_config; 15 | 16 | use self::cmd::{parse_cmds, check_and_set_from_args, check_and_set_server_from_args}; 17 | use self::toml::{read_config, save_if_not_exists, append_to_default_config, 18 | check_and_set_from_toml, check_and_set_servers_from_toml}; 19 | 20 | pub use self::proxy_config::ProxyConfig; 21 | pub use self::running_config::RunningConfig as Config; 22 | 23 | lazy_static! { 24 | pub static ref CONFIG: Config = init_config().unwrap_or_else(|e| { 25 | println!("{:?}", e); 26 | exit(1); 27 | }); 28 | } 29 | 30 | pub type ConfigResult = Result; 31 | 32 | pub enum ConfigError { 33 | MissServerMethod, 34 | MissServerPassword, 35 | MissServerAddress, 36 | MissServerPort, 37 | OpenFileFailed(String), 38 | ParseConfigFailed(String), 39 | InvalidMode(String), 40 | InvalidMethod(String), 41 | InvalidNumber(String), 42 | InvalidAddress(String), 43 | OutOfRange(i64), 44 | Other(String), 45 | } 46 | 47 | impl fmt::Debug for ConfigError { 48 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 49 | match *self { 50 | ConfigError::MissServerMethod => write!(f, "server method is missing"), 51 | ConfigError::MissServerPassword => write!(f, "server password is missing"), 52 | ConfigError::MissServerAddress => write!(f, "server address is missing"), 53 | ConfigError::MissServerPort => write!(f, "server port is missing"), 54 | ConfigError::OpenFileFailed(ref desc) => write!(f, "open config file failed: {}", desc), 55 | ConfigError::ParseConfigFailed(ref desc) => { 56 | write!(f, "parse config file error: {}", desc) 57 | } 58 | ConfigError::InvalidMode(ref desc) => write!(f, "invalid mode: {}", desc), 59 | ConfigError::InvalidMethod(ref desc) => { 60 | write!(f, "invalid encryption method: {}", desc) 61 | } 62 | ConfigError::InvalidNumber(ref desc) => write!(f, "invalid number: {}", desc), 63 | ConfigError::InvalidAddress(ref desc) => write!(f, "invalid address: {}", desc), 64 | ConfigError::OutOfRange(n) => write!(f, "{} is out of range", n), 65 | ConfigError::Other(ref desc) => write!(f, "{}", desc), 66 | } 67 | } 68 | } 69 | 70 | /// The working config follows a few rules: 71 | /// 1. Command line is prior to config file. 72 | /// 2. If no arguments provide, then read from default config file. 73 | /// 3. If default config file doesn't exists, then randomly generated one and save it. 74 | pub fn init_config() -> Result { 75 | let mut conf = Config::default(); 76 | let default_config_path = Config::default_config_path(); 77 | let args = parse_cmds(); 78 | 79 | if cfg!(feature = "sslocal") { 80 | if let Some(server_conf) = args.value_of("add_server") { 81 | let mut tmp = Arc::make_mut(&mut conf.proxy_conf); 82 | tmp.base64_decode(server_conf)?; 83 | append_to_default_config(tmp); 84 | exit(0); 85 | } 86 | // TODO: share sslocal server according mode 87 | if args.is_present("share_server") { 88 | exit(0); 89 | } 90 | } else { 91 | // TODO: share ssserver server (check 0.0.0.0 & 127.0.0.1) 92 | if args.is_present("share_server") { 93 | exit(0); 94 | } 95 | } 96 | 97 | // setup from input and save it if no default config 98 | if let Some(input) = args.value_of("input") { 99 | let mut proxy_conf = ProxyConfig::default(); 100 | proxy_conf.base64_decode(input)?; 101 | let proxy_conf = Arc::new(proxy_conf); 102 | if cfg!(feature = "sslocal") { 103 | conf.server_confs = Some(vec![proxy_conf]); 104 | } else { 105 | conf.proxy_conf = proxy_conf; 106 | } 107 | check_and_set_from_args(&args, &mut conf)?; 108 | save_if_not_exists(&conf); 109 | // setup from command line 110 | } else if args.value_of("server").is_some() { 111 | check_and_set_from_args(&args, &mut conf)?; 112 | check_and_set_server_from_args(&args, &mut conf)?; 113 | // setup from config file 114 | } else if args.value_of("config").is_some() || default_config_path.exists() { 115 | let config_path = match args.value_of("config") { 116 | Some(path) => PathBuf::from(path), 117 | None => default_config_path, 118 | }; 119 | let tbl = read_config(&config_path)?; 120 | check_and_set_from_toml(&tbl, &mut conf)?; 121 | check_and_set_from_args(&args, &mut conf)?; 122 | // setup `server` or `servers` 123 | if conf.daemon != my_daemonize::Cmd::Stop { 124 | if cfg!(feature = "sslocal") { 125 | check_and_set_servers_from_toml(&tbl, &mut conf)?; 126 | println!("start sslocal with {}", config_path.display()); 127 | } else { 128 | println!("start ssserver with {}", config_path.display()); 129 | } 130 | } 131 | // create config if no args 132 | } else if !cfg!(feature = "sslocal") && args.args.is_empty() { 133 | { 134 | // set `address` to external ip 135 | let mut tmp = Arc::make_mut(&mut conf.proxy_conf); 136 | let ip = get_external_ip()?; 137 | tmp.set_address(Some(ip.as_str()))?; 138 | } 139 | println!("{}", conf.proxy_conf.base64_encode()); 140 | save_if_not_exists(&conf); 141 | } else { 142 | check_and_set_from_args(&args, &mut conf)?; 143 | } 144 | 145 | if (conf.daemon == my_daemonize::Cmd::Start || conf.daemon == my_daemonize::Cmd::Restart) && 146 | conf.log_file.is_none() { 147 | conf.log_file = Some(Config::default_log_path()); 148 | } 149 | 150 | if cfg!(feature = "sslocal") && conf.server_confs.is_none() && 151 | conf.daemon != my_daemonize::Cmd::Stop { 152 | return Err(ConfigError::MissServerAddress); 153 | } 154 | 155 | Ok(conf) 156 | } 157 | 158 | fn get_external_ip() -> ConfigResult { 159 | const HOST_PATHS: &'static [(&'static str, &'static str)] = &[("ident.me", "/"), 160 | ("icanhazip.com", "/")]; 161 | let mut external_ip = None; 162 | 163 | for host_path in HOST_PATHS { 164 | let ip = echo_ip(host_path.0, host_path.1); 165 | if ip.is_some() { 166 | external_ip = ip; 167 | break; 168 | } 169 | } 170 | 171 | match external_ip { 172 | Some(ip) => { 173 | if check_ip(&ip) { 174 | Ok(ip) 175 | } else { 176 | Err(ConfigError::Other("no external ip available".to_string())) 177 | } 178 | } 179 | None => Err(ConfigError::Other("cannot get external ip".to_string())), 180 | } 181 | } 182 | 183 | fn echo_ip(host: &str, path: &str) -> Option { 184 | let addr = try_opt!((host, 80).to_socket_addrs().ok().and_then(|mut addrs| addrs.next())); 185 | let mut conn = try_opt!(TcpStream::connect(addr).ok()); 186 | let r = format!("GET {} HTTP/1.1\r\nHost: {}\r\n\r\n", path, host); 187 | try_opt!(conn.write_all(r.as_bytes()).ok()); 188 | let mut s = String::new(); 189 | try_opt!(conn.read_to_string(&mut s).ok()); 190 | 191 | // handle HTTP chunks 192 | let mut lines: Vec<&str> = s.trim().lines().collect(); 193 | let mut ip = lines.pop(); 194 | if ip == Some("0") { 195 | ip = lines.pop().map(|l| l.trim()); 196 | } 197 | ip.map(|s| s.to_string()) 198 | } 199 | 200 | fn get_all_ips() -> Option { 201 | let cmd = if cfg!(windows) { 202 | "ipconfig" 203 | } else { 204 | "ifconfig" 205 | }; 206 | 207 | let output = try_opt!(Command::new(cmd).output().ok()); 208 | String::from_utf8(output.stdout).ok() 209 | } 210 | 211 | fn check_ip(ip: &str) -> bool { 212 | if let Some(ips) = get_all_ips() { 213 | ips.find(ip).is_some() 214 | } else { 215 | false 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/config/proxy_config.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use rand::{Rng, thread_rng}; 4 | use rustc_serialize::base64::{ToBase64, FromBase64, STANDARD}; 5 | 6 | use crypto::Method; 7 | use util::slice2str; 8 | use network::{is_ip, is_hostname}; 9 | use super::{ConfigError, ConfigResult}; 10 | 11 | #[derive(PartialEq, Eq, Hash, Clone)] 12 | pub struct ProxyConfig { 13 | pub address: String, 14 | pub port: u16, 15 | pub method: Method, 16 | pub password: String, 17 | pub timeout: u16, 18 | pub one_time_auth: bool, 19 | } 20 | 21 | impl fmt::Display for ProxyConfig { 22 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 23 | write!(f, 24 | "address = \"{}\"\n\ 25 | port = {}\n\ 26 | method = \"{}\"\n\ 27 | password = \"{}\"\n\ 28 | timeout = {}\n\ 29 | one_time_auth = {}", 30 | self.address, 31 | self.port, 32 | self.method, 33 | self.password, 34 | self.timeout, 35 | self.one_time_auth) 36 | } 37 | } 38 | 39 | impl fmt::Debug for ProxyConfig { 40 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 41 | fmt::Display::fmt(self, f) 42 | } 43 | } 44 | 45 | impl Default for ProxyConfig { 46 | fn default() -> Self { 47 | let mut rng = thread_rng(); 48 | let address = String::from(if cfg!(feature = "sslocal") { 49 | "127.0.0.1" 50 | } else { 51 | "0.0.0.0" 52 | }); 53 | 54 | let port = if cfg!(feature = "sslocal") { 55 | 1080 56 | } else { 57 | rng.gen::() 58 | }; 59 | 60 | let method = rng.choose(&Method::all()).cloned().or(Some(Method::aes_256_ctr)).unwrap(); 61 | let password = rng.gen_ascii_chars().take(4).collect(); 62 | let timeout = 60; 63 | let one_time_auth = false; 64 | 65 | ProxyConfig { 66 | address: address, 67 | port: port, 68 | method: method, 69 | password: password, 70 | timeout: timeout, 71 | one_time_auth: one_time_auth, 72 | } 73 | } 74 | } 75 | 76 | impl ProxyConfig { 77 | pub fn base64_encode(&self) -> String { 78 | // aes-256-ctr:foo@example.com:8888 79 | let encoded = format!("{}:{}@{}:{}", 80 | self.method, 81 | self.password, 82 | self.address, 83 | self.port); 84 | format!("ss://{}", encoded.as_bytes().to_base64(STANDARD)) 85 | } 86 | 87 | pub fn base64_decode(&mut self, s: &str) -> ConfigResult<()> { 88 | if s.starts_with("ss://") { 89 | let s = &s[5..].from_base64() 90 | .map_err(|_| ConfigError::Other(format!("decode config failed: {}", s)))?; 91 | let s = 92 | slice2str(s).ok_or(ConfigError::Other("decode config failed: invalid UTF-8 chars" 93 | .to_string()))?; 94 | 95 | let parts: Vec<&str> = s.rsplitn(2, '@').collect(); 96 | let port_address: Vec<&str> = parts[0].rsplitn(2, ':').collect(); 97 | let method_password: Vec<&str> = parts[1].splitn(2, ':').collect(); 98 | 99 | self.method = method_password[0].parse::() 100 | .map_err(|_| ConfigError::InvalidMethod(method_password[0].to_string()))?; 101 | self.password = method_password[1].to_string(); 102 | self.address = port_address[1].to_string(); 103 | self.port = port_address[0].parse::() 104 | .map_err(|_| ConfigError::InvalidNumber(port_address[0].to_string()))?; 105 | Ok(()) 106 | } else { 107 | Err(ConfigError::Other(format!("decode config failed: {}", s))) 108 | } 109 | } 110 | 111 | pub fn set_address(&mut self, val: Option<&str>) -> ConfigResult<()> { 112 | if let Some(v) = val { 113 | if !(is_ip(v) || is_hostname(v)) { 114 | return Err(ConfigError::InvalidAddress(v.to_string())); 115 | } else { 116 | self.address = v.to_string(); 117 | } 118 | } 119 | Ok(()) 120 | } 121 | 122 | pub fn set_port(&mut self, val: Option) -> ConfigResult<()> { 123 | if let Some(v) = val { 124 | if v < 0 || (u16::max_value() as i64) < v { 125 | return Err(ConfigError::OutOfRange(v)); 126 | } else { 127 | self.port = v as u16; 128 | } 129 | } 130 | Ok(()) 131 | } 132 | 133 | pub fn set_method(&mut self, val: Option<&str>) -> ConfigResult<()> { 134 | if let Some(v) = val { 135 | let method = v.parse::() 136 | .map_err(|_| ConfigError::InvalidMethod(v.to_string()))?; 137 | self.method = method; 138 | } 139 | Ok(()) 140 | } 141 | 142 | pub fn set_password(&mut self, val: Option<&str>) -> ConfigResult<()> { 143 | if let Some(v) = val { 144 | self.password = v.to_string(); 145 | } 146 | Ok(()) 147 | } 148 | 149 | pub fn set_timeout(&mut self, val: Option) -> ConfigResult<()> { 150 | if let Some(v) = val { 151 | if v < 0 { 152 | return Err(ConfigError::OutOfRange(v)); 153 | } else { 154 | self.timeout = v as u16; 155 | } 156 | } 157 | Ok(()) 158 | } 159 | 160 | pub fn set_one_time_auth(&mut self, val: Option) -> ConfigResult<()> { 161 | if let Some(v) = val { 162 | self.one_time_auth = v; 163 | } 164 | Ok(()) 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/config/running_config.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::env; 3 | use std::fs; 4 | use std::sync::Arc; 5 | use std::path::PathBuf; 6 | use std::default::Default; 7 | 8 | use my_daemonize; 9 | use mode::Mode; 10 | use crypto::Method; 11 | use super::{ConfigError, ConfigResult, ProxyConfig}; 12 | 13 | macro_rules! create_set_fn { 14 | ($name:ident, $t:ty) => { 15 | pub fn $name(&mut self, val: Option<$t>) -> ConfigResult<()> { 16 | Arc::get_mut(&mut self.proxy_conf).unwrap().$name(val)?; 17 | Ok(()) 18 | } 19 | } 20 | } 21 | 22 | pub struct RunningConfig { 23 | pub daemon: my_daemonize::Cmd, 24 | pub log_level: i8, 25 | pub log_file: Option, 26 | pub pid_file: PathBuf, 27 | pub prefer_ipv6: bool, 28 | pub mode: Mode, 29 | pub proxy_conf: Arc, 30 | pub server_confs: Option>>, 31 | } 32 | 33 | impl fmt::Display for RunningConfig { 34 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 35 | let mut s = format!("{}\nprefer_ipv6 = {}", self.proxy_conf, self.prefer_ipv6); 36 | match self.mode { 37 | Mode::None => {} 38 | _ => s = format!("{}\nmode = \"{}\"", s, self.mode), 39 | } 40 | if let Some(ref p) = self.log_file { 41 | s = format!("{}\nlog_file = \"{}\"", s, p.display()); 42 | } 43 | s = format!("{}\npid_file = \"{}\"", s, self.pid_file.display()); 44 | 45 | if let Some(ref servers) = self.server_confs { 46 | for server in servers { 47 | s = format!("{}\n\n[[servers]]\n{}", s, server); 48 | } 49 | } 50 | 51 | write!(f, "{}", s) 52 | } 53 | } 54 | 55 | impl fmt::Debug for RunningConfig { 56 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 57 | let s = format!("log_level: {}\n\ 58 | log_file: {:?}\n\ 59 | pid_file: {:?}\n\ 60 | prefer_ipv6: {}\n\ 61 | mode: {:?}\n\ 62 | proxy_conf: {{\n\ 63 | {:?}\n\ 64 | }}\n\ 65 | server_confs: {:?}", 66 | self.log_level, 67 | self.log_file, 68 | self.pid_file, 69 | self.prefer_ipv6, 70 | self.mode, 71 | self.proxy_conf, 72 | self.server_confs); 73 | 74 | write!(f, "{}", s) 75 | } 76 | } 77 | 78 | impl Default for RunningConfig { 79 | fn default() -> Self { 80 | let mode = if cfg!(feature = "sslocal") { 81 | Mode::Balance 82 | } else { 83 | Mode::None 84 | }; 85 | 86 | RunningConfig { 87 | daemon: my_daemonize::Cmd::None, 88 | log_level: 0, 89 | log_file: None, 90 | pid_file: Self::default_pid_path(), 91 | prefer_ipv6: false, 92 | mode: mode, 93 | proxy_conf: Arc::new(ProxyConfig::default()), 94 | server_confs: None, 95 | } 96 | } 97 | } 98 | 99 | impl RunningConfig { 100 | // return "~/.shadowsocks/" or "" 101 | fn default_file_path(file_name: &str) -> PathBuf { 102 | env::home_dir() 103 | .and_then(|mut path| { 104 | path.push(".shadowsocks"); 105 | try_opt!(fs::create_dir_all(&path).ok()); 106 | path.push(file_name); 107 | Some(path) 108 | }) 109 | .or(Some(PathBuf::from(file_name))) 110 | .unwrap() 111 | } 112 | 113 | pub fn default_config_path() -> PathBuf { 114 | let name = if cfg!(feature = "sslocal") { 115 | "sslocal.toml" 116 | } else { 117 | "ssserver.toml" 118 | }; 119 | Self::default_file_path(name) 120 | } 121 | 122 | pub fn default_log_path() -> PathBuf { 123 | let log_file = if cfg!(feature = "sslocal") { 124 | "sslocal.log" 125 | } else { 126 | "ssserver.log" 127 | }; 128 | Self::default_file_path(log_file) 129 | } 130 | 131 | pub fn default_pid_path() -> PathBuf { 132 | let pid_file = if cfg!(feature = "sslocal") { 133 | "sslocal.pid" 134 | } else { 135 | "ssserver.pid" 136 | }; 137 | Self::default_file_path(pid_file) 138 | } 139 | 140 | pub fn address(&self) -> &String { 141 | &self.proxy_conf.address 142 | } 143 | 144 | pub fn port(&self) -> u16 { 145 | self.proxy_conf.port 146 | } 147 | 148 | pub fn method(&self) -> Method { 149 | self.proxy_conf.method 150 | } 151 | 152 | pub fn password(&self) -> &String { 153 | &self.proxy_conf.password 154 | } 155 | 156 | pub fn timeout(&self) -> u16 { 157 | self.proxy_conf.timeout 158 | } 159 | 160 | pub fn one_time_auth(&self) -> bool { 161 | self.proxy_conf.one_time_auth 162 | } 163 | 164 | pub fn set_quiet(&mut self, val: Option) -> ConfigResult<()> { 165 | if let Some(v) = val { 166 | if v < 0 { 167 | return Err(ConfigError::OutOfRange(v)); 168 | } else { 169 | self.log_level = -v as i8; 170 | } 171 | } 172 | Ok(()) 173 | } 174 | 175 | pub fn set_verbose(&mut self, val: Option) -> ConfigResult<()> { 176 | if let Some(v) = val { 177 | if v < 0 { 178 | return Err(ConfigError::OutOfRange(v)); 179 | } else { 180 | self.log_level = v as i8; 181 | } 182 | } 183 | Ok(()) 184 | } 185 | 186 | pub fn set_log_file(&mut self, val: Option<&str>) -> ConfigResult<()> { 187 | if val.is_some() { 188 | self.log_file = val.map(PathBuf::from); 189 | } 190 | Ok(()) 191 | } 192 | 193 | pub fn set_pid_file(&mut self, val: Option<&str>) -> ConfigResult<()> { 194 | if let Some(p) = val { 195 | self.pid_file = PathBuf::from(p); 196 | } 197 | Ok(()) 198 | } 199 | 200 | pub fn set_prefer_ipv6(&mut self, val: Option) -> ConfigResult<()> { 201 | if let Some(v) = val { 202 | self.prefer_ipv6 = v; 203 | } 204 | Ok(()) 205 | } 206 | 207 | pub fn set_daemon(&mut self, val: Option<&str>) -> ConfigResult<()> { 208 | if let Some(v) = val { 209 | self.daemon = v.parse::().map_err(ConfigError::Other)?; 210 | } 211 | Ok(()) 212 | } 213 | 214 | pub fn set_mode(&mut self, val: Option<&str>) -> ConfigResult<()> { 215 | if let Some(v) = val { 216 | match v { 217 | "balance" => self.mode = Mode::Balance, 218 | "fast" => self.mode = Mode::Fast, 219 | _ => return Err(ConfigError::InvalidMode(v.to_string())), 220 | } 221 | } 222 | Ok(()) 223 | } 224 | 225 | create_set_fn!(set_address, &str); 226 | create_set_fn!(set_port, i64); 227 | create_set_fn!(set_method, &str); 228 | create_set_fn!(set_password, &str); 229 | create_set_fn!(set_timeout, i64); 230 | create_set_fn!(set_one_time_auth, bool); 231 | } 232 | -------------------------------------------------------------------------------- /src/config/toml.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::fs::{File, OpenOptions}; 3 | use std::sync::Arc; 4 | use std::path::Path; 5 | use std::io::prelude::*; 6 | 7 | use toml::{Parser, Value, Table}; 8 | 9 | use super::{ConfigError, ConfigResult, Config, ProxyConfig}; 10 | 11 | #[macro_export] 12 | macro_rules! tbl_get { 13 | ($t:expr, $name:expr, str) => { $t.get($name).and_then(Value::as_str) }; 14 | ($t:expr, $name:expr, int) => { $t.get($name).and_then(Value::as_integer) }; 15 | ($t:expr, $name:expr, bool) => { $t.get($name).and_then(Value::as_bool) }; 16 | ($t:expr, $name:expr, slice) => { $t.get($name).and_then(Value::as_slice) }; 17 | } 18 | 19 | pub fn check_and_set_from_toml(tbl: &Table, conf: &mut Config) -> ConfigResult<()> { 20 | conf.set_quiet(tbl_get!(tbl, "quiet", int))?; 21 | conf.set_verbose(tbl_get!(tbl, "verbose", int))?; 22 | conf.set_log_file(tbl_get!(tbl, "log_file", str))?; 23 | conf.set_pid_file(tbl_get!(tbl, "pid_file", str))?; 24 | conf.set_prefer_ipv6(tbl_get!(tbl, "prefer_ipv6", bool))?; 25 | conf.set_mode(tbl_get!(tbl, "mode", str))?; 26 | if let Some(true) = tbl_get!(tbl, "daemon", bool) { 27 | conf.set_daemon(Some("start"))?; 28 | } 29 | 30 | conf.set_address(tbl_get!(tbl, "address", str))?; 31 | conf.set_port(tbl_get!(tbl, "port", int))?; 32 | conf.set_method(tbl_get!(tbl, "method", str))?; 33 | conf.set_password(tbl_get!(tbl, "password", str))?; 34 | conf.set_timeout(tbl_get!(tbl, "timeout", int))?; 35 | conf.set_one_time_auth(tbl_get!(tbl, "one_time_auth", bool))?; 36 | Ok(()) 37 | } 38 | 39 | pub fn check_and_set_servers_from_toml(tbl: &Table, conf: &mut Config) -> ConfigResult<()> { 40 | let servers = tbl_get!(tbl, "servers", slice).ok_or(ConfigError::MissServerAddress)?; 41 | let mut server_confs = vec![]; 42 | 43 | for server in servers { 44 | match *server { 45 | Value::Table(ref tbl) => { 46 | let mut server_conf = conf.proxy_conf.clone(); 47 | 48 | { 49 | let mut tmp = Arc::make_mut(&mut server_conf); 50 | 51 | if let Some(address) = tbl.get("address") { 52 | tmp.set_address(address.as_str())?; 53 | } else { 54 | return Err(ConfigError::MissServerAddress); 55 | } 56 | if let Some(port) = tbl.get("port") { 57 | tmp.set_port(port.as_integer())?; 58 | } else { 59 | return Err(ConfigError::MissServerPort); 60 | } 61 | 62 | tmp.set_method(tbl_get!(tbl, "method", str))?; 63 | tmp.set_password(tbl_get!(tbl, "password", str))?; 64 | tmp.set_timeout(tbl_get!(tbl, "timeout", int))?; 65 | tmp.set_one_time_auth(tbl_get!(tbl, "one_time_auth", bool))?; 66 | } 67 | 68 | server_confs.push(server_conf); 69 | } 70 | _ => { 71 | let errmsg = format!("server config should be table:\n{}", server); 72 | return Err(ConfigError::ParseConfigFailed(errmsg)); 73 | } 74 | } 75 | } 76 | 77 | conf.server_confs = Some(server_confs); 78 | Ok(()) 79 | } 80 | 81 | pub fn read_config + fmt::Debug>(config_path: P) -> Result { 82 | let mut f = File::open(&config_path).map_err(|e| { 83 | let errmsg = format!("{} ({})", config_path.as_ref().display(), e); 84 | ConfigError::OpenFileFailed(errmsg) 85 | })?; 86 | 87 | let mut input = String::new(); 88 | f.read_to_string(&mut input) 89 | .map_err(|e| { 90 | let errmsg = format!("{} is not valid UTF-8 file ({})", 91 | config_path.as_ref().display(), 92 | e); 93 | ConfigError::OpenFileFailed(errmsg) 94 | })?; 95 | 96 | let mut parser = Parser::new(&input); 97 | match parser.parse() { 98 | Some(config) => Ok(config), 99 | None => { 100 | let mut errmsg = String::new(); 101 | for e in &parser.errors { 102 | errmsg = format!("{}\n{}", errmsg, e); 103 | } 104 | Err(ConfigError::ParseConfigFailed(errmsg)) 105 | } 106 | } 107 | } 108 | 109 | pub fn save_if_not_exists(conf: &Config) { 110 | let path = Config::default_config_path(); 111 | if path.exists() { 112 | return; 113 | } 114 | 115 | if let Ok(ref mut f) = File::create(&path) { 116 | let content = format!("{}\n", conf); 117 | let _ = f.write_all(content.as_bytes()); 118 | } 119 | } 120 | 121 | pub fn append_to_default_config(server_conf: &ProxyConfig) { 122 | let path = Config::default_config_path(); 123 | let _ = OpenOptions::new().append(true).open(path).and_then(|mut f| { 124 | let content = format!("\n[[servers]]\n{}\n", server_conf); 125 | f.write_all(content.as_bytes()) 126 | }); 127 | } 128 | -------------------------------------------------------------------------------- /src/crypto/cipher.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use super::error::CipherResult; 4 | use super::{Method, Mode}; 5 | use super::methods::BelongLib; 6 | use super::crypto_lib::CryptoCipher; 7 | #[cfg(feature = "openssl")] 8 | use super::openssl_lib::OpensslCipher; 9 | 10 | pub struct Cipher { 11 | key: Arc>, 12 | iv: Vec, 13 | inner: Box, 14 | } 15 | 16 | impl Cipher { 17 | pub fn new(method: Method, mode: Mode, key: Arc>, iv: Vec) -> CipherResult { 18 | let cipher: Box = match method.belong_lib() { 19 | BelongLib::Crypto => Box::new(CryptoCipher::new(method, mode, &key, &iv)?), 20 | #[cfg(feature = "openssl")] 21 | BelongLib::Openssl => Box::new(OpensslCipher::new(method, mode, &key, &iv)?), 22 | }; 23 | 24 | Ok(Cipher { 25 | key: key, 26 | iv: iv, 27 | inner: cipher, 28 | }) 29 | } 30 | 31 | pub fn key(&self) -> &[u8] { 32 | &self.key 33 | } 34 | 35 | pub fn iv(&self) -> &[u8] { 36 | &self.iv 37 | } 38 | 39 | pub fn set_iv(&mut self, iv: &[u8]) { 40 | self.iv[..].copy_from_slice(iv); 41 | } 42 | 43 | pub fn key_len(&self) -> usize { 44 | self.key.len() 45 | } 46 | 47 | pub fn iv_len(&self) -> usize { 48 | self.iv.len() 49 | } 50 | } 51 | 52 | impl StreamCipher for Cipher { 53 | fn update(&mut self, input: &[u8], output: &mut Vec) -> CipherResult<()> { 54 | self.inner.update(input, output) 55 | } 56 | } 57 | 58 | pub trait StreamCipher { 59 | fn update(&mut self, input: &[u8], output: &mut Vec) -> CipherResult<()>; 60 | } 61 | -------------------------------------------------------------------------------- /src/crypto/crypto_lib.rs: -------------------------------------------------------------------------------- 1 | use rust_crypto::aes; 2 | use rust_crypto::rc4::Rc4; 3 | use rust_crypto::hc128::Hc128; 4 | use rust_crypto::salsa20::Salsa20; 5 | use rust_crypto::chacha20::ChaCha20; 6 | use rust_crypto::sosemanuk::Sosemanuk; 7 | use rust_crypto::symmetriccipher::SynchronousStreamCipher; 8 | 9 | use super::{Method, Mode}; 10 | use super::cipher::StreamCipher; 11 | use super::error::CipherResult; 12 | #[cfg(feature = "openssl")] 13 | use super::error::Error; 14 | 15 | pub struct CryptoCipher { 16 | inner: Box, 17 | } 18 | 19 | impl CryptoCipher { 20 | pub fn new(method: Method, _mode: Mode, key: &[u8], iv: &[u8]) -> CipherResult { 21 | let cipher = match method { 22 | Method::aes_128_ctr => aes::ctr(aes::KeySize::KeySize128, key, iv), 23 | Method::aes_192_ctr => aes::ctr(aes::KeySize::KeySize192, key, iv), 24 | Method::aes_256_ctr => aes::ctr(aes::KeySize::KeySize256, key, iv), 25 | Method::rc4 => Box::new(Rc4::new(key)), 26 | Method::hc128 => Box::new(Hc128::new(key, iv)), 27 | Method::salsa20 => Box::new(Salsa20::new(key, iv)), 28 | Method::xsalsa20 => Box::new(Salsa20::new_xsalsa20(key, iv)), 29 | Method::chacha20 => Box::new(ChaCha20::new(key, iv)), 30 | Method::xchacha20 => Box::new(ChaCha20::new_xchacha20(key, iv)), 31 | Method::sosemanuk => Box::new(Sosemanuk::new(key, iv)), 32 | #[cfg(feature = "openssl")] 33 | m => return Err(Error::UnsupportMethod(m)), 34 | }; 35 | 36 | Ok(CryptoCipher { inner: cipher }) 37 | } 38 | } 39 | 40 | impl StreamCipher for CryptoCipher { 41 | fn update(&mut self, input: &[u8], output: &mut Vec) -> CipherResult<()> { 42 | output.resize(input.len(), 0); 43 | self.inner.process(input, output); 44 | Ok(()) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/crypto/encryptor.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use std::sync::Mutex; 3 | use lru_time_cache::LruCache; 4 | 5 | use rand::{Rng, OsRng}; 6 | use rust_crypto::util::fixed_time_eq; 7 | use rust_crypto::mac::Mac; 8 | use rust_crypto::md5::Md5; 9 | use rust_crypto::sha1::Sha1; 10 | use rust_crypto::hmac::Hmac; 11 | use rust_crypto::digest::Digest; 12 | use network::{NetworkReadBytes, NetworkWriteBytes}; 13 | 14 | use super::error::CipherResult; 15 | use super::{Method, Cipher, Mode}; 16 | use super::cipher::StreamCipher; 17 | 18 | const BUF_SIZE: usize = 64 * 1024; 19 | const KEY_CACHE_SIZE: usize = 1024; 20 | const HMAC_SHA1_LEN: usize = 10; 21 | 22 | pub struct Encryptor { 23 | ota_helper: Option, 24 | is_iv_sent: bool, 25 | key: Arc>, 26 | iv_len: usize, 27 | password: String, 28 | method: Method, 29 | cipher: Cipher, 30 | decipher: Option, 31 | } 32 | 33 | // First packet format: 34 | // 35 | // +-----------+----------------+ 36 | // | cipher iv | encrypted data | 37 | // +-----------+----------------+ 38 | impl Encryptor { 39 | pub fn new(password: &str, method: Method) -> CipherResult { 40 | let (key, iv) = gen_key_iv(password, method); 41 | let iv_len = iv.len(); 42 | let cipher = Cipher::new(method, Mode::Encrypt, key.clone(), iv)?; 43 | 44 | Ok(Encryptor { 45 | ota_helper: None, 46 | is_iv_sent: false, 47 | key: key, 48 | iv_len: iv_len, 49 | password: String::from(password), 50 | method: method, 51 | cipher: cipher, 52 | decipher: None, 53 | }) 54 | } 55 | 56 | #[cfg(feature = "sslocal")] 57 | fn cipher_iv(&self) -> &[u8] { 58 | self.cipher.iv() 59 | } 60 | 61 | fn decipher_iv(&self) -> Option<&[u8]> { 62 | self.decipher.as_ref().map(|c| c.iv()) 63 | } 64 | 65 | #[cfg(feature = "sslocal")] 66 | pub fn enable_ota(&mut self, 67 | addr_type: u8, 68 | header_length: usize, 69 | data: &[u8]) 70 | -> Option> { 71 | let mut ota = OtaHelper::new(); 72 | // OTA header 73 | let mut header = vec![]; 74 | header.push(addr_type); 75 | // first byte is addr_type 76 | header.extend_from_slice(&data[1..header_length]); 77 | 78 | // sha1 of header 79 | let mut key = vec![]; 80 | key.extend_from_slice(self.cipher_iv()); 81 | key.extend_from_slice(&self.key); 82 | let sha1 = ota.hmac_sha1(&header, &key); 83 | header.extend_from_slice(&sha1); 84 | 85 | let data = &data[header_length..]; 86 | if data.is_empty() { 87 | self.ota_helper = Some(ota); 88 | Some(header) 89 | } else { 90 | // OTA chunk 91 | let chunk = try_opt!(ota.pack_chunk(data, &self.cipher_iv())); 92 | 93 | // OTA request 94 | let mut data = vec![]; 95 | data.extend_from_slice(&header); 96 | data.extend_from_slice(&chunk); 97 | 98 | self.ota_helper = Some(ota); 99 | Some(data) 100 | } 101 | } 102 | 103 | #[cfg(not(feature = "sslocal"))] 104 | pub fn enable_ota(&mut self, 105 | _addr_type: u8, 106 | header_length: usize, 107 | data: &[u8]) 108 | -> Option> { 109 | let mut ota = OtaHelper::new(); 110 | // verify OTA header 111 | let header = &data[..header_length]; 112 | let sha1 = &data[header_length..header_length + HMAC_SHA1_LEN]; 113 | let mut key = vec![]; 114 | key.extend_from_slice(try_opt!(self.decipher_iv())); 115 | key.extend_from_slice(&self.key); 116 | if !ota.verify_sha1(header, &key, sha1) { 117 | return None; 118 | } 119 | 120 | // unpack OTA chunks 121 | let res = ota.unpack_chunk(&data[header_length + HMAC_SHA1_LEN..], 122 | try_opt!(self.decipher_iv())); 123 | self.ota_helper = Some(ota); 124 | res 125 | } 126 | 127 | #[cfg(feature = "disable-encrypt")] 128 | pub fn raw_encrypt(&mut self, data: &[u8]) -> Option> { 129 | Some(data.to_vec()) 130 | } 131 | 132 | #[cfg(feature = "disable-encrypt")] 133 | pub fn raw_decrypt(&mut self, data: &[u8]) -> Option> { 134 | Some(data.to_vec()) 135 | } 136 | 137 | #[cfg(not(feature = "disable-encrypt"))] 138 | pub fn raw_encrypt(&mut self, data: &[u8]) -> Option> { 139 | let mut output = vec![]; 140 | self.cipher.update(data, &mut output).ok().map(|_| output) 141 | } 142 | 143 | #[cfg(not(feature = "disable-encrypt"))] 144 | pub fn raw_decrypt(&mut self, data: &[u8]) -> Option> { 145 | self.decipher.as_mut().and_then(|decipher| { 146 | let mut output = vec![]; 147 | decipher.update(data, &mut output).ok().map(|_| output) 148 | }) 149 | } 150 | 151 | pub fn encrypt(&mut self, data: &[u8]) -> Option> { 152 | // if first request 153 | if !self.is_iv_sent { 154 | self.is_iv_sent = true; 155 | match self.raw_encrypt(data) { 156 | Some(ref mut encrypted) => { 157 | let mut result = vec![]; 158 | result.extend_from_slice(self.cipher.iv()); 159 | result.append(encrypted); 160 | 161 | Some(result) 162 | } 163 | _ => None, 164 | } 165 | } else { 166 | // if this is a OTA request 167 | if cfg!(feature = "sslocal") && self.ota_helper.is_some() { 168 | let mut ota = self.ota_helper.take().unwrap(); 169 | let data = &try_opt!(ota.pack_chunk(data, &self.cipher.iv())); 170 | self.ota_helper = Some(ota); 171 | self.raw_encrypt(data) 172 | } else { 173 | self.raw_encrypt(data) 174 | } 175 | } 176 | } 177 | 178 | pub fn decrypt(&mut self, data: &[u8]) -> Option> { 179 | // if first request 180 | if self.decipher.is_none() { 181 | let iv_len = self.iv_len; 182 | if data.len() > iv_len { 183 | let iv = Vec::from(&data[..iv_len]); 184 | self.decipher = Cipher::new(self.method, Mode::Decrypt, self.key.clone(), iv).ok(); 185 | self.raw_decrypt(&data[iv_len..]) 186 | } else { 187 | None 188 | } 189 | } else { 190 | let mut decrypted = try_opt!(self.raw_decrypt(data)); 191 | // if this is a OTA request 192 | if !cfg!(feature = "sslocal") && self.ota_helper.is_some() { 193 | let mut ota = self.ota_helper.take().unwrap(); 194 | decrypted = try_opt!(ota.unpack_chunk(&decrypted, try_opt!(self.decipher_iv()))); 195 | self.ota_helper = Some(ota); 196 | } 197 | Some(decrypted) 198 | } 199 | } 200 | 201 | fn raw_encrypt_udp(&self, key: Arc>, iv: &[u8], data: &[u8]) -> Option> { 202 | let mut cipher = try_opt!(Cipher::new(self.method, Mode::Encrypt, key, Vec::from(iv)).ok()); 203 | let mut encrypted = vec![0u8; data.len()]; 204 | try_opt!(cipher.update(data, &mut encrypted).ok()); 205 | 206 | let mut res = vec![]; 207 | res.extend_from_slice(iv); 208 | res.extend_from_slice(&encrypted); 209 | Some(res) 210 | } 211 | 212 | fn raw_decrypt_udp(&self, 213 | iv_len: usize, 214 | key: Arc>, 215 | data: &[u8]) 216 | -> Option<(Cipher, Vec)> { 217 | let iv = &data[..iv_len]; 218 | let mut decipher = try_opt!(Cipher::new(self.method, Mode::Decrypt, key, Vec::from(iv)) 219 | .ok()); 220 | let mut decrypted = vec![0u8; data.len() - iv_len]; 221 | try_opt!(decipher.update(&data[iv_len..], &mut decrypted).ok()); 222 | 223 | Some((decipher, decrypted)) 224 | } 225 | 226 | pub fn encrypt_udp(&mut self, data: &[u8]) -> Option> { 227 | let (key, iv) = gen_key_iv(&self.password, self.method); 228 | self.raw_encrypt_udp(key, &iv, data) 229 | } 230 | 231 | pub fn decrypt_udp(&mut self, data: &[u8]) -> Option> { 232 | let (key, _iv) = gen_key_iv(&self.password, self.method); 233 | self.raw_decrypt_udp(_iv.len(), key, data).and_then(|(decipher, data)| { 234 | self.decipher = Some(decipher); 235 | Some(data) 236 | }) 237 | } 238 | 239 | pub fn encrypt_udp_ota(&mut self, addr_type: u8, data: &[u8]) -> Option> { 240 | if self.ota_helper.is_none() { 241 | self.ota_helper = Some(OtaHelper::new()); 242 | } 243 | let ota = self.ota_helper.take().unwrap(); 244 | 245 | let mut chunk = Vec::with_capacity(data.len() + HMAC_SHA1_LEN); 246 | chunk.push(addr_type); 247 | chunk.extend_from_slice(&data[1..]); 248 | 249 | let (key, iv) = gen_key_iv(&self.password, self.method); 250 | let mut ota_key = Vec::with_capacity(key.len() + iv.len()); 251 | ota_key.extend_from_slice(&iv); 252 | ota_key.extend_from_slice(&key); 253 | 254 | let sha1 = ota.hmac_sha1(&chunk, &ota_key); 255 | chunk.extend_from_slice(&sha1); 256 | 257 | self.ota_helper = Some(ota); 258 | self.raw_encrypt_udp(key, &iv, &chunk) 259 | } 260 | 261 | pub fn decrypt_udp_ota(&mut self, _addr_type: u8, data: &[u8]) -> Option> { 262 | if data.len() < HMAC_SHA1_LEN { 263 | return None; 264 | } 265 | 266 | if self.ota_helper.is_none() { 267 | self.ota_helper = Some(OtaHelper::new()); 268 | } 269 | let ota = self.ota_helper.take().unwrap(); 270 | 271 | let mut ota_key = vec![]; 272 | ota_key.extend_from_slice(try_opt!(self.decipher_iv())); 273 | ota_key.extend_from_slice(&self.key); 274 | 275 | let sha1 = &data[data.len() - HMAC_SHA1_LEN..]; 276 | let data = &data[..data.len() - HMAC_SHA1_LEN]; 277 | 278 | if ota.verify_sha1(data, &ota_key, sha1) { 279 | self.ota_helper = Some(ota); 280 | Some(data.to_vec()) 281 | } else { 282 | None 283 | } 284 | } 285 | } 286 | 287 | struct OtaHelper { 288 | index: i32, 289 | chunk_sha1: Vec, 290 | chunk_len: u16, 291 | chunk_buf: Vec, 292 | } 293 | 294 | impl OtaHelper { 295 | fn new() -> OtaHelper { 296 | OtaHelper { 297 | index: 0, 298 | chunk_sha1: Vec::with_capacity(HMAC_SHA1_LEN), 299 | chunk_len: 0, 300 | chunk_buf: Vec::with_capacity(BUF_SIZE), 301 | } 302 | } 303 | 304 | fn hmac_sha1(&self, data: &[u8], key: &[u8]) -> Vec { 305 | let mut hmac = Hmac::new(Sha1::new(), key); 306 | let len = hmac.output_bytes(); 307 | let mut res = vec![0u8; len]; 308 | hmac.input(data); 309 | hmac.raw_result(&mut res); 310 | res.resize(HMAC_SHA1_LEN, 0); 311 | res 312 | } 313 | 314 | fn verify_sha1(&self, data: &[u8], key: &[u8], sha1: &[u8]) -> bool { 315 | fixed_time_eq(sha1, &self.hmac_sha1(data, key)[..]) 316 | } 317 | 318 | fn pack_chunk(&mut self, data: &[u8], cipher_iv: &[u8]) -> Option> { 319 | let mut ota_key = vec![]; 320 | ota_key.extend_from_slice(cipher_iv); 321 | pack!(i32, ota_key, self.index); 322 | 323 | let sha1 = self.hmac_sha1(data, &ota_key); 324 | let mut chunk = vec![]; 325 | pack!(u16, chunk, data.len() as u16); 326 | chunk.extend_from_slice(&sha1); 327 | chunk.extend_from_slice(data); 328 | 329 | self.index += 1; 330 | Some(chunk) 331 | } 332 | 333 | fn unpack_chunk(&mut self, mut data: &[u8], decipher_iv: &[u8]) -> Option> { 334 | let mut unpacked = Vec::with_capacity(data.len()); 335 | 336 | while !data.is_empty() { 337 | // make sure read a complete header 338 | if self.chunk_len == 0 { 339 | // wait a complete header 340 | if data.len() + self.chunk_buf.len() < 12 { 341 | self.chunk_buf.extend_from_slice(data); 342 | break; 343 | } else { 344 | // split DATA.LEN, HMAC-SHA1 from DATA 345 | let offset = 12 - self.chunk_buf.len(); 346 | self.chunk_buf.extend_from_slice(&data[..offset]); 347 | self.chunk_len = unpack!(u16, &self.chunk_buf[..2]); 348 | unsafe { 349 | self.chunk_sha1.set_len(0); 350 | } 351 | self.chunk_sha1.extend_from_slice(&self.chunk_buf[2..]); 352 | unsafe { 353 | self.chunk_buf.set_len(0); 354 | } 355 | data = &data[offset..]; 356 | } 357 | } 358 | 359 | if data.len() + self.chunk_buf.len() < self.chunk_len as usize { 360 | self.chunk_buf.extend_from_slice(data); 361 | break; 362 | // if there are one or more chunks 363 | } else { 364 | let offset = self.chunk_len as usize - self.chunk_buf.len(); 365 | // make sure there is a chunk data in chunk_buf 366 | self.chunk_buf.extend_from_slice(&data[..offset]); 367 | data = &data[offset..]; 368 | 369 | let mut key = Vec::with_capacity(decipher_iv.len() + 4); 370 | key.extend_from_slice(decipher_iv); 371 | pack!(i32, key, self.index); 372 | self.index += 1; 373 | 374 | if self.verify_sha1(&self.chunk_buf, &key, &self.chunk_sha1) { 375 | unpacked.extend_from_slice(&self.chunk_buf); 376 | self.chunk_len = 0; 377 | unsafe { 378 | self.chunk_buf.set_len(0); 379 | } 380 | } else { 381 | self.chunk_len = 0; 382 | unsafe { 383 | self.chunk_buf.set_len(0); 384 | } 385 | break; 386 | } 387 | } 388 | } 389 | 390 | Some(unpacked) 391 | } 392 | } 393 | 394 | fn gen_key_iv(password: &str, method: Method) -> (Arc>, Vec) { 395 | lazy_static! { 396 | static ref CACHE: Mutex>>> = 397 | Mutex::new(LruCache::with_capacity(KEY_CACHE_SIZE)); 398 | } 399 | 400 | let (key_len, iv_len) = Method::info(method); 401 | 402 | let key = match CACHE.lock().unwrap().get(&(password.to_string(), method)) { 403 | Some(key) => key.clone(), 404 | None => Arc::new(evp_bytes_to_key(password, key_len, iv_len).0), 405 | }; 406 | 407 | let mut iv = vec![0u8; iv_len]; 408 | let _ = OsRng::new().map(|mut rng| rng.fill_bytes(&mut iv)); 409 | (key, iv) 410 | } 411 | 412 | // equivalent to OpenSSL's EVP_BytesToKey() with count 1 413 | fn evp_bytes_to_key(password: &str, key_len: usize, iv_len: usize) -> (Vec, Vec) { 414 | const MD5_LEN: usize = 16; 415 | let mut i = 0; 416 | let mut m: Vec> = Vec::with_capacity(key_len + iv_len); 417 | let password = password.as_bytes(); 418 | let mut data = Vec::with_capacity(MD5_LEN + password.len()); 419 | let mut cnt = 0; 420 | 421 | while cnt < key_len + iv_len { 422 | unsafe { 423 | data.set_len(0); 424 | } 425 | if i > 0 { 426 | data.extend_from_slice(&*m[i - 1]); 427 | } 428 | data.extend_from_slice(password); 429 | 430 | let mut buf = Box::new([0u8; MD5_LEN]); 431 | let mut md5 = Md5::new(); 432 | md5.input(&data); 433 | md5.result(&mut *buf); 434 | cnt += buf.len(); 435 | 436 | m.push(buf); 437 | i += 1; 438 | } 439 | 440 | let mut tmp: Vec = Vec::with_capacity(MD5_LEN * m.capacity()); 441 | for bytes in m { 442 | tmp.extend_from_slice(&*bytes); 443 | } 444 | 445 | let key = Vec::from(&tmp[..key_len]); 446 | let iv = Vec::from(&tmp[key_len..key_len + iv_len]); 447 | 448 | (key, iv) 449 | } 450 | -------------------------------------------------------------------------------- /src/crypto/error.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::fmt; 3 | 4 | #[cfg(feature = "openssl")] 5 | use rust_openssl::error::ErrorStack; 6 | 7 | use super::Method; 8 | 9 | pub type CipherResult = Result; 10 | 11 | pub enum Error { 12 | UnknownMethod(String), 13 | UnsupportMethod(Method), 14 | #[cfg(feature = "openssl")] 15 | OpensslError(ErrorStack), 16 | IoError(io::Error), 17 | } 18 | 19 | #[cfg(feature = "openssl")] 20 | impl From for Error { 21 | fn from(e: ErrorStack) -> Error { 22 | Error::OpensslError(e) 23 | } 24 | } 25 | 26 | impl fmt::Debug for Error { 27 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 28 | match *self { 29 | Error::UnknownMethod(ref s) => write!(f, "unknown method {}", s), 30 | Error::UnsupportMethod(m) => write!(f, "unsupport method {:?}", m), 31 | #[cfg(feature = "openssl")] 32 | Error::OpensslError(ref err) => write!(f, "{:?}", err), 33 | Error::IoError(ref err) => write!(f, "{:?}", err), 34 | } 35 | } 36 | } 37 | 38 | impl fmt::Display for Error { 39 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 40 | match *self { 41 | Error::UnknownMethod(ref s) => write!(f, "unknown method {}", s), 42 | Error::UnsupportMethod(m) => write!(f, "unsupport method {:?}", m), 43 | #[cfg(feature = "openssl")] 44 | Error::OpensslError(ref err) => write!(f, "{}", err), 45 | Error::IoError(ref err) => write!(f, "{}", err), 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/crypto/methods.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::str::FromStr; 3 | 4 | pub enum BelongLib { 5 | Crypto, 6 | #[cfg(feature = "openssl")] 7 | Openssl, 8 | } 9 | 10 | macro_rules! define_methods { 11 | [$($method:tt => ($key_len:expr, $iv_len:expr, $lib:tt),)*] => ( 12 | #[allow(non_camel_case_types)] 13 | #[derive(Debug, Clone, Copy, Hash, Eq, Ord, PartialEq, PartialOrd)] 14 | pub enum Method { 15 | $( 16 | $method, 17 | )* 18 | } 19 | 20 | impl Method { 21 | pub fn info(self) -> (usize, usize) { 22 | match self { 23 | $( 24 | Method::$method => ($key_len, $iv_len), 25 | )* 26 | } 27 | } 28 | 29 | pub fn belong_lib(self) -> BelongLib { 30 | match self { 31 | $( 32 | Method::$method => BelongLib::$lib, 33 | )* 34 | } 35 | } 36 | 37 | pub fn all() -> Vec { 38 | vec![ 39 | $( 40 | Method::$method, 41 | )* 42 | ] 43 | } 44 | } 45 | 46 | impl FromStr for Method { 47 | type Err = (); 48 | fn from_str(s: &str) -> Result { 49 | let s = s.replace("-", "_"); 50 | match s.as_str() { 51 | $( 52 | stringify!($method) => Ok(Method::$method), 53 | )* 54 | _ => Err(()), 55 | } 56 | } 57 | } 58 | 59 | impl fmt::Display for Method { 60 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 61 | match *self { 62 | $( 63 | Method::$method => write!(f, "{}", 64 | stringify!($method).replace("_", "-").as_str()), 65 | )* 66 | } 67 | } 68 | } 69 | ) 70 | } 71 | 72 | #[cfg(not(feature = "openssl"))] 73 | define_methods!( 74 | aes_128_ctr => (16, 16, Crypto), 75 | aes_192_ctr => (24, 16, Crypto), 76 | aes_256_ctr => (32, 16, Crypto), 77 | rc4 => (16, 0, Crypto), 78 | hc128 => (16, 16, Crypto), 79 | salsa20 => (32, 8, Crypto), 80 | xsalsa20 => (32, 24, Crypto), 81 | chacha20 => (32, 8, Crypto), 82 | xchacha20 => (32, 24, Crypto), 83 | sosemanuk => (32, 16, Crypto), 84 | ); 85 | 86 | #[cfg(feature = "openssl")] 87 | define_methods!( 88 | aes_128_ctr => (16, 16, Crypto), 89 | aes_192_ctr => (24, 16, Crypto), 90 | aes_256_ctr => (32, 16, Crypto), 91 | rc4 => (16, 0, Crypto), 92 | hc128 => (16, 16, Crypto), 93 | salsa20 => (32, 8, Crypto), 94 | xsalsa20 => (32, 24, Crypto), 95 | chacha20 => (32, 8, Crypto), 96 | xchacha20 => (32, 24, Crypto), 97 | sosemanuk => (32, 16, Crypto), 98 | 99 | aes_128_cfb => (16, 16, Openssl), 100 | aes_256_cfb => (32, 16, Openssl), 101 | aes_128_cfb1 => (16, 16, Openssl), 102 | aes_256_cfb1 => (32, 16, Openssl), 103 | aes_128_cfb8 => (16, 16, Openssl), 104 | aes_256_cfb8 => (32, 16, Openssl), 105 | ); 106 | -------------------------------------------------------------------------------- /src/crypto/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "openssl")] 2 | use super::rust_openssl; 3 | 4 | mod methods; 5 | mod cipher; 6 | mod encryptor; 7 | pub mod error; 8 | 9 | mod crypto_lib; 10 | #[cfg(feature = "openssl")] 11 | mod openssl_lib; 12 | 13 | pub use self::methods::Method; 14 | pub use self::cipher::Cipher; 15 | pub use self::encryptor::Encryptor; 16 | 17 | #[derive(Debug, Clone, Copy)] 18 | pub enum Mode { 19 | Encrypt, 20 | Decrypt, 21 | } 22 | 23 | #[cfg(feature = "openssl")] 24 | impl From for rust_openssl::symm::Mode { 25 | fn from(m: Mode) -> rust_openssl::symm::Mode { 26 | match m { 27 | Mode::Encrypt => rust_openssl::symm::Mode::Encrypt, 28 | Mode::Decrypt => rust_openssl::symm::Mode::Decrypt, 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/crypto/openssl_lib.rs: -------------------------------------------------------------------------------- 1 | use rust_openssl::symm::{Cipher, Crypter}; 2 | 3 | use super::{Method, Mode}; 4 | use super::error::{Error, CipherResult}; 5 | use super::cipher::StreamCipher; 6 | 7 | pub struct OpensslCipher { 8 | block_size: usize, 9 | inner: Crypter, 10 | } 11 | 12 | impl OpensslCipher { 13 | pub fn new(method: Method, mode: Mode, key: &[u8], iv: &[u8]) -> CipherResult { 14 | let cipher = match method { 15 | Method::aes_128_cfb => Cipher::aes_128_cfb128(), 16 | Method::aes_256_cfb => Cipher::aes_256_cfb128(), 17 | Method::aes_128_cfb1 => Cipher::aes_128_cfb1(), 18 | Method::aes_256_cfb1 => Cipher::aes_256_cfb1(), 19 | Method::aes_128_cfb8 => Cipher::aes_128_cfb8(), 20 | Method::aes_256_cfb8 => Cipher::aes_256_cfb8(), 21 | m => return Err(Error::UnsupportMethod(m)), 22 | }; 23 | let block_size = cipher.block_size(); 24 | let inner = Crypter::new(cipher, mode.into(), key, Some(iv))?; 25 | 26 | Ok(OpensslCipher { 27 | block_size: block_size, 28 | inner: inner, 29 | }) 30 | } 31 | } 32 | 33 | impl StreamCipher for OpensslCipher { 34 | fn update(&mut self, input: &[u8], output: &mut Vec) -> CipherResult<()> { 35 | let cap = input.len() + self.block_size; 36 | output.resize(cap, 0); 37 | let length = self.inner.update(input, output)?; 38 | output.resize(length, 0); 39 | Ok(()) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::result; 3 | use std::convert::From; 4 | use std::net::SocketAddr; 5 | 6 | pub use std::io::Error as IoError; 7 | pub use asyncdns::Error as DnsError; 8 | pub use socks5::Error as Socks5Error; 9 | pub use relay::Error as ProcessError; 10 | 11 | pub type Result = result::Result; 12 | 13 | #[macro_export] 14 | macro_rules! err_from { 15 | ($e:expr) => { Err(From::from($e)) } 16 | } 17 | 18 | pub enum SocketError { 19 | InitSocketFailed, 20 | EventError, 21 | RegisterFailed, 22 | ReadFailed(IoError), 23 | WriteFailed(IoError), 24 | BindAddrFailed(SocketAddr), 25 | AllocTokenFailed, 26 | ConnectionClosed, 27 | ParseAddrFailed(String), 28 | } 29 | 30 | impl fmt::Debug for SocketError { 31 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 32 | match *self { 33 | SocketError::InitSocketFailed => write!(f, "initialize socket failed"), 34 | SocketError::EventError => write!(f, "got a event error"), 35 | SocketError::RegisterFailed => write!(f, "register to event loop failed"), 36 | SocketError::ReadFailed(ref e) => write!(f, "read data from socket failed ({})", e), 37 | SocketError::WriteFailed(ref e) => write!(f, "write data to socket failed ({})", e), 38 | SocketError::BindAddrFailed(ref addr) => { 39 | write!(f, "bind socket to address {} failed", addr) 40 | } 41 | SocketError::AllocTokenFailed => write!(f, "alloc token failed"), 42 | SocketError::ConnectionClosed => write!(f, "connection closed by the other side"), 43 | SocketError::ParseAddrFailed(ref addr) => { 44 | write!(f, "parse socket address {} failed", addr) 45 | } 46 | } 47 | } 48 | } 49 | 50 | pub enum Error { 51 | DnsError(DnsError), 52 | SocketError(SocketError), 53 | Socks5Error(Socks5Error), 54 | ProcessError(ProcessError), 55 | IoError(IoError), 56 | Other(String), 57 | } 58 | 59 | macro_rules! create_from { 60 | ($err:tt) => ( 61 | impl From<$err> for Error { 62 | fn from(e: $err) -> Error { 63 | Error::$err(e) 64 | } 65 | } 66 | ) 67 | } 68 | 69 | create_from!(DnsError); 70 | create_from!(SocketError); 71 | create_from!(Socks5Error); 72 | create_from!(ProcessError); 73 | create_from!(IoError); 74 | 75 | impl fmt::Debug for Error { 76 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 77 | match *self { 78 | Error::DnsError(ref e) => write!(f, "{:?}", e), 79 | Error::SocketError(ref e) => write!(f, "{:?}", e), 80 | Error::Socks5Error(ref e) => write!(f, "{:?}", e), 81 | Error::ProcessError(ref e) => write!(f, "{:?}", e), 82 | Error::IoError(ref e) => write!(f, "{:?}", e), 83 | Error::Other(ref desc) => write!(f, "{}", desc), 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(feature="clippy", feature(plugin))] 2 | #![cfg_attr(feature="clippy", plugin(clippy))] 3 | #![cfg_attr(feature="clippy", allow(collapsible_if, 4 | needless_return, 5 | needless_range_loop, 6 | or_fun_call))] 7 | 8 | #[macro_use] 9 | #[cfg(target_family = "unix")] 10 | extern crate sig; 11 | 12 | #[macro_use] 13 | extern crate try_opt; 14 | #[macro_use] 15 | extern crate lazy_static; 16 | #[macro_use(o, slog_log, slog_debug, slog_info, slog_warn, slog_error, slog_trace)] 17 | extern crate slog; 18 | #[macro_use(debug, info, warn, error, trace)] 19 | extern crate slog_scope; 20 | extern crate slog_term; 21 | extern crate slog_stream; 22 | 23 | extern crate mio; 24 | extern crate fnv; 25 | extern crate rand; 26 | extern crate toml; 27 | extern crate clap; 28 | extern crate regex; 29 | extern crate chrono; 30 | extern crate byteorder; 31 | extern crate lru_time_cache; 32 | extern crate rustc_serialize; 33 | extern crate crypto as rust_crypto; 34 | #[cfg(feature = "openssl")] 35 | extern crate openssl as rust_openssl; 36 | 37 | #[macro_use] 38 | pub mod error; 39 | #[macro_use] 40 | pub mod util; 41 | #[macro_use] 42 | pub mod network; 43 | #[macro_use] 44 | pub mod relay; 45 | pub mod mode; 46 | pub mod config; 47 | pub mod socks5; 48 | pub mod crypto; 49 | pub mod asyncdns; 50 | pub mod my_logger; 51 | pub mod my_daemonize; 52 | pub mod collections; 53 | -------------------------------------------------------------------------------- /src/mode/mod.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::sync::Arc; 3 | use std::time::SystemTime; 4 | use std::cmp::{Ord, Ordering}; 5 | use std::collections::VecDeque; 6 | 7 | use mio::Token; 8 | use rand::{thread_rng, ThreadRng, Rng}; 9 | 10 | use config::{CONFIG, ProxyConfig}; 11 | use collections::Dict; 12 | 13 | #[derive(PartialEq, Clone, Copy)] 14 | pub enum Mode { 15 | Fast, 16 | Balance, 17 | None, 18 | } 19 | 20 | impl fmt::Display for Mode { 21 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 22 | match *self { 23 | Mode::Fast => write!(f, "fast"), 24 | Mode::Balance => write!(f, "balance"), 25 | Mode::None => write!(f, "none"), 26 | } 27 | } 28 | } 29 | 30 | impl fmt::Debug for Mode { 31 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 32 | fmt::Display::fmt(self, f) 33 | } 34 | } 35 | 36 | pub struct ServerChooser { 37 | rng: ThreadRng, 38 | rtts: Dict, RttRecord>, 39 | activities: Dict>, 40 | } 41 | 42 | impl ServerChooser { 43 | pub fn new() -> ServerChooser { 44 | let mut rtts = Dict::default(); 45 | 46 | // reduce some compute... 47 | if cfg!(feature = "sslocal") { 48 | for server_conf in CONFIG.server_confs.as_ref().unwrap() { 49 | rtts.insert(server_conf.clone(), RttRecord::new()); 50 | } 51 | } 52 | 53 | ServerChooser { 54 | rng: thread_rng(), 55 | rtts: rtts, 56 | activities: Dict::default(), 57 | } 58 | } 59 | 60 | pub fn choose(&mut self) -> Option> { 61 | match CONFIG.mode { 62 | Mode::Fast => self.choose_by_weight(), 63 | Mode::Balance => self.random_choose(), 64 | _ => unreachable!(), 65 | } 66 | } 67 | 68 | fn random_choose(&mut self) -> Option> { 69 | let server_confs: Vec<&Arc> = self.rtts.keys().collect(); 70 | let &server_conf = try_opt!(self.rng.choose(&server_confs)); 71 | Some(server_conf.clone()) 72 | } 73 | 74 | // This method will choose the last latency server with 80% probability, 75 | // and choose other servers with 20% probability. 76 | fn choose_by_weight(&mut self) -> Option> { 77 | let is_choose_min = self.rng.gen::() < (0.8 * u8::max_value() as f32) as u8; 78 | if is_choose_min { 79 | let mut min_conf = None; 80 | let mut min_rtt = None; 81 | 82 | for (conf, rtt) in &self.rtts { 83 | if min_rtt.is_none() || min_rtt > Some(rtt) { 84 | min_rtt = Some(rtt); 85 | min_conf = Some(conf); 86 | } 87 | } 88 | 89 | min_conf.cloned() 90 | } else { 91 | self.random_choose() 92 | } 93 | } 94 | 95 | pub fn record(&mut self, token: Token) { 96 | if Mode::Fast == CONFIG.mode { 97 | let times = self.activities.entry(token).or_insert_with(VecDeque::new); 98 | times.push_back(SystemTime::now()); 99 | } 100 | } 101 | 102 | pub fn update(&mut self, token: Token, server_conf: &Arc) { 103 | if Mode::Fast == CONFIG.mode { 104 | let time = self.activities.get_mut(&token).and_then(|times| times.pop_front()); 105 | match time { 106 | Some(time) => { 107 | self.rtts.get_mut(server_conf).map(|rtt| rtt.update(&time)); 108 | } 109 | None => { 110 | self.activities.remove(&token); 111 | } 112 | } 113 | } 114 | } 115 | 116 | pub fn punish(&mut self, token: Token, server_conf: &Arc) { 117 | if Mode::Fast == CONFIG.mode { 118 | self.activities.remove(&token); 119 | self.rtts.get_mut(server_conf).map(|rtt| rtt.punish()); 120 | } 121 | } 122 | } 123 | 124 | #[derive(Eq, Debug, Copy, Clone)] 125 | struct RttRecord { 126 | rto: u64, 127 | rtt: u32, 128 | dev: u32, 129 | last_activity: SystemTime, 130 | } 131 | 132 | impl RttRecord { 133 | fn new() -> RttRecord { 134 | RttRecord { 135 | rto: 0, 136 | rtt: 0, 137 | dev: 0, 138 | last_activity: SystemTime::now(), 139 | } 140 | } 141 | 142 | fn update_rto(&mut self) { 143 | self.rto = self.rtt as u64 + 4 * self.dev as u64; 144 | } 145 | 146 | fn update(&mut self, last_activity: &SystemTime) { 147 | self.last_activity = last_activity.clone(); 148 | let dt = last_activity.elapsed() 149 | .map(|d| d.as_secs() as u32 * 1000 + d.subsec_nanos() / 1000000); 150 | 151 | if let Ok(elapsed_ms) = dt { 152 | let mut rtt = self.rtt as f32; 153 | let mut dev = self.dev as f32; 154 | 155 | rtt = 0.875 * rtt + 0.125 * elapsed_ms as f32; 156 | dev = 0.75 * dev + 0.25 * (elapsed_ms as f32 - rtt).abs(); 157 | 158 | self.rtt = rtt as u32; 159 | self.dev = dev as u32; 160 | self.update_rto(); 161 | } 162 | } 163 | 164 | fn punish(&mut self) { 165 | let dt = self.last_activity 166 | .elapsed() 167 | .map(|d| d.as_secs() as u32 * 1000 + d.subsec_nanos() / 1000000); 168 | 169 | if let Ok(elapsed_ms) = dt { 170 | // self.dev = 2 * self.dev + elapsed_ms 171 | let dev = self.dev 172 | .checked_mul(2) 173 | .and_then(|d| d.checked_add(elapsed_ms)); 174 | 175 | match dev { 176 | Some(dev) => self.dev = dev, 177 | None => self.dev = u32::max_value(), 178 | } 179 | self.update_rto(); 180 | } 181 | } 182 | } 183 | 184 | impl Ord for RttRecord { 185 | fn cmp(&self, other: &RttRecord) -> Ordering { 186 | self.rto.cmp(&other.rto) 187 | } 188 | } 189 | 190 | impl PartialOrd for RttRecord { 191 | fn partial_cmp(&self, other: &RttRecord) -> Option { 192 | Some(self.cmp(other)) 193 | } 194 | } 195 | 196 | impl PartialEq for RttRecord { 197 | fn eq(&self, other: &RttRecord) -> bool { 198 | self.rto == other.rto 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /src/my_daemonize.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] 4 | pub enum Cmd { 5 | None, 6 | Stop, 7 | Start, 8 | Restart, 9 | } 10 | 11 | impl FromStr for Cmd { 12 | type Err = String; 13 | 14 | fn from_str(s: &str) -> Result { 15 | match s { 16 | "none" => Ok(Cmd::None), 17 | "stop" => Ok(Cmd::Stop), 18 | "start" => Ok(Cmd::Start), 19 | "restart" => Ok(Cmd::Restart), 20 | _ => Err(format!("invalid daemon command: {}", s)), 21 | } 22 | } 23 | } 24 | 25 | pub use self::_daemonize::init; 26 | 27 | #[cfg(target_family = "unix")] 28 | mod _daemonize { 29 | extern crate sig; 30 | extern crate daemonize; 31 | 32 | use std::io::Read; 33 | use std::str::FromStr; 34 | use std::process::exit; 35 | use std::{thread, time}; 36 | use std::fs::{File, remove_file}; 37 | use std::path::PathBuf; 38 | 39 | use super::Cmd; 40 | 41 | pub fn init(daemon: Cmd, pid_file: &PathBuf) { 42 | match daemon { 43 | Cmd::Start => daemon_start(pid_file), 44 | Cmd::Stop => { 45 | daemon_stop(pid_file); 46 | exit(0); 47 | } 48 | Cmd::Restart => { 49 | daemon_stop(pid_file); 50 | daemon_start(pid_file); 51 | } 52 | _ => {} 53 | } 54 | } 55 | 56 | fn daemon_start(pid_file: &PathBuf) { 57 | let d = daemonize::Daemonize::new().pid_file(pid_file); 58 | if let Err(e) = d.start() { 59 | println!("daemonize failed: {}", e); 60 | let _ = remove_file(pid_file); 61 | exit(1); 62 | } 63 | } 64 | 65 | fn daemon_stop(pid_file: &PathBuf) { 66 | macro_rules! err { 67 | ($fmt:expr) => { 68 | if cfg!(feature = "sslocal") { 69 | println!(concat!("stop sslocal daemon failed: ", $fmt)); 70 | } else { 71 | println!(concat!("stop ssserver daemon failed: ", $fmt)); 72 | } 73 | }; 74 | ($fmt:expr, $($arg:tt)*) => { 75 | if cfg!(feature = "sslocal") { 76 | println!(concat!("stop sslocal daemon failed: ", $fmt), $($arg)*); 77 | } else { 78 | println!(concat!("stop ssserver daemon failed: ", $fmt), $($arg)*); 79 | } 80 | } 81 | } 82 | 83 | let _ = File::open(pid_file) 84 | .map_err(|e| err!("{}", e)) 85 | .and_then(|mut f| { 86 | let mut pid = String::new(); 87 | f.read_to_string(&mut pid) 88 | .map_err(|e| err!("{}", e))?; 89 | let pid = i32::from_str(&pid).map_err(|_| { 90 | err!("{} is not a valid number", pid); 91 | })?; 92 | 93 | if kill!(pid, sig::ffi::Sig::TERM) { 94 | err!("not running"); 95 | } 96 | 97 | // sleep for maximum 10s 98 | let mut timeout = true; 99 | let nap = time::Duration::from_millis(50); 100 | for _ in 0..200 { 101 | if !kill!(pid, 0) { 102 | timeout = false; 103 | break; 104 | } 105 | thread::sleep(nap); 106 | } 107 | if timeout { 108 | err!("timed out"); 109 | } 110 | 111 | Ok(()) 112 | }); 113 | 114 | let _ = remove_file(pid_file); 115 | } 116 | } 117 | 118 | 119 | #[cfg(not(target_family = "unix"))] 120 | mod _daemonize { 121 | use std::path::PathBuf; 122 | use super::Cmd; 123 | 124 | pub fn init(daemon: Cmd, pid_file: &PathBuf) { 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/my_logger.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::fmt; 3 | use std::error::Error; 4 | use std::path::PathBuf; 5 | use std::fs::OpenOptions; 6 | 7 | use chrono::Local; 8 | use slog; 9 | use slog_term; 10 | use slog_stream; 11 | use slog_scope; 12 | use slog::{Level, DrainExt}; 13 | 14 | macro_rules! now { 15 | () => ( Local::now().format("%m-%d %H:%M:%S%.3f") ) 16 | } 17 | 18 | macro_rules! setup_global_logger { 19 | ($lv:expr, $drain:expr) => ( 20 | let d = slog::level_filter($lv, $drain).fuse(); 21 | let logger = slog::Logger::root(d, o!()); 22 | slog_scope::set_global_logger(logger); 23 | ) 24 | } 25 | 26 | pub fn init(log_level: i8, log_path: Option<&PathBuf>) -> Result<(), LoggerInitError> { 27 | let log_level = match log_level { 28 | n if n > 1 => Level::Trace, 29 | 1 => Level::Debug, 30 | 0 => Level::Info, 31 | -1 => Level::Warning, 32 | -2 => Level::Error, 33 | _ => Level::Critical, 34 | }; 35 | 36 | if let Some(log_path) = log_path { 37 | let f = OpenOptions::new() 38 | .create(true) 39 | .write(true) 40 | .truncate(true) 41 | .open(log_path); 42 | 43 | match f { 44 | Ok(file) => { 45 | let streamer = slog_stream::stream(file, MyFormat); 46 | setup_global_logger!(log_level, streamer); 47 | } 48 | Err(_) => { 49 | let errmsg = format!("cannot open log file {:?}", log_path); 50 | return Err(LoggerInitError::new(errmsg)); 51 | } 52 | } 53 | } else { 54 | let drain = slog_term::StreamerBuilder::new() 55 | .use_custom_timestamp(move |io| write!(io, "{}", now!())) 56 | .build(); 57 | setup_global_logger!(log_level, drain); 58 | } 59 | 60 | Ok(()) 61 | } 62 | 63 | 64 | struct MyFormat; 65 | 66 | impl slog_stream::Format for MyFormat { 67 | fn format(&self, 68 | io: &mut io::Write, 69 | rinfo: &slog::Record, 70 | _logger_values: &slog::OwnedKeyValueList) 71 | -> io::Result<()> { 72 | let msg = format!("{} {} - {}\n", now!(), rinfo.level(), rinfo.msg()); 73 | io.write_all(msg.as_bytes()).map(|_| ()) 74 | } 75 | } 76 | 77 | #[derive(Debug)] 78 | pub struct LoggerInitError { 79 | desc: String, 80 | } 81 | 82 | impl LoggerInitError { 83 | fn new(desc: String) -> LoggerInitError { 84 | LoggerInitError { desc: desc } 85 | } 86 | } 87 | 88 | impl fmt::Display for LoggerInitError { 89 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 90 | write!(f, "{}", self.desc) 91 | } 92 | } 93 | 94 | impl Error for LoggerInitError { 95 | fn description(&self) -> &str { 96 | &self.desc 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/network.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::io::Cursor; 3 | use std::convert::From; 4 | use std::str::FromStr; 5 | use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; 6 | 7 | use regex::Regex; 8 | use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt}; 9 | 10 | use error::{SocketError, Result}; 11 | use util::slice2str; 12 | 13 | macro_rules! slice2sized { 14 | ($bytes:expr, $l: expr) => ( 15 | { 16 | let mut arr = [0u8; $l]; 17 | for i in 0..$bytes.len() { 18 | arr[i] = $bytes[i]; 19 | } 20 | 21 | arr 22 | } 23 | ) 24 | } 25 | 26 | #[derive(PartialEq, Eq, Hash, Clone, Debug)] 27 | pub struct Address(pub String, pub u16); 28 | 29 | #[allow(non_camel_case_types)] 30 | pub enum AddressFamily { 31 | AF_INET, 32 | AF_INET6, 33 | } 34 | 35 | pub fn is_ipv4(ip: &str) -> bool { 36 | Ipv4Addr::from_str(ip).is_ok() 37 | } 38 | 39 | pub fn is_ipv6(ip: &str) -> bool { 40 | Ipv6Addr::from_str(ip).is_ok() 41 | } 42 | 43 | pub fn is_ip(ip: &str) -> bool { 44 | is_ipv4(ip) || is_ipv6(ip) 45 | } 46 | 47 | // For detail, see page 7 of RFC 1035 48 | pub fn is_hostname(hostname: &str) -> bool { 49 | if hostname.len() > 255 { 50 | return false; 51 | } 52 | 53 | lazy_static! { 54 | static ref RE: Regex = Regex::new(r"[A-Za-z\d-]{1,63}$").unwrap(); 55 | } 56 | 57 | let hostname = hostname.trim_right_matches('.'); 58 | hostname.as_bytes() 59 | .split(|c| *c == b'.') 60 | .all(|s| { 61 | let s = slice2str(s).unwrap_or(""); 62 | !s.is_empty() && !s.starts_with('-') && !s.ends_with('-') && RE.is_match(s) 63 | }) 64 | } 65 | 66 | pub fn slice2ip4(data: &[u8]) -> Option { 67 | if data.len() >= 4 { 68 | Some(format!("{}", Ipv4Addr::from(slice2sized!(data, 4)))) 69 | } else { 70 | None 71 | } 72 | } 73 | 74 | pub fn slice2ip6(data: &[u8]) -> Option { 75 | if data.len() >= 16 { 76 | Some(format!("{}", Ipv6Addr::from(slice2sized!(data, 16)))) 77 | } else { 78 | None 79 | } 80 | } 81 | 82 | pub fn pair2addr4(ip: &str, port: u16) -> Option { 83 | Ipv4Addr::from_str(ip).map(|ip| SocketAddr::new(IpAddr::V4(ip), port)).ok() 84 | } 85 | 86 | pub fn pair2addr6(ip: &str, port: u16) -> Option { 87 | Ipv6Addr::from_str(ip).map(|ip| SocketAddr::new(IpAddr::V6(ip), port)).ok() 88 | } 89 | 90 | pub fn pair2addr(ip: &str, port: u16) -> Result { 91 | let res = match pair2addr4(ip, port) { 92 | None => pair2addr6(ip, port), 93 | addr => addr, 94 | }; 95 | res.ok_or(From::from(SocketError::ParseAddrFailed(format!("{}:{}", ip, port)))) 96 | } 97 | 98 | pub trait NetworkWriteBytes: WriteBytesExt { 99 | fn put_u8(&mut self, num: u8) -> io::Result<()> { 100 | self.write_u8(num) 101 | } 102 | 103 | fn put_u16(&mut self, num: u16) -> io::Result<()> { 104 | self.write_u16::(num) 105 | } 106 | 107 | fn put_i32(&mut self, num: i32) -> io::Result<()> { 108 | self.write_i32::(num) 109 | } 110 | } 111 | 112 | impl NetworkWriteBytes for Vec {} 113 | 114 | pub trait NetworkReadBytes: ReadBytesExt { 115 | fn get_u8(&mut self) -> io::Result { 116 | self.read_u8() 117 | } 118 | 119 | fn get_u16(&mut self) -> io::Result { 120 | self.read_u16::() 121 | } 122 | 123 | fn get_u32(&mut self) -> io::Result { 124 | self.read_u32::() 125 | } 126 | } 127 | 128 | impl<'a> NetworkReadBytes for Cursor<&'a [u8]> {} 129 | impl<'a> NetworkReadBytes for Cursor<&'a Vec> {} 130 | 131 | impl<'a> NetworkReadBytes for &'a [u8] { 132 | fn get_u8(&mut self) -> io::Result { 133 | Cursor::new(self).read_u8() 134 | } 135 | 136 | fn get_u16(&mut self) -> io::Result { 137 | Cursor::new(self).read_u16::() 138 | } 139 | 140 | fn get_u32(&mut self) -> io::Result { 141 | Cursor::new(self).read_u32::() 142 | } 143 | } 144 | 145 | #[macro_export] 146 | macro_rules! pack { 147 | (i32, $r:expr, $v:expr) => ( try_opt!($r.put_i32($v).ok()) ); 148 | (u16, $r:expr, $v:expr) => ( try_opt!($r.put_u16($v).ok()) ); 149 | (u8, $r:expr, $v:expr) => ( try_opt!($r.put_u8($v).ok()) ); 150 | } 151 | 152 | #[macro_export] 153 | macro_rules! unpack { 154 | (u32, $r:expr) => ( try_opt!($r.get_u32().ok()) ); 155 | (u16, $r:expr) => ( try_opt!($r.get_u16().ok()) ); 156 | (u8, $r:expr) => ( try_opt!($r.get_u8().ok()) ); 157 | } 158 | 159 | #[macro_export] 160 | macro_rules! try_pack { 161 | (i32, $r:expr, $v:expr) => ( $r.put_i32($v)? ); 162 | (u16, $r:expr, $v:expr) => ( $r.put_u16($v)? ); 163 | (u8, $r:expr, $v:expr) => ( $r.put_u8($v)? ); 164 | } 165 | 166 | #[macro_export] 167 | macro_rules! try_unpack { 168 | (u32, $r:expr) => ( $r.get_u32()? ); 169 | (u16, $r:expr) => ( $r.get_u16()? ); 170 | (u8, $r:expr) => ( $r.get_u8()? ); 171 | } 172 | -------------------------------------------------------------------------------- /src/relay/mod.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::net::SocketAddr; 3 | 4 | use mio::{Handler, Token, EventSet, EventLoop}; 5 | 6 | use mode::ServerChooser; 7 | use config::CONFIG; 8 | use network::pair2addr; 9 | use collections::Holder; 10 | use asyncdns::{DnsResolver, Caller, HostIpPair}; 11 | use util::{RcCell, new_rc_cell}; 12 | use error::{DnsError, SocketError, Result}; 13 | use crypto::error::Error as CryptoError; 14 | 15 | pub use self::tcp_relay::TcpRelay; 16 | pub use self::udp_relay::UdpRelay; 17 | pub use self::tcp_processor::TcpProcessor; 18 | pub use self::udp_processor::UdpProcessor; 19 | 20 | pub enum Error { 21 | EnableOneTimeAuthFailed, 22 | NotOneTimeAuthSession, 23 | ConnectFailed(String), 24 | EncryptFailed, 25 | DecryptFailed, 26 | NoServerAvailable, 27 | InitEncryptorFailed(CryptoError), 28 | } 29 | 30 | impl fmt::Debug for Error { 31 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 32 | match *self { 33 | Error::EnableOneTimeAuthFailed => write!(f, "enable one time auth failed"), 34 | Error::NotOneTimeAuthSession => { 35 | write!(f, "current connection is not a one time auth session") 36 | } 37 | Error::ConnectFailed(ref e) => write!(f, "connect to server failed ({})", e), 38 | Error::EncryptFailed => write!(f, "encrypt data failed"), 39 | Error::DecryptFailed => write!(f, "decrypt data failed"), 40 | Error::NoServerAvailable => write!(f, "no ssserver available"), 41 | Error::InitEncryptorFailed(ref e) => write!(f, "init encryptor failed ({:?})", e), 42 | } 43 | } 44 | } 45 | 46 | impl From for Error { 47 | fn from(e: CryptoError) -> Error { 48 | Error::InitEncryptorFailed(e) 49 | } 50 | } 51 | 52 | #[derive(Clone)] 53 | pub enum Relay { 54 | Tcp(RcCell), 55 | Udp(RcCell), 56 | } 57 | 58 | impl Handler for Relay { 59 | type Message = (); 60 | type Timeout = Token; 61 | 62 | fn ready(&mut self, event_loop: &mut EventLoop, token: Token, events: EventSet) { 63 | match self.clone() { 64 | Relay::Tcp(r) => { 65 | r.borrow_mut().ready(event_loop, token, events); 66 | } 67 | Relay::Udp(r) => { 68 | r.borrow_mut().ready(event_loop, token, events); 69 | } 70 | } 71 | } 72 | 73 | fn timeout(&mut self, event_loop: &mut EventLoop, token: Token) { 74 | match self.clone() { 75 | Relay::Tcp(r) => { 76 | r.borrow_mut().timeout(event_loop, token); 77 | } 78 | Relay::Udp(r) => { 79 | r.borrow_mut().timeout(event_loop, token); 80 | } 81 | } 82 | } 83 | } 84 | 85 | pub trait MyHandler { 86 | fn ready(&mut self, event_loop: &mut EventLoop, token: Token, events: EventSet); 87 | fn timeout(&mut self, event_loop: &mut EventLoop, token: Token); 88 | } 89 | 90 | fn init_relay(f: F) -> Result 91 | where F: FnOnce(Token, 92 | Token, 93 | RcCell, 94 | RcCell, 95 | Holder>, 96 | SocketAddr) 97 | -> Result 98 | { 99 | let mut processors = Holder::new(); 100 | let token = processors.alloc_token().ok_or(SocketError::AllocTokenFailed)?; 101 | let dns_token = processors.alloc_token().ok_or(SocketError::AllocTokenFailed)?; 102 | 103 | let mut dns_resolver = DnsResolver::new(dns_token, None, CONFIG.prefer_ipv6)?; 104 | let server_chooser = ServerChooser::new(); 105 | 106 | let host = CONFIG.address().clone(); 107 | let port = CONFIG.port(); 108 | 109 | let HostIpPair(_host, ip) = dns_resolver.block_resolve(host) 110 | .and_then(|h| h.ok_or(From::from(DnsError::Timeout)))?; 111 | 112 | let socket_addr = pair2addr(&ip, port)?; 113 | 114 | f(token, 115 | dns_token, 116 | new_rc_cell(dns_resolver), 117 | new_rc_cell(server_chooser), 118 | processors, 119 | socket_addr) 120 | } 121 | 122 | mod tcp_relay; 123 | mod udp_relay; 124 | mod tcp_processor; 125 | mod udp_processor; 126 | -------------------------------------------------------------------------------- /src/relay/tcp_processor.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::fmt; 3 | use std::sync::Arc; 4 | use std::borrow::{Cow, Borrow}; 5 | use std::io::{Read, Write}; 6 | use std::net::SocketAddr; 7 | 8 | use mio::tcp::{TcpStream, Shutdown}; 9 | use mio::{EventLoop, Token, Timeout, EventSet, PollOpt}; 10 | 11 | use mode::ServerChooser; 12 | use socks5; 13 | use socks5::{addr_type, Socks5Header}; 14 | use util::{RcCell, shift_vec}; 15 | use config::{CONFIG, ProxyConfig}; 16 | use crypto::Encryptor; 17 | use asyncdns::{Caller, DnsResolver, HostIpPair}; 18 | use network::{pair2addr, NetworkWriteBytes, Address}; 19 | use socks5::{pack_addr, parse_header, check_auth_method, CheckAuthResult}; 20 | use error; 21 | use error::{Result, SocketError, ProcessError, Socks5Error}; 22 | use super::Relay; 23 | 24 | pub struct TcpProcessor { 25 | proxy_conf: Arc, 26 | server_chooser: RcCell, 27 | dns_resolver: RcCell, 28 | stage: HandleStage, 29 | timeout: Option, 30 | local_token: Token, 31 | local_sock: TcpStream, 32 | remote_token: Token, 33 | remote_sock: Option, 34 | local_interest: EventSet, 35 | remote_interest: EventSet, 36 | local_buf: Option>, 37 | remote_buf: Option>, 38 | client_address: Address, 39 | server_address: Option
, 40 | encryptor: Encryptor, 41 | } 42 | 43 | impl TcpProcessor { 44 | pub fn new(local_token: Token, 45 | remote_token: Token, 46 | local_sock: TcpStream, 47 | dns_resolver: &RcCell, 48 | server_chooser: &RcCell) 49 | -> Result { 50 | let stage = if cfg!(feature = "sslocal") { 51 | HandleStage::Handshake1 52 | } else { 53 | HandleStage::Handshake3 54 | }; 55 | 56 | let (server_address, proxy_conf) = if cfg!(feature = "sslocal") { 57 | let proxy_conf = 58 | server_chooser.borrow_mut().choose().ok_or(ProcessError::NoServerAvailable)?; 59 | (Some(Address(proxy_conf.address.clone(), proxy_conf.port)), proxy_conf) 60 | } else { 61 | (None, CONFIG.proxy_conf.clone()) 62 | }; 63 | 64 | let encryptor = Encryptor::new(&proxy_conf.password, proxy_conf.method) 65 | .map_err(ProcessError::InitEncryptorFailed)?; 66 | 67 | // TODO: this is a bug of mio 0.5.x (fixed in mio 0.6.x) 68 | let client_address = if cfg!(windows) { 69 | Address("?".to_string(), 0) 70 | } else { 71 | local_sock.peer_addr() 72 | .map(|addr| Address(addr.ip().to_string(), addr.port()))? 73 | }; 74 | 75 | local_sock.set_nodelay(true)?; 76 | 77 | Ok(TcpProcessor { 78 | proxy_conf: proxy_conf, 79 | server_chooser: server_chooser.clone(), 80 | dns_resolver: dns_resolver.clone(), 81 | stage: stage, 82 | timeout: None, 83 | local_token: local_token, 84 | local_sock: local_sock, 85 | remote_token: remote_token, 86 | remote_sock: None, 87 | local_buf: None, 88 | remote_buf: None, 89 | client_address: client_address, 90 | server_address: server_address, 91 | encryptor: encryptor, 92 | local_interest: EventSet::readable(), 93 | remote_interest: EventSet::readable() | EventSet::writable(), 94 | }) 95 | } 96 | 97 | fn get_sock(&mut self, is_local_sock: bool) -> &mut TcpStream { 98 | if is_local_sock { 99 | &mut self.local_sock 100 | } else { 101 | self.remote_sock.as_mut().unwrap() 102 | } 103 | } 104 | 105 | fn get_buf(&mut self, is_local_sock: bool) -> Vec { 106 | if is_local_sock { 107 | if self.local_buf.is_none() { 108 | self.local_buf = Some(Vec::with_capacity(BUF_SIZE)); 109 | } 110 | self.local_buf.take().unwrap() 111 | } else { 112 | if self.remote_buf.is_none() { 113 | self.remote_buf = Some(Vec::with_capacity(BUF_SIZE)); 114 | } 115 | self.remote_buf.take().unwrap() 116 | } 117 | } 118 | 119 | fn set_buf(&mut self, buf: Vec, is_local_sock: bool) { 120 | if is_local_sock { 121 | self.local_buf = Some(buf); 122 | } else { 123 | self.remote_buf = Some(buf); 124 | } 125 | } 126 | 127 | fn extend_buf(&mut self, data: &[u8], is_local_sock: bool) { 128 | let mut buf = self.get_buf(is_local_sock); 129 | buf.extend_from_slice(data); 130 | self.set_buf(buf, is_local_sock); 131 | } 132 | 133 | pub fn reset_timeout(&mut self, event_loop: &mut EventLoop) { 134 | if self.timeout.is_some() { 135 | let timeout = self.timeout.take().unwrap(); 136 | event_loop.clear_timeout(timeout); 137 | } 138 | let delay = self.proxy_conf.timeout as u64 * 1000; 139 | // it's ok if setup timeout failed 140 | self.timeout = event_loop.timeout_ms(self.get_id(), delay).ok(); 141 | } 142 | 143 | fn update_interest_depend_on(&mut self, is_finished: bool, is_local_sock: bool) { 144 | if is_local_sock { 145 | if is_finished { 146 | self.local_interest = EventSet::readable(); 147 | } else { 148 | self.local_interest = EventSet::readable() | EventSet::writable(); 149 | } 150 | } else { 151 | if is_finished { 152 | self.remote_interest = EventSet::readable(); 153 | } else { 154 | self.remote_interest = EventSet::readable() | EventSet::writable(); 155 | } 156 | } 157 | } 158 | 159 | fn do_register(&mut self, 160 | event_loop: &mut EventLoop, 161 | is_local_sock: bool, 162 | is_reregister: bool) 163 | -> Result<()> { 164 | let token = if is_local_sock { 165 | self.local_token 166 | } else { 167 | self.remote_token 168 | }; 169 | let events = if is_local_sock { 170 | self.local_interest 171 | } else { 172 | self.remote_interest 173 | }; 174 | let pollopts = PollOpt::edge() | PollOpt::oneshot(); 175 | 176 | let register_result = if is_reregister { 177 | event_loop.reregister(self.get_sock(is_local_sock), token, events, pollopts) 178 | } else { 179 | event_loop.register(self.get_sock(is_local_sock), token, events, pollopts) 180 | }; 181 | 182 | register_result.map(|_| { 183 | debug!("registered {:?}-{} with {:?}", 184 | self, 185 | if is_local_sock { "local" } else { "remote" }, 186 | events); 187 | }) 188 | .map_err(From::from) 189 | } 190 | 191 | pub fn register(&mut self, 192 | event_loop: &mut EventLoop, 193 | is_local_sock: bool) 194 | -> Result<()> { 195 | self.do_register(event_loop, is_local_sock, REMOTE) 196 | } 197 | 198 | fn reregister(&mut self, event_loop: &mut EventLoop, is_local_sock: bool) -> Result<()> { 199 | self.do_register(event_loop, is_local_sock, LOCAL) 200 | } 201 | 202 | fn record_activity(&self) { 203 | match self.stage { 204 | HandleStage::Handshake3 | 205 | HandleStage::Connecting | 206 | HandleStage::Stream => { 207 | self.server_chooser.borrow_mut().record(self.get_id()); 208 | } 209 | _ => {} 210 | } 211 | } 212 | 213 | fn update_activity(&self) { 214 | match self.stage { 215 | HandleStage::Handshake3 | 216 | HandleStage::Connecting | 217 | HandleStage::Stream => { 218 | self.server_chooser.borrow_mut().update(self.get_id(), &self.proxy_conf); 219 | } 220 | _ => {} 221 | } 222 | } 223 | 224 | fn receive_data(&mut self, is_local_sock: bool) -> Result> { 225 | let mut buf = Vec::with_capacity(BUF_SIZE); 226 | new_fat_slice_from_vec!(buf_slice, buf); 227 | 228 | // to avoid the stupid borrow error 229 | { 230 | let res = self.get_sock(is_local_sock).read(buf_slice); 231 | match res { 232 | Ok(nread) => { 233 | if cfg!(feature = "sslocal") && !is_local_sock { 234 | self.update_activity(); 235 | } 236 | unsafe { 237 | buf.set_len(nread); 238 | } 239 | } 240 | Err(e) => return err_from!(SocketError::ReadFailed(e)), 241 | } 242 | 243 | // no read received which means client closed 244 | if buf.is_empty() { 245 | return err_from!(SocketError::ConnectionClosed); 246 | } 247 | } 248 | 249 | if (cfg!(feature = "sslocal") && !is_local_sock) || 250 | (!cfg!(feature = "sslocal") && is_local_sock) { 251 | self.encryptor.decrypt(&buf).ok_or(From::from(ProcessError::DecryptFailed)) 252 | } else { 253 | Ok(buf) 254 | } 255 | } 256 | 257 | fn write_to_sock(&mut self, data: &[u8], is_local_sock: bool) -> Result { 258 | let nwrite = self.get_sock(is_local_sock) 259 | .write(data) 260 | .map_err(SocketError::WriteFailed)?; 261 | if cfg!(feature = "sslocal") && !is_local_sock { 262 | self.record_activity(); 263 | } 264 | Ok(nwrite) 265 | } 266 | 267 | // data => remote_sock => ssserver/server 268 | fn handle_stage_stream(&mut self, 269 | _event_loop: &mut EventLoop, 270 | data: &[u8]) 271 | -> Result<()> { 272 | trace!("{:?} handle stage stream", self); 273 | 274 | let mut data = Cow::Borrowed(data); 275 | if cfg!(feature = "sslocal") { 276 | match self.encryptor.encrypt(data.borrow()) { 277 | Some(encrypted) => data = Cow::Owned(encrypted), 278 | None => return err_from!(ProcessError::EncryptFailed), 279 | } 280 | } 281 | 282 | let nwrite = self.write_to_sock(data.borrow(), REMOTE)?; 283 | let is_finished = data.len() == nwrite; 284 | if !is_finished { 285 | self.extend_buf(&data[nwrite..], REMOTE); 286 | } 287 | self.update_interest_depend_on(is_finished, REMOTE); 288 | Ok(()) 289 | } 290 | 291 | fn handle_stage_connecting(&mut self, 292 | _event_loop: &mut EventLoop, 293 | data: &[u8]) 294 | -> Result<()> { 295 | trace!("{:?} handle stage connecting", self); 296 | 297 | let mut data = Cow::Borrowed(data); 298 | if cfg!(feature = "sslocal") { 299 | match self.encryptor.encrypt(data.borrow()) { 300 | Some(encrypted) => data = Cow::Owned(encrypted), 301 | None => return err_from!(ProcessError::EncryptFailed), 302 | } 303 | } 304 | 305 | self.extend_buf(data.borrow(), REMOTE); 306 | Ok(()) 307 | } 308 | 309 | fn handle_udp_handshake(&mut self) -> Result<()> { 310 | trace!("{:?} handle udp associate handshake", self); 311 | self.stage = HandleStage::UDPAssoc; 312 | 313 | let addr = self.local_sock.local_addr()?; 314 | let packed_addr = pack_addr(addr.ip()); 315 | let mut packed_port = Vec::::new(); 316 | try_pack!(u16, packed_port, addr.port()); 317 | 318 | let mut header = Vec::with_capacity(32); 319 | // IPv4 header 320 | header.extend_from_slice(&[0x05, 0x00, 0x00]); 321 | header.extend_from_slice(&packed_addr); 322 | header.extend_from_slice(&packed_port); 323 | 324 | self.local_sock.write_all(&header)?; 325 | 326 | Ok(()) 327 | } 328 | 329 | fn check_one_time_auth(&mut self, addr_type: u8) -> Result { 330 | let is_ota_enabled = self.proxy_conf.one_time_auth; 331 | let is_ota_session = if cfg!(feature = "sslocal") { 332 | is_ota_enabled 333 | } else { 334 | addr_type & addr_type::AUTH == addr_type::AUTH 335 | }; 336 | 337 | // if ssserver enabled OTA but client not 338 | if !cfg!(feature = "sslocal") && is_ota_enabled && !is_ota_session { 339 | err_from!(ProcessError::NotOneTimeAuthSession) 340 | } else { 341 | Ok(is_ota_session) 342 | } 343 | } 344 | 345 | fn handle_stage_handshake1(&mut self, 346 | _event_loop: &mut EventLoop, 347 | data: &[u8]) 348 | -> Result<()> { 349 | trace!("{:?} handle stage handshake1", self); 350 | 351 | match check_auth_method(data) { 352 | CheckAuthResult::Success => { 353 | self.write_to_sock(&[0x05, 0x00], LOCAL)?; 354 | self.stage = HandleStage::Handshake2; 355 | Ok(()) 356 | } 357 | res => err_from!(Socks5Error::CheckAuthFailed(res)), 358 | } 359 | } 360 | 361 | // spec `replies` section of https://www.ietf.org/rfc/rfc1928.txt 362 | fn handle_stage_handshake2(&mut self, 363 | event_loop: &mut EventLoop, 364 | mut data: &[u8]) 365 | -> Result<()> { 366 | trace!("{:?} handle stage handshake2", self); 367 | 368 | if cfg!(feature = "sslocal") { 369 | match data[1] { 370 | socks5::cmd::UDP_ASSOCIATE => return self.handle_udp_handshake(), 371 | socks5::cmd::CONNECT => data = &data[3..], 372 | cmd => return err_from!(Socks5Error::UnknownCmd(cmd)), 373 | } 374 | 375 | // +----+-----+-------+------+----------+----------+ 376 | // |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | 377 | // +----+-----+-------+------+----------+----------+ 378 | // | 5 | 0 | 0 | 1/4 | 0 | 0 | 379 | // +----+-----+-------+------+----------+----------+ 380 | // fake ip fake port 381 | let response = match self.local_sock.local_addr() { 382 | Ok(SocketAddr::V6(_)) => { 383 | [0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 384 | } 385 | _ => [0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 386 | }; 387 | self.write_to_sock(&response, LOCAL)?; 388 | } 389 | 390 | if data.is_empty() { 391 | self.stage = HandleStage::Handshake3; 392 | Ok(()) 393 | } else { 394 | self.handle_stage_handshake3(event_loop, data) 395 | } 396 | } 397 | 398 | fn handle_stage_handshake3(&mut self, 399 | event_loop: &mut EventLoop, 400 | data: &[u8]) 401 | -> Result<()> { 402 | trace!("{:?} handle stage handshake3", self); 403 | let Socks5Header(addr_type, remote_address, remote_port, header_length) = 404 | parse_header(data).ok_or(Socks5Error::InvalidHeader)?; 405 | info!("connecting to {}:{}", remote_address, remote_port); 406 | self.stage = HandleStage::Connecting; 407 | 408 | let is_ota_session = self.check_one_time_auth(addr_type)?; 409 | let data = if is_ota_session { 410 | match self.encryptor.enable_ota(addr_type | addr_type::AUTH, header_length, data) { 411 | Some(ota_data) => Cow::Owned(ota_data), 412 | None => return err_from!(ProcessError::EnableOneTimeAuthFailed), 413 | } 414 | } else { 415 | Cow::Borrowed(data) 416 | }; 417 | 418 | // send socks5 response to client 419 | if cfg!(feature = "sslocal") { 420 | match self.encryptor.encrypt(data.borrow()) { 421 | Some(ref data) => self.extend_buf(data, REMOTE), 422 | None => return err_from!(ProcessError::EncryptFailed), 423 | } 424 | } else { 425 | // buffer data 426 | if is_ota_session { 427 | self.extend_buf(&data, REMOTE); 428 | } else if data.len() > header_length { 429 | self.extend_buf(&data[header_length..], REMOTE); 430 | } 431 | 432 | self.server_address = Some(Address(remote_address, remote_port)); 433 | } 434 | 435 | let token = self.get_id(); 436 | let remote_hostname = self.server_address.as_ref().map(|addr| addr.0.clone()).unwrap(); 437 | let resolved_res = self.dns_resolver.borrow_mut().resolve(token, remote_hostname); 438 | if let Ok(None) = resolved_res { 439 | Ok(()) 440 | // if hostname is resolved immediately 441 | } else { 442 | self.handle_dns_resolved(event_loop, resolved_res); 443 | Ok(()) 444 | } 445 | } 446 | 447 | fn on_local_read(&mut self, event_loop: &mut EventLoop) -> Result<()> { 448 | let data = self.receive_data(LOCAL)?; 449 | self.reset_timeout(event_loop); 450 | match self.stage { 451 | HandleStage::Handshake1 => self.handle_stage_handshake1(event_loop, &data), 452 | HandleStage::Handshake2 => self.handle_stage_handshake2(event_loop, &data), 453 | HandleStage::Handshake3 => self.handle_stage_handshake3(event_loop, &data), 454 | HandleStage::Connecting => self.handle_stage_connecting(event_loop, &data), 455 | HandleStage::Stream => self.handle_stage_stream(event_loop, &data), 456 | _ => Ok(()), 457 | } 458 | } 459 | 460 | // remote_sock <= data 461 | fn on_remote_read(&mut self, event_loop: &mut EventLoop) -> Result<()> { 462 | trace!("{:?} on remote read", self); 463 | self.reset_timeout(event_loop); 464 | 465 | let mut data = self.receive_data(REMOTE)?; 466 | if !cfg!(feature = "sslocal") { 467 | match self.encryptor.encrypt(&data) { 468 | Some(encrypted) => data = encrypted, 469 | None => return err_from!(ProcessError::EncryptFailed), 470 | } 471 | } 472 | 473 | // buffer unfinished bytes 474 | let nwrite = self.write_to_sock(&data, LOCAL)?; 475 | if nwrite < data.len() { 476 | self.extend_buf(&data[nwrite..], LOCAL); 477 | } 478 | self.update_interest_depend_on(data.len() == nwrite, LOCAL); 479 | Ok(()) 480 | } 481 | 482 | fn on_write(&mut self, _event_loop: &mut EventLoop, is_local_sock: bool) -> Result<()> { 483 | let mut buf = self.get_buf(is_local_sock); 484 | if !buf.is_empty() { 485 | let nwrite = self.write_to_sock(&buf, is_local_sock)?; 486 | shift_vec(&mut buf, nwrite); 487 | } 488 | self.update_interest_depend_on(buf.is_empty(), is_local_sock); 489 | self.set_buf(buf, is_local_sock); 490 | Ok(()) 491 | } 492 | 493 | fn on_local_write(&mut self, event_loop: &mut EventLoop) -> Result<()> { 494 | self.on_write(event_loop, LOCAL) 495 | } 496 | 497 | fn on_remote_write(&mut self, event_loop: &mut EventLoop) -> Result<()> { 498 | self.stage = HandleStage::Stream; 499 | self.on_write(event_loop, REMOTE) 500 | } 501 | 502 | fn create_connection(&mut self, ip: &str, port: u16) -> Result { 503 | let addr = pair2addr(ip, port)?; 504 | Ok(TcpStream::connect(&addr).and_then(|conn| { 505 | conn.set_nodelay(true)?; 506 | Ok(conn) 507 | })?) 508 | } 509 | 510 | pub fn handle_events(&mut self, 511 | event_loop: &mut EventLoop, 512 | token: Token, 513 | events: EventSet) 514 | -> Result<()> { 515 | debug!("{:?} is handling {:?}", self, self.stage); 516 | 517 | if token == self.local_token { 518 | if events.is_error() { 519 | let e = self.local_sock.take_socket_error().unwrap_err(); 520 | if e.kind() != io::ErrorKind::ConnectionReset { 521 | error!("events error on {:?}-local: {}", self, e); 522 | return err_from!(SocketError::EventError); 523 | } else { 524 | return err_from!(SocketError::ConnectionClosed); 525 | } 526 | } 527 | debug!("{:?} events for {:?}-local", events, self); 528 | 529 | if events.is_readable() || events.is_hup() { 530 | self.on_local_read(event_loop)?; 531 | } 532 | if events.is_writable() { 533 | self.on_local_write(event_loop)?; 534 | } 535 | self.reregister(event_loop, LOCAL) 536 | } else if token == self.remote_token { 537 | if events.is_error() { 538 | let e = self.remote_sock.take().unwrap().take_socket_error().unwrap_err(); 539 | if e.kind() != io::ErrorKind::ConnectionReset { 540 | error!("events error on {:?}-remote: {}", self, e); 541 | return err_from!(SocketError::EventError); 542 | } else { 543 | return err_from!(SocketError::ConnectionClosed); 544 | } 545 | } 546 | debug!("{:?} events for {:?}-remote", events, self); 547 | 548 | if events.is_readable() || events.is_hup() { 549 | self.on_remote_read(event_loop)?; 550 | } 551 | if events.is_writable() { 552 | self.on_remote_write(event_loop)?; 553 | } 554 | self.reregister(event_loop, REMOTE) 555 | } else { 556 | unreachable!(); 557 | } 558 | } 559 | 560 | pub fn destroy(&mut self, event_loop: &mut EventLoop) -> (Token, Token) { 561 | debug!("destroy {:?}", self); 562 | 563 | if let Err(e) = self.local_sock.shutdown(Shutdown::Both) { 564 | if e.kind() != io::ErrorKind::NotConnected { 565 | error!("shutdown {:?}-local failed: {}", self, e); 566 | } 567 | } 568 | 569 | if let Some(sock) = self.remote_sock.take() { 570 | if let Err(e) = sock.shutdown(Shutdown::Both) { 571 | if e.kind() != io::ErrorKind::NotConnected { 572 | error!("shutdown {:?}-remote failed: {}", self, e); 573 | } 574 | } 575 | } 576 | 577 | if let Some(timeout) = self.timeout.take() { 578 | event_loop.clear_timeout(timeout); 579 | } 580 | 581 | if cfg!(feature = "sslocal") { 582 | self.server_chooser.borrow_mut().punish(self.get_id(), &self.proxy_conf); 583 | } 584 | 585 | self.dns_resolver.borrow_mut().remove_caller(self.get_id()); 586 | self.local_interest = EventSet::none(); 587 | self.remote_interest = EventSet::none(); 588 | self.stage = HandleStage::Destroyed; 589 | (self.local_token, self.remote_token) 590 | } 591 | 592 | pub fn fetch_error(&mut self) -> Result<()> { 593 | match self.stage { 594 | HandleStage::Error(ref mut e) => Err(e.take().unwrap()), 595 | _ => Ok(()), 596 | } 597 | } 598 | } 599 | 600 | impl Caller for TcpProcessor { 601 | fn get_id(&self) -> Token { 602 | self.remote_token 603 | } 604 | 605 | fn handle_dns_resolved(&mut self, 606 | event_loop: &mut EventLoop, 607 | res: Result>) { 608 | debug!("{:?} dns resolved: {:?}", self, res); 609 | 610 | macro_rules! my_try { 611 | ($r:expr) => ( 612 | match $r { 613 | Ok(r) => r, 614 | Err(e) => { 615 | self.stage = HandleStage::Error(Some(e)); 616 | return; 617 | } 618 | } 619 | ) 620 | } 621 | 622 | if let Some(HostIpPair(_hostname, ip)) = my_try!(res) { 623 | let port = self.server_address 624 | .as_ref() 625 | .map(|addr| addr.1) 626 | .unwrap(); 627 | 628 | let sock = my_try!(self.create_connection(&ip, port)); 629 | self.remote_sock = Some(sock); 630 | my_try!(self.register(event_loop, REMOTE)); 631 | my_try!(self.reregister(event_loop, LOCAL)); 632 | } else { 633 | error!("resolve dns failed: empty response"); 634 | } 635 | } 636 | } 637 | 638 | impl fmt::Debug for TcpProcessor { 639 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 640 | let Address(ref ip, ref port) = self.client_address; 641 | write!(f, "{}:{}/tcp", ip, port) 642 | } 643 | } 644 | 645 | const BUF_SIZE: usize = 32 * 1024; 646 | pub const LOCAL: bool = true; 647 | pub const REMOTE: bool = false; 648 | 649 | // for each opening port, we have a TcpRelay 650 | // for each connection, we have a TcpProcessor to handle the connection 651 | // 652 | // for each handler, we have 2 sockets: 653 | // local: connected to the client 654 | // remote: connected to remote server 655 | 656 | // for each handler, it could be at one of several stages: 657 | #[derive(Debug)] 658 | enum HandleStage { 659 | // only sslocal: auth METHOD received from local, reply with selection message 660 | Handshake1, 661 | Handshake2, 662 | Handshake3, 663 | // only sslocal: UDP assoc 664 | UDPAssoc, 665 | // connecting to remote server, more data from local received 666 | Connecting, 667 | // remote connected, piping local and remote 668 | Stream, 669 | Destroyed, 670 | Error(Option), 671 | } 672 | -------------------------------------------------------------------------------- /src/relay/tcp_relay.rs: -------------------------------------------------------------------------------- 1 | use mio::tcp::{TcpListener, TcpStream}; 2 | use mio::{Token, EventSet, EventLoop, PollOpt}; 3 | 4 | use mode::ServerChooser; 5 | use collections::Holder; 6 | use asyncdns::DnsResolver; 7 | use util::{RcCell, new_rc_cell}; 8 | use error::{Result, SocketError, Error as UnionError}; 9 | use super::{init_relay, TcpProcessor, MyHandler, Relay}; 10 | use super::tcp_processor::LOCAL; 11 | 12 | pub struct TcpRelay { 13 | token: Token, 14 | listener: TcpListener, 15 | dns_token: Token, 16 | dns_resolver: RcCell, 17 | server_chooser: RcCell, 18 | processors: Holder>, 19 | } 20 | 21 | impl TcpRelay { 22 | pub fn new() -> Result { 23 | init_relay(|token, dns_token, dns_resolver, server_chooser, processors, socket_addr| { 24 | let listener = 25 | TcpListener::bind(&socket_addr).or(Err(SocketError::BindAddrFailed(socket_addr)))?; 26 | 27 | if cfg!(feature = "sslocal") { 28 | info!("ssclient tcp relay listen on {}", socket_addr); 29 | } else { 30 | info!("ssserver tcp relay listen on {}", socket_addr); 31 | } 32 | 33 | Ok(TcpRelay { 34 | token: token, 35 | listener: listener, 36 | dns_token: dns_token, 37 | dns_resolver: dns_resolver, 38 | server_chooser: server_chooser, 39 | processors: processors, 40 | }) 41 | }) 42 | } 43 | 44 | /// start event loop 45 | pub fn run(self) -> Result<()> { 46 | let mut event_loop = EventLoop::new()?; 47 | event_loop.register(&self.listener, 48 | self.token, 49 | EventSet::readable(), 50 | PollOpt::edge() | PollOpt::oneshot()) 51 | .or(Err(SocketError::RegisterFailed))?; 52 | self.dns_resolver 53 | .borrow_mut() 54 | .register(&mut event_loop) 55 | .or(Err(SocketError::RegisterFailed))?; 56 | let this = new_rc_cell(self); 57 | event_loop.run(&mut Relay::Tcp(this))?; 58 | Ok(()) 59 | } 60 | 61 | fn destroy_processor(&mut self, event_loop: &mut EventLoop, token: Token) { 62 | let tokens = self.processors[token].borrow_mut().destroy(event_loop); 63 | self.processors.remove(tokens.0); 64 | self.processors.remove(tokens.1); 65 | } 66 | 67 | fn create_processor(&mut self, 68 | event_loop: &mut EventLoop, 69 | local_token: Token, 70 | remote_token: Token, 71 | conn: TcpStream) 72 | -> Result<()> { 73 | let p = TcpProcessor::new(local_token, 74 | remote_token, 75 | conn, 76 | &self.dns_resolver, 77 | &self.server_chooser)?; 78 | let p = new_rc_cell(p); 79 | self.processors.insert_with(local_token, p.clone()); 80 | self.processors.insert_with(remote_token, p.clone()); 81 | 82 | p.borrow_mut().reset_timeout(event_loop); 83 | self.dns_resolver.borrow_mut().add_caller(p.clone()); 84 | let res = p.borrow_mut().register(event_loop, LOCAL); 85 | match res { 86 | Err(e) => { 87 | self.destroy_processor(event_loop, local_token); 88 | Err(e) 89 | } 90 | res => res, 91 | } 92 | } 93 | 94 | /// Create `TcpProcessor` to handle the new TCP connection. 95 | fn handle_events(&mut self, event_loop: &mut EventLoop, events: EventSet) -> Result<()> { 96 | event_loop.reregister(&self.listener, 97 | self.token, 98 | EventSet::readable(), 99 | PollOpt::edge() | PollOpt::oneshot())?; 100 | if events.is_error() { 101 | error!("events error on tcp relay: {:?}", 102 | self.listener.take_socket_error().unwrap_err()); 103 | return err_from!(SocketError::EventError); 104 | } 105 | 106 | match self.listener.accept()? { 107 | Some((conn, _addr)) => { 108 | debug!("create tcp processor for {}", _addr); 109 | let tokens = (self.processors.alloc_token(), self.processors.alloc_token()); 110 | if let (Some(local_token), Some(remote_token)) = tokens { 111 | self.create_processor(event_loop, local_token, remote_token, conn) 112 | } else { 113 | match tokens { 114 | (None, None) => {} 115 | (Some(t), None) | (None, Some(t)) => { 116 | self.processors.remove(t); 117 | } 118 | _ => {} 119 | } 120 | err_from!(SocketError::AllocTokenFailed) 121 | } 122 | } 123 | None => Ok(()), 124 | } 125 | } 126 | } 127 | 128 | impl MyHandler for TcpRelay { 129 | /// Dispatch events to relative handler. 130 | fn ready(&mut self, event_loop: &mut EventLoop, token: Token, events: EventSet) { 131 | if token == self.token { 132 | if let Err(e) = self.handle_events(event_loop, events) { 133 | error!("tcp relay: {:?}", e); 134 | } 135 | } else if token == self.dns_token { 136 | if let Err(e) = self.dns_resolver.borrow_mut().handle_events(event_loop, events) { 137 | error!("dns resolver: {:?}", e); 138 | } 139 | } else { 140 | let res = self.processors.get(token).map(|p| { 141 | p.borrow_mut().fetch_error()?; 142 | p.borrow_mut().handle_events(event_loop, token, events) 143 | }); 144 | if let Some(Err(e)) = res { 145 | match e { 146 | UnionError::SocketError(SocketError::ConnectionClosed) => {} 147 | _ => { 148 | error!("{:?}: {:?}", 149 | &self.processors[token].borrow() as &TcpProcessor, 150 | e) 151 | } 152 | } 153 | self.destroy_processor(event_loop, token); 154 | } 155 | } 156 | } 157 | 158 | fn timeout(&mut self, event_loop: &mut EventLoop, token: Token) { 159 | self.processors.get(token).map(|p| { 160 | debug!("{:?} timed out", p); 161 | }); 162 | self.destroy_processor(event_loop, token); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/relay/udp_processor.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::sync::Arc; 3 | use std::borrow::Cow; 4 | use std::convert::From; 5 | use std::net::SocketAddr; 6 | 7 | use mio::udp::UdpSocket; 8 | use mio::{EventSet, Token, Timeout, EventLoop, PollOpt}; 9 | 10 | use mode::ServerChooser; 11 | use util::RcCell; 12 | use config::{CONFIG, ProxyConfig}; 13 | use collections::Dict; 14 | use crypto::Encryptor; 15 | use socks5::{parse_header, pack_addr, addr_type, Socks5Header}; 16 | use network::{pair2addr, NetworkWriteBytes}; 17 | use asyncdns::{Caller, DnsResolver, HostIpPair}; 18 | use error; 19 | use error::{Result, SocketError, ProcessError, Socks5Error}; 20 | use super::Relay; 21 | 22 | type Socks5Requests = Vec>; 23 | type PortRequestMap = Dict; 24 | 25 | pub struct UdpProcessor { 26 | proxy_conf: Arc, 27 | server_chooser: RcCell, 28 | token: Token, 29 | stage: HandleStage, 30 | interest: EventSet, 31 | timeout: Option, 32 | addr: SocketAddr, 33 | sock: UdpSocket, 34 | relay_sock: RcCell, 35 | receive_buf: Option>, 36 | requests: Dict, 37 | dns_resolver: RcCell, 38 | encryptor: RcCell, 39 | } 40 | 41 | impl UdpProcessor { 42 | pub fn new(token: Token, 43 | addr: SocketAddr, 44 | relay_sock: &RcCell, 45 | proxy_conf: &Arc, 46 | dns_resolver: &RcCell, 47 | server_chooser: &RcCell, 48 | encryptor: &RcCell) 49 | -> Result { 50 | let sock = if CONFIG.prefer_ipv6 { 51 | UdpSocket::v6() 52 | } else { 53 | UdpSocket::v4() 54 | }; 55 | 56 | let sock = sock.map_err(|_| SocketError::InitSocketFailed)?; 57 | 58 | Ok(UdpProcessor { 59 | proxy_conf: proxy_conf.clone(), 60 | token: token, 61 | stage: HandleStage::Init, 62 | interest: EventSet::readable(), 63 | timeout: None, 64 | addr: addr, 65 | sock: sock, 66 | relay_sock: relay_sock.clone(), 67 | receive_buf: Some(Vec::with_capacity(BUF_SIZE)), 68 | requests: Dict::default(), 69 | encryptor: encryptor.clone(), 70 | dns_resolver: dns_resolver.clone(), 71 | server_chooser: server_chooser.clone(), 72 | }) 73 | } 74 | 75 | pub fn addr(&self) -> &SocketAddr { 76 | &self.addr 77 | } 78 | 79 | pub fn reset_timeout(&mut self, event_loop: &mut EventLoop) { 80 | if self.timeout.is_some() { 81 | let timeout = self.timeout.take().unwrap(); 82 | event_loop.clear_timeout(timeout); 83 | } 84 | let delay = self.proxy_conf.timeout as u64 * 1000; 85 | self.timeout = event_loop.timeout_ms(self.get_id(), delay).ok(); 86 | } 87 | 88 | fn do_register(&mut self, 89 | event_loop: &mut EventLoop, 90 | is_reregister: bool) 91 | -> Result<()> { 92 | let token = self.get_id(); 93 | let pollopts = PollOpt::edge() | PollOpt::oneshot(); 94 | 95 | let register_result = if is_reregister { 96 | event_loop.reregister(&self.sock, token, self.interest, pollopts) 97 | } else { 98 | event_loop.register(&self.sock, token, self.interest, pollopts) 99 | }; 100 | 101 | register_result.map(|_| { 102 | debug!("registered {:?} socket with {:?}", self, self.interest); 103 | }) 104 | .map_err(From::from) 105 | } 106 | 107 | pub fn register(&mut self, event_loop: &mut EventLoop) -> Result<()> { 108 | self.do_register(event_loop, false) 109 | } 110 | 111 | fn reregister(&mut self, event_loop: &mut EventLoop) -> Result<()> { 112 | self.do_register(event_loop, true) 113 | } 114 | 115 | fn record_activity(&mut self) { 116 | match self.stage { 117 | HandleStage::Addr | HandleStage::Stream => { 118 | self.server_chooser.borrow_mut().record(self.token); 119 | } 120 | _ => {} 121 | } 122 | } 123 | 124 | fn update_activity(&mut self) { 125 | match self.stage { 126 | HandleStage::Addr | HandleStage::Stream => { 127 | self.server_chooser.borrow_mut().update(self.token, &self.proxy_conf); 128 | } 129 | _ => {} 130 | } 131 | } 132 | 133 | fn add_request(&mut self, server_addr: String, server_port: u16, data: Vec) { 134 | if !self.requests.contains_key(&server_addr) { 135 | self.requests.insert(server_addr.clone(), Dict::default()); 136 | } 137 | let port_requests_map = self.requests.get_mut(&server_addr).unwrap(); 138 | port_requests_map.entry(server_port).or_insert(vec![]).push(data); 139 | } 140 | 141 | fn send_to(&self, 142 | is_send_to_client: bool, 143 | data: &[u8], 144 | addr: &SocketAddr) 145 | -> Result> { 146 | let res = if is_send_to_client { 147 | self.sock.send_to(data, addr) 148 | } else { 149 | self.relay_sock.borrow().send_to(data, addr) 150 | }; 151 | 152 | res.map_err(|e| From::from(SocketError::WriteFailed(e))) 153 | } 154 | 155 | pub fn handle_request(&mut self, 156 | event_loop: &mut EventLoop, 157 | data: &[u8], 158 | header: Socks5Header) 159 | -> Result<()> { 160 | let Socks5Header(addr_type, remote_address, remote_port, header_length) = header; 161 | info!("sending udp request to {}:{}", remote_address, remote_port); 162 | self.stage = HandleStage::Addr; 163 | self.reset_timeout(event_loop); 164 | 165 | let is_ota_enabled = self.proxy_conf.one_time_auth; 166 | let request = if cfg!(feature = "sslocal") { 167 | // if is a OTA session 168 | let encrypted: Option> = if is_ota_enabled { 169 | self.encryptor.borrow_mut().encrypt_udp_ota(addr_type | addr_type::AUTH, data) 170 | } else { 171 | self.encryptor.borrow_mut().encrypt_udp(data) 172 | }; 173 | let encrypted = encrypted.ok_or({ 174 | let err: error::Error = From::from(ProcessError::EncryptFailed); 175 | err 176 | })?; 177 | Cow::Owned(encrypted) 178 | } else { 179 | // if is a OTA session 180 | if addr_type & addr_type::AUTH == addr_type::AUTH { 181 | let decrypted: Option> = self.encryptor 182 | .borrow_mut() 183 | .decrypt_udp_ota(addr_type, data); 184 | let decrypted = decrypted.ok_or({ 185 | let err: error::Error = From::from(ProcessError::DecryptFailed); 186 | err 187 | })?; 188 | Cow::Owned(decrypted) 189 | // if ssserver enabled OTA but client not 190 | } else if is_ota_enabled { 191 | return err_from!(ProcessError::NotOneTimeAuthSession); 192 | } else { 193 | Cow::Borrowed(data) 194 | } 195 | }; 196 | 197 | let server_addr = if cfg!(feature = "sslocal") { 198 | self.record_activity(); 199 | let server_addr = self.proxy_conf.address.clone(); 200 | let server_port = self.proxy_conf.port; 201 | self.add_request(server_addr.clone(), server_port, request.into_owned()); 202 | server_addr 203 | } else { 204 | let request = request[header_length..].to_vec(); 205 | self.add_request(remote_address.clone(), remote_port, request); 206 | remote_address 207 | }; 208 | 209 | let resolved = self.dns_resolver.borrow_mut().resolve(self.token, server_addr); 210 | match resolved { 211 | Ok(None) => {} 212 | // if hostname is resolved immediately 213 | res => self.handle_dns_resolved(event_loop, res), 214 | } 215 | Ok(()) 216 | } 217 | 218 | fn on_remote_read(&mut self, event_loop: &mut EventLoop) -> Result> { 219 | trace!("{:?} handle stage stream", self); 220 | self.stage = HandleStage::Stream; 221 | self.reset_timeout(event_loop); 222 | 223 | let mut buf = self.receive_buf.take().unwrap(); 224 | new_fat_slice_from_vec!(buf_slice, buf); 225 | 226 | let res = self.sock.recv_from(buf_slice).map_err(SocketError::ReadFailed)?; 227 | let res = match res { 228 | None => Ok(None), 229 | Some((nread, addr)) => { 230 | unsafe { 231 | buf.set_len(nread); 232 | } 233 | 234 | if cfg!(feature = "sslocal") { 235 | self.update_activity(); 236 | match self.encryptor.borrow_mut().decrypt_udp(&buf) { 237 | Some(data) => { 238 | if parse_header(&data).is_some() { 239 | let mut response = Vec::with_capacity(3 + data.len()); 240 | response.extend_from_slice(&[0u8; 3]); 241 | response.extend_from_slice(&data); 242 | self.send_to(SERVER, &response, &self.addr) 243 | } else { 244 | err_from!(Socks5Error::InvalidHeader) 245 | } 246 | } 247 | None => err_from!(ProcessError::DecryptFailed), 248 | } 249 | } else { 250 | // construct a socks5 request 251 | let packed_addr = pack_addr(addr.ip()); 252 | let mut packed_port = Vec::::new(); 253 | try_pack!(u16, packed_port, addr.port()); 254 | 255 | let mut data = Vec::with_capacity(packed_addr.len() + packed_port.len() + 256 | buf.len()); 257 | data.extend_from_slice(&packed_addr); 258 | data.extend_from_slice(&packed_port); 259 | data.extend_from_slice(&buf); 260 | 261 | match self.encryptor.borrow_mut().encrypt_udp(&data) { 262 | Some(response) => self.send_to(SERVER, &response, &self.addr), 263 | None => err_from!(ProcessError::EncryptFailed), 264 | } 265 | } 266 | } 267 | }; 268 | 269 | self.receive_buf = Some(buf); 270 | res 271 | } 272 | 273 | // send to up stream 274 | pub fn handle_events(&mut self, 275 | event_loop: &mut EventLoop, 276 | _token: Token, 277 | events: EventSet) 278 | -> Result<()> { 279 | debug!("current handle stage of {:?} is {:?}", self, self.stage); 280 | 281 | if events.is_error() { 282 | error!("{:?} got a events error", self); 283 | return err_from!(SocketError::EventError); 284 | } 285 | 286 | self.on_remote_read(event_loop)?; 287 | self.reregister(event_loop) 288 | } 289 | 290 | pub fn destroy(&mut self, event_loop: &mut EventLoop) { 291 | debug!("destroy {:?}", self); 292 | 293 | if let Some(timeout) = self.timeout.take() { 294 | event_loop.clear_timeout(timeout); 295 | } 296 | 297 | if cfg!(feature = "sslocal") { 298 | self.server_chooser.borrow_mut().punish(self.get_id(), &self.proxy_conf); 299 | } 300 | 301 | self.dns_resolver.borrow_mut().remove_caller(self.get_id()); 302 | self.interest = EventSet::none(); 303 | self.receive_buf = None; 304 | self.stage = HandleStage::Destroyed; 305 | } 306 | } 307 | 308 | impl Caller for UdpProcessor { 309 | fn get_id(&self) -> Token { 310 | self.token 311 | } 312 | 313 | fn handle_dns_resolved(&mut self, 314 | _event_loop: &mut EventLoop, 315 | res: Result>) { 316 | debug!("{:?} handle dns resolved: {:?}", self, res); 317 | self.stage = HandleStage::Dns; 318 | 319 | macro_rules! my_try { 320 | ($r:expr) => ( 321 | match $r { 322 | Ok(r) => r, 323 | Err(e) => { 324 | self.stage = HandleStage::Error(Some(e)); 325 | return; 326 | } 327 | } 328 | ) 329 | } 330 | 331 | if let Some(HostIpPair(hostname, ip)) = my_try!(res) { 332 | if let Some(port_requests_map) = self.requests.remove(&hostname) { 333 | for (port, requests) in &port_requests_map { 334 | let server_addr = my_try!(pair2addr(&ip, port.clone())); 335 | for request in requests { 336 | my_try!(self.send_to(CLIENT, request, &server_addr)); 337 | } 338 | } 339 | } else { 340 | let err = error::Error::Other(format!("unknown host {}", hostname)); 341 | self.stage = HandleStage::Error(Some(err)); 342 | return; 343 | } 344 | } 345 | } 346 | } 347 | 348 | 349 | impl fmt::Debug for UdpProcessor { 350 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 351 | write!(f, "{:?}/udp", self.addr) 352 | } 353 | } 354 | 355 | const BUF_SIZE: usize = 64 * 1024; 356 | const CLIENT: bool = true; 357 | const SERVER: bool = false; 358 | 359 | #[derive(Debug)] 360 | enum HandleStage { 361 | Init, 362 | // only sslocal: auth METHOD received from local, reply with selection message 363 | Addr, 364 | // DNS resolved, connect to remote 365 | Dns, 366 | Stream, 367 | Destroyed, 368 | Error(Option), 369 | } 370 | -------------------------------------------------------------------------------- /src/relay/udp_relay.rs: -------------------------------------------------------------------------------- 1 | // SOCKS5 UDP Request/Response 2 | // +----+------+------+----------+----------+----------+ 3 | // |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | 4 | // +----+------+------+----------+----------+----------+ 5 | // | 2 | 1 | 1 | Variable | 2 | Variable | 6 | // +----+------+------+----------+----------+----------+ 7 | 8 | // shadowsocks UDP Request/Response (before encrypted) 9 | // +------+----------+----------+----------+ 10 | // | ATYP | DST.ADDR | DST.PORT | DATA | 11 | // +------+----------+----------+----------+ 12 | // | 1 | Variable | 2 | Variable | 13 | // +------+----------+----------+----------+ 14 | 15 | // shadowsocks UDP Request/Response (after encrypted) 16 | // +-------+--------------+ 17 | // | IV | PAYLOAD | 18 | // +-------+--------------+ 19 | // | Fixed | Variable | 20 | // +-------+--------------+ 21 | use std::sync::Arc; 22 | use std::net::SocketAddr; 23 | 24 | use mio::udp::UdpSocket; 25 | use mio::{Token, EventSet, EventLoop, PollOpt}; 26 | 27 | use mode::ServerChooser; 28 | use util::{RcCell, new_rc_cell}; 29 | use config::{CONFIG, ProxyConfig}; 30 | use socks5::parse_header; 31 | use crypto::Encryptor; 32 | use asyncdns::DnsResolver; 33 | use collections::{Holder, Dict}; 34 | use error::{Result, SocketError, Error as UnionError, Socks5Error, ProcessError}; 35 | use super::{init_relay, Relay, MyHandler, UdpProcessor}; 36 | 37 | // only receive data from client/sslocal, 38 | // and relay the data to `UdpProcessor` 39 | pub struct UdpRelay { 40 | proxy_conf: Arc, 41 | server_chooser: RcCell, 42 | dns_resolver: RcCell, 43 | token: Token, 44 | interest: EventSet, 45 | listener: RcCell, 46 | receive_buf: Option>, 47 | dns_token: Token, 48 | cache: Dict>, 49 | processors: Holder>, 50 | encryptor: RcCell, 51 | } 52 | 53 | impl UdpRelay { 54 | pub fn new() -> Result { 55 | init_relay(|token, dns_token, dns_resolver, server_chooser, processors, socket_addr| { 56 | let proxy_conf = if cfg!(feature = "sslocal") { 57 | server_chooser.borrow_mut().choose().ok_or(ProcessError::NoServerAvailable)? 58 | } else { 59 | CONFIG.proxy_conf.clone() 60 | }; 61 | 62 | let encryptor = Encryptor::new(&proxy_conf.password, proxy_conf.method) 63 | .map_err(ProcessError::InitEncryptorFailed)?; 64 | 65 | let listener = if CONFIG.prefer_ipv6 { 66 | UdpSocket::v6() 67 | } else { 68 | UdpSocket::v4() 69 | }; 70 | let listener = listener.map_err(|_| SocketError::InitSocketFailed)?; 71 | listener.bind(&socket_addr).map_err(|_| SocketError::BindAddrFailed(socket_addr))?; 72 | 73 | if cfg!(feature = "sslocal") { 74 | info!("ssclient udp relay listen on {}", socket_addr); 75 | } else { 76 | info!("ssserver udp relay listen on {}", socket_addr); 77 | } 78 | 79 | Ok(UdpRelay { 80 | proxy_conf: proxy_conf, 81 | server_chooser: server_chooser, 82 | dns_resolver: dns_resolver, 83 | token: token, 84 | interest: EventSet::readable(), 85 | receive_buf: Some(Vec::with_capacity(BUF_SIZE)), 86 | listener: new_rc_cell(listener), 87 | dns_token: dns_token, 88 | cache: Dict::default(), 89 | processors: processors, 90 | encryptor: new_rc_cell(encryptor), 91 | }) 92 | }) 93 | } 94 | 95 | pub fn run(self) -> Result<()> { 96 | let mut event_loop = EventLoop::new()?; 97 | event_loop.register(&*self.listener.borrow(), 98 | self.token, 99 | self.interest, 100 | PollOpt::edge() | PollOpt::oneshot()) 101 | .or(Err(SocketError::RegisterFailed))?; 102 | self.dns_resolver 103 | .borrow_mut() 104 | .register(&mut event_loop) 105 | .or(Err(SocketError::RegisterFailed))?; 106 | 107 | let this = new_rc_cell(self); 108 | event_loop.run(&mut Relay::Udp(this))?; 109 | Ok(()) 110 | } 111 | 112 | fn remove_processor(&mut self, token: Token) -> Option> { 113 | let p = try_opt!(self.processors.remove(token)); 114 | let res = self.cache.remove(p.borrow().addr()); 115 | res 116 | } 117 | 118 | fn destroy_processor(&mut self, event_loop: &mut EventLoop, token: Token) { 119 | self.processors[token].borrow_mut().destroy(event_loop); 120 | self.remove_processor(token); 121 | } 122 | 123 | fn create_processor(&mut self, 124 | event_loop: &mut EventLoop, 125 | token: Token, 126 | client_addr: SocketAddr) 127 | -> Result<()> { 128 | let p = new_rc_cell(UdpProcessor::new(token, 129 | client_addr, 130 | &self.listener, 131 | &self.proxy_conf, 132 | &self.dns_resolver, 133 | &self.server_chooser, 134 | &self.encryptor)?); 135 | self.processors.insert_with(token, p.clone()); 136 | self.cache.insert(client_addr, p.clone()); 137 | self.dns_resolver.borrow_mut().add_caller(p.clone()); 138 | let res = p.borrow_mut().register(event_loop).map_err(|e| { 139 | self.destroy_processor(event_loop, token); 140 | e 141 | }); 142 | res 143 | } 144 | 145 | // handle data from client or sslocal 146 | fn handle_request(&mut self, 147 | event_loop: &mut EventLoop, 148 | client_addr: SocketAddr, 149 | data: &[u8]) 150 | -> Result<()> { 151 | // parse socks5 header 152 | match parse_header(data) { 153 | Some(header) => { 154 | if !self.cache.contains_key(&client_addr) { 155 | debug!("create udp processor for {:?}", client_addr); 156 | let token = self.processors.alloc_token().ok_or(SocketError::AllocTokenFailed)?; 157 | self.create_processor(event_loop, token, client_addr)?; 158 | } 159 | 160 | if data.len() > 0 { 161 | let p = &self.cache[&client_addr]; 162 | p.borrow_mut().handle_request(event_loop, data, header)?; 163 | } 164 | Ok(()) 165 | } 166 | None => err_from!(Socks5Error::InvalidHeader), 167 | } 168 | } 169 | 170 | fn handle_events(&mut self, event_loop: &mut EventLoop, events: EventSet) -> Result<()> { 171 | event_loop.reregister(&*self.listener.borrow(), 172 | self.token, 173 | self.interest, 174 | PollOpt::edge() | PollOpt::oneshot())?; 175 | if events.is_error() { 176 | error!("events error on udp relay"); 177 | return err_from!(SocketError::EventError); 178 | } 179 | 180 | let mut buf = self.receive_buf.take().unwrap(); 181 | new_fat_slice_from_vec!(buf_slice, buf); 182 | 183 | let mut res = Ok(()); 184 | let result = self.listener.borrow().recv_from(buf_slice); 185 | match result { 186 | Ok(None) => {} 187 | Ok(Some((nwrite, addr))) => { 188 | debug!("received udp request from {}", addr); 189 | if nwrite < 3 { 190 | warn!("handshake header of udp request is too short"); 191 | } else { 192 | unsafe { 193 | buf.set_len(nwrite); 194 | } 195 | if cfg!(feature = "sslocal") { 196 | if buf[2] == 0 { 197 | // skip REV and FRAG fields 198 | res = self.handle_request(event_loop, addr, &buf[3..]); 199 | } else { 200 | warn!("drop the udp request since FRAG is not 0"); 201 | } 202 | } else { 203 | let decrypted = self.encryptor.borrow_mut().decrypt_udp(&buf); 204 | match decrypted { 205 | Some(data) => { 206 | res = self.handle_request(event_loop, addr, &data); 207 | } 208 | None => { 209 | res = err_from!(ProcessError::DecryptFailed); 210 | } 211 | } 212 | } 213 | } 214 | } 215 | Err(e) => error!("udp relay receive data failed: {}", e), 216 | } 217 | 218 | self.receive_buf = Some(buf); 219 | res 220 | } 221 | } 222 | 223 | impl MyHandler for UdpRelay { 224 | fn ready(&mut self, event_loop: &mut EventLoop, token: Token, events: EventSet) { 225 | if token == self.token { 226 | if let Err(e) = self.handle_events(event_loop, events) { 227 | error!("udp relay: {:?}", e); 228 | } 229 | } else if token == self.dns_token { 230 | if let Err(e) = self.dns_resolver.borrow_mut().handle_events(event_loop, events) { 231 | error!("dns resolver: {:?}", e); 232 | } 233 | } else { 234 | let res = self.processors 235 | .get(token) 236 | .map(|p| p.borrow_mut().handle_events(event_loop, token, events)); 237 | if let Some(Err(e)) = res { 238 | match e { 239 | UnionError::SocketError(SocketError::ConnectionClosed) => {} 240 | _ => { 241 | error!("{:?}: {:?}", 242 | &self.processors[token].borrow() as &UdpProcessor, 243 | e) 244 | } 245 | } 246 | self.destroy_processor(event_loop, token); 247 | } 248 | } 249 | } 250 | 251 | fn timeout(&mut self, event_loop: &mut EventLoop, token: Token) { 252 | self.processors.get(token).map(|p| { 253 | debug!("{:?} timed out", p); 254 | }); 255 | self.destroy_processor(event_loop, token); 256 | } 257 | } 258 | 259 | const BUF_SIZE: usize = 64 * 1024; 260 | -------------------------------------------------------------------------------- /src/socks5.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::net::IpAddr; 3 | 4 | use network::{slice2ip4, slice2ip6, NetworkReadBytes}; 5 | 6 | pub enum Error { 7 | CheckAuthFailed(CheckAuthResult), 8 | UnknownCmd(u8), 9 | InvalidHeader, 10 | } 11 | 12 | impl fmt::Debug for Error { 13 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 14 | match *self { 15 | Error::CheckAuthFailed(ref r) => { 16 | match *r { 17 | CheckAuthResult::BadSocksHeader => write!(f, "bad socks5 header"), 18 | CheckAuthResult::NoAcceptableMethods => { 19 | write!(f, "no acceptable socks5 methods") 20 | } 21 | _ => unreachable!(), 22 | } 23 | } 24 | Error::UnknownCmd(cmd) => write!(f, "unknown socks5 command: {}", cmd), 25 | Error::InvalidHeader => write!(f, "invalid socks5 header"), 26 | } 27 | } 28 | } 29 | 30 | // (addr_type, dest_addr, dest_port, header_length) 31 | pub struct Socks5Header(pub u8, pub String, pub u16, pub usize); 32 | 33 | #[derive(Debug, PartialEq)] 34 | pub enum CheckAuthResult { 35 | Success, 36 | BadSocksHeader, 37 | NoAcceptableMethods, 38 | } 39 | 40 | // +------+----------+----------+----------+ 41 | // | ATYP | DST.ADDR | DST.PORT | DATA | 42 | // +------+----------+----------+----------+ 43 | // | 1 | Variable | 2 | Variable | 44 | // +------+----------+----------+----------+ 45 | pub fn parse_header(data: &[u8]) -> Option { 46 | let addr_type = data[0]; 47 | let mut dest_addr = None; 48 | let mut dest_port = 0; 49 | let mut header_len = 0; 50 | 51 | match addr_type & addr_type::MASK { 52 | addr_type::IPV4 => { 53 | if data.len() >= 7 { 54 | dest_addr = slice2ip4(&data[1..5]); 55 | dest_port = (&data[5..7]).get_u16().unwrap(); 56 | header_len = 7; 57 | } else { 58 | warn!("header is too short"); 59 | } 60 | } 61 | addr_type::IPV6 => { 62 | if data.len() >= 19 { 63 | dest_addr = slice2ip6(&data[1..17]); 64 | dest_port = (&data[17..19]).get_u16().unwrap(); 65 | header_len = 19; 66 | } else { 67 | warn!("header is too short"); 68 | } 69 | } 70 | addr_type::HOST => { 71 | if data.len() >= 2 { 72 | let addr_len = data[1] as usize; 73 | if data.len() >= 4 + addr_len { 74 | dest_addr = match String::from_utf8(Vec::from(&data[2..2 + addr_len])) { 75 | Ok(s) => Some(s), 76 | Err(e) => { 77 | warn!("not a valid UTF-8 string: {}", e); 78 | None 79 | } 80 | }; 81 | dest_port = (&data[2 + addr_len..4 + addr_len]).get_u16().unwrap(); 82 | header_len = 4 + addr_len; 83 | } else { 84 | warn!("header is too short"); 85 | } 86 | } else { 87 | warn!("header is too short"); 88 | } 89 | } 90 | _ => { 91 | warn!("unsupported addrtype {}, maybe wrong password or encryption method", 92 | addr_type) 93 | } 94 | } 95 | 96 | dest_addr.and_then(|dest_addr| Some(Socks5Header(addr_type, dest_addr, dest_port, header_len))) 97 | } 98 | 99 | pub fn check_auth_method(data: &[u8]) -> CheckAuthResult { 100 | if data.len() < 3 { 101 | warn!("method selection header too short"); 102 | return CheckAuthResult::BadSocksHeader; 103 | } 104 | 105 | let socks_version = data[0]; 106 | if socks_version != 5 { 107 | warn!("unsupported SOCKS protocol version {}", socks_version); 108 | return CheckAuthResult::BadSocksHeader; 109 | } 110 | 111 | let nmethods = data[1]; 112 | if nmethods < 1 || data.len() as u8 != nmethods + 2 { 113 | warn!("NMETHODS and number of METHODS mismatch"); 114 | return CheckAuthResult::BadSocksHeader; 115 | } 116 | 117 | let mut noauto_exist = false; 118 | for method in &data[2..] { 119 | if *method == method::NOAUTH { 120 | noauto_exist = true; 121 | break; 122 | } 123 | } 124 | 125 | if noauto_exist { 126 | CheckAuthResult::Success 127 | } else { 128 | warn!("none of socks method's requested by client is supported"); 129 | CheckAuthResult::NoAcceptableMethods 130 | } 131 | } 132 | 133 | pub fn pack_addr(ip: IpAddr) -> Vec { 134 | let mut res = Vec::with_capacity(17); 135 | match ip { 136 | IpAddr::V4(ip) => { 137 | res.push(0x01); 138 | res.extend_from_slice(&ip.octets()); 139 | } 140 | IpAddr::V6(ip) => { 141 | res.push(0x04); 142 | res.extend_from_slice(&ip.octets()); 143 | } 144 | } 145 | res 146 | } 147 | 148 | #[allow(dead_code, non_snake_case)] 149 | pub mod addr_type { 150 | pub const IPV4: u8 = 0x01; 151 | pub const IPV6: u8 = 0x04; 152 | pub const HOST: u8 = 0x03; 153 | pub const AUTH: u8 = 0x10; 154 | pub const MASK: u8 = 0xF; 155 | } 156 | 157 | // SOCKS method definition 158 | #[allow(dead_code, non_snake_case)] 159 | pub mod method { 160 | pub const NOAUTH: u8 = 0; 161 | pub const GSSAPI: u8 = 1; 162 | pub const USER_PASS: u8 = 2; 163 | } 164 | 165 | // SOCKS command definition 166 | #[allow(dead_code, non_snake_case)] 167 | pub mod cmd { 168 | pub const CONNECT: u8 = 1; 169 | pub const BIND: u8 = 2; 170 | pub const UDP_ASSOCIATE: u8 = 3; 171 | } 172 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | use std::str; 2 | use std::fs::File; 3 | use std::io::{BufReader, Result}; 4 | use std::io::prelude::*; 5 | use std::path::Path; 6 | use std::rc::Rc; 7 | use std::cell::RefCell; 8 | 9 | macro_rules! io_err { 10 | ($desc:expr) => ( io::Error::new(io::ErrorKind::Other, $desc) ); 11 | ($fmt:expr, $($arg:tt)*) => ( io::Error::new(io::ErrorKind::Other, format!($fmt, $($arg)*)) ); 12 | } 13 | 14 | macro_rules! new_fat_slice_from_vec { 15 | ($name:ident, $v:expr) => ( 16 | use std::slice::from_raw_parts_mut; 17 | 18 | let ptr = $v.as_mut_ptr(); 19 | let cap = $v.capacity(); 20 | let raw = unsafe { &mut from_raw_parts_mut(ptr, cap) }; 21 | let $name = raw; 22 | unsafe { $v.set_len(0); } 23 | ); 24 | } 25 | 26 | pub fn slice2str(data: &[u8]) -> Option<&str> { 27 | str::from_utf8(data).ok() 28 | } 29 | 30 | pub fn slice2string(data: &[u8]) -> Option { 31 | String::from_utf8(data.to_vec()).ok() 32 | } 33 | 34 | pub fn handle_every_line>(filepath: P, func: &mut FnMut(String)) -> Result<()> { 35 | let f = File::open(filepath)?; 36 | let reader = BufReader::new(f); 37 | for line in reader.lines() { 38 | let line = match line { 39 | Ok(line) => line.trim().to_string(), 40 | _ => break, 41 | }; 42 | 43 | func(line); 44 | } 45 | Ok(()) 46 | } 47 | 48 | pub fn shift_vec(v: &mut Vec, offset: usize) { 49 | let remain = v.len() - offset; 50 | for i in 0..remain { 51 | v[i] = v[i + offset].clone(); 52 | } 53 | unsafe { 54 | v.set_len(remain); 55 | } 56 | } 57 | 58 | pub type RcCell = Rc>; 59 | 60 | pub fn new_rc_cell(val: T) -> RcCell { 61 | Rc::new(RefCell::new(val)) 62 | } 63 | -------------------------------------------------------------------------------- /tests/base_test.py: -------------------------------------------------------------------------------- 1 | from threading import Thread 2 | import time 3 | from config_tests import * 4 | 5 | def BaseTests(object): 6 | def __init__(create_connection, assert_recv_eq): 7 | self.create_connection = create_connection 8 | self.assert_recv_eq = assert_recv_eq 9 | 10 | def all_in_one(self): 11 | conn = self.create_connection() 12 | for test in tests: 13 | self.assert_recv_eq(conn, test) 14 | conn.close() 15 | 16 | def one_by_one(self): 17 | for test in tests: 18 | conn = self.create_connection() 19 | self.assert_recv_eq(conn, test) 20 | conn.close() 21 | 22 | def concurrent_with_different_task(self): 23 | def start_conn(test): 24 | time.sleep(0.1) 25 | conn = self.create_connection() 26 | self.assert_recv_eq(conn, test) 27 | conn.close() 28 | 29 | threads = [Thread(target=start_conn, args=(t,)) for t in tests] 30 | [thread.start() for thread in threads] 31 | [thread.join() for thread in threads] 32 | 33 | def concurrent_all_in_one(self): 34 | threads = [Thread(target=self.all_in_one) for _ in tests] 35 | [thread.start() for thread in threads] 36 | [thread.join() for thread in threads] 37 | -------------------------------------------------------------------------------- /tests/config/rs_local.toml: -------------------------------------------------------------------------------- 1 | port = 8010 2 | password = "foo" 3 | timeout = 60 4 | method = "aes-256-cfb" 5 | one_time_auth = false 6 | mode = "fast" 7 | 8 | [[servers]] 9 | address = "localhost.loggerhead.me" 10 | port = 8111 11 | -------------------------------------------------------------------------------- /tests/config/rs_local_ota.toml: -------------------------------------------------------------------------------- 1 | port = 8010 2 | password = "foo" 3 | timeout = 60 4 | method = "aes-256-cfb" 5 | one_time_auth = true 6 | mode = "fast" 7 | 8 | [[servers]] 9 | address = "localhost.loggerhead.me" 10 | port = 8111 11 | -------------------------------------------------------------------------------- /tests/config/rs_server.toml: -------------------------------------------------------------------------------- 1 | address = "127.0.0.1" 2 | port = 8111 3 | password = "foo" 4 | timeout = 60 5 | method = "aes-256-cfb" 6 | one_time_auth = false 7 | -------------------------------------------------------------------------------- /tests/config/ss.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": "127.0.0.1", 3 | "server_port": 8111, 4 | "local_address": "127.0.0.1", 5 | "local_port": 8010, 6 | "password": "foo", 7 | "timeout": 60, 8 | "method": "aes-256-cfb", 9 | "fast_open": false, 10 | "one_time_auth": false 11 | } 12 | -------------------------------------------------------------------------------- /tests/config/ss_ota.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": "127.0.0.1", 3 | "server_port": 8111, 4 | "local_address": "127.0.0.1", 5 | "local_port": 8010, 6 | "password": "foo", 7 | "timeout": 60, 8 | "method": "aes-256-cfb", 9 | "fast_open": false, 10 | "one_time_auth": true 11 | } 12 | -------------------------------------------------------------------------------- /tests/config_tests.py: -------------------------------------------------------------------------------- 1 | import time 2 | from threading import Thread 3 | 4 | PROXY_PORT = 8010 5 | SERVER_PORT = 9000 6 | BUF_SIZE = 8192 7 | 8 | tests = [ 9 | b'a', 10 | b'ab', 11 | b'abc' * 30, 12 | b'1' * 1024, 13 | b'2' * BUF_SIZE, 14 | ] 15 | 16 | def p(fmt, data, mode=None, limit=40): 17 | if mode == 'hex': 18 | data = map(lambda b: format(ord(b), '02x'), data) 19 | else: 20 | data = map(ord, data) 21 | 22 | if len(data) > limit: 23 | fmt += ' ... (%d)' 24 | print(fmt % (data[:limit], len(data))) 25 | else: 26 | print(fmt % data) 27 | 28 | class BaseTests(object): 29 | def __init__(self, create_connection, assert_recv_eq): 30 | self._create_connection = create_connection 31 | self._assert_recv_eq = assert_recv_eq 32 | self._fmt = """def test_{1}(): 33 | return {0}.{1}()""" 34 | 35 | def _create_defs(self, name): 36 | methods = [m for m in dir(self) if not m.startswith('_')] 37 | defs = [] 38 | for m in methods: 39 | defs.append(self._fmt.format(name, m)) 40 | return defs 41 | 42 | def all_in_one(self): 43 | conn = self._create_connection() 44 | for test in tests: 45 | self._assert_recv_eq(conn, test) 46 | conn.close() 47 | 48 | def one_by_one(self): 49 | for test in tests: 50 | conn = self._create_connection() 51 | self._assert_recv_eq(conn, test) 52 | conn.close() 53 | 54 | def concurrent_with_different_task(self): 55 | def start_conn(test): 56 | time.sleep(0.1) 57 | conn = self._create_connection() 58 | self._assert_recv_eq(conn, test) 59 | conn.close() 60 | 61 | threads = [Thread(target=start_conn, args=(t,)) for t in tests] 62 | [thread.start() for thread in threads] 63 | [thread.join() for thread in threads] 64 | 65 | def concurrent_all_in_one(self): 66 | threads = [Thread(target=self.all_in_one) for _ in tests] 67 | [thread.start() for thread in threads] 68 | [thread.join() for thread in threads] 69 | -------------------------------------------------------------------------------- /tests/echo_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import SocketServer 3 | from threading import Thread 4 | from config_tests import SERVER_PORT, BUF_SIZE, p 5 | 6 | class TcpEchoHandler(SocketServer.BaseRequestHandler): 7 | def handle(self): 8 | while True: 9 | data = self.request.recv(BUF_SIZE) 10 | if len(data) == 0: 11 | break 12 | self.request.sendall(data) 13 | 14 | class UdpEchoHandler(SocketServer.BaseRequestHandler): 15 | def handle(self): 16 | data = self.request[0] 17 | conn = self.request[1] 18 | conn.sendto(data, self.client_address) 19 | 20 | class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): 21 | pass 22 | 23 | class ThreadedUDPServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): 24 | pass 25 | 26 | def start_tcp_server(): 27 | s = ThreadedTCPServer(("127.0.0.1", SERVER_PORT), TcpEchoHandler) 28 | s.serve_forever() 29 | 30 | def start_udp_server(): 31 | s = ThreadedUDPServer(("127.0.0.1", SERVER_PORT), UdpEchoHandler) 32 | s.serve_forever() 33 | 34 | if __name__ == '__main__': 35 | Thread(target=start_tcp_server).start() 36 | Thread(target=start_udp_server).start() 37 | -------------------------------------------------------------------------------- /tests/encrypt.rs: -------------------------------------------------------------------------------- 1 | extern crate shadowsocks; 2 | 3 | use std::str; 4 | use std::thread; 5 | use std::io::prelude::*; 6 | use std::sync::mpsc::channel; 7 | use std::net::{TcpListener, TcpStream, Shutdown}; 8 | 9 | use shadowsocks::crypto::{Encryptor, Method}; 10 | 11 | const PASSWORD: &'static str = "foo"; 12 | const MESSAGES: &'static [&'static str] = &["a", "hi", "foo", "hello", "world"]; 13 | 14 | macro_rules! assert_new { 15 | ($method:expr) => ( 16 | { 17 | let encryptor = Encryptor::new(PASSWORD, $method); 18 | match encryptor { 19 | Ok(encryptor) => encryptor, 20 | Err(e) => { 21 | println!("create encryptor failed: {:?}", e); 22 | return assert!(false); 23 | } 24 | } 25 | } 26 | ) 27 | } 28 | 29 | macro_rules! assert_do { 30 | ($cryptor:expr, $func:tt, $data:expr) => ( 31 | { 32 | let processed = $cryptor.$func($data); 33 | assert!(processed.is_some()); 34 | processed.unwrap() 35 | } 36 | ) 37 | } 38 | 39 | macro_rules! assert_raw_encrypt { 40 | ($cryptor:expr, $data:expr) => ( assert_do!($cryptor, raw_encrypt, $data) ) 41 | } 42 | 43 | macro_rules! assert_raw_decrypt { 44 | ($cryptor:expr, $data:expr) => ( assert_do!($cryptor, raw_decrypt, $data) ) 45 | } 46 | 47 | macro_rules! assert_encrypt { 48 | ($cryptor:expr, $data:expr) => ( assert_do!($cryptor, encrypt, $data) ) 49 | } 50 | 51 | macro_rules! assert_decrypt { 52 | ($cryptor:expr, $data:expr) => ( assert_do!($cryptor, decrypt, $data) ) 53 | } 54 | 55 | macro_rules! assert_encrypt_udp { 56 | ($cryptor:expr, $data:expr) => ( assert_do!($cryptor, encrypt_udp, $data) ) 57 | } 58 | 59 | macro_rules! assert_decrypt_udp { 60 | ($cryptor:expr, $data:expr) => ( assert_do!($cryptor, decrypt_udp, $data) ) 61 | } 62 | 63 | #[test] 64 | fn in_order() { 65 | for method in Method::all() { 66 | let mut encryptor = assert_new!(method); 67 | for msg in MESSAGES { 68 | let encrypted = assert_encrypt!(encryptor, msg.as_bytes()); 69 | let decrypted = assert_decrypt!(encryptor, &encrypted); 70 | assert_eq!(msg.as_bytes()[..], decrypted[..]); 71 | } 72 | } 73 | } 74 | 75 | #[test] 76 | fn chaos() { 77 | for method in Method::all() { 78 | let mut encryptor = assert_new!(method); 79 | let mut buf_msg = vec![]; 80 | let mut buf_encrypted = vec![]; 81 | 82 | for i in 0..MESSAGES.len() { 83 | let msg = MESSAGES[i].as_bytes(); 84 | let encrypted = assert_encrypt!(encryptor, msg); 85 | 86 | buf_msg.extend_from_slice(msg); 87 | buf_encrypted.extend_from_slice(&encrypted); 88 | if i % 2 == 0 { 89 | let decrypted = assert_decrypt!(encryptor, &buf_encrypted); 90 | assert_eq!(buf_msg[..], decrypted[..]); 91 | buf_msg.clear(); 92 | buf_encrypted.clear(); 93 | } 94 | } 95 | 96 | let decrypted = assert_decrypt!(encryptor, &buf_encrypted); 97 | assert_eq!(buf_msg[..], decrypted[..]); 98 | buf_msg.clear(); 99 | buf_encrypted.clear(); 100 | } 101 | } 102 | 103 | #[test] 104 | fn tcp_server() { 105 | fn test_encryptor(mut stream: TcpStream, mut encryptor: Encryptor) { 106 | for msg in MESSAGES.iter() { 107 | let encrypted = assert_encrypt!(encryptor, msg.as_bytes()); 108 | stream.write(&encrypted).unwrap(); 109 | } 110 | stream.shutdown(Shutdown::Write).unwrap(); 111 | 112 | let mut data = vec![]; 113 | stream.read_to_end(&mut data).unwrap(); 114 | let decrypted = assert_decrypt!(encryptor, &data); 115 | 116 | let mut msgs = vec![]; 117 | for msg in MESSAGES.iter() { 118 | msgs.extend_from_slice(msg.as_bytes()); 119 | } 120 | assert_eq!(&msgs, &decrypted); 121 | } 122 | 123 | 124 | for method in Method::all() { 125 | let (tx, rx) = channel(); 126 | 127 | let t1 = thread::spawn(move || { 128 | let encryptor = assert_new!(method); 129 | let listener = TcpListener::bind("127.0.0.1:0").unwrap(); 130 | tx.send(listener.local_addr().unwrap()).unwrap(); 131 | let stream = listener.incoming().next().unwrap().unwrap(); 132 | test_encryptor(stream, encryptor); 133 | }); 134 | 135 | let t2 = thread::spawn(move || { 136 | let encryptor = assert_new!(method); 137 | let server_addr = rx.recv().unwrap(); 138 | let stream = TcpStream::connect(server_addr).unwrap(); 139 | test_encryptor(stream, encryptor); 140 | }); 141 | 142 | t1.join().unwrap(); 143 | t2.join().unwrap(); 144 | } 145 | } 146 | 147 | #[test] 148 | fn udp() { 149 | for method in Method::all() { 150 | let mut encryptor = assert_new!(method); 151 | for msg in MESSAGES { 152 | let encrypted = assert_encrypt_udp!(encryptor, msg.as_bytes()); 153 | let decrypted = assert_decrypt_udp!(encryptor, &encrypted); 154 | assert_eq!(msg.as_bytes()[..], decrypted[..]); 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /tests/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | work_dir=/tmp 3 | sss_pid_path=/tmp/sss.pid 4 | sss_log_path=/tmp/sss.log 5 | ssc_pid_path=/tmp/ssc.pid 6 | ssc_log_path=/tmp/ssc.log 7 | 8 | src_dir=$(pwd) 9 | echo_port=9000 10 | sss_port=8111 11 | ssc_port=8010 12 | 13 | # run at crate root directory 14 | cargo build --features "openssl" && mv $src_dir/target/debug/ssserver $work_dir/ssserver 15 | cargo build --features "openssl sslocal" && mv $src_dir/target/debug/ssserver $work_dir/sslocal 16 | 17 | python $src_dir/tests/echo_server.py & 18 | cd $work_dir 19 | 20 | function get_pid { 21 | lsof -i :$1 | grep LISTEN | awk '{ print $2 }' | tail -n 1 22 | } 23 | 24 | function kill_all { 25 | kill $(get_pid $echo_port) $(get_pid $ssc_port) $(get_pid $sss_port) 26 | } 27 | 28 | function assert { 29 | echo "$@" 30 | $command "$@" 31 | if [ $? -ne 0 ]; then 32 | echo "failed: $@" 33 | kill_all 34 | exit 1 35 | fi 36 | } 37 | 38 | function assert_raise { 39 | if [ $? -ne 0 ]; then 40 | echo "$1" 41 | kill_all 42 | exit 1 43 | fi 44 | } 45 | 46 | function run_test { 47 | sss_version=$1 48 | ssc_version=$2 49 | sss_conf_name=$3 50 | ssc_conf_name=$4 51 | 52 | sss_conf=$src_dir/tests/config/$sss_conf_name 53 | ssc_conf=$src_dir/tests/config/$ssc_conf_name 54 | sss_cmd=$work_dir/ssserver 55 | ssc_cmd=$work_dir/sslocal 56 | if [[ "$sss_version" == "py" ]]; then 57 | sss_cmd=ssserver 58 | fi 59 | if [[ "$ssc_version" == "py" ]]; then 60 | ssc_cmd=sslocal 61 | fi 62 | 63 | start_sss_cmd="$sss_cmd -d start -v -c $sss_conf --pid-file $sss_pid_path --log-file $sss_log_path" 64 | start_ssc_cmd="$ssc_cmd -d start -v -c $ssc_conf --pid-file $ssc_pid_path --log-file $ssc_log_path" 65 | 66 | # start ssserver 67 | if [[ "$sss_version" == "py" ]]; then 68 | start_sss_cmd="$start_sss_cmd --forbidden-ip ''" 69 | fi 70 | 71 | # start ssserver & sslocal 72 | echo "start ssserver..." 73 | eval $start_sss_cmd 74 | assert_raise "ERROR: start ssserver failed ($sss_conf_name)" 75 | echo "start sslocal..." 76 | eval $start_ssc_cmd 77 | assert_raise "ERROR: start sslocal failed ($ssc_conf_name)" 78 | 79 | # test 80 | assert nosetests -q -x $src_dir/tests/test_tcp.py 81 | assert nosetests -q -x $src_dir/tests/test_udp.py 82 | 83 | # stop 84 | echo "stop ssserver..." 85 | $sss_cmd -d stop --pid-file $sss_pid_path 86 | assert_raise "ERROR: stop ssserver failed ($sss_conf_name)" 87 | echo "stop sslocal..." 88 | # a bug of python version sslocal 89 | if [[ "$ssc_version" == "py" ]]; then 90 | kill $(get_pid $ssc_port) 91 | else 92 | $ssc_cmd -d stop --pid-file $ssc_pid_path 93 | fi 94 | assert_raise "ERROR: stop sslocal failed ($ssc_conf_name)" 95 | echo "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" 96 | } 97 | 98 | # ssserver sslocal 99 | run_test rs rs rs_server.toml rs_local.toml 100 | run_test rs py rs_server.toml ss.json 101 | run_test rs py rs_server.toml ss_ota.json 102 | run_test py rs ss.json rs_local.toml 103 | run_test py rs ss.json rs_local_ota.toml 104 | 105 | kill_all 106 | -------------------------------------------------------------------------------- /tests/test_tcp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import socket 3 | import socks 4 | 5 | from config_tests import * 6 | 7 | tests.append(b'3' * 32 * 1024) 8 | tests.append(b'6' * 64 * 1024) 9 | 10 | def create_connection(): 11 | c = socks.socksocket() 12 | c.settimeout(3) 13 | c.setblocking(True) 14 | c.set_proxy(socks.SOCKS5, "127.0.0.1", PROXY_PORT) 15 | c.connect(("127.0.0.1", SERVER_PORT)) 16 | return c 17 | 18 | def assert_recv_eq(conn, test): 19 | conn.sendall(test) 20 | 21 | recv = b'' 22 | while len(recv) < len(test): 23 | r = conn.recv(BUF_SIZE) 24 | if len(r) == 0: 25 | break 26 | else: 27 | recv += r 28 | 29 | try: 30 | assert recv == test 31 | except Exception as e: 32 | p("expect: %s", test) 33 | p("recv: %s", recv) 34 | raise e 35 | 36 | 37 | ts = BaseTests(create_connection, assert_recv_eq) 38 | defs = ts._create_defs("ts") 39 | for d in defs: 40 | exec(d) 41 | -------------------------------------------------------------------------------- /tests/test_udp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import socks 3 | import socket 4 | 5 | from config_tests import * 6 | 7 | tests.append(b'3' * 1024) 8 | tests.append(b'4' * 4096) 9 | 10 | def create_connection(): 11 | conn = socks.socksocket(socket.AF_INET, socket.SOCK_DGRAM, socket.SOL_UDP) 12 | conn.set_proxy(socks.SOCKS5, "127.0.0.1", PROXY_PORT) 13 | conn.settimeout(3) 14 | return conn 15 | 16 | def assert_recv_eq(conn, test): 17 | conn.sendto(test, ('127.0.0.1', SERVER_PORT)) 18 | recv, _ = conn.recvfrom(BUF_SIZE + 1024) 19 | try: 20 | assert recv == test 21 | except Exception as e: 22 | p("expect: %s", test) 23 | p("recv: %s", recv) 24 | raise e 25 | 26 | ts = BaseTests(create_connection, assert_recv_eq) 27 | defs = ts._create_defs("ts") 28 | for d in defs: 29 | exec(d) 30 | --------------------------------------------------------------------------------