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:
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:
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
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
knockd is already packaged in the Raspbian repositories. Therefore installing
it is just a case of running
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
#!/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.
The next step is to configure knockd. Add the following config to
[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
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
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
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
#!/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