Created
December 22, 2020 08:22
-
-
Save LuoZijun/cde4b00ed038159e19642834ee72dea9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![allow(dead_code, unused_imports)] | |
use std::net::TcpStream; | |
use std::net::Shutdown; | |
use std::net::Ipv4Addr; | |
use std::net::SocketAddr; | |
use std::net::SocketAddrV4; | |
use std::net::ToSocketAddrs; | |
use std::io::{self, Read, Write}; | |
use std::time::Instant; | |
use std::time::Duration; | |
pub fn test_socks5(socks5_server_addr: SocketAddr, target_addr: SocketAddr) -> Result<Duration, io::Error> { | |
pub const SOCKS_V4: u8 = 0x04; // SOCKS-4、SOCKS-4A | |
pub const SOCKS_V5: u8 = 0x05; // SOCKS-5 | |
pub const SOCKS_CMD_CONNECT: u8 = 0x01; // SOCKS-4、SOCKS-4A、SOCKS-5 | |
pub const SOCKS_CMD_BIND: u8 = 0x02; // SOCKS-4、SOCKS-4A、SOCKS-5 | |
pub const SOCKS_CMD_UDP_ASSOCIATE: u8 = 0x03; // SOCKS-5 | |
pub const SOCKS_REP_SUCCEEDED: u8 = 0x00; | |
pub const SOCKS_REP_GENERAL_SERVER_FAILURE: u8 = 0x01; | |
pub const SOCKS_REP_CONNECTION_NOT_ALLOWED_BY_RULESET: u8 = 0x02; | |
pub const SOCKS_REP_NETWORK_UNREACHABLE: u8 = 0x03; | |
pub const SOCKS_REP_HOST_UNREACHABLE: u8 = 0x04; | |
pub const SOCKS_REP_CONNECTION_REFUSED: u8 = 0x05; | |
pub const SOCKS_REP_TTL_EXPIRED: u8 = 0x06; | |
pub const SOCKS_REP_COMMAND_NOT_SUPPORTED: u8 = 0x07; | |
pub const SOCKS_REP_ADDRESS_TYPE_NOT_SUPPORTED: u8 = 0x08; | |
pub const SOCKS_ATYP_IPV4: u8 = 0x01; | |
pub const SOCKS_ATYP_DOMAIN_NAME: u8 = 0x03; | |
pub const SOCKS_ATYP_IPV6: u8 = 0x04; | |
pub const SOCKS_METHOD_NO_AUTH: u8 = 0x00; | |
pub const SOCKS_METHOD_GSSAPI: u8 = 0x01; | |
pub const SOCKS_METHOD_PASSWD_AUTH: u8 = 0x02; | |
pub const SOCKS_METHOD_NO_ACCEPTABLE: u8 = 0xFF; | |
let mut buffer = [0u8; 4096]; | |
let now = Instant::now(); | |
let mut stream = TcpStream::connect(socks5_server_addr)?; | |
// https://tools.ietf.org/html/rfc1928#section-3 | |
// +----+----------+----------+ | |
// |VER | NMETHODS | METHODS | | |
// +----+----------+----------+ | |
// | 1 | 1 | 1 to 255 | | |
// +----+----------+----------+ | |
buffer[0] = SOCKS_V5; | |
buffer[1] = 0x01; | |
buffer[2] = SOCKS_METHOD_NO_AUTH; | |
stream.write_all(&buffer[..3])?; | |
// +----+--------+ | |
// |VER | METHOD | | |
// +----+--------+ | |
// | 1 | 1 | | |
// +----+--------+ | |
stream.read_exact(&mut buffer[..2])?; | |
assert_eq!(buffer[0], SOCKS_V5); | |
assert_eq!(buffer[1], SOCKS_METHOD_NO_AUTH); | |
// https://tools.ietf.org/html/rfc1928#section-4 | |
// +----+-----+-------+------+----------+----------+ | |
// |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | | |
// +----+-----+-------+------+----------+----------+ | |
// | 1 | 1 | X'00' | 1 | Variable | 2 | | |
// +----+-----+-------+------+----------+----------+ | |
buffer[0] = SOCKS_V5; // VER | |
buffer[1] = SOCKS_CMD_CONNECT; // CMD | |
buffer[2] = 0x00; // RSV | |
match target_addr { | |
SocketAddr::V4(v4_addr) => { | |
let ip_octets = v4_addr.ip().octets(); | |
let port_octets = v4_addr.port().to_be_bytes(); | |
buffer[3] = SOCKS_ATYP_IPV4; // ATYP | |
buffer[4..8].copy_from_slice(&ip_octets); // BND.ADDR | |
buffer[8] = port_octets[0]; // BND.PORT | |
buffer[9] = port_octets[1]; | |
let pkt = &buffer[..10]; | |
stream.write_all(pkt)?; | |
}, | |
SocketAddr::V6(v6_addr) => { | |
let ip_octets = v6_addr.ip().octets(); | |
let port_octets = v6_addr.port().to_be_bytes(); | |
buffer[3] = SOCKS_ATYP_IPV6; // ATYP | |
buffer[4..20].copy_from_slice(&ip_octets); // BND.ADDR | |
buffer[20] = port_octets[0]; // BND.PORT | |
buffer[21] = port_octets[1]; | |
let pkt = &buffer[..22]; | |
stream.write_all(pkt)?; | |
}, | |
} | |
// https://tools.ietf.org/html/rfc1928#section-6 | |
// +----+-----+-------+------+----------+----------+ | |
// |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | | |
// +----+-----+-------+------+----------+----------+ | |
// | 1 | 1 | X'00' | 1 | Variable | 2 | | |
// +----+-----+-------+------+----------+----------+ | |
stream.read_exact(&mut buffer[..4])?; | |
assert_eq!(buffer[0], SOCKS_V5); | |
assert_eq!(buffer[1], SOCKS_REP_SUCCEEDED); | |
let atype = buffer[3]; | |
match atype { | |
SOCKS_ATYP_IPV4 => { | |
stream.read_exact(&mut buffer[..6])?; // IPV4_ADDR + Port | |
}, | |
SOCKS_ATYP_DOMAIN_NAME => { | |
stream.read_exact(&mut buffer[..1])?; // DOMAIN-NAME LEN in octets | |
let nlen = buffer[0] as usize; | |
stream.read_exact(&mut buffer[..nlen])?; // DOMAIN-NAME | |
stream.read_exact(&mut buffer[..2])?; // Port | |
}, | |
SOCKS_ATYP_IPV6 => { | |
stream.read_exact(&mut buffer[..18])?; // IPV6_ADDR + Port | |
}, | |
_ => return Err(io::Error::new(io::ErrorKind::ConnectionAborted, "unsupported socks5 address type")), | |
} | |
// Relay | |
stream.write_all(b"GET / HTTP/1.1\r\n\ | |
Host: www.pornhub.com\r\n\ | |
\r\n")?; | |
let amt = stream.read(&mut buffer)?; | |
assert!(amt > 0); | |
let new_now = Instant::now(); | |
let duration = new_now.duration_since(now); | |
stream.shutdown(Shutdown::Both)?; | |
Ok(duration) | |
} | |
pub fn test_native(target_addr: SocketAddr) -> Result<Duration, io::Error> { | |
let mut buffer = [0u8; 4096]; | |
let now = Instant::now(); | |
let mut stream = TcpStream::connect(target_addr)?; | |
stream.write_all(b"GET / HTTP/1.1\r\n\ | |
Host: www.pornhub.com\r\n\ | |
\r\n")?; | |
let amt = stream.read(&mut buffer)?; | |
assert!(amt > 0); | |
let new_now = Instant::now(); | |
let duration = new_now.duration_since(now); | |
stream.shutdown(Shutdown::Both)?; | |
Ok(duration) | |
} | |
fn main() -> Result<(), Box<dyn std::error::Error>> { | |
let socks5_server_addr = SocketAddr::from(([127, 0, 0, 1], 1080)); | |
let target_addr = SocketAddr::from(([127, 0, 0, 1], 80)); | |
println!("TARGET-ADDR: {:?}", target_addr); | |
for _ in 0..20 { | |
let t1 = test_native(target_addr)?; | |
let t2 = test_socks5(socks5_server_addr, target_addr)?; | |
println!(" Native : {:>13} via SOCKS-5: {:>13}", format!("{:?}", t1), format!("{:?}", t2)); | |
} | |
let target_addr = SocketAddr::from(([180, 101, 49, 12], 80)); // baidu.com | |
println!("TARGET-ADDR: {:?}", target_addr); | |
for _ in 0..20 { | |
let t1 = test_native(target_addr)?; | |
let t2 = test_socks5(socks5_server_addr, target_addr)?; | |
println!(" Native : {:>13} via SOCKS-5: {:>13}", format!("{:?}", t1), format!("{:?}", t2)); | |
} | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment