GotaTun Documentation

repository·main·Indexed 23 days ago

https://github.com/mullvad/gotatun

A userspace implementation of the WireGuard® protocol and fork of BoringTun designed for portability and speed. GotaTun allows running WireGuard tunnels on platforms without kernel support and can be used as a standalone tunnel or integrated with wg-quick. The library provides a DeviceBuilder for configuring UDP transport, TUN interfaces, and peer identities, as well as a callback-based API for managing device state and statistics.

Tokens
14K
Snippets
11
Records
72
Agent score
80%

What's inside gotatun

  1. Security Audit Overview (2026-02-17)

    main
    GotaTun underwent a security audit by Assured in February 2026. The audit identified 12 findings: 1 'good' finding regarding compile-time size checks, 2 'low' severity issues (peer identifier generation and payload padding), and 9 'notes' covering topics like memory protection, dependency management, and cryptographic implementation details. Most identified issues have been addressed in subsequent releases (v0.3.0 and v0.4.0).
  2. Cryptographic Implementation Details

    main

    GotaTun's cryptographic choices are driven by a balance of security and performance:

    • ring crate: GotaTun uses the ring crate for ChaCha20-Poly1305. While ring is an experimental project, it is a de facto standard in the Rust ecosystem. Alternatives like chacha20poly1305 (native Rust) resulted in a ~50% drop in throughput, while aws-lc-rs (maintained by AWS) provides equivalent performance to ring.
    • Decryption and Authentication Order: GotaTun uses ring's open_in_place method, which decrypts data before authenticating it. While the cryptographic best practice is to authenticate before operating on data, the ring API prevents access to data if authentication fails, mitigating practical risks. This approach is also used by the Linux Kernel WireGuard implementation.
    • IP Packet Checksums: GotaTun skips IP packet checksum verification after decryption because the successful authentication step ensures the packet is intact, matching the behavior of the Linux Kernel WireGuard implementation.
  3. Configure GotaTun on macOS

    main

    On macOS, interface names must follow the utun[0-9]+ pattern.

    • Use an explicit name like utun0.
    • Use utun to let the kernel select the lowest available interface.

    If you use utun as the interface name and define the WG_TUN_NAME_FILE environment variable, GotaTun will write the actual interface name chosen by the kernel to the specified file.

  4. Install GotaTun

    main

    You can install GotaTun by building from source using cargo. The executable will be placed in ./target/release by default. To install it to your system path, use the cargo install command.

    Alternatively, if you use Nix, you can build the executable using nix build.

  5. Run GotaTun as a standalone tunnel

    main

    To start a tunnel, run the gotatun executable followed by the desired interface name. You can use the -f or --foreground flag to run in the foreground.

    Once the tunnel is running, you can configure it using standard WireGuard tools like wg.

    gotatun [-f/--foreground] INTERFACE-NAME
  6. Peer Identifier Generation and Payload Padding (Fixed in v0.3.0)

    main

    Two low-severity issues were identified and resolved in version 0.3.0:

    1. Peer Identifiers: Previously, GotaTun did not generate random 32-bit peer identifiers as required by the WireGuard specification, which could potentially reveal information about peer counts and handshake frequency. This was fixed in release 0.3.0.
    2. Payload Padding: GotaTun previously did not pad payloads to a multiple of 16 bytes before encryption, which is recommended by the WireGuard specification to complicate traffic analysis. This was implemented in release 0.3.0.

    Note: For sophisticated traffic analysis protection, Mullvad recommends enabling DAITA functionality.

  7. Configure GotaTun on Linux

    main

    On Linux, gotatun drops privileges by default. When privileges are dropped, it is impossible to set fwmark.

    If you need to use fwmark (for example, when using wg-quick), you must either:

    1. Run with the --disable-drop-privileges flag.
    2. Set the WG_SUDO=1 environment variable.

    To run the executable without requiring sudo every time, grant it the CAP_NET_ADMIN capability: sudo setcap cap_net_admin+epi gotatun.

    sudo setcap cap_net_admin+epi gotatun
  8. Use the Packet type for zero-copy network packet handling

    main

    The Packet<Kind> struct provides a zero-copy way to create, parse, and manipulate network packets. It uses BytesMut as a backing buffer and is generic over Kind, which represents the packet type (e.g., [u8], Ipv4, Udp).

    Key behaviors:

    • Type Safety: You can cast packets between types (e.g., from raw bytes to an IP packet) using try_into_* methods.
    • Zero-Copy: Many operations, such as stripping headers with into_payload, simply advance the internal buffer pointer rather than copying data.
    • Memory Management: When used with a PacketBufPool, packets can be configured to automatically return their buffer to the pool when dropped.

    To work with raw bytes, start with Packet<[u8]> and use decoding methods to transition to structured types.

    use gotatun::packet::Packet;
    use std::net::Ipv4Addr;
    use zerocopy::IntoBytes;
    
    let ip_header = Ipv4Header::new(
        Ipv4Addr::new(10, 0, 0, 1),
        Ipv4Addr::new(1, 2, 3, 4),
        IpNextProtocol::Icmp,
        &[],
    );
    
    let ip_header_bytes = ip_header.as_bytes();
    
    // Create an owned packet from bytes
    let raw_packet: Packet<[u8]> = Packet::copy_from(ip_header_bytes);
    
    // Transition to a structured IPv4 packet
    let ipv4_packet: Packet<Ipv4> = raw_packet.try_into_ipvx().unwrap().unwrap_left();
    assert_eq!(&ip_header, &ipv4_packet.header);
  9. Configure memory allocators for GotaTun

    main

    By default, gotatun uses the system's default allocator. However, you can enable alternative global memory allocators by enabling specific Cargo features during compilation:

    • mimalloc: Uses mi-malloc as the global memory allocator.
    • jemalloc: Uses jemalloc as the global memory allocator (Note: This is currently not available for Windows).
  10. How `UdpChannelFactory` manages UDP endpoints

    main

    The UdpChannelFactory implements UdpTransportFactory and is used to produce UdpSend and UdpRecv implementations that communicate via internal channels rather than network sockets.

    Binding Endpoints

    Calling bind on the factory claims exclusive access to the inner channels for the lifetime of the returned UdpChannelTx, UdpChannelV6Rx, and UdpChannelV4Rx.

    Warning: A subsequent call to bind will block until the previously bound handles are dropped.

    Bind Parameters

    The bind method takes UdpTransportFactoryParams. If the port in these params is set to 0, a random port will be assigned.

    Returned Types

    • SendV4 / SendV6: UdpChannelTx
    • RecvV4: UdpChannelV4Rx
    • RecvV6: UdpChannelV6Rx