use std::io::{Read, Write};
use std::net::{IpAddr, Ipv4Addr};
use std::sync::Arc;
use crate::configuration::Configuration;
use crate::device::AbstractDevice;
use crate::error::{Error, Result};
use crate::run_command::run_command;
use crate::Layer;
use wintun_bindings::{load_from_path, Adapter, Session, MAX_RING_CAPACITY};
pub enum Driver {
Tun(Tun),
#[allow(dead_code)]
Tap(()),
}
pub struct Device {
pub(crate) driver: Driver,
mtu: u16,
}
impl Device {
pub fn new(config: &Configuration) -> Result<Self> {
let layer = config.layer.unwrap_or(Layer::L3);
if layer == Layer::L3 {
let wintun_file = &config.platform_config.wintun_file;
let wintun = unsafe { load_from_path(wintun_file)? };
let tun_name = config.tun_name.as_deref().unwrap_or("wintun");
let guid = config.platform_config.device_guid;
let adapter = match Adapter::open(&wintun, tun_name) {
Ok(a) => a,
Err(_) => Adapter::create(&wintun, tun_name, tun_name, guid)?,
};
if let Some(metric) = config.metric {
let i = adapter.get_adapter_index()?.to_string();
let m = format!("metric={}", metric);
run_command("netsh", &["interface", "ip", "set", "interface", &i, &m])?;
}
let address = config
.address
.unwrap_or(IpAddr::V4(Ipv4Addr::new(10, 1, 0, 2)));
let mask = config
.netmask
.unwrap_or(IpAddr::V4(Ipv4Addr::new(255, 255, 255, 0)));
let gateway = config.destination.map(IpAddr::from);
adapter.set_network_addresses_tuple(address, mask, gateway)?;
if let Some(dns_servers) = &config.platform_config.dns_servers {
adapter.set_dns_servers(dns_servers)?;
}
let mtu = config.mtu.unwrap_or(crate::DEFAULT_MTU);
let capacity = config.ring_capacity.unwrap_or(MAX_RING_CAPACITY);
let session = adapter.start_session(capacity)?;
adapter.set_mtu(mtu as _)?;
let mut device = Device {
driver: Driver::Tun(Tun { session }),
mtu,
};
device.configure(config)?;
Ok(device)
} else if layer == Layer::L2 {
todo!()
} else {
panic!("unknow layer {:?}", layer);
}
}
pub fn split(self) -> (Reader, Writer) {
match self.driver {
Driver::Tun(tun) => {
let tun = Arc::new(tun);
(Reader(tun.clone()), Writer(tun))
}
Driver::Tap(_) => unimplemented!(),
}
}
pub fn recv(&self, buf: &mut [u8]) -> std::io::Result<usize> {
match &self.driver {
Driver::Tun(tun) => tun.recv(buf),
Driver::Tap(_tap) => unimplemented!(),
}
}
pub fn send(&self, buf: &[u8]) -> std::io::Result<usize> {
match &self.driver {
Driver::Tun(tun) => tun.send(buf),
Driver::Tap(_tap) => unimplemented!(),
}
}
}
impl Read for Device {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match &mut self.driver {
Driver::Tun(tun) => tun.read(buf),
Driver::Tap(_tap) => unimplemented!(),
}
}
}
impl Write for Device {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
match &mut self.driver {
Driver::Tun(tun) => tun.write(buf),
Driver::Tap(_tap) => unimplemented!(),
}
}
fn flush(&mut self) -> std::io::Result<()> {
match &mut self.driver {
Driver::Tun(tun) => tun.flush(),
Driver::Tap(_tap) => unimplemented!(),
}
}
}
impl AbstractDevice for Device {
fn tun_index(&self) -> Result<i32> {
match &self.driver {
Driver::Tun(tun) => Ok(tun.session.get_adapter().get_adapter_index()? as i32),
Driver::Tap(_tap) => Err(Error::NotImplemented),
}
}
fn tun_name(&self) -> Result<String> {
match &self.driver {
Driver::Tun(tun) => Ok(tun.session.get_adapter().get_name()?),
Driver::Tap(_tap) => unimplemented!(),
}
}
fn set_tun_name(&mut self, value: &str) -> Result<()> {
match &self.driver {
Driver::Tun(tun) => {
tun.session.get_adapter().set_name(value)?;
Ok(())
}
Driver::Tap(_tap) => unimplemented!(),
}
}
fn enabled(&mut self, _value: bool) -> Result<()> {
Ok(())
}
fn address(&self) -> Result<IpAddr> {
match &self.driver {
Driver::Tun(tun) => {
let addresses = tun.session.get_adapter().get_addresses()?;
addresses
.iter()
.find_map(|a| match a {
std::net::IpAddr::V4(a) => Some(std::net::IpAddr::V4(*a)),
_ => None,
})
.ok_or(Error::InvalidConfig)
}
Driver::Tap(_tap) => unimplemented!(),
}
}
fn set_address(&mut self, value: IpAddr) -> Result<()> {
let IpAddr::V4(value) = value else {
unimplemented!("do not support IPv6 yet")
};
match &self.driver {
Driver::Tun(tun) => {
tun.session.get_adapter().set_address(value)?;
Ok(())
}
Driver::Tap(_tap) => unimplemented!(),
}
}
fn destination(&self) -> Result<IpAddr> {
match &self.driver {
Driver::Tun(tun) => tun
.session
.get_adapter()
.get_gateways()?
.iter()
.find_map(|a| match a {
std::net::IpAddr::V4(a) => Some(std::net::IpAddr::V4(*a)),
_ => None,
})
.ok_or(Error::InvalidConfig),
Driver::Tap(_tap) => unimplemented!(),
}
}
fn set_destination(&mut self, value: IpAddr) -> Result<()> {
let IpAddr::V4(value) = value else {
unimplemented!("do not support IPv6 yet")
};
match &self.driver {
Driver::Tun(tun) => {
tun.session.get_adapter().set_gateway(Some(value))?;
Ok(())
}
Driver::Tap(_tap) => unimplemented!(),
}
}
fn broadcast(&self) -> Result<IpAddr> {
Err(Error::NotImplemented)
}
fn set_broadcast(&mut self, value: IpAddr) -> Result<()> {
log::debug!("set_broadcast {} is not need", value);
Ok(())
}
fn netmask(&self) -> Result<IpAddr> {
let current_addr = self.address()?;
match &self.driver {
Driver::Tun(tun) => tun
.session
.get_adapter()
.get_netmask_of_address(¤t_addr)
.map_err(Error::WintunError),
Driver::Tap(_tap) => unimplemented!(),
}
}
fn set_netmask(&mut self, value: IpAddr) -> Result<()> {
let IpAddr::V4(value) = value else {
unimplemented!("do not support IPv6 yet")
};
match &self.driver {
Driver::Tun(tun) => {
tun.session.get_adapter().set_netmask(value)?;
Ok(())
}
Driver::Tap(_tap) => unimplemented!(),
}
}
fn mtu(&self) -> Result<u16> {
Ok(self.mtu)
}
fn set_mtu(&mut self, mtu: u16) -> Result<()> {
match &self.driver {
Driver::Tun(tun) => {
tun.session.get_adapter().set_mtu(mtu as _)?;
self.mtu = mtu;
Ok(())
}
Driver::Tap(_tap) => unimplemented!(),
}
}
fn packet_information(&self) -> bool {
false
}
}
pub struct Tun {
session: Arc<Session>,
}
impl Tun {
pub fn get_session(&self) -> Arc<Session> {
self.session.clone()
}
fn read_by_ref(&self, mut buf: &mut [u8]) -> std::io::Result<usize> {
use std::io::{Error, ErrorKind::ConnectionAborted};
match self.session.receive_blocking() {
Ok(pkt) => match std::io::copy(&mut pkt.bytes(), &mut buf) {
Ok(n) => Ok(n as usize),
Err(e) => Err(e),
},
Err(e) => Err(Error::new(ConnectionAborted, e)),
}
}
fn write_by_ref(&self, mut buf: &[u8]) -> std::io::Result<usize> {
use std::io::{Error, ErrorKind::OutOfMemory};
let size = buf.len();
match self.session.allocate_send_packet(size as u16) {
Err(e) => Err(Error::new(OutOfMemory, e)),
Ok(mut packet) => match std::io::copy(&mut buf, &mut packet.bytes_mut()) {
Ok(s) => {
self.session.send_packet(packet);
Ok(s as usize)
}
Err(e) => Err(e),
},
}
}
pub fn recv(&self, buf: &mut [u8]) -> std::io::Result<usize> {
self.read_by_ref(buf)
}
pub fn send(&self, buf: &[u8]) -> std::io::Result<usize> {
self.write_by_ref(buf)
}
}
impl Read for Tun {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.read_by_ref(buf)
}
}
impl Write for Tun {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.write_by_ref(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
#[repr(transparent)]
pub struct Reader(Arc<Tun>);
impl Read for Reader {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.0.read_by_ref(buf)
}
}
#[repr(transparent)]
pub struct Writer(Arc<Tun>);
impl Write for Writer {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.0.write_by_ref(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}