OpenWRT Wireguard Client to QNAP NAS Server

Hello everybody, first post here, although I had a little experience with OpenWRT few years ago on a D-Link router (DGN-3500). I'm familiar with Linux (and similar systems) but I've always been a sucker at more than basic network configurations. :wink:
I'm setting up a TP-Link TR-ML6400 as a Wireguard client to connect to my QNAP NAS at home that hosts (among other things) a security camera recording system. Basically I need the cameras on 6400 lan (wlan) to be "seen" by the NAS via the tunnel.
I've managed to install OpenWRT, set up the cellular modem (thanks to this thread), set up the Wireguard connection between the 6400 (acting as a client) and the NAS (server).
I think I'm missing something in the routing/firewall settings of one or both sides.
Thanks in advance for your help, following are the configuration files and outputs:

ML6400 network conf file:

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 'fdea:8cd3:2e4c::/48'

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'eth0.1'

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 interface 'wan'
	option device 'eth0.2'
	option proto 'dhcp'

config interface 'wan6'
	option device 'eth0.2'
	option proto 'dhcpv6'

config switch
	option name 'switch0'
	option reset '1'
	option enable_vlan '1'

config switch_vlan
	option device 'switch0'
	option vlan '1'
	option ports '0 1 2 6t'

config switch_vlan
	option device 'switch0'
	option vlan '2'
	option ports '3 6t'

config interface 'wwan'
	option proto 'dhcp'

config interface 'wdm0'
	option proto 'qmi'
	option device '/dev/cdc-wdm0'
	option apn 'internet.wind'
	option auth 'none'
	option pdptype 'ipv4v6'
	option default_profile '1'

config interface 'wg0'
	option proto 'wireguard'
	option private_key '[...]'
	list addresses '198.18.7.2/32'
	option mtu '1412'

config wireguard_wg0
	option description 'NAS-EMILIO'
	option public_key '[...]'
	list allowed_ips '0.0.0.0/0'
	option route_allowed_ips '1'
	option endpoint_host '[...].myqnapcloud.com'
	option endpoint_port '51820'

ML6400 firewall conf

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'
	list network 'wan6'
	list network 'wwan'
	list network 'wdm0'

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 zone
	option name 'ivpn_fw'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option masq '1'
	option mtu_fix '1'
	list network 'wg0'

config forwarding
	option src 'lan'
	option dest 'ivpn_fw'

NAS VPN config:

[Interface]
Address        = 198.18.7.1/24
ListenPort     = 51820
PrivateKey     = [...]
PostUp = iptables -A FORWARD -i %i -j ACCEPT;
PostDown = iptables -D FORWARD -i %i -j ACCEPT;
SaveConfig     = true

[Peer]
PublicKey        = [...]
AllowedIPs       = 198.18.7.2/32
PersistentKeepalive   = 10

NAS iptables -L output:

[~] # iptables -L    
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
QUFIREWALL  all  --  anywhere             anywhere             state NEW

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
DOCKER-USER  all  --  anywhere             anywhere            
DOCKER-ISOLATION-STAGE-1  all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
DOCKER     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
SYSDOCKER-USER  all  --  anywhere             anywhere            
SYSDOCKER-ISOLATION-STAGE-1  all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
SYSDOCKER  all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
SYSDOCKER  all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
CSFORWARD  all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
DROP       all  --  anywhere             anywhere             match-set BRNOIPSET src,dst

