Prepare DNS support

This commit is contained in:
B. Blechschmidt 2023-03-22 19:11:28 +01:00
parent ca3aadcf1a
commit 1a5eeece6f
2 changed files with 93 additions and 27 deletions

View file

@ -1,7 +1,7 @@
use crate::error::Error; use crate::error::Error;
use crate::tun2proxy::{ use crate::tun2proxy::{
Connection, ConnectionManager, Credentials, IncomingDataEvent, IncomingDirection, Connection, ConnectionManager, Credentials, DestinationHost, IncomingDataEvent,
OutgoingDataEvent, OutgoingDirection, TcpProxy, IncomingDirection, OutgoingDataEvent, OutgoingDirection, TcpProxy,
}; };
use std::collections::VecDeque; use std::collections::VecDeque;
use std::net::{IpAddr, SocketAddr}; use std::net::{IpAddr, SocketAddr};
@ -18,7 +18,6 @@ enum SocksState {
Established, Established,
} }
#[allow(dead_code)]
#[repr(u8)] #[repr(u8)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
enum SocksAddressType { enum SocksAddressType {
@ -28,7 +27,6 @@ enum SocksAddressType {
} }
#[allow(dead_code)] #[allow(dead_code)]
#[repr(u8)]
enum SocksAuthentication { enum SocksAuthentication {
None = 0, None = 0,
Password = 2, Password = 2,
@ -68,7 +66,7 @@ pub(crate) struct SocksConnection {
impl SocksConnection { impl SocksConnection {
pub fn new(connection: &Connection, manager: std::rc::Rc<dyn ConnectionManager>) -> Self { pub fn new(connection: &Connection, manager: std::rc::Rc<dyn ConnectionManager>) -> Self {
let mut result = Self { let mut result = Self {
connection: *connection, connection: connection.clone(),
state: SocksState::ServerHello, state: SocksState::ServerHello,
client_inbuf: Default::default(), client_inbuf: Default::default(),
server_inbuf: Default::default(), server_inbuf: Default::default(),
@ -84,9 +82,11 @@ impl SocksConnection {
fn send_client_hello(&mut self) { fn send_client_hello(&mut self) {
let credentials = self.manager.get_credentials(); let credentials = self.manager.get_credentials();
if credentials.is_some() { if credentials.is_some() {
self.server_outbuf.extend(&[5u8, 1, 2]); self.server_outbuf
.extend(&[5u8, 1, SocksAuthentication::Password as u8]);
} else { } else {
self.server_outbuf.extend(&[5u8, 1, 0]); self.server_outbuf
.extend(&[5u8, 1, SocksAuthentication::None as u8]);
} }
self.state = SocksState::ServerHello; self.state = SocksState::ServerHello;
} }
@ -191,16 +191,28 @@ impl SocksConnection {
} }
fn send_request(&mut self) -> Result<(), Error> { fn send_request(&mut self) -> Result<(), Error> {
let dst_ip = self.connection.dst.ip(); self.server_outbuf.extend(&[5u8, 1, 0]);
let cmd = if dst_ip.is_ipv4() { 1 } else { 4 }; match &self.connection.dst.host {
self.server_outbuf.extend(&[5u8, 1, 0, cmd]); DestinationHost::Address(dst_ip) => {
match dst_ip { let cmd = if dst_ip.is_ipv4() {
IpAddr::V4(ip) => self.server_outbuf.extend(ip.octets().as_ref()), SocksAddressType::Ipv4
IpAddr::V6(ip) => self.server_outbuf.extend(ip.octets().as_ref()), } else {
}; SocksAddressType::Ipv6
};
self.server_outbuf.extend(&[cmd as u8]);
match dst_ip {
IpAddr::V4(ip) => self.server_outbuf.extend(ip.octets().as_ref()),
IpAddr::V6(ip) => self.server_outbuf.extend(ip.octets().as_ref()),
};
}
DestinationHost::Hostname(_) => {
self.server_outbuf
.extend(&[SocksAddressType::DomainName as u8]);
}
}
self.server_outbuf.extend(&[ self.server_outbuf.extend(&[
(self.connection.dst.port() >> 8) as u8, (self.connection.dst.port >> 8) as u8,
(self.connection.dst.port() & 0xff) as u8, (self.connection.dst.port & 0xff) as u8,
]); ]);
self.state = SocksState::ReceiveResponse; self.state = SocksState::ReceiveResponse;
self.state_change() self.state_change()

View file

@ -14,16 +14,67 @@ use smoltcp::wire::{
}; };
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::From; use std::convert::From;
use std::fmt::{Display, Formatter};
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::net::Shutdown::Both; use std::net::Shutdown::Both;
use std::net::{IpAddr, Shutdown, SocketAddr}; use std::net::{IpAddr, Shutdown, SocketAddr};
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
#[derive(Hash, Clone, Copy, Eq, PartialEq)] #[derive(Hash, Clone, Eq, PartialEq)]
pub struct Connection { pub enum DestinationHost {
pub src: std::net::SocketAddr, Address(IpAddr),
pub dst: std::net::SocketAddr, Hostname(String),
pub proto: u8, }
impl ToString for DestinationHost {
fn to_string(&self) -> String {
match self {
DestinationHost::Address(addr) => addr.to_string(),
DestinationHost::Hostname(name) => name.clone(),
}
}
}
#[derive(Hash, Clone, Eq, PartialEq)]
pub(crate) struct Destination {
pub(crate) host: DestinationHost,
pub(crate) port: u16,
}
impl From<Destination> for SocketAddr {
fn from(value: Destination) -> Self {
SocketAddr::new(
match value.host {
DestinationHost::Address(addr) => addr,
DestinationHost::Hostname(_) => {
panic!("Failed to convert hostname destination into socket address")
}
},
value.port,
)
}
}
impl From<SocketAddr> for Destination {
fn from(addr: SocketAddr) -> Self {
Self {
host: DestinationHost::Address(addr.ip()),
port: addr.port(),
}
}
}
impl Display for Destination {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.host.to_string(), self.port)
}
}
#[derive(Hash, Clone, Eq, PartialEq)]
pub(crate) struct Connection {
pub(crate) src: std::net::SocketAddr,
pub(crate) dst: Destination,
pub(crate) proto: u8,
} }
impl std::fmt::Display for Connection { impl std::fmt::Display for Connection {
@ -105,7 +156,7 @@ fn connection_tuple(frame: &[u8]) -> Option<(Connection, bool, usize, usize)> {
) { ) {
let connection = Connection { let connection = Connection {
src: SocketAddr::new(src_addr, ports.0), src: SocketAddr::new(src_addr, ports.0),
dst: SocketAddr::new(dst_addr, ports.1), dst: SocketAddr::new(dst_addr, ports.1).into(),
proto, proto,
}; };
return Some((connection, first_packet, payload_offset, payload_size)); return Some((connection, first_packet, payload_offset, payload_size));
@ -130,7 +181,7 @@ fn connection_tuple(frame: &[u8]) -> Option<(Connection, bool, usize, usize)> {
{ {
let connection = Connection { let connection = Connection {
src: SocketAddr::new(src_addr, ports.0), src: SocketAddr::new(src_addr, ports.0),
dst: SocketAddr::new(dst_addr, ports.1), dst: SocketAddr::new(dst_addr, ports.1).into(),
proto, proto,
}; };
Some((connection, first_packet, payload_offset, payload_size)) Some((connection, first_packet, payload_offset, payload_size))
@ -348,7 +399,10 @@ impl<'a> TunToProxy<'a> {
smoltcp::socket::tcp::SocketBuffer::new(vec![0; 4096]), smoltcp::socket::tcp::SocketBuffer::new(vec![0; 4096]),
); );
socket.set_ack_delay(None); socket.set_ack_delay(None);
socket.listen(connection.dst).unwrap(); let dst = connection.dst.clone();
socket
.listen(<Destination as Into<SocketAddr>>::into(dst))
.unwrap();
let handle = self.sockets.add(socket); let handle = self.sockets.add(socket);
let client = TcpStream::connect(server).unwrap(); let client = TcpStream::connect(server).unwrap();
@ -363,7 +417,7 @@ impl<'a> TunToProxy<'a> {
handler, handler,
}; };
self.token_to_connection.insert(token, connection); self.token_to_connection.insert(token, connection.clone());
self.poll self.poll
.registry() .registry()
.register( .register(
@ -373,7 +427,7 @@ impl<'a> TunToProxy<'a> {
) )
.unwrap(); .unwrap();
self.connections.insert(connection, state); self.connections.insert(connection.clone(), state);
info!("CONNECT {}", connection,); info!("CONNECT {}", connection,);
break; break;
@ -456,7 +510,7 @@ impl<'a> TunToProxy<'a> {
fn mio_socket_event(&mut self, event: &Event) { fn mio_socket_event(&mut self, event: &Event) {
if let Some(conn_ref) = self.token_to_connection.get(&event.token()) { if let Some(conn_ref) = self.token_to_connection.get(&event.token()) {
let connection = *conn_ref; let connection = conn_ref.clone();
if event.is_readable() { if event.is_readable() {
{ {
let state = self.connections.get_mut(&connection).unwrap(); let state = self.connections.get_mut(&connection).unwrap();