2 unstable releases

0.2.0 Dec 14, 2025
0.1.0 Dec 8, 2025

#7 in #tcp-tunnel


Used in 2 crates

GPL-3.0 license

80KB
1.5K SLoC

Userspace WireGuard tunnel with TCP/IP network stack.

This crate provides:

  • WireGuard tunnel implementation using gotatun
  • Userspace TCP/IP stack using smoltcp
  • DNS-over-HTTPS resolver for privacy (with configurable DNS servers)
  • High-level ManagedTunnel for easy integration

DNS Configuration

You can configure different DNS servers for:

  • Pre-connection (direct mode): Used before the WireGuard tunnel is established
  • Post-connection (tunnel mode): Used after the tunnel is up, queries go through VPN
use wireguard_netstack::{WgConfigFile, DohServerConfig, DnsConfig};

// Use Google DNS for resolving the WireGuard endpoint
let config = WgConfigFile::from_file("wg.conf")?
    .into_wireguard_config_with_dns(DohServerConfig::google())
    .await?;

Example

use wireguard_netstack::{ManagedTunnel, WgConfigFile, TcpConnection};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Load WireGuard configuration
    let config = WgConfigFile::from_file("wg.conf")?
        .into_wireguard_config()
        .await?;
    
    // Connect (handles all background tasks automatically)
    let tunnel = ManagedTunnel::connect(config).await?;
    
    // Create a TCP connection through the tunnel
    let addr = "93.184.216.34:80".parse()?;
    let conn = TcpConnection::connect(tunnel.netstack(), addr).await?;
    
    // Use the connection...
    conn.write_all(b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n").await?;
    
    // Graceful shutdown
    tunnel.shutdown().await;
    Ok(())
}

Dependencies

~28–45MB
~705K SLoC