Posted March 15th 2017
OpenWRT 22.03 switched its firewall setup from 'iptables' to 'netfilter', but fwknop hasn't been updated, so it won't work. There are a few workarounds:
Wait for an update to fwknop. Might happen, might not. It could be done by the (OpenWRT) maintainer of the fwknop package, or by someone with an itch to scratch, or by fwknop upstream. But... the most recent activity in upstream (at cipherdyne.org) is from 2018.
Hack around the limitation. Some posts to OpenWRT forums suggest using some netfilter/iptables compatibility modules, but this doesn't seem to work for most people. Another possibility is to use external scripts to update the firewall rules. All of these approaches seem pretty flaky.
Run 'fwknop' on a server instead of a firewall. This is what I ended up doing.
On the (debian) server, I did a bunch of things:
sudo iptables -A INPUT -i eth0 -p tcp --dport 22 -j DROP sudo iptables -A INPUT -i eth0 -p tcp --dport 22 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo systemctl enable fwknop-server sudo systemctl start fwknop-server
After doing all that, fwknopd should be running, and it should log things to syslog.
On the OpenWRT firewall, I uninstalled fwknop and opened ordinary port forwarding to the debian server, of UDP/62201 and TCP/22. The first is so that fwknop packets get through. The second is the the service I actually want, i.e. SSH.
I use fwknop to limit network access to a server behind an TP-Link Archer C7 running OpenWRT. Configuring 'fwknop' was fiddly, so I've written down how I got it working.
I chose the Archer C7 v2.0 because it's listed as working by OpenWRT, it has four GbE ports and a reasonably fast CPU, it's popular and relatively cheap.
I like OpenWRT, mostly because it lets me SSH in to the access point and run things like 'tcpdump'. Installing on the Archer C7 was not straightforward. Installing the 15.05.1 firmware linked from openwrt.org left me with a device which didn't even answer 'ping'. Fortunately, there's a 'recovery mode' which re-flashes the device over TFTP. Flashing bleeding edge (50104) 'trunk' OpenWRT firmware fixed it. Instructions are easily googled, so I won't link them.
I have an SSH and HTTPS server I want to access remotely. But I don't like having apache (HTTPS) open to the internet, partly because any configuration mistakes are likely to be exploited in no time and partly because of possible unpatched vulnerabilities.
Limiting port-forwarding in OpenWRT to certain IP addresses would improve the situation, but I don't want to do that manually. 'fwknop' automates that.
'fwknop' works by having a daemon listen to UDP port 66201 on a firewall. You can see it on the firewall by running 'ps'. When it sees an UDP packet with the right credentials, it runs 'iptables' commands on the firewall to open up access for a specific host on the outside.
Update 2018-10: Easiest way is 'opkg install luci-app-fwknopd'.
There's a fwknop package for OpenWRT, so 'opkg install
fwknop' does it. Unfortunately, it didn't install cleanly,
the post-install script bombed out. Maybe because of that
the LUCI interface didn't seem to work. In any case, I
wanted to understand exactly what I was doing, so I
configured it manually.
.fwknoprc (for my home PC):
[tegner] ACCESS tcp/443 NAT_ACCESS 10.1.2.3:443 SPA_SERVER my.firewall.hostname.com KEY_BASE64 /* secret */ HMAC_KEY_BASE64 /* secret */ USE_HMAC Y RESOLVE_IP_HTTPS Y WGET_CMD /usr/bin/wget
'/etc/fwknop/fwknopd.conf' on the firewall required one change:
ENABLE_IPT_FORWARDING Y;
'/etc/fwknop/access.conf' had me confused for a while. First, I didn't realise that 'stanzas' have to go all together down the bottom, i.e. each 'stanza' starts with the SOURCE setting and then other settings. Second, I needed the 'FORCE_NAT' option, which isn't documented in the config file 'opkg' installs. In the end my 'stanza' looked like this:
SOURCE ANY OPEN_PORTS tcp/443 REQUIRE_SOURCE_ADDRESS Y FW_ACCESS_TIMEOUT 500000 FORCE_NAT 10.1.2.3 443 KEY_BASE64 /* secret */ HMAC_KEY_BASE64 /* secret */
The 'FORCE_NAT' setting is a bit weird. I initially wanted to use a 'DESTINATION' setting to limit forwarding to one host, but that seemed to cause fwknop to reject all requests. FORCE_NAT seems to ignore the IP address in the request and send to the specified one. Close enough to what I want.
'fwknop' sends quite a bit of useful debugging information to the log, use 'logread -f' to watch it.