WireGuard client VPN: Clients Can't Access Internet on VPN-Enabled SSID

Hello OpenWrt community,

I'm setting up a WireGuard VPN client on a WRT3200ACM router running OpenWrt 23.05.5. My goal is to have multiple SSIDs with different VPN settings. Such that 1 ssid uses 1 VPN connection to a Canada based endpoint, the other SSID to a New York based endpoint, and all wired clients no VPN at all. Currently, I'm just trying to get one of these functional and I have an issue where clients connected to a VPN-enabled SSID can't access the internet, despite the WireGuard connection appearing to be established.

Setup Details:

  • WireGuard interface name: wgclient_ca
  • VPN-enabled SSID network: gianellevpn
  • the router is downstream from the ISP Wifi router

Current Status:

  1. WireGuard connection establishes successfully
  2. Clients on gianellevpn network can obtain IP addresses and resolve DNS
  3. Clients cannot load web pages or access internet services

Configurations:

  1. WireGuard interface:
wg show
interface: wgclient_ca
public key: (hidden)
private key: (hidden)
listening port: 41961

peer: (hidden)
endpoint: [2606:6080:2001:24::117]:1276
allowed ips: 0.0.0.0/0, ::/0
latest handshake: 58 seconds ago
transfer: 3.04 MiB received, 5.12 KiB sent
persistent keepalive: every 25 seconds
  1. Routing table
ip route show
default via 10.0.0.1 dev wan proto static src 10.0.0.95
10.0.0.0/24 dev wan proto kernel scope link src 10.0.0.95
192.168.1.0/24 dev br-lan proto kernel scope link src 192.168.1.1
192.168.20.0/24 dev br-gianellevpn proto kernel scope link src 192.168.20.1
  1. Firewall zones (relevant)
config zone
option name 'gianellevpn'
option input 'ACCEPT'
option output 'ACCEPT'
option forward 'REJECT'
list network 'gianellevpn_net'

config zone
option name 'fw_wgcli_ca'
option input 'REJECT'
option output 'ACCEPT'
option forward 'REJECT'
list network 'wgclient_ca'

config forwarding
option src 'gianellevpn'
option dest 'fw_wgcli_ca'

config forwarding
option src 'gianellevpn'
option dest 'wan'


What I've Tried:

  1. Verified WireGuard connection status
  2. Checked firewall rules and zones. The client can reach the internet only in wan is included in the forward zone of the wireguard firewall zone.

Questions:

  1. Is my routing configuration correct for directing gianellevpn traffic through the WireGuard interface?
  2. Do I need additional firewall rules or zone configurations?
  3. Are there any specific settings required for masquerading or NAT with this setup?
  4. How can I troubleshoot where exactly the traffic is getting blocked?

Any guidance or suggestions would be greatly appreciated. Let me know if you need any additional information.

Thank you!

A firewall only allows or rejects traffic, it does not route traffic.

For routing you have to use some form of Policy Based Routing:
https://openwrt.org/docs/guide-user/network/routing/pbr

Thank you for your suggestion. I did enable PBR and create a rule for the subnet I want to route through the WireGuard interface. However, I've observed unexpected behavior. It doesn't seem to matter that I enabled a pbr rule, traceroute command move packets from the ssid to the nexthop router (Wifi ISP Router)

current PBR configuration:

IP Rules:

0:	from all lookup local
32766:	from all lookup main
32767:	from all lookup default

PBR Status:

/etc/init.d/pbr status

pbr - environment
pbr 1.1.6-22 running on OpenWrt 23.05.5.

Dnsmasq version 2.90  Copyright (c) 2000-2024 Simon Kelley
Compile time options: IPv6 GNU-getopt no-DBus UBus no-i18n no-IDN DHCP no-DHCPv6 no-Lua TFTP no-conntrack no-ipset no-nftset no-auth no-cryptohash no-DNSSEC no-ID loop-detect inotify dumpfile

