replace tun

This commit is contained in:
lbl
2024-12-31 11:26:59 +08:00
parent 8aa4736b01
commit c0d8645833
42 changed files with 317 additions and 3781 deletions

231
Cargo.lock generated
View File

@@ -139,7 +139,7 @@ version = "0.69.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
"cexpr",
"clang-sys",
"itertools",
@@ -152,7 +152,7 @@ dependencies = [
"regex",
"rustc-hash",
"shlex",
"syn 2.0.60",
"syn 2.0.93",
"which",
]
@@ -164,9 +164,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.5.0"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "block-buffer"
@@ -204,6 +204,26 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
[[package]]
name = "c2rust-bitfields"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "367e5d1b30f28be590b6b3868da1578361d29d9bfac516d22f497d28ed7c9055"
dependencies = [
"c2rust-bitfields-derive",
]
[[package]]
name = "c2rust-bitfields-derive"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a279db9c50c4024eeca1a763b6e0f033848ce74e83e47454bcf8a8a98f7b0b56"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "cbc"
version = "0.1.2"
@@ -239,6 +259,12 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cfg_aliases"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "cfg_aliases"
version = "0.2.1"
@@ -520,6 +546,15 @@ version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "encoding_rs"
version = "0.8.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
dependencies = [
"cfg-if",
]
[[package]]
name = "equivalent"
version = "1.0.1"
@@ -571,7 +606,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.60",
"syn 2.0.93",
]
[[package]]
@@ -621,6 +656,17 @@ dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "getifaddrs"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ba121d81ab5ea05b0cd5858516266800bf965531a794f7ac58e3eeb804f364f"
dependencies = [
"bitflags 2.6.0",
"libc",
"windows-sys 0.59.0",
]
[[package]]
name = "getopts"
version = "0.2.21"
@@ -803,10 +849,10 @@ dependencies = [
]
[[package]]
name = "ioctl-sys"
version = "0.8.0"
name = "ipnet"
version = "2.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bd11f3a29434026f5ff98c730b668ba74b1033637b8817940b54d040696133c"
checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
[[package]]
name = "itertools"
@@ -858,9 +904,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.155"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "libloading"
@@ -946,7 +992,7 @@ dependencies = [
"serde-value",
"serde_json",
"serde_yaml",
"thiserror",
"thiserror 1.0.58",
"thread-id",
"typemap-ors",
"winapi",
@@ -972,12 +1018,31 @@ version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5"
[[package]]
name = "mac_address"
version = "1.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8836fae9d0d4be2c8b4efcdd79e828a2faa058a90d005abf42f91cac5493a08e"
dependencies = [
"nix 0.28.0",
"winapi",
]
[[package]]
name = "memchr"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[package]]
name = "memoffset"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
dependencies = [
"autocfg",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
@@ -1013,10 +1078,35 @@ checksum = "433419f898328beca4f2c6c73a1b52540658d92b0a99f0269330457e0fd998d5"
dependencies = [
"cc",
"libc",
"thiserror",
"thiserror 1.0.58",
"winapi",
]
[[package]]
name = "nix"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
dependencies = [
"bitflags 2.6.0",
"cfg-if",
"cfg_aliases 0.1.1",
"libc",
"memoffset",
]
[[package]]
name = "nix"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags 2.6.0",
"cfg-if",
"cfg_aliases 0.2.1",
"libc",
]
[[package]]
name = "nom"
version = "7.1.3"
@@ -1271,14 +1361,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e"
dependencies = [
"proc-macro2",
"syn 2.0.60",
"syn 2.0.93",
]
[[package]]
name = "proc-macro2"
version = "1.0.81"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
@@ -1291,7 +1381,7 @@ checksum = "b55bad9126f378a853655831eb7363b7b01b81d19f8cb1218861086ca4a1a61e"
dependencies = [
"once_cell",
"protobuf-support",
"thiserror",
"thiserror 1.0.58",
]
[[package]]
@@ -1306,7 +1396,7 @@ dependencies = [
"protobuf-parse",
"regex",
"tempfile",
"thiserror",
"thiserror 1.0.58",
]
[[package]]
@@ -1321,7 +1411,7 @@ dependencies = [
"protobuf",
"protobuf-support",
"tempfile",
"thiserror",
"thiserror 1.0.58",
"which",
]
@@ -1331,7 +1421,7 @@ version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5d4d7b8601c814cfb36bcebb79f0e61e45e1e93640cf778837833bbed05c372"
dependencies = [
"thiserror",
"thiserror 1.0.58",
]
[[package]]
@@ -1526,7 +1616,7 @@ version = "0.38.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
"errno",
"libc",
"linux-raw-sys",
@@ -1614,7 +1704,7 @@ version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
"core-foundation",
"core-foundation-sys",
"libc",
@@ -1658,7 +1748,7 @@ checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.60",
"syn 2.0.93",
]
[[package]]
@@ -1838,9 +1928,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.60"
version = "2.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058"
dependencies = [
"proc-macro2",
"quote",
@@ -1874,7 +1964,16 @@ version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
dependencies = [
"thiserror-impl",
"thiserror-impl 1.0.58",
]
[[package]]
name = "thiserror"
version = "2.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc"
dependencies = [
"thiserror-impl 2.0.9",
]
[[package]]
@@ -1885,7 +1984,18 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.60",
"syn 2.0.93",
]
[[package]]
name = "thiserror-impl"
version = "2.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.93",
]
[[package]]
@@ -1940,7 +2050,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.60",
"syn 2.0.93",
]
[[package]]
@@ -1972,17 +2082,29 @@ dependencies = [
]
[[package]]
name = "tun"
version = "0.1.0"
name = "tun-rs"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53141e64197ff7e758b8152615e50bb4a3b18c970738876e7906d31f242c7d6e"
dependencies = [
"ioctl-sys",
"bitflags 2.6.0",
"byteorder",
"bytes",
"c2rust-bitfields",
"cfg-if",
"encoding_rs",
"getifaddrs",
"ipnet",
"libc",
"libloading",
"log",
"rand",
"sha2",
"widestring",
"winapi",
"mac_address",
"nix 0.29.0",
"scopeguard",
"thiserror 2.0.9",
"windows-sys 0.59.0",
"winreg",
"wintun-bindings",
]
[[package]]
@@ -2001,7 +2123,7 @@ dependencies = [
"rustls",
"rustls-pki-types",
"sha1",
"thiserror",
"thiserror 1.0.58",
"utf-8",
]
@@ -2148,7 +2270,7 @@ dependencies = [
"anyhow",
"bytes",
"cbc",
"cfg_aliases",
"cfg_aliases 0.2.1",
"chacha20",
"chacha20poly1305",
"crossbeam-epoch",
@@ -2180,10 +2302,10 @@ dependencies = [
"socket2",
"spki",
"stun-format",
"thiserror",
"thiserror 1.0.58",
"tokio",
"tokio-tungstenite",
"tun",
"tun-rs",
"windows-sys 0.59.0",
"zstd",
]
@@ -2231,7 +2353,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.60",
"syn 2.0.93",
"wasm-bindgen-shared",
]
@@ -2253,7 +2375,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.60",
"syn 2.0.93",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -2285,12 +2407,6 @@ dependencies = [
"rustix",
]
[[package]]
name = "widestring"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
[[package]]
name = "wildmatch"
version = "1.1.0"
@@ -2476,6 +2592,29 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winreg"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]]
name = "wintun-bindings"
version = "0.7.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e35d3911efde5ee25586385204127ff6a3f251477dcdd3b222775aaa4d95977"
dependencies = [
"c2rust-bitfields",
"libloading",
"log",
"thiserror 2.0.9",
"windows-sys 0.59.0",
]
[[package]]
name = "xml-rs"
version = "0.8.20"

View File

@@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tun = { path = "tun", optional = true }
tun-rs = { version = "1.5.0", optional = true,features = ["experimental"] }
packet = { path = "./packet" }
bytes = "1.5.0"
log = "0.4.17"
@@ -81,7 +81,7 @@ ip_proxy = []
port_mapping = []
lz4_compress = ["lz4_flex"]
zstd_compress = ["zstd"]
integrated_tun = ["tun"]
integrated_tun = ["tun-rs"]
upnp = ["igd"]
ws = ["tokio-tungstenite"]
wss = ["ws", "tokio-tungstenite/rustls-tls-native-roots", "tokio-tungstenite/rustls-tls-webpki-roots", "rustls"]

View File

