Wireguard "server" routing with PBR

Hi. I have wireguard interface as a VPN server on my router. I also have a PBR service that routes my LAN traffic to the internet. I would like to apply the PBR rules to WG clients traffic. How can this be achieved? Thanks.

Your WG clients enter your network with their WG address (the address which is set in the Allowed IP of the Peer).
This address can be used to restrict/allow access to certain things on your network.

The LAN clients on your network should have their own firewall which should block all traffic from non local origin so also from your WG clients (unless you enabled Masquerading on the LAN zone).

So bottom line if access restrictions is what you want you should look into the firewall and not so much into routing.

Any special access restrictions you want or is it something else you desire?

It has been noticed that PBR doesn't cope well with the locally generated traffic of Wireguard. You can see from other topics that it is better solution to manually setup an ip rule to capture the WG traffic (by source port) and lookup from the routing table for the wan connection.

1 Like

I just want my WG clients to be able to access the internet through PBR.

I have some interfaces:

  • LAN
  • WAN
  • VPN (client)
  • WG (server)

For now PBR route my LAN traffic through WAN or VPN
My goal is to route all my outgoing traffic (LAN and WG) according to the same rules.

Are you saying that the only option is to set the entire routing manually without PBR?

I'm saying that you should use ip rule for classifying the WG server and route it over the wan link.

You probably already found it but regarding PBR see:

It finally dawns on me what it is you want.

But first pay attention to @trendy 's remark.
You are running a VPN server and client on the same router, which could be troublesome.
In order to connect to your WG server, traffic comes in via the WAN but should also go out via the WAN.
A VPN client might route everything out via the VPN so you cannot connect to your WG-server.
To make sure the WG-server always uses the WAN for its outgoing traffic you have to make in ip rule, see: No Wireguard handshake outside local network // Firewall help - #5 by egc

With that out of the way you are free to use whatever PBR and setup you want.

Traffic from your WG clients which connect from outside to your WG server have the source address of the WG client, that source address can be used to make a PBR routing rule.

As @trendy remarked it is possible this does not work (I will test it shortly but @trendy is the superior authority) and that you have to revert to making an ip rule just as described for your WG server above.

But we have not seen any configs so the above are just some general recommendation.
If it does not work then post configs:

Please copy the output of the following commands and post it here using the "Preformatted text </> " button.
Remember to redact passwords, MAC addresses and any public IP addresses you may have:

cat /etc/config/network
cat /etc/config/dhcp
cat /etc/config/firewall
cat /etc/config/pbr
ip ro
ip route show table all
ip ru
wg show

Thank you for the detailed answer.

This is the current behavior. All outgoing WG traffic goes to WAN and I have no problems connecting to the server. But I need PBR to control where the traffic is going. This works for the LAN traffic but not for WG.

root@OpenWrt:~# cat /etc/config/network

config interface 'loopback'
        option device 'lo'
        option proto 'static'
        option ipaddr '127.0.0.1'
        option netmask '255.0.0.0'

config globals 'globals'
        option ula_prefix 'fdae:2a5b:d9eb::/48'
        option packet_steering '1'

config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'lan1'
        list ports 'lan2'
        list ports 'lan3'

config interface 'lan'
        option device 'br-lan'
        option proto 'static'
        option ipaddr '192.168.1.1'
        option netmask '255.255.255.0'
        option ip6assign '60'
        list dns '192.168.1.1'

config interface 'wan'
        option device 'lan0'
        option proto 'dhcp'
        option peerdns '0'
        list dns '192.168.1.4'

config interface 'wgc'
        option proto 'wireguard'
        option private_key '...'
        list addresses '10.8.1.2'
        option defaultroute '0'

config wireguard_wgc
        option description 'VPS'
        option public_key '...'
        list allowed_ips '0.0.0.0/0'
        option route_allowed_ips '1'
        option endpoint_host '...'
        option endpoint_port '...'

config interface 'wgs'
        option proto 'wireguard'
        option private_key '...'
        option listen_port '...'
        list addresses '10.8.0.1'
        option defaultroute '0'
        list dns '192.168.1.4'

config wireguard_wgs
        option description ''
        option public_key '...'
        list allowed_ips '10.8.0.5/32'
        option route_allowed_ips '1'

----------------------------------------------------------------

root@OpenWrt:~# cat /etc/config/dhcp

config dnsmasq
        option domainneeded '1'
        option localise_queries '1'
        option rebind_protection '1'
        option rebind_localhost '1'
        option local '/lan/'
        option domain 'lan'
        option expandhosts '1'
        option cachesize '1000'
        option authoritative '1'
        option readethers '1'
        option leasefile '/tmp/dhcp.leases'
        option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto'
        option localservice '1'
        option ednspacket_max '1232'

config dhcp 'lan'
        option interface 'lan'
        option start '100'
        option limit '150'
        option leasetime '12h'
        option dhcpv4 'server'
        option dhcpv6 'server'
        option ra 'server'
        list ra_flags 'managed-config'
        list ra_flags 'other-config'

config dhcp 'wan'
        option interface 'wan'
        option ignore '1'

config odhcpd 'odhcpd'
        option maindhcp '0'
        option leasefile '/tmp/hosts/odhcpd'
        option leasetrigger '/usr/sbin/odhcpd-update'
        option loglevel '4'

----------------------------------------------------------------

root@OpenWrt:~# cat /etc/config/firewall

config defaults
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option synflood_protect '1'

config zone
        option name 'lan'
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'ACCEPT'
        list network 'lan'

config zone
        option name 'wan'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option masq '1'
        option mtu_fix '1'
        list network 'wan'

config forwarding
        option src 'lan'
        option dest 'wan'

config rule
        option name 'Allow-DHCP-Renew'
        option src 'wan'
        option proto 'udp'
        option dest_port '68'
        option target 'ACCEPT'
        option family 'ipv4'

config rule
        option name 'Allow-Ping'
        option src 'wan'
        option proto 'icmp'
        option icmp_type 'echo-request'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-IGMP'
        option src 'wan'
        option proto 'igmp'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-DHCPv6'
        option src 'wan'
        option proto 'udp'
        option dest_port '546'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-MLD'
        option src 'wan'
        option proto 'icmp'
        option src_ip 'fe80::/10'
        list icmp_type '130/0'
        list icmp_type '131/0'
        list icmp_type '132/0'
        list icmp_type '143/0'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Input'
        option src 'wan'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        list icmp_type 'router-solicitation'
        list icmp_type 'neighbour-solicitation'
        list icmp_type 'router-advertisement'
        list icmp_type 'neighbour-advertisement'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Forward'
        option src 'wan'
        option dest '*'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-IPSec-ESP'
        option src 'wan'
        option dest 'lan'
        option proto 'esp'
        option target 'ACCEPT'

config rule
        option name 'Allow-ISAKMP'
        option src 'wan'
        option dest 'lan'
        option dest_port '500'
        option proto 'udp'
        option target 'ACCEPT'

config include 'pbr'
        option fw4_compatible '1'
        option type 'script'
        option path '/usr/share/pbr/pbr.firewall.include'

config zone
        option name 'VPNclient'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option masq '1'
        list network 'wgc'

config forwarding
        option src 'lan'
        option dest 'VPNclient'

config zone
        option name 'VPNserver'
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'REJECT'
        list network 'wgs'

config forwarding
        option src 'VPNserver'
        option dest 'VPNclient'

config forwarding
        option src 'VPNserver'
        option dest 'wan'

config redirect
        option dest 'VPNserver'
        option target 'DNAT'
        option name 'allow-wireguard'
        list proto 'udp'
        option src 'wan'
        option src_dport '...'
        option dest_port '...'
        option dest_ip '10.8.0.1/32'

----------------------------------------------------------------

root@OpenWrt:~# cat /etc/config/pbr

config pbr 'config'
        option enabled '1'
        option verbosity '2'
        option strict_enforcement '1'
        option resolver_set 'dnsmasq.nftset'
        option ipv6_enabled '0'
        option boot_timeout '30'
        option rule_create_option 'add'
        option procd_reload_delay '1'
        option webui_show_ignore_target '0'
        list webui_supported_protocol 'all'
        list webui_supported_protocol 'tcp'
        list webui_supported_protocol 'udp'
        list webui_supported_protocol 'tcp udp'
        list webui_supported_protocol 'icmp'

config policy
        option name 'ip'
        option dest_addr 'ip.me'
        option interface 'wgc'

----------------------------------------------------------------

root@OpenWrt:~# ip ro

default via ... dev lan0 proto static src ...
10.8.0.5 dev wgs proto static scope link
.../21 dev lan0 proto kernel scope link src ...
... via ... dev lan0 proto static
192.168.1.0/24 dev br-lan proto kernel scope link src 192.168.1.1

----------------------------------------------------------------

root@OpenWrt:~# ip route show table all

