mirror of
https://github.com/aramperes/onetun.git
synced 2025-09-09 06:38:32 -04:00
Implement IP sink interface
This commit is contained in:
parent
cfdbdc8f51
commit
2bcb9e714b
4 changed files with 82 additions and 6 deletions
35
src/ip_sink.rs
Normal file
35
src/ip_sink.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
use crate::virtual_device::VirtualIpDevice;
|
||||||
|
use crate::wg::WireGuardTunnel;
|
||||||
|
use smoltcp::iface::InterfaceBuilder;
|
||||||
|
use smoltcp::socket::SocketSet;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::time::Duration;
|
||||||
|
|
||||||
|
/// A repeating task that processes unroutable IP packets.
|
||||||
|
pub async fn run_ip_sink_interface(wg: Arc<WireGuardTunnel>) -> ! {
|
||||||
|
// Initialize interface
|
||||||
|
let device = VirtualIpDevice::new_sink(wg)
|
||||||
|
.await
|
||||||
|
.expect("Failed to initialize VirtualIpDevice for sink interface");
|
||||||
|
|
||||||
|
// No sockets on sink interface
|
||||||
|
let mut socket_set_entries: [_; 0] = Default::default();
|
||||||
|
let mut socket_set = SocketSet::new(&mut socket_set_entries[..]);
|
||||||
|
let mut virtual_interface = InterfaceBuilder::new(device).ip_addrs([]).finalize();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let loop_start = smoltcp::time::Instant::now();
|
||||||
|
match virtual_interface.poll(&mut socket_set, loop_start) {
|
||||||
|
Ok(processed) if processed => {
|
||||||
|
trace!("[SINK] Virtual interface polled some packets to be processed",);
|
||||||
|
tokio::time::sleep(Duration::from_millis(1)).await;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("[SINK] Virtual interface poll error: {:?}", e);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
tokio::time::sleep(Duration::from_millis(5)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ use crate::virtual_device::VirtualIpDevice;
|
||||||
use crate::wg::WireGuardTunnel;
|
use crate::wg::WireGuardTunnel;
|
||||||
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod ip_sink;
|
||||||
pub mod port_pool;
|
pub mod port_pool;
|
||||||
pub mod virtual_device;
|
pub mod virtual_device;
|
||||||
pub mod wg;
|
pub mod wg;
|
||||||
|
@ -47,6 +48,12 @@ async fn main() -> anyhow::Result<()> {
|
||||||
tokio::spawn(async move { wg.consume_task().await });
|
tokio::spawn(async move { wg.consume_task().await });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Start IP sink task for incoming IP packets
|
||||||
|
let wg = wg.clone();
|
||||||
|
tokio::spawn(async move { ip_sink::run_ip_sink_interface(wg).await });
|
||||||
|
}
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Tunnelling [{}]->[{}] (via [{}] as peer {})",
|
"Tunnelling [{}]->[{}] (via [{}] as peer {})",
|
||||||
&config.source_addr, &config.dest_addr, &config.endpoint_addr, &config.source_peer_ip
|
&config.source_addr, &config.dest_addr, &config.endpoint_addr, &config.source_peer_ip
|
||||||
|
@ -278,7 +285,6 @@ async fn virtual_tcp_interface(
|
||||||
IpCidr::new(IpAddress::from(source_peer_ip), 32),
|
IpCidr::new(IpAddress::from(source_peer_ip), 32),
|
||||||
IpCidr::new(IpAddress::from(dest_addr.ip()), 32),
|
IpCidr::new(IpAddress::from(dest_addr.ip()), 32),
|
||||||
])
|
])
|
||||||
.any_ip(true)
|
|
||||||
.finalize();
|
.finalize();
|
||||||
|
|
||||||
// Server socket: this is a placeholder for the interface to route new connections to.
|
// Server socket: this is a placeholder for the interface to route new connections to.
|
||||||
|
|
|
@ -22,6 +22,14 @@ impl VirtualIpDevice {
|
||||||
|
|
||||||
Ok(Self { wg, ip_dispatch_rx })
|
Ok(Self { wg, ip_dispatch_rx })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn new_sink(wg: Arc<WireGuardTunnel>) -> anyhow::Result<Self> {
|
||||||
|
let ip_dispatch_rx = wg
|
||||||
|
.register_sink_interface()
|
||||||
|
.await
|
||||||
|
.with_context(|| "Failed to register IP dispatch for sink virtual interface")?;
|
||||||
|
Ok(Self { wg, ip_dispatch_rx })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Device<'a> for VirtualIpDevice {
|
impl<'a> Device<'a> for VirtualIpDevice {
|
||||||
|
|
37
src/wg.rs
37
src/wg.rs
|
@ -10,6 +10,7 @@ use smoltcp::wire::{
|
||||||
TcpPacket, TcpRepr, TcpSeqNumber,
|
TcpPacket, TcpRepr, TcpSeqNumber,
|
||||||
};
|
};
|
||||||
use tokio::net::UdpSocket;
|
use tokio::net::UdpSocket;
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::MAX_PACKET;
|
use crate::MAX_PACKET;
|
||||||
|
@ -30,6 +31,8 @@ pub struct WireGuardTunnel {
|
||||||
endpoint: SocketAddr,
|
endpoint: SocketAddr,
|
||||||
/// Maps virtual ports to the corresponding IP packet dispatcher.
|
/// Maps virtual ports to the corresponding IP packet dispatcher.
|
||||||
virtual_port_ip_tx: lockfree::map::Map<u16, tokio::sync::mpsc::Sender<Vec<u8>>>,
|
virtual_port_ip_tx: lockfree::map::Map<u16, tokio::sync::mpsc::Sender<Vec<u8>>>,
|
||||||
|
/// IP packet dispatcher for unroutable packets. `None` if not initialized.
|
||||||
|
sink_ip_tx: RwLock<Option<tokio::sync::mpsc::Sender<Vec<u8>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WireGuardTunnel {
|
impl WireGuardTunnel {
|
||||||
|
@ -49,6 +52,7 @@ impl WireGuardTunnel {
|
||||||
udp,
|
udp,
|
||||||
endpoint,
|
endpoint,
|
||||||
virtual_port_ip_tx,
|
virtual_port_ip_tx,
|
||||||
|
sink_ip_tx: RwLock::new(None),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,6 +102,18 @@ impl WireGuardTunnel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register a virtual interface (using its assigned virtual port) with the given IP packet `Sender`.
|
||||||
|
pub async fn register_sink_interface(
|
||||||
|
&self,
|
||||||
|
) -> anyhow::Result<tokio::sync::mpsc::Receiver<Vec<u8>>> {
|
||||||
|
let (sender, receiver) = tokio::sync::mpsc::channel(DISPATCH_CAPACITY);
|
||||||
|
|
||||||
|
let mut sink_ip_tx = self.sink_ip_tx.write().await;
|
||||||
|
*sink_ip_tx = Some(sender);
|
||||||
|
|
||||||
|
Ok(receiver)
|
||||||
|
}
|
||||||
|
|
||||||
/// Releases the virtual interface from IP dispatch.
|
/// Releases the virtual interface from IP dispatch.
|
||||||
pub fn release_virtual_interface(&self, virtual_port: u16) {
|
pub fn release_virtual_interface(&self, virtual_port: u16) {
|
||||||
self.virtual_port_ip_tx.remove(&virtual_port);
|
self.virtual_port_ip_tx.remove(&virtual_port);
|
||||||
|
@ -223,7 +239,7 @@ impl WireGuardTunnel {
|
||||||
}
|
}
|
||||||
RouteResult::TcpReset => {
|
RouteResult::TcpReset => {
|
||||||
trace!("Resetting dead TCP connection after packet from WireGuard endpoint");
|
trace!("Resetting dead TCP connection after packet from WireGuard endpoint");
|
||||||
self.route_tcp_sink(packet).await.unwrap_or_else(|e| {
|
self.route_ip_sink(packet).await.unwrap_or_else(|e| {
|
||||||
error!("Failed to send TCP reset to sink: {:?}", e)
|
error!("Failed to send TCP reset to sink: {:?}", e)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -295,10 +311,21 @@ impl WireGuardTunnel {
|
||||||
.unwrap_or(RouteResult::Drop)
|
.unwrap_or(RouteResult::Drop)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Route a packet to the TCP sink interface.
|
/// Route a packet to the IP sink interface.
|
||||||
async fn route_tcp_sink(&self, _packet: &[u8]) -> anyhow::Result<()> {
|
async fn route_ip_sink(&self, packet: &[u8]) -> anyhow::Result<()> {
|
||||||
// TODO
|
let ip_sink_tx = self.sink_ip_tx.read().await;
|
||||||
Ok(())
|
|
||||||
|
if let Some(ip_sink_tx) = &*ip_sink_tx {
|
||||||
|
ip_sink_tx
|
||||||
|
.send(packet.to_vec())
|
||||||
|
.await
|
||||||
|
.with_context(|| "Failed to dispatch IP packet to sink interface")
|
||||||
|
} else {
|
||||||
|
warn!(
|
||||||
|
"Could not dispatch unroutable IP packet to sink because interface is not active."
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue