Matthias' personal blog

Using 'fwknop' on OpenWRT

Posted March 15th 2017

2023 update: fwknop is broken in OpenWRT 22.03

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:

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.

Original post (2017)

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.

TP-Link Archer C7

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.

OpenWRT

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.

fwknop: what's the idea?

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.

Installing fwknop

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.

Permalink | Tags: blog