Virtual interface thread

This commit is contained in:
Aram 🍐 2021-10-13 21:03:23 -04:00
parent 7b5aefa623
commit 8f5f8670af
2 changed files with 81 additions and 15 deletions

View file

@ -9,6 +9,7 @@ use std::time::Duration;
use anyhow::Context; use anyhow::Context;
use tokio::io::Interest; use tokio::io::Interest;
use tokio::net::{TcpListener, TcpStream}; use tokio::net::{TcpListener, TcpStream};
use tokio::sync::mpsc::error::TryRecvError;
use crate::config::Config; use crate::config::Config;
use crate::port_pool::PortPool; use crate::port_pool::PortPool;
@ -112,12 +113,20 @@ async fn handle_tcp_proxy_connection(
virtual_port: u16, virtual_port: u16,
wg: Arc<WireGuardTunnel>, wg: Arc<WireGuardTunnel>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
// Abort signal for stopping the Virtual Interface
let abort = Arc::new(AtomicBool::new(false)); let abort = Arc::new(AtomicBool::new(false));
// data_to_real_client_(tx/rx): This task reads the data from this mpsc channel to send back
// to the real client.
let (data_to_real_client_tx, mut data_to_real_client_rx) =
tokio::sync::mpsc::channel(1_000_000);
// Spawn virtual interface // Spawn virtual interface
{ {
let abort = abort.clone(); let abort = abort.clone();
tokio::spawn(async move { virtual_tcp_interface(virtual_port, wg, abort).await }); tokio::spawn(async move {
virtual_tcp_interface(virtual_port, wg, abort, data_to_real_client_tx).await
});
} }
loop { loop {
@ -140,7 +149,7 @@ async fn handle_tcp_proxy_connection(
"[{}] Read {} bytes of TCP data from real client", "[{}] Read {} bytes of TCP data from real client",
virtual_port, size virtual_port, size
); );
trace!("[{}] {:?}", virtual_port, data); trace!("[{}] Read: {:?}", virtual_port, data);
} }
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => { Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
continue; continue;
@ -156,11 +165,42 @@ async fn handle_tcp_proxy_connection(
} }
} }
if ready.is_writable() {} if ready.is_writable() {
// Flush the data_to_real_client_rx channel
match data_to_real_client_rx.try_recv() {
Ok(data) => match socket.try_write(&data) {
Ok(size) => {
debug!(
"[{}] Wrote {} bytes of TCP data to real client",
virtual_port, size
);
}
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
error!(
"[{}] Failed to write to client TCP socket: {:?}",
virtual_port, e
);
}
},
Err(e) => match e {
TryRecvError::Empty => {
// Nothing else to consume in the data channel.
}
TryRecvError::Disconnected => {
// Channel is broken, probably terminated.
}
},
}
}
if ready.is_read_closed() || ready.is_write_closed() { if ready.is_read_closed() || ready.is_write_closed() {
break; break;
} }
tokio::time::sleep(Duration::from_millis(5)).await;
} }
trace!("[{}] TCP socket handler task terminated", virtual_port); trace!("[{}] TCP socket handler task terminated", virtual_port);
@ -172,12 +212,35 @@ async fn virtual_tcp_interface(
virtual_port: u16, virtual_port: u16,
wg: Arc<WireGuardTunnel>, wg: Arc<WireGuardTunnel>,
abort: Arc<AtomicBool>, abort: Arc<AtomicBool>,
data_to_real_client_tx: tokio::sync::mpsc::Sender<Vec<u8>>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
// Create a device and interface to simulate IP packets
// In essence:
// * TCP packets received from the 'real' client are 'sent' via the 'virtual client'
// * Those TCP packets generate IP packets, which are captured from the interface and sent to the WireGuardTunnel
// * IP packets received by the WireGuardTunnel (from the endpoint) are fed into this 'virtual interface'
// * The interface processes those IP packets and routes them to the 'virtual client' (the rest is discarded)
// * The TCP data read by the 'virtual client' is sent to the 'real' TCP client
loop { loop {
if abort.load(Ordering::Relaxed) { if abort.load(Ordering::Relaxed) {
break; break;
} }
tokio::time::sleep(Duration::from_millis(100)).await;
// Test START
tokio::time::sleep(Duration::from_millis(1000)).await;
match data_to_real_client_tx.send(b"pong".to_vec()).await {
Ok(_) => {
trace!("Wrote stuff in the data_to_real_client_tx")
}
Err(e) => {
trace!(
"[{}] Virtual interface failed to dispatch data to parent task: {:?}",
virtual_port,
e
);
}
}
// Test END
} }
trace!("[{}] Virtual interface task terminated", virtual_port); trace!("[{}] Virtual interface task terminated", virtual_port);
Ok(()) Ok(())

View file

@ -3,6 +3,7 @@ use std::time::Duration;
use anyhow::Context; use anyhow::Context;
use boringtun::noise::{Tunn, TunnResult}; use boringtun::noise::{Tunn, TunnResult};
use log::Level;
use tokio::net::UdpSocket; use tokio::net::UdpSocket;
use crate::config::Config; use crate::config::Config;
@ -203,17 +204,19 @@ impl WireGuardTunnel {
} }
fn trace_ip_packet(packet: &[u8]) { fn trace_ip_packet(packet: &[u8]) {
use smoltcp::wire::*; if log_enabled!(Level::Trace) {
use smoltcp::wire::*;
match IpVersion::of_packet(&packet) { match IpVersion::of_packet(&packet) {
Ok(IpVersion::Ipv4) => trace!( Ok(IpVersion::Ipv4) => trace!(
"IPv4 packet received: {}", "IPv4 packet received: {}",
PrettyPrinter::<Ipv4Packet<&mut [u8]>>::new("", &packet) PrettyPrinter::<Ipv4Packet<&mut [u8]>>::new("", &packet)
), ),
Ok(IpVersion::Ipv6) => trace!( Ok(IpVersion::Ipv6) => trace!(
"IPv6 packet received: {}", "IPv6 packet received: {}",
PrettyPrinter::<Ipv6Packet<&mut [u8]>>::new("", &packet) PrettyPrinter::<Ipv6Packet<&mut [u8]>>::new("", &packet)
), ),
_ => {} _ => {}
}
} }
} }