use dns_parser::{Builder, Packet, QueryClass, QueryType};
use socks::{Socks5Datagram, TargetAddr};
use std::io::{Error, ErrorKind, Result};
use std::net::{SocketAddr, UdpSocket};
use std::time::{Duration, Instant};
pub trait RW: Send + Sync {
fn send_to(&self, buf: &[u8], addr: SocketAddr) -> Result<usize>;
fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)>;
fn set_read_timeout(&self, dur: Option<Duration>) -> Result<()>;
fn set_write_timeout(&self, dur: Option<Duration>) -> Result<()>;
fn read_timeout(&self) -> Result<Option<Duration>>;
fn write_timeout(&self) -> Result<Option<Duration>>;
}
#[derive(Debug)]
pub struct Datagram {
datagram: Socks5Datagram,
}
impl Datagram {
pub fn bind(
proxy: SocketAddr,
addr: SocketAddr,
auth: Option<(String, String)>,
) -> Result<Datagram> {
let datagram = match auth {
Some((username, password)) => Socks5Datagram::bind_with_password(
proxy,
addr,
username.as_str(),
password.as_str(),
)?,
None => Socks5Datagram::bind(proxy, addr)?,
};
Ok(Datagram { datagram })
}
}
impl RW for Datagram {
fn send_to(&self, buf: &[u8], addr: SocketAddr) -> Result<usize> {
self.datagram.send_to(buf, addr)
}
fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> {
let (size, addr) = self.datagram.recv_from(buf)?;
return match addr {
TargetAddr::Ip(addr) => Ok((size, addr)),
_ => unreachable!(),
};
}
fn set_read_timeout(&self, dur: Option<Duration>) -> Result<()> {
self.datagram.get_ref().set_read_timeout(dur)
}
fn set_write_timeout(&self, dur: Option<Duration>) -> Result<()> {
self.datagram.get_ref().set_write_timeout(dur)
}
fn read_timeout(&self) -> Result<Option<Duration>> {
self.datagram.get_ref().read_timeout()
}
fn write_timeout(&self) -> Result<Option<Duration>> {
self.datagram.get_ref().write_timeout()
}
}
#[derive(Debug)]
pub struct Socket {
socket: UdpSocket,
}
impl Socket {
pub fn bind(addr: SocketAddr) -> Result<Socket> {
let socket = UdpSocket::bind(addr)?;
Ok(Socket { socket })
}
}
impl RW for Socket {
fn send_to(&self, buf: &[u8], addr: SocketAddr) -> Result<usize> {
self.socket.send_to(buf, addr)
}
fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> {
self.socket.recv_from(buf)
}
fn set_read_timeout(&self, dur: Option<Duration>) -> Result<()> {
self.socket.set_read_timeout(dur)
}
fn set_write_timeout(&self, dur: Option<Duration>) -> Result<()> {
self.socket.set_write_timeout(dur)
}
fn read_timeout(&self) -> Result<Option<Duration>> {
self.socket.read_timeout()
}
fn write_timeout(&self) -> Result<Option<Duration>> {
self.socket.write_timeout()
}
}
pub fn ping(
rw: &Box<dyn RW>,
addr: SocketAddr,
id: u16,
iterate: bool,
host: &String,
) -> Result<(usize, Duration)> {
let is_ipv6 = match addr {
SocketAddr::V4(_) => false,
SocketAddr::V6(_) => true,
};
let mut query = Builder::new_query(id, iterate);
if is_ipv6 {
query.add_question(&host, false, QueryType::AAAA, QueryClass::IN);
} else {
query.add_question(&host, false, QueryType::A, QueryClass::IN);
}
let buffer = match query.build() {
Ok(buffer) => buffer,
Err(_) => {
return Err(Error::from(ErrorKind::InvalidData));
}
};
let mut recv_buffer = vec![0u8; u16::MAX as usize];
let instant = Instant::now();
let _ = rw.send_to(buffer.as_slice(), addr)?;
loop {
let (size, a) = rw.recv_from(recv_buffer.as_mut_slice())?;
if size <= 0 {
return Err(Error::from(ErrorKind::UnexpectedEof));
} else {
if a == addr {
if let Ok(packet) = Packet::parse(&recv_buffer[..size]) {
if packet.header.id == id {
return Ok((size, instant.elapsed()));
}
}
}
}
}
}