default via ... dev lan0 table pbr_wan
192.168.1.0/24 dev br-lan table pbr_wan proto kernel scope link src 192.168.1.1
default via 10.8.1.2 dev wgc table pbr_wgc
192.168.1.0/24 dev br-lan table pbr_wgc proto kernel scope link src 192.168.1.1
default via 10.8.0.1 dev wgs table pbr_wgs
192.168.1.0/24 dev br-lan table pbr_wgs proto kernel scope link src 192.168.1.1
default via ... dev lan0 proto static src ...
10.8.0.5 dev wgs proto static scope link
.../21 dev lan0 proto kernel scope link src ...
... via ... dev lan0 proto static
192.168.1.0/24 dev br-lan proto kernel scope link src 192.168.1.1
local 10.8.0.1 dev wgs table local proto kernel scope host src 10.8.0.1
local 10.8.1.2 dev wgc table local proto kernel scope host src 10.8.1.2
local 127.0.0.0/8 dev lo table local proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo table local proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo table local proto kernel scope link src 127.0.0.1
local ... dev lan0 table local proto kernel scope host src ...
broadcast ... dev lan0 table local proto kernel scope link src ...
local 192.168.1.1 dev br-lan table local proto kernel scope host src 192.168.1.1
broadcast 192.168.1.255 dev br-lan table local proto kernel scope link src 192.168.1.1
fd6e:2a7b:f9eb::/64 dev br-lan proto static metric 1024 pref medium
unreachable fd6e:2a7b:f9eb::/48 dev lo proto static metric 2147483647 pref medium
fe80::/64 dev br-lan proto kernel metric 256 pref medium
fe80::/64 dev lan0 proto kernel metric 256 pref medium
local ::1 dev lo table local proto kernel metric 0 pref medium
anycast fd6e:2a7b:f9eb:: dev br-lan table local proto kernel metric 0 pref medium
local fd6e:2a7b:f9eb::1 dev br-lan table local proto kernel metric 0 pref medium
anycast fe80:: dev br-lan table local proto kernel metric 0 pref medium
anycast fe80:: dev lan0 table local proto kernel metric 0 pref medium
local fe80::1ae8:29ff:febc:33e6 dev lan0 table local proto kernel metric 0 pref medium
local fe80::1ae8:29ff:febc:33e7 dev br-lan table local proto kernel metric 0 pref medium
multicast ff00::/8 dev br-lan table local proto kernel metric 256 pref medium
multicast ff00::/8 dev lan0 table local proto kernel metric 256 pref medium
multicast ff00::/8 dev wgs table local proto kernel metric 256 pref medium
multicast ff00::/8 dev wgc table local proto kernel metric 256 pref medium

----------------------------------------------------------------

root@OpenWrt:~# ip ru

0:      from all lookup local
30000:  from all fwmark 0x10000/0xff0000 lookup pbr_wan
30001:  from all fwmark 0x20000/0xff0000 lookup pbr_wgc
30002:  from all fwmark 0x30000/0xff0000 lookup pbr_wgs
32766:  from all lookup main
32767:  from all lookup default

----------------------------------------------------------------

root@OpenWrt:~# wg show

interface: wgs
  public key: ...
  private key: (hidden)
  listening port: ...

peer: ...
  endpoint: ...
  allowed ips: 10.8.0.5/32
  latest handshake: 14 minutes, 15 seconds ago
  transfer: 740.90 KiB received, 2.91 MiB sent

interface: wgc
  public key: ...
  private key: (hidden)
  listening port: ...

peer: ...
  endpoint: ...
  allowed ips: 0.0.0.0/0
  latest handshake: 9 minutes, 41 seconds ago
  transfer: 34.79 MiB received, 3.29 MiB sent

A few things you might take a look at:

Change to list addresses '10.8.0.1/24'

The following can be removed if the goal is to allow traffic to your WG server:

A simple ACCEPT rule should be sufficient:

config rule
	option name 'wgserver'
	list proto 'udp'
	option src 'wan'
	option dest_port '<set listen port of WG server>'
	option target 'ACCEPT'

I would set option forward 'ACCEPT', you control it with the forward rules (note you do not forward from the WG server to the LAN if this is on purpose then fine)

On the PBR interface add the WG server as an exception so that local routes are copied to all tables.
e.g.:
` list ignored_interface 'wgs'

There could be more and/or I made a mistake but I am running out of time, will have a look later.
Consider implementing above changes Save Apply and reboot.

If you want to route the clients which are connected via the WG server out via your WG client add a PBR rule to route 10.8.0.0/24 via the WG client.

There are several ways to deal with running a VPN server and client together, using no host route as you are doing, using an ip rule as described above but also disable route allowed IPs all will/can have different behaviour.

I personally do it with the ip rule but with no host route might/should also work.