Understanding WireGuard's AllowedIPs setting (and a bit of tcpdump)

January 14, 2021

WireGuard is usually described as a VPN, but it's really a secure IP tunnel system with VPNs as the most common use; I've been using WireGuard on Linux for a while. One of the settings you configure for WireGuard peers is AllowedIPs, which back in 2017 I described vaguely as that it '[...] controls which traffic is allowed to flow inside the secure tunnel'. Recently I had an opportunity to discover that my understanding of AllowedIPs was incomplete, so here is a more precise and verbose version.

I'll start by quoting the current wg(8) manpage:

AllowedIPs — a comma-separated list of IP (v4 or v6) addresses with CIDR masks from which incoming traffic for this peer is allowed and to which outgoing traffic for this peer is directed.

As the manual page says, AllowedIPs affects both incoming traffic from your peers and outgoing traffic to your peers. For incoming traffic from a peer, the AllowedIPs setting determines what source IP addresses the traffic can have. Packets from a peer that have an IP source address that's not in the peer's AllowedIPs will be silently dropped by WireGuard.

(WireGuard knows which peer an incoming packet is from because of the cryptography involved.)

For outgoing traffic, the AllowedIPs setting determines which peer a packet will be sent to, based on the packet's destination address. If there is no peer that matches the destination address, the WireGuard interface will reject the packet at the IP level, possibly generating an ICMP message to that effect that it sends to the source IP. If you're using ping on the same machine, it will probably report 'ping: sendmsg: Required key not available'.

How AllowedIPs affects incoming traffic is basically a safety feature; I see it as a form of firewalling. How AllowedIPs affects outgoing traffic is essential, since you can have multiple peers attached to a single WireGuard interface and thus have to pick which peer a given packet will be sent to. I believe that AllowedIPs can't overlap between peers on the same WireGuard interface, but I haven't tested it.

(You can have multiple WireGuard interfaces, each with different peers, and I believe you can duplicate AllowedIPs ranges between peers on different WireGuard interfaces. Getting the right traffic to the right WireGuard interface is up to you; you may need policy based routing or perhaps network namespaces.)

By itself, configuring AllowedIPs for a peer on a particular WireGuard interface doesn't cause the Linux kernel to actually route traffic for that IP address range to the WireGuard interface; where traffic for an IP address range is routed is separate from what peers are configured. You can route traffic to a WireGuard interface without peers configured to handle it, and configure a wider AllowedIPs for a peer than you route traffic to the WireGuard interface.

If you're receiving WireGuard traffic, your AllowedIPs doesn't restrict what destination IP addresses the traffic can have. If your peer configured its peer entry for you with an AllowedIPs of, it can send you traffic with any random destination IP it feels like. Similarly, if you're sending WireGuard traffic to a peer, that traffic can have any source IP address you want, although the peer will drop it if it's not in their AllowedIPs for you.

If you use 'tcpdump' on a WireGuard interface to test all of this, the traffic you see is conceptually outside WireGuard itself. For outgoing packets, what you see is before WireGuard has picked which peer the packet will be sent to or rejected it because no peer matches. For incoming packets, what you see is after WireGuard has dropped packets for having a source IP that doesn't match the peer's AllowedIPs. This means that outgoing packets may not actually be sent, but incoming packets have definitely been accepted (well, by WireGuard).

(I don't know if there's any easy way to see if WireGuard has dropped some incoming packets because they don't match the peer's AllowedIPs. I suppose you could try to correlate the arrival of encrypted WireGuard packets from a peer's current IP with a lack of packets showing up on the WireGuard interface.)

Comments on this page:

From at 2021-01-17 05:51:06:

I don't know if there's any easy way to see if WireGuard has dropped some incoming packets because they don't match the peer's AllowedIPs.

This is logged to dmesg at pr_debug level, as soon as you enable it through the kernel's "dynamic debug" system:

echo "module wireguard +p" > /sys/kernel/debug/dynamic_debug/control

You should then start seeing "Packet has unallowed src IP (%pISc) from peer..." in dmesg. There is also a similar message for outgoing packets, as well as a bunch of other interesting stuff – the ones related to failing handshakes are particularly useful.

From at 2021-01-17 05:59:37:

Oh, and even besides debug, the driver does increment rx_err in this case so you can get the RX error counter from ip -s link. There are three checks performed, but the other two seem extremely unlikely to come from a normal peer, so it may be safe to assume rx_err just counts AllowedIPs mismatches.

Written on 14 January 2021.
« Installing Pip in Python 2 environments that don't provide it already
SMART attributes can predict SSD failures under the right circumstances »

Page tools: View Source, View Normal, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Thu Jan 14 23:57:24 2021
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.