@@ -96,15 +96,6 @@ impl Config {
allow_wire_guard: bool,
local_dev: Option<String>,
) -> anyhow::Result<Self> {
#[cfg(windows)]
#[cfg(feature = "integrated_tun")]
if !tap {
if let Err(e) = tun::Device::check_tun_dll() {
log::warn!("校验平台dll {:?}", e);
Err(e)?;
}
}
for x in stun_server.iter_mut() {
if !x.contains(":") {
x.push_str(":3478");

View File

@@ -7,12 +7,12 @@ use std::sync::Arc;
use std::time::{Duration, Instant};
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use protobuf::Message;
use packet::icmp::{icmp, Kind};
use packet::ip::ipv4;
use packet::ip::ipv4::packet::IpV4Packet;
use parking_lot::Mutex;
use protobuf::Message;
use tun_rs::AbstractDevice;
use crate::channel::context::ChannelContext;
use crate::channel::{Route, RouteKey};
@@ -360,10 +360,9 @@ impl<Call: VntCallback, Device: DeviceWrite> ServerPacketHandler<Call, Device> {
&self.callback,
) {
Ok(device) => {
use tun::device::IFace;
let tun_info = crate::handle::callback::DeviceInfo::new(
device.name().unwrap_or("unknown".into()),
device.version().unwrap_or("unknown".into()),
"".into(),
);
log::info!("tun信息{:?}", tun_info);
self.callback.create_tun(tun_info);
@@ -392,7 +391,7 @@ impl<Call: VntCallback, Device: DeviceWrite> ServerPacketHandler<Call, Device> {
"device_fd == 0".into(),
));
} else {
match tun::Device::new(device_fd as _) {
match tun_rs::platform::Device::from_fd(device_fd as _) {
Ok(device) => {
if let Err(e) = self.tun_device_helper.start(
Arc::new(device),

View File

@@ -1,19 +1,11 @@
pub mod tun_handler;
#[cfg(unix)]
mod unix;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use std::sync::Arc;
#[cfg(unix)]
pub(crate) use unix::*;
mod platform;
#[cfg(target_os = "windows")]
mod windows;
#[cfg(target_os = "windows")]
pub(crate) use windows::*;
pub(crate) use platform::*;
/// 仅仅是停止tun不停止vnt
#[derive(Clone, Default)]

View File

@@ -13,8 +13,7 @@ use parking_lot::Mutex;
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::sync::Arc;
use tun::device::IFace;
use tun::Device;
use tun_rs::platform::Device;
pub(crate) fn start_simple(
stop_manager: StopManager,
@@ -85,8 +84,7 @@ fn start_simple0(
let mut buf = [0; BUFFER_SIZE];
let mut extend = [0; BUFFER_SIZE];
loop {
let len = device.read(&mut buf[12..])? + 12;
//单线程的
let len = device.recv(&mut buf[12..])? + 12;
// buf是重复利用的需要重置头部
buf[..12].fill(0);
match crate::handle::tun_tap::tun_handler::handle(

View File

@@ -1,16 +1,14 @@
use crossbeam_utils::atomic::AtomicCell;
use packet::icmp::icmp::IcmpPacket;
use packet::icmp::Kind;
use packet::ip::ipv4::packet::IpV4Packet;
use packet::ip::ipv4::protocol::Protocol;
use parking_lot::Mutex;
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::{io, thread};
use packet::icmp::icmp::IcmpPacket;
use packet::icmp::Kind;
use packet::ip::ipv4::packet::IpV4Packet;
use packet::ip::ipv4::protocol::Protocol;
use tun::device::IFace;
use tun::Device;
use tun_rs::platform::Device;
use crate::channel::context::ChannelContext;
use crate::channel::sender::{send_to_wg, send_to_wg_broadcast};
@@ -38,7 +36,7 @@ fn icmp(device_writer: &Device, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> anyho
ipv4_packet.set_source_ip(ipv4_packet.destination_ip());
ipv4_packet.set_destination_ip(src);
ipv4_packet.update_checksum();
device_writer.write(ipv4_packet.buffer)?;
device_writer.send(ipv4_packet.buffer)?;
}
}
Ok(())

View File

@@ -1,154 +0,0 @@
use crate::channel::context::ChannelContext;
use crate::channel::BUFFER_SIZE;
use crate::cipher::Cipher;
use crate::compression::Compressor;
use crate::external_route::ExternalRoute;
use crate::handle::tun_tap::DeviceStop;
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
#[cfg(feature = "ip_proxy")]
use crate::ip_proxy::IpProxyMap;
use crate::util::StopManager;
use crossbeam_utils::atomic::AtomicCell;
use mio::event::Source;
use mio::unix::SourceFd;
use mio::{Events, Interest, Poll, Token, Waker};
use parking_lot::Mutex;
use std::collections::HashMap;
use std::io;
use std::net::Ipv4Addr;
use std::os::fd::AsRawFd;
use std::sync::Arc;
use tun::Device;
const STOP: Token = Token(0);
const FD: Token = Token(1);
pub(crate) fn start_simple(
stop_manager: StopManager,
context: &ChannelContext,
device: Arc<Device>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
ip_route: ExternalRoute,
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
compressor: Compressor,
device_stop: DeviceStop,
allow_wire_guard: bool,
) -> anyhow::Result<()> {
let poll = Poll::new()?;
let waker = Arc::new(Waker::new(poll.registry(), STOP)?);
let _waker = waker.clone();
let worker = {
stop_manager.add_listener("tun_device".into(), move || {
if let Err(e) = waker.wake() {
log::warn!("{:?}", e);
}
})?
};
let worker_cell = Arc::new(AtomicCell::new(Some(worker)));
let _worker_cell = worker_cell.clone();
device_stop.set_stop_fn(move || {
if let Some(worker) = _worker_cell.take() {
worker.stop_self()
}
});
if let Err(e) = start_simple0(
poll,
context,
device,
current_device,
ip_route,
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
client_cipher,
server_cipher,
device_map,
compressor,
allow_wire_guard,
) {
log::error!("{:?}", e);
};
device_stop.stopped();
if let Some(worker) = worker_cell.take() {
worker.stop_all();
}
drop(_waker);
Ok(())
}
fn start_simple0(
mut poll: Poll,
context: &ChannelContext,
device: Arc<Device>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
ip_route: ExternalRoute,
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
compressor: Compressor,
allow_wire_guard: bool,
) -> anyhow::Result<()> {
let mut buf = [0; BUFFER_SIZE];
let mut extend = [0; BUFFER_SIZE];
let fd = device.as_tun_fd();
fd.set_nonblock()?;
SourceFd(&fd.as_raw_fd()).register(poll.registry(), FD, Interest::READABLE)?;
let mut events = Events::with_capacity(4);
#[cfg(not(target_os = "macos"))]
let start = 12;
#[cfg(target_os = "macos")]
let start = 12 - 4;
loop {
if let Err(e) = poll.poll(&mut events, None) {
crate::ignore_io_interrupted(e)?;
continue;
}
for event in events.iter() {
if event.token() == STOP {
return Ok(());
}
let mut retries = 0;
loop {
let len = match fd.read(&mut buf[start..]) {
Ok(len) => len + start,
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
retries += 1;
if retries < 8 {
continue;
}
break;
}
Err(e)?
}
};
// buf是重复利用的需要重置头部
buf[..12].fill(0);
match crate::handle::tun_tap::tun_handler::handle(
context,
&mut buf,
len,
&mut extend,
&device,
current_device.load(),
&ip_route,
#[cfg(feature = "ip_proxy")]
&ip_proxy_map,
&client_cipher,
&server_cipher,
&device_map,
&compressor,
allow_wire_guard,
) {
Ok(_) => {}
Err(e) => {
log::warn!("{:?}", e)
}
}
}
}
}
}

View File

@@ -1,9 +1,10 @@
use crate::{DeviceConfig, ErrorInfo, ErrorType, VntCallback};
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
use tun::device::IFace;
use tun::Device;
use tun_rs::platform::Device;
use tun_rs::AbstractDevice;
use crate::{DeviceConfig, ErrorInfo, ErrorType, VntCallback};
#[cfg(any(target_os = "windows", target_os = "linux"))]
const DEFAULT_TUN_NAME: &str = "vnt-tun";
@@ -23,30 +24,24 @@ pub fn create_device<Call: VntCallback>(
));
}
};
if let Err(e) = device.set_ip(config.virtual_ip, config.virtual_netmask) {
log::error!("LocalIpExists {:?}", e);
return Err(ErrorInfo::new_msg(
ErrorType::LocalIpExists,
format!("set_ip {:?}", e),
));
}
if let Err(e) = device.add_route(config.virtual_network, config.virtual_netmask, 1) {
log::warn!("添加默认路由失败 ={:?}", e);
}
if let Err(e) = device.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, 1) {
#[cfg(windows)]
let index = device.if_index().unwrap();
#[cfg(unix)]
let index = &device.name().unwrap();
if let Err(e) = add_route(index, Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST) {
log::warn!("添加广播路由失败 ={:?}", e);
}
if let Err(e) = device.add_route(
if let Err(e) = add_route(
index,
Ipv4Addr::from([224, 0, 0, 0]),
Ipv4Addr::from([240, 0, 0, 0]),
1,
) {
log::warn!("添加组播路由失败 ={:?}", e);
}
for (dest, mask) in config.external_route {
if let Err(e) = device.add_route(dest, mask, 1) {
if let Err(e) = add_route(index, dest, mask) {
log::warn!("添加路由失败,请检查-i参数是否和现有路由冲突 ={:?}", e);
call.error(ErrorInfo::new_msg(
ErrorType::Warn,
@@ -61,14 +56,29 @@ pub fn create_device<Call: VntCallback>(
}
fn create_device0(config: &DeviceConfig) -> io::Result<Arc<Device>> {
let mut tun_config = tun_rs::Configuration::default();
let netmask = u32::from_be_bytes(config.virtual_netmask.octets());
tun_config
.address_with_prefix(config.virtual_ip, netmask.count_ones() as u8)
.up();
#[cfg(target_os = "windows")]
let default_name: &str = if config.tap {
DEFAULT_TAP_NAME
} else {
DEFAULT_TUN_NAME
};
{
let default_name = if config.tap {
tun_config.layer(tun_rs::Layer::L2);
DEFAULT_TAP_NAME
} else {
DEFAULT_TUN_NAME
};
tun_config.name(
config
.device_name
.clone()
.unwrap_or(default_name.to_string()),
);
}
#[cfg(target_os = "linux")]
let device = {
{
let device_name = config
.device_name
.clone()
@@ -76,20 +86,11 @@ fn create_device0(config: &DeviceConfig) -> io::Result<Arc<Device>> {
if &device_name == DEFAULT_TUN_NAME {
delete_device(DEFAULT_TUN_NAME);
}
Arc::new(Device::new(Some(device_name))?)
};
#[cfg(target_os = "macos")]
let device = Arc::new(Device::new(config.device_name.clone())?);
#[cfg(target_os = "windows")]
let device = Arc::new(Device::new(
config
.device_name
.clone()
.unwrap_or(default_name.to_string()),
config.tap,
)?);
device.set_mtu(config.mtu)?;
Ok(device)
}
tun_config.mtu(config.mtu as u16);
let device = tun_rs::create(&tun_config)?;
Ok(Arc::new(device))
}
#[cfg(target_os = "linux")]
@@ -106,3 +107,76 @@ fn delete_device(name: &str) {
log::warn!("删除网卡失败:{:?}", delete_tun);
}
}
#[cfg(target_os = "windows")]
pub fn add_route(index: u32, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
let cmd = format!(
"route add {:?} mask {:?} {:?} metric {} if {}",
dest,
netmask,
Ipv4Addr::UNSPECIFIED,
1,
index
);
exe_cmd(&cmd)
}
#[cfg(target_os = "windows")]
pub fn exe_cmd(cmd: &str) -> io::Result<()> {
use std::os::windows::process::CommandExt;
println!("exe cmd: {}", cmd);
let out = std::process::Command::new("cmd")
.creation_flags(windows_sys::Win32::System::Threading::CREATE_NO_WINDOW)
.arg("/C")
.arg(&cmd)
.output()?;
if !out.status.success() {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("cmd={},out={:?}", cmd, String::from_utf8(out.stderr)),
));
}
Ok(())
}
#[cfg(target_os = "macos")]
pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
let cmd = format!(
"route -n add {} -netmask {} -interface {}",
address, netmask, name
);
exe_cmd(&cmd)?;
Ok(())
}
#[cfg(target_os = "linux")]
pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
let cmd = if netmask.is_broadcast() {
format!("route add -host {:?} {}", address, name)
} else {
format!(
"route add -net {}/{} {}",
address,
u32::from(netmask).count_ones(),
name
)
};
exe_cmd(&cmd)?;
Ok(())
}
#[cfg(any(target_os = "macos", target_os = "linux"))]
pub fn exe_cmd(cmd: &str) -> io::Result<std::process::Output> {
use std::process::Command;
println!("exe cmd: {}", cmd);
let out = Command::new("sh")
.arg("-c")
.arg(cmd)
.output()
.expect("sh exec error!");
if !out.status.success() {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("cmd={},out={:?}", cmd, out),
));
}
Ok(out)
}

View File

@@ -3,12 +3,6 @@ use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use tun::device::IFace;
use tun::Device;
use crate::channel::context::ChannelContext;
use crate::cipher::Cipher;
use crate::compression::Compressor;
@@ -19,6 +13,9 @@ use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
use crate::ip_proxy::IpProxyMap;
use crate::tun_tap_device::vnt_device::DeviceWrite;
use crate::util::StopManager;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use tun_rs::platform::Device;
#[repr(transparent)]
#[derive(Clone, Default)]
@@ -41,7 +38,7 @@ impl DeviceWrite for DeviceAdapter {
#[inline]
fn write(&self, buf: &[u8]) -> io::Result<usize> {
if let Some(tun) = self.tun.lock().as_ref() {
tun.write(buf)
tun.send(buf)
} else {
Err(io::Error::new(io::ErrorKind::NotFound, "not tun device"))
}

View File

@@ -1,34 +0,0 @@
[package]
name = "tun"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libc = "0.2.153"
log = { version = "0.4.20", features = [] }
rand = "0.8.5"
sha2 = { version = "0.10.6", features = ["oid"] }
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
ioctl = { version = "0.8", package = "ioctl-sys" }
[target.'cfg(target_os = "windows")'.dependencies]
libloading = "0.8.0"
widestring = "1.0.2"
winapi = { version = "0.3", features = [
"errhandlingapi",
"libloaderapi",
"combaseapi",
"ioapiset",
"winioctl",
"setupapi",
"synchapi",
"netioapi",
"fileapi", "handleapi", "winerror", "minwindef", "ifdef", "basetsd", "winnt", "winreg", "winbase", "minwinbase",
"impl-default"
] }

View File

@@ -1,61 +0,0 @@
use crate::device::IFace;
use crate::Fd;
use std::io;
use std::net::Ipv4Addr;
use std::os::fd::RawFd;
pub struct Device {
fd: Fd,
}
impl Device {
pub fn new(fd: RawFd) -> io::Result<Self> {
Ok(Self { fd: Fd::new(fd)? })
}
}
impl Device {
pub fn as_tun_fd(&self) -> &Fd {
&self.fd
}
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
Ok(String::new())
}
fn name(&self) -> io::Result<String> {
Ok(String::new())
}
fn shutdown(&self) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn set_ip(&self, _address: Ipv4Addr, _mask: Ipv4Addr) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn mtu(&self) -> io::Result<u32> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn set_mtu(&self, _value: u32) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn add_route(&self, _dest: Ipv4Addr, _netmask: Ipv4Addr, _metric: u16) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn delete_route(&self, _dest: Ipv4Addr, _netmask: Ipv4Addr) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.fd.read(buf)
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.fd.write(buf)
}
}

View File

@@ -1,24 +0,0 @@
use io::Result;
use std::io;
use std::net::Ipv4Addr;
pub trait IFace {
fn version(&self) -> Result<String>;
/// Get the device name.
fn name(&self) -> Result<String>;
fn shutdown(&self) -> Result<()>;
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> Result<()>;
/// Get the MTU.
fn mtu(&self) -> Result<u32>;
/// Set the MTU.
fn set_mtu(&self, value: u32) -> Result<()>;
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> Result<()>;
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> Result<()>;
fn read(&self, buf: &mut [u8]) -> Result<usize>;
fn write(&self, buf: &[u8]) -> Result<usize>;
}

View File

@@ -1,33 +0,0 @@
/// 参考
/// https://github.com/meh/rust-tun
/// https://github.com/Tazdevil971/tap-windows
/// https://github.com/nulldotblack/wintun
pub mod device;
#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "linux")]
pub use linux::Device;
#[cfg(target_os = "android")]
mod android;
#[cfg(target_os = "android")]
pub use android::Device;
#[cfg(target_os = "macos")]
mod macos;
#[cfg(target_os = "macos")]
pub use macos::Device;
#[cfg(unix)]
mod unix;
#[cfg(unix)]
pub use unix::Fd;
#[cfg(windows)]
mod windows;
#[cfg(windows)]
pub use windows::Device;
#[cfg(windows)]
mod packet;

View File

@@ -1,281 +0,0 @@
#![allow(dead_code)]
use std::ffi::{CStr, CString};
use std::net::Ipv4Addr;
use std::os::fd::AsRawFd;
use std::{io, mem, ptr};
use libc::{
c_char, c_short, ifreq, AF_INET, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_RUNNING, IFF_TUN, IFF_UP,
IFNAMSIZ, O_RDWR, SOCK_DGRAM,
};
use crate::device::IFace;
use crate::linux::route;
use crate::linux::sys::*;
use crate::unix::{exe_cmd, Fd, SockAddr};
pub struct Device {
name: String,
ctl: Fd,
tun: Fd,
}
impl Device {
pub fn new(name: Option<String>) -> io::Result<Self> {
let device = unsafe {
let dev = match name {
Some(name) => {
let name =
CString::new(name).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
if name.as_bytes_with_nul().len() > IFNAMSIZ {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "name too long"));
}
Some(name)
}
None => None,
};
let mut req: ifreq = mem::zeroed();
if let Some(dev) = dev.as_ref() {
ptr::copy_nonoverlapping(
dev.as_ptr() as *const c_char,
req.ifr_name.as_mut_ptr(),
dev.as_bytes().len(),
);
}
let device_type: c_short = IFF_TUN as c_short; //if tap { IFF_TAP } else { IFF_TUN } as c_short;
let queues_num = 1;
let iff_no_pi = IFF_NO_PI as c_short;
let iff_multi_queue = IFF_MULTI_QUEUE as c_short;
let packet_information = false;
req.ifr_ifru.ifru_flags = device_type
| if packet_information { 0 } else { iff_no_pi }
| if queues_num > 1 { iff_multi_queue } else { 0 };
let tun = Fd::new(libc::open(b"/dev/net/tun\0".as_ptr() as *const _, O_RDWR))
.map_err(|_| io::Error::last_os_error())?;
if tunsetiff(tun.0, &mut req as *mut _ as *mut _) < 0 {
return Err(io::Error::last_os_error());
}
let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))?;
let name = CStr::from_ptr(req.ifr_name.as_ptr())
.to_string_lossy()
.to_string();
let set_txqueuelen = format!("ifconfig {} txqueuelen 1000", name);
if let Err(e) = exe_cmd(&set_txqueuelen) {
log::warn!("{:?}", e);
}
Device { name, tun, ctl }
};
device.enabled(true)?;
Ok(device)
}
}
impl Device {
fn enabled(&self, value: bool) -> io::Result<()> {
unsafe {
let mut req = self.request();
if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error());
}
if value {
req.ifr_ifru.ifru_flags |= (IFF_UP | IFF_RUNNING) as c_short;
} else {
req.ifr_ifru.ifru_flags &= !(IFF_UP as c_short);
}
if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
unsafe fn request(&self) -> ifreq {
let mut req: ifreq = mem::zeroed();
ptr::copy_nonoverlapping(
self.name.as_ptr() as *const c_char,
req.ifr_name.as_mut_ptr(),
self.name.len(),
);
req
}
fn address(&self) -> io::Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifr_ifru.ifru_addr).map(Into::into)
}
}
fn set_address(&self, value: Ipv4Addr) -> io::Result<()> {
unsafe {
let mut req = self.request();
req.ifr_ifru.ifru_addr = SockAddr::from(value).into();
if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
fn destination(&self) -> io::Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifdstaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error());
}
SockAddr::new(&req.ifr_ifru.ifru_dstaddr).map(Into::into)
}
}
fn set_destination(&self, value: Ipv4Addr) -> io::Result<()> {
unsafe {
let mut req = self.request();
req.ifr_ifru.ifru_dstaddr = SockAddr::from(value).into();
if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
fn broadcast(&self) -> io::Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifbrdaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error());
}
SockAddr::new(&req.ifr_ifru.ifru_broadaddr).map(Into::into)
}
}
fn set_broadcast(&self, value: Ipv4Addr) -> io::Result<()> {
unsafe {
let mut req = self.request();
req.ifr_ifru.ifru_broadaddr = SockAddr::from(value).into();
if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
fn netmask(&self) -> io::Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifnetmask(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error());
}
SockAddr::new(&req.ifr_ifru.ifru_netmask).map(Into::into)
}
}
fn set_netmask(&self, value: Ipv4Addr) -> io::Result<()> {
unsafe {
let mut req = self.request();
req.ifr_ifru.ifru_netmask = SockAddr::from(value).into();
if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
}
impl Device {
pub fn as_tun_fd(&self) -> &Fd {
&self.tun
}
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
Ok(String::new())
}
fn name(&self) -> io::Result<String> {
Ok(self.name.clone())
}
fn shutdown(&self) -> io::Result<()> {
exe_cmd(&format!("ip link delete {}", self.name))?;
Ok(())
}
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
self.set_address(address)?;
self.set_netmask(mask)
}
fn mtu(&self) -> io::Result<u32> {
unsafe {
let mut req = self.request();
if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(req.ifr_ifru.ifru_mtu as u32)
}
}
fn set_mtu(&self, value: u32) -> io::Result<()> {
unsafe {
let mut req = self.request();
req.ifr_ifru.ifru_mtu = value as _;
if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, _metric: u16) -> io::Result<()> {
route::add_route(&self.name, dest, netmask)
}
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
route::del_route(&self.name, dest, netmask)
}
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.tun.read(buf)
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.tun.write(buf)
}
}

