#[forbid(unsafe_code)]
#[macro_use]
extern crate log;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use fast_socks5::{client::Socks5Datagram, Result};
use structopt::StructOpt;
use tokio::{
io::{AsyncRead, AsyncWrite},
net::TcpStream,
};
#[derive(Debug, StructOpt)]
#[structopt(
name = "socks5-udp-client",
about = "A simple example of a socks5 UDP client (proxied DNS client)."
)]
struct Opt {
#[structopt(short, long)]
pub socks_server: SocketAddr,
#[structopt(short = "a", long)]
pub target_server: String,
#[structopt(short = "p", long)]
pub target_port: Option<u16>,
#[structopt(short = "d", long)]
pub query_domain: String,
#[structopt(short, long)]
pub username: Option<String>,
#[structopt(long)]
pub password: Option<String>,
}
#[tokio::main]
async fn main() -> Result<()> {
env_logger::init();
spawn_socks_client().await
}
async fn spawn_socks_client() -> Result<()> {
let opt: Opt = Opt::from_args();
let backing_socket = TcpStream::connect(opt.socks_server).await?;
let client_bind_addr = if opt.socks_server.is_ipv4() {
SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)
} else {
SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0)
};
let mut socks = match opt.username {
Some(username) => {
Socks5Datagram::bind_with_password(
backing_socket,
client_bind_addr,
&username,
&opt.password.expect("Please fill the password"),
)
.await?
}
_ => Socks5Datagram::bind(backing_socket, client_bind_addr).await?,
};
dns_request(
&mut socks,
opt.target_server,
opt.target_port.unwrap_or(53),
opt.query_domain,
)
.await?;
Ok(())
}
async fn dns_request<S: AsyncRead + AsyncWrite + Unpin>(
socket: &mut Socks5Datagram<S>,
server: String,
port: u16,
domain: String,
) -> Result<()> {
debug!("Requesting results...");
let mut query: Vec<u8> = vec![
0x13, 0x37, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
for part in domain.split('.') {
query.push(part.len() as u8);
query.extend(part.chars().map(|c| c as u8));
}
query.extend_from_slice(&[0, 0, 1, 0, 1]);
debug!("query: {:?}", query);
let _sent = socket.send_to(&query, (&server[..], port)).await?;
let mut buf = [0u8; 256];
let (len, adr) = socket.recv_from(&mut buf).await?;
let msg = &buf[..len];
info!("response: {:?} from {:?}", msg, adr);
assert_eq!(msg[0], 0x13);
assert_eq!(msg[1], 0x37);
Ok(())
}