pbr fw4 nft file: /usr/share/nftables.d/ruleset-post/30-pbr.nft
add chain inet fw4 pbr_mark_0x010000
add rule inet fw4 pbr_mark_0x010000  mark set mark and 0xff00ffff xor 0x010000
add rule inet fw4 pbr_mark_0x010000 return
add chain inet fw4 pbr_mark_0x020000
add rule inet fw4 pbr_mark_0x020000  mark set mark and 0xff00ffff xor 0x020000
add rule inet fw4 pbr_mark_0x020000 return
add rule inet fw4 pbr_prerouting ip saddr { 192.168.20.0/24 }  goto pbr_mark_0x020000 comment "canada_vpn_policy"

pbr chains - policies
	chain pbr_forward { # handle 43
	}
	chain pbr_input { # handle 44
	}
	chain pbr_output { # handle 45
	}
	chain pbr_postrouting { # handle 47
	}
	chain pbr_prerouting { # handle 46
		ip saddr 192.168.20.0/24 goto pbr_mark_0x020000 comment "canada_vpn_policy" # handle 726
	}
	chain pbr_dstnat { # handle 42
	}

pbr chains - marking
	chain pbr_mark_0x010000 { # handle 124
		meta mark set meta mark & 0xff01ffff | 0x00010000 # handle 722
		return # handle 723
	}
	chain pbr_mark_0x020000 { # handle 127
		meta mark set meta mark & 0xff02ffff | 0x00020000 # handle 724
		return # handle 725
	}

pbr nft sets

Error: ipv4: FIB table does not exist.
Dump terminated
IPv4 table 256 route: 
IPv4 table 256 rule(s):
Error: ipv4: FIB table does not exist.
Dump terminated
IPv4 table 257 route: 
IPv4 table 257 rule(s):

I'm puzzled by this behavior.

  1. Why doesn't the PBR rule alone seem to affect the routing as expected? Could it have anything to do with the errors in pbr status?
  2. Why does including 'wan' in the WireGuard interface's firewall zone, allow the intended lan clients to reach the internet (but not through the VPN)?

Most probably.

You are also using a rather old PBR version so I would advice you to upgrade PBR to start with, see: https://docs.openwrt.melmac.net/

Furthermore if that does not help, Please connect to your OpenWRT device using ssh and copy the output of the following commands and post it here using the "Preformatted text </> " button:

Remember to redact keys, passwords, MAC addresses and any public IP addresses you may have:

ubus call system board
cat /etc/config/network
cat /etc/config/firewall
ip route show
ip route show table all
ip rule show
wg show
cat /etc/config/pbr
service pbr status
cat /var/run/pbr.nft
nft -c -f /var/run/pbr.nft
****@OpenWrt:~# ubus call system board
{
    "kernel": "5.10.146",
    "hostname": "OpenWrt",
    "system": "ARMv7 Processor rev 1 (v7l)",
    "model": "Linksys WRT3200ACM",
    "board_name": "linksys,wrt3200acm",
    "rootfs_type": "squashfs",
    "release": {
        "distribution": "OpenWrt",
        "version": "22.03.2",
        "revision": "r19803-9a599fee93",
        "target": "mvebu/cortexa9",
        "description": "OpenWrt 22.03.2 r19803-9a599fee93"
    }
}

****@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 'fd45:3010:946d::/48'

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

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'

config device
    option name 'wan'
    option macaddr 'XX:XX:XX:XX:XX:XX'

config interface 'wan'
    option device 'wan'
    option proto 'dhcp'

config interface 'wan6'
    option device 'wan'
    option proto 'dhcpv6'

config device 'gianelle_dev'
    option type 'bridge'
    option name 'br-gianelle'

config interface 'gianelle'
    option proto 'static'
    option device 'br-gianelle'
    option ipaddr '192.168.19.1'
    option netmask '255.255.255.0'