View File

@@ -1,4 +0,0 @@
mod device;
pub use device::Device;
mod route;
mod sys;

View File

@@ -1,25 +0,0 @@
use std::io;
use std::net::Ipv4Addr;
use crate::unix::exe_cmd;
pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
let cmd = if netmask.is_broadcast() {
format!("route add -host {:?} {}", address, name)
} else {
format!(
"route add -net {}/{} {}",
address,
u32::from(netmask).count_ones(),
name
)
};
exe_cmd(&cmd)?;
Ok(())
}
pub fn del_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
let cmd = format!("ip route del {:?}/{:?} dev {}", address, netmask, name);
exe_cmd(&cmd)?;
Ok(())
}

View File

@@ -1,21 +0,0 @@
use ioctl::*;
use libc::{c_int, ifreq};
ioctl!(bad read siocgifflags with 0x8913; ifreq);
ioctl!(bad write siocsifflags with 0x8914; ifreq);
ioctl!(bad read siocgifaddr with 0x8915; ifreq);
ioctl!(bad write siocsifaddr with 0x8916; ifreq);
ioctl!(bad read siocgifdstaddr with 0x8917; ifreq);
ioctl!(bad write siocsifdstaddr with 0x8918; ifreq);
ioctl!(bad read siocgifbrdaddr with 0x8919; ifreq);
ioctl!(bad write siocsifbrdaddr with 0x891a; ifreq);
ioctl!(bad read siocgifnetmask with 0x891b; ifreq);
ioctl!(bad write siocsifnetmask with 0x891c; ifreq);
ioctl!(bad read siocgifmtu with 0x8921; ifreq);
ioctl!(bad write siocsifmtu with 0x8922; ifreq);
ioctl!(bad write siocsifname with 0x8923; ifreq);
ioctl!(write tunsetiff with b'T', 202; c_int);
ioctl!(write tunsetpersist with b'T', 203; c_int);
ioctl!(write tunsetowner with b'T', 204; c_int);
ioctl!(write tunsetgroup with b'T', 206; c_int);

View File

@@ -1,297 +0,0 @@
#![allow(dead_code)]
use std::ffi::{c_void, CStr};
use std::net::Ipv4Addr;
use std::os::fd::AsRawFd;
use std::{io, mem, ptr};
use libc::{
c_char, c_short, c_uint, sockaddr, socklen_t, AF_INET, AF_SYSTEM, AF_SYS_CONTROL, IFF_RUNNING,
IFF_UP, IFNAMSIZ, PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL, UTUN_OPT_IFNAME,
};
use crate::device::IFace;
use crate::macos::route;
use crate::macos::sys::*;
use crate::unix::{Fd, SockAddr};
pub struct Device {
name: String,
ctl: Fd,
tun: Fd,
}
impl Device {
pub fn new(name: Option<String>) -> io::Result<Self> {
let id = if let Some(name) = name {
if name.len() > IFNAMSIZ {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "name too long"));
}
if !name.starts_with("utun") {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid name"));
}
name[4..]
.parse::<u32>()
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?
+ 1u32
} else {
0u32
};
let device = unsafe {
let tun = Fd::new(libc::socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL))?;
let mut info = ctl_info {
ctl_id: 0,
ctl_name: {
let mut buffer = [0; 96];
for (i, o) in UTUN_CONTROL_NAME.as_bytes().iter().zip(buffer.iter_mut()) {
*o = *i as _;
}
buffer
},
};
if ctliocginfo(tun.0, &mut info as *mut _ as *mut _) < 0 {
return Err(io::Error::last_os_error());
}
let addr = sockaddr_ctl {
sc_id: info.ctl_id,
sc_len: mem::size_of::<sockaddr_ctl>() as _,
sc_family: AF_SYSTEM as _,
ss_sysaddr: AF_SYS_CONTROL as _,
sc_unit: id as c_uint,
sc_reserved: [0; 5],
};
let address = &addr as *const sockaddr_ctl as *const sockaddr;
if libc::connect(tun.0, address, mem::size_of_val(&addr) as socklen_t) < 0 {
return Err(io::Error::last_os_error());
}
let mut name = [0u8; 64];
let mut name_len: socklen_t = 64;
let optval = &mut name as *mut _ as *mut c_void;
let optlen = &mut name_len as *mut socklen_t;
if libc::getsockopt(tun.0, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, optval, optlen) < 0 {
return Err(io::Error::last_os_error());
}
let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))?;
Device {
name: CStr::from_ptr(name.as_ptr() as *const c_char)
.to_string_lossy()
.into(),
tun,
ctl,
}
};
device.enabled(true)?;
Ok(device)
}
}
impl Device {
fn enabled(&self, value: bool) -> io::Result<()> {
unsafe {
let mut req = self.request();
if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error());
}
if value {
req.ifru.flags |= (IFF_UP | IFF_RUNNING) as c_short;
} else {
req.ifru.flags &= !(IFF_UP as c_short);
}
if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
unsafe fn request(&self) -> ifreq {
let mut req: ifreq = mem::zeroed();
ptr::copy_nonoverlapping(
self.name.as_ptr() as *const c_char,
req.ifrn.name.as_mut_ptr(),
self.name.len(),
);
req
}
fn address(&self) -> io::Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error());
}
SockAddr::new(&req.ifru.addr).map(Into::into)
}
}
fn set_address(&self, value: Ipv4Addr) -> io::Result<()> {
unsafe {
let mut req = self.request();
req.ifru.addr = SockAddr::from(value).into();
if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
fn destination(&self) -> io::Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifdstaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error());
}
SockAddr::new(&req.ifru.dstaddr).map(Into::into)
}
}
fn set_destination(&self, value: Ipv4Addr) -> io::Result<()> {
unsafe {
let mut req = self.request();
req.ifru.dstaddr = SockAddr::from(value).into();
if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
fn broadcast(&self) -> io::Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifbrdaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error());
}
SockAddr::new(&req.ifru.broadaddr).map(Into::into)
}
}
fn set_broadcast(&self, value: Ipv4Addr) -> io::Result<()> {
unsafe {
let mut req = self.request();
req.ifru.broadaddr = SockAddr::from(value).into();
if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
fn netmask(&self) -> io::Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifnetmask(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error());
}
SockAddr::unchecked(&req.ifru.addr).map(Into::into)
}
}
fn set_netmask(&self, value: Ipv4Addr) -> io::Result<()> {
unsafe {
let mut req = self.request();
req.ifru.addr = SockAddr::from(value).into();
if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
}
impl Device {
pub fn as_tun_fd(&self) -> &Fd {
&self.tun
}
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
Ok(String::new())
}
fn name(&self) -> io::Result<String> {
Ok(self.name.clone())
}
fn shutdown(&self) -> io::Result<()> {
Ok(())
}
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
self.set_address(address)?;
self.set_netmask(mask)
}
fn mtu(&self) -> io::Result<u32> {
unsafe {
let mut req = self.request();
if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(req.ifru.mtu as _)
}
}
fn set_mtu(&self, value: u32) -> io::Result<()> {
unsafe {
let mut req = self.request();
req.ifru.mtu = value as _;
if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, _metric: u16) -> io::Result<()> {
route::add_route(&self.name, dest, netmask)
}
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
route::del_route(&self.name, dest, netmask)
}
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.tun.read(buf)
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
let mut packet = Vec::<u8>::with_capacity(4 + buf.len());
packet.push(0);
packet.push(0);
packet.extend_from_slice(&(libc::PF_INET as u16).to_be_bytes());
packet.extend_from_slice(buf);
self.tun.write(&packet)
}
}

View File

@@ -1,5 +0,0 @@
mod device;
pub use device::Device;
mod sys;
mod route;

View File

@@ -1,20 +0,0 @@
use crate::unix::exe_cmd;
use std::io;
use std::net::Ipv4Addr;
pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
let cmd = format!(
"route -n add {} -netmask {} -interface {}",
address, netmask, name
);
exe_cmd(&cmd)?;
Ok(())
}
pub fn del_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
let cmd = format!(
"route -n delete {} -netmask {} -interface {}",
address, netmask, name
);
exe_cmd(&cmd)?;
Ok(())
}

View File

@@ -1,119 +0,0 @@
//! Bindings to internal macOS stuff.
use ioctl::*;
use libc::{c_char, c_int, c_short, c_uint, c_ushort, c_void, sockaddr, IFNAMSIZ};
pub const UTUN_CONTROL_NAME: &str = "com.apple.net.utun_control";
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ctl_info {
pub ctl_id: c_uint,
pub ctl_name: [c_char; 96],
}
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct sockaddr_ctl {
pub sc_len: c_char,
pub sc_family: c_char,
pub ss_sysaddr: c_ushort,
pub sc_id: c_uint,
pub sc_unit: c_uint,
pub sc_reserved: [c_uint; 5],
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifrn {
pub name: [c_char; IFNAMSIZ],
}
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifdevmtu {
pub current: c_int,
pub min: c_int,
pub max: c_int,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifku {
pub ptr: *mut c_void,
pub value: c_int,
}
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifkpi {
pub module_id: c_uint,
pub type_: c_uint,
pub ifku: ifku,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifru {
pub addr: sockaddr,
pub dstaddr: sockaddr,
pub broadaddr: sockaddr,
pub flags: c_short,
pub metric: c_int,
pub mtu: c_int,
pub phys: c_int,
pub media: c_int,
pub intval: c_int,
pub data: *mut c_void,
pub devmtu: ifdevmtu,
pub wake_flags: c_uint,
pub route_refcnt: c_uint,
pub cap: [c_int; 2],
pub functional_type: c_uint,
}
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifreq {
pub ifrn: ifrn,
pub ifru: ifru,
}
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifaliasreq {
pub ifran: [c_char; IFNAMSIZ],
pub addr: sockaddr,
pub broadaddr: sockaddr,
pub mask: sockaddr,
}
ioctl!(readwrite ctliocginfo with 'N', 3; ctl_info);
ioctl!(write siocsifflags with 'i', 16; ifreq);
ioctl!(readwrite siocgifflags with 'i', 17; ifreq);
ioctl!(write siocsifaddr with 'i', 12; ifreq);
ioctl!(readwrite siocgifaddr with 'i', 33; ifreq);
ioctl!(write siocsifdstaddr with 'i', 14; ifreq);
ioctl!(readwrite siocgifdstaddr with 'i', 34; ifreq);
ioctl!(write siocsifbrdaddr with 'i', 19; ifreq);
ioctl!(readwrite siocgifbrdaddr with 'i', 35; ifreq);
ioctl!(write siocsifnetmask with 'i', 22; ifreq);
ioctl!(readwrite siocgifnetmask with 'i', 37; ifreq);
ioctl!(write siocsifmtu with 'i', 52; ifreq);
ioctl!(readwrite siocgifmtu with 'i', 51; ifreq);
ioctl!(write siocaifaddr with 'i', 26; ifaliasreq);
ioctl!(write siocdifaddr with 'i', 25; ifreq);

View File

@@ -1 +0,0 @@
pub mod packet;

View File

@@ -1,123 +0,0 @@
#![allow(dead_code)]
use std::{fmt, io};
/// 地址解析协议由IP地址找到MAC地址
/// https://www.ietf.org/rfc/rfc6747.txt
/*
0 2 4 5 6 8 10 (字节)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 硬件类型|协议类型|硬件地址长度|协议地址长度|操作类型|
| 源MAC地址 | 源ip地址 |
| 目的MAC地址 | 目的ip地址 |
*/
pub struct ArpPacket<B> {
buffer: B,
}
impl<B: AsRef<[u8]>> ArpPacket<B> {
pub fn unchecked(buffer: B) -> Self {
Self { buffer }
}
pub fn new(buffer: B) -> io::Result<Self> {
if buffer.as_ref().len() != 28 {
Err(io::Error::from(io::ErrorKind::InvalidData))?;
}
let packet = Self::unchecked(buffer);
Ok(packet)
}
}
impl<B: AsRef<[u8]>> ArpPacket<B> {
/// 硬件类型 以太网类型为1
pub fn hardware_type(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[0..2].try_into().unwrap())
}
/// 上层协议类型,ipv4是0x0800
pub fn protocol_type(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
}
/// 如果是MAC地址 则长度为6
pub fn hardware_size(&self) -> u8 {
self.buffer.as_ref()[4]
}
/// 如果是IPv4 则长度为4
pub fn protocol_size(&self) -> u8 {
self.buffer.as_ref()[5]
}
/// 操作类型,请求和响应 1ARP请求2ARP响应3RARP请求4RARP响应
pub fn op_code(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap())
}
/// 发送端硬件地址,仅支持以太网
pub fn sender_hardware_addr(&self) -> &[u8] {
&self.buffer.as_ref()[8..14]
}
/// 发送端协议地址仅支持IPv4
pub fn sender_protocol_addr(&self) -> &[u8] {
&self.buffer.as_ref()[14..18]
}
/// 接收端硬件地址,仅支持以太网
pub fn target_hardware_addr(&self) -> &[u8] {
&self.buffer.as_ref()[18..24]
}
/// 接收端协议地址仅支持IPv4
pub fn target_protocol_addr(&self) -> &[u8] {
&self.buffer.as_ref()[24..28]
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> ArpPacket<B> {
/// 硬件类型 以太网类型为1
pub fn set_hardware_type(&mut self, value: u16) {
self.buffer.as_mut()[0..2].copy_from_slice(&value.to_be_bytes())
}
/// 上层协议类型,ipv4是0x0800
pub fn set_protocol_type(&mut self, value: u16) {
self.buffer.as_mut()[2..4].copy_from_slice(&value.to_be_bytes())
}
/// 如果是MAC地址 则长度为6
pub fn set_hardware_size(&mut self, value: u8) {
self.buffer.as_mut()[4] = value
}
/// 如果是IPv4 则长度为4
pub fn set_protocol_size(&mut self, value: u8) {
self.buffer.as_mut()[5] = value
}
/// 操作类型,请求和响应 1ARP请求2ARP响应3RARP请求4RARP响应
pub fn set_op_code(&mut self, value: u16) {
self.buffer.as_mut()[6..8].copy_from_slice(&value.to_be_bytes())
}
/// 发送端硬件地址,仅支持以太网
pub fn set_sender_hardware_addr(&mut self, buf: &[u8]) {
self.buffer.as_mut()[8..14].copy_from_slice(buf)
}
/// 发送端协议地址仅支持IPv4
pub fn set_sender_protocol_addr(&mut self, buf: &[u8]) {
self.buffer.as_mut()[14..18].copy_from_slice(buf)
}
/// 接收端硬件地址,仅支持以太网
pub fn set_target_hardware_addr(&mut self, buf: &[u8]) {
self.buffer.as_mut()[18..24].copy_from_slice(buf)
}
/// 接收端协议地址仅支持IPv4
pub fn set_target_protocol_addr(&mut self, buf: &[u8]) {
self.buffer.as_mut()[24..28].copy_from_slice(buf)
}
}
impl<B: AsRef<[u8]>> fmt::Debug for ArpPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ArpPacket")
.field("hardware_type", &self.hardware_type())
.field("protocol_type", &self.protocol_type())
.field("hardware_size", &self.hardware_size())
.field("protocol_size", &self.protocol_size())
.field("op_code", &self.op_code())
.field("sender_hardware_addr", &self.sender_hardware_addr())
.field("sender_protocol_addr", &self.sender_protocol_addr())
.field("target_hardware_addr", &self.target_hardware_addr())
.field("target_protocol_addr", &self.target_protocol_addr())
.finish()
}
}

View File

@@ -1,2 +0,0 @@
pub mod packet;
pub mod protocol;

View File

@@ -1,80 +0,0 @@
use crate::packet::ethernet::protocol::Protocol;
use std::{fmt, io};
/// 以太网帧协议
/// https://www.ietf.org/rfc/rfc894.txt
/*
0 6 12 14 (字节)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 目的地址 | 源地址 | 类型 |
*/
pub struct EthernetPacket<B> {
pub buffer: B,
}
impl<B: AsRef<[u8]>> EthernetPacket<B> {
pub fn unchecked(buffer: B) -> EthernetPacket<B> {
EthernetPacket { buffer }
}
pub fn new(buffer: B) -> io::Result<EthernetPacket<B>> {
let packet = EthernetPacket::unchecked(buffer);
//头部固定14位
if packet.buffer.as_ref().len() < 14 {
Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("len={}", packet.buffer.as_ref().len()),
))?;
}
Ok(packet)
}
}
impl<B: AsRef<[u8]>> EthernetPacket<B> {
/// 目的MAC地址
pub fn destination(&self) -> &[u8] {
&self.buffer.as_ref()[0..6]
}
/// 源MAC地址
pub fn source(&self) -> &[u8] {
&self.buffer.as_ref()[6..12]
}
/// 3层协议
pub fn protocol(&self) -> Protocol {
u16::from_be_bytes(self.buffer.as_ref()[12..14].try_into().unwrap()).into()
}
/// 载荷
pub fn payload(&self) -> &[u8] {
&self.buffer.as_ref()[14..]
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> EthernetPacket<B> {
pub fn set_destination(&mut self, value: &[u8]) {
self.buffer.as_mut()[0..6].copy_from_slice(value);
}
pub fn set_source(&mut self, value: &[u8]) {
self.buffer.as_mut()[6..12].copy_from_slice(value);
}
pub fn set_protocol(&mut self, value: Protocol) {
let p: u16 = value.into();
self.buffer.as_mut()[12..14].copy_from_slice(&p.to_be_bytes())
}
pub fn payload_mut(&mut self) -> &mut [u8] {
&mut self.buffer.as_mut()[14..]
}
}
impl<B: AsRef<[u8]>> fmt::Debug for EthernetPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EthernetPacket")
.field("destination", &self.destination())
.field("source", &self.source())
.field("protocol", &self.protocol())
.field("payload", &self.payload())
.finish()
}
}

