Skip to content

Commit

Permalink
Merge pull request #70 from blocklessnetwork/feature/net-windows
Browse files Browse the repository at this point in the history
Feature/net windows
  • Loading branch information
Joinhack authored Jun 2, 2024
2 parents 5064878 + 6d2a096 commit 26ccb4c
Show file tree
Hide file tree
Showing 14 changed files with 1,266 additions and 11 deletions.
16 changes: 16 additions & 0 deletions crates/tuntap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,19 @@ futures = { workspace = true, features= ["thread-pool"]}

[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
ioctl = { version = "0.6", package = "ioctl-sys" }

[target.'cfg(any(target_os = "windows"))'.dependencies]
scopeguard = "1.2.0"
winreg = "0.7"
[dependencies.winapi]
version = "0.3"
features = [
"errhandlingapi",
"combaseapi",
"ioapiset",
"winioctl",
"setupapi",
"synchapi",
"netioapi",
"fileapi"
]
8 changes: 8 additions & 0 deletions crates/tuntap/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ pub enum Error {
#[error("invalid queues number")]
InvalidQueuesNumber,

#[cfg(windows)]
#[error("windows")]
FakeRegister,

#[cfg(windows)]
#[error("netsh execute error")]
NetshExecError,

#[error(transparent)]
Io(#[from] io::Error),

Expand Down
7 changes: 3 additions & 4 deletions crates/tuntap/src/platform/macos/dev.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::io::{Read, Write};
use std::io::{self, Read, Write};
use std::ptr;

use libc::{
AF_INET, SOCK_DGRAM
};
use std::io;

use crate::address::EtherAddr;
use crate::platform::macos::sys::*;
Expand All @@ -15,7 +15,7 @@ use crate::{
};
use crate::{Error, Result, Token};
use crate::platform::posix::IntoSockAddr;
use std::ptr;

#[allow(unused)]
use super::sys::*;

Expand All @@ -27,7 +27,6 @@ pub struct Tap {
}

impl Tap {


fn ifmtu(&self) -> ifmtu {
unsafe {
Expand Down
30 changes: 29 additions & 1 deletion crates/tuntap/src/platform/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ macro_rules! get_ifname {
}

/// syscall macro wrapper.
#[cfg(any(target_os="linux", target_os="macos"))]
macro_rules! syscall {
($call: expr) => {
unsafe {
Expand All @@ -33,4 +34,31 @@ macro_rules! syscall {
n
}
};
}
}

/// syscall macro wrapper for windows.
#[cfg(target_os="windows")]
macro_rules! syscall_handle {
($call: expr) => {
unsafe {
match $call {
INVALID_HANDLE_VALUE => Err(Error::Io(io::Error::last_os_error())),
d => Ok(d)
}
}
};
}

/// syscall macro wrapper for windows.
#[cfg(target_os="windows")]
macro_rules! syscall {
($call: expr) => {
unsafe {
let n = $call;
if n == 0 {
return Err(Error::Io(io::Error::last_os_error()));
}
n
}
};
}
6 changes: 6 additions & 0 deletions crates/tuntap/src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ mod posix;
#[cfg(target_os="linux")]
mod linux;

#[cfg(target_os="windows")]
mod windows;

#[cfg(target_os="macos")]
pub use macos::*;

Expand All @@ -17,3 +20,6 @@ pub use linux::*;

#[cfg(any(target_os="linux", target_os="macos"))]
pub use posix::*;

#[cfg(target_os="windows")]
pub use windows::*;
1 change: 1 addition & 0 deletions crates/tuntap/src/platform/posix/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod fd;
mod address;

pub use fd::*;
pub use address::*;
230 changes: 230 additions & 0 deletions crates/tuntap/src/platform/windows/dev.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
use std::io::{Read, Write};
use std::{io, ptr, time};

use winapi::shared::ifdef::NET_LUID;
use winapi::um::minwinbase::OVERLAPPED;
use winapi::um::winioctl::{
CTL_CODE, FILE_ANY_ACCESS, FILE_DEVICE_UNKNOWN, METHOD_BUFFERED
};

use crate::{Configuration, Device};
use crate::{Result, Error};
use super::fd::Fd;
use super::{encode_utf16, netsh};
use super::{decode_utf16, ffi};


winapi::DEFINE_GUID! {
GUID_NETWORK_ADAPTER,
0x4d36e972, 0xe325, 0x11ce,
0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18
}

pub struct Tap {
fd: Fd,
dev_index: u32,
is_open: bool,
read_overlapped: Option<OVERLAPPED>,
write_overlapped: Option<OVERLAPPED>,
name: String,
luid: NET_LUID,
}

impl Tap {

pub fn open(name: &str) -> Result<Self> {
let name_string = name.to_string();
let name = encode_utf16(name);

let luid = ffi::alias_to_luid(&name)?;
ffi::check_interface(&luid)?;

let handle = ffi::open_interface(&luid)?;
let dev_index = ffi::luid_to_index(&luid).unwrap() as _;
Ok(Self {
luid,
dev_index,
is_open: true,
fd: Fd::new(handle),
name: name_string,
read_overlapped: None,
write_overlapped: None,
})
}

pub fn new(_config: Configuration) -> Result<Self> {
let luid = ffi::create_interface()?;

// Even after retrieving the luid, we might need to wait
let start = time::Instant::now();
let handle = loop {
// If we surpassed 2 seconds just return
let now = time::Instant::now();
if now - start > time::Duration::from_secs(2) {
return Err(Error::Io(io::Error::new(
io::ErrorKind::TimedOut,
"Interface timed out",
)));
}

match ffi::open_interface(&luid) {
Err(_) => {
std::thread::yield_now();
continue;
}
Ok(handle) => break handle,
};
};

let name = ffi::luid_to_alias(&luid)
.map(|name| decode_utf16(&name))?;
let dev_index = ffi::luid_to_index(&luid).unwrap() as _;

Ok(Self {
luid,
name,
dev_index,
is_open: false,
read_overlapped: None,
write_overlapped: None,
fd: Fd::new(handle),
})
}
}

impl Device for Tap {
fn token(&self) -> crate::Token {
todo!()
}
fn set_nonblock(&mut self) -> Result<()> {
Ok(())
}

fn name(&self) -> &str {
&self.name
}

fn set_name(&mut self, name: &str) -> Result<()> {
let ret = netsh::set_interface_name(&self.name, name);
if ret.is_ok() {
self.name = name.to_string();
}
ret
}

fn enabled(&mut self, value: bool) -> Result<()> {
let status: u32 = if value { 1 } else { 0 };

ffi::device_io_control(
*self.fd,
CTL_CODE(FILE_DEVICE_UNKNOWN, 6, METHOD_BUFFERED, FILE_ANY_ACCESS),
&status,
&mut (),
)
}

fn address(&self) -> Result<std::net::Ipv4Addr> {
let dev_index = self.dev_index;
let mut ip = Vec::new();
ffi::visit_adapters_info(|dev_info| {
if dev_index == dev_info.Index {
ip = dev_info
.IpAddressList
.IpAddress
.String
.iter()
.filter_map(|i| if *i == 0 {None} else {Some(*i as _)})
.collect::<Vec<u8>>();

}
}).unwrap();
let ip: String = String::from_utf8(ip).unwrap();
ip.parse().map_err(|_| Error::InvalidAddress)
}

fn set_address(&mut self, value: std::net::Ipv4Addr) -> Result<()> {
netsh::set_ip(&self.name, &value.to_string())
}

fn broadcast(&self) -> Result<std::net::Ipv4Addr> {
todo!()
}

fn set_broadcast(&mut self, value: std::net::Ipv4Addr) -> Result<()> {
todo!()
}

fn netmask(&self) -> Result<std::net::Ipv4Addr> {
todo!()
}

fn set_netmask(&mut self, value: std::net::Ipv4Addr) -> Result<()> {
netsh::set_mask(&self.name, &value.to_string())
}

fn mtu(&self) -> Result<i32> {
let mut mtu = 0;
ffi::device_io_control(
*self.fd,
CTL_CODE(FILE_DEVICE_UNKNOWN, 3, METHOD_BUFFERED, FILE_ANY_ACCESS),
&(),
&mut mtu,
)
.map(|_| mtu)
}

fn set_mtu(&mut self, value: i32) -> Result<()> {
Ok(())
}

fn set_ether_address(&mut self, eth: crate::EtherAddr) -> Result<()> {
Ok(())
}

fn fd(&self) -> &Fd {
&self.fd
}
}

impl Read for Tap {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.fd.read(buf)
}
}

impl Write for Tap {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.fd.write(buf)
}

fn flush(&mut self) -> io::Result<()> {
self.fd.flush()
}
}

impl Drop for Tap {
fn drop(&mut self) {
if !self.is_open {
ffi::delete_interface(&self.luid).unwrap();
}
}
}

#[cfg(test)]
mod test {
use std::time::Duration;

use crate::{platform::windows::netsh, Configuration, Device};

use super::Tap;

fn test_create() {
let mut config = Configuration::new();
let ip = "192.168.0.1";
config.address(ip);
let tap = Tap::new(config).unwrap();
println!("{}", tap.name());
netsh::set_ip(tap.name(), ip).unwrap();
assert_eq!(tap.address().unwrap().to_string(), ip);
}
}
25 changes: 25 additions & 0 deletions crates/tuntap/src/platform/windows/event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use crate::{interest::Interest, token::Token};

pub struct Event {
pub(crate) token: Token,
pub(crate) interest: Interest,
}

impl Event {
#[inline]
pub fn token(&self) -> Token {
self.token
}

#[inline]
pub fn is_readable(&self) -> bool {
self.interest.is_readable()
}

#[inline]
pub fn is_writable(&self) -> bool {
self.interest.is_writable()
}
}

pub type Events = Vec<Event>;
Loading

0 comments on commit 26ccb4c

Please sign in to comment.