config interface 'wg0'
    option proto 'wireguard'
    option private_key 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
    list addresses '10.X.XX.X/32'
    list addresses 'XXXX:XXXX:XXXX::XXXX:XXXX/128'

config wireguard_wg0 'wgserver'
    option public_key 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
    option endpoint_host 'wg.starzone.io'
    option endpoint_port '1276'
    option route_allowed_ips '1'
    list allowed_ips '0.0.0.0/0'
    list allowed_ips '::/0'
    option persistent_keepalive '25'

config rule 'gianelle_rule'
    option in_interface 'br-gianelle'
    option lookup 'wg0'
    option priority '100'

config route
    option interface 'wan'
    option target 'wg.starzone.io'
    option gateway '10.0.0.1'

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

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

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

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

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

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 'gianelle'
    option name 'gianelle'
    option network 'gianelle'
    option output 'ACCEPT'
    option input 'ACCEPT'
    option forward 'ACCEPT'

config rule 'gianelle_dns'
    option name 'Allow-DNS-gianelle'
    option src 'gianelle'
    option dest_port '53'
    list proto 'tcp'
    list proto 'udp'
    option target 'ACCEPT'

config rule 'gianelle_dhcp'
    option name 'Allow-DHCP-gianelle'
    option src 'gianelle'
    option dest_port '67'
    option proto 'udp'
    option family 'ipv4'
    option target 'ACCEPT'

config zone 'wg0zone'
    option name 'wg0zone'
    list network 'wg0'
    option input 'REJECT'
    option output 'ACCEPT'
    option forward 'REJECT'
    option masq '1'

config forwarding 'gianelle_to_wg'
    option src 'gianelle'
    option dest 'wg0zone'

config rule
    option name 'Allow_Wireguard_OUT'
    option proto 'udp'
    option src '*'
    option dest 'wan'
    option dest_ip 'wg.starzone.io'
    option dest_port '1276'
    option target 'ACCEPT'


****@OpenWrt:~# ip route show
default dev wg0 proto static scope link 
10.0.0.0/24 dev wan proto kernel scope link src 10.0.0.94 
184.75.208.229 via 10.0.0.1 dev wan proto static 
192.168.1.0/24 dev br-lan proto kernel scope link src 192.168.1.1 
192.168.19.0/24 dev br-gianelle proto kernel scope link src 192.168.19.1 

****@OpenWrt:~# ip route show table all
[Output omitted for brevity]

****@OpenWrt:~# ip rule show
0:    from all lookup local
32766:    from all lookup main
32767:    from all lookup default

****@OpenWrt:~# wg show
interface: wg0
  public key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  private key: (hidden)
  listening port: 60321

peer: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  endpoint: [XXXX:XXXX:XXXX::XXXX:XXXX]:1276
  allowed ips: 0.0.0.0/0, ::/0
  latest handshake: 10 seconds ago
  transfer: 46.21 KiB received, 2.01 MiB sent
  persistent keepalive: every 25 seconds

****@OpenWrt:~# cat /etc/config/pbr
[PBR configuration omitted for brevity]

****@OpenWrt:~# service pbr status
pbr 1.1.1-7 running on OpenWrt 22.03.2. WAN (IPv4): wan/wan/10.0.0.1.
============================================================
Dnsmasq version 2.86  Copyright (c) 2000-2021 Simon Kelley
Compile time options: IPv6 GNU-getopt no-DBus UBus no-i18n no-IDN DHCP no-DHCPv6 no-Lua TFTP no-conntrack no-ipset no-auth no-cryptohash no-DNSSEC no-ID loop-detect inotify dumpfile
============================================================
Routes/IP Rules
default         *               0.0.0.0         U     0      0        0 wg0
/etc/rc.common: line 2415: ipset: not found
============================================================
Current ipsets
============================================================
Your support details have been logged to '/var/pbr-support'. [✓]

****@OpenWrt:~# cat /var/run/pbr.nft
cat: can't open '/var/run/pbr.nft': No such file or directory

