start changes
This commit is contained in:
+40
-67
@@ -1,63 +1,41 @@
|
|||||||
use bytes::{Bytes, BytesMut};
|
use std::sync::{Arc, atomic::AtomicBool};
|
||||||
use netrunner_common::proxy::connection::muxer::{MuxMessage, Muxer};
|
|
||||||
use smoltcp::iface::{Config, Interface, SocketHandle, SocketSet, SocketStorage};
|
use smoltcp::{iface::{Config, Interface as InterfaceInstance, SocketSet}, phy::DeviceCapabilities, socket::tcp::{Socket, SocketBuffer}, time::Instant, wire::IpListenEndpoint};
|
||||||
use smoltcp::phy::{DeviceCapabilities, Medium};
|
|
||||||
use smoltcp::socket::tcp::{Socket as SmolTcpSocket, SocketBuffer};
|
|
||||||
use smoltcp::time::Instant;
|
|
||||||
use smoltcp::wire::IpListenEndpoint;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::atomic::AtomicBool;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
|
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
|
||||||
use tracing::{debug, info, trace};
|
|
||||||
|
|
||||||
use crate::tun::virt_device::{TokenBuffer, VirtTunDevice};
|
use crate::tun::virt_device::{TokenBuffer, VirtTunDevice};
|
||||||
|
pub struct Interface {
|
||||||
pub enum BridgeState {
|
instance: InterfaceInstance,
|
||||||
WaitingHandshake,
|
socket_set: SocketSet<'static>,
|
||||||
WaitingConnect,
|
|
||||||
DataTransferring {
|
|
||||||
tx_to_muxer: tokio::sync::mpsc::Sender<MuxMessage>,
|
|
||||||
stream_id: u32,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NetStack {
|
|
||||||
interface: Interface,
|
|
||||||
sockets: SocketSet<'static>,
|
|
||||||
socket_buffers: HashMap<SocketHandle, BytesMut>,
|
|
||||||
bridges: HashMap<SocketHandle, BridgeState>,
|
|
||||||
muxer: Muxer,
|
|
||||||
input: UnboundedSender<TokenBuffer>,
|
input: UnboundedSender<TokenBuffer>,
|
||||||
output: UnboundedReceiver<TokenBuffer>,
|
output: UnboundedReceiver<TokenBuffer>,
|
||||||
tun_available: Arc<AtomicBool>,
|
available: Arc<AtomicBool>
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref START_TIME: std::time::Instant = std::time::Instant::now();
|
static ref START_TIME: std::time::Instant = std::time::Instant::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn current_smoltcp_time() -> Instant {
|
fn current_smoltcp_time() -> Instant {
|
||||||
let nanos = START_TIME.elapsed().as_micros() as i64;
|
let nanos = START_TIME.elapsed().as_micros() as i64;
|
||||||
smoltcp::time::Instant::from_micros(nanos)
|
smoltcp::time::Instant::from_micros(nanos)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetStack {
|
|
||||||
pub fn new(muxer: Muxer) -> Self {
|
|
||||||
let now = current_smoltcp_time();
|
|
||||||
|
|
||||||
let mut caps = DeviceCapabilities::default();
|
impl Interface {
|
||||||
caps.medium = Medium::Ip;
|
pub fn new(caps: DeviceCapabilities, config: Config) -> Self {
|
||||||
caps.max_transmission_unit = 1500;
|
//create virtual tun device (async device)
|
||||||
|
let (virt_device, output, input, available) = VirtTunDevice::new(caps);
|
||||||
let (virt_device, iface_output, iface_input, in_buf_avail) = VirtTunDevice::new(caps);
|
|
||||||
let device = Box::leak(Box::new(virt_device));
|
let device = Box::leak(Box::new(virt_device));
|
||||||
|
|
||||||
let config = Config::new(smoltcp::wire::HardwareAddress::Ip);
|
let now: Instant = current_smoltcp_time();
|
||||||
let mut interface = Interface::new(config, device, now);
|
//smoltcp interface instance create
|
||||||
interface.set_any_ip(true);
|
let mut instance = InterfaceInstance::new(config, device, now);
|
||||||
|
//instance settings
|
||||||
|
instance.set_any_ip(true);
|
||||||
|
|
||||||
interface.update_ip_addrs(|addrs| {
|
instance.update_ip_addrs(|addrs| {
|
||||||
addrs
|
addrs
|
||||||
.push(smoltcp::wire::IpCidr::new(
|
.push(smoltcp::wire::IpCidr::new(
|
||||||
smoltcp::wire::IpAddress::v4(10, 0, 0, 2),
|
smoltcp::wire::IpAddress::v4(10, 0, 0, 2),
|
||||||
@@ -65,46 +43,44 @@ impl NetStack {
|
|||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
});
|
});
|
||||||
|
instance
|
||||||
interface
|
|
||||||
.routes_mut()
|
.routes_mut()
|
||||||
.add_default_ipv4_route(smoltcp::wire::Ipv4Address::new(10, 0, 0, 2))
|
.add_default_ipv4_route(smoltcp::wire::Ipv4Address::new(10, 0, 0, 2))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
||||||
|
let socket_set = SocketSet::new(vec![]);
|
||||||
|
|
||||||
|
let endpoint = IpListenEndpoint {
|
||||||
|
addr: None,
|
||||||
|
port: 443,
|
||||||
|
};
|
||||||
let rx_data = Box::leak(vec![0u8; 4096].into_boxed_slice());
|
let rx_data = Box::leak(vec![0u8; 4096].into_boxed_slice());
|
||||||
let tx_data = Box::leak(vec![0u8; 4096].into_boxed_slice());
|
let tx_data = Box::leak(vec![0u8; 4096].into_boxed_slice());
|
||||||
|
|
||||||
let mut socket = SmolTcpSocket::new(SocketBuffer::new(rx_data), SocketBuffer::new(tx_data));
|
let mut socket = Socket::new(SocketBuffer::new(rx_data), SocketBuffer::new(tx_data));
|
||||||
|
|
||||||
// 4. Теперь listen() сработает, так как у интерфейса есть адрес!
|
|
||||||
let endpoint = IpListenEndpoint {
|
|
||||||
addr: None, // ВАЖНО: Принимаем пакеты для ЛЮБОГО IP назначения
|
|
||||||
port: 443, // Для HTTPS
|
|
||||||
};
|
|
||||||
socket.listen(endpoint).unwrap();
|
socket.listen(endpoint).unwrap();
|
||||||
|
|
||||||
let storage: Vec<SocketStorage> = (0..16).map(|_| SocketStorage::EMPTY).collect();
|
|
||||||
let mut sockets = SocketSet::new(Box::leak(storage.into_boxed_slice()));
|
|
||||||
sockets.add(socket);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
interface,
|
instance,
|
||||||
sockets,
|
socket_set,
|
||||||
socket_buffers: HashMap::new(),
|
input,
|
||||||
bridges: HashMap::new(),
|
output,
|
||||||
muxer,
|
available
|
||||||
input: iface_input,
|
|
||||||
output: iface_output,
|
|
||||||
tun_available: in_buf_avail,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
pub fn process_tun_input(&mut self, data: &[u8]) {
|
pub fn process_tun_input(&mut self, data: &[u8]) {
|
||||||
let mut token = TokenBuffer::with_capacity(data.len());
|
let mut token = TokenBuffer::with_capacity(data.len());
|
||||||
token.extend_from_slice(data);
|
token.extend_from_slice(data);
|
||||||
|
|
||||||
if self.input.send(token).is_ok() {
|
if self.input.send(token).is_ok() {
|
||||||
self.tun_available
|
self.available
|
||||||
.store(true, std::sync::atomic::Ordering::Release);
|
.store(true, std::sync::atomic::Ordering::Release);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,15 +92,12 @@ impl NetStack {
|
|||||||
pub fn poll_delay(&mut self) -> tokio::time::Sleep {
|
pub fn poll_delay(&mut self) -> tokio::time::Sleep {
|
||||||
let timestamp = current_smoltcp_time();
|
let timestamp = current_smoltcp_time();
|
||||||
let ms = self
|
let ms = self
|
||||||
.interface
|
.instance
|
||||||
.poll_delay(timestamp, &self.sockets)
|
.poll_delay(timestamp, &self.socket_set)
|
||||||
.map(|d| d.total_millis())
|
.map(|d| d.total_millis())
|
||||||
.unwrap_or(10); // Порог отзывчивости стека
|
.unwrap_or(10); // Порог отзывчивости стека
|
||||||
|
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(ms))
|
tokio::time::sleep(std::time::Duration::from_millis(ms))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll(&mut self) {
|
|
||||||
let timestamp = current_smoltcp_time();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
pub mod interface;
|
pub mod interface;
|
||||||
pub mod tun;
|
pub mod tun;
|
||||||
|
pub mod stack;
|
||||||
|
|||||||
+7
-12
@@ -1,27 +1,23 @@
|
|||||||
use std::sync::atomic::Ordering;
|
use netrunner_client::{stack::NetStack, tun::tun_builder::TunBuilder};
|
||||||
|
|
||||||
use netrunner_client::{
|
|
||||||
interface::NetStack,
|
|
||||||
tun::{
|
|
||||||
linux_tun_device::create_linux_tun,
|
|
||||||
virt_device::{TokenBuffer, VirtTunDevice},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
use netrunner_common::{
|
use netrunner_common::{
|
||||||
logger_init,
|
logger_init,
|
||||||
proxy::{connection::connection::ConnectionRole, network::Network},
|
proxy::{connection::connection::ConnectionRole, network::Network},
|
||||||
};
|
};
|
||||||
use smoltcp::phy::{DeviceCapabilities, Medium};
|
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let mut tun = create_linux_tun();
|
let mut tun_result = TunBuilder::new().build().await;
|
||||||
logger_init();
|
logger_init();
|
||||||
|
|
||||||
let net = Network::new(8080, ConnectionRole::Client, Some("0.0.0.0:4443".into()));
|
let net = Network::new(8080, ConnectionRole::Client, Some("0.0.0.0:4443".into()));
|
||||||
|
|
||||||
|
let Ok(tun) = tun_result else {
|
||||||
|
error!("Tun creation error");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let muxer = match net.initialize_client_tunnel().await {
|
let muxer = match net.initialize_client_tunnel().await {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -41,7 +37,6 @@ async fn main() {
|
|||||||
let mut net_stack = NetStack::new(muxer);
|
let mut net_stack = NetStack::new(muxer);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// 1. Сначала ВСЕГДА даем стеку поработать (обработать то, что уже пришло)
|
|
||||||
net_stack.poll();
|
net_stack.poll();
|
||||||
|
|
||||||
let mut buf = [0u8; 1600];
|
let mut buf = [0u8; 1600];
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
use bytes::{Bytes, BytesMut};
|
||||||
|
use netrunner_common::proxy::connection::muxer::{MuxMessage, Muxer};
|
||||||
|
use smoltcp::iface::{Config, Interface, SocketHandle, SocketSet, SocketStorage};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use tracing::{debug, info, trace};
|
||||||
|
|
||||||
|
pub enum BridgeState {
|
||||||
|
WaitingHandshake,
|
||||||
|
WaitingConnect,
|
||||||
|
DataTransferring {
|
||||||
|
tx_to_muxer: tokio::sync::mpsc::Sender<MuxMessage>,
|
||||||
|
stream_id: u32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NetStack {
|
||||||
|
socket_buffers: HashMap<SocketHandle, BytesMut>,
|
||||||
|
bridges: HashMap<SocketHandle, BridgeState>,
|
||||||
|
muxer: Muxer,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl NetStack {
|
||||||
|
pub fn new(muxer: Muxer) -> Self {
|
||||||
|
Self {
|
||||||
|
socket_buffers: HashMap::new(),
|
||||||
|
bridges: HashMap::new(),
|
||||||
|
muxer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn poll(&mut self) {}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
use tun::AsyncDevice;
|
|
||||||
|
|
||||||
//tun device
|
|
||||||
pub fn create_linux_tun() -> AsyncDevice {
|
|
||||||
let mut config = tun::Configuration::default();
|
|
||||||
config
|
|
||||||
.tun_name("netr0")
|
|
||||||
.address((10, 0, 0, 1))
|
|
||||||
.netmask((255, 255, 255, 0))
|
|
||||||
.up();
|
|
||||||
|
|
||||||
let dev = tun::create_as_async(&config).expect("Нужны права root или CAP_NET_ADMIN!");
|
|
||||||
dev
|
|
||||||
}
|
|
||||||
+1
-202
@@ -1,204 +1,3 @@
|
|||||||
use std::os::unix::io::RawFd;
|
|
||||||
use std::{io, mem, net::IpAddr, time::Duration};
|
|
||||||
|
|
||||||
use byte_string::ByteStr;
|
|
||||||
use ipnet::IpNet;
|
|
||||||
use log::{error, info, trace, warn};
|
|
||||||
use tokio::io::AsyncReadExt;
|
|
||||||
|
|
||||||
use tun::{
|
|
||||||
create_as_async, AbstractDevice, AsyncDevice, Configuration as TunConfiguration,
|
|
||||||
Error as TunError, Layer,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::tun::ip_packet::IpPacket;
|
|
||||||
use crate::tun::virt_device::TokenBuffer;
|
|
||||||
|
|
||||||
mod ip_packet;
|
mod ip_packet;
|
||||||
pub mod linux_tun_device;
|
pub mod tun_builder;
|
||||||
pub mod virt_device;
|
pub mod virt_device;
|
||||||
|
|
||||||
/// Tun service builder
|
|
||||||
pub struct TunBuilder {
|
|
||||||
tun_config: TunConfiguration,
|
|
||||||
udp_expiry_duration: Option<Duration>,
|
|
||||||
udp_capacity: Option<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// TunConfiguration contains a HANDLE, which is a *mut c_void on Windows.
|
|
||||||
unsafe impl Send for TunBuilder {}
|
|
||||||
|
|
||||||
impl TunBuilder {
|
|
||||||
/// Create a Tun service builder
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
tun_config: TunConfiguration::default(),
|
|
||||||
udp_expiry_duration: None,
|
|
||||||
udp_capacity: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn address(&mut self, addr: IpNet) {
|
|
||||||
self.tun_config.address(addr.addr()).netmask(addr.netmask());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn destination(&mut self, addr: IpNet) {
|
|
||||||
self.tun_config.destination(addr.addr());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&mut self, name: &str) {
|
|
||||||
self.tun_config.tun_name(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
pub fn file_descriptor(&mut self, fd: RawFd) {
|
|
||||||
self.tun_config.raw_fd(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn udp_expiry_duration(&mut self, udp_expiry_duration: Duration) {
|
|
||||||
self.udp_expiry_duration = Some(udp_expiry_duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn udp_capacity(&mut self, udp_capacity: usize) {
|
|
||||||
self.udp_capacity = Some(udp_capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build Tun server
|
|
||||||
pub async fn build(mut self) -> io::Result<Tun> {
|
|
||||||
self.tun_config.layer(Layer::L3).up();
|
|
||||||
|
|
||||||
let device = match create_as_async(&self.tun_config) {
|
|
||||||
Ok(d) => d,
|
|
||||||
Err(TunError::Io(err)) => return Err(err),
|
|
||||||
Err(err) => return Err(io::Error::other(err)),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Tun { device })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tun service
|
|
||||||
pub struct Tun {
|
|
||||||
device: AsyncDevice,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Tun {
|
|
||||||
/// Start serving
|
|
||||||
pub async fn run(mut self) -> io::Result<()> {
|
|
||||||
info!(
|
|
||||||
"tun device {}",
|
|
||||||
self.device
|
|
||||||
.tun_name()
|
|
||||||
.or_else(|r| Ok::<_, ()>(r.to_string()))
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let address = match self.device.address() {
|
|
||||||
Ok(a) => a,
|
|
||||||
Err(err) => {
|
|
||||||
error!("[TUN] failed to get device address, error: {}", err);
|
|
||||||
return Err(io::Error::other(err));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let netmask = match self.device.netmask() {
|
|
||||||
Ok(n) => n,
|
|
||||||
Err(err) => {
|
|
||||||
error!("[TUN] failed to get device netmask, error: {}", err);
|
|
||||||
return Err(io::Error::other(err));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let address_net = match IpNet::with_netmask(address, netmask) {
|
|
||||||
Ok(n) => n,
|
|
||||||
Err(err) => {
|
|
||||||
error!(
|
|
||||||
"[TUN] invalid address {}, netmask {}, error: {}",
|
|
||||||
address, netmask, err
|
|
||||||
);
|
|
||||||
return Err(io::Error::other(err));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
trace!(
|
|
||||||
"[TUN] tun device network: {} (address: {}, netmask: {})",
|
|
||||||
address_net,
|
|
||||||
address,
|
|
||||||
netmask
|
|
||||||
);
|
|
||||||
|
|
||||||
let address_broadcast = address_net.broadcast();
|
|
||||||
|
|
||||||
let create_packet_buffer = || {
|
|
||||||
const PACKET_BUFFER_SIZE: usize = 65536;
|
|
||||||
let mut packet_buffer = TokenBuffer::with_capacity(PACKET_BUFFER_SIZE);
|
|
||||||
unsafe {
|
|
||||||
packet_buffer.set_len(PACKET_BUFFER_SIZE);
|
|
||||||
}
|
|
||||||
packet_buffer
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut packet_buffer = create_packet_buffer();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
tokio::select! {
|
|
||||||
// tun device
|
|
||||||
n = self.device.read(&mut packet_buffer) => {
|
|
||||||
let n = n?;
|
|
||||||
|
|
||||||
let mut packet_buffer = mem::replace(&mut packet_buffer, create_packet_buffer());
|
|
||||||
unsafe {
|
|
||||||
packet_buffer.set_len(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
trace!("[TUN] received IP packet {:?}", ByteStr::new(&packet_buffer));
|
|
||||||
|
|
||||||
if let Err(err) = self.handle_tun_frame(&address_broadcast, packet_buffer).await {
|
|
||||||
error!("[TUN] handle IP frame failed, error: {}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_tun_frame(
|
|
||||||
&mut self,
|
|
||||||
device_broadcast_addr: &IpAddr,
|
|
||||||
frame: TokenBuffer,
|
|
||||||
) -> smoltcp::wire::Result<()> {
|
|
||||||
let packet = match IpPacket::new_checked(frame.as_ref())? {
|
|
||||||
Some(packet) => packet,
|
|
||||||
None => {
|
|
||||||
warn!("unrecognized IP packet {:?}", ByteStr::new(&frame));
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
trace!("[TUN] {:?}", packet);
|
|
||||||
|
|
||||||
let src_ip_addr = packet.src_addr();
|
|
||||||
let dst_ip_addr = packet.dst_addr();
|
|
||||||
let src_non_unicast = src_ip_addr == *device_broadcast_addr
|
|
||||||
|| match src_ip_addr {
|
|
||||||
IpAddr::V4(v4) => v4.is_broadcast() || v4.is_multicast() || v4.is_unspecified(),
|
|
||||||
IpAddr::V6(v6) => v6.is_multicast() || v6.is_unspecified(),
|
|
||||||
};
|
|
||||||
let dst_non_unicast = dst_ip_addr == *device_broadcast_addr
|
|
||||||
|| match dst_ip_addr {
|
|
||||||
IpAddr::V4(v4) => v4.is_broadcast() || v4.is_multicast() || v4.is_unspecified(),
|
|
||||||
IpAddr::V6(v6) => v6.is_multicast() || v6.is_unspecified(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if src_non_unicast || dst_non_unicast {
|
|
||||||
trace!(
|
|
||||||
"[TUN] IP packet {} (unicast? {}) -> {} (unicast? {}) throwing away",
|
|
||||||
src_ip_addr,
|
|
||||||
!src_non_unicast,
|
|
||||||
dst_ip_addr,
|
|
||||||
!dst_non_unicast
|
|
||||||
);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,197 @@
|
|||||||
|
use std::os::unix::io::RawFd;
|
||||||
|
use std::{io, mem, net::IpAddr, time::Duration};
|
||||||
|
|
||||||
|
use byte_string::ByteStr;
|
||||||
|
use ipnet::IpNet;
|
||||||
|
use log::{error, info, trace, warn};
|
||||||
|
use tokio::io::AsyncReadExt;
|
||||||
|
|
||||||
|
use tun::{
|
||||||
|
create_as_async, AbstractDevice, AsyncDevice, Configuration as TunConfiguration,
|
||||||
|
Error as TunError, Layer,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::tun::ip_packet::IpPacket;
|
||||||
|
use crate::tun::virt_device::TokenBuffer;
|
||||||
|
pub struct TunBuilder {
|
||||||
|
tun_config: TunConfiguration,
|
||||||
|
udp_expiry_duration: Option<Duration>,
|
||||||
|
udp_capacity: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TunConfiguration contains a HANDLE, which is a *mut c_void on Windows.
|
||||||
|
unsafe impl Send for TunBuilder {}
|
||||||
|
|
||||||
|
impl TunBuilder {
|
||||||
|
/// Create a Tun service builder
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
tun_config: TunConfiguration::default(),
|
||||||
|
udp_expiry_duration: None,
|
||||||
|
udp_capacity: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn address(&mut self, addr: IpNet) {
|
||||||
|
self.tun_config.address(addr.addr()).netmask(addr.netmask());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destination(&mut self, addr: IpNet) {
|
||||||
|
self.tun_config.destination(addr.addr());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&mut self, name: &str) {
|
||||||
|
self.tun_config.tun_name(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub fn file_descriptor(&mut self, fd: RawFd) {
|
||||||
|
self.tun_config.raw_fd(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn udp_expiry_duration(&mut self, udp_expiry_duration: Duration) {
|
||||||
|
self.udp_expiry_duration = Some(udp_expiry_duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn udp_capacity(&mut self, udp_capacity: usize) {
|
||||||
|
self.udp_capacity = Some(udp_capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build Tun server
|
||||||
|
pub async fn build(mut self) -> io::Result<Tun> {
|
||||||
|
self.tun_config.layer(Layer::L3).up();
|
||||||
|
|
||||||
|
let device = match create_as_async(&self.tun_config) {
|
||||||
|
Ok(d) => d,
|
||||||
|
Err(TunError::Io(err)) => return Err(err),
|
||||||
|
Err(err) => return Err(io::Error::other(err)),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Tun { device })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tun service
|
||||||
|
pub struct Tun {
|
||||||
|
device: AsyncDevice,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tun {
|
||||||
|
/// Start serving
|
||||||
|
pub async fn run(mut self) -> io::Result<()> {
|
||||||
|
info!(
|
||||||
|
"tun device {}",
|
||||||
|
self.device
|
||||||
|
.tun_name()
|
||||||
|
.or_else(|r| Ok::<_, ()>(r.to_string()))
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let address = match self.device.address() {
|
||||||
|
Ok(a) => a,
|
||||||
|
Err(err) => {
|
||||||
|
error!("[TUN] failed to get device address, error: {}", err);
|
||||||
|
return Err(io::Error::other(err));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let netmask = match self.device.netmask() {
|
||||||
|
Ok(n) => n,
|
||||||
|
Err(err) => {
|
||||||
|
error!("[TUN] failed to get device netmask, error: {}", err);
|
||||||
|
return Err(io::Error::other(err));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let address_net = match IpNet::with_netmask(address, netmask) {
|
||||||
|
Ok(n) => n,
|
||||||
|
Err(err) => {
|
||||||
|
error!(
|
||||||
|
"[TUN] invalid address {}, netmask {}, error: {}",
|
||||||
|
address, netmask, err
|
||||||
|
);
|
||||||
|
return Err(io::Error::other(err));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
trace!(
|
||||||
|
"[TUN] tun device network: {} (address: {}, netmask: {})",
|
||||||
|
address_net,
|
||||||
|
address,
|
||||||
|
netmask
|
||||||
|
);
|
||||||
|
|
||||||
|
let address_broadcast = address_net.broadcast();
|
||||||
|
|
||||||
|
let create_packet_buffer = || {
|
||||||
|
const PACKET_BUFFER_SIZE: usize = 65536;
|
||||||
|
let mut packet_buffer = TokenBuffer::with_capacity(PACKET_BUFFER_SIZE);
|
||||||
|
unsafe {
|
||||||
|
packet_buffer.set_len(PACKET_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
packet_buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut packet_buffer = create_packet_buffer();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
tokio::select! {
|
||||||
|
n = self.device.read(&mut packet_buffer) => {
|
||||||
|
let n = n?;
|
||||||
|
|
||||||
|
let mut packet_buffer = mem::replace(&mut packet_buffer, create_packet_buffer());
|
||||||
|
unsafe {
|
||||||
|
packet_buffer.set_len(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
trace!("[TUN] received IP packet {:?}", ByteStr::new(&packet_buffer));
|
||||||
|
|
||||||
|
if let Err(err) = self.handle_tun_frame(&address_broadcast, packet_buffer).await {
|
||||||
|
error!("[TUN] handle IP frame failed, error: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_tun_frame(
|
||||||
|
&mut self,
|
||||||
|
device_broadcast_addr: &IpAddr,
|
||||||
|
frame: TokenBuffer,
|
||||||
|
) -> smoltcp::wire::Result<()> {
|
||||||
|
let packet = match IpPacket::new_checked(frame.as_ref())? {
|
||||||
|
Some(packet) => packet,
|
||||||
|
None => {
|
||||||
|
warn!("unrecognized IP packet {:?}", ByteStr::new(&frame));
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
trace!("[TUN] {:?}", packet);
|
||||||
|
|
||||||
|
let src_ip_addr = packet.src_addr();
|
||||||
|
let dst_ip_addr = packet.dst_addr();
|
||||||
|
let src_non_unicast = src_ip_addr == *device_broadcast_addr
|
||||||
|
|| match src_ip_addr {
|
||||||
|
IpAddr::V4(v4) => v4.is_broadcast() || v4.is_multicast() || v4.is_unspecified(),
|
||||||
|
IpAddr::V6(v6) => v6.is_multicast() || v6.is_unspecified(),
|
||||||
|
};
|
||||||
|
let dst_non_unicast = dst_ip_addr == *device_broadcast_addr
|
||||||
|
|| match dst_ip_addr {
|
||||||
|
IpAddr::V4(v4) => v4.is_broadcast() || v4.is_multicast() || v4.is_unspecified(),
|
||||||
|
IpAddr::V6(v6) => v6.is_multicast() || v6.is_unspecified(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if src_non_unicast || dst_non_unicast {
|
||||||
|
trace!(
|
||||||
|
"[TUN] IP packet {} (unicast? {}) -> {} (unicast? {}) throwing away",
|
||||||
|
src_ip_addr,
|
||||||
|
!src_non_unicast,
|
||||||
|
dst_ip_addr,
|
||||||
|
!dst_non_unicast
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user