GotaTun Documentation
repository·main·Indexed 23 days ago
https://github.com/mullvad/gotatunA 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.
What's inside gotatun
- 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).
Cryptographic Implementation Details
mainGotaTun's cryptographic choices are driven by a balance of security and performance:
ringcrate: GotaTun uses theringcrate for ChaCha20-Poly1305. Whileringis an experimental project, it is a de facto standard in the Rust ecosystem. Alternatives likechacha20poly1305(native Rust) resulted in a ~50% drop in throughput, whileaws-lc-rs(maintained by AWS) provides equivalent performance toring.- Decryption and Authentication Order: GotaTun uses
ring'sopen_in_placemethod, which decrypts data before authenticating it. While the cryptographic best practice is to authenticate before operating on data, theringAPI 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.
Configure GotaTun on macOS
mainOn macOS, interface names must follow the
utun[0-9]+pattern.- Use an explicit name like
utun0. - Use
utunto let the kernel select the lowest available interface.
If you use
utunas the interface name and define theWG_TUN_NAME_FILEenvironment variable, GotaTun will write the actual interface name chosen by the kernel to the specified file.- Use an explicit name like
Install GotaTun
mainYou can install GotaTun by building from source using
cargo. The executable will be placed in./target/releaseby default. To install it to your system path, use thecargo installcommand.Alternatively, if you use Nix, you can build the executable using
nix build.Build GotaTun from source
mainYou can build GotaTun usingcargo. You can build just the library or the full executable. Both support specifying a target triple via--target.Run GotaTun as a standalone tunnel
mainTo start a tunnel, run the
gotatunexecutable followed by the desired interface name. You can use the-for--foregroundflag to run in the foreground.Once the tunnel is running, you can configure it using standard WireGuard tools like
wg.gotatun [-f/--foreground] INTERFACE-NAMERoaming Support and Endpoint Updates (Fixed in v0.4.0)
mainGotaTun previously did not update the remote peer's IP address according to the WireGuard specification, which hindered smooth roaming between different IPs. This was resolved in the 0.4.0 release to ensure better roaming support.Peer Identifier Generation and Payload Padding (Fixed in v0.3.0)
mainTwo low-severity issues were identified and resolved in version 0.3.0:
- 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.
- 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.
Configure GotaTun on Linux
mainOn Linux,
gotatundrops privileges by default. When privileges are dropped, it is impossible to setfwmark.If you need to use
fwmark(for example, when usingwg-quick), you must either:- Run with the
--disable-drop-privilegesflag. - Set the
WG_SUDO=1environment variable.
To run the executable without requiring
sudoevery time, grant it theCAP_NET_ADMINcapability:sudo setcap cap_net_admin+epi gotatun.sudo setcap cap_net_admin+epi gotatun- Run with the
Use the Packet type for zero-copy network packet handling
mainThe
Packet<Kind>struct provides a zero-copy way to create, parse, and manipulate network packets. It usesBytesMutas a backing buffer and is generic overKind, 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);- Type Safety: You can cast packets between types (e.g., from raw bytes to an IP packet) using
Configure memory allocators for GotaTun
mainBy default,
gotatunuses the system's default allocator. However, you can enable alternative global memory allocators by enabling specific Cargo features during compilation:mimalloc: Usesmi-mallocas the global memory allocator.jemalloc: Usesjemallocas the global memory allocator (Note: This is currently not available for Windows).
How `UdpChannelFactory` manages UDP endpoints
mainThe
UdpChannelFactoryimplementsUdpTransportFactoryand is used to produceUdpSendandUdpRecvimplementations that communicate via internal channels rather than network sockets.Binding Endpoints
Calling
bindon the factory claims exclusive access to the inner channels for the lifetime of the returnedUdpChannelTx,UdpChannelV6Rx, andUdpChannelV4Rx.Warning: A subsequent call to
bindwill block until the previously bound handles are dropped.Bind Parameters
The
bindmethod takesUdpTransportFactoryParams. If theportin these params is set to0, a random port will be assigned.Returned Types
SendV4/SendV6:UdpChannelTxRecvV4:UdpChannelV4RxRecvV6:UdpChannelV6Rx