Chain CSFORWARD (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
DROP       all  --  anywhere             anywhere             ctstate INVALID,NEW
DROP       all  --  anywhere             anywhere             ctstate INVALID,NEW
DROP       all  --  anywhere             anywhere             ctstate INVALID,NEW
DROP       all  --  anywhere             anywhere             ctstate INVALID,NEW

Chain DOCKER (1 references)
target     prot opt source               destination         

Chain DOCKER-ISOLATION-STAGE-1 (1 references)
target     prot opt source               destination         
DOCKER-ISOLATION-STAGE-2  all  --  anywhere             anywhere            
RETURN     all  --  anywhere             anywhere            

Chain DOCKER-ISOLATION-STAGE-2 (1 references)
target     prot opt source               destination         
DROP       all  --  anywhere             anywhere            
RETURN     all  --  anywhere             anywhere            

Chain DOCKER-USER (1 references)
target     prot opt source               destination         
RETURN     all  --  anywhere             anywhere            

Chain QUFIREWALL (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             -m geoip --source-country IT,TW 
ACCEPT     all  --  198.18.7.0           anywhere            
ACCEPT     udp  --  anywhere             anywhere             multiport dports 51820
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
NFLOG      all  --  anywhere             anywhere             match-set PSIRT.ipv4 src nflog-prefix  "RULE=12 ACT=DROP"
DROP       all  --  anywhere             anywhere             match-set PSIRT.ipv4 src
NFLOG      all  --  anywhere             anywhere             match-set TOR.ipv4 src nflog-prefix  "RULE=13 ACT=DROP"
DROP       all  --  anywhere             anywhere             match-set TOR.ipv4 src
ACCEPT     all  --  192.168.0.0/24       anywhere            
ACCEPT     all  --  anywhere             anywhere             -m geoip --source-country IT 
NFLOG      all  --  anywhere             anywhere             nflog-prefix  "RULE=16 ACT=DROP"
DROP       all  --  anywhere             anywhere            

[Chain SYSDOCKER (2 references)
target     prot opt source               destination         
ACCEPT     tcp  --  anywhere             172.30.8.2           tcp dpt:www

Chain SYSDOCKER-ISOLATION-STAGE-1 (1 references)
target     prot opt source               destination         
SYSDOCKER-ISOLATION-STAGE-2  all  --  anywhere             anywhere            
SYSDOCKER-ISOLATION-STAGE-2  all  --  anywhere             anywhere            
RETURN     all  --  anywhere             anywhere            

Chain SYSDOCKER-ISOLATION-STAGE-2 (2 references)
target     prot opt source               destination         
DROP       all  --  anywhere             anywhere            
DROP       all  --  anywhere             anywhere            
RETURN     all  --  anywhere             anywhere            

Chain SYSDOCKER-USER (1 references)
target     prot opt source               destination         
RETURN     all  --  anywhere             anywhere]

Do you get a successful handhake?

wg show

Yes, sorry I forgot to mention.

wg show in OpenWRT:

interface: wg0
  public key: [...]
  private key: (hidden)
  listening port: 55392

peer: [...]
  endpoint: [NAS external IP]:51820
  allowed ips: 0.0.0.0/0
  latest handshake: 58 seconds ago
  transfer: 636 B received, 8.16 KiB sent

wg show on the NAS:

interface: wg0
  public key: [...]
  private key: (hidden)
  listening port: 51820

peer: [...]
  endpoint: [OpenWRT router external IP]:33028
  allowed ips: 198.18.7.2/32
  latest handshake: 2 minutes, 3 seconds ago
  transfer: 18.93 KiB received, 6.12 KiB sent
  persistent keepalive: every 25 seconds

As Address range for WireGuard you better choose a private address range outside the already taken address ranges.

This is a routed solution so there is no seamless discovery of your cameras you have to connect by IP address.

I assume the QNAP is just a client on your lan behind a router.

If you cannot connect by IP address the problem could be that there is no return route set on your network to the QNAP, in this respect the QNAP is like a Dumb AP.

Either set a static route on the main router to route your WG subnet to the QNAP or easier NAT the WG traffic coming out of the QNAP:
iptables -t nat -I POSTROUTING -s <WG-subnet> -o <ethernet-interface> -j MASQUERADE

2 Likes

Hi, thanks for the help. Adding a static route to the NAS LAN IP in the "main router" (a Fritzbox 7530) has solved the problem of accessing the remote cameras. I had to go for the static route because the Fritzbox has very limited configuration options, so I don't know how to set up NAT in it.

I just had to add some port routing on the OpenWRT "client" side to let the NAS access their management and video stream.

BTW about your first suggestion on the WireGuard address range, the NAS interface doesn't let me change it (actually it lets me change just the first number, the other fields are greyed out and locked):

The only problem I still have to solve with this configuration is that all other devices connected to the OpenWRT lan (and the ruoter itself, who's unable to download packages) can't access the internet. I would like to have the possibility to navigate the internet with my mobile, connected to the OpenWRT wifi, when I go down to the garage, where my mobile struggles with signal, while the router is fine (they are on different providers and I've connected a big outdoor antenna to the router). May it be caused by the fact that when I created the WG interface, in the "Peers" section I set as "AllowedIPs" "0.0.0.0/0" and then checked the "Route Allowerd IPs" box?
Should I change the allowed IPs to just those of the two cameras?

I probably was not very clear but the POSTROUTINg rule was meant to be set on the QNAP and not on the FRITZbox, but a static route also gets the job done :slight_smile:

About your question:

Assuming the TP link OpenWRT has its own internet connection you can use as allowed IPs the WG address of the other side and the LAN subnet of the other side so change list allowed_ips '0.0.0.0/0' in:

list allowed_ips `198.18.7.1/32`
list allowed_ips `192.168.0.0/24`

Furthermore on the NAS add as allowed IPs the subnet of the TPLink/OpenWRT (check if this is the right subnet:

AllowedIPs       = 198.18.7.2/32, 192.168.1.0/24

On the TPlink/Openwrt you can now disable Masquerading on the ivpn_fw zone and allow traffic from ivpn_fw to lan so you do not need the port forward rules you have made.
But even easier, instead of the above, is just add the wg0 interface to the lan zone, so remove list network 'wg0' from ivpn_fw zone , and add to lan zone and then you can delete the whole ivpn_fw zone.

This can be done as the other side (the NAS) can be trusted

Basically we are using a site-to-site setup

1 Like

I also have a QNAP and looked it up

Enter a fixed IP subnet for the VPN server.
Important:

By default, this server reserves the use of IP addresses from 10.8.0.0/24. 
If another connection is configured to use this range, an IP conflict error will occur.
Before adding this server, ensure a VPN client isn't configured to use this range as well.

So not sure how you set 198.18.7.0/24 as WG subnet, must be a bug in QNAP setup, for now just leave it

Edit: I just tried, just change 198 e.g. in 192 or 10 etc

Ok, setting 198.18.7.1/32 as the only allowed IP on the OpenWRT router solved the problem of the devices connected to it not accessing the internet via its wan.

No no, it was very clear that the postrouting rule had to be added to the NAS, problem is (and I know that's not in the scope of this thread and this whole forum :wink: ) that I don't know how to add iptables rules to the QNAP NAS, provided anything you set via ssh console is wiped away everytime you reboot the machine and sometimes even by just changing settings in the web interface. Not to mention how ridicously simplified (not to say "for dummies") the QuFirewall app is that lets the creation of very simple (and often useless) rules.
Anyways, I've tried (by manually editing config files on both the NAS and OpenWRT router) your final solution without the vpn firewall zone (that would be a lot cleaner and more elegant) but it doesn't work (the cameras aren't accessible anymore) and, as usual, QNAP interface gets in the way, not letting to edit the "AllowedIPs" field in the "Peer" section (in order to add the IP range of the OpenWRT LAN).

P.S.: why you insist on changing the default 198.x.x.x address into something else?

That is the public address of someone else, so for internal use you should only use RFC1918 addresses e.g. 192.168.X.X, 10.X.X.X and 172.16-31.X.X

But is it no big deal unless you actually want to visit that IP address

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.