flu0r1ne.net/logs/announcing-wg2ndLast Updated: 2023-08-27

Announcing wg2nd: Migrate WireGuard Configurations to networkd

Today, I am excited to release wg2nd, a tool specifically engineered to convert WireGuard configurations from the wg-quick(8) format to systemd-networkd compatible configurations.


wg2nd serves as a bridge to translate wg-quick configurations into networkd configurations without requiring additional setup. networkd is a feature-complete network manager, allowing users greater control over WireGuard tunnels. This tool also addresses potential reliability issues that may arise when networkd interferes with tunnels it doesn't manage. Moreover, wg2nd can batch-convert wg-quick configurations to networkd.

Goals of the Project

  1. Compatibility: wg2nd supports all wg-quick configurations except those that involve PreUp, PostUp, PreDown, and PostDown scripts, which are omitted.

  2. Security: Private and symmetric keys are stored in keyfiles with restricted access permissions. wg2nd leverages the same formally-verified Curve25519 implementation employed in WireGuard. All operations involving private keys are executed in constant-time. Additionally, the web port operates entirely on the client-side. It does not transmit or store any sensitive data.

  3. Reproducibility: wg2nd generates configurations deterministically with respect to the input WireGuard configuration. When updates are made to the WireGuard source configurations, only the corresponding elements in the output will be altered. This ensures that configurations from a VPN provider can be batch-converted without generating unnecessary files or inducing unexpected behavioral changes.

    Keyfiles for both private and symmetric keys are named according to the public key of the relevant interface or peer. These keyfiles are encoded in base32 rather than base64 to avoid issues with the Unix path separator present in base64 encoding. The public key corresponding to a keyfile can be obtained using the following command:

    echo $KEY | sed -E 's/\.(priv|sym)key//' | base32 -d | base64

    This approach effectively ensures that if two interfaces share the same private key, a single shared keyfile will be generated. The fwmark field employs a SipHash of the interface name, enabling the generation of identical network and netdev files across separate program invocations, while minimizing the risk of fwmark collisions.

Compatibility and Limitations

wg2nd is designed for high compatibility but comes with some caveats:

  1. Dynamic Firewall Installation: Unlike wg-quick, which installs a firewall by default when a default route is specified, wg2nd does not. However, an equivalent firewall can be generated if desired.

  2. Pre/Post Interface Setup Scripts: wg2nd does not handle PreUp, PostUp, PreDown, and PostDown script snippets, which wg-quick does recognize.

  3. FwMark and Table Handling: wg2nd uses a deterministic method for generating fwmark based on the interface name. This contrasts with wg-quick, which dynamically checks availability. This deterministic approach is necessary because a static value must be chosen for configuration. However, this could result in a birthday collision if a large number of interfaces are ported. (Such a scenario becomes only remotely probable after porting around 500 interfaces.)

Web Port

The web port has been developed by converting the C / C++ implementation into WebAssembly (WASM). It offers an entirely browser-based experience, converting your WireGuard configurations into a series of Bash commands to configure the interface. This allows you to experiment within your browser.

The code is dual-licensed under the GPL-2.0 and MIT licenses. Feel free to send me patches via email or submit pull requests through GitHub.

For further details, including installation instructions, please consult the project README.

Happy networking!