Quick Links

Key Takeaways

  • Port knocking is a method of securing a server by closing firewall ports and allowing access only if a specific sequence of connection attempts is made.
  • Port knocking should not be relied upon as the sole form of security, as it can be easily breached if the secret knock is revealed.

Port knocking is a way to secure a server by closing firewall ports—even those you know will be used. Those ports are opened on demand if—and only if—the connection request provides the secret knock.

Port Knocking Is a "Secret Knock"

In the 1920s, when prohibition was in full swing, if you wanted to get into a speakeasy, you had to know the secret knock and tap it out correctly to get inside.

Port knocking is a modern equivalent. If you want people to have access to services on your computer but don't want to open your firewall to the internet, you can use port knocking. It allows you to close the ports on your firewall that allow incoming connections and have them open automatically when a prearranged pattern of connection attempts is made. The sequence of connection attempts acts as the secret knock. Another secret knock closes the port.

Port knocking is something of a novelty, but it's important to know it's an example of security through obscurity, and that concept is fundamentally flawed. The secret of how to access a system is safe because only those in a specific group know it. But once that secret is out—either because it's revealed, observed, guessed, or worked out—your security is void. You're better off securing your server in other, stronger ways, like requiring key-based logins for an SSH server.

The most robust approaches to cybersecurity are multilayered, so, perhaps port knocking should be one of those layers. The more layers, the better, right? However, you could argue that port knocking doesn't add much (if anything) to a properly hardened, secure system.

Cybersecurity is a vast and complicated topic, but you shouldn't use port knocking as your only form of defense.

Installing knockd

To demonstrate port knocking, we're going to use it to control port 22, which is the SSH port. We'll use a tool called knockd. Use apt-get to install this package onto your system if you use Ubuntu or another Debian-based distribution. On other Linux distributions, use your Linux distribution’s package management tool, instead.

Type the following:

sudo apt-get install knockd

sudo apt-get install knockd in a terminal window

You probably already have the iptables firewall installed on your system, but you might need to install the iptables-persistent package. It handles the automatic loading of saved iptable rules.

Type the following to install it:

sudo apt-get install iptables-persistent

sudo apt-get install iptables-persistent in a terminal window

When the IPV4 configuration screen appears, press the space bar to accept the "Yes" option.

iptables-persistent IPV4 screen

Press the space bar again in IPv6 configuration screen to accept the "Yes" option and move on.

iptables-persistent IPV6 screen

The following command tells iptables to allow established and ongoing connections to continue. We'll now issue another command to close the SSH port.

If someone is connected by SSH when we issue this command, we don't want them to be cut off:

sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

This command adds a rule to the firewall, that says:

  • -A: Append the rule to the firewall rules table. That is, add it to the bottom.
  • INPUT: This is a rule about incoming connections.
  • -m conntrack: Firewall rules act upon network traffic (packets) that match criteria in the rule. The -m parameter causes iptables to use extra packet matching modules—in this case, the one called conntrack works with the network connection tracking capabilities of the kernel.
  • --cstate ESTABLISHED,RELATED: This specifies the type of connection to which the rule will apply, namely ESTABLISHED and RELATED connections. An established connection is one that's already in progress. A related connection is one that's made due to an action from an established connection. Perhaps someone who is connected wants to download a file; that might happen over a new connection initiated by the host.
  • -j ACCEPT: If the traffic matches the rule, jump to the ACCEPT target in the firewall. In other words, the traffic is accepted and allowed to pass through the firewall.

Now we can issue the command to close the port:

sudo iptables -A INPUT -p tcp --dport 22 -j REJECT

sudo iptables -A INPUT -p tcp --dport 22 -j REJECT in a terminal window

This command adds a rule to the firewall, that says:

  • -A: Append the rule to the firewall rules table, i.e., add it to the bottom.
  • INPUT: This rule is about incoming connections.
  • -p tcp: This rule applies to traffic that uses the Transmission Control Protocol.
  • --dport 22: This rule specifically applies to TCP traffic that targets port 22 (the SSH port).
  • -j REJECT: If the traffic matches the rule, jump to the REJECT target in the firewall. So, if the traffic is rejected, it's not permitted through the firewall.

We must start the netfilter-persistent daemon. We can do so with this command:

sudo systemctl start netfilter-persistent

sudo systemctl start netfilter-persistent in a terminal window

We want netfilter-persistent to go through a save and reload cycle, so it loads and controls the iptable rules.

Type the following commands:

sudo netfilter-persistent save

sudo netfilter-persistent save in a terminal window

sudo netfilter-persistent reload

sudo netfilter-persistent reload in a terminal window

You've now installed the utilities, and the SSH port is closed (hopefully, without terminating anyone's connection). Now, it's time to configure the secret knock.

Configuring knockd

There are two files you edit to configure knockd. The first is the following knockd configuration file:

sudo gedit /etc/knockd.conf

sudo gedit /etc/knockd.conf in a terminal window

The gedit editor opens with the knockd configuration file loaded.

The knockd config file in the gedit editor

We'll edit this file to suit our needs. The sections we're interested in are "openSSH" and "closeSSH." The following four entries are in each section:

  • sequence: The sequence of ports someone must access to open or close port 22. The default ports are 7000, 8000, and 9000 to open it, and 9000, 8000, and 7000 to close it. You can change these or add more ports to the list. For our purposes, we'll stick with the defaults.
  • seq_timeout: The time period within which someone has to access the ports to trigger it to open or close.
  • command: The command sent to the iptables firewall when the open or close action is triggered. These commands either add a rule to the firewall (to open the port) or take it out (to close the port).
  • tcpflags: The type of packet each port must receive in the secret sequence. A SYN (synchronize) packet is the first in a TCP connection request, called a three-way handshake.

