mirror of
https://github.com/shadowsocks/shadowsocks-rust.git
synced 2026-02-09 01:59:16 +08:00
Add DNS, HTTP, Socks4/4a tests
This commit is contained in:
90
tests/dns.rs
Normal file
90
tests/dns.rs
Normal file
@@ -0,0 +1,90 @@
|
||||
#![cfg(feature = "local-dns-relay")]
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
use tokio::{
|
||||
net::{TcpStream, UdpSocket},
|
||||
prelude::*,
|
||||
time,
|
||||
};
|
||||
|
||||
use shadowsocks::{
|
||||
config::{Config, ConfigType},
|
||||
run_local,
|
||||
run_server,
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
async fn dns_relay() {
|
||||
let _ = env_logger::try_init();
|
||||
|
||||
let mut local_config = Config::load_from_str(
|
||||
r#"{
|
||||
"local_port": 6110,
|
||||
"local_address": "127.0.0.1",
|
||||
"server": "127.0.0.1",
|
||||
"server_port": 6120,
|
||||
"password": "password",
|
||||
"method": "aes-256-gcm"
|
||||
}"#,
|
||||
ConfigType::DnsLocal,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
local_config.local_dns_addr = Some("114.114.114.114:53".parse().unwrap());
|
||||
local_config.remote_dns_addr = Some("8.8.8.8:53".parse().unwrap());
|
||||
|
||||
let server_config = Config::load_from_str(
|
||||
r#"{
|
||||
"server": "127.0.0.1",
|
||||
"server_port": 6120,
|
||||
"password": "password",
|
||||
"method": "aes-256-gcm",
|
||||
"mode": "tcp_and_udp"
|
||||
}"#,
|
||||
ConfigType::Server,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
tokio::spawn(run_local(local_config));
|
||||
tokio::spawn(run_server(server_config));
|
||||
|
||||
time::sleep(Duration::from_secs(1)).await;
|
||||
|
||||
// Query firefox.com, TransactionID: 0x1234
|
||||
static DNS_QUERY: &[u8] = b"\x12\x34\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07firefox\x03com\x00\x00\x01\x00\x01";
|
||||
|
||||
// 1. DoT
|
||||
{
|
||||
let mut c = TcpStream::connect("127.0.0.1:6110").await.unwrap();
|
||||
|
||||
let mut len_buf = [0u8; 2];
|
||||
BigEndian::write_u16(&mut len_buf, DNS_QUERY.len() as u16);
|
||||
c.write_all(&len_buf).await.unwrap();
|
||||
|
||||
c.write_all(DNS_QUERY).await.unwrap();
|
||||
c.flush().await.unwrap();
|
||||
|
||||
c.read_exact(&mut len_buf).await.unwrap();
|
||||
let resp_len = BigEndian::read_u16(&len_buf);
|
||||
|
||||
let mut buf = vec![0u8; resp_len as usize];
|
||||
c.read_exact(&mut buf).await.unwrap();
|
||||
|
||||
assert!(buf.starts_with(b"\x12\x34"));
|
||||
}
|
||||
|
||||
// 2. DoU
|
||||
{
|
||||
let c = UdpSocket::bind("0.0.0.0:0").await.unwrap();
|
||||
c.send_to(DNS_QUERY, "127.0.0.1:6110").await.unwrap();
|
||||
|
||||
let mut buf = [0u8; 65536];
|
||||
let n = c.recv(&mut buf).await.unwrap();
|
||||
assert!(n >= 12);
|
||||
|
||||
let pkt = &buf[..n];
|
||||
assert_eq!(&pkt[..2], b"\x12\x34");
|
||||
}
|
||||
}
|
||||
76
tests/http.rs
Normal file
76
tests/http.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
#![cfg(feature = "local-http")]
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use tokio::{net::TcpStream, prelude::*, time};
|
||||
|
||||
use shadowsocks::{
|
||||
config::{Config, ConfigType},
|
||||
run_local,
|
||||
run_server,
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
async fn http_proxy() {
|
||||
let _ = env_logger::try_init();
|
||||
|
||||
let local_config = Config::load_from_str(
|
||||
r#"{
|
||||
"local_port": 5110,
|
||||
"local_address": "127.0.0.1",
|
||||
"server": "127.0.0.1",
|
||||
"server_port": 5120,
|
||||
"password": "password",
|
||||
"method": "aes-256-gcm"
|
||||
}"#,
|
||||
ConfigType::HttpLocal,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let server_config = Config::load_from_str(
|
||||
r#"{
|
||||
"server": "127.0.0.1",
|
||||
"server_port": 5120,
|
||||
"password": "password",
|
||||
"method": "aes-256-gcm"
|
||||
}"#,
|
||||
ConfigType::Server,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
tokio::spawn(run_local(local_config));
|
||||
tokio::spawn(run_server(server_config));
|
||||
|
||||
time::sleep(Duration::from_secs(1)).await;
|
||||
|
||||
{
|
||||
let mut c = TcpStream::connect("127.0.0.1:5110").await.unwrap();
|
||||
c.write_all(b"GET http://www.example.com/ HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n")
|
||||
.await
|
||||
.unwrap();
|
||||
c.flush().await.unwrap();
|
||||
|
||||
let mut buf = Vec::new();
|
||||
c.read_to_end(&mut buf).await.unwrap();
|
||||
|
||||
assert!(buf.starts_with(b"HTTP/1.0 200 OK\r\n"));
|
||||
}
|
||||
|
||||
{
|
||||
let mut c = TcpStream::connect("127.0.0.1:5110").await.unwrap();
|
||||
c.write_all(b"CONNECT http://www.example.com/ HTTP/1.0\r\n\r\n")
|
||||
.await
|
||||
.unwrap();
|
||||
c.flush().await.unwrap();
|
||||
|
||||
c.write_all(b"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n")
|
||||
.await
|
||||
.unwrap();
|
||||
c.flush().await.unwrap();
|
||||
|
||||
let mut buf = Vec::new();
|
||||
c.read_to_end(&mut buf).await.unwrap();
|
||||
|
||||
assert!(buf.starts_with(b"HTTP/1.0 200 OK\r\n"));
|
||||
}
|
||||
}
|
||||
110
tests/socks4.rs
Normal file
110
tests/socks4.rs
Normal file
@@ -0,0 +1,110 @@
|
||||
#![cfg(feature = "local-socks4")]
|
||||
|
||||
use std::{
|
||||
net::{SocketAddr, ToSocketAddrs},
|
||||
str,
|
||||
};
|
||||
|
||||
use tokio::{
|
||||
net::TcpStream,
|
||||
prelude::*,
|
||||
time::{self, Duration},
|
||||
};
|
||||
|
||||
use shadowsocks::{
|
||||
config::{Config, ConfigType, ServerAddr, ServerConfig},
|
||||
crypto::CipherType,
|
||||
relay::socks4::{Address, Command, HandshakeRequest, HandshakeResponse, ResultCode},
|
||||
run_local,
|
||||
run_server,
|
||||
};
|
||||
|
||||
pub struct Socks4TestServer {
|
||||
local_addr: SocketAddr,
|
||||
svr_config: Config,
|
||||
cli_config: Config,
|
||||
}
|
||||
|
||||
impl Socks4TestServer {
|
||||
pub fn new<S, L>(svr_addr: S, local_addr: L, pwd: &str, method: CipherType) -> Socks4TestServer
|
||||
where
|
||||
S: ToSocketAddrs,
|
||||
L: ToSocketAddrs,
|
||||
{
|
||||
let svr_addr = svr_addr.to_socket_addrs().unwrap().next().unwrap();
|
||||
let local_addr = local_addr.to_socket_addrs().unwrap().next().unwrap();
|
||||
|
||||
Socks4TestServer {
|
||||
local_addr,
|
||||
svr_config: {
|
||||
let mut cfg = Config::new(ConfigType::Server);
|
||||
cfg.server = vec![ServerConfig::basic(svr_addr, pwd.to_owned(), method)];
|
||||
cfg
|
||||
},
|
||||
cli_config: {
|
||||
let mut cfg = Config::new(ConfigType::Socks4Local);
|
||||
cfg.local_addr = Some(ServerAddr::from(local_addr));
|
||||
cfg.server = vec![ServerConfig::basic(svr_addr, pwd.to_owned(), method)];
|
||||
cfg
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn client_addr(&self) -> &SocketAddr {
|
||||
&self.local_addr
|
||||
}
|
||||
|
||||
pub async fn run(&self) {
|
||||
let svr_cfg = self.svr_config.clone();
|
||||
tokio::spawn(run_server(svr_cfg));
|
||||
|
||||
let client_cfg = self.cli_config.clone();
|
||||
tokio::spawn(run_local(client_cfg));
|
||||
|
||||
time::sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn socks4_relay_connect() {
|
||||
let _ = env_logger::try_init();
|
||||
|
||||
const SERVER_ADDR: &str = "127.0.0.1:7100";
|
||||
const LOCAL_ADDR: &str = "127.0.0.1:7200";
|
||||
|
||||
const PASSWORD: &str = "test-password";
|
||||
const METHOD: CipherType = CipherType::Aes128Gcm;
|
||||
|
||||
let svr = Socks4TestServer::new(SERVER_ADDR, LOCAL_ADDR, PASSWORD, METHOD);
|
||||
svr.run().await;
|
||||
|
||||
static HTTP_REQUEST: &[u8] = b"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n";
|
||||
|
||||
let mut c = TcpStream::connect(LOCAL_ADDR).await.unwrap();
|
||||
|
||||
let req = HandshakeRequest {
|
||||
cd: Command::Connect,
|
||||
dst: Address::from(("www.example.com".to_owned(), 80)),
|
||||
user_id: Vec::new(),
|
||||
};
|
||||
|
||||
let mut handshake_buf = Vec::new();
|
||||
req.write_to_buf(&mut handshake_buf);
|
||||
|
||||
c.write_all(&handshake_buf).await.unwrap();
|
||||
c.flush().await.unwrap();
|
||||
|
||||
let rsp = HandshakeResponse::read_from(&mut c).await.unwrap();
|
||||
assert_eq!(rsp.cd, ResultCode::RequestGranted);
|
||||
|
||||
c.write_all(HTTP_REQUEST).await.unwrap();
|
||||
c.flush().await.unwrap();
|
||||
|
||||
let mut buf = Vec::new();
|
||||
c.read_to_end(&mut buf).await.unwrap();
|
||||
|
||||
println!("Got reply from server: {}", str::from_utf8(&buf).unwrap());
|
||||
|
||||
let http_status = b"HTTP/1.0 200 OK\r\n";
|
||||
buf.starts_with(http_status);
|
||||
}
|
||||
@@ -72,7 +72,7 @@ async fn socks5_relay_stream() {
|
||||
const LOCAL_ADDR: &str = "127.0.0.1:8200";
|
||||
|
||||
const PASSWORD: &str = "test-password";
|
||||
const METHOD: CipherType = CipherType::Aes128Gcm;
|
||||
const METHOD: CipherType = CipherType::Aes128Cfb;
|
||||
|
||||
let svr = Socks5TestServer::new(SERVER_ADDR, LOCAL_ADDR, PASSWORD, METHOD, false);
|
||||
svr.run().await;
|
||||
|
||||
Reference in New Issue
Block a user