View File

@@ -1,141 +0,0 @@
/// 以太网帧协议
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Protocol {
///
Ipv4,
///
Arp,
///
WakeOnLan,
///
Trill,
///
DecNet,
///
Rarp,
///
AppleTalk,
///
Aarp,
///
Ipx,
///
Qnx,
///
Ipv6,
///
FlowControl,
///
CobraNet,
///
Mpls,
///
MplsMulticast,
///
PppoeDiscovery,
///
PppoeSession,
///
Vlan,
///
PBridge,
///
Lldp,
///
Ptp,
///
Cfm,
///
QinQ,
///
Unknown(u16),
}
impl From<u16> for Protocol {
fn from(value: u16) -> Protocol {
use self::Protocol::*;
match value {
0x0800 => Ipv4,
0x0806 => Arp,
0x0842 => WakeOnLan,
0x22f3 => Trill,
0x6003 => DecNet,
0x8035 => Rarp,
0x809b => AppleTalk,
0x80f3 => Aarp,
0x8137 => Ipx,
0x8204 => Qnx,
0x86dd => Ipv6,
0x8808 => FlowControl,
0x8819 => CobraNet,
0x8847 => Mpls,
0x8848 => MplsMulticast,
0x8863 => PppoeDiscovery,
0x8864 => PppoeSession,
0x8100 => Vlan,
0x88a8 => PBridge,
0x88cc => Lldp,
0x88f7 => Ptp,
0x8902 => Cfm,
0x9100 => QinQ,
n => Unknown(n),
}
}
}
impl Into<u16> for Protocol {
fn into(self) -> u16 {
use self::Protocol::*;
match self {
Ipv4 => 0x0800,
Arp => 0x0806,
WakeOnLan => 0x0842,
Trill => 0x22f3,
DecNet => 0x6003,
Rarp => 0x8035,
AppleTalk => 0x809b,
Aarp => 0x80f3,
Ipx => 0x8137,
Qnx => 0x8204,
Ipv6 => 0x86dd,
FlowControl => 0x8808,
CobraNet => 0x8819,
Mpls => 0x8847,
MplsMulticast => 0x8848,
PppoeDiscovery => 0x8863,
PppoeSession => 0x8864,
Vlan => 0x8100,
PBridge => 0x88a8,
Lldp => 0x88cc,
Ptp => 0x88f7,
Cfm => 0x8902,
QinQ => 0x9100,
Unknown(n) => n,
}
}
}

View File

@@ -1,67 +0,0 @@
use crate::packet::ethernet::protocol::Protocol;
use std::io;
pub mod arp;
pub mod ethernet;
const MAC: [u8; 6] = [0xf, 0xf, 0xf, 0xf, 0xe, 0x9];
pub fn read_tap<W, R>(buf: &mut [u8], read_fn: R, write_fn: W) -> io::Result<usize>
where
W: Fn(&[u8]) -> io::Result<usize>,
R: Fn(&mut [u8]) -> io::Result<usize>,
{
let mut eth_buf = [0; 65536];
loop {
let len = read_fn(&mut eth_buf)?;
if len == 0 {
return Ok(len);
}
//处理arp包
let mut ether = ethernet::packet::EthernetPacket::new(&mut eth_buf[..len])?;
match ether.protocol() {
Protocol::Ipv4 => {
let len = ether.payload().len();
if len > buf.len() {
return Err(io::Error::new(io::ErrorKind::Other, "short"));
}
buf[..len].copy_from_slice(ether.payload());
return Ok(len);
}
Protocol::Arp => {
let mut arp_packet = arp::packet::ArpPacket::unchecked(ether.payload_mut());
let sender_h: [u8; 6] = arp_packet.sender_hardware_addr().try_into().unwrap();
let sender_p: [u8; 4] = arp_packet.sender_protocol_addr().try_into().unwrap();
let target_p: [u8; 4] = arp_packet.target_protocol_addr().try_into().unwrap();
if target_p == [0, 0, 0, 0] || sender_p == [0, 0, 0, 0] || target_p == sender_p {
continue;
}
if arp_packet.op_code() == 1 {
//回复一个默认的MAC
arp_packet.set_op_code(2);
arp_packet.set_target_hardware_addr(&sender_h);
arp_packet.set_target_protocol_addr(&sender_p);
arp_packet.set_sender_protocol_addr(&target_p);
arp_packet.set_sender_hardware_addr(&MAC);
ether.set_destination(&sender_h);
ether.set_source(&MAC);
write_fn(ether.buffer)?;
}
}
_ => {
//忽略这些数据
}
}
}
}
pub fn write_tap<W>(buf: &[u8], write_fn: W, mac: &[u8; 6]) -> io::Result<usize>
where
W: Fn(&[u8]) -> io::Result<usize>,
{
// 封装二层数据
let mut ether = ethernet::packet::EthernetPacket::unchecked(vec![0; 14 + buf.len()]);
ether.set_source(&MAC);
ether.set_destination(mac);
ether.set_protocol(Protocol::Ipv4);
ether.payload_mut().copy_from_slice(buf);
write_fn(&ether.buffer)
}

View File

@@ -1,68 +0,0 @@
use libc::{fcntl, F_GETFL, F_SETFL, O_NONBLOCK};
use std::io;
use std::os::fd::{AsRawFd, IntoRawFd, RawFd};
pub struct Fd(pub RawFd);
impl Fd {
pub fn new(value: RawFd) -> io::Result<Self> {
if value < 0 {
return Err(io::Error::from(io::ErrorKind::InvalidInput));
}
Ok(Fd(value))
}
pub fn set_nonblock(&self) -> io::Result<()> {
match unsafe { fcntl(self.0, F_SETFL, fcntl(self.0, F_GETFL) | O_NONBLOCK) } {
0 => Ok(()),
_ => Err(io::Error::last_os_error()),
}
}
}
impl Fd {
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
unsafe {
let amount = libc::read(self.0, buf.as_mut_ptr() as *mut _, buf.len());
if amount < 0 {
return Err(io::Error::last_os_error());
}
Ok(amount as usize)
}
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
unsafe {
let amount = libc::write(self.0, buf.as_ptr() as *const _, buf.len());
if amount < 0 {
return Err(io::Error::last_os_error());
}
Ok(amount as usize)
}
}
}
impl AsRawFd for Fd {
fn as_raw_fd(&self) -> RawFd {
self.0
}
}
impl IntoRawFd for Fd {
fn into_raw_fd(mut self) -> RawFd {
let fd = self.0;
self.0 = -1;
fd
}
}
#[cfg(not(target_os = "android"))]
impl Drop for Fd {
fn drop(&mut self) {
unsafe {
libc::close(self.0);
}
}
}

View File

@@ -1,28 +0,0 @@
mod fd;
pub use fd::Fd;
#[cfg(any(target_os = "macos", target_os = "linux"))]
use std::process::Output;
#[cfg(any(target_os = "macos", target_os = "linux"))]
mod sockaddr;
#[cfg(any(target_os = "macos", target_os = "linux"))]
pub use sockaddr::SockAddr;
#[cfg(any(target_os = "macos", target_os = "linux"))]
pub fn exe_cmd(cmd: &str) -> std::io::Result<Output> {
use std::io;
use std::process::Command;
println!("exe cmd: {}", cmd);
let out = Command::new("sh")
.arg("-c")
.arg(cmd)
.output()
.expect("sh exec error!");
if !out.status.success() {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("cmd={},out={:?}", cmd, out),
));
}
Ok(out)
}

View File

@@ -1,67 +0,0 @@
use libc::{in_addr, sockaddr, sockaddr_in};
use std::{io, mem, net::Ipv4Addr, ptr};
use io::Result;
/// A wrapper for `sockaddr_in`.
#[derive(Copy, Clone)]
pub struct SockAddr(sockaddr_in);
impl SockAddr {
/// Create a new `SockAddr` from a generic `sockaddr`.
pub fn new(value: &sockaddr) -> Result<Self> {
if value.sa_family != libc::AF_INET as libc::sa_family_t {
return Err(io::Error::new(io::ErrorKind::Other, "invalid address"));
}
unsafe { Self::unchecked(value) }
}
/// # Safety
/// Create a new `SockAddr` and not check the source.
pub unsafe fn unchecked(value: &sockaddr) -> Result<Self> {
Ok(SockAddr(ptr::read(value as *const _ as *const _)))
}
/// # Safety
/// Get a generic pointer to the `SockAddr`.
pub unsafe fn as_ptr(&self) -> *const sockaddr {
&self.0 as *const _ as *const sockaddr
}
}
impl From<Ipv4Addr> for SockAddr {
fn from(ip: Ipv4Addr) -> SockAddr {
let octets = ip.octets();
let mut addr = unsafe { mem::zeroed::<sockaddr_in>() };
addr.sin_family = libc::AF_INET as libc::sa_family_t;
addr.sin_port = 0;
addr.sin_addr = in_addr {
s_addr: u32::from_ne_bytes(octets),
};
SockAddr(addr)
}
}
impl From<SockAddr> for Ipv4Addr {
fn from(addr: SockAddr) -> Ipv4Addr {
let ip = addr.0.sin_addr.s_addr;
let [a, b, c, d] = ip.to_ne_bytes();
Ipv4Addr::new(a, b, c, d)
}
}
impl From<SockAddr> for sockaddr {
fn from(addr: SockAddr) -> sockaddr {
unsafe { mem::transmute(addr.0) }
}
}
impl From<SockAddr> for sockaddr_in {
fn from(addr: SockAddr) -> sockaddr_in {
addr.0
}
}

View File

@@ -1,167 +0,0 @@
use libloading::Library;
use std::ffi::{c_char, CStr, CString};
use std::fs::File;
use std::io::{self, Read, Seek};
use std::path::PathBuf;
use winapi::shared::minwindef::HINSTANCE;
use winapi::um::libloaderapi::{GetModuleFileNameA, GetModuleHandleA};
#[repr(C)]
#[derive(Debug)]
struct DosHeader {
e_magic: u16,
e_cblp: u16,
e_cp: u16,
e_crlc: u16,
e_cparhdr: u16,
e_minalloc: u16,
e_maxalloc: u16,
e_ss: u16,
e_sp: u16,
e_csum: u16,
e_ip: u16,
e_cs: u16,
e_lfarlc: u16,
e_ovno: u16,
e_res: [u16; 4],
e_oemid: u16,
e_oeminfo: u16,
e_res2: [u16; 10],
e_lfanew: i32,
}
#[repr(C)]
#[derive(Debug)]
struct FileHeader {
machine: u16,
number_of_sections: u16,
time_date_stamp: u32,
pointer_to_symbol_table: u32,
number_of_symbols: u32,
size_of_optional_header: u16,
characteristics: u16,
}
const IMAGE_FILE_MACHINE_I386: u16 = 0x014C;
const IMAGE_FILE_MACHINE_AMD64: u16 = 0x8664;
const IMAGE_FILE_MACHINE_ARM: u16 = 0x01C4;
const IMAGE_FILE_MACHINE_ARM64: u16 = 0xAA64;
fn get_dll_path(dll_name: &str) -> Result<PathBuf, String> {
unsafe {
// 使用libloading加载DLL
// 转换DLL名称为C字符串
let dll_name_c =
CString::new(dll_name).map_err(|e| format!("Failed to convert to CString: {}", e))?;
// 获取DLL的模块句柄
let h_instance: HINSTANCE = GetModuleHandleA(dll_name_c.as_ptr() as *const c_char);
if h_instance.is_null() {
return Err("Failed to get module handle".to_string());
}
// 获取DLL文件路径
let mut buffer: [c_char; 260] = [0; 260];
let length = GetModuleFileNameA(h_instance, buffer.as_mut_ptr(), buffer.len() as u32);
if length == 0 {
return Err("Failed to get module file name".to_string());
}
let path = CStr::from_ptr(buffer.as_ptr());
let path_str = path
.to_str()
.map_err(|e| format!("Failed to convert to &str: {}", e))?;
Ok(PathBuf::from(path_str))
}
}
pub fn check_win_tun_dll() -> io::Result<()> {
let _lib = unsafe {
Library::new("wintun.dll").map_err(|_| {
io::Error::new(
io::ErrorKind::NotFound,
"wintun.dll not found,Please download https://www.wintun.net",
)
})
};
match get_dll_path("wintun.dll") {
Ok(path) => match_platform(path),
Err(e) => {
// 能加载说明存在wintun这里获取不到路径是代码的问题
log::info!("{:?}", e);
Ok(())
}
}
}
fn match_platform(path: PathBuf) -> io::Result<()> {
let current_arch = if cfg!(target_arch = "x86") {
"x86"
} else if cfg!(target_arch = "x86_64") {
"AMD64"
} else if cfg!(target_arch = "arm") {
"ARM"
} else if cfg!(target_arch = "aarch64") {
"ARM64"
} else {
return Ok(());
};
let mut file = File::open(&path)?;
// 读取 DOS 头部
let mut dos_header = [0u8; std::mem::size_of::<DosHeader>()];
file.read_exact(&mut dos_header)?;
let dos_header: DosHeader = unsafe { std::ptr::read(dos_header.as_ptr() as *const _) };
if dos_header.e_magic != 0x5A4D {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("Not a valid PE file {:?}", path),
));
}
// 跳转到 PE 头部
file.seek(io::SeekFrom::Start(dos_header.e_lfanew as u64))?;
// 读取 PE 头部
let mut pe_signature = [0u8; 4];
file.read_exact(&mut pe_signature)?;
if &pe_signature != b"PE\0\0" {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("Not a valid PE file {:?}", path),
));
}
// 读取文件头部
let mut file_header = [0u8; std::mem::size_of::<FileHeader>()];
file.read_exact(&mut file_header)?;
let file_header: FileHeader = unsafe { std::ptr::read(file_header.as_ptr() as *const _) };
let dll_arch = match file_header.machine {
IMAGE_FILE_MACHINE_I386 => "x86",
IMAGE_FILE_MACHINE_AMD64 => "AMD64",
IMAGE_FILE_MACHINE_ARM => "ARM",
IMAGE_FILE_MACHINE_ARM64 => "ARM64",
_ => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("Unknown machine type: {}", file_header.machine),
))
}
};
if dll_arch != current_arch {
return Err(io::Error::new(
io::ErrorKind::Other,
format!(
"wintun.dll architecture ({}) does not match the current platform architecture ({}).",
dll_arch, current_arch
),
));
}
Ok(())
}

View File

@@ -1,94 +0,0 @@
use crate::device::IFace;
use crate::windows::{tap, tun};
use std::io;
use std::net::Ipv4Addr;
pub enum Device {
Tap(tap::Device),
Tun(tun::Device),
}
impl Device {
pub fn new(name: String, tap: bool) -> io::Result<Self> {
if tap {
Ok(Device::Tap(tap::Device::new(name)?))
} else {
Ok(Device::Tun(tun::Device::new(name)?))
}
}
pub fn check_tun_dll() -> io::Result<()> {
crate::windows::check::check_win_tun_dll()
}
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
match self {
Device::Tap(dev) => dev.version(),
Device::Tun(dev) => dev.version(),
}
}
fn name(&self) -> io::Result<String> {
match self {
Device::Tap(dev) => dev.name(),
Device::Tun(dev) => dev.name(),
}
}
fn shutdown(&self) -> io::Result<()> {
match self {
Device::Tap(dev) => dev.shutdown(),
Device::Tun(dev) => dev.shutdown(),
}
}
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
match self {
Device::Tap(dev) => dev.set_ip(address, mask),
Device::Tun(dev) => dev.set_ip(address, mask),
}
}
fn mtu(&self) -> io::Result<u32> {
match self {
Device::Tap(dev) => dev.mtu(),
Device::Tun(dev) => dev.mtu(),
}
}
fn set_mtu(&self, value: u32) -> io::Result<()> {
match self {
Device::Tap(dev) => dev.set_mtu(value),
Device::Tun(dev) => dev.set_mtu(value),
}
}
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> {
match self {
Device::Tap(dev) => dev.add_route(dest, netmask, metric),
Device::Tun(dev) => dev.add_route(dest, netmask, metric),
}
}
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
match self {
Device::Tap(dev) => dev.delete_route(dest, netmask),
Device::Tun(dev) => dev.delete_route(dest, netmask),
}
}
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
match self {
Device::Tap(dev) => dev.read(buf),
Device::Tun(dev) => dev.read(buf),
}
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
match self {
Device::Tap(dev) => dev.write(buf),
Device::Tun(dev) => dev.write(buf),
}
}
}

View File