****@OpenWrt:~# nft -c -f /var/run/pbr.nft
internal:0:0-0: Error: Could not open file "/var/run/pbr.nft": No such file or directory

I was having radio problems with later versions of openwrt on this linksys WRT3200ACM, so I downgraded all the way to 22.03.2.

My intent was to have just one specific network (gianelle) be VPN enabled. But at this point, it would be an incremental win if I could get any network working through the VPN. So ive parked the pbr stuff for now.

  1. WireGuard interface (wg0) is up and configured.
  2. Default route is set to wg0.
  3. WAN interface (eth0) has a DHCP-assigned IP (10.0.0.94/24) from upstream ISP Wifi router.

I've seen you mentioned you have this working in another thread Multiple OpenWRT router with wireguard vpn (client) on both router connected via ethernet - #9 by egc?

perhaps you can provide me with a complete template config to use.

Your build is old and EOL so not sure what will work and what not.

You PBR is also old and if your only intent is to route one interface (gianelle) through the VPN we can try with a simple netifd setup.

Start with making a backup so you can go back to this config

Stop the PBR app.

Remove this rule it should not be necessary:

Remove the option route_allowed_ips '1' , this will route everything default through the WAN:

Remove this:

Next we make a table with default route via the wg interface:

config route
	option interface 'wg0'
	option table '102'
	option target '0.0.0.0/0'

and a rule to bind interface gianelle with this table:

config rule
	# for interface
	option in 'gianelle'
	option lookup '102'

Interface gianelle already has a forward to the VPN zone in the firewall but not to the WAN so this interface will only work via the VPN and not via the wan if that is your intent then fine

Reboot your router and test.
If it does not work please show the following and redact keys, passwords, MAC addresses and any public IP addresses you may have:

cat /etc/config/network
cat /etc/config/dhcp
cat /etc/config/firewall
ip route show
ip route show table all
ip rule show
wg show

Again not sure if this will work on your old build.

I've resolved the main issues. So now LAN traffic goes through the regular WAN connection, Gianelle network traffic is routed through the WireGuard VPN. Both networks can access the internet and local resources as intended.

Here's a summary of what worked and some lessons learned:

Key Changes:

  1. Removed unnecessary firewall rules and removed PBR configurations.
  2. Modified WireGuard configuration:
    • Set option route_allowed_ips '0' (crucial change)
  3. Implemented a custom routing table for my VPN-enabled network (gianelle)
  4. Added a rule to direct gianelle traffic to the new routing table.

Lessons Learned:

  1. The route_allowed_ips option is an obscure but extremely impactful setting. Setting it to '0' prevents WireGuard from overwriting the default route table. This option is enabled by default in the OpenWrt.org WireGuard sample configs. None of the OpenWrt WireGuard pages seem to adequately cover its significance. It can override other routing configurations, making troubleshooting difficult.

  2. Interplay between LuCI and CLI:
    I wasn't consistently committing changes and restarting services after modifications. And I was making modifications back in forth in the cli and luci.

  3. You can accomplish my intended topology with just routing tables. PBR would be needed if I need to do more complex things like have clients on a VPN enabled network, not use VPN for something like Netflix. So for now I can keep things simple.

  4. Version-specific issues:
    What also made troubleshooting difficult was packet loss issues in newer OpenWrt versions (+22.x) on my current hardware (Linksys WRT3200ACM) - on BOTH lan and wlan connections. I need to upgrade my router in the near future. I'm considering a move to a GL.iNet Flint 2.

I hope these insights prove valuable to others tackling similar issues. The route_allowed_ips setting, in particular, deserves more attention in the documentation, IMO.

Thank you again to the community (and egc) for your help.

1 Like

Great to hear it is solved :+1:

If your problem is solved, please consider marking this topic as [Solved]. See How to mark a topic as [Solved] for a short how-to.
Thanks! :slight_smile: