tun

repository·master·Indexed 20 days ago

https://github.com/meh/rust-tun

A cross-platform Rust library for creating and managing TUN (network tunnel) interfaces on Linux, macOS, Windows, and OpenHarmony. It provides a unified abstraction via the AbstractDevice trait for handling network parameters like IP addresses, netmasks, and MTU. The library supports both synchronous APIs and asynchronous I/O through an optional `async` feature compatible with the Tokio runtime, offering AsyncDevice for non-blocking packet reading and writing.

Tokens
7.2K
Snippets
31
Records
40
Agent score
68%

What's inside tun

  1. Install the tun crate

    master

    Add tun to your Cargo.toml dependencies. By default, it provides synchronous APIs. If you intend to use the TUN interface with mio or tokio for asynchronous I/O, you must enable the async feature.

    For synchronous usage:

    [dependencies]
    tun = "0.8"

    For asynchronous usage:

    [dependencies]
    tun = { version = "0.8", features = ["async"] }
    [dependencies]
    tun = "0.8"
  2. Use async TUN device operations

    master
    If the async feature is enabled, the crate provides asynchronous versions of the device operations. This allows for non-blocking packet reading and writing, which is essential for high-performance networking applications or integration with async runtimes like Tokio.
  3. Configure TUN device layers and settings

    master
    The rust-tun crate uses a Configuration object to define how a TUN interface behaves. You can specify the network layer using the Layer enum (e.g., IP or Ethernet) and use the ToAddress trait to manage IP addresses. The configuration is then used to instantiate an AbstractDevice.
  4. Receive packets with timeouts on OpenHarmony

    master

    Because TUN devices are character devices, standard SO_RCVTIMEO socket options do not work. The recv_timeout method implements timeouts using poll(2) followed by a read.

    • If no packet arrives within the specified timeout, it returns std::io::ErrorKind::TimedOut.
    • A timeout of std::time::Duration::from_secs(0) performs a non-blocking check.
    • Concurrency Warning: If multiple threads call recv or recv_timeout on the same device, one thread may consume the packet, causing the other thread's read to block even if a timeout was expected.
    // Non-blocking check
    let size = device.recv_timeout(&mut buf, std::time::Duration::from_secs(0));
    
    // Blocking with 500ms timeout
    let size = device.recv_timeout(&mut buf, std::time::Duration::from_millis(500));
  5. Configure Windows-specific TUN settings with PlatformConfig

    master

    When targeting Windows, you can use PlatformConfig to fine-tune device creation. This allows you to specify a custom wintun.dll path, set a specific device GUID, configure DNS servers, and control how the library waits for IPv4/IPv6 interfaces to appear after creation.

    Key configuration methods:

    • device_guid(u128): Sets a specific GUID for the device.
    • wintun_file(S): Sets a custom path to the wintun.dll file (e.g., "path/to/wintun" or "path/to/wintun.dll").
    • dns_servers(&[IpAddr]): Configures a list of DNS servers to use.
    • wait_for_interfaces(ipv4: bool, ipv6: bool, timeout: Duration): Configures whether to wait for IPv4 and IPv6 interfaces to become available and the maximum duration to wait.
    // Example of configuring Windows-specific settings
    let mut config = PlatformConfig::default();
    config.wintun_file("C:\\tools\\wintun.dll");
    config.dns_servers(&["8.8.8.8".parse().unwrap()]);
    config.wait_for_interfaces(true, false, Duration::from_secs(10));
  6. Configure packet information for iOS TUN devices

    master

    The PlatformConfig struct allows you to enable or disable packet information (PI) for the network driver.

    When packet_information is enabled (the default), the first 4 bytes of each packet delivered from/to the iOS underlying API contain a header with flags and protocol type.

    Behavioral Note:

    • If you obtain the file descriptor via `[[NEPacketTunnelProvider::packetFlow valueForKeyPath:@
  7. Use DeviceReader and DeviceWriter for split I/O

    master

    When using the split components:

    • DeviceReader: Implements AsyncRead. Use this to asynchronously read packets from the TUN interface.
    • DeviceWriter: Implements AsyncWrite. Use this to asynchronously write packets to the TUN interface.

    These are useful when you want to move the reader and writer into separate tokio::spawn tasks.

    let (mut writer, mut reader) = async_device.split()?;
    
    // Task for reading
    tokio::spawn(async move {
        let mut buf = [0u8; 1500];
        while let Ok(n) = reader.read(&mut buf).await {
            if n == 0 { break; }
            // process packet
        }
    });
    
    // Task for writing
    tokio::spawn(async move {
        writer.write_all(b"some packet data").await.unwrap();
    });
  8. Split AsyncDevice into DeviceReader and DeviceWriter

    master

    If you need to handle reading and writing on different tasks or threads, use split() to divide the AsyncDevice into a DeviceReader and a DeviceWriter. Both components are backed by an Arc<AsyncFd<Device>>, allowing them to share the underlying file descriptor safely.

    let (writer, reader) = async_device.split()?;
    
    // 'writer' implements AsyncWrite
    // 'reader' implements AsyncRead
  9. Create a TUN device on macOS

    master

    Use the create function to initialize a new TUN Device using a provided Configuration. This is the primary entry point for instantiating a TUN interface on macOS platforms.

    use rust_tun::platform::macos::create;
    use rust_tun::configuration::Configuration;
    
    let config = Configuration::default(); // Assuming Configuration is available
    let device = create(&config).expect("Failed to create TUN device");
  10. Access Windows TUN LUID via AbstractDeviceExt

    master

    On Windows, you can access the Locally Unique Identifier (LUID) of a TUN device by implementing or using the AbstractDeviceExt trait. This is useful for low-level Windows networking operations that require the interface's LUID.

    // Assuming `device` is an instance of a Windows `Device`
    use crate::platform::windows::AbstractDeviceExt;
    
    let luid = device.tun_luid();
  11. Initialize an OpenHarmony TUN Device

    master

    To create a new Device, you must provide a Configuration object that includes a raw_fd.

    • config.raw_fd: Must be Some(raw_fd). If this is missing, Device::new returns Error::InvalidConfig.
    • config.close_fd_on_drop: If provided, determines whether the file descriptor is closed when the Device is dropped. Defaults to true if not specified.
    • config.mtu: If provided, sets the MTU for the device. Defaults to crate::DEFAULT_MTU if not specified.
    let config = Configuration {
        raw_fd: Some(some_fd),
        close_fd_on_drop: Some(true),
        mtu: Some(1500),
        ..Default::default()
    };
    
    let device = Device::new(&config)?;
  12. Initialize an Android TUN device with `Device::new`

    master

    To create a TUN device on Android, use Device::new by passing a reference to a Configuration object. The Configuration must provide a raw_fd (the file descriptor of the TUN interface).

    Note that Device implements AbstractDevice, but several methods like tun_index, tun_name, and set_tun_name are currently not implemented and will return Error::NotImplemented.

    use rust_tun::configuration::Configuration;
    use rust_tun::platform::android::Device;
    
    // Assuming config is already constructed with a valid raw_fd
    let device = Device::new(&config)?;