@@ -1,502 +0,0 @@
// Many things will be used in the future
#![allow(unused)]
//! Module holding safe wrappers over winapi functions
use winapi::shared::basetsd::*;
use winapi::shared::guiddef::GUID;
use winapi::shared::ifdef::*;
use winapi::shared::minwindef::*;
use winapi::shared::netioapi::*;
use winapi::shared::winerror::*;
use winapi::um::combaseapi::*;
use winapi::um::errhandlingapi::*;
use winapi::um::fileapi::*;
use winapi::um::handleapi::*;
use winapi::um::ioapiset::*;
use winapi::um::setupapi::*;
use winapi::um::synchapi::*;
use winapi::um::winioctl::*;
use winapi::um::winnt::*;
use winapi::um::winreg::*;
use std::error::Error;
use std::{io, mem, ptr};
use winapi::um::minwinbase::OVERLAPPED_u;
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[repr(C)]
#[derive(Clone, Copy)]
/// Custom type to handle variable size SP_DRVINFO_DETAIL_DATA_W
pub struct SP_DRVINFO_DETAIL_DATA_W2 {
pub cbSize: DWORD,
pub InfDate: FILETIME,
pub CompatIDsOffset: DWORD,
pub CompatIDsLength: DWORD,
pub Reserved: ULONG_PTR,
pub SectionName: [WCHAR; 256],
pub InfFileName: [WCHAR; 260],
pub DrvDescription: [WCHAR; 256],
pub HardwareID: [WCHAR; 512],
}
pub fn string_from_guid(guid: &GUID) -> io::Result<Vec<WCHAR>> {
// GUID_STRING_CHARACTERS + 1
let mut string = vec![0; 39];
match unsafe { StringFromGUID2(guid, string.as_mut_ptr(), string.len() as _) } {
0 => Err(io::Error::new(io::ErrorKind::Other, "Insufficent buffer")),
_ => Ok(string),
}
}
pub fn alias_to_luid(alias: &[WCHAR]) -> io::Result<NET_LUID> {
let mut luid = unsafe { mem::zeroed() };
match unsafe { ConvertInterfaceAliasToLuid(alias.as_ptr(), &mut luid) } {
0 => Ok(luid),
err => Err(io::Error::from_raw_os_error(err as _)),
}
}
pub fn luid_to_index(luid: &NET_LUID) -> io::Result<NET_IFINDEX> {
let mut index = 0;
match unsafe { ConvertInterfaceLuidToIndex(luid, &mut index) } {
0 => Ok(index),
err => Err(io::Error::from_raw_os_error(err as _)),
}
}
pub fn luid_to_guid(luid: &NET_LUID) -> io::Result<GUID> {
let mut guid = unsafe { mem::zeroed() };
match unsafe { ConvertInterfaceLuidToGuid(luid, &mut guid) } {
0 => Ok(guid),
err => Err(io::Error::from_raw_os_error(err as _)),
}
}
pub fn luid_to_alias(luid: &NET_LUID) -> io::Result<Vec<WCHAR>> {
// IF_MAX_STRING_SIZE + 1
let mut alias = vec![0; 257];
match unsafe { ConvertInterfaceLuidToAlias(luid, alias.as_mut_ptr(), alias.len()) } {
0 => Ok(alias),
err => Err(io::Error::from_raw_os_error(err as _)),
}
}
pub fn close_handle(handle: HANDLE) -> io::Result<()> {
match unsafe { CloseHandle(handle) } {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn create_file(
file_name: &[WCHAR],
desired_access: DWORD,
share_mode: DWORD,
creation_disposition: DWORD,
flags_and_attributes: DWORD,
) -> io::Result<HANDLE> {
match unsafe {
CreateFileW(
file_name.as_ptr(),
desired_access,
share_mode,
ptr::null_mut(),
creation_disposition,
flags_and_attributes,
ptr::null_mut(),
)
} {
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
handle => Ok(handle),
}
}
pub fn read_file(handle: HANDLE, buffer: &mut [u8]) -> io::Result<DWORD> {
let mut ret = 0;
//https://www.cnblogs.com/linyilong3/archive/2012/05/03/2480451.html
unsafe {
let mut ip_overlapped = winapi::um::minwinbase::OVERLAPPED {
Internal: 0,
InternalHigh: 0,
u: Default::default(),
hEvent: ptr::null_mut(),
};
if 0 == ReadFile(
handle,
buffer.as_mut_ptr() as _,
buffer.len() as _,
&mut ret,
&mut ip_overlapped,
) {
let e = io::Error::last_os_error();
if e.raw_os_error().unwrap_or(0) == ERROR_IO_PENDING as _ {
if 0 == GetOverlappedResult(handle, &mut ip_overlapped, &mut ret, 1) {
return Err(e);
}
} else {
return Err(e);
}
}
Ok(ret)
}
}
pub fn write_file(handle: HANDLE, buffer: &[u8]) -> io::Result<DWORD> {
let mut ret = 0;
let mut ip_overlapped = winapi::um::minwinbase::OVERLAPPED {
Internal: 0,
InternalHigh: 0,
u: Default::default(),
hEvent: ptr::null_mut(),
};
unsafe {
if 0 == WriteFile(
handle,
buffer.as_ptr() as _,
buffer.len() as _,
&mut ret,
&mut ip_overlapped,
) {
let e = io::Error::last_os_error();
if e.raw_os_error().unwrap_or(0) == ERROR_IO_PENDING as _ {
if 0 == GetOverlappedResult(handle, &mut ip_overlapped, &mut ret, 1) {
return Err(e);
}
} else {
return Err(e);
}
}
Ok(ret)
}
}
pub fn create_device_info_list(guid: &GUID) -> io::Result<HDEVINFO> {
match unsafe { SetupDiCreateDeviceInfoList(guid, ptr::null_mut()) } {
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
devinfo => Ok(devinfo),
}
}
pub fn get_class_devs(guid: &GUID, flags: DWORD) -> io::Result<HDEVINFO> {
match unsafe { SetupDiGetClassDevsW(guid, ptr::null(), ptr::null_mut(), flags) } {
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
devinfo => Ok(devinfo),
}
}
pub fn destroy_device_info_list(devinfo: HDEVINFO) -> io::Result<()> {
match unsafe { SetupDiDestroyDeviceInfoList(devinfo) } {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn class_name_from_guid(guid: &GUID) -> io::Result<Vec<WCHAR>> {
let mut class_name = vec![0; 32];
match unsafe {
SetupDiClassNameFromGuidW(
guid,
class_name.as_mut_ptr(),
class_name.len() as _,
ptr::null_mut(),
)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(class_name),
}
}
pub fn create_device_info(
devinfo: HDEVINFO,
device_name: &[WCHAR],
guid: &GUID,
device_description: &[WCHAR],
creation_flags: DWORD,
) -> io::Result<SP_DEVINFO_DATA> {
let mut devinfo_data: SP_DEVINFO_DATA = unsafe { mem::zeroed() };
devinfo_data.cbSize = mem::size_of_val(&devinfo_data) as _;
match unsafe {
SetupDiCreateDeviceInfoW(
devinfo,
device_name.as_ptr(),
guid,
device_description.as_ptr(),
ptr::null_mut(),
creation_flags,
&mut devinfo_data,
)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(devinfo_data),
}
}
pub fn set_selected_device(devinfo: HDEVINFO, devinfo_data: &SP_DEVINFO_DATA) -> io::Result<()> {
match unsafe { SetupDiSetSelectedDevice(devinfo, devinfo_data as *const _ as _) } {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn set_device_registry_property(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
property: DWORD,
value: &[WCHAR],
) -> io::Result<()> {
match unsafe {
SetupDiSetDeviceRegistryPropertyW(
devinfo,
devinfo_data as *const _ as _,
property,
value.as_ptr() as _,
(value.len() * 2) as _,
)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn get_device_registry_property(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
property: DWORD,
) -> io::Result<Vec<WCHAR>> {
let mut value = vec![0; 32];
match unsafe {
SetupDiGetDeviceRegistryPropertyW(
devinfo,
devinfo_data as *const _ as _,
property,
ptr::null_mut(),
value.as_mut_ptr() as _,
(value.len() * 2) as _,
ptr::null_mut(),
)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(value),
}
}
pub fn build_driver_info_list(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
driver_type: DWORD,
) -> io::Result<()> {
match unsafe { SetupDiBuildDriverInfoList(devinfo, devinfo_data as *const _ as _, driver_type) }
{
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn destroy_driver_info_list(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
driver_type: DWORD,
) -> io::Result<()> {
match unsafe {
SetupDiDestroyDriverInfoList(devinfo, devinfo_data as *const _ as _, driver_type)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn get_driver_info_detail(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
drvinfo_data: &SP_DRVINFO_DATA_W,
) -> io::Result<SP_DRVINFO_DETAIL_DATA_W2> {
let mut drvinfo_detail: SP_DRVINFO_DETAIL_DATA_W2 = unsafe { mem::zeroed() };
drvinfo_detail.cbSize = mem::size_of::<SP_DRVINFO_DETAIL_DATA_W>() as _;
match unsafe {
SetupDiGetDriverInfoDetailW(
devinfo,
devinfo_data as *const _ as _,
drvinfo_data as *const _ as _,
&mut drvinfo_detail as *mut _ as _,
mem::size_of_val(&drvinfo_detail) as _,
ptr::null_mut(),
)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(drvinfo_detail),
}
}
pub fn set_selected_driver(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
drvinfo_data: &SP_DRVINFO_DATA_W,
) -> io::Result<()> {
match unsafe {
SetupDiSetSelectedDriverW(
devinfo,
devinfo_data as *const _ as _,
drvinfo_data as *const _ as _,
)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn set_class_install_params(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
params: &impl Copy,
) -> io::Result<()> {
match unsafe {
SetupDiSetClassInstallParamsW(
devinfo,
devinfo_data as *const _ as _,
params as *const _ as _,
mem::size_of_val(params) as _,
)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn call_class_installer(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
install_function: DI_FUNCTION,
) -> io::Result<()> {
match unsafe {
SetupDiCallClassInstaller(install_function, devinfo, devinfo_data as *const _ as _)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn open_dev_reg_key(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
scope: DWORD,
hw_profile: DWORD,
key_type: DWORD,
sam_desired: REGSAM,
) -> io::Result<HKEY> {
const INVALID_KEY_VALUE: HKEY = INVALID_HANDLE_VALUE as _;
match unsafe {
SetupDiOpenDevRegKey(
devinfo,
devinfo_data as *const _ as _,
scope,
hw_profile,
key_type,
sam_desired,
)
} {
INVALID_KEY_VALUE => Err(io::Error::last_os_error()),
key => Ok(key),
}
}
pub fn notify_change_key_value(
key: HKEY,
watch_subtree: BOOL,
notify_filter: DWORD,
milliseconds: DWORD,
) -> io::Result<()> {
let event = match unsafe { CreateEventW(ptr::null_mut(), FALSE, FALSE, ptr::null()) } {
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
event => Ok(event),
}?;
match unsafe { RegNotifyChangeKeyValue(key, watch_subtree, notify_filter, event, TRUE) } {
0 => Ok(()),
err => Err(io::Error::from_raw_os_error(err)),
}?;
match unsafe { WaitForSingleObject(event, milliseconds) } {
0 => Ok(()),
0x102 => Err(io::Error::new(
io::ErrorKind::TimedOut,
"Registry timed out",
)),
_ => Err(io::Error::last_os_error()),
}
}
pub fn enum_driver_info(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
driver_type: DWORD,
member_index: DWORD,
) -> Option<io::Result<SP_DRVINFO_DATA_W>> {
let mut drvinfo_data: SP_DRVINFO_DATA_W = unsafe { mem::zeroed() };
drvinfo_data.cbSize = mem::size_of_val(&drvinfo_data) as _;
match unsafe {
SetupDiEnumDriverInfoW(
devinfo,
devinfo_data as *const _ as _,
driver_type,
member_index,
&mut drvinfo_data,
)
} {
0 if unsafe { GetLastError() == ERROR_NO_MORE_ITEMS } => None,
0 => Some(Err(io::Error::last_os_error())),
_ => Some(Ok(drvinfo_data)),
}
}
pub fn enum_device_info(
devinfo: HDEVINFO,
member_index: DWORD,
) -> Option<io::Result<SP_DEVINFO_DATA>> {
let mut devinfo_data: SP_DEVINFO_DATA = unsafe { mem::zeroed() };
devinfo_data.cbSize = mem::size_of_val(&devinfo_data) as _;
match unsafe { SetupDiEnumDeviceInfo(devinfo, member_index, &mut devinfo_data) } {
0 if unsafe { GetLastError() == ERROR_NO_MORE_ITEMS } => None,
0 => Some(Err(io::Error::last_os_error())),
_ => Some(Ok(devinfo_data)),
}
}
pub fn device_io_control(
handle: HANDLE,
io_control_code: DWORD,
in_buffer: &impl Copy,
out_buffer: &mut impl Copy,
) -> io::Result<()> {
let mut junk = 0;
match unsafe {
DeviceIoControl(
handle,
io_control_code,
in_buffer as *const _ as _,
mem::size_of_val(in_buffer) as _,
out_buffer as *mut _ as _,
mem::size_of_val(out_buffer) as _,
&mut junk,
ptr::null_mut(),
)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}

View File

@@ -1,44 +0,0 @@
use std::io;
use std::os::windows::process::CommandExt;
use winapi::shared::minwindef::DWORD;
use winapi::um::winbase::CREATE_NO_WINDOW;
mod check;
mod device;
mod ffi;
mod netsh;
mod route;
mod tap;
mod tun;
pub use device::Device;
/// Encode a string as a utf16 buffer
pub fn encode_utf16(string: &str) -> Vec<u16> {
use std::iter::once;
string.encode_utf16().chain(once(0)).collect()
}
pub fn decode_utf16(string: &[u16]) -> String {
let end = string.iter().position(|b| *b == 0).unwrap_or(string.len());
String::from_utf16_lossy(&string[..end])
}
pub const fn ctl_code(device_type: DWORD, function: DWORD, method: DWORD, access: DWORD) -> DWORD {
(device_type << 16) | (access << 14) | (function << 2) | method
}
pub fn exe_cmd(cmd: &str) -> io::Result<()> {
println!("exe cmd: {}", cmd);
let out = std::process::Command::new("cmd")
.creation_flags(CREATE_NO_WINDOW)
.arg("/C")
.arg(&cmd)
.output()?;
if !out.status.success() {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("cmd={},out={:?}", cmd, String::from_utf8(out.stderr)),
));
}
Ok(())
}

View File

@@ -1,48 +0,0 @@
#![allow(dead_code)]
use crate::windows::exe_cmd;
use std::io;
use std::net::Ipv4Addr;
/// 设置网卡名称
pub fn set_interface_name(old_name: &str, new_name: &str) -> io::Result<()> {
let cmd = format!(
" netsh interface set interface name={:?} newname={:?}",
old_name, new_name
);
exe_cmd(&cmd)
}
/// 删除缓存
pub fn delete_cache() -> io::Result<()> {
//清除缓存
let cmd = "netsh interface ip delete destinationcache";
exe_cmd(cmd)
}
/// 设置网卡ip
pub fn set_interface_ip(index: u32, address: &Ipv4Addr, netmask: &Ipv4Addr) -> io::Result<()> {
let cmd = format!(
"netsh interface ip set address {} static {:?} {:?} ",
index, address, netmask,
);
exe_cmd(&cmd)
}
pub fn set_interface_mtu(index: u32, mtu: u32) -> io::Result<()> {
let cmd = format!(
"netsh interface ipv4 set subinterface {} mtu={} store=persistent",
index, mtu
);
exe_cmd(&cmd)
}
pub fn set_interface_metric(index: u32, metric: u16) -> io::Result<()> {
let cmd = format!(
"netsh interface ip set interface {} metric={}",
index, metric
);
exe_cmd(&cmd)
}
/// 禁用ipv6
pub fn disabled_ipv6(index: u32) -> io::Result<()> {
let cmd = format!("netsh interface ipv6 set interface {} disabled", index);
exe_cmd(&cmd)
}

View File

@@ -1,33 +0,0 @@
use std::io;
use std::net::Ipv4Addr;
use crate::windows::exe_cmd;
/// 添加路由
pub fn add_route(
index: u32,
dest: Ipv4Addr,
netmask: Ipv4Addr,
gateway: Ipv4Addr,
metric: u16,
) -> io::Result<()> {
let cmd = format!(
"route add {:?} mask {:?} {:?} metric {} if {}",
dest, netmask, gateway, metric, index
);
exe_cmd(&cmd)
}
/// 删除路由
pub fn delete_route(
index: u32,
dest: Ipv4Addr,
netmask: Ipv4Addr,
gateway: Ipv4Addr,
) -> io::Result<()> {
let cmd = format!(
"route delete {:?} mask {:?} {:?} if {}",
dest, netmask, gateway, index
);
exe_cmd(&cmd)
}

View File

@@ -1,185 +0,0 @@
#![allow(dead_code)]
use std::io;
use std::net::Ipv4Addr;
use winapi::shared::ifdef::NET_LUID;
use winapi::shared::minwindef::DWORD;
use winapi::um::fileapi::OPEN_EXISTING;
use winapi::um::winbase::FILE_FLAG_OVERLAPPED;
use winapi::um::winioctl::{FILE_ANY_ACCESS, FILE_DEVICE_UNKNOWN, METHOD_BUFFERED};
use winapi::um::winnt::{
FILE_ATTRIBUTE_SYSTEM, FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE, HANDLE,
};
use crate::device::IFace;
use crate::packet;
use crate::windows::{ctl_code, decode_utf16, encode_utf16, ffi, netsh, route};
/* Present in 8.1 */
const TAP_WIN_IOCTL_GET_MAC: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 1, METHOD_BUFFERED, FILE_ANY_ACCESS);
const TAP_WIN_IOCTL_GET_VERSION: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 2, METHOD_BUFFERED, FILE_ANY_ACCESS);
const TAP_WIN_IOCTL_GET_MTU: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 3, METHOD_BUFFERED, FILE_ANY_ACCESS);
const TAP_WIN_IOCTL_GET_INFO: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 4, METHOD_BUFFERED, FILE_ANY_ACCESS);
const TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 5, METHOD_BUFFERED, FILE_ANY_ACCESS);
const TAP_WIN_IOCTL_SET_MEDIA_STATUS: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 6, METHOD_BUFFERED, FILE_ANY_ACCESS);
const TAP_WIN_IOCTL_CONFIG_DHCP_MASQ: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 7, METHOD_BUFFERED, FILE_ANY_ACCESS);
const TAP_WIN_IOCTL_GET_LOG_LINE: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 8, METHOD_BUFFERED, FILE_ANY_ACCESS);
const TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 9, METHOD_BUFFERED, FILE_ANY_ACCESS);
/* Added in 8.2 */
/* obsoletes TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT */
const TAP_WIN_IOCTL_CONFIG_TUN: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 10, METHOD_BUFFERED, FILE_ANY_ACCESS);
pub struct Device {
handle: HANDLE,
index: u32,
luid: NET_LUID,
mac: [u8; 6],
}
unsafe impl Send for Device {}
unsafe impl Sync for Device {}
impl Device {
/// 打开设备设置为TUN模式激活网卡
pub fn new(name: String) -> io::Result<Self> {
let luid = ffi::alias_to_luid(&encode_utf16(&name)).map_err(|e| {
io::Error::new(e.kind(), format!("alias_to_luid name={},err={:?}", name, e))
})?;
let guid = ffi::luid_to_guid(&luid)
.and_then(|guid| ffi::string_from_guid(&guid))
.map_err(|e| {
io::Error::new(e.kind(), format!("luid_to_guid name={},err={:?}", name, e))
})?;
let path = format!(r"\\.\Global\{}.tap", decode_utf16(&guid));
let handle = ffi::create_file(
&encode_utf16(&path),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
)
.map_err(|e| io::Error::new(e.kind(), format!("tap name={},err={:?}", name, e)))?;
// ep保存tun网卡的IP地址和掩码
// let mut ep = [0;3];
// ep[0] = Ipv4Addr::new(10,26,0,11).into();
// ep[2] = Ipv4Addr::new(255,255,255,0).into();;
// ep[1] = ep[0] & ep[2];
// //tun模式收不到ipv4包原因未知 https://github.com/OpenVPN/tap-windows6/issues/111
// ffi::device_io_control(handle, TAP_WIN_IOCTL_CONFIG_TUN, &ep, &mut ()).map_err(
// |e| {
// io::Error::new(
// e.kind(),
// format!("TAP_WIN_IOCTL_CONFIG_TUN name={},err={:?}", name_str, e),
// )
// },
// )?;
let mut mac = [0u8; 6];
ffi::device_io_control(handle, TAP_WIN_IOCTL_GET_MAC, &(), &mut mac)
.map_err(|e| {
io::Error::new(
e.kind(),
format!("TAP_WIN_IOCTL_CONFIG_TUN name={},err={:?}", name, e),
)
})
.map_err(|e| io::Error::new(e.kind(), format!("TAP_WIN_IOCTL_GET_MAC,err={:?}", e)))?;
let index = ffi::luid_to_index(&luid).map(|index| index as u32)?;
// 设置网卡跃点
if let Err(e) = netsh::set_interface_metric(index, 0) {
log::warn!("{:?}", e);
}
let device = Self {
handle,
index,
luid,
mac,
};
device.enabled(true)?;
Ok(device)
}
fn write_tap(&self, buf: &[u8]) -> io::Result<usize> {
ffi::write_file(self.handle, buf).map(|res| res as _)
}
fn enabled(&self, value: bool) -> io::Result<()> {
let status: u32 = if value { 1 } else { 0 };
ffi::device_io_control(
self.handle,
TAP_WIN_IOCTL_SET_MEDIA_STATUS,
&status,
&mut (),
)
}
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
let mut version = [0u32; 3];
ffi::device_io_control(self.handle, TAP_WIN_IOCTL_GET_VERSION, &(), &mut version)?;
Ok(format!("{}.{}.{}", version[0], version[1], version[2]))
}
fn name(&self) -> io::Result<String> {
ffi::luid_to_alias(&self.luid).map(|name| decode_utf16(&name))
}
fn shutdown(&self) -> io::Result<()> {
self.enabled(false)
}
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
netsh::set_interface_ip(self.index, &address, &mask)
}
fn mtu(&self) -> io::Result<u32> {
let mut mtu = 0;
ffi::device_io_control(self.handle, TAP_WIN_IOCTL_GET_MTU, &(), &mut mtu).map(|_| mtu)
}
fn set_mtu(&self, value: u32) -> io::Result<()> {
netsh::set_interface_mtu(self.index, value)
}
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> {
route::add_route(self.index, dest, netmask, Ipv4Addr::UNSPECIFIED, metric)?;
netsh::delete_cache()
}
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
route::delete_route(self.index, dest, netmask, Ipv4Addr::UNSPECIFIED)?;
netsh::delete_cache()
}
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
packet::read_tap(
buf,
|eth_buf| ffi::read_file(self.handle, eth_buf).map(|res| res as usize),
|eth_buf| ffi::write_file(self.handle, eth_buf).map(|res| res as _),
)
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
// 封装二层数据
packet::write_tap(
buf,
|eth_buf| ffi::write_file(self.handle, eth_buf).map(|res| res as _),
&self.mac,
)
}
}
impl Drop for Device {
fn drop(&mut self) {
if let Err(e) = ffi::close_handle(self.handle) {
log::warn!("close_handle={:?}", e)
}
}
}

View File

@@ -1,363 +0,0 @@
#![allow(dead_code)]
use libloading::Library;
use sha2::Digest;
use std::io;
use std::net::Ipv4Addr;
use winapi::um::winbase;
use winapi::um::{synchapi, winnt};
use crate::device::IFace;
use crate::windows::decode_utf16;
use crate::windows::{encode_utf16, ffi, netsh, route};
mod packet;
mod wintun_log;
mod wintun_raw;
/// The maximum size of wintun's internal ring buffer (in bytes)
pub const MAX_RING_CAPACITY: u32 = 0x400_0000;
/// The minimum size of wintun's internal ring buffer (in bytes)
pub const MIN_RING_CAPACITY: u32 = 0x2_0000;
/// Maximum pool name length including zero terminator
pub const MAX_POOL: usize = 256;
pub struct Device {
pub(crate) luid: u64,
pub(crate) index: u32,
/// The session handle given to us by WintunStartSession
pub(crate) session: wintun_raw::WINTUN_SESSION_HANDLE,
/// Shared dll for required wintun driver functions
pub(crate) win_tun: wintun_raw::wintun,
/// Windows event handle that is signaled by the wintun driver when data becomes available to
/// read
pub(crate) read_event: winnt::HANDLE,
/// Windows event handle that is signaled when [`TunSession::shutdown`] is called force blocking
/// readers to exit
pub(crate) shutdown_event: winnt::HANDLE,
/// The adapter that owns this session
pub(crate) adapter: wintun_raw::WINTUN_ADAPTER_HANDLE,
}
unsafe impl Send for Device {}
unsafe impl Sync for Device {}
impl Device {
pub fn new(name: String) -> io::Result<Self> {
unsafe {
let library = match Library::new("wintun.dll") {
Ok(library) => library,
Err(e) => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("wintun.dll not found {:?}", e),
));
}
};
let win_tun = match wintun_raw::wintun::from_library(library) {
Ok(win_tun) => win_tun,
Err(e) => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("library error {:?} ", e),
));
}
};
let name_utf16 = encode_utf16(&name);
if name_utf16.len() > MAX_POOL {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("too long {}:{:?}", MAX_POOL, name),
));
}
wintun_log::set_default_logger_if_unset(&win_tun);
if Self::delete_for_name(&win_tun, &name_utf16).is_ok() {
std::thread::sleep(std::time::Duration::from_millis(500));
}
let guid_bytes: [u8; 16] = hash_guid(&name);
let guid = u128::from_ne_bytes(guid_bytes);
//SAFETY: guid is a unique integer so transmuting either all zeroes or the user's preferred
//guid to the winapi guid type is safe and will allow the windows kernel to see our GUID
let guid_struct: wintun_raw::GUID = std::mem::transmute(guid);
let guid_ptr = &guid_struct as *const wintun_raw::GUID;
//SAFETY: the function is loaded from the wintun dll properly, we are providing valid
//pointers, and all the strings are correct null terminated UTF-16. This safety rationale
//applies for all Wintun* functions below
let adapter =
win_tun.WintunCreateAdapter(name_utf16.as_ptr(), name_utf16.as_ptr(), guid_ptr);
if adapter.is_null() {
log::error!("adapter.is_null {:?}", io::Error::last_os_error());
return Err(io::Error::new(
io::ErrorKind::Other,
"Failed to crate adapter",
));
}
// 开启session
let session = win_tun.WintunStartSession(adapter, 4 * 1024 * 1024);
if session.is_null() {
log::error!("session.is_null {:?}", io::Error::last_os_error());
return Err(io::Error::new(
io::ErrorKind::Other,
"WintunStartSession failed",
));
}
//SAFETY: We follow the contract required by CreateEventA. See MSDN
//(the pointers are allowed to be null, and 0 is okay for the others)
let shutdown_event =
synchapi::CreateEventA(std::ptr::null_mut(), 0, 0, std::ptr::null_mut());
let read_event = win_tun.WintunGetReadWaitEvent(session) as winnt::HANDLE;
let mut luid: wintun_raw::NET_LUID = std::mem::zeroed();
win_tun.WintunGetAdapterLUID(adapter, &mut luid as *mut wintun_raw::NET_LUID);
let index = ffi::luid_to_index(&std::mem::transmute(luid)).map(|index| index as u32)?;
// 设置网卡跃点
if let Err(e) = netsh::set_interface_metric(index, 0) {
log::warn!("{:?}", e);
}
Ok(Self {
luid: std::mem::transmute(luid),
index,
session,
win_tun,
read_event,
shutdown_event,
adapter,
})
}
}
pub unsafe fn delete_for_name(
win_tun: &wintun_raw::wintun,
name_utf16: &Vec<u16>,
) -> io::Result<()> {
let adapter = win_tun.WintunOpenAdapter(name_utf16.as_ptr());
if adapter.is_null() {
log::error!(
"delete_for_name adapter.is_null {:?}",
io::Error::last_os_error()
);
return Err(io::Error::new(
io::ErrorKind::Other,
"Failed to open adapter",
));
}
win_tun.WintunCloseAdapter(adapter);
win_tun.WintunDeleteDriver();
Ok(())
}
}
fn hash_guid(input: &str) -> [u8; 16] {
let mut hasher = sha2::Sha256::new();
hasher.update(input.as_bytes());
hasher.update(b"VNT");
hasher.update(input.as_bytes());
hasher.update(b"2024");
let hash: [u8; 32] = hasher.finalize().into();
hash[..16].try_into().unwrap()
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
let version = unsafe { self.win_tun.WintunGetRunningDriverVersion() };
if version == 0 {
return Err(io::Error::new(
io::ErrorKind::Other,
"WintunGetRunningDriverVersion",
));
} else {
Ok(format!("{}.{}", (version >> 16) & 0xFFFF, version & 0xFFFF))
}
}
fn name(&self) -> io::Result<String> {
let luid = self.luid;
ffi::luid_to_alias(&unsafe { std::mem::transmute(luid) }).map(|name| decode_utf16(&name))
}
fn shutdown(&self) -> io::Result<()> {
unsafe {
if winapi::shared::minwindef::TRUE == synchapi::SetEvent(self.shutdown_event) {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
}
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
netsh::set_interface_ip(self.index, &address, &mask)
}
fn mtu(&self) -> io::Result<u32> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn set_mtu(&self, value: u32) -> io::Result<()> {
netsh::set_interface_mtu(self.index, value)
}
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> {
route::add_route(self.index, dest, netmask, Ipv4Addr::UNSPECIFIED, metric)?;
netsh::delete_cache()
}
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
route::delete_route(self.index, dest, netmask, Ipv4Addr::UNSPECIFIED)?;
netsh::delete_cache()
}
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let packet = self.receive_blocking()?;
let packet = packet.bytes();
let len = packet.len();
if len > buf.len() {
return Err(io::Error::new(io::ErrorKind::InvalidData, "data too long"));
}
buf[..len].copy_from_slice(packet);
Ok(len)
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
let mut packet = self.allocate_send_packet(buf.len() as u16)?;
packet.bytes_mut().copy_from_slice(buf);
self.send_packet(packet);
Ok(buf.len())
}
}
impl Device {
pub fn try_receive(&self) -> io::Result<Option<packet::TunPacket>> {
let mut size = 0u32;
let bytes_ptr = unsafe {
self.win_tun
.WintunReceivePacket(self.session, &mut size as *mut u32)
};
debug_assert!(size <= u16::MAX as u32);
if bytes_ptr.is_null() {
//Wintun returns ERROR_NO_MORE_ITEMS instead of blocking if packets are not available
let last_error = unsafe { winapi::um::errhandlingapi::GetLastError() };
if last_error == winapi::shared::winerror::ERROR_NO_MORE_ITEMS {
Ok(None)
} else {
Err(io::Error::new(
io::ErrorKind::Other,
format!("try_receive failed {:?}", io::Error::last_os_error()),
))
}
} else {
Ok(Some(packet::TunPacket {
kind: packet::Kind::ReceivePacket,
size: size as usize,
//SAFETY: ptr is non null, aligned for u8, and readable for up to size bytes (which
//must be less than isize::MAX because bytes is a u16
bytes_ptr,
tun_device: Some(&self),
}))
}
}
pub fn receive_blocking(&self) -> io::Result<packet::TunPacket> {
loop {
//Try 16 times to receive without blocking so we don't have to issue a syscall to wait
//for the event if packets are being received at a rapid rate
for i in 0..20 {
match self.try_receive() {
Ok(data) => match data {
None => {
continue;
}
Some(packet) => {
return Ok(packet);
}
},
Err(e) => {
if i > 10 {
// 某些系统存在错误退出的情况(原因不明),这里尝试忽略部分错误
return Err(e);
}
}
}
}
//Wait on both the read handle and the shutdown handle so that we stop when requested
let handles = [self.read_event, self.shutdown_event];
let result = unsafe {
//SAFETY: We abide by the requirements of WaitForMultipleObjects, handles is a
//pointer to valid, aligned, stack memory
synchapi::WaitForMultipleObjects(
2,
&handles as *const winnt::HANDLE,
0,
winbase::INFINITE,
)
};
match result {
winbase::WAIT_FAILED => {
return Err(io::Error::new(io::ErrorKind::Other, "WAIT_FAILED"));
}
_ => {
if result == winbase::WAIT_OBJECT_0 {
//We have data!
continue;
} else {
//Shutdown event triggered
return Err(io::Error::new(
io::ErrorKind::Other,
format!("Shutdown event triggered {}", io::Error::last_os_error()),
));
}
}
}
}
}
pub fn allocate_send_packet(&self, size: u16) -> io::Result<packet::TunPacket> {
let bytes_ptr = unsafe {
self.win_tun
.WintunAllocateSendPacket(self.session, size as u32)
};
if bytes_ptr.is_null() {
Err(io::Error::new(
io::ErrorKind::Other,
"allocate_send_packet failed",
))
} else {
Ok(packet::TunPacket {
kind: packet::Kind::SendPacketPending,
size: size as usize,
//SAFETY: ptr is non null, aligned for u8, and readable for up to size bytes (which
//must be less than isize::MAX because bytes is a u16
bytes_ptr,
tun_device: None,
})
}
}
pub fn send_packet(&self, mut packet: packet::TunPacket) {
assert!(matches!(packet.kind, packet::Kind::SendPacketPending));
unsafe {
self.win_tun
.WintunSendPacket(self.session, packet.bytes_ptr)
};
//Mark the packet at sent
packet.kind = packet::Kind::SendPacketSent;
}
}
impl Drop for Device {
fn drop(&mut self) {
unsafe {
if let Err(e) = ffi::close_handle(self.shutdown_event) {
log::warn!("close shutdown_event={:?}", e)
}
self.win_tun.WintunEndSession(self.session);
self.win_tun.WintunCloseAdapter(self.adapter);
if winapi::shared::minwindef::FALSE == self.win_tun.WintunDeleteDriver() {
log::warn!("WintunDeleteDriver failed {:?}", io::Error::last_os_error())
}
}
}
}

