WireGuard
WireGuard is a L3 connection-less tunnel protocol, based on UDP.
- After a 1-RTT handshale, packets will be encrypted and transmitted in WireGuard Transport Data messages. No additional messages needed.
- The transport data message takes 16Bytes, the UDP header takes 8, and the IP header takes 20 (or 40 for IPv6), leaving MTU = 1440 or 1420 (IPv6).
- No server / client distinction. Peers are identified via public keys.
- Peers may roam to whatever IP they want as long as they handshake with the same public key.
- Only one side of the tunnel needs a public IP address.
- Multiple peers per interface possible, with crypto-based internal routing and allowed IPs filter.
For the Linux implementation:
- WireGuard interfaces are just represented as Linux virtual interfaces, and they can be managed using iproute2 and wg(1).
- Has very well support for network namespaces.
- Do not work well with vrf.
- Could be hard to debug.
Basic Operation
Setup the interface and address with ordinary Linux network management tools, e.g. iproute2:
$ ip l add dev wg0 type wireguard
$ ip l set dev wg0 up
$ ip a add dev wg0 ...
Set WireGuard-specific options using wg(1)
:
$ wg
$ wg set nic listen-port uint16_t
$ wg set nic private-key /path/to/private-key
$ wg set peer public-key preshared-key /path/to/preshared-key
$ wg set peer public-key endpoint ip:port
$ wg set peer public-key persistent-keepalive intervals
$ wg set peer public-key allowed-ips ip/cidr
$ wg set peer public-key remove
Crypto Routing and Allowed IPs
Give a WireGuard NIC a block of IP address, and specify allowed ranges of each peer. Packets will be routed to peers based on allowed IPs. This does not go through system routing table.
TODO
Network Namespace
WireGuard will continue to listen on the originating network namespace after it
is moved to new namespaces. That is, for example, you want WireGuard to bind to
an Ethernet interface, but you want to route packets in a netns from / to the
WireGuard interface, but that Ethernet interface is not in the netns. You can
just create the WireGuard interface in the netns that has the Ethernet NIC, and
use ip l set dev NIC netns NETNS
to move that into the specific netns.
See wireguard.com/netns.
fwmark
TODO
wg-quick(1)
A bash script that takes the input configuration file and automatically invokes ip-link(1), ip-addr(1), wg(1), ip-route(1), and resolvconf(1). It is a oneshot script: it will exit after applying the configuration.
It doesn't support network namespaces. You can do ip-link(1) yourself and patch wg-quick(1) to ignore creating the WireGuard interface.
Sample configuration:
# /path/to/wg0.conf
[Interface]
Address =
PrivateKey = private-key
ListenPort = port
# Table = off
# DNS =
[Peer]
PublicKey = public-key
AllowedIPs = cidr, cidr, cidr
PersistentKeepalive =
Endpoint = ip:port
Note that when using its systemd service, the file has to exist when stopping the service, otherwise the stop command will fail and you have to clear the failed unit yourself.
Debugging
Could be hard though. Good luck with tcpdump(1).
For kernel module debug logs:
$ modprobe wireguard
$ echo module wireguard +p > /sys/kernel/debug/dynamic_debug/control
Created: November 5, 2023