Running knockd
If you've ever run an Internet facing server you'll quickly discover people and/or bots trying to connect. Below are some stats generated by logging rejected inbound traffic with iptables for a week:
Port | Protocol | Connection attempts |
---|---|---|
TCP/22 | SSH | 792 |
TCP/80 | HTTP | 120 |
TCP/443 | HTTPS | 67 |
So that's just shy of a thousand connection attempts on a system that's passively listening. OK the Internet being what it is, none of this is very surprising. However if you do actually allow any of the connections through, there is a good chance your logs will quickly fill up with failed connection attempts.
Where do the connections come from?
The short answer is from all over the globe. The map below shows where connection attempts were made from:
Note: The map was generated using OpenHeatMap and freegeoip.net. The background map is taken from the OpenStreetMap project (© OpenStreetMap contributors).
Time to hide?
There are a few ways to avoid unwanted connection attempts including:
- Whitelist IP address ranges and ignore other traffic.
- Run daemons on non-standard ports.
- Set up port knocking.
The rest of this post is going to look at port knocking. Before continuing it's worth noting that port knocking is effectively security through obscurity. Therefore port knocking should not be your only security measure. Make sure you take steps to secure services before they get anywhere near the Internet.
Port knocking and knockd
The basic idea behind port knocking is you deny connections by default, but listen for a special "knock" sequence of port-hits. When you see the correct sequence you can then perform an action, normally adding an extra firewall rule to allow connections in.
knockd is a port-knock server that can be used to implement port knocking. The rest of this post is going to go though setting up knockd on a Raspberry pi running Raspbian. More specifically a Raspberry Pi model B plus running Raspbian Jessie Lite (2016-05-27).
Change default password
By default Raspbian has the following login details:
Username: pi
Password: raspberry
Before doing anything else you should login and change the password using the
passwd
command.
Switch to root
The commands below will assume you are running as root. Either switch up to
root or run all of the commands below using sudo
. You can get a root shell by
running:
sudo -s
Install knockd
knockd is already packaged in the Raspbian repositories. Therefore installing
it is just a case of running apt-get
:
apt-get install knockd
Set up iptables:
Run the following commands to configure iptables:
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -p icmp -s 192.168.0.0/16 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -s 192.168.0.0/16 -j ACCEPT
iptables -N KNOCKD
iptables -A INPUT -j KNOCKD -m comment --comment 'Check rules added by knockd'
iptables -A INPUT -j REJECT
iptables -A FORWARD -j REJECT
This will allow traffic on the loopback interface and allow you to SSH to your Raspberry Pi from the LAN. Connections from outside the LAN will be rejected. You can check the rules by running:
iptables -L -v
At this point you might want to try starting a new SSH connection to your Raspberry Pi to make sure you have allowed SSH connections from your LAN. If you can't get in just reboot the Raspberry Pi and start again, none of the rules are persistent yet.
Making iptables persistent
Once your happy iptables is working run the following command to create a config file:
iptables-save > /etc/network/iptables
Then create a script called /etc/network/if-pre-up.d/iptables
with the
following contents:
#!/bin/sh
#
# Load iptables rules before the network comes online.
#
/sbin/iptables-restore < /etc/network/iptables
Note: Don't forget to add execute permissions to the script.
Configure knockd
The next step is to configure knockd. Add the following config to
/etc/knockd.conf
:
[options]
UseSyslog
[openSSH]
sequence = 4438,1813,8235
seq_timeout = 5
command = /sbin/iptables -A KNOCKD -s %IP% -p tcp --dport 22 -j ACCEPT
tcpflags = syn
UseSyslog
will tell knockd to log using syslog. The next section sets what
knockd should do once it sees the specified port sequence. In this case
iptables is used to add an allow rule to the KNOCKD
chain we set up earlier.
The last thing to do is enable and start knockd. To do this run the following commands:
sed -i '/^START_KNOCKD=0$/s/0/1/' /etc/default/knockd
systemctl enable knockd
systemctl start knockd
Finally make sure knockd is running correctly:
systemctl status knockd
Testing knockd
Once knockd is set up an running you will want to test it. From a remote client run the following command:
knock 192.168.1.129 4438 1813 8235
Alternatively if you haven't installed the knockd client you can use any command which will try to establish a TCP connection. For example the following curl commands can be used:
curl --max-time 1 http://192.168.1.129:4438 &
curl --max-time 1 http://192.168.1.129:1813 &
curl --max-time 1 http://192.168.1.129:8235 &
Note: You will want to change the IP address to match the address assigned to the Raspberry Pi.
If everything works correctly you should see messages similar to the following
in /var/log/syslog
:
Jul 06 19:46:33 raspberrypi knockd: 192.168.1.63: openSSH: Stage 1
Jul 06 19:46:34 raspberrypi knockd: 192.168.1.63: openSSH: Stage 2
Jul 06 19:46:35 raspberrypi knockd: 192.168.1.63: openSSH: Stage 3
Jul 06 19:46:35 raspberrypi knockd: 192.168.1.63: openSSH: OPEN SESAME
Jul 06 19:46:35 raspberrypi knockd: openSSH: running command: /sbin/iptables -A KNOCKD -s 192.168.1.63 -p tcp --dport 22 -j ACCEPT
You should also see a new iptables rule has been created to allow you to
connect to the Raspberry Pi in the KNOCKD
chain:
Chain KNOCKD (1 references)
pkts bytes target prot opt in out source destination
1 52 ACCEPT tcp -- * * 192.168.1.63 0.0.0.0/0 tcp dpt:22
Tidying old rules
The iptables rules which knockd adds will, by default hang around until the
network interface is restarted. To make sure old rules are tidied up overnight
you can create /etc/cron.daily/clear_knockd_iptables
with the following
contents:
#!/bin/sh
/sbin/iptables -F KNOCKD
This will remove all rules from the KNOCKD
chain. Note that if you have an
active SSH connection, you won't get kicked out. This is because established
and related traffic is explicitly allowed in the INPUT
chain.