IfConfigBuilder {
28 | /// Platform-specific settings
29 | pub fn platform(&mut self, f: F) -> Result<&mut Self, E>
30 | where
31 | F: Fn(P::Builder) -> Result,
32 | {
33 | let builder = P::Builder::default();
34 | self.platform = Some(f(builder)?);
35 | Ok(self)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Alexander Shishenko
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/examples/simple_std.rs:
--------------------------------------------------------------------------------
1 | use std::io::{Read, Write};
2 | use tunio::traits::{DriverT, InterfaceT};
3 | use tunio::{DefaultDriver, DefaultInterface};
4 |
5 | fn main() {
6 | // DefaultDriver is an alias for a supported driver for current platform.
7 | // It may be not optimal for your needs (for example, it can lack support of TAP),
8 | // but it will work in some cases. If you need another driver, then import and use it instead.
9 | let mut driver = DefaultDriver::new().unwrap();
10 | // Preparing configuration for new interface. We use `Builder` pattern for this.
11 | let if_config = DefaultInterface::config_builder()
12 | .name("iface1".to_string())
13 | .build()
14 | .unwrap();
15 |
16 | // Then, we create the interface using config and start it immediately.
17 | let mut interface = DefaultInterface::new_up(&mut driver, if_config).unwrap();
18 |
19 | // The interface is created and running.
20 |
21 | // Write to interface using Write trait
22 | let buf = [0u8; 4096];
23 | let _ = interface.write(&buf);
24 |
25 | // Read from interface using Read trait
26 | let mut mut_buf = [0u8; 4096];
27 | let _ = interface.read(&mut mut_buf);
28 | }
29 |
--------------------------------------------------------------------------------
/platforms/linux/src/lib.rs:
--------------------------------------------------------------------------------
1 | //! # [Universal TUN/TAP device driver](https://www.kernel.org/doc/Documentation/networking/tuntap.txt) support for tunio.
2 | //!
3 | //! This module provides support for TUN/TAP driver, used in Linux.
4 | //!
5 | //! Supported features:
6 | //! - TUN/TAP modes
7 | //! - Sync and async mode
8 | //!
9 | //! Low-level documentation for this driver can be found [here](https://www.kernel.org/doc/Documentation/networking/tuntap.txt).
10 |
11 | mod interface;
12 | mod queue;
13 |
14 | use derive_builder::Builder;
15 | use tunio_core::traits::{DriverT, PlatformIfConfigT};
16 | use tunio_core::Error;
17 |
18 | #[cfg(feature = "tokio")]
19 | pub use interface::TokioInterface;
20 | pub use interface::{Interface, LinuxInterface};
21 |
22 | pub struct Driver {}
23 |
24 | #[derive(Builder, Clone)]
25 | pub struct PlatformIfConfig {}
26 |
27 | impl PlatformIfConfigT for PlatformIfConfig {
28 | type Builder = PlatformIfConfigBuilder;
29 | }
30 |
31 | impl Default for PlatformIfConfig {
32 | fn default() -> Self {
33 | PlatformIfConfigBuilder::default().build().unwrap()
34 | }
35 | }
36 |
37 | impl DriverT for Driver {
38 | type PlatformIfConfig = PlatformIfConfig;
39 |
40 | fn new() -> Result {
41 | Ok(Self {})
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/.github/workflows/tunio.yml:
--------------------------------------------------------------------------------
1 | name: Tunio
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | tags: [ 'v*' ]
7 | pull_request:
8 | branches: [ main ]
9 |
10 | env:
11 | CARGO_TERM_COLOR: always
12 |
13 | jobs:
14 | build:
15 | runs-on: ${{ matrix.os }}
16 | strategy:
17 | matrix:
18 | os: [ubuntu-latest, windows-latest]
19 |
20 | steps:
21 | - uses: actions/checkout@v3
22 | - name: Release build
23 | uses: actions-rs/cargo@v1
24 | with:
25 | command: build
26 | args: -p tunio --release --all-features
27 | - name: Run tests
28 | uses: actions-rs/cargo@v1
29 | with:
30 | command: test
31 | args: -p tunio --verbose
32 | - name: Check if can be packaged
33 | uses: actions-rs/cargo@v1
34 | with:
35 | command: package
36 | args: -p tunio
37 |
38 | publish:
39 | runs-on: ubuntu-latest
40 | needs: [build]
41 | if: startsWith(github.ref, 'refs/tags/')
42 |
43 | steps:
44 | - uses: actions/checkout@v3
45 | - name: Publish to Crates.io
46 | uses: actions-rs/cargo@v1
47 | with:
48 | command: publish
49 | args: -p tunio
50 | env:
51 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
52 |
--------------------------------------------------------------------------------
/core/src/error.rs:
--------------------------------------------------------------------------------
1 | use crate::config::Layer;
2 | use std::io;
3 | use thiserror::Error as ThisError;
4 |
5 | #[non_exhaustive]
6 | #[derive(Debug, ThisError)]
7 | pub enum Error {
8 | #[error("I/O error: {0}")]
9 | Io(io::Error),
10 | #[error("interface name is not valid Unicode")]
11 | InterfaceNameUnicodeError,
12 | #[error("interface name too long: {0} > {1}")]
13 | InterfaceNameTooLong(usize, usize),
14 | #[error("interface name is invalid")]
15 | InterfaceNameInvalid,
16 | #[error("library not loaded: {reason}")]
17 | LibraryNotLoaded { reason: String },
18 | #[error("netconfig error: {0}")]
19 | NetConfigError(netconfig::Error),
20 | #[error("interface name error: {0}")]
21 | InterfaceNameError(String),
22 | #[error("config value is invalid ({reason}): {name}={value}")]
23 | InvalidConfigValue {
24 | name: String,
25 | value: String,
26 | reason: String,
27 | },
28 | #[error("layer is unsupported: {0:?}")]
29 | LayerUnsupported(Layer),
30 | }
31 |
32 | impl From for Error {
33 | fn from(err: io::Error) -> Self {
34 | Error::Io(err)
35 | }
36 | }
37 |
38 | impl From for Error {
39 | fn from(err: netconfig::Error) -> Self {
40 | Error::NetConfigError(err)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/.idea/tunio.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/core/src/traits.rs:
--------------------------------------------------------------------------------
1 | use crate::config::{IfConfig, IfConfigBuilder};
2 | use crate::Error;
3 | use futures::{AsyncRead, AsyncWrite};
4 | use std::io::{Read, Write};
5 |
6 | pub trait PlatformIfConfigT: Default + Clone {
7 | type Builder: Default;
8 | }
9 |
10 | pub trait DriverT: Sized {
11 | type PlatformIfConfig: PlatformIfConfigT;
12 |
13 | fn new() -> Result;
14 | }
15 |
16 | pub trait InterfaceT: Sized {
17 | type PlatformDriver: DriverT;
18 | type PlatformIfConfig: PlatformIfConfigT;
19 |
20 | fn new(
21 | driver: &mut Self::PlatformDriver,
22 | params: IfConfig,
23 | ) -> Result;
24 | fn new_up(
25 | driver: &mut Self::PlatformDriver,
26 | params: IfConfig,
27 | ) -> Result {
28 | let mut interface = Self::new(driver, params)?;
29 | interface.up()?;
30 | Ok(interface)
31 | }
32 |
33 | fn up(&mut self) -> Result<(), Error>;
34 | fn down(&mut self) -> Result<(), Error>;
35 | fn handle(&self) -> netconfig::Interface;
36 |
37 | fn config_builder() -> IfConfigBuilder {
38 | IfConfigBuilder::default()
39 | }
40 | }
41 |
42 | pub trait SyncQueueT: Read + Write {}
43 | pub trait AsyncQueueT: AsyncRead + AsyncWrite + Unpin {}
44 |
--------------------------------------------------------------------------------
/platforms/utun/src/queue.rs:
--------------------------------------------------------------------------------
1 | use crate::Error;
2 | use libc::{PF_SYSTEM, SYSPROTO_CONTROL};
3 | use nix::sys::socket::SysControlAddr;
4 | use socket2::{Domain, Protocol, SockAddr, Socket, Type};
5 | use std::mem;
6 | use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd};
7 |
8 | const UTUN_CONTROL_NAME: &str = "com.apple.net.utun_control";
9 |
10 | pub(crate) fn create_device(name: &str, blocking: bool) -> Result {
11 | let mut id = match name {
12 | s if s.starts_with("utun") => s[4..].parse().map_err(|_| Error::InterfaceNameInvalid),
13 | _ => Err(Error::InterfaceNameInvalid),
14 | }?;
15 | id += 1;
16 |
17 | let tun_device = Socket::new(
18 | Domain::from(PF_SYSTEM),
19 | Type::DGRAM,
20 | Some(Protocol::from(SYSPROTO_CONTROL)),
21 | )
22 | .unwrap();
23 |
24 | let sa = SysControlAddr::from_name(tun_device.as_raw_fd(), UTUN_CONTROL_NAME, id).unwrap();
25 |
26 | let (_, sa) = unsafe {
27 | SockAddr::init(|sa_storage, len| {
28 | let sockaddr = sa_storage as *mut libc::sockaddr_ctl;
29 | *sockaddr = *sa.as_ref();
30 | *len = mem::size_of::() as _;
31 | Ok(())
32 | })
33 | }
34 | .unwrap();
35 | if !blocking {
36 | tun_device.set_nonblocking(true)?;
37 | }
38 | tun_device.connect(&sa).unwrap();
39 |
40 | Ok(unsafe { OwnedFd::from_raw_fd(tun_device.into_raw_fd()) })
41 | }
42 |
--------------------------------------------------------------------------------
/wintun-sys/build.rs:
--------------------------------------------------------------------------------
1 | use std::env;
2 | use std::path::PathBuf;
3 |
4 | fn main() {
5 | println!("cargo:rerun-if-changed=wintun/wintun_functions.h");
6 |
7 | #[cfg(target_os = "windows")]
8 | {
9 | let bindings = bindgen::Builder::default()
10 | .header("wintun/wintun_functions.h")
11 | .parse_callbacks(Box::new(bindgen::CargoCallbacks))
12 | .allowlist_function("Wintun.*")
13 | .allowlist_type("WINTUN_.*")
14 | .allowlist_var("WINTUN_.*")
15 | .blocklist_type("_GUID")
16 | .blocklist_type("BOOL")
17 | .blocklist_type("BYTE")
18 | .blocklist_type("DWORD")
19 | .blocklist_type("DWORD64")
20 | .blocklist_type("GUID")
21 | .blocklist_type("HANDLE")
22 | .blocklist_type("LPCWSTR")
23 | .blocklist_type("NET_LUID")
24 | .blocklist_type("WCHAR")
25 | .blocklist_type("wchar_t")
26 | .dynamic_library_name("wintun")
27 | .dynamic_link_require_all(true)
28 | .opaque_type("NET_LUID")
29 | .generate()
30 | .expect("Unable to generate bindings");
31 |
32 | // Write the bindings to the $OUT_DIR/bindings.rs file.
33 | let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
34 | bindings
35 | .write_to_file(out_path.join("bindings.rs"))
36 | .expect("Couldn't write bindings!");
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/platforms/linux/src/queue.rs:
--------------------------------------------------------------------------------
1 | use crate::Error;
2 | use libc::{IFF_NO_PI, IFF_TAP, IFF_TUN};
3 | use netconfig::sys::posix::ifreq::ifreq;
4 | use std::fs;
5 | use std::os::unix::fs::OpenOptionsExt;
6 | use std::os::unix::io::AsRawFd;
7 | use tunio_core::config::Layer;
8 |
9 | mod ioctls {
10 | nix::ioctl_write_int!(tunsetiff, b'T', 202);
11 | nix::ioctl_write_int!(tunsetpersist, b'T', 203);
12 | nix::ioctl_write_int!(tunsetowner, b'T', 204);
13 | nix::ioctl_write_int!(tunsetgroup, b'T', 206);
14 | }
15 |
16 | pub(crate) struct Device {
17 | pub device: fs::File,
18 | pub name: String,
19 | }
20 |
21 | pub(crate) fn create_device(name: &str, layer: Layer, blocking: bool) -> Result {
22 | let mut open_opts = fs::OpenOptions::new();
23 | open_opts.read(true).write(true);
24 | if !blocking {
25 | open_opts.custom_flags(libc::O_NONBLOCK);
26 | }
27 | let tun_device = open_opts.open("/dev/net/tun")?;
28 |
29 | let mut init_flags = match layer {
30 | Layer::L2 => IFF_TAP,
31 | Layer::L3 => IFF_TUN,
32 | };
33 | init_flags |= IFF_NO_PI;
34 |
35 | let mut req = ifreq::new(name);
36 | req.ifr_ifru.ifru_flags = init_flags as _;
37 |
38 | unsafe { ioctls::tunsetiff(tun_device.as_raw_fd(), &req as *const _ as _) }.unwrap();
39 |
40 | // Name can change due to formatting
41 | Ok(Device {
42 | device: tun_device,
43 | name: String::try_from(req.ifr_ifrn)
44 | .map_err(|e| Error::InterfaceNameError(format!("{e:?}")))?,
45 | })
46 | }
47 |
--------------------------------------------------------------------------------
/platforms/wintun/src/async_interface.rs:
--------------------------------------------------------------------------------
1 | use super::async_queue::AsyncQueue;
2 | use super::interface::CommonInterface;
3 | use futures::{AsyncRead, AsyncWrite};
4 | use std::io::{self};
5 | use std::pin::Pin;
6 | use std::task::{Context, Poll};
7 |
8 | pub type AsyncInterface = CommonInterface;
9 |
10 | impl AsyncRead for AsyncInterface {
11 | fn poll_read(
12 | mut self: Pin<&mut Self>,
13 | cx: &mut Context<'_>,
14 | buf: &mut [u8],
15 | ) -> Poll> {
16 | match self.inner_queue_mut() {
17 | Ok(queue) => Pin::new(queue).poll_read(cx, buf),
18 | Err(e) => Poll::Ready(Err(e)),
19 | }
20 | }
21 | }
22 |
23 | impl AsyncWrite for AsyncInterface {
24 | fn poll_write(
25 | mut self: Pin<&mut Self>,
26 | cx: &mut Context<'_>,
27 | buf: &[u8],
28 | ) -> Poll> {
29 | match self.inner_queue_mut() {
30 | Ok(queue) => Pin::new(queue).poll_write(cx, buf),
31 | Err(e) => Poll::Ready(Err(e)),
32 | }
33 | }
34 |
35 | fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> {
36 | match self.inner_queue_mut() {
37 | Ok(queue) => Pin::new(queue).poll_flush(cx),
38 | Err(e) => Poll::Ready(Err(e)),
39 | }
40 | }
41 |
42 | fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> {
43 | match self.inner_queue_mut() {
44 | Ok(queue) => Pin::new(queue).poll_close(cx),
45 | Err(e) => Poll::Ready(Err(e)),
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/examples/simple.rs:
--------------------------------------------------------------------------------
1 | use etherparse::PacketBuilder;
2 | use futures::AsyncReadExt;
3 | use futures::AsyncWriteExt;
4 | use std::thread::sleep;
5 | use std::time::Duration;
6 | use tunio::traits::{DriverT, InterfaceT};
7 | use tunio::{DefaultAsyncInterface, DefaultDriver};
8 |
9 | #[tokio::main]
10 | async fn main() {
11 | env_logger::init();
12 | let mut driver = DefaultDriver::new().unwrap();
13 |
14 | let mut interface_config = DefaultAsyncInterface::config_builder();
15 | interface_config.name("name".into());
16 | #[cfg(target_os = "windows")]
17 | interface_config
18 | .platform(|mut b| b.description("description".into()).build())
19 | .unwrap();
20 | let interface_config = interface_config.build().unwrap();
21 |
22 | let mut interface = DefaultAsyncInterface::new_up(&mut driver, interface_config).unwrap();
23 | let iff = interface.handle();
24 |
25 | iff.add_address("18.3.5.6/24".parse().unwrap()).unwrap();
26 | iff.add_address("20.3.5.6/24".parse().unwrap()).unwrap();
27 | iff.remove_address("18.3.5.6/24".parse().unwrap()).unwrap();
28 | iff.add_address("fd3c:dea:7f96:2b14::/64".parse().unwrap())
29 | .unwrap();
30 |
31 | for _ in 1..10 {
32 | let builder = PacketBuilder::ipv6(
33 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
34 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
35 | 5,
36 | )
37 | .udp(8080, 8080);
38 |
39 | let mut packet = Vec::with_capacity(builder.size(0));
40 | builder.write(&mut packet, &[]).unwrap();
41 |
42 | interface.write(&*packet).await;
43 |
44 | sleep(Duration::from_secs(1));
45 | }
46 |
47 | let mut buf = vec![0u8; 4096];
48 | while let Ok(n) = interface.read(buf.as_mut_slice()).await {
49 | buf.truncate(n);
50 | println!("{buf:x?}");
51 | buf.resize(4096, 0u8);
52 | }
53 |
54 | tokio::signal::ctrl_c().await;
55 | }
56 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "tunio"
3 | version = "0.4.0"
4 | edition.workspace = true
5 | license.workspace = true
6 | repository.workspace = true
7 | description = "Crate for creating and managing TUN/TAP interfaces with async support. Works best with netconfig crate."
8 | categories.workspace = true
9 | keywords.workspace = true
10 | readme = "README.md"
11 | rust-version.workspace = true
12 |
13 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
14 |
15 | [dependencies]
16 | log.workspace = true
17 | futures.workspace = true
18 | netconfig.workspace = true
19 | derive_builder.workspace = true
20 | delegate.workspace = true
21 | tunio-core.workspace = true
22 | cfg-if = "1.0.0"
23 |
24 | [target.'cfg(target_os = "windows")'.dependencies]
25 | tunio-wintun = { version = "0.1.0", path = "platforms/wintun" }
26 |
27 | [target.'cfg(target_os = "linux")'.dependencies]
28 | tunio-linux = { version = "0.1.0", path = "platforms/linux" }
29 |
30 | [target.'cfg(target_os = "macos")'.dependencies]
31 | tunio-utun = { version = "0.1.0", path = "platforms/utun"}
32 |
33 | [features]
34 | default = []
35 | tokio = ["tunio-linux/tokio", "tunio-utun/tokio"]
36 |
37 | [dev-dependencies]
38 | tokio = { workspace = true, features = ["rt", "macros", "rt-multi-thread", "signal", "sync", "io-util"] }
39 | etherparse = "0.12.0"
40 | env_logger = "0.9.0"
41 |
42 | [package.metadata.docs.rs]
43 | all-features = true
44 | rustdoc-args = ["--cfg", "docsrs"]
45 |
46 | [workspace]
47 | members = ["wintun-sys", "core", "platforms/wintun", "platforms/linux", "platforms/utun"]
48 |
49 | [[example]]
50 | name = "simple"
51 | path = "examples/simple.rs"
52 | required-features = ["tokio"]
53 |
54 | [workspace.package]
55 | repository = "https://github.com/GamePad64/tunio"
56 | keywords = ["network", "networking", "cross-platform", "tun"]
57 | license = "MIT"
58 | categories = ["os", "network-programming"]
59 | edition = "2021"
60 | rust-version = "1.64"
61 |
62 | [workspace.dependencies]
63 | log = "0.4.17"
64 | netconfig = "0.4.0"
65 | futures = "0.3.21"
66 | derive_builder = "0.11.2"
67 | delegate = "0.8.0"
68 | tunio-core = { version = "0.1.0", path = "core" }
69 | nix = "0.25.0"
70 | libc = "0.2.126"
71 | tokio = "1.21.2"
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Tunio
2 | [](https://crates.io/crates/tunio)
3 | [](https://docs.rs/tunio)
4 |
5 | Create TUN/TAP interfaces in cross-platform and idiomatic Rust!
6 |
7 | ## Features ⭐
8 | - [Tokio](https://tokio.rs/) support (optional).
9 | - TUN/TAP support.
10 | - Extensible architecture for adding other platforms later.
11 |
12 | ## Short example 📜
13 | ```rust,no_run
14 | use std::io::{Read, Write};
15 | use tunio::traits::{DriverT, InterfaceT};
16 | use tunio::{DefaultDriver, DefaultInterface};
17 |
18 | fn main() {
19 | // DefaultDriver is an alias for a supported driver for current platform.
20 | // It may be not optimal for your needs (for example, it can lack support of TAP),
21 | // but it will work in some cases. If you need another driver, then import and use it instead.
22 | let mut driver = DefaultDriver::new().unwrap();
23 | // Preparing configuration for new interface. We use `Builder` pattern for this.
24 | let if_config = DefaultInterface::config_builder()
25 | .name("iface1".to_string())
26 | .build()
27 | .unwrap();
28 |
29 | // Then, we create the interface using config and start it immediately.
30 | let mut interface = DefaultInterface::new_up(&mut driver, if_config).unwrap();
31 |
32 | // The interface is created and running.
33 |
34 | // Write to interface using Write trait
35 | let buf = [0u8; 4096];
36 | let _ = interface.write(&buf);
37 |
38 | // Read from interface using Read trait
39 | let mut mut_buf = [0u8; 4096];
40 | let _ = interface.read(&mut mut_buf);
41 | }
42 |
43 | ```
44 |
45 | ## Supported platforms 🖥️
46 | - **Windows**, TUN only (using [`Wintun`] driver).
47 | - [`Wintun`] driver requires a prebuilt DLL inside application folder. Please, refer to [`Wintun`] documentation for more details.
48 | - **Linux**
49 |
50 | [`Wintun`]: https://www.wintun.net/
51 |
52 | macOS support for utun and feth drivers is planned. Feel free to post a PR, it is always greatly appreciated 😉
53 |
54 | ## Related projects 🔗
55 | - [`netconfig`]: A high-level abstraction for gathering and changing network interface configuration.
56 |
57 | [`netconfig`]: https://github.com/GamePad64/netconfig
58 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### Rust template
2 | # Generated by Cargo
3 | # will have compiled files and executables
4 | debug/
5 | target/
6 |
7 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
8 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
9 | tunio/Cargo.lock
10 |
11 | # These are backup files generated by rustfmt
12 | **/*.rs.bk
13 |
14 | ### JetBrains template
15 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
16 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
17 |
18 | # User-specific stuff
19 | .idea/**/workspace.xml
20 | .idea/**/tasks.xml
21 | .idea/**/usage.statistics.xml
22 | .idea/**/dictionaries
23 | .idea/**/shelf
24 |
25 | # Generated files
26 | .idea/**/contentModel.xml
27 |
28 | # Sensitive or high-churn files
29 | .idea/**/dataSources/
30 | .idea/**/dataSources.ids
31 | .idea/**/dataSources.local.xml
32 | .idea/**/sqlDataSources.xml
33 | .idea/**/dynamic.xml
34 | .idea/**/uiDesigner.xml
35 | .idea/**/dbnavigator.xml
36 |
37 | # Gradle
38 | .idea/**/gradle.xml
39 | .idea/**/libraries
40 |
41 | # Gradle and Maven with auto-import
42 | # When using Gradle or Maven with auto-import, you should exclude module files,
43 | # since they will be recreated, and may cause churn. Uncomment if using
44 | # auto-import.
45 | # .idea/artifacts
46 | # .idea/compiler.xml
47 | # .idea/jarRepositories.xml
48 | # .idea/modules.xml
49 | # .idea/*.iml
50 | # .idea/modules
51 | # *.iml
52 | # *.ipr
53 |
54 | # CMake
55 | cmake-build-*/
56 |
57 | # Mongo Explorer plugin
58 | .idea/**/mongoSettings.xml
59 |
60 | # File-based project format
61 | *.iws
62 |
63 | # IntelliJ
64 | out/
65 |
66 | # mpeltonen/sbt-idea plugin
67 | .idea_modules/
68 |
69 | # JIRA plugin
70 | atlassian-ide-plugin.xml
71 |
72 | # Cursive Clojure plugin
73 | .idea/replstate.xml
74 |
75 | # Crashlytics plugin (for Android Studio and IntelliJ)
76 | com_crashlytics_export_strings.xml
77 | crashlytics.properties
78 | crashlytics-build.properties
79 | fabric.properties
80 |
81 | # Editor-based Rest Client
82 | .idea/httpRequests
83 |
84 | # Android studio 3.1+ serialized cache file
85 | .idea/caches/build_file_checksums.ser
86 |
87 |
--------------------------------------------------------------------------------
/platforms/wintun/src/wrappers/adapter.rs:
--------------------------------------------------------------------------------
1 | use super::HandleWrapper;
2 | use log::error;
3 | use std::io;
4 | use std::sync::Arc;
5 | use tunio_core::Error;
6 | use widestring::U16CString;
7 | use windows::core::{GUID, PCWSTR};
8 | use windows::Win32::NetworkManagement::Ndis::NET_LUID_LH;
9 | use wintun_sys::WINTUN_ADAPTER_HANDLE;
10 |
11 | const MAX_NAME: usize = 255;
12 |
13 | pub struct Adapter {
14 | wintun: Arc,
15 | handle: HandleWrapper,
16 | }
17 |
18 | impl Adapter {
19 | pub fn new(
20 | guid: GUID,
21 | name: &str,
22 | description: &str,
23 | wintun: Arc,
24 | ) -> Result {
25 | let [name_u16, description_u16] = [name, description].map(encode_name);
26 | let (name_u16, description_u16) = (name_u16?, description_u16?);
27 |
28 | let adapter_handle = unsafe {
29 | wintun.WintunCreateAdapter(
30 | PCWSTR::from_raw(name_u16.as_ptr()),
31 | PCWSTR::from_raw(description_u16.as_ptr()),
32 | &guid,
33 | )
34 | };
35 |
36 | if adapter_handle.is_null() {
37 | let err = io::Error::last_os_error();
38 | error!("Failed to create adapter: {err}");
39 | return Err(Error::from(err));
40 | }
41 |
42 | Ok(Self {
43 | wintun,
44 | handle: HandleWrapper(adapter_handle),
45 | })
46 | }
47 |
48 | pub fn luid(&self) -> u64 {
49 | let mut luid_buf = NET_LUID_LH::default();
50 | unsafe {
51 | self.wintun
52 | .WintunGetAdapterLUID(self.handle.0, &mut luid_buf as _);
53 | luid_buf.Value
54 | }
55 | }
56 |
57 | pub fn handle(&self) -> WINTUN_ADAPTER_HANDLE {
58 | self.handle.0
59 | }
60 | }
61 |
62 | impl Drop for Adapter {
63 | fn drop(&mut self) {
64 | unsafe { self.wintun.WintunCloseAdapter(self.handle.0) };
65 | }
66 | }
67 |
68 | fn encode_name(string: &str) -> Result {
69 | let result = U16CString::from_str(string).map_err(|_| Error::InterfaceNameUnicodeError)?;
70 | match result.len() {
71 | 0..=MAX_NAME => Ok(result),
72 | l => Err(Error::InterfaceNameTooLong(l, MAX_NAME)),
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/core/src/queue/tokiofd.rs:
--------------------------------------------------------------------------------
1 | use crate::queue::syncfd::SyncFdQueue;
2 | use crate::queue::FdQueueT;
3 | use crate::traits::AsyncQueueT;
4 | use futures::{AsyncRead, AsyncWrite};
5 | use std::io::{self, Read, Write};
6 | use std::os::unix::io::OwnedFd;
7 | use std::pin::Pin;
8 | use std::task::{ready, Context, Poll};
9 | use tokio::io::unix::AsyncFd;
10 |
11 | pub struct TokioFdQueue {
12 | inner: AsyncFd,
13 | }
14 |
15 | impl AsyncQueueT for TokioFdQueue {}
16 |
17 | impl FdQueueT for TokioFdQueue {
18 | const BLOCKING: bool = false;
19 |
20 | fn new(device: OwnedFd) -> Self {
21 | Self {
22 | inner: AsyncFd::new(SyncFdQueue::new(device)).unwrap(),
23 | }
24 | }
25 | }
26 |
27 | impl AsyncRead for TokioFdQueue {
28 | fn poll_read(
29 | self: Pin<&mut Self>,
30 | cx: &mut Context<'_>,
31 | buf: &mut [u8],
32 | ) -> Poll> {
33 | let self_mut = self.get_mut();
34 | loop {
35 | let mut guard = ready!(self_mut.inner.poll_read_ready_mut(cx))?;
36 |
37 | match guard.try_io(|inner| inner.get_mut().read(buf)) {
38 | Ok(Ok(n)) => {
39 | return Poll::Ready(Ok(n));
40 | }
41 | Ok(Err(e)) => return Poll::Ready(Err(e)),
42 | Err(_) => continue,
43 | }
44 | }
45 | }
46 | }
47 |
48 | impl AsyncWrite for TokioFdQueue {
49 | fn poll_write(
50 | self: Pin<&mut Self>,
51 | cx: &mut Context<'_>,
52 | buf: &[u8],
53 | ) -> Poll> {
54 | let self_mut = self.get_mut();
55 | loop {
56 | let mut guard = ready!(self_mut.inner.poll_write_ready_mut(cx))?;
57 |
58 | match guard.try_io(|inner| inner.get_mut().write(buf)) {
59 | Ok(Ok(n)) => {
60 | return Poll::Ready(Ok(n));
61 | }
62 | Ok(Err(e)) => return Poll::Ready(Err(e)),
63 | Err(_) => continue,
64 | }
65 | }
66 | }
67 |
68 | fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> {
69 | let self_mut = self.get_mut();
70 | loop {
71 | let mut guard = ready!(self_mut.inner.poll_write_ready_mut(cx))?;
72 |
73 | match guard.try_io(|inner| inner.get_mut().flush()) {
74 | Ok(Ok(())) => {
75 | return Poll::Ready(Ok(()));
76 | }
77 | Ok(Err(e)) => return Poll::Ready(Err(e)),
78 | Err(_) => continue,
79 | }
80 | }
81 | }
82 |
83 | fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> {
84 | Poll::Ready(Ok(()))
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/platforms/wintun/src/interface.rs:
--------------------------------------------------------------------------------
1 | use super::queue::SessionQueueT;
2 | use super::wrappers::{Adapter, Session};
3 | use super::PlatformIfConfig;
4 | use super::Queue;
5 | use crate::Driver;
6 | use std::io;
7 | use std::io::{ErrorKind, Read, Write};
8 | use std::sync::Arc;
9 | use tunio_core::config::{IfConfig, Layer};
10 | use tunio_core::traits::InterfaceT;
11 | use tunio_core::Error;
12 | use windows::core::GUID;
13 | use windows::Win32::NetworkManagement::IpHelper::ConvertInterfaceLuidToIndex;
14 | use windows::Win32::NetworkManagement::Ndis::NET_LUID_LH;
15 |
16 | pub struct CommonInterface {
17 | wintun: Arc,
18 | adapter: Arc,
19 | config: IfConfig,
20 | pub(crate) queue: Option,
21 | }
22 |
23 | impl InterfaceT for CommonInterface {
24 | type PlatformDriver = Driver;
25 | type PlatformIfConfig = PlatformIfConfig;
26 |
27 | fn new(
28 | driver: &mut Self::PlatformDriver,
29 | params: IfConfig,
30 | ) -> Result {
31 | let _ = Session::validate_capacity(params.platform.capacity);
32 | if params.layer == Layer::L2 {
33 | return Err(Error::LayerUnsupported(params.layer));
34 | }
35 |
36 | let wintun = driver.wintun().clone();
37 |
38 | let adapter = Arc::new(Adapter::new(
39 | GUID::from_u128(params.platform.guid),
40 | ¶ms.name,
41 | ¶ms.platform.description,
42 | wintun.clone(),
43 | )?);
44 |
45 | Ok(Self {
46 | wintun,
47 | adapter,
48 | config: params,
49 | queue: None,
50 | })
51 | }
52 |
53 | fn up(&mut self) -> Result<(), Error> {
54 | let session = Session::new(
55 | self.adapter.clone(),
56 | self.wintun.clone(),
57 | self.config.platform.capacity,
58 | )?;
59 | self.queue = Some(Q::new(session));
60 |
61 | Ok(())
62 | }
63 |
64 | fn down(&mut self) -> Result<(), Error> {
65 | let _ = self.queue.take();
66 | Ok(())
67 | }
68 |
69 | fn handle(&self) -> netconfig::Interface {
70 | let mut index = 0;
71 | let luid = NET_LUID_LH {
72 | Value: self.adapter.luid(),
73 | };
74 |
75 | unsafe {
76 | ConvertInterfaceLuidToIndex(&luid, &mut index).unwrap();
77 | }
78 |
79 | netconfig::Interface::try_from_index(index).unwrap()
80 | }
81 | }
82 |
83 | impl CommonInterface {
84 | pub(crate) fn inner_queue_mut(&mut self) -> io::Result<&mut Q> {
85 | match &mut self.queue {
86 | Some(queue) => Ok(queue),
87 | None => Err(ErrorKind::BrokenPipe.into()),
88 | }
89 | }
90 | }
91 |
92 | pub type Interface = CommonInterface;
93 |
94 | impl Read for Interface {
95 | delegate::delegate! {
96 | to self.inner_queue_mut()? {
97 | fn read(&mut self, buf: &mut [u8]) -> io::Result;
98 | }
99 | }
100 | }
101 |
102 | impl Write for Interface {
103 | delegate::delegate! {
104 | to self.inner_queue_mut()? {
105 | fn write(&mut self, buf: &[u8]) -> io::Result;
106 | fn flush(&mut self) -> io::Result<()>;
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/platforms/linux/src/interface.rs:
--------------------------------------------------------------------------------
1 | use super::queue::{create_device, Device};
2 | use super::Driver;
3 | use super::PlatformIfConfig;
4 | use delegate::delegate;
5 | use futures::{AsyncRead, AsyncWrite};
6 | use log::debug;
7 | use netconfig::sys::InterfaceExt;
8 | use std::io;
9 | use std::io::{Read, Write};
10 | use std::pin::Pin;
11 | use std::task::{Context, Poll};
12 | use tunio_core::config::IfConfig;
13 | use tunio_core::queue::syncfd::SyncFdQueue;
14 | #[cfg(feature = "tokio")]
15 | use tunio_core::queue::tokiofd::TokioFdQueue;
16 | use tunio_core::queue::FdQueueT;
17 | use tunio_core::traits::{AsyncQueueT, InterfaceT, SyncQueueT};
18 | use tunio_core::Error;
19 |
20 | pub struct LinuxInterface {
21 | name: String,
22 | pub(crate) queue: Q,
23 | }
24 |
25 | impl LinuxInterface {
26 | pub fn name(&self) -> &str {
27 | &self.name
28 | }
29 | }
30 |
31 | impl InterfaceT for LinuxInterface {
32 | type PlatformDriver = Driver;
33 | type PlatformIfConfig = PlatformIfConfig;
34 |
35 | fn new(
36 | _driver: &mut Self::PlatformDriver,
37 | params: IfConfig,
38 | ) -> Result {
39 | let Device { device, name } = create_device(¶ms.name, params.layer, Q::BLOCKING)?;
40 | let queue = Q::new(device.into());
41 |
42 | if params.name != name {
43 | debug!(
44 | "Interface name is changed \"{}\" -> \"{}\"",
45 | params.name, name
46 | );
47 | }
48 |
49 | Ok(Self { name, queue })
50 | }
51 |
52 | fn up(&mut self) -> Result<(), Error> {
53 | Ok(self.handle().set_up(true)?)
54 | }
55 |
56 | fn down(&mut self) -> Result<(), Error> {
57 | Ok(self.handle().set_up(false)?)
58 | }
59 |
60 | fn handle(&self) -> netconfig::Interface {
61 | netconfig::Interface::try_from_name(self.name()).unwrap()
62 | }
63 | }
64 |
65 | pub type Interface = LinuxInterface;
66 | impl SyncQueueT for Interface {}
67 |
68 | impl Read for LinuxInterface {
69 | delegate! {
70 | to self.queue {
71 | fn read(&mut self, buf: &mut [u8]) -> Result;
72 | }
73 | }
74 | }
75 |
76 | impl Write for LinuxInterface {
77 | delegate! {
78 | to self.queue {
79 | fn write(&mut self, buf: &[u8]) -> io::Result;
80 | fn flush(&mut self) -> io::Result<()>;
81 | }
82 | }
83 | }
84 |
85 | #[cfg(feature = "tokio")]
86 | pub type TokioInterface = LinuxInterface;
87 | #[cfg(feature = "tokio")]
88 | impl AsyncQueueT for TokioInterface {}
89 |
90 | impl AsyncRead for LinuxInterface {
91 | delegate! {
92 | to Pin::new(&mut self.queue) {
93 | fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll>;
94 | }
95 | }
96 | }
97 |
98 | impl AsyncWrite for LinuxInterface {
99 | delegate! {
100 | to Pin::new(&mut self.queue) {
101 | fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll>;
102 | fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>;
103 | fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>;
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/platforms/utun/src/interface.rs:
--------------------------------------------------------------------------------
1 | use crate::queue::create_device;
2 | use crate::{Driver, PlatformIfConfig};
3 | use delegate::delegate;
4 | use futures::{AsyncRead, AsyncWrite};
5 | use netconfig::sys::InterfaceExt;
6 | use std::io::{self, Read, Write};
7 | use std::pin::Pin;
8 | use std::task::{Context, Poll};
9 | use tunio_core::config::IfConfig;
10 | use tunio_core::queue::syncfd::SyncFdQueue;
11 | #[cfg(feature = "tokio")]
12 | use tunio_core::queue::tokiofd::TokioFdQueue;
13 | use tunio_core::queue::FdQueueT;
14 | use tunio_core::traits::{AsyncQueueT, InterfaceT, SyncQueueT};
15 | use tunio_core::Error;
16 |
17 | pub struct UtunInterface {
18 | name: String,
19 | queue: Q,
20 | }
21 |
22 | impl InterfaceT for UtunInterface {
23 | type PlatformDriver = Driver;
24 | type PlatformIfConfig = PlatformIfConfig;
25 |
26 | fn new_up(
27 | _driver: &mut Self::PlatformDriver,
28 | params: IfConfig,
29 | ) -> Result {
30 | let queue = Q::new(create_device(¶ms.name, Q::BLOCKING)?);
31 |
32 | Ok(Self {
33 | name: params.name,
34 | queue,
35 | })
36 | }
37 |
38 | fn new(
39 | driver: &mut Self::PlatformDriver,
40 | params: IfConfig,
41 | ) -> Result {
42 | let mut interface = Self::new_up(driver, params)?;
43 | interface.down()?;
44 | Ok(interface)
45 | }
46 |
47 | fn up(&mut self) -> Result<(), Error> {
48 | let handle = self.handle();
49 | handle.set_up(true)?;
50 | handle.set_running(true)?;
51 |
52 | Ok(())
53 | }
54 |
55 | fn down(&mut self) -> Result<(), Error> {
56 | let handle = self.handle();
57 | handle.set_up(false)?;
58 | handle.set_running(false)?;
59 |
60 | Ok(())
61 | }
62 |
63 | fn handle(&self) -> netconfig::Interface {
64 | netconfig::Interface::try_from_name(self.name()).unwrap()
65 | }
66 | }
67 |
68 | impl UtunInterface {
69 | pub fn name(&self) -> &str {
70 | &self.name
71 | }
72 | }
73 |
74 | pub type Interface = UtunInterface;
75 |
76 | impl SyncQueueT for Interface {}
77 |
78 | impl Read for UtunInterface {
79 | delegate! {
80 | to self.queue {
81 | fn read(&mut self, buf: &mut [u8]) -> Result;
82 | }
83 | }
84 | }
85 |
86 | impl Write for UtunInterface {
87 | delegate! {
88 | to self.queue {
89 | fn write(&mut self, buf: &[u8]) -> io::Result;
90 | fn flush(&mut self) -> io::Result<()>;
91 | }
92 | }
93 | }
94 |
95 | #[cfg(feature = "tokio")]
96 | pub type TokioInterface = UtunInterface;
97 | #[cfg(feature = "tokio")]
98 | impl AsyncQueueT for TokioInterface {}
99 |
100 | impl AsyncRead for UtunInterface {
101 | delegate! {
102 | to Pin::new(&mut self.queue) {
103 | fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll>;
104 | }
105 | }
106 | }
107 |
108 | impl AsyncWrite for UtunInterface {
109 | delegate! {
110 | to Pin::new(&mut self.queue) {
111 | fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll>;
112 | fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>;
113 | fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>;
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/platforms/wintun/src/async_queue.rs:
--------------------------------------------------------------------------------
1 | use super::event::SafeEvent;
2 | use super::wrappers::Session;
3 | use crate::queue::SessionQueueT;
4 | use futures::{AsyncRead, AsyncWrite};
5 | use std::future::Future;
6 | use std::io::{self, Read, Write};
7 | use std::pin::Pin;
8 | use std::sync::Arc;
9 | use std::task::{Context, Poll};
10 | use windows::Win32::Foundation::WIN32_ERROR;
11 | use windows::{
12 | Win32::Foundation::HANDLE, Win32::Foundation::WAIT_ABANDONED_0,
13 | Win32::Foundation::WAIT_OBJECT_0, Win32::System::Threading::WaitForMultipleObjects,
14 | Win32::System::WindowsProgramming::INFINITE,
15 | };
16 |
17 | enum WaitingStopReason {
18 | Shutdown,
19 | Ready,
20 | }
21 |
22 | enum ReadState {
23 | Waiting(Option>),
24 | Idle,
25 | Closed,
26 | }
27 |
28 | pub struct AsyncQueue {
29 | session: Session,
30 |
31 | read_state: ReadState,
32 | shutdown_event: Arc,
33 | }
34 |
35 | impl SessionQueueT for AsyncQueue {
36 | fn new(session: Session) -> Self {
37 | Self {
38 | session,
39 |
40 | read_state: ReadState::Idle,
41 |
42 | // Manual reset, because we use this event once and it must fire on all threads
43 | shutdown_event: Arc::new(SafeEvent::new(true, false)),
44 | }
45 | }
46 | }
47 |
48 | impl Drop for AsyncQueue {
49 | fn drop(&mut self) {
50 | self.shutdown_event.set_event();
51 | }
52 | }
53 |
54 | fn wait_for_read(read_event: HANDLE, shutdown_event: Arc) -> WaitingStopReason {
55 | const WAIT_OBJECT_1: WIN32_ERROR = WIN32_ERROR(WAIT_OBJECT_0.0 + 1);
56 | const WAIT_ABANDONED_1: WIN32_ERROR = WIN32_ERROR(WAIT_ABANDONED_0.0 + 1);
57 |
58 | match unsafe { WaitForMultipleObjects(&[shutdown_event.handle(), read_event], false, INFINITE) }
59 | {
60 | // Shutdown
61 | WAIT_OBJECT_0 | WAIT_ABANDONED_0 => WaitingStopReason::Shutdown,
62 | // Ready for read
63 | WAIT_OBJECT_1 => WaitingStopReason::Ready,
64 | // Read event deleted
65 | WAIT_ABANDONED_1 => {
66 | panic!("Read event deleted unexpectedly");
67 | }
68 |
69 | e => {
70 | panic!("Unexpected event result: {e:?}");
71 | }
72 | }
73 | }
74 |
75 | impl AsyncRead for AsyncQueue {
76 | fn poll_read(
77 | mut self: Pin<&mut Self>,
78 | cx: &mut Context<'_>,
79 | buf: &mut [u8],
80 | ) -> Poll> {
81 | loop {
82 | match &mut self.read_state {
83 | ReadState::Waiting(task) => {
84 | let mut task = task.take().unwrap();
85 |
86 | self.read_state = match Pin::new(&mut task).poll(cx) {
87 | Poll::Ready(WaitingStopReason::Shutdown) => ReadState::Closed,
88 | Poll::Ready(WaitingStopReason::Ready) => ReadState::Idle,
89 | Poll::Pending => ReadState::Waiting(Some(task)),
90 | };
91 |
92 | if let ReadState::Waiting(..) = self.read_state {
93 | return Poll::Pending;
94 | }
95 | }
96 | ReadState::Idle => match self.session.read(buf) {
97 | Ok(n) => return Poll::Ready(Ok(n)),
98 | Err(e) => {
99 | if e.kind() == io::ErrorKind::WouldBlock {
100 | let read_event = self.session.read_event();
101 | let inner_shutdown_event = self.shutdown_event.clone();
102 |
103 | self.read_state =
104 | ReadState::Waiting(Some(blocking::unblock(move || {
105 | wait_for_read(read_event, inner_shutdown_event)
106 | })));
107 | } else {
108 | return Poll::Ready(Err(e));
109 | }
110 | }
111 | },
112 | ReadState::Closed => return Poll::Ready(Ok(0)),
113 | }
114 | }
115 | }
116 | }
117 |
118 | impl AsyncWrite for AsyncQueue {
119 | // Write to wintun is already nonblocking
120 | fn poll_write(
121 | mut self: Pin<&mut Self>,
122 | _cx: &mut Context<'_>,
123 | buf: &[u8],
124 | ) -> Poll> {
125 | Poll::Ready(self.session.write(buf))
126 | }
127 |
128 | fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> {
129 | // Not implemented by driver
130 | Poll::Ready(Ok(()))
131 | }
132 |
133 | fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> {
134 | // Not implemented by driver
135 | Poll::Ready(Ok(()))
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/platforms/wintun/src/wrappers/session.rs:
--------------------------------------------------------------------------------
1 | use super::Adapter;
2 | use super::HandleWrapper;
3 | use bytes::BufMut;
4 | use log::error;
5 | use std::io;
6 | use std::io::{Read, Write};
7 | use std::sync::Arc;
8 | use tunio_core::Error;
9 | use windows::Win32::Foundation::{ERROR_BUFFER_OVERFLOW, ERROR_NO_MORE_ITEMS, HANDLE, WIN32_ERROR};
10 | use wintun_sys::{WINTUN_MAX_RING_CAPACITY, WINTUN_MIN_RING_CAPACITY, WINTUN_SESSION_HANDLE};
11 |
12 | struct PacketReader<'a> {
13 | handle: HandleWrapper,
14 | wintun: &'a wintun_sys::wintun,
15 |
16 | ptr: *const u8,
17 | len: usize,
18 | }
19 |
20 | impl<'a> PacketReader<'a> {
21 | pub fn read(
22 | handle: HandleWrapper,
23 | wintun: &'a wintun_sys::wintun,
24 | ) -> io::Result {
25 | let mut len: u32 = 0;
26 | let ptr = unsafe { wintun.WintunReceivePacket(handle.0, &mut len) };
27 |
28 | if !ptr.is_null() {
29 | Ok(Self {
30 | handle,
31 | wintun,
32 | ptr,
33 | len: len as _,
34 | })
35 | } else {
36 | Err(io::Error::last_os_error())
37 | }
38 | }
39 |
40 | pub fn as_slice(&self) -> &[u8] {
41 | unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
42 | }
43 | }
44 |
45 | impl<'a> Drop for PacketReader<'a> {
46 | fn drop(&mut self) {
47 | if !self.ptr.is_null() {
48 | unsafe {
49 | self.wintun
50 | .WintunReleaseReceivePacket(self.handle.0, self.ptr);
51 | }
52 | }
53 | }
54 | }
55 |
56 | pub struct Session {
57 | handle: HandleWrapper,
58 | wintun: Arc,
59 | }
60 |
61 | impl Session {
62 | pub fn new(
63 | adapter: Arc,
64 | wintun: Arc,
65 | capacity: u32,
66 | ) -> Result {
67 | let _ = Self::validate_capacity(capacity)?;
68 |
69 | let session_handle = unsafe { wintun.WintunStartSession(adapter.handle(), capacity) };
70 |
71 | if session_handle.is_null() {
72 | let err = io::Error::last_os_error();
73 | error!("Failed to create session: {err}");
74 | return Err(err.into());
75 | }
76 |
77 | Ok(Self {
78 | handle: HandleWrapper(session_handle),
79 | wintun,
80 | })
81 | }
82 |
83 | #[allow(dead_code)]
84 | pub fn read_event(&self) -> HANDLE {
85 | unsafe { self.wintun.WintunGetReadWaitEvent(self.handle.0) }
86 | }
87 |
88 | pub fn validate_capacity(capacity: u32) -> Result<(), Error> {
89 | let range = WINTUN_MIN_RING_CAPACITY..=WINTUN_MAX_RING_CAPACITY;
90 | if !range.contains(&capacity) || !capacity.is_power_of_two() {
91 | return Err(Error::InvalidConfigValue {
92 | name: "capacity".to_string(),
93 | value: capacity.to_string(),
94 | reason: format!(
95 | "must be power of 2 between {} and {}",
96 | WINTUN_MIN_RING_CAPACITY, WINTUN_MAX_RING_CAPACITY
97 | ),
98 | });
99 | }
100 | Ok(())
101 | }
102 | }
103 |
104 | impl Read for Session {
105 | fn read(&mut self, mut buf: &mut [u8]) -> io::Result {
106 | let packet = PacketReader::read(self.handle.clone(), &self.wintun);
107 | match packet {
108 | Ok(packet) => {
109 | let packet_slice = packet.as_slice();
110 | buf.put(packet_slice);
111 | Ok(packet_slice.len())
112 | }
113 | Err(e) => match error_eq(&e, ERROR_NO_MORE_ITEMS) {
114 | true => Err(io::ErrorKind::WouldBlock.into()),
115 | false => Err(e),
116 | },
117 | }
118 | }
119 | }
120 |
121 | impl Write for Session {
122 | // does not block, as WintunAllocateSendPacket and WintunSendPacket are executed right one ofter another
123 | fn write(&mut self, buf: &[u8]) -> io::Result {
124 | let packet = unsafe {
125 | self.wintun
126 | .WintunAllocateSendPacket(self.handle.0, buf.len() as _)
127 | };
128 | if !packet.is_null() {
129 | // Copy buffer to allocated packet
130 | unsafe {
131 | packet.copy_from_nonoverlapping(buf.as_ptr(), buf.len());
132 | self.wintun.WintunSendPacket(self.handle.0, packet); // Deallocates packet
133 | }
134 | Ok(buf.len())
135 | } else {
136 | let e = io::Error::last_os_error();
137 | match error_eq(&e, ERROR_BUFFER_OVERFLOW) {
138 | true => panic!("send buffer overflow"),
139 | false => Err(e),
140 | }
141 | }
142 | }
143 |
144 | fn flush(&mut self) -> io::Result<()> {
145 | Ok(())
146 | }
147 | }
148 |
149 | impl Drop for Session {
150 | fn drop(&mut self) {
151 | unsafe {
152 | self.wintun.WintunEndSession(self.handle.0);
153 | }
154 | }
155 | }
156 |
157 | fn error_eq(err: &io::Error, win32_error: WIN32_ERROR) -> bool {
158 | match err.raw_os_error() {
159 | None => false,
160 | Some(os_error) => os_error == win32_error.0 as _,
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/wintun-sys/wintun/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Prebuilt Binaries License
2 | -------------------------
3 |
4 | 1. DEFINITIONS. "Software" means the precise contents of the "wintun.dll"
5 | files that are included in the .zip file that contains this document as
6 | downloaded from wintun.net/builds.
7 |
8 | 2. LICENSE GRANT. WireGuard LLC grants to you a non-exclusive and
9 | non-transferable right to use Software for lawful purposes under certain
10 | obligations and limited rights as set forth in this agreement.
11 |
12 | 3. RESTRICTIONS. Software is owned and copyrighted by WireGuard LLC. It is
13 | licensed, not sold. Title to Software and all associated intellectual
14 | property rights are retained by WireGuard. You must not:
15 | a. reverse engineer, decompile, disassemble, extract from, or otherwise
16 | modify the Software;
17 | b. modify or create derivative work based upon Software in whole or in
18 | parts, except insofar as only the API interfaces of the "wintun.h" file
19 | distributed alongside the Software (the "Permitted API") are used;
20 | c. remove any proprietary notices, labels, or copyrights from the Software;
21 | d. resell, redistribute, lease, rent, transfer, sublicense, or otherwise
22 | transfer rights of the Software without the prior written consent of
23 | WireGuard LLC, except insofar as the Software is distributed alongside
24 | other software that uses the Software only via the Permitted API;
25 | e. use the name of WireGuard LLC, the WireGuard project, the Wintun
26 | project, or the names of its contributors to endorse or promote products
27 | derived from the Software without specific prior written consent.
28 |
29 | 4. LIMITED WARRANTY. THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF
30 | ANY KIND. WIREGUARD LLC HEREBY EXCLUDES AND DISCLAIMS ALL IMPLIED OR
31 | STATUTORY WARRANTIES, INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS
32 | FOR A PARTICULAR PURPOSE, QUALITY, NON-INFRINGEMENT, TITLE, RESULTS,
33 | EFFORTS, OR QUIET ENJOYMENT. THERE IS NO WARRANTY THAT THE PRODUCT WILL BE
34 | ERROR-FREE OR WILL FUNCTION WITHOUT INTERRUPTION. YOU ASSUME THE ENTIRE
35 | RISK FOR THE RESULTS OBTAINED USING THE PRODUCT. TO THE EXTENT THAT
36 | WIREGUARD LLC MAY NOT DISCLAIM ANY WARRANTY AS A MATTER OF APPLICABLE LAW,
37 | THE SCOPE AND DURATION OF SUCH WARRANTY WILL BE THE MINIMUM PERMITTED UNDER
38 | SUCH LAW. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
39 | WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR
40 | A PARTICULAR PURPOSE OR NON-INFRINGEMENT ARE DISCLAIMED, EXCEPT TO THE
41 | EXTENT THAT THESE DISCLAIMERS ARE HELD TO BE LEGALLY INVALID.
42 |
43 | 5. LIMITATION OF LIABILITY. To the extent not prohibited by law, in no event
44 | WireGuard LLC or any third-party-developer will be liable for any lost
45 | revenue, profit or data or for special, indirect, consequential, incidental
46 | or punitive damages, however caused regardless of the theory of liability,
47 | arising out of or related to the use of or inability to use Software, even
48 | if WireGuard LLC has been advised of the possibility of such damages.
49 | Solely you are responsible for determining the appropriateness of using
50 | Software and accept full responsibility for all risks associated with its
51 | exercise of rights under this agreement, including but not limited to the
52 | risks and costs of program errors, compliance with applicable laws, damage
53 | to or loss of data, programs or equipment, and unavailability or
54 | interruption of operations. The foregoing limitations will apply even if
55 | the above stated warranty fails of its essential purpose. You acknowledge,
56 | that it is in the nature of software that software is complex and not
57 | completely free of errors. In no event shall WireGuard LLC or any
58 | third-party-developer be liable to you under any theory for any damages
59 | suffered by you or any user of Software or for any special, incidental,
60 | indirect, consequential or similar damages (including without limitation
61 | damages for loss of business profits, business interruption, loss of
62 | business information or any other pecuniary loss) arising out of the use or
63 | inability to use Software, even if WireGuard LLC has been advised of the
64 | possibility of such damages and regardless of the legal or quitable theory
65 | (contract, tort, or otherwise) upon which the claim is based.
66 |
67 | 6. TERMINATION. This agreement is affected until terminated. You may
68 | terminate this agreement at any time. This agreement will terminate
69 | immediately without notice from WireGuard LLC if you fail to comply with
70 | the terms and conditions of this agreement. Upon termination, you must
71 | delete Software and all copies of Software and cease all forms of
72 | distribution of Software.
73 |
74 | 7. SEVERABILITY. If any provision of this agreement is held to be
75 | unenforceable, this agreement will remain in effect with the provision
76 | omitted, unless omission would frustrate the intent of the parties, in
77 | which case this agreement will immediately terminate.
78 |
79 | 8. RESERVATION OF RIGHTS. All rights not expressly granted in this agreement
80 | are reserved by WireGuard LLC. For example, WireGuard LLC reserves the
81 | right at any time to cease development of Software, to alter distribution
82 | details, features, specifications, capabilities, functions, licensing
83 | terms, release dates, APIs, ABIs, general availability, or other
84 | characteristics of the Software.
85 |
--------------------------------------------------------------------------------
/wintun-sys/wintun/wintun.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: GPL-2.0 OR MIT
2 | *
3 | * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
4 | */
5 |
6 | #pragma once
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #ifdef __cplusplus
15 | extern "C" {
16 | #endif
17 |
18 | #ifndef ALIGNED
19 | # if defined(_MSC_VER)
20 | # define ALIGNED(n) __declspec(align(n))
21 | # elif defined(__GNUC__)
22 | # define ALIGNED(n) __attribute__((aligned(n)))
23 | # else
24 | # error "Unable to define ALIGNED"
25 | # endif
26 | #endif
27 |
28 | /* MinGW is missing this one, unfortunately. */
29 | #ifndef _Post_maybenull_
30 | # define _Post_maybenull_
31 | #endif
32 |
33 | #pragma warning(push)
34 | #pragma warning(disable : 4324) /* structure was padded due to alignment specifier */
35 |
36 | /**
37 | * A handle representing Wintun adapter
38 | */
39 | typedef struct _WINTUN_ADAPTER *WINTUN_ADAPTER_HANDLE;
40 |
41 | /**
42 | * Creates a new Wintun adapter.
43 | *
44 | * @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
45 | * characters.
46 | *
47 | * @param TunnelType Name of the adapter tunnel type. Zero-terminated string of up to MAX_ADAPTER_NAME-1
48 | * characters.
49 | *
50 | * @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation deterministically.
51 | * If it is set to NULL, the GUID is chosen by the system at random, and hence a new NLA entry is
52 | * created for each new adapter. It is called "requested" GUID because the API it uses is
53 | * completely undocumented, and so there could be minor interesting complications with its usage.
54 | *
55 | * @return If the function succeeds, the return value is the adapter handle. Must be released with
56 | * WintunCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call
57 | * GetLastError.
58 | */
59 | typedef _Must_inspect_result_
60 | _Return_type_success_(return != NULL)
61 | _Post_maybenull_
62 | WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_CREATE_ADAPTER_FUNC)
63 | (_In_z_ LPCWSTR Name, _In_z_ LPCWSTR TunnelType, _In_opt_ const GUID *RequestedGUID);
64 |
65 | /**
66 | * Opens an existing Wintun adapter.
67 | *
68 | * @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
69 | * characters.
70 | *
71 | * @return If the function succeeds, the return value is the adapter handle. Must be released with
72 | * WintunCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call
73 | * GetLastError.
74 | */
75 | typedef _Must_inspect_result_
76 | _Return_type_success_(return != NULL)
77 | _Post_maybenull_
78 | WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_OPEN_ADAPTER_FUNC)(_In_z_ LPCWSTR Name);
79 |
80 | /**
81 | * Releases Wintun adapter resources and, if adapter was created with WintunCreateAdapter, removes adapter.
82 | *
83 | * @param Adapter Adapter handle obtained with WintunCreateAdapter or WintunOpenAdapter.
84 | */
85 | typedef VOID(WINAPI WINTUN_CLOSE_ADAPTER_FUNC)(_In_opt_ WINTUN_ADAPTER_HANDLE Adapter);
86 |
87 | /**
88 | * Deletes the Wintun driver if there are no more adapters in use.
89 | *
90 | * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
91 | * get extended error information, call GetLastError.
92 | */
93 | typedef _Return_type_success_(return != FALSE)
94 | BOOL(WINAPI WINTUN_DELETE_DRIVER_FUNC)(VOID);
95 |
96 | /**
97 | * Returns the LUID of the adapter.
98 | *
99 | * @param Adapter Adapter handle obtained with WintunCreateAdapter or WintunOpenAdapter
100 | *
101 | * @param Luid Pointer to LUID to receive adapter LUID.
102 | */
103 | typedef VOID(WINAPI WINTUN_GET_ADAPTER_LUID_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid);
104 |
105 | /**
106 | * Determines the version of the Wintun driver currently loaded.
107 | *
108 | * @return If the function succeeds, the return value is the version number. If the function fails, the return value is
109 | * zero. To get extended error information, call GetLastError. Possible errors include the following:
110 | * ERROR_FILE_NOT_FOUND Wintun not loaded
111 | */
112 | typedef _Return_type_success_(return != 0)
113 | DWORD(WINAPI WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC)(VOID);
114 |
115 | /**
116 | * Determines the level of logging, passed to WINTUN_LOGGER_CALLBACK.
117 | */
118 | typedef enum
119 | {
120 | WINTUN_LOG_INFO, /**< Informational */
121 | WINTUN_LOG_WARN, /**< Warning */
122 | WINTUN_LOG_ERR /**< Error */
123 | } WINTUN_LOGGER_LEVEL;
124 |
125 | /**
126 | * Called by internal logger to report diagnostic messages
127 | *
128 | * @param Level Message level.
129 | *
130 | * @param Timestamp Message timestamp in in 100ns intervals since 1601-01-01 UTC.
131 | *
132 | * @param Message Message text.
133 | */
134 | typedef VOID(CALLBACK *WINTUN_LOGGER_CALLBACK)(
135 | _In_ WINTUN_LOGGER_LEVEL Level,
136 | _In_ DWORD64 Timestamp,
137 | _In_z_ LPCWSTR Message);
138 |
139 | /**
140 | * Sets logger callback function.
141 | *
142 | * @param NewLogger Pointer to callback function to use as a new global logger. NewLogger may be called from various
143 | * threads concurrently. Should the logging require serialization, you must handle serialization in
144 | * NewLogger. Set to NULL to disable.
145 | */
146 | typedef VOID(WINAPI WINTUN_SET_LOGGER_FUNC)(_In_ WINTUN_LOGGER_CALLBACK NewLogger);
147 |
148 | /**
149 | * Minimum ring capacity.
150 | */
151 | #define WINTUN_MIN_RING_CAPACITY 0x20000 /* 128kiB */
152 |
153 | /**
154 | * Maximum ring capacity.
155 | */
156 | #define WINTUN_MAX_RING_CAPACITY 0x4000000 /* 64MiB */
157 |
158 | /**
159 | * A handle representing Wintun session
160 | */
161 | typedef struct _TUN_SESSION *WINTUN_SESSION_HANDLE;
162 |
163 | /**
164 | * Starts Wintun session.
165 | *
166 | * @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter
167 | *
168 | * @param Capacity Rings capacity. Must be between WINTUN_MIN_RING_CAPACITY and WINTUN_MAX_RING_CAPACITY (incl.)
169 | * Must be a power of two.
170 | *
171 | * @return Wintun session handle. Must be released with WintunEndSession. If the function fails, the return value is
172 | * NULL. To get extended error information, call GetLastError.
173 | */
174 | typedef _Must_inspect_result_
175 | _Return_type_success_(return != NULL)
176 | _Post_maybenull_
177 | WINTUN_SESSION_HANDLE(WINAPI WINTUN_START_SESSION_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity);
178 |
179 | /**
180 | * Ends Wintun session.
181 | *
182 | * @param Session Wintun session handle obtained with WintunStartSession
183 | */
184 | typedef VOID(WINAPI WINTUN_END_SESSION_FUNC)(_In_ WINTUN_SESSION_HANDLE Session);
185 |
186 | /**
187 | * Gets Wintun session's read-wait event handle.
188 | *
189 | * @param Session Wintun session handle obtained with WintunStartSession
190 | *
191 | * @return Pointer to receive event handle to wait for available data when reading. Should
192 | * WintunReceivePackets return ERROR_NO_MORE_ITEMS (after spinning on it for a while under heavy
193 | * load), wait for this event to become signaled before retrying WintunReceivePackets. Do not call
194 | * CloseHandle on this event - it is managed by the session.
195 | */
196 | typedef HANDLE(WINAPI WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HANDLE Session);
197 |
198 | /**
199 | * Maximum IP packet size
200 | */
201 | #define WINTUN_MAX_IP_PACKET_SIZE 0xFFFF
202 |
203 | /**
204 | * Retrieves one or packet. After the packet content is consumed, call WintunReleaseReceivePacket with Packet returned
205 | * from this function to release internal buffer. This function is thread-safe.
206 | *
207 | * @param Session Wintun session handle obtained with WintunStartSession
208 | *
209 | * @param PacketSize Pointer to receive packet size.
210 | *
211 | * @return Pointer to layer 3 IPv4 or IPv6 packet. Client may modify its content at will. If the function fails, the
212 | * return value is NULL. To get extended error information, call GetLastError. Possible errors include the
213 | * following:
214 | * ERROR_HANDLE_EOF Wintun adapter is terminating;
215 | * ERROR_NO_MORE_ITEMS Wintun buffer is exhausted;
216 | * ERROR_INVALID_DATA Wintun buffer is corrupt
217 | */
218 | typedef _Must_inspect_result_
219 | _Return_type_success_(return != NULL)
220 | _Post_maybenull_
221 | _Post_writable_byte_size_(*PacketSize)
222 | BYTE *(WINAPI WINTUN_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize);
223 |
224 | /**
225 | * Releases internal buffer after the received packet has been processed by the client. This function is thread-safe.
226 | *
227 | * @param Session Wintun session handle obtained with WintunStartSession
228 | *
229 | * @param Packet Packet obtained with WintunReceivePacket
230 | */
231 | typedef VOID(
232 | WINAPI WINTUN_RELEASE_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
233 |
234 | /**
235 | * Allocates memory for a packet to send. After the memory is filled with packet data, call WintunSendPacket to send
236 | * and release internal buffer. WintunAllocateSendPacket is thread-safe and the WintunAllocateSendPacket order of
237 | * calls define the packet sending order.
238 | *
239 | * @param Session Wintun session handle obtained with WintunStartSession
240 | *
241 | * @param PacketSize Exact packet size. Must be less or equal to WINTUN_MAX_IP_PACKET_SIZE.
242 | *
243 | * @return Returns pointer to memory where to prepare layer 3 IPv4 or IPv6 packet for sending. If the function fails,
244 | * the return value is NULL. To get extended error information, call GetLastError. Possible errors include the
245 | * following:
246 | * ERROR_HANDLE_EOF Wintun adapter is terminating;
247 | * ERROR_BUFFER_OVERFLOW Wintun buffer is full;
248 | */
249 | typedef _Must_inspect_result_
250 | _Return_type_success_(return != NULL)
251 | _Post_maybenull_
252 | _Post_writable_byte_size_(PacketSize)
253 | BYTE *(WINAPI WINTUN_ALLOCATE_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize);
254 |
255 | /**
256 | * Sends the packet and releases internal buffer. WintunSendPacket is thread-safe, but the WintunAllocateSendPacket
257 | * order of calls define the packet sending order. This means the packet is not guaranteed to be sent in the
258 | * WintunSendPacket yet.
259 | *
260 | * @param Session Wintun session handle obtained with WintunStartSession
261 | *
262 | * @param Packet Packet obtained with WintunAllocateSendPacket
263 | */
264 | typedef VOID(WINAPI WINTUN_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
265 |
266 | #pragma warning(pop)
267 |
268 | #ifdef __cplusplus
269 | }
270 | #endif
271 |
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "advmac"
7 | version = "1.0.3"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "41c1bfd911d1173023132c681f7434ed956ec5459d7520b4f85331fc00d93bf0"
10 | dependencies = [
11 | "arrayvec",
12 | "rand",
13 | "serde",
14 | ]
15 |
16 | [[package]]
17 | name = "aho-corasick"
18 | version = "0.7.19"
19 | source = "registry+https://github.com/rust-lang/crates.io-index"
20 | checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
21 | dependencies = [
22 | "memchr",
23 | ]
24 |
25 | [[package]]
26 | name = "anyhow"
27 | version = "1.0.65"
28 | source = "registry+https://github.com/rust-lang/crates.io-index"
29 | checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
30 |
31 | [[package]]
32 | name = "arrayvec"
33 | version = "0.7.2"
34 | source = "registry+https://github.com/rust-lang/crates.io-index"
35 | checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
36 | dependencies = [
37 | "serde",
38 | ]
39 |
40 | [[package]]
41 | name = "async-channel"
42 | version = "1.7.1"
43 | source = "registry+https://github.com/rust-lang/crates.io-index"
44 | checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28"
45 | dependencies = [
46 | "concurrent-queue",
47 | "event-listener",
48 | "futures-core",
49 | ]
50 |
51 | [[package]]
52 | name = "async-lock"
53 | version = "2.6.0"
54 | source = "registry+https://github.com/rust-lang/crates.io-index"
55 | checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685"
56 | dependencies = [
57 | "event-listener",
58 | "futures-lite",
59 | ]
60 |
61 | [[package]]
62 | name = "async-task"
63 | version = "4.3.0"
64 | source = "registry+https://github.com/rust-lang/crates.io-index"
65 | checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524"
66 |
67 | [[package]]
68 | name = "atomic-waker"
69 | version = "1.0.0"
70 | source = "registry+https://github.com/rust-lang/crates.io-index"
71 | checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a"
72 |
73 | [[package]]
74 | name = "atty"
75 | version = "0.2.14"
76 | source = "registry+https://github.com/rust-lang/crates.io-index"
77 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
78 | dependencies = [
79 | "hermit-abi",
80 | "libc",
81 | "winapi",
82 | ]
83 |
84 | [[package]]
85 | name = "autocfg"
86 | version = "1.1.0"
87 | source = "registry+https://github.com/rust-lang/crates.io-index"
88 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
89 |
90 | [[package]]
91 | name = "bindgen"
92 | version = "0.61.0"
93 | source = "registry+https://github.com/rust-lang/crates.io-index"
94 | checksum = "8a022e58a142a46fea340d68012b9201c094e93ec3d033a944a24f8fd4a4f09a"
95 | dependencies = [
96 | "bitflags",
97 | "cexpr",
98 | "clang-sys",
99 | "lazy_static",
100 | "lazycell",
101 | "log",
102 | "peeking_take_while",
103 | "proc-macro2",
104 | "quote",
105 | "regex",
106 | "rustc-hash",
107 | "shlex",
108 | "syn",
109 | "which",
110 | ]
111 |
112 | [[package]]
113 | name = "bitflags"
114 | version = "1.3.2"
115 | source = "registry+https://github.com/rust-lang/crates.io-index"
116 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
117 |
118 | [[package]]
119 | name = "blocking"
120 | version = "1.3.0"
121 | source = "registry+https://github.com/rust-lang/crates.io-index"
122 | checksum = "3c67b173a56acffd6d2326fb7ab938ba0b00a71480e14902b2591c87bc5741e8"
123 | dependencies = [
124 | "async-channel",
125 | "async-lock",
126 | "async-task",
127 | "atomic-waker",
128 | "fastrand",
129 | "futures-lite",
130 | ]
131 |
132 | [[package]]
133 | name = "byteorder"
134 | version = "1.4.3"
135 | source = "registry+https://github.com/rust-lang/crates.io-index"
136 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
137 |
138 | [[package]]
139 | name = "bytes"
140 | version = "1.4.0"
141 | source = "registry+https://github.com/rust-lang/crates.io-index"
142 | checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
143 |
144 | [[package]]
145 | name = "cache-padded"
146 | version = "1.2.0"
147 | source = "registry+https://github.com/rust-lang/crates.io-index"
148 | checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c"
149 |
150 | [[package]]
151 | name = "cexpr"
152 | version = "0.6.0"
153 | source = "registry+https://github.com/rust-lang/crates.io-index"
154 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
155 | dependencies = [
156 | "nom",
157 | ]
158 |
159 | [[package]]
160 | name = "cfg-if"
161 | version = "1.0.0"
162 | source = "registry+https://github.com/rust-lang/crates.io-index"
163 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
164 |
165 | [[package]]
166 | name = "clang-sys"
167 | version = "1.4.0"
168 | source = "registry+https://github.com/rust-lang/crates.io-index"
169 | checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3"
170 | dependencies = [
171 | "glob",
172 | "libc",
173 | "libloading",
174 | ]
175 |
176 | [[package]]
177 | name = "concurrent-queue"
178 | version = "1.2.4"
179 | source = "registry+https://github.com/rust-lang/crates.io-index"
180 | checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c"
181 | dependencies = [
182 | "cache-padded",
183 | ]
184 |
185 | [[package]]
186 | name = "core-foundation"
187 | version = "0.9.3"
188 | source = "registry+https://github.com/rust-lang/crates.io-index"
189 | checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
190 | dependencies = [
191 | "core-foundation-sys",
192 | "libc",
193 | ]
194 |
195 | [[package]]
196 | name = "core-foundation-sys"
197 | version = "0.8.3"
198 | source = "registry+https://github.com/rust-lang/crates.io-index"
199 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
200 |
201 | [[package]]
202 | name = "darling"
203 | version = "0.14.1"
204 | source = "registry+https://github.com/rust-lang/crates.io-index"
205 | checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02"
206 | dependencies = [
207 | "darling_core",
208 | "darling_macro",
209 | ]
210 |
211 | [[package]]
212 | name = "darling_core"
213 | version = "0.14.1"
214 | source = "registry+https://github.com/rust-lang/crates.io-index"
215 | checksum = "649c91bc01e8b1eac09fb91e8dbc7d517684ca6be8ebc75bb9cafc894f9fdb6f"
216 | dependencies = [
217 | "fnv",
218 | "ident_case",
219 | "proc-macro2",
220 | "quote",
221 | "strsim",
222 | "syn",
223 | ]
224 |
225 | [[package]]
226 | name = "darling_macro"
227 | version = "0.14.1"
228 | source = "registry+https://github.com/rust-lang/crates.io-index"
229 | checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5"
230 | dependencies = [
231 | "darling_core",
232 | "quote",
233 | "syn",
234 | ]
235 |
236 | [[package]]
237 | name = "delegate"
238 | version = "0.8.0"
239 | source = "registry+https://github.com/rust-lang/crates.io-index"
240 | checksum = "082a24a9967533dc5d743c602157637116fc1b52806d694a5a45e6f32567fcdd"
241 | dependencies = [
242 | "proc-macro2",
243 | "quote",
244 | "syn",
245 | ]
246 |
247 | [[package]]
248 | name = "derive_builder"
249 | version = "0.11.2"
250 | source = "registry+https://github.com/rust-lang/crates.io-index"
251 | checksum = "d07adf7be193b71cc36b193d0f5fe60b918a3a9db4dad0449f57bcfd519704a3"
252 | dependencies = [
253 | "derive_builder_macro",
254 | ]
255 |
256 | [[package]]
257 | name = "derive_builder_core"
258 | version = "0.11.2"
259 | source = "registry+https://github.com/rust-lang/crates.io-index"
260 | checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4"
261 | dependencies = [
262 | "darling",
263 | "proc-macro2",
264 | "quote",
265 | "syn",
266 | ]
267 |
268 | [[package]]
269 | name = "derive_builder_macro"
270 | version = "0.11.2"
271 | source = "registry+https://github.com/rust-lang/crates.io-index"
272 | checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68"
273 | dependencies = [
274 | "derive_builder_core",
275 | "syn",
276 | ]
277 |
278 | [[package]]
279 | name = "either"
280 | version = "1.8.0"
281 | source = "registry+https://github.com/rust-lang/crates.io-index"
282 | checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
283 |
284 | [[package]]
285 | name = "env_logger"
286 | version = "0.9.1"
287 | source = "registry+https://github.com/rust-lang/crates.io-index"
288 | checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272"
289 | dependencies = [
290 | "atty",
291 | "humantime",
292 | "log",
293 | "regex",
294 | "termcolor",
295 | ]
296 |
297 | [[package]]
298 | name = "etherparse"
299 | version = "0.12.0"
300 | source = "registry+https://github.com/rust-lang/crates.io-index"
301 | checksum = "bcb08c4aab4e2985045305551e67126b43f1b6b136bc4e1cd87fb0327877a611"
302 | dependencies = [
303 | "arrayvec",
304 | ]
305 |
306 | [[package]]
307 | name = "event-listener"
308 | version = "2.5.3"
309 | source = "registry+https://github.com/rust-lang/crates.io-index"
310 | checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
311 |
312 | [[package]]
313 | name = "fastrand"
314 | version = "1.8.0"
315 | source = "registry+https://github.com/rust-lang/crates.io-index"
316 | checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
317 | dependencies = [
318 | "instant",
319 | ]
320 |
321 | [[package]]
322 | name = "fnv"
323 | version = "1.0.7"
324 | source = "registry+https://github.com/rust-lang/crates.io-index"
325 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
326 |
327 | [[package]]
328 | name = "futures"
329 | version = "0.3.24"
330 | source = "registry+https://github.com/rust-lang/crates.io-index"
331 | checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c"
332 | dependencies = [
333 | "futures-channel",
334 | "futures-core",
335 | "futures-executor",
336 | "futures-io",
337 | "futures-sink",
338 | "futures-task",
339 | "futures-util",
340 | ]
341 |
342 | [[package]]
343 | name = "futures-channel"
344 | version = "0.3.24"
345 | source = "registry+https://github.com/rust-lang/crates.io-index"
346 | checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050"
347 | dependencies = [
348 | "futures-core",
349 | "futures-sink",
350 | ]
351 |
352 | [[package]]
353 | name = "futures-core"
354 | version = "0.3.24"
355 | source = "registry+https://github.com/rust-lang/crates.io-index"
356 | checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf"
357 |
358 | [[package]]
359 | name = "futures-executor"
360 | version = "0.3.24"
361 | source = "registry+https://github.com/rust-lang/crates.io-index"
362 | checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab"
363 | dependencies = [
364 | "futures-core",
365 | "futures-task",
366 | "futures-util",
367 | ]
368 |
369 | [[package]]
370 | name = "futures-io"
371 | version = "0.3.24"
372 | source = "registry+https://github.com/rust-lang/crates.io-index"
373 | checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68"
374 |
375 | [[package]]
376 | name = "futures-lite"
377 | version = "1.12.0"
378 | source = "registry+https://github.com/rust-lang/crates.io-index"
379 | checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48"
380 | dependencies = [
381 | "fastrand",
382 | "futures-core",
383 | "futures-io",
384 | "memchr",
385 | "parking",
386 | "pin-project-lite",
387 | "waker-fn",
388 | ]
389 |
390 | [[package]]
391 | name = "futures-macro"
392 | version = "0.3.24"
393 | source = "registry+https://github.com/rust-lang/crates.io-index"
394 | checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17"
395 | dependencies = [
396 | "proc-macro2",
397 | "quote",
398 | "syn",
399 | ]
400 |
401 | [[package]]
402 | name = "futures-sink"
403 | version = "0.3.24"
404 | source = "registry+https://github.com/rust-lang/crates.io-index"
405 | checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56"
406 |
407 | [[package]]
408 | name = "futures-task"
409 | version = "0.3.24"
410 | source = "registry+https://github.com/rust-lang/crates.io-index"
411 | checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1"
412 |
413 | [[package]]
414 | name = "futures-util"
415 | version = "0.3.24"
416 | source = "registry+https://github.com/rust-lang/crates.io-index"
417 | checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90"
418 | dependencies = [
419 | "futures-channel",
420 | "futures-core",
421 | "futures-io",
422 | "futures-macro",
423 | "futures-sink",
424 | "futures-task",
425 | "memchr",
426 | "pin-project-lite",
427 | "pin-utils",
428 | "slab",
429 | ]
430 |
431 | [[package]]
432 | name = "getrandom"
433 | version = "0.2.7"
434 | source = "registry+https://github.com/rust-lang/crates.io-index"
435 | checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
436 | dependencies = [
437 | "cfg-if",
438 | "libc",
439 | "wasi",
440 | ]
441 |
442 | [[package]]
443 | name = "glob"
444 | version = "0.3.0"
445 | source = "registry+https://github.com/rust-lang/crates.io-index"
446 | checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
447 |
448 | [[package]]
449 | name = "hermit-abi"
450 | version = "0.1.19"
451 | source = "registry+https://github.com/rust-lang/crates.io-index"
452 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
453 | dependencies = [
454 | "libc",
455 | ]
456 |
457 | [[package]]
458 | name = "humantime"
459 | version = "2.1.0"
460 | source = "registry+https://github.com/rust-lang/crates.io-index"
461 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
462 |
463 | [[package]]
464 | name = "ident_case"
465 | version = "1.0.1"
466 | source = "registry+https://github.com/rust-lang/crates.io-index"
467 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
468 |
469 | [[package]]
470 | name = "instant"
471 | version = "0.1.12"
472 | source = "registry+https://github.com/rust-lang/crates.io-index"
473 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
474 | dependencies = [
475 | "cfg-if",
476 | ]
477 |
478 | [[package]]
479 | name = "ipnet"
480 | version = "2.5.0"
481 | source = "registry+https://github.com/rust-lang/crates.io-index"
482 | checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b"
483 |
484 | [[package]]
485 | name = "ipnetwork"
486 | version = "0.20.0"
487 | source = "registry+https://github.com/rust-lang/crates.io-index"
488 | checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e"
489 | dependencies = [
490 | "serde",
491 | ]
492 |
493 | [[package]]
494 | name = "lazy_static"
495 | version = "1.4.0"
496 | source = "registry+https://github.com/rust-lang/crates.io-index"
497 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
498 |
499 | [[package]]
500 | name = "lazycell"
501 | version = "1.3.0"
502 | source = "registry+https://github.com/rust-lang/crates.io-index"
503 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
504 |
505 | [[package]]
506 | name = "libc"
507 | version = "0.2.135"
508 | source = "registry+https://github.com/rust-lang/crates.io-index"
509 | checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
510 |
511 | [[package]]
512 | name = "libloading"
513 | version = "0.7.3"
514 | source = "registry+https://github.com/rust-lang/crates.io-index"
515 | checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
516 | dependencies = [
517 | "cfg-if",
518 | "winapi",
519 | ]
520 |
521 | [[package]]
522 | name = "log"
523 | version = "0.4.17"
524 | source = "registry+https://github.com/rust-lang/crates.io-index"
525 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
526 | dependencies = [
527 | "cfg-if",
528 | ]
529 |
530 | [[package]]
531 | name = "memchr"
532 | version = "2.5.0"
533 | source = "registry+https://github.com/rust-lang/crates.io-index"
534 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
535 |
536 | [[package]]
537 | name = "memoffset"
538 | version = "0.6.5"
539 | source = "registry+https://github.com/rust-lang/crates.io-index"
540 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
541 | dependencies = [
542 | "autocfg",
543 | ]
544 |
545 | [[package]]
546 | name = "minimal-lexical"
547 | version = "0.2.1"
548 | source = "registry+https://github.com/rust-lang/crates.io-index"
549 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
550 |
551 | [[package]]
552 | name = "mio"
553 | version = "0.8.4"
554 | source = "registry+https://github.com/rust-lang/crates.io-index"
555 | checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
556 | dependencies = [
557 | "libc",
558 | "log",
559 | "wasi",
560 | "windows-sys",
561 | ]
562 |
563 | [[package]]
564 | name = "netconfig"
565 | version = "0.4.0"
566 | source = "registry+https://github.com/rust-lang/crates.io-index"
567 | checksum = "9470678982a5926708b6b9d4dae8f6c4e9b0817dce979f4b88dddab70e5619cf"
568 | dependencies = [
569 | "advmac",
570 | "cfg-if",
571 | "core-foundation",
572 | "delegate",
573 | "ipnet",
574 | "ipnetwork",
575 | "libc",
576 | "log",
577 | "netlink-packet-route",
578 | "netlink-sys",
579 | "nix",
580 | "scopeguard",
581 | "system-configuration-sys",
582 | "thiserror",
583 | "widestring",
584 | "windows",
585 | ]
586 |
587 | [[package]]
588 | name = "netlink-packet-core"
589 | version = "0.4.2"
590 | source = "registry+https://github.com/rust-lang/crates.io-index"
591 | checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297"
592 | dependencies = [
593 | "anyhow",
594 | "byteorder",
595 | "libc",
596 | "netlink-packet-utils",
597 | ]
598 |
599 | [[package]]
600 | name = "netlink-packet-route"
601 | version = "0.13.0"
602 | source = "registry+https://github.com/rust-lang/crates.io-index"
603 | checksum = "f5dee5ed749373c298237fe694eb0a51887f4cc1a27370c8464bac4382348f1a"
604 | dependencies = [
605 | "anyhow",
606 | "bitflags",
607 | "byteorder",
608 | "libc",
609 | "netlink-packet-core",
610 | "netlink-packet-utils",
611 | ]
612 |
613 | [[package]]
614 | name = "netlink-packet-utils"
615 | version = "0.5.1"
616 | source = "registry+https://github.com/rust-lang/crates.io-index"
617 | checksum = "25af9cf0dc55498b7bd94a1508af7a78706aa0ab715a73c5169273e03c84845e"
618 | dependencies = [
619 | "anyhow",
620 | "byteorder",
621 | "paste",
622 | "thiserror",
623 | ]
624 |
625 | [[package]]
626 | name = "netlink-sys"
627 | version = "0.8.3"
628 | source = "registry+https://github.com/rust-lang/crates.io-index"
629 | checksum = "92b654097027250401127914afb37cb1f311df6610a9891ff07a757e94199027"
630 | dependencies = [
631 | "bytes",
632 | "libc",
633 | "log",
634 | ]
635 |
636 | [[package]]
637 | name = "nix"
638 | version = "0.25.0"
639 | source = "registry+https://github.com/rust-lang/crates.io-index"
640 | checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb"
641 | dependencies = [
642 | "autocfg",
643 | "bitflags",
644 | "cfg-if",
645 | "libc",
646 | "memoffset",
647 | "pin-utils",
648 | ]
649 |
650 | [[package]]
651 | name = "nom"
652 | version = "7.1.1"
653 | source = "registry+https://github.com/rust-lang/crates.io-index"
654 | checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
655 | dependencies = [
656 | "memchr",
657 | "minimal-lexical",
658 | ]
659 |
660 | [[package]]
661 | name = "num_cpus"
662 | version = "1.13.1"
663 | source = "registry+https://github.com/rust-lang/crates.io-index"
664 | checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
665 | dependencies = [
666 | "hermit-abi",
667 | "libc",
668 | ]
669 |
670 | [[package]]
671 | name = "once_cell"
672 | version = "1.14.0"
673 | source = "registry+https://github.com/rust-lang/crates.io-index"
674 | checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0"
675 |
676 | [[package]]
677 | name = "parking"
678 | version = "2.0.0"
679 | source = "registry+https://github.com/rust-lang/crates.io-index"
680 | checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
681 |
682 | [[package]]
683 | name = "paste"
684 | version = "1.0.9"
685 | source = "registry+https://github.com/rust-lang/crates.io-index"
686 | checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1"
687 |
688 | [[package]]
689 | name = "peeking_take_while"
690 | version = "0.1.2"
691 | source = "registry+https://github.com/rust-lang/crates.io-index"
692 | checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
693 |
694 | [[package]]
695 | name = "pin-project-lite"
696 | version = "0.2.9"
697 | source = "registry+https://github.com/rust-lang/crates.io-index"
698 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
699 |
700 | [[package]]
701 | name = "pin-utils"
702 | version = "0.1.0"
703 | source = "registry+https://github.com/rust-lang/crates.io-index"
704 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
705 |
706 | [[package]]
707 | name = "proc-macro2"
708 | version = "1.0.43"
709 | source = "registry+https://github.com/rust-lang/crates.io-index"
710 | checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
711 | dependencies = [
712 | "unicode-ident",
713 | ]
714 |
715 | [[package]]
716 | name = "quote"
717 | version = "1.0.21"
718 | source = "registry+https://github.com/rust-lang/crates.io-index"
719 | checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
720 | dependencies = [
721 | "proc-macro2",
722 | ]
723 |
724 | [[package]]
725 | name = "rand"
726 | version = "0.8.5"
727 | source = "registry+https://github.com/rust-lang/crates.io-index"
728 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
729 | dependencies = [
730 | "rand_core",
731 | ]
732 |
733 | [[package]]
734 | name = "rand_core"
735 | version = "0.6.4"
736 | source = "registry+https://github.com/rust-lang/crates.io-index"
737 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
738 | dependencies = [
739 | "getrandom",
740 | ]
741 |
742 | [[package]]
743 | name = "regex"
744 | version = "1.6.0"
745 | source = "registry+https://github.com/rust-lang/crates.io-index"
746 | checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
747 | dependencies = [
748 | "aho-corasick",
749 | "memchr",
750 | "regex-syntax",
751 | ]
752 |
753 | [[package]]
754 | name = "regex-syntax"
755 | version = "0.6.27"
756 | source = "registry+https://github.com/rust-lang/crates.io-index"
757 | checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
758 |
759 | [[package]]
760 | name = "rustc-hash"
761 | version = "1.1.0"
762 | source = "registry+https://github.com/rust-lang/crates.io-index"
763 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
764 |
765 | [[package]]
766 | name = "scopeguard"
767 | version = "1.1.0"
768 | source = "registry+https://github.com/rust-lang/crates.io-index"
769 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
770 |
771 | [[package]]
772 | name = "serde"
773 | version = "1.0.145"
774 | source = "registry+https://github.com/rust-lang/crates.io-index"
775 | checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
776 |
777 | [[package]]
778 | name = "shlex"
779 | version = "1.1.0"
780 | source = "registry+https://github.com/rust-lang/crates.io-index"
781 | checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
782 |
783 | [[package]]
784 | name = "signal-hook-registry"
785 | version = "1.4.0"
786 | source = "registry+https://github.com/rust-lang/crates.io-index"
787 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
788 | dependencies = [
789 | "libc",
790 | ]
791 |
792 | [[package]]
793 | name = "slab"
794 | version = "0.4.7"
795 | source = "registry+https://github.com/rust-lang/crates.io-index"
796 | checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
797 | dependencies = [
798 | "autocfg",
799 | ]
800 |
801 | [[package]]
802 | name = "socket2"
803 | version = "0.4.7"
804 | source = "registry+https://github.com/rust-lang/crates.io-index"
805 | checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd"
806 | dependencies = [
807 | "libc",
808 | "winapi",
809 | ]
810 |
811 | [[package]]
812 | name = "strsim"
813 | version = "0.10.0"
814 | source = "registry+https://github.com/rust-lang/crates.io-index"
815 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
816 |
817 | [[package]]
818 | name = "syn"
819 | version = "1.0.99"
820 | source = "registry+https://github.com/rust-lang/crates.io-index"
821 | checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
822 | dependencies = [
823 | "proc-macro2",
824 | "quote",
825 | "unicode-ident",
826 | ]
827 |
828 | [[package]]
829 | name = "system-configuration-sys"
830 | version = "0.5.0"
831 | source = "registry+https://github.com/rust-lang/crates.io-index"
832 | checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
833 | dependencies = [
834 | "core-foundation-sys",
835 | "libc",
836 | ]
837 |
838 | [[package]]
839 | name = "termcolor"
840 | version = "1.1.3"
841 | source = "registry+https://github.com/rust-lang/crates.io-index"
842 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
843 | dependencies = [
844 | "winapi-util",
845 | ]
846 |
847 | [[package]]
848 | name = "thiserror"
849 | version = "1.0.37"
850 | source = "registry+https://github.com/rust-lang/crates.io-index"
851 | checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
852 | dependencies = [
853 | "thiserror-impl",
854 | ]
855 |
856 | [[package]]
857 | name = "thiserror-impl"
858 | version = "1.0.37"
859 | source = "registry+https://github.com/rust-lang/crates.io-index"
860 | checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
861 | dependencies = [
862 | "proc-macro2",
863 | "quote",
864 | "syn",
865 | ]
866 |
867 | [[package]]
868 | name = "tokio"
869 | version = "1.21.2"
870 | source = "registry+https://github.com/rust-lang/crates.io-index"
871 | checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099"
872 | dependencies = [
873 | "autocfg",
874 | "bytes",
875 | "libc",
876 | "memchr",
877 | "mio",
878 | "num_cpus",
879 | "pin-project-lite",
880 | "signal-hook-registry",
881 | "socket2",
882 | "tokio-macros",
883 | "winapi",
884 | ]
885 |
886 | [[package]]
887 | name = "tokio-macros"
888 | version = "1.8.0"
889 | source = "registry+https://github.com/rust-lang/crates.io-index"
890 | checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
891 | dependencies = [
892 | "proc-macro2",
893 | "quote",
894 | "syn",
895 | ]
896 |
897 | [[package]]
898 | name = "tunio"
899 | version = "0.4.0"
900 | dependencies = [
901 | "cfg-if",
902 | "delegate",
903 | "derive_builder",
904 | "env_logger",
905 | "etherparse",
906 | "futures",
907 | "log",
908 | "netconfig",
909 | "tokio",
910 | "tunio-core",
911 | "tunio-linux",
912 | "tunio-utun",
913 | "tunio-wintun",
914 | ]
915 |
916 | [[package]]
917 | name = "tunio-core"
918 | version = "0.1.0"
919 | dependencies = [
920 | "delegate",
921 | "derive_builder",
922 | "futures",
923 | "log",
924 | "netconfig",
925 | "thiserror",
926 | "tokio",
927 | ]
928 |
929 | [[package]]
930 | name = "tunio-linux"
931 | version = "0.1.0"
932 | dependencies = [
933 | "delegate",
934 | "derive_builder",
935 | "futures",
936 | "libc",
937 | "log",
938 | "netconfig",
939 | "nix",
940 | "tunio-core",
941 | ]
942 |
943 | [[package]]
944 | name = "tunio-utun"
945 | version = "0.1.0"
946 | dependencies = [
947 | "delegate",
948 | "derive_builder",
949 | "futures",
950 | "libc",
951 | "log",
952 | "netconfig",
953 | "nix",
954 | "socket2",
955 | "tunio-core",
956 | ]
957 |
958 | [[package]]
959 | name = "tunio-wintun"
960 | version = "0.1.0"
961 | dependencies = [
962 | "async-task",
963 | "blocking",
964 | "bytes",
965 | "delegate",
966 | "derive_builder",
967 | "futures",
968 | "log",
969 | "netconfig",
970 | "tunio-core",
971 | "widestring",
972 | "windows",
973 | "wintun-sys",
974 | ]
975 |
976 | [[package]]
977 | name = "unicode-ident"
978 | version = "1.0.4"
979 | source = "registry+https://github.com/rust-lang/crates.io-index"
980 | checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
981 |
982 | [[package]]
983 | name = "waker-fn"
984 | version = "1.1.0"
985 | source = "registry+https://github.com/rust-lang/crates.io-index"
986 | checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
987 |
988 | [[package]]
989 | name = "wasi"
990 | version = "0.11.0+wasi-snapshot-preview1"
991 | source = "registry+https://github.com/rust-lang/crates.io-index"
992 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
993 |
994 | [[package]]
995 | name = "which"
996 | version = "4.3.0"
997 | source = "registry+https://github.com/rust-lang/crates.io-index"
998 | checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b"
999 | dependencies = [
1000 | "either",
1001 | "libc",
1002 | "once_cell",
1003 | ]
1004 |
1005 | [[package]]
1006 | name = "widestring"
1007 | version = "1.0.2"
1008 | source = "registry+https://github.com/rust-lang/crates.io-index"
1009 | checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
1010 |
1011 | [[package]]
1012 | name = "winapi"
1013 | version = "0.3.9"
1014 | source = "registry+https://github.com/rust-lang/crates.io-index"
1015 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
1016 | dependencies = [
1017 | "winapi-i686-pc-windows-gnu",
1018 | "winapi-x86_64-pc-windows-gnu",
1019 | ]
1020 |
1021 | [[package]]
1022 | name = "winapi-i686-pc-windows-gnu"
1023 | version = "0.4.0"
1024 | source = "registry+https://github.com/rust-lang/crates.io-index"
1025 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1026 |
1027 | [[package]]
1028 | name = "winapi-util"
1029 | version = "0.1.5"
1030 | source = "registry+https://github.com/rust-lang/crates.io-index"
1031 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
1032 | dependencies = [
1033 | "winapi",
1034 | ]
1035 |
1036 | [[package]]
1037 | name = "winapi-x86_64-pc-windows-gnu"
1038 | version = "0.4.0"
1039 | source = "registry+https://github.com/rust-lang/crates.io-index"
1040 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1041 |
1042 | [[package]]
1043 | name = "windows"
1044 | version = "0.42.0"
1045 | source = "registry+https://github.com/rust-lang/crates.io-index"
1046 | checksum = "0286ba339aa753e70765d521bb0242cc48e1194562bfa2a2ad7ac8a6de28f5d5"
1047 | dependencies = [
1048 | "windows_aarch64_gnullvm",
1049 | "windows_aarch64_msvc 0.42.0",
1050 | "windows_i686_gnu 0.42.0",
1051 | "windows_i686_msvc 0.42.0",
1052 | "windows_x86_64_gnu 0.42.0",
1053 | "windows_x86_64_gnullvm",
1054 | "windows_x86_64_msvc 0.42.0",
1055 | ]
1056 |
1057 | [[package]]
1058 | name = "windows-sys"
1059 | version = "0.36.1"
1060 | source = "registry+https://github.com/rust-lang/crates.io-index"
1061 | checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
1062 | dependencies = [
1063 | "windows_aarch64_msvc 0.36.1",
1064 | "windows_i686_gnu 0.36.1",
1065 | "windows_i686_msvc 0.36.1",
1066 | "windows_x86_64_gnu 0.36.1",
1067 | "windows_x86_64_msvc 0.36.1",
1068 | ]
1069 |
1070 | [[package]]
1071 | name = "windows_aarch64_gnullvm"
1072 | version = "0.42.0"
1073 | source = "registry+https://github.com/rust-lang/crates.io-index"
1074 | checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
1075 |
1076 | [[package]]
1077 | name = "windows_aarch64_msvc"
1078 | version = "0.36.1"
1079 | source = "registry+https://github.com/rust-lang/crates.io-index"
1080 | checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
1081 |
1082 | [[package]]
1083 | name = "windows_aarch64_msvc"
1084 | version = "0.42.0"
1085 | source = "registry+https://github.com/rust-lang/crates.io-index"
1086 | checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
1087 |
1088 | [[package]]
1089 | name = "windows_i686_gnu"
1090 | version = "0.36.1"
1091 | source = "registry+https://github.com/rust-lang/crates.io-index"
1092 | checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
1093 |
1094 | [[package]]
1095 | name = "windows_i686_gnu"
1096 | version = "0.42.0"
1097 | source = "registry+https://github.com/rust-lang/crates.io-index"
1098 | checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
1099 |
1100 | [[package]]
1101 | name = "windows_i686_msvc"
1102 | version = "0.36.1"
1103 | source = "registry+https://github.com/rust-lang/crates.io-index"
1104 | checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
1105 |
1106 | [[package]]
1107 | name = "windows_i686_msvc"
1108 | version = "0.42.0"
1109 | source = "registry+https://github.com/rust-lang/crates.io-index"
1110 | checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
1111 |
1112 | [[package]]
1113 | name = "windows_x86_64_gnu"
1114 | version = "0.36.1"
1115 | source = "registry+https://github.com/rust-lang/crates.io-index"
1116 | checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
1117 |
1118 | [[package]]
1119 | name = "windows_x86_64_gnu"
1120 | version = "0.42.0"
1121 | source = "registry+https://github.com/rust-lang/crates.io-index"
1122 | checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
1123 |
1124 | [[package]]
1125 | name = "windows_x86_64_gnullvm"
1126 | version = "0.42.0"
1127 | source = "registry+https://github.com/rust-lang/crates.io-index"
1128 | checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
1129 |
1130 | [[package]]
1131 | name = "windows_x86_64_msvc"
1132 | version = "0.36.1"
1133 | source = "registry+https://github.com/rust-lang/crates.io-index"
1134 | checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
1135 |
1136 | [[package]]
1137 | name = "windows_x86_64_msvc"
1138 | version = "0.42.0"
1139 | source = "registry+https://github.com/rust-lang/crates.io-index"
1140 | checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
1141 |
1142 | [[package]]
1143 | name = "wintun-sys"
1144 | version = "0.2.0"
1145 | dependencies = [
1146 | "bindgen",
1147 | "libloading",
1148 | "windows",
1149 | ]
1150 |
--------------------------------------------------------------------------------