View File

@@ -1,64 +0,0 @@
use crate::windows::tun::Device;
pub(crate) enum Kind {
SendPacketPending,
//Send packet type, but not sent yet
SendPacketSent,
//Send packet type - sent
ReceivePacket,
}
/// Represents a wintun packet
pub struct TunPacket<'a> {
pub(crate) kind: Kind,
pub(crate) size: usize,
pub(crate) bytes_ptr: *const u8,
//Share ownership of session to prevent the session from being dropped before packets that
//belong to it
pub(crate) tun_device: Option<&'a Device>,
}
impl<'a> TunPacket<'a> {
/// Returns the bytes this packet holds as &mut.
/// The lifetime of the bytes is tied to the lifetime of this packet.
pub fn bytes_mut(&mut self) -> &mut [u8] {
unsafe { std::slice::from_raw_parts_mut(self.bytes_ptr as *mut u8, self.size) }
}
/// Returns an immutable reference to the bytes this packet holds.
/// The lifetime of the bytes is tied to the lifetime of this packet.
pub fn bytes(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.bytes_ptr, self.size) }
}
}
impl<'a> Drop for TunPacket<'a> {
fn drop(&mut self) {
match self.kind {
Kind::ReceivePacket => {
unsafe {
//SAFETY:
//
// 1. We share ownership of the session therefore it hasn't been dropped yet
// 2. Bytes is valid because each packet holds exclusive access to a region of the
// ring buffer that the wintun session owns. We return that region of
// memory back to wintun here
let tun_device = self.tun_device.unwrap();
tun_device
.win_tun
.WintunReleaseReceivePacket(tun_device.session, self.bytes_ptr)
};
}
Kind::SendPacketPending => {
//If someone allocates a packet with session.allocate_send_packet() and then it is
//dropped without being sent, this will hold up the send queue because wintun expects
//that every allocated packet is sent
panic!("Packet was never sent!");
}
Kind::SendPacketSent => {
//Nop
}
}
}
}

View File

@@ -1,48 +0,0 @@
#![allow(dead_code)]
use log::*;
use crate::windows::tun::wintun_raw;
use std::sync::atomic::{AtomicBool, Ordering};
use widestring::U16CStr;
/// Sets the logger wintun will use when logging. Maps to the WintunSetLogger C function
pub fn set_logger(win_tun: &wintun_raw::wintun, f: wintun_raw::WINTUN_LOGGER_CALLBACK) {
unsafe { win_tun.WintunSetLogger(f) };
}
pub fn reset_logger(win_tun: &wintun_raw::wintun) {
set_logger(win_tun, None);
}
static SET_LOGGER: AtomicBool = AtomicBool::new(false);
/// The logger that is active by default. Logs messages to the log crate
///
/// # Safety
/// `message` must be a valid pointer that points to an aligned null terminated UTF-16 string
pub unsafe extern "C" fn default_logger(
level: wintun_raw::WINTUN_LOGGER_LEVEL,
_timestamp: wintun_raw::DWORD64,
message: *const wintun_raw::WCHAR,
) {
//Cant wait for RFC 2585
#[allow(unused_unsafe)]
//Wintun will always give us a valid UTF16 null termineted string
let msg = unsafe { U16CStr::from_ptr_str(message) };
let utf8_msg = msg.to_string_lossy();
match level {
wintun_raw::WINTUN_LOGGER_LEVEL_WINTUN_LOG_INFO => info!("WinTun: {}", utf8_msg),
wintun_raw::WINTUN_LOGGER_LEVEL_WINTUN_LOG_WARN => warn!("WinTun: {}", utf8_msg),
wintun_raw::WINTUN_LOGGER_LEVEL_WINTUN_LOG_ERR => error!("WinTun: {}", utf8_msg),
_ => error!("WinTun: {} (with invalid log level {})", utf8_msg, level),
}
}
pub(crate) fn set_default_logger_if_unset(win_tun: &wintun_raw::wintun) {
if SET_LOGGER
.compare_exchange(false, true, Ordering::SeqCst, Ordering::Relaxed)
.is_ok()
{
set_logger(win_tun, Some(default_logger));
}
}

View File