The "openSSH" section can be read as "a TCP connection request must be made to ports 7000, 8000, and 9000—in that order and within 5 seconds—for the command to open port 22 to be sent to the firewall."

The "closeSSH" section can be read as "a TCP connection request must be made to ports 9000, 8000, and 7000—in that order and within 5 seconds—for the command to close port 22 to be sent to the firewall."

The Firewall Rules

The "command" entries in the openSSH and closeSSH sections remain the same, except for one parameter. This is how they're comprised:

  • -A: Append the rule to the bottom of the firewall rules list (for the openSSH command).
  • -D: Delete the command from the firewall rules list (for the closeSSH command).
  • INPUT: This rule is concerned with incoming network traffic.
  • -s %IP%: The IP address of the device requesting a connection.
  • -p: Network protocol; in this case, it's TCP.
  • --dport: The destination port; in our example, it's port 22.
  • -j ACCEPT: Jump to the accept target within the firewall. In other words, let the packet drop through the rest of the rules without acting on it.

The knockd Configuration File Edits

The edits we'll make to the file are highlighted in red below:

The knockd config file in the gedit editor with the edits highlighted

We extend the "seq_timeout" to 15 seconds. This is generous, but if someone's manually firing in connection requests, he might need this much time.

In the "openSSH" section, we change the -A (append) option in the command to -I (insert). This command inserts a new firewall rule at the top of the firewall rule list. If you leave the -A option, it appends the firewall rule list and puts it at the bottom.

Incoming traffic is tested against each firewall rule in the list from the top down. We already have a rule that closes port 22. So, if incoming traffic is tested against that rule before it sees the rule that allows the traffic, the connection is refused; if it sees this new rule first, the connection is allowed.

The close command removes the rule added by openSSH from the firewall rules. SSH traffic is once more handled by the pre-existing "port 22 is closed" rule.

After you make these edits, save the configuration file.

The knockd Control File Edits

The knockd control file is altogether simpler. Before we dive in and edit that, though, we need to know the internal name for our network connection; to find it, type this command:

ip addr

ip addr in a terminal window

The connection this machine uses to research this article is called enp0s3. Make a note of the name of your connection.

The following command edits the knockd control file:

sudo gedit /etc/default/knockd

sudo gedit /etc/default/knockd in a terminal window

Here's the knockd file in gedit.

the knockd control file in gedit

The few edits we need to make are highlighted in red:

the knockd control file in gedit with the edits highlighted

We changed the "START_KNOCKD=" entry to from 0 to 1.

We also removed the hash # from the start of the "KNOCKD_OPTS=" entry, and replaced "eth1" with the name of our network connection, enp0s3. Of course, if your network connection is eth1, you won't change it.

The Proof Is in the Pudding

It's time to see if this works. We'll start the knockd daemon with this command:

sudo systemctrl start knockd

sudo systemctrl start knockd in a terminal window

Now, we'll jump on another machine and try to connect. We installed the knockd tool on that computer, too, not because we want to set up port knocking, but because the knockd package provides another tool called knock. We'll use this machine to fire in our secret sequence and do the knocking for us.

Use the following command to send your secret sequence of connection requests to the ports on the port knocking host computer with the IP address 192.168.4.24:

knock 192.168.4.24 7000 8000 9000 -d 500

This tells knock to target the computer at IP address 192.168.4.24 and fire a connection request to ports 7000, 8000, and 9000, in turn, with a -d (delay) of 500 milliseconds between them.

A user called "dave" then makes an SSH request to 192.168.4.24:

ssh dave@192.168.4.24

His connection is accepted, he enters his password, and his remote session begins. His command prompt changes from dave@nostromo to dave@howtogeek. To log out of the remote computer, he types:

exit

His command prompt returns to his local computer. He uses knock once more, and this time, it targets the ports in reverse order to close the SSH port on the remote computer.

knock 192.168.4.24 9000 8000 7000 -d 500

Port knocking and ssh connection session in a terminal window

Admittedly, this wasn't a particularly fruitful remote session, but it demonstrates the opening and closing of the port via port knocking and fits in a single screenshot.

So, what did this look like from the other side? The system administrator on the port knocking host uses the following command to view new entries that arrive in the system log:

tail -f /var/log/syslog

syslog showing the port knocking events in a terminal window
  • You see three openSSH entries. These are raised as each port is targeted by the remote knock utility.
  • When all three stages of the trigger sequence are met, an entry that says "OPEN SESAME," is logged
  • The command to insert the rule into the iptables rules list is sent. It permits access via SSH on port 22 from the specific IP address of the PC that gave the correct secret knock (192.168.4.23).
  • The user "dave" connects for a few seconds only, and then disconnects.
  • You see three closeSSH entries. These are raised as each port is targeted by the remote knock utility—it tells the port knocking host to close port 22.
  • After all three stages are triggered, we get the "OPEN SESAME" message again. The command is sent to the firewall to remove the rule. (Why not "CLOSE SESAME" when it's closing the port? Who knows?)

Now the only rule in the iptables rules list regarding port 22 is the one we typed at the beginning to close that port. So, port 22 is now closed again.

Knock It on the Head

That's port knocking's parlor trick. Treat it as a diversion and don't do it in the real world. Or, if you must, don't rely on it as your only form of security.