TTR Networks

Intermediate · WireGuard on Debian: users, routing and keys · section 5 of 10

Traffic between users

✓ Lab-tested 21 October 2026 on Debian 13.7, wireguard-tools 1.0.20210914, nftables 1.1.3

WireGuard has no equivalent of OpenVPN's client-to-client. Every packet from one user to another arrives on wg0, goes through the server's kernel, and leaves on wg0 again, so the firewall always decides. That's simpler and safer: there's no mode where user-to-user traffic bypasses your rules.

With the lesson's firewall, the branch PC and the office reach each other, but alice can reach neither bob nor the branch LAN: the forward chain's default drop counts those packets.

To allow something specific, add a rule for exactly that. One rule lets alice, and only alice, reach the branch LAN; alice to bob is still dropped. Because cryptokey routing guarantees that packets from 10.9.0.10 really came from alice's key, a firewall rule on her VPN address is a rule about her.

The branch and the office, and alice blocked (real output)
root@branchpc:~# ping -c 2 -W 1 10.10.0.20
PING 10.10.0.20 (10.10.0.20) 56(84) bytes of data.
64 bytes from 10.10.0.20: icmp_seq=1 ttl=61 time=0.262 ms
64 bytes from 10.10.0.20: icmp_seq=2 ttl=61 time=1.20 ms

--- 10.10.0.20 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1012ms
rtt min/avg/max/mdev = 0.262/0.731/1.201/0.469 ms

root@office:~# ping -c 3 -W 2 10.20.0.10
PING 10.20.0.10 (10.20.0.10) 56(84) bytes of data.
64 bytes from 10.20.0.10: icmp_seq=1 ttl=62 time=0.273 ms
From 10.10.0.254 icmp_seq=2 Redirect Host(New nexthop: 10.10.0.1)
64 bytes from 10.20.0.10: icmp_seq=2 ttl=62 time=0.374 ms

--- 10.20.0.10 ping statistics ---
2 packets transmitted, 2 received, +1 errors, 0% packet loss, time 1053ms
rtt min/avg/max/mdev = 0.273/0.323/0.374/0.050 ms

root@alice:~# ping -c 2 -W 1 10.20.0.10; ping -c 2 -W 1 10.9.0.11
PING 10.20.0.10 (10.20.0.10) 56(84) bytes of data.

--- 10.20.0.10 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1059ms

PING 10.9.0.11 (10.9.0.11) 56(84) bytes of data.

--- 10.9.0.11 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1044ms


root@vpn:~# nft list chain inet filter forward | grep -E "counter"
		counter packets 4 bytes 336 comment "everything else, including user to user, is dropped"
  • Lines 1–8: A branch PC reaches the office: branch router, tunnel, VPN server, office LAN.
  • Lines 10–18: And back. lanrtr forwards the first packet, then tells the office host (an ICMP redirect) to use the VPN server directly.
  • Lines 20–29: alice can reach neither the branch LAN nor bob.
  • Lines 32–33: Four packets: alice's two pings to each. The default drop decided.
Allowing alice, and only alice, to the branch (real output)
root@vpn:~# nft insert rule inet filter forward iifname "wg0" oifname "wg0" ip saddr 10.9.0.10 ip daddr 10.20.0.0/24 counter accept comment \"alice to the branch LAN\"

root@alice:~# ping -c 2 -W 1 10.20.0.10; ping -c 2 -W 1 10.9.0.11
PING 10.20.0.10 (10.20.0.10) 56(84) bytes of data.
64 bytes from 10.20.0.10: icmp_seq=1 ttl=62 time=0.450 ms
64 bytes from 10.20.0.10: icmp_seq=2 ttl=62 time=1.75 ms

--- 10.20.0.10 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1050ms
rtt min/avg/max/mdev = 0.450/1.101/1.753/0.651 ms
PING 10.9.0.11 (10.9.0.11) 56(84) bytes of data.

--- 10.9.0.11 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1020ms


root@vpn:~# nft list chain inet filter forward | grep -E "counter"
		iifname "wg0" oifname "wg0" ip saddr 10.9.0.10 ip daddr 10.20.0.0/24 counter packets 2 bytes 168 accept comment "alice to the branch LAN"
		counter packets 2 bytes 168 comment "everything else, including user to user, is dropped"
  • Line 1: insert puts the rule at the top of the chain, before the final counter.
  • Lines 3–14: alice reaches the branch PC, and still not bob.
  • Lines 18–19: Two packets accepted by the new rule, two (to bob) dropped.

Check your understanding

Why is a firewall rule matching ip saddr 10.9.0.10 on packets from wg0 a trustworthy rule about alice?

  • Because WireGuard only accepts 10.9.0.10 from alice's key, so no other user can send from it.
  • Because the address is fixed in alice's config.
  • Because nftables checks WireGuard keys.
  • It isn't; anyone could use that address.