@@ -1,449 +0,0 @@
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
/* automatically generated by rust-bindgen 0.59.1 */
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct __BindgenBitfieldUnit<Storage> {
storage: Storage,
}
impl<Storage> __BindgenBitfieldUnit<Storage> {
#[inline]
pub const fn new(storage: Storage) -> Self {
Self { storage }
}
}
impl<Storage> __BindgenBitfieldUnit<Storage>
where
Storage: AsRef<[u8]> + AsMut<[u8]>,
{
#[inline]
pub fn get_bit(&self, index: usize) -> bool {
debug_assert!(index / 8 < self.storage.as_ref().len());
let byte_index = index / 8;
let byte = self.storage.as_ref()[byte_index];
let bit_index = if cfg!(target_endian = "big") {
7 - (index % 8)
} else {
index % 8
};
let mask = 1 << bit_index;
byte & mask == mask
}
#[inline]
pub fn set_bit(&mut self, index: usize, val: bool) {
debug_assert!(index / 8 < self.storage.as_ref().len());
let byte_index = index / 8;
let byte = &mut self.storage.as_mut()[byte_index];
let bit_index = if cfg!(target_endian = "big") {
7 - (index % 8)
} else {
index % 8
};
let mask = 1 << bit_index;
if val {
*byte |= mask;
} else {
*byte &= !mask;
}
}
#[inline]
pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
debug_assert!(bit_width <= 64);
debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
let mut val = 0;
for i in 0..(bit_width as usize) {
if self.get_bit(i + bit_offset) {
let index = if cfg!(target_endian = "big") {
bit_width as usize - 1 - i
} else {
i
};
val |= 1 << index;
}
}
val
}
#[inline]
pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
debug_assert!(bit_width <= 64);
debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
for i in 0..(bit_width as usize) {
let mask = 1 << i;
let val_bit_is_set = val & mask == mask;
let index = if cfg!(target_endian = "big") {
bit_width as usize - 1 - i
} else {
i
};
self.set_bit(index + bit_offset, val_bit_is_set);
}
}
}
pub type wchar_t = ::std::os::raw::c_ushort;
pub type DWORD = ::std::os::raw::c_ulong;
pub type BOOL = ::std::os::raw::c_int;
pub type BYTE = ::std::os::raw::c_uchar;
pub type ULONG64 = ::std::os::raw::c_ulonglong;
pub type DWORD64 = ::std::os::raw::c_ulonglong;
pub type WCHAR = wchar_t;
pub type LPCWSTR = *const WCHAR;
pub type HANDLE = *mut ::std::os::raw::c_void;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _GUID {
pub Data1: ::std::os::raw::c_ulong,
pub Data2: ::std::os::raw::c_ushort,
pub Data3: ::std::os::raw::c_ushort,
pub Data4: [::std::os::raw::c_uchar; 8usize],
}
#[test]
fn bindgen_test_layout__GUID() {
assert_eq!(
::std::mem::size_of::<_GUID>(),
16usize,
concat!("Size of: ", stringify!(_GUID))
);
assert_eq!(
::std::mem::align_of::<_GUID>(),
4usize,
concat!("Alignment of ", stringify!(_GUID))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<_GUID>())).Data1 as *const _ as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(_GUID),
"::",
stringify!(Data1)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<_GUID>())).Data2 as *const _ as usize },
4usize,
concat!(
"Offset of field: ",
stringify!(_GUID),
"::",
stringify!(Data2)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<_GUID>())).Data3 as *const _ as usize },
6usize,
concat!(
"Offset of field: ",
stringify!(_GUID),
"::",
stringify!(Data3)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<_GUID>())).Data4 as *const _ as usize },
8usize,
concat!(
"Offset of field: ",
stringify!(_GUID),
"::",
stringify!(Data4)
)
);
}
pub type GUID = _GUID;
#[repr(C)]
#[derive(Copy, Clone)]
pub union _NET_LUID_LH {
pub Value: ULONG64,
pub Info: _NET_LUID_LH__bindgen_ty_1,
}
#[repr(C)]
#[repr(align(8))]
#[derive(Debug, Copy, Clone)]
pub struct _NET_LUID_LH__bindgen_ty_1 {
pub _bitfield_align_1: [u32; 0],
pub _bitfield_1: __BindgenBitfieldUnit<[u8; 8usize]>,
}
#[test]
fn bindgen_test_layout__NET_LUID_LH__bindgen_ty_1() {
assert_eq!(
::std::mem::size_of::<_NET_LUID_LH__bindgen_ty_1>(),
8usize,
concat!("Size of: ", stringify!(_NET_LUID_LH__bindgen_ty_1))
);
assert_eq!(
::std::mem::align_of::<_NET_LUID_LH__bindgen_ty_1>(),
8usize,
concat!("Alignment of ", stringify!(_NET_LUID_LH__bindgen_ty_1))
);
}
impl _NET_LUID_LH__bindgen_ty_1 {
#[inline]
pub fn Reserved(&self) -> ULONG64 {
unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 24u8) as u64) }
}
#[inline]
pub fn set_Reserved(&mut self, val: ULONG64) {
unsafe {
let val: u64 = ::std::mem::transmute(val);
self._bitfield_1.set(0usize, 24u8, val as u64)
}
}
#[inline]
pub fn NetLuidIndex(&self) -> ULONG64 {
unsafe { ::std::mem::transmute(self._bitfield_1.get(24usize, 24u8) as u64) }
}
#[inline]
pub fn set_NetLuidIndex(&mut self, val: ULONG64) {
unsafe {
let val: u64 = ::std::mem::transmute(val);
self._bitfield_1.set(24usize, 24u8, val as u64)
}
}
#[inline]
pub fn IfType(&self) -> ULONG64 {
unsafe { ::std::mem::transmute(self._bitfield_1.get(48usize, 16u8) as u64) }
}
#[inline]
pub fn set_IfType(&mut self, val: ULONG64) {
unsafe {
let val: u64 = ::std::mem::transmute(val);
self._bitfield_1.set(48usize, 16u8, val as u64)
}
}
#[inline]
pub fn new_bitfield_1(
Reserved: ULONG64,
NetLuidIndex: ULONG64,
IfType: ULONG64,
) -> __BindgenBitfieldUnit<[u8; 8usize]> {
let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 8usize]> = Default::default();
__bindgen_bitfield_unit.set(0usize, 24u8, {
let Reserved: u64 = unsafe { ::std::mem::transmute(Reserved) };
Reserved as u64
});
__bindgen_bitfield_unit.set(24usize, 24u8, {
let NetLuidIndex: u64 = unsafe { ::std::mem::transmute(NetLuidIndex) };
NetLuidIndex as u64
});
__bindgen_bitfield_unit.set(48usize, 16u8, {
let IfType: u64 = unsafe { ::std::mem::transmute(IfType) };
IfType as u64
});
__bindgen_bitfield_unit
}
}
#[test]
fn bindgen_test_layout__NET_LUID_LH() {
assert_eq!(
::std::mem::size_of::<_NET_LUID_LH>(),
8usize,
concat!("Size of: ", stringify!(_NET_LUID_LH))
);
assert_eq!(
::std::mem::align_of::<_NET_LUID_LH>(),
8usize,
concat!("Alignment of ", stringify!(_NET_LUID_LH))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<_NET_LUID_LH>())).Value as *const _ as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(_NET_LUID_LH),
"::",
stringify!(Value)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<_NET_LUID_LH>())).Info as *const _ as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(_NET_LUID_LH),
"::",
stringify!(Info)
)
);
}
pub type NET_LUID_LH = _NET_LUID_LH;
pub type NET_LUID = NET_LUID_LH;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _WINTUN_ADAPTER {
_unused: [u8; 0],
}
#[doc = " A handle representing Wintun adapter"]
pub type WINTUN_ADAPTER_HANDLE = *mut _WINTUN_ADAPTER;
#[doc = "< Informational"]
pub const WINTUN_LOGGER_LEVEL_WINTUN_LOG_INFO: WINTUN_LOGGER_LEVEL = 0;
#[doc = "< Warning"]
pub const WINTUN_LOGGER_LEVEL_WINTUN_LOG_WARN: WINTUN_LOGGER_LEVEL = 1;
#[doc = "< Error"]
pub const WINTUN_LOGGER_LEVEL_WINTUN_LOG_ERR: WINTUN_LOGGER_LEVEL = 2;
#[doc = " Determines the level of logging, passed to WINTUN_LOGGER_CALLBACK."]
pub type WINTUN_LOGGER_LEVEL = ::std::os::raw::c_int;
#[doc = " Called by internal logger to report diagnostic messages"]
#[doc = ""]
#[doc = " @param Level Message level."]
#[doc = ""]
#[doc = " @param Timestamp Message timestamp in in 100ns intervals since 1601-01-01 UTC."]
#[doc = ""]
#[doc = " @param Message Message text."]
pub type WINTUN_LOGGER_CALLBACK = ::std::option::Option<
unsafe extern "C" fn(Level: WINTUN_LOGGER_LEVEL, Timestamp: DWORD64, Message: LPCWSTR),
>;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _TUN_SESSION {
_unused: [u8; 0],
}
#[doc = " A handle representing Wintun session"]
pub type WINTUN_SESSION_HANDLE = *mut _TUN_SESSION;
extern crate libloading;
pub struct wintun {
__library: ::libloading::Library,
pub WintunCreateAdapter: unsafe extern "C" fn(
arg1: LPCWSTR,
arg2: LPCWSTR,
arg3: *const GUID,
) -> WINTUN_ADAPTER_HANDLE,
pub WintunCloseAdapter: unsafe extern "C" fn(arg1: WINTUN_ADAPTER_HANDLE),
pub WintunOpenAdapter: unsafe extern "C" fn(arg1: LPCWSTR) -> WINTUN_ADAPTER_HANDLE,
pub WintunGetAdapterLUID:
unsafe extern "C" fn(arg1: WINTUN_ADAPTER_HANDLE, arg2: *mut NET_LUID),
pub WintunGetRunningDriverVersion: unsafe extern "C" fn() -> DWORD,
pub WintunDeleteDriver: unsafe extern "C" fn() -> BOOL,
pub WintunSetLogger: unsafe extern "C" fn(arg1: WINTUN_LOGGER_CALLBACK),
pub WintunStartSession:
unsafe extern "C" fn(arg1: WINTUN_ADAPTER_HANDLE, arg2: DWORD) -> WINTUN_SESSION_HANDLE,
pub WintunEndSession: unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE),
pub WintunGetReadWaitEvent: unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE) -> HANDLE,
pub WintunReceivePacket:
unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: *mut DWORD) -> *mut BYTE,
pub WintunReleaseReceivePacket:
unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: *const BYTE),
pub WintunAllocateSendPacket:
unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: DWORD) -> *mut BYTE,
pub WintunSendPacket: unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: *const BYTE),
}
impl wintun {
pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error>
where
P: AsRef<::std::ffi::OsStr>,
{
let library = ::libloading::Library::new(path)?;
Self::from_library(library)
}
pub unsafe fn from_library<L>(library: L) -> Result<Self, ::libloading::Error>
where
L: Into<::libloading::Library>,
{
let __library = library.into();
let WintunCreateAdapter = __library.get(b"WintunCreateAdapter\0").map(|sym| *sym)?;
let WintunCloseAdapter = __library.get(b"WintunCloseAdapter\0").map(|sym| *sym)?;
let WintunOpenAdapter = __library.get(b"WintunOpenAdapter\0").map(|sym| *sym)?;
let WintunGetAdapterLUID = __library.get(b"WintunGetAdapterLUID\0").map(|sym| *sym)?;
let WintunGetRunningDriverVersion = __library
.get(b"WintunGetRunningDriverVersion\0")
.map(|sym| *sym)?;
let WintunDeleteDriver = __library.get(b"WintunDeleteDriver\0").map(|sym| *sym)?;
let WintunSetLogger = __library.get(b"WintunSetLogger\0").map(|sym| *sym)?;
let WintunStartSession = __library.get(b"WintunStartSession\0").map(|sym| *sym)?;
let WintunEndSession = __library.get(b"WintunEndSession\0").map(|sym| *sym)?;
let WintunGetReadWaitEvent = __library.get(b"WintunGetReadWaitEvent\0").map(|sym| *sym)?;
let WintunReceivePacket = __library.get(b"WintunReceivePacket\0").map(|sym| *sym)?;
let WintunReleaseReceivePacket = __library
.get(b"WintunReleaseReceivePacket\0")
.map(|sym| *sym)?;
let WintunAllocateSendPacket = __library
.get(b"WintunAllocateSendPacket\0")
.map(|sym| *sym)?;
let WintunSendPacket = __library.get(b"WintunSendPacket\0").map(|sym| *sym)?;
Ok(wintun {
__library,
WintunCreateAdapter,
WintunCloseAdapter,
WintunOpenAdapter,
WintunGetAdapterLUID,
WintunGetRunningDriverVersion,
WintunDeleteDriver,
WintunSetLogger,
WintunStartSession,
WintunEndSession,
WintunGetReadWaitEvent,
WintunReceivePacket,
WintunReleaseReceivePacket,
WintunAllocateSendPacket,
WintunSendPacket,
})
}
pub unsafe fn WintunCreateAdapter(
&self,
arg1: LPCWSTR,
arg2: LPCWSTR,
arg3: *const GUID,
) -> WINTUN_ADAPTER_HANDLE {
(self.WintunCreateAdapter)(arg1, arg2, arg3)
}
pub unsafe fn WintunCloseAdapter(&self, arg1: WINTUN_ADAPTER_HANDLE) -> () {
(self.WintunCloseAdapter)(arg1)
}
pub unsafe fn WintunOpenAdapter(&self, arg1: LPCWSTR) -> WINTUN_ADAPTER_HANDLE {
(self.WintunOpenAdapter)(arg1)
}
pub unsafe fn WintunGetAdapterLUID(
&self,
arg1: WINTUN_ADAPTER_HANDLE,
arg2: *mut NET_LUID,
) -> () {
(self.WintunGetAdapterLUID)(arg1, arg2)
}
pub unsafe fn WintunGetRunningDriverVersion(&self) -> DWORD {
(self.WintunGetRunningDriverVersion)()
}
pub unsafe fn WintunDeleteDriver(&self) -> BOOL {
(self.WintunDeleteDriver)()
}
pub unsafe fn WintunSetLogger(&self, arg1: WINTUN_LOGGER_CALLBACK) -> () {
(self.WintunSetLogger)(arg1)
}
pub unsafe fn WintunStartSession(
&self,
arg1: WINTUN_ADAPTER_HANDLE,
arg2: DWORD,
) -> WINTUN_SESSION_HANDLE {
(self.WintunStartSession)(arg1, arg2)
}
pub unsafe fn WintunEndSession(&self, arg1: WINTUN_SESSION_HANDLE) -> () {
(self.WintunEndSession)(arg1)
}
pub unsafe fn WintunGetReadWaitEvent(&self, arg1: WINTUN_SESSION_HANDLE) -> HANDLE {
(self.WintunGetReadWaitEvent)(arg1)
}
pub unsafe fn WintunReceivePacket(
&self,
arg1: WINTUN_SESSION_HANDLE,
arg2: *mut DWORD,
) -> *mut BYTE {
(self.WintunReceivePacket)(arg1, arg2)
}
pub unsafe fn WintunReleaseReceivePacket(
&self,
arg1: WINTUN_SESSION_HANDLE,
arg2: *const BYTE,
) -> () {
(self.WintunReleaseReceivePacket)(arg1, arg2)
}
pub unsafe fn WintunAllocateSendPacket(
&self,
arg1: WINTUN_SESSION_HANDLE,
arg2: DWORD,
) -> *mut BYTE {
(self.WintunAllocateSendPacket)(arg1, arg2)
}
pub unsafe fn WintunSendPacket(&self, arg1: WINTUN_SESSION_HANDLE, arg2: *const BYTE) -> () {
(self.WintunSendPacket)(arg1, arg2)
}
}