Wireguard with systemd and nftables
Hi;
I am trying to configure Wireguard VPN using systemd.networkd on a Server with NFTables as a firewall.
These are the files of my configuration:
I am still not able to connect a client successfully nor get internet access.
Can you point me in the right direction?
Thank you in advance.
I am trying to configure Wireguard VPN using systemd.networkd on a Server with NFTables as a firewall.
These are the files of my configuration:
/etc/systemd/network/def_if.network
[Match]
MACAddress=52:54:00:12:12:12
[Network]
Description=Underlying main ethernet interface
Bridge=br0
LinkLocalAddressing=no
/etc/systemd/network/br0.netdev
[NetDev]
Description=Main bridge interface
Name=br0
Kind=bridge
/etc/systemd/network/br0.network
[Match]
Name=br0
[Link]
MACAddress=52:54:00:12:12:12
[Network]
Description=Main bridge interface
Address=2a01:4f8:10a:68b::15/64
Address=88.99.30.87/27
Gateway=fe80::1
Gateway=148.251.52.1
IPv6AcceptRA=no
IPForward=yes
IPMasquerade=yes
/etc/systemd/network/wg0.netdev
[NetDev]
Name=wg0
Kind=wireguard
Description=Wireguard VPN
[WireGuard]
PrivateKey=sKEIBk773uHzTMEVayvzC0n7UslviO8yj/j7dU7+ANWc=
ListenPort=51820
[WireGuardPeer]
PublicKey=ImVcJRxLrjTEJ62rLwLEGxgT5E4iOA5zth9NDeappA0=
AllowedIPs=0.0.0.0/0,::/0
EndPoint=192.168.129.129/32 [fdf6:fd:f6:fdf6::aa13]/128
PresharedKey=OdGpK/xuTJtiH6Nc12xEQ99sooFJz3x8tveU84czrQ8=
/etc/systemd/network/wg0.network
[Match]
Name=wg0
[Network]
Address=192.168.129.220/24
Address=fdf6:fd:f6:fdf6::3003/72
DNS=192.168.129.129
IPForward=yes
IPMasquerade=yes
/etc/nftables/inet-filter.nft
table inet filter {
chain input {
type filter hook input priority 0; policy drop
ct state invalid drop
ct state established accept
ct state related accept
iifname lo accept;
iifname wg0 accept
ip protocol icmp icmp type { echo-request, destination-unreachable } counter packets 0 bytes 0 accept;
ip6 nexthdr ipv6-icmp accept
icmpv6 type { nd-neighbor-advert, nd-neighbor-solicit, nd-router-advert, destination-unreachable} ip6 hoplimit 255 counter accept
udp dport { 51820 } accept;
}
chain forward {
type filter hook forward priority 0; policy drop
iifname br0 oifname wg0 accept comment "wireguard wg0"
iifname wg0 oifname br0 accept comment "Wireguard wg0"
log
}
chain output {
type filter hook output priority 0; accept
oifname wg0 accept
oifname lo accept
log
}
I am still not able to connect a client successfully nor get internet access.
Can you point me in the right direction?
Thank you in advance.
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 92586419613
Url: https://administrator.de/contentid/92586419613
Ausgedruckt am: 23.11.2024 um 16:11 Uhr
21 Kommentare
Neuester Kommentar
The above configuration is very weired and totally different from a standard Wireguard configuration. Why didnt you use the classical approach with a text config file in /etc/wireguard which is fully integrated into systemd as well?? It makes a WG setup much easier and quicker.
All steps are described HERE. Unfortunately in German but maybe a translation tool can help here.
You should also start in a strategic way which means setup your VPN connection first without nftables running to make sure you do not step into firewall issues.
In case the VPN connection runs fine you should activate the firewall. So you can make sure any possible malfunction could only be a firewall misconfiguration and NOT the VPN itself.
Your correct nftables setup is based on how your WG server looks like (interface etc.). You can find some good examples here:
https://www.procustodibus.com/blog/2021/11/wireguard-nftables/
But keep in mind: First VPN checks always without firewall.
All steps are described HERE. Unfortunately in German but maybe a translation tool can help here.
You should also start in a strategic way which means setup your VPN connection first without nftables running to make sure you do not step into firewall issues.
In case the VPN connection runs fine you should activate the firewall. So you can make sure any possible malfunction could only be a firewall misconfiguration and NOT the VPN itself.
Your correct nftables setup is based on how your WG server looks like (interface etc.). You can find some good examples here:
https://www.procustodibus.com/blog/2021/11/wireguard-nftables/
But keep in mind: First VPN checks always without firewall.
You have forgotten to add a real network adapter to the bridge! A bridge alone without hardware has no contact to the outside world 🤪.
So add another *.network file for the real Ethernet adapter which makes it a member of the bridge.
Regards
So add another *.network file for the real Ethernet adapter which makes it a member of the bridge.
[Match]
Name=eth0
[Network]
Bridge=br0
Regards
There is another catastrophic failure here, private IPs as Endpoint addresses does not make any sense when connecting from the outside world ... also a missing comma delimiter, and the brackets for the IPv6 address are obsolete:
The IPs have to be in the AllowedIPs not in the Endpoint on the Server-Side!
The peer section should look like this
AllowedIPs=0.0.0.0/0,::/0
EndPoint = 192.168.129.129/32 [fdf6:fd:f6:fdf6::aa13]/128
EndPoint = 192.168.129.129/32 [fdf6:fd:f6:fdf6::aa13]/128
The IPs have to be in the AllowedIPs not in the Endpoint on the Server-Side!
The peer section should look like this
[WireGuardPeer]
PublicKey=xxxxxxxxx
AllowedIPs=192.168.129.129/32, fdf6:fd:f6:fdf6::aa13/128
PresharedKey=xxxxxxxxx
Zitat von @Linuxero:
On the server I can see this in dmesg output:
[718058.070069] IN=br0 OUT= PHYSIN=eth0 MAC=xx:xx:xx:xx:xx:xx:yy:yy:yy:yy:yy:yy:00:00 SRC=xxx.xxx.xxx.xxx DST=xxx.xxx.xxx.xxx LEN=63 TOS=0x00 PREC=0x00 TTL=57 ID=28320 DF PROTO=UDP SPT=58024 DPT=51820 LEN=43
...
[718258.873489] IN=br0 OUT= PHYSIN=eth0 MAC=xx:xx:xx:xx:xx:xx:yy:yy:yy:yy:yy:yy:00:00 SRC=xxx.xxx.xxx.xxx DST=xxx.xxx.xxx.xxx LEN=54 TOS=0x00 PREC=0x00 TTL=57 ID=33109 DF PROTO=UDP SPT=60888 DPT=51820 LEN=34
On the server I can see this in dmesg output:
[718058.070069] IN=br0 OUT= PHYSIN=eth0 MAC=xx:xx:xx:xx:xx:xx:yy:yy:yy:yy:yy:yy:00:00 SRC=xxx.xxx.xxx.xxx DST=xxx.xxx.xxx.xxx LEN=63 TOS=0x00 PREC=0x00 TTL=57 ID=28320 DF PROTO=UDP SPT=58024 DPT=51820 LEN=43
...
[718258.873489] IN=br0 OUT= PHYSIN=eth0 MAC=xx:xx:xx:xx:xx:xx:yy:yy:yy:yy:yy:yy:00:00 SRC=xxx.xxx.xxx.xxx DST=xxx.xxx.xxx.xxx LEN=54 TOS=0x00 PREC=0x00 TTL=57 ID=33109 DF PROTO=UDP SPT=60888 DPT=51820 LEN=34
Normal, you forgott to add established related traffic to the forward chain as well as you block local forward traffic, so you only have a statefull firewall on the input chain but not the forward chain 😉.
As @aqui said, first bring up your tunnel successfully and after that your firewall.
This will do the job for your scenario (tested successfully in a VM with above systemd config)
#!/usr/bin/nft -f
flush ruleset
table inet filter {
chain INPUT {
type filter hook input priority 0; policy drop;
ct state vmap { established : accept, related : accept, invalid : drop }
ip6 saddr ::1 ip6 daddr ::1 counter accept
iifname vmap { "lo" : accept, "br0" : jump INPUT_WAN, "wg0" : accept }
log
}
chain FORWARD {
type filter hook forward priority 0; policy drop;
ct state vmap { established : accept, related : accept, invalid : drop }
ct status dnat counter accept
iifname vmap { "lo" : accept, "br0" : drop, "wg0" : accept }
log
}
chain OUTPUT {
type filter hook output priority 0; policy accept;
}
chain INPUT_WAN {
# icmpv6
icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem } counter accept
icmpv6 type { nd-neighbor-solicit,nd-neighbor-advert } ip6 hoplimit 255 counter accept
# icmpv4
icmp type { destination-unreachable, echo-request } limit rate 5/second accept
# wireguard
udp dport 51820 counter accept
}
}
table inet nat {
chain PREROUTING {
type nat hook prerouting priority -100; policy accept;
}
chain POSTROUTING {
type nat hook postrouting priority 100; policy accept;
oifname br0 counter masquerade
}
}
I have seen that this thread is marked as solved, but it is sadly not
Due to good reasons this can ONLY be done by YOU as the threadowner!If you do not want it to be marked as "solved" YOU can always change it by yourself using the Edit/Bearbeiten button!
I cannot use the peer as a gateway or dns.
What do you exactly mean with "gateway"? In general WG has only 2 options as all VPNs have it:- Split Tunneling = only relevant traffic is routed into the tunnel which is done by WG's own crypto routing and declared by the IP networks under "AllowedIPs"
- Gateway Redirect = All traffic is by default routed into the tunnel (default gateway) in case the peer is active and established.
Gateway redirect implies also a DNS traffic redirect, because it includes of course TCP and UDP 53 traffic as well as all other traffic. Here you have to take care by yourself that your configured DNS servers are fully reachable over the tunnel.
In case of split tunneling you declare an alternative DNS server who will be active when the peer is established with the extra "dns" parameter.
"ip r" as well as dig and host are your best friends (dnsutils, bindutils) to check this.
Zitat von @aqui:
As you can see in the above routing table: 192.168.11.1 is the default gateway in case the client is active, cause it has the highest routing metric and is most likeley your WG server IP address or HAS to be the WG server address!
I think this can only be a firewall issue now
Definitely!As you can see in the above routing table: 192.168.11.1 is the default gateway in case the client is active, cause it has the highest routing metric and is most likeley your WG server IP address or HAS to be the WG server address!
With
ip r
you cannot see the wireguard rules!!When wireguard default redirect is enabled the rule is not listet in the main routing table but in another one with higher precedence to which the traffic is redirected by a firewall mark! The main table does not list this, but using
ip route list table all
does. And ip rule show
lists the rules which redirect to the tables.Another error lies here:
[Network]
Address=192.168.129.220/24
Address=fdf6:fd:f6:fdf6::3003/72
DNS=192.168.129.129
IPForward=yes
IPMasquerade=yes
Address=192.168.129.220/24
Address=fdf6:fd:f6:fdf6::3003/72
DNS=192.168.129.129
IPForward=yes
IPMasquerade=yes
The DNS-Line is wrong. You have set the DNS Server for the Wireguard interface to the client address! Just remove the line and only set this on the client WG config
A DNS address should only be set on the WAN Interface and on the client wireguard config not on the WG interface of the server itself. WG has no DHCP so it does not distribute this setting to the clients !
I tested the config from the user above who posted the firewall sample and it is definitely working if you fix the DNS error .
I will post my complete working config later on.
With ip r you cannot see the wireguard rules!!
Are you sure? If you issue a wg-quick down wg0
all WG related routing entries are gone in the main table even with the short ip r
. So i guess ip r
shows some basic WG routing rules as well. The longer version just shows some more detailed local connected interface, broad- and multicast rules on top but the major rules are shown with ip r
as well.
Without a doubt!
If you issue a
But only the basic routes for the tunnel-subnet itself, if you use a gateway redirect these are set in a separate routing table and the traffic is marked with firewall marks to flow through the created table!wg-quick down wg0
all WG related routing entries are gone in the main table even with the short ip r
. So i guess ip r
shows some basic WG routing rules as well.
As promised here is my working setup for the TO:
IPv4 and IPv6 addresses and gateways on WAN bridge are set manually without using DHCP or RA as in your setup above, so router advertisements are not needed and disabled on the bridge and in the firewall.
Just works 100% as promised ! 👍
Good luck
Systemd-Networkd Setup
br0
= Bridge to WANeth0
= Member of bridge br0
WAN facingwg0
= Wireguard interfaceIPv4 and IPv6 addresses and gateways on WAN bridge are set manually without using DHCP or RA as in your setup above, so router advertisements are not needed and disabled on the bridge and in the firewall.
/etc/systemd/network/10-br0.netdev
[NetDev]
Name=br0
Kind=bridge
/etc/systemd/network/20-br0.network
[Match]
Name=br0
[Network]
Address=1.2.3.4/24
Gateway=1.2.3.1
Address=2a00:1111:2222::1/64
Gateway=fe80::1
DNS=1.1.1.1
IPv6AcceptRA=no
IPForward=yes
/etc/systemd/network/30-eth0.network
[Match]
Name=eth0
[Network]
Bridge=br0
/etc/systemd/network/40-wg0.netdev
[NetDev]
Name=wg0
Kind=wireguard
[WireGuard]
PrivateKey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ListenPort=51820
[WireGuardPeer]
PublicKey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
AllowedIPs=10.80.0.2/32,fd99:bade:affe::2/128
/etc/systemd/network/50-wg0.network
[Match]
Name=wg0
[Network]
Address=10.80.0.1/24
Address=fd99:bade:affe::1/64
IPForward=yes
NFTables Firewall Config
#!/usr/bin/nft -f
flush ruleset
table inet filter {
chain INPUT {
type filter hook input priority 0; policy drop;
ct state vmap { established : accept, related : accept, invalid : drop }
ip6 saddr ::1 ip6 daddr ::1 counter accept
iifname vmap { "lo" : accept, "br0" : jump INPUT_WAN, "wg0" : accept }
log
}
chain FORWARD {
type filter hook forward priority 0; policy drop;
ct state vmap { established : accept, related : accept, invalid : drop }
ct status dnat counter accept
iifname vmap { "lo" : accept, "br0" : drop, "wg0" : accept }
log
}
chain OUTPUT {
type filter hook output priority 0; policy accept;
}
chain INPUT_WAN {
# icmpv6
icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem } counter accept
icmpv6 type { nd-neighbor-solicit,nd-neighbor-advert} ip6 hoplimit 255 counter accept
# icmpv4
icmp type { destination-unreachable, echo-request } limit rate 5/second accept
# wireguard
udp dport 51820 counter accept
}
}
table inet nat {
chain PREROUTING {
type nat hook prerouting priority -100; policy accept;
}
chain POSTROUTING {
type nat hook postrouting priority 100; policy accept;
oifname br0 counter masquerade
}
}
Wireguard Client config
[Interface]
PrivateKey=xxxxxxxxxxxxxxxxxxxxxxxxxxx
Address=10.80.0.2/24, fd99:bade:affe::2/64
DNS=1.1.1.1
[Peer]
PublicKey=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
AllowedIPs=0.0.0.0/0, ::/0
Endpoint=1.2.3.4:51820
PersistentKeepalive=25
Test from client
Just works 100% as promised ! 👍
Good luck