Cleaning and update

This commit is contained in:
Elvis Gallagher 2022-08-01 14:36:58 +00:00
parent 8af93a278e
commit 8d408bbe76
8 changed files with 295 additions and 252 deletions

3
.gitignore vendored
View file

@ -1,3 +1,2 @@
/target /target
/.idea Cargo.lock
/*.iml

12
CHANGELOG.md Normal file
View file

@ -0,0 +1,12 @@
# Changelog for Tun2Proxy
## 0.1.1
- Updated dependencies:
- `chrono`: v0.4, ready for next planned release ;
- `clap`: last version ;
- `mio`: v0.8 + rename renamed feature (os-util became os-ext) + some fixes due to removal of `TcpSocket` type ;
- `smoltcp`: set v0.8 but from crates.io, plus old reference could not work.
- Fixes:
- Removed typo from Cargo.toml ;
- Clippy.

View file

@ -1,12 +1,11 @@
[package] [package]
name = "tun2proxy"
version = "0.1.0"
authors = ["B. Blechschmidt"] authors = ["B. Blechschmidt"]
edition = "2018" edition = "2018"
name = "tun2proxy"
version = "0.1.1"
[dependencies] [dependencies]
smoltcp = { version="0.8.0", git="https://github.com/smoltcp-rs/smoltcp", features = ["std"], rev="cb1828cbe6d19b10cb50d3e4323fa8c5ca25e5e4" } chrono = "0.4"
mio = { version="0.7", features = ["os-poll", "net", "os-util"]} clap = "3.2"
clap = { version = "2.33.3" } mio = { version = "0.8", features = ["os-poll", "net", "os-ext"] }
chrono = {version = "" } smoltcp = { version = "0.8", features = ["std"] }

View file

@ -1,4 +1,7 @@
use crate::tun2proxy::{Connection, TcpProxy, IncomingDirection, OutgoingDirection, OutgoingDataEvent, IncomingDataEvent, ConnectionManager, ProxyError}; use crate::tun2proxy::{
Connection, ConnectionManager, IncomingDataEvent, IncomingDirection, OutgoingDataEvent,
OutgoingDirection, ProxyError, TcpProxy,
};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::net::SocketAddr; use std::net::SocketAddr;
@ -8,7 +11,7 @@ enum HttpState {
SendRequest, SendRequest,
ExpectStatusCode, ExpectStatusCode,
ExpectResponse, ExpectResponse,
Established Established,
} }
pub struct HttpConnection { pub struct HttpConnection {
@ -18,7 +21,7 @@ pub struct HttpConnection {
client_outbuf: VecDeque<u8>, client_outbuf: VecDeque<u8>,
server_outbuf: VecDeque<u8>, server_outbuf: VecDeque<u8>,
data_buf: VecDeque<u8>, data_buf: VecDeque<u8>,
crlf_state: u8 crlf_state: u8,
} }
impl HttpConnection { impl HttpConnection {
@ -30,14 +33,17 @@ impl HttpConnection {
client_outbuf: Default::default(), client_outbuf: Default::default(),
server_outbuf: Default::default(), server_outbuf: Default::default(),
data_buf: Default::default(), data_buf: Default::default(),
crlf_state: Default::default() crlf_state: Default::default(),
}; };
result.server_outbuf.extend(b"CONNECT ".iter()); result.server_outbuf.extend(b"CONNECT ".iter());
result.server_outbuf.extend(connection.dst.to_string().as_bytes()); result
.server_outbuf
.extend(connection.dst.to_string().as_bytes());
result.server_outbuf.extend(b" HTTP/1.1\r\nHost: ".iter()); result.server_outbuf.extend(b" HTTP/1.1\r\nHost: ".iter());
result.server_outbuf.extend(connection.dst.to_string().as_bytes()); result
.server_outbuf
.extend(connection.dst.to_string().as_bytes());
result.server_outbuf.extend(b"\r\n\r\n".iter()); result.server_outbuf.extend(b"\r\n\r\n".iter());
result result
@ -46,12 +52,22 @@ impl HttpConnection {
fn state_change(&mut self) -> Result<(), ProxyError> { fn state_change(&mut self) -> Result<(), ProxyError> {
match self.state { match self.state {
HttpState::ExpectStatusCode if self.server_inbuf.len() >= "HTTP/1.1 200 ".len() => { HttpState::ExpectStatusCode if self.server_inbuf.len() >= "HTTP/1.1 200 ".len() => {
let status_line: Vec<u8> = self.server_inbuf.range(0.."HTTP/1.1 200 ".len()).map(|&x| x).collect(); let status_line: Vec<u8> = self
.server_inbuf
.range(0.."HTTP/1.1 200 ".len())
.copied()
.collect();
let slice = &status_line.as_slice()[0.."HTTP/1.1 2".len()]; let slice = &status_line.as_slice()[0.."HTTP/1.1 2".len()];
if slice != b"HTTP/1.1 2" && slice != b"HTTP/1.0 2" if slice != b"HTTP/1.1 2" && slice != b"HTTP/1.0 2"
|| self.server_inbuf["HTTP/1.1 200 ".len() - 1] != b' '{ || self.server_inbuf["HTTP/1.1 200 ".len() - 1] != b' '
let status_str = String::from_utf8_lossy(&status_line.as_slice()[0.."HTTP/1.1 200".len()]); {
return Err(ProxyError::new("Expected success status code. Server replied with ".to_owned() + &*status_str + ".")); let status_str =
String::from_utf8_lossy(&status_line.as_slice()[0.."HTTP/1.1 200".len()]);
return Err(ProxyError::new(
"Expected success status code. Server replied with ".to_owned()
+ &*status_str
+ ".",
));
} }
self.state = HttpState::ExpectResponse; self.state = HttpState::ExpectResponse;
return self.state_change(); return self.state_change();
@ -86,14 +102,12 @@ impl HttpConnection {
self.server_inbuf.clear(); self.server_inbuf.clear();
self.client_inbuf.clear(); self.client_inbuf.clear();
} }
_ => { _ => {}
}
} }
Ok(()) Ok(())
} }
} }
impl TcpProxy for HttpConnection { impl TcpProxy for HttpConnection {
fn push_data(&mut self, event: IncomingDataEvent<'_>) -> Result<(), ProxyError> { fn push_data(&mut self, event: IncomingDataEvent<'_>) -> Result<(), ProxyError> {
let direction = event.direction; let direction = event.direction;
@ -101,7 +115,7 @@ impl TcpProxy for HttpConnection {
match direction { match direction {
IncomingDirection::FromServer => { IncomingDirection::FromServer => {
self.server_inbuf.extend(buffer.iter()); self.server_inbuf.extend(buffer.iter());
}, }
IncomingDirection::FromClient => { IncomingDirection::FromClient => {
if self.state == HttpState::Established { if self.state == HttpState::Established {
self.client_inbuf.extend(buffer.iter()); self.client_inbuf.extend(buffer.iter());
@ -112,12 +126,10 @@ impl TcpProxy for HttpConnection {
} }
self.state_change() self.state_change()
} }
fn consume_data(&mut self, dir: OutgoingDirection, size: usize) { fn consume_data(&mut self, dir: OutgoingDirection, size: usize) {
let buffer = if dir == OutgoingDirection::ToServer let buffer = if dir == OutgoingDirection::ToServer {
{
&mut self.server_outbuf &mut self.server_outbuf
} else { } else {
&mut self.client_outbuf &mut self.client_outbuf
@ -131,15 +143,14 @@ impl TcpProxy for HttpConnection {
} else { } else {
&mut self.client_outbuf &mut self.client_outbuf
}; };
let event = OutgoingDataEvent { OutgoingDataEvent {
direction: dir, direction: dir,
buffer: buffer.make_contiguous() buffer: buffer.make_contiguous(),
}; }
return event;
} }
fn connection_established(&self) -> bool { fn connection_established(&self) -> bool {
return self.state == HttpState::Established self.state == HttpState::Established
} }
} }
@ -156,7 +167,7 @@ impl ConnectionManager for HttpManager {
if connection.proto != smoltcp::wire::IpProtocol::Tcp.into() { if connection.proto != smoltcp::wire::IpProtocol::Tcp.into() {
return None; return None;
} }
Some(std::boxed::Box::new(HttpConnection::new(&connection))) Some(std::boxed::Box::new(HttpConnection::new(connection)))
} }
fn close_connection(&mut self, _: &Connection) {} fn close_connection(&mut self, _: &Connection) {}
@ -168,8 +179,6 @@ impl ConnectionManager for HttpManager {
impl HttpManager { impl HttpManager {
pub fn new(server: SocketAddr) -> Self { pub fn new(server: SocketAddr) -> Self {
Self { Self { server }
server,
}
} }
} }

View file

@ -1,43 +1,45 @@
#![feature(deque_make_contiguous)]
#![feature(deque_range)]
mod virtdevice;
mod socks5;
mod http; mod http;
mod socks5;
mod tun2proxy; mod tun2proxy;
mod virtdevice;
use socks5::*;
use crate::http::HttpManager; use crate::http::HttpManager;
use crate::tun2proxy::TunToProxy; use crate::tun2proxy::TunToProxy;
use socks5::*;
use std::net::ToSocketAddrs; use std::net::ToSocketAddrs;
fn main() { fn main() {
let matches = clap::App::new(env!("CARGO_PKG_NAME")) let matches = clap::App::new(env!("CARGO_PKG_NAME"))
.version(env!("CARGO_PKG_VERSION")) .version(env!("CARGO_PKG_VERSION"))
.about("Tunnel interface to proxy.") .about("Tunnel interface to proxy.")
.arg(clap::Arg::with_name("tun") .arg(
.short("t") clap::Arg::with_name("tun")
.long("tun") .short('t')
.value_name("TUN") .long("tun")
.help("Name of the tun interface") .value_name("TUN")
.required(true) .help("Name of the tun interface")
.takes_value(true)) .required(true)
.arg(clap::Arg::with_name("socks5_server") .takes_value(true),
.help("SOCKS5 server to use") )
.short("s") .arg(
.long("socks5") clap::Arg::with_name("socks5_server")
.value_name("IP:PORT")) .help("SOCKS5 server to use")
.arg(clap::Arg::with_name("http_server") .short('s')
.help("HTTP server to use") .long("socks5")
.short("h") .value_name("IP:PORT"),
.long("http") )
.value_name("IP:PORT")) .arg(
clap::Arg::with_name("http_server")
.help("HTTP server to use")
.short('h')
.long("http")
.value_name("IP:PORT"),
)
.get_matches(); .get_matches();
if matches.value_of("socks5_server").is_some() if matches.value_of("socks5_server").is_some() && matches.value_of("http_server").is_some()
&& matches.value_of("http_server").is_some() || matches.value_of("socks5_server").is_none() && matches.value_of("http_server").is_none()
|| matches.value_of("socks5_server").is_none() {
&& matches.value_of("http_server").is_none() {
eprintln!("You need to specify exactly one server."); eprintln!("You need to specify exactly one server.");
return; return;
} }
@ -45,8 +47,7 @@ fn main() {
let tun_name = matches.value_of("tun").unwrap(); let tun_name = matches.value_of("tun").unwrap();
let mut ttp = TunToProxy::new(tun_name); let mut ttp = TunToProxy::new(tun_name);
if let Some(addr) = matches.value_of("socks5_server") { if let Some(addr) = matches.value_of("socks5_server") {
if let Ok(mut servers) = addr.to_socket_addrs() if let Ok(mut servers) = addr.to_socket_addrs() {
{
let server = servers.next().unwrap(); let server = servers.next().unwrap();
println!("SOCKS5 server: {}", server); println!("SOCKS5 server: {}", server);
ttp.add_connection_manager(Box::new(Socks5Manager::new(server))); ttp.add_connection_manager(Box::new(Socks5Manager::new(server)));
@ -57,8 +58,7 @@ fn main() {
} }
if let Some(addr) = matches.value_of("http_server") { if let Some(addr) = matches.value_of("http_server") {
if let Ok(mut servers) = addr.to_socket_addrs() if let Ok(mut servers) = addr.to_socket_addrs() {
{
let server = servers.next().unwrap(); let server = servers.next().unwrap();
println!("HTTP server: {}", server); println!("HTTP server: {}", server);
ttp.add_connection_manager(Box::new(HttpManager::new(server))); ttp.add_connection_manager(Box::new(HttpManager::new(server)));

View file

@ -1,4 +1,7 @@
use crate::tun2proxy::{Connection, OutgoingDirection, OutgoingDataEvent, IncomingDirection, IncomingDataEvent, ConnectionManager, TcpProxy, ProxyError}; use crate::tun2proxy::{
Connection, ConnectionManager, IncomingDataEvent, IncomingDirection, OutgoingDataEvent,
OutgoingDirection, ProxyError, TcpProxy,
};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::net::{IpAddr, SocketAddr}; use std::net::{IpAddr, SocketAddr};
@ -9,7 +12,7 @@ enum SocksState {
ServerHello, ServerHello,
SendRequest, SendRequest,
ReceiveResponse, ReceiveResponse,
Established Established,
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -18,14 +21,14 @@ enum SocksState {
enum SocksAddressType { enum SocksAddressType {
Ipv4 = 1, Ipv4 = 1,
DomainName = 3, DomainName = 3,
Ipv6 = 4 Ipv6 = 4,
} }
#[allow(dead_code)] #[allow(dead_code)]
#[repr(u8)] #[repr(u8)]
enum SocksAuthentication { enum SocksAuthentication {
None = 0, None = 0,
Password = 2 Password = 2,
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -39,7 +42,7 @@ enum SocksReplies {
ConnectionRefused, ConnectionRefused,
TtlExpired, TtlExpired,
CommandUnsupported, CommandUnsupported,
AddressUnsupported AddressUnsupported,
} }
impl std::fmt::Display for SocksReplies { impl std::fmt::Display for SocksReplies {
@ -77,20 +80,20 @@ impl SocksConnection {
pub fn state_change(&mut self) -> Result<(), ProxyError> { pub fn state_change(&mut self) -> Result<(), ProxyError> {
let dst_ip = self.connection.dst.ip(); let dst_ip = self.connection.dst.ip();
match self.state { match self.state {
SocksState::ServerHello if self.server_inbuf.len() >= 2 => { SocksState::ServerHello if self.server_inbuf.len() >= 2 => {
if self.server_inbuf[0] != 5 { if self.server_inbuf[0] != 5 {
return Err(ProxyError::new( return Err(ProxyError::new(
"SOCKS server replied with an unexpected version.".into())); "SOCKS server replied with an unexpected version.".into(),
));
} }
if self.server_inbuf[1] != 0 { if self.server_inbuf[1] != 0 {
return Err(ProxyError::new( return Err(ProxyError::new(
"SOCKS server requires an unsupported authentication method.".into())); "SOCKS server requires an unsupported authentication method.".into(),
));
} }
self.server_inbuf.drain(0..2); self.server_inbuf.drain(0..2);
let cmd = if dst_ip.is_ipv4() { 1 } else { 4 }; let cmd = if dst_ip.is_ipv4() { 1 } else { 4 };
@ -101,7 +104,7 @@ impl SocksConnection {
}; };
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;
@ -115,7 +118,9 @@ impl SocksConnection {
let atyp = self.server_inbuf[3]; let atyp = self.server_inbuf[3];
if ver != 5 { if ver != 5 {
return Err(ProxyError::new("SOCKS server replied with an unexpected version.".into())); return Err(ProxyError::new(
"SOCKS server replied with an unexpected version.".into(),
));
} }
if rep != 0 { if rep != 0 {
@ -124,8 +129,11 @@ impl SocksConnection {
if atyp != SocksAddressType::Ipv4 as u8 if atyp != SocksAddressType::Ipv4 as u8
&& atyp != SocksAddressType::Ipv6 as u8 && atyp != SocksAddressType::Ipv6 as u8
&& atyp != SocksAddressType::DomainName as u8 { && atyp != SocksAddressType::DomainName as u8
return Err(ProxyError::new("SOCKS server replied with unrecognized address type.".into())); {
return Err(ProxyError::new(
"SOCKS server replied with unrecognized address type.".into(),
));
} }
if atyp == SocksAddressType::DomainName as u8 && self.server_inbuf.len() < 5 { if atyp == SocksAddressType::DomainName as u8 && self.server_inbuf.len() < 5 {
@ -133,7 +141,8 @@ impl SocksConnection {
} }
if atyp == SocksAddressType::DomainName as u8 if atyp == SocksAddressType::DomainName as u8
&& self.server_inbuf.len() < 7 + (self.server_inbuf[4] as usize) { && self.server_inbuf.len() < 7 + (self.server_inbuf[4] as usize)
{
return Ok(()); return Ok(());
} }
@ -173,7 +182,7 @@ impl TcpProxy for SocksConnection {
match direction { match direction {
IncomingDirection::FromServer => { IncomingDirection::FromServer => {
self.server_inbuf.extend(buffer.iter()); self.server_inbuf.extend(buffer.iter());
}, }
IncomingDirection::FromClient => { IncomingDirection::FromClient => {
if self.state == SocksState::Established { if self.state == SocksState::Established {
self.client_inbuf.extend(buffer.iter()); self.client_inbuf.extend(buffer.iter());
@ -184,12 +193,10 @@ impl TcpProxy for SocksConnection {
} }
self.state_change() self.state_change()
} }
fn consume_data(&mut self, dir: OutgoingDirection, size: usize) { fn consume_data(&mut self, dir: OutgoingDirection, size: usize) {
let buffer = if dir == OutgoingDirection::ToServer let buffer = if dir == OutgoingDirection::ToServer {
{
&mut self.server_outbuf &mut self.server_outbuf
} else { } else {
&mut self.client_outbuf &mut self.client_outbuf
@ -203,15 +210,14 @@ impl TcpProxy for SocksConnection {
} else { } else {
&mut self.client_outbuf &mut self.client_outbuf
}; };
let event = OutgoingDataEvent { OutgoingDataEvent {
direction: dir, direction: dir,
buffer: buffer.make_contiguous() buffer: buffer.make_contiguous(),
}; }
return event;
} }
fn connection_established(&self) -> bool { fn connection_established(&self) -> bool {
return self.state == SocksState::Established self.state == SocksState::Established
} }
} }
@ -231,7 +237,7 @@ impl ConnectionManager for Socks5Manager {
if connection.proto != smoltcp::wire::IpProtocol::Tcp.into() { if connection.proto != smoltcp::wire::IpProtocol::Tcp.into() {
return None; return None;
} }
Some(std::boxed::Box::new(SocksConnection::new(&connection))) Some(std::boxed::Box::new(SocksConnection::new(connection)))
} }
fn close_connection(&mut self, _: &Connection) {} fn close_connection(&mut self, _: &Connection) {}
@ -247,7 +253,7 @@ impl Socks5Manager {
server, server,
authentication: SocksAuthentication::None, authentication: SocksAuthentication::None,
username: Default::default(), username: Default::default(),
password: Default::default() password: Default::default(),
} }
} }
@ -258,4 +264,4 @@ impl Socks5Manager {
self.username = Vec::from(username); self.username = Vec::from(username);
self.password = Vec::from(password); self.password = Vec::from(password);
} }
} }

View file

@ -1,30 +1,27 @@
use crate::virtdevice::VirtualTunDevice;
use mio::event::Event;
use mio::net::TcpStream;
use mio::unix::SourceFd;
use mio::{Events, Interest, Poll, Token};
use smoltcp::iface::{Interface, InterfaceBuilder, Routes, SocketHandle};
use smoltcp::phy::{Device, Medium, RxToken, TunTapInterface, TxToken};
use smoltcp::socket::{TcpSocket, TcpSocketBuffer};
use smoltcp::time::Instant;
use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Packet, Ipv6Packet, TcpPacket, UdpPacket};
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::convert::From; use std::convert::From;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::net::{IpAddr, SocketAddr, Shutdown}; use std::net::Shutdown::Both;
use std::net::{IpAddr, Shutdown, SocketAddr};
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use mio::{Events, Interest, Poll, Token};
use mio::event::Event;
use mio::net::{TcpSocket as MioTcp, TcpStream};
use mio::unix::SourceFd;
use smoltcp::iface::{Interface, InterfaceBuilder, Routes};
use smoltcp::phy::{Device, Medium, RxToken, TunTapInterface, TxToken};
use smoltcp::socket::{SocketHandle, SocketSet, TcpSocket, TcpSocketBuffer};
use smoltcp::time::Instant;
use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Packet, TcpPacket, UdpPacket, Ipv6Packet};
use crate::virtdevice::VirtualTunDevice;
use std::net::Shutdown::Both;
pub struct ProxyError { pub struct ProxyError {
message: String message: String,
} }
impl ProxyError { impl ProxyError {
pub fn new(message: String) -> Self { pub fn new(message: String) -> Self {
Self { Self { message }
message
}
} }
pub fn message(&self) -> String { pub fn message(&self) -> String {
@ -32,11 +29,11 @@ impl ProxyError {
} }
} }
#[derive(Hash, Clone, Copy)] #[derive(Hash, Clone, Copy, Eq, PartialEq)]
pub struct Connection { pub struct Connection {
pub src: std::net::SocketAddr, pub src: std::net::SocketAddr,
pub dst: std::net::SocketAddr, pub dst: std::net::SocketAddr,
pub proto: u8 pub proto: u8,
} }
impl std::fmt::Display for Connection { impl std::fmt::Display for Connection {
@ -45,93 +42,92 @@ impl std::fmt::Display for Connection {
} }
} }
impl Eq for Connection {}
impl PartialEq<Self> for Connection {
fn eq(&self, other: &Self) -> bool {
return other.src == self.src && other.dst == self.dst && other.proto == self.proto;
}
}
#[derive(Eq, PartialEq, Debug)] #[derive(Eq, PartialEq, Debug)]
pub(crate) enum IncomingDirection { pub(crate) enum IncomingDirection {
FromServer, FromServer,
FromClient FromClient,
} }
#[derive(Eq, PartialEq, Debug)] #[derive(Eq, PartialEq, Debug)]
pub(crate) enum OutgoingDirection { pub(crate) enum OutgoingDirection {
ToServer, ToServer,
ToClient ToClient,
} }
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) enum ConnectionEvent<'a> { pub(crate) enum ConnectionEvent<'a> {
NewConnection(&'a Connection), NewConnection(&'a Connection),
ConnectionClosed(&'a Connection) ConnectionClosed(&'a Connection),
} }
pub(crate) struct DataEvent<'a, T> { pub(crate) struct DataEvent<'a, T> {
pub(crate) direction: T, pub(crate) direction: T,
pub(crate) buffer: &'a [u8] pub(crate) buffer: &'a [u8],
} }
pub(crate) type IncomingDataEvent<'a> = DataEvent<'a, IncomingDirection>; pub(crate) type IncomingDataEvent<'a> = DataEvent<'a, IncomingDirection>;
pub(crate) type OutgoingDataEvent<'a> = DataEvent<'a, OutgoingDirection>; pub(crate) type OutgoingDataEvent<'a> = DataEvent<'a, OutgoingDirection>;
fn get_transport_info(proto: u8, transport_offset: usize, packet: &[u8]) -> Option<((u16, u16), bool, usize, usize)> { fn get_transport_info(
proto: u8,
transport_offset: usize,
packet: &[u8],
) -> Option<((u16, u16), bool, usize, usize)> {
if proto == smoltcp::wire::IpProtocol::Udp.into() { if proto == smoltcp::wire::IpProtocol::Udp.into() {
match UdpPacket::new_checked(packet) { match UdpPacket::new_checked(packet) {
Ok(result) => { Ok(result) => Some((
Some(((result.src_port(), result.dst_port()), false, transport_offset + 8, packet.len() - 8)) (result.src_port(), result.dst_port()),
}, false,
Err(_) => None transport_offset + 8,
packet.len() - 8,
)),
Err(_) => None,
} }
} else if proto == smoltcp::wire::IpProtocol::Tcp.into() { } else if proto == smoltcp::wire::IpProtocol::Tcp.into() {
match TcpPacket::new_checked(packet) { match TcpPacket::new_checked(packet) {
Ok(result) => { Ok(result) => Some((
Some(((result.src_port(), result.dst_port()), result.syn() && !result.ack(), (result.src_port(), result.dst_port()),
transport_offset + result.header_len() as usize, packet.len())) result.syn() && !result.ack(),
}, transport_offset + result.header_len() as usize,
Err(_) => None packet.len(),
)),
Err(_) => None,
} }
} } else {
else {
None None
} }
} }
fn connection_tuple(frame: &[u8]) -> Option<(Connection, bool, usize, usize)> { fn connection_tuple(frame: &[u8]) -> Option<(Connection, bool, usize, usize)> {
match Ipv4Packet::new_checked(frame) { if let Ok(packet) = Ipv4Packet::new_checked(frame) {
Ok(packet) => { let proto: u8 = packet.protocol().into();
let proto:u8 = packet.protocol().into();
let mut a: [u8; 4] = Default::default(); let mut a: [u8; 4] = Default::default();
a.copy_from_slice(packet.src_addr().as_bytes()); a.copy_from_slice(packet.src_addr().as_bytes());
let src_addr = IpAddr::from(a); let src_addr = IpAddr::from(a);
a.copy_from_slice(packet.dst_addr().as_bytes()); a.copy_from_slice(packet.dst_addr().as_bytes());
let dst_addr = IpAddr::from(a); let dst_addr = IpAddr::from(a);
if let Some((ports, first_packet, payload_offset, payload_size))
= get_transport_info(proto,packet.header_len().into(), &frame[packet.header_len().into()..]) {
let connection = Connection {
src: SocketAddr::new(src_addr, ports.0),
dst: SocketAddr::new(dst_addr, ports.1),
proto
};
return Some((connection, first_packet, payload_offset, payload_size));
} else {
return None;
}
if let Some((ports, first_packet, payload_offset, payload_size)) = get_transport_info(
proto,
packet.header_len().into(),
&frame[packet.header_len().into()..],
) {
let connection = Connection {
src: SocketAddr::new(src_addr, ports.0),
dst: SocketAddr::new(dst_addr, ports.1),
proto,
};
return Some((connection, first_packet, payload_offset, payload_size));
} else {
return None;
} }
_ => { }
} }
match Ipv6Packet::new_checked(frame) { match Ipv6Packet::new_checked(frame) {
Ok(packet) => { Ok(packet) => {
// TODO: Support extension headers. // TODO: Support extension headers.
let proto:u8 = packet.next_header().into(); let proto: u8 = packet.next_header().into();
let mut a: [u8; 16] = Default::default(); let mut a: [u8; 16] = Default::default();
a.copy_from_slice(packet.src_addr().as_bytes()); a.copy_from_slice(packet.src_addr().as_bytes());
@ -139,20 +135,20 @@ fn connection_tuple(frame: &[u8]) -> Option<(Connection, bool, usize, usize)> {
a.copy_from_slice(packet.dst_addr().as_bytes()); a.copy_from_slice(packet.dst_addr().as_bytes());
let dst_addr = IpAddr::from(a); let dst_addr = IpAddr::from(a);
if let Some((ports, first_packet, payload_offset, payload_size)) if let Some((ports, first_packet, payload_offset, payload_size)) =
= get_transport_info(proto,packet.header_len().into(), &frame[packet.header_len().into()..]) { get_transport_info(proto, packet.header_len(), &frame[packet.header_len()..])
{
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),
proto proto,
}; };
Some((connection, first_packet, payload_offset, payload_size)) Some((connection, first_packet, payload_offset, payload_size))
} else { } else {
None None
} }
} }
_ => None _ => None,
} }
} }
@ -160,7 +156,7 @@ struct ConnectionState {
smoltcp_handle: SocketHandle, smoltcp_handle: SocketHandle,
mio_stream: TcpStream, mio_stream: TcpStream,
token: Token, token: Token,
handler: std::boxed::Box<dyn TcpProxy> handler: std::boxed::Box<dyn TcpProxy>,
} }
pub(crate) trait TcpProxy { pub(crate) trait TcpProxy {
@ -187,30 +183,35 @@ pub(crate) struct TunToProxy<'a> {
connection_managers: Vec<std::boxed::Box<dyn ConnectionManager>>, connection_managers: Vec<std::boxed::Box<dyn ConnectionManager>>,
next_token: usize, next_token: usize,
token_to_connection: HashMap<Token, Connection>, token_to_connection: HashMap<Token, Connection>,
socketset: SocketSet<'a>
} }
impl<'a> TunToProxy<'a> { impl<'a> TunToProxy<'a> {
pub(crate) fn new(interface: &str) -> Self { pub(crate) fn new(interface: &str) -> Self {
let tun_token = Token(0); let tun_token = Token(0);
let tun = TunTapInterface::new(interface, Medium::Ip).unwrap(); let tun = TunTapInterface::new(interface, Medium::Ip).unwrap();
let poll = Poll::new().unwrap(); let poll = Poll::new().unwrap();
poll.registry().register(&mut SourceFd(&tun.as_raw_fd()), tun_token, Interest::READABLE).unwrap(); poll.registry()
.register(
&mut SourceFd(&tun.as_raw_fd()),
tun_token,
Interest::READABLE,
)
.unwrap();
let virt = VirtualTunDevice::new(tun.capabilities()); let virt = VirtualTunDevice::new(tun.capabilities());
let builder = InterfaceBuilder::new(virt); let builder = InterfaceBuilder::new(virt, vec![]);
let ip_addrs = [ let ip_addrs = [IpCidr::new(IpAddress::v4(0, 0, 0, 1), 0)];
IpCidr::new(IpAddress::v4(0, 0, 0, 1), 0),
];
let mut routes = Routes::new(BTreeMap::new()); let mut routes = Routes::new(BTreeMap::new());
routes.add_default_ipv4_route(Ipv4Address::new(0, 0, 0, 1)).unwrap(); routes
.add_default_ipv4_route(Ipv4Address::new(0, 0, 0, 1))
.unwrap();
let iface = builder.any_ip(true)
.ip_addrs(ip_addrs).routes(routes).finalize();
let iface = builder
.any_ip(true)
.ip_addrs(ip_addrs)
.routes(routes)
.finalize();
Self { Self {
tun, tun,
@ -221,8 +222,7 @@ impl<'a> TunToProxy<'a> {
connections: Default::default(), connections: Default::default(),
next_token: 2, next_token: 2,
token_to_connection: Default::default(), token_to_connection: Default::default(),
socketset: SocketSet::new([]), connection_managers: Default::default(),
connection_managers: Default::default()
} }
} }
@ -231,30 +231,37 @@ impl<'a> TunToProxy<'a> {
} }
fn expect_smoltcp_send(&mut self) { fn expect_smoltcp_send(&mut self) {
self.iface.poll(&mut self.socketset, Instant::now()).unwrap(); self.iface.poll(Instant::now()).unwrap();
while let Some(vec) = self.iface.device_mut().exfiltrate_packet() { while let Some(vec) = self.iface.device_mut().exfiltrate_packet() {
let slice = vec.as_slice(); let slice = vec.as_slice();
// TODO: Actual write. Replace. // TODO: Actual write. Replace.
self.tun.transmit().unwrap().consume(Instant::now(), slice.len(), |buf| { self.tun
buf[..].clone_from_slice(slice); .transmit()
Ok(()) .unwrap()
}).unwrap(); .consume(Instant::now(), slice.len(), |buf| {
buf[..].clone_from_slice(slice);
Ok(())
})
.unwrap();
} }
} }
fn remove_connection(&mut self, connection: &Connection) { fn remove_connection(&mut self, connection: &Connection) {
let mut connection_state = self.connections.remove(connection).unwrap(); let mut connection_state = self.connections.remove(connection).unwrap();
self.token_to_connection.remove(&connection_state.token); self.token_to_connection.remove(&connection_state.token);
self.poll.registry().deregister(&mut connection_state.mio_stream).unwrap(); self.poll
.registry()
.deregister(&mut connection_state.mio_stream)
.unwrap();
println!("[{:?}] CLOSE {}", chrono::offset::Local::now(), connection); println!("[{:?}] CLOSE {}", chrono::offset::Local::now(), connection);
} }
fn get_connection_manager(&self, connection: &Connection) -> Option<&Box<dyn ConnectionManager>>{ fn get_connection_manager(&self, connection: &Connection) -> Option<&dyn ConnectionManager> {
for manager in self.connection_managers.iter() { for manager in self.connection_managers.iter() {
if manager.handles_connection(connection) { if manager.handles_connection(connection) {
return Some(manager); return Some(manager.as_ref());
} }
} }
None None
@ -265,46 +272,51 @@ impl<'a> TunToProxy<'a> {
} }
fn tunsocket_read_and_forward(&mut self, connection: &Connection) { fn tunsocket_read_and_forward(&mut self, connection: &Connection) {
if let Some(state) = self.connections.get_mut(&connection) { if let Some(state) = self.connections.get_mut(connection) {
let closed = { let closed = {
let mut socket = self.socketset.get::<TcpSocket>(state.smoltcp_handle); let socket = self.iface.get_socket::<TcpSocket>(state.smoltcp_handle);
let mut error = Ok(()); let mut error = Ok(());
while socket.can_recv() && error.is_ok() { while socket.can_recv() && error.is_ok() {
socket.recv(|data| { socket
let event = IncomingDataEvent { .recv(|data| {
direction: IncomingDirection::FromClient, let event = IncomingDataEvent {
buffer: data, direction: IncomingDirection::FromClient,
buffer: data,
};
error = state.handler.push_data(event);
}; (data.len(), ())
error = state.handler.push_data(event); })
.unwrap();
(data.len(), ())
}).unwrap();
} }
if error.is_err() { match error {
Self::print_error(error.unwrap_err()); Ok(_) => socket.state() == smoltcp::socket::TcpState::CloseWait,
true Err(e) => {
} else { Self::print_error(e);
socket.state() == smoltcp::socket::TcpState::CloseWait true
}
} }
}; };
if closed { if closed {
let connection_state = self.connections.get_mut(&connection).unwrap(); let connection_state = self.connections.get_mut(connection).unwrap();
connection_state.mio_stream.shutdown(Shutdown::Both).unwrap(); connection_state
self.remove_connection(&connection); .mio_stream
return; .shutdown(Shutdown::Both)
.unwrap();
self.remove_connection(connection);
} }
} }
} }
fn receive_tun(&mut self, frame: &mut [u8]) { fn receive_tun(&mut self, frame: &mut [u8]) {
if let Some((connection, first_packet, _payload_offset, _payload_size)) = connection_tuple(frame) { if let Some((connection, first_packet, _payload_offset, _payload_size)) =
connection_tuple(frame)
{
if connection.proto == smoltcp::wire::IpProtocol::Tcp.into() { if connection.proto == smoltcp::wire::IpProtocol::Tcp.into() {
let cm = self.get_connection_manager(&connection); let cm = self.get_connection_manager(&connection);
if !cm.is_some() { if cm.is_none() {
return; return;
} }
let server = cm.unwrap().get_server(); let server = cm.unwrap().get_server();
@ -313,17 +325,13 @@ impl<'a> TunToProxy<'a> {
if let Some(handler) = manager.new_connection(&connection) { if let Some(handler) = manager.new_connection(&connection) {
let mut socket = TcpSocket::new( let mut socket = TcpSocket::new(
TcpSocketBuffer::new(vec![0; 4096]), TcpSocketBuffer::new(vec![0; 4096]),
TcpSocketBuffer::new(vec![0; 4096])); TcpSocketBuffer::new(vec![0; 4096]),
);
socket.set_ack_delay(None); socket.set_ack_delay(None);
socket.listen(connection.dst).unwrap(); socket.listen(connection.dst).unwrap();
let handle = self.socketset.add(socket); let handle = self.iface.add_socket(socket);
let socket = if server.is_ipv4() { let client = TcpStream::connect(server).unwrap();
MioTcp::new_v4().unwrap()
} else {
MioTcp::new_v6().unwrap()
};
let client = socket.connect(server).unwrap();
let token = Token(self.next_token); let token = Token(self.next_token);
self.next_token += 1; self.next_token += 1;
@ -332,18 +340,26 @@ impl<'a> TunToProxy<'a> {
smoltcp_handle: handle, smoltcp_handle: handle,
mio_stream: client, mio_stream: client,
token, token,
handler handler,
}; };
self.token_to_connection.insert(token, connection); self.token_to_connection.insert(token, connection);
self.poll.registry().register(&mut state.mio_stream, token, Interest::READABLE | Interest::WRITABLE).unwrap(); self.poll
.registry()
.register(
&mut state.mio_stream,
token,
Interest::READABLE | Interest::WRITABLE,
)
.unwrap();
self.connections.insert(connection, state); self.connections.insert(connection, state);
println!(
"[{:?}] CONNECT {}",
chrono::offset::Local::now(),
println!("[{:?}] CONNECT {}", chrono::offset::Local::now(), connection); connection
);
break; break;
} }
} }
@ -365,8 +381,7 @@ impl<'a> TunToProxy<'a> {
// The connection handler builds up the connection or encapsulates the data. // The connection handler builds up the connection or encapsulates the data.
// Therefore, we now expect it to write data to the server. // Therefore, we now expect it to write data to the server.
self.write_to_server(&connection); self.write_to_server(&connection);
} } else if connection.proto == smoltcp::wire::IpProtocol::Udp.into() {
else if connection.proto == smoltcp::wire::IpProtocol::Udp.into() {
/* // UDP is not yet supported. /* // UDP is not yet supported.
if payload_offset > frame.len() || payload_offset + payload_offset > frame.len() { if payload_offset > frame.len() || payload_offset + payload_offset > frame.len() {
return; return;
@ -377,17 +392,19 @@ impl<'a> TunToProxy<'a> {
} }
fn write_to_server(&mut self, connection: &Connection) { fn write_to_server(&mut self, connection: &Connection) {
if let Some(state) = self.connections.get_mut(&connection) { if let Some(state) = self.connections.get_mut(connection) {
let event = state.handler.peek_data(OutgoingDirection::ToServer); let event = state.handler.peek_data(OutgoingDirection::ToServer);
if event.buffer.len() == 0 { if event.buffer.is_empty() {
return; return;
} }
let result = state.mio_stream.write(event.buffer); let result = state.mio_stream.write(event.buffer);
match result { match result {
Ok(consumed) => { Ok(consumed) => {
state.handler.consume_data(OutgoingDirection::ToServer, consumed); state
.handler
.consume_data(OutgoingDirection::ToServer, consumed);
} }
Err(error) if error.kind() != std::io::ErrorKind::WouldBlock => { Err(error) if error.kind() != std::io::ErrorKind::WouldBlock => {
panic!("Error: {:?}", error); panic!("Error: {:?}", error);
} }
_ => { _ => {
@ -398,12 +415,14 @@ impl<'a> TunToProxy<'a> {
} }
fn write_to_client(&mut self, connection: &Connection) { fn write_to_client(&mut self, connection: &Connection) {
if let Some(state) = self.connections.get_mut(&connection) { if let Some(state) = self.connections.get_mut(connection) {
let event = state.handler.peek_data(OutgoingDirection::ToClient); let event = state.handler.peek_data(OutgoingDirection::ToClient);
let socket = &mut self.socketset.get::<TcpSocket>(state.smoltcp_handle); let socket = &mut self.iface.get_socket::<TcpSocket>(state.smoltcp_handle);
if socket.may_send() { if socket.may_send() {
let consumed = socket.send_slice(event.buffer).unwrap(); let consumed = socket.send_slice(event.buffer).unwrap();
state.handler.consume_data(OutgoingDirection::ToClient, consumed); state
.handler
.consume_data(OutgoingDirection::ToClient, consumed);
} }
} }
} }
@ -433,7 +452,9 @@ impl<'a> TunToProxy<'a> {
if read == 0 { if read == 0 {
{ {
let mut socket = self.socketset.get::<TcpSocket>(self.connections.get(&connection).unwrap().smoltcp_handle); let socket = self.iface.get_socket::<TcpSocket>(
self.connections.get(&connection).unwrap().smoltcp_handle,
);
socket.close(); socket.close();
} }
self.expect_smoltcp_send(); self.expect_smoltcp_send();
@ -444,12 +465,13 @@ impl<'a> TunToProxy<'a> {
let event = IncomingDataEvent { let event = IncomingDataEvent {
direction: IncomingDirection::FromServer, direction: IncomingDirection::FromServer,
buffer: &buf[0..read], buffer: &buf[0..read],
}; };
if let Err(error) = state.handler.push_data(event) { if let Err(error) = state.handler.push_data(event) {
state.mio_stream.shutdown(Both).unwrap(); state.mio_stream.shutdown(Both).unwrap();
{ {
let mut socket = self.socketset.get::<TcpSocket>(self.connections.get(&connection).unwrap().smoltcp_handle); let socket = self.iface.get_socket::<TcpSocket>(
self.connections.get(&connection).unwrap().smoltcp_handle,
);
socket.close(); socket.close();
} }
self.expect_smoltcp_send(); self.expect_smoltcp_send();
@ -471,12 +493,9 @@ impl<'a> TunToProxy<'a> {
} }
} }
fn udp_event(&mut self, _event: &Event) { fn udp_event(&mut self, _event: &Event) {}
}
pub(crate) fn run(&mut self) { pub(crate) fn run(&mut self) {
let mut events = Events::with_capacity(1024); let mut events = Events::with_capacity(1024);
loop { loop {
@ -492,4 +511,4 @@ impl<'a> TunToProxy<'a> {
} }
} }
} }
} }

View file

@ -6,17 +6,16 @@ use smoltcp::time::Instant;
pub struct VirtualTunDevice { pub struct VirtualTunDevice {
capabilities: DeviceCapabilities, capabilities: DeviceCapabilities,
inbuf: Vec<Vec<u8>>, inbuf: Vec<Vec<u8>>,
outbuf: Vec<Vec<u8>> outbuf: Vec<Vec<u8>>,
} }
impl VirtualTunDevice { impl VirtualTunDevice {
pub fn inject_packet(self: &mut Self, buffer: &[u8]) { pub fn inject_packet(&mut self, buffer: &[u8]) {
let vec = Vec::from(buffer); let vec = Vec::from(buffer);
self.inbuf.push(vec); self.inbuf.push(vec);
} }
pub fn exfiltrate_packet(self: &mut Self, ) -> Option<Vec<u8>> { pub fn exfiltrate_packet(&mut self) -> Option<Vec<u8>> {
self.outbuf.pop() self.outbuf.pop()
} }
} }
@ -27,8 +26,8 @@ pub struct VirtRxToken {
impl phy::RxToken for VirtRxToken { impl phy::RxToken for VirtRxToken {
fn consume<R, F>(mut self, _timestamp: Instant, f: F) -> smoltcp::Result<R> fn consume<R, F>(mut self, _timestamp: Instant, f: F) -> smoltcp::Result<R>
where where
F: FnOnce(&mut [u8]) -> smoltcp::Result<R>, F: FnOnce(&mut [u8]) -> smoltcp::Result<R>,
{ {
f(&mut self.buffer[..]) f(&mut self.buffer[..])
} }
@ -38,12 +37,12 @@ pub struct VirtTxToken<'a>(&'a mut VirtualTunDevice);
impl<'a> phy::TxToken for VirtTxToken<'a> { impl<'a> phy::TxToken for VirtTxToken<'a> {
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> smoltcp::Result<R> fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> smoltcp::Result<R>
where where
F: FnOnce(&mut [u8]) -> smoltcp::Result<R>, F: FnOnce(&mut [u8]) -> smoltcp::Result<R>,
{ {
let mut buffer = vec![0; len]; let mut buffer = vec![0; len];
let result = f(&mut buffer); let result = f(&mut buffer);
self.0.outbuf.push(Vec::from(buffer)); self.0.outbuf.push(buffer);
result result
} }
} }
@ -70,11 +69,11 @@ impl<'a> Device<'a> for VirtualTunDevice {
} }
} }
impl<'a> VirtualTunDevice { impl VirtualTunDevice {
pub fn new(capabilities: DeviceCapabilities) -> Self { pub fn new(capabilities: DeviceCapabilities) -> Self {
Self { Self {
capabilities, capabilities,
..Default::default() ..Default::default()
} }
} }
} }