Implement Port-Knocking Security with knockd

Instead of closing ports, make them disappear.
Configuring and Running knockd

The config file /etc/knockd.conf is divided into sections, one for each specific knock sequence, with a special general section, options, for global parameters. Let's go through the general options first:

  • You can log events either to a specific file by using LogFile=/path/to/log/file, or to the standard Linux log files by using UseSyslog. Note: it's sometimes suggested that you avoid such logging, because it enables an extra possible goal for attackers—should they get their hands on the log, they would have the port-knocking sequences.

  • When knockd runs as a dæmon, you may want to check whether it's still running. The PidFile=/path/to/PID/file option specifies a file into which knockd's PID (process ID) will be stored. An interesting point: should knockd crash, your system will be safer than ever—all ports will be closed (so safer) but totally unaccessible. You might consider implementing a cron task that would check for the knockd PID periodically and restart the dæmon if needed.

  • By default, eth0 will be the observed network interface. You can change this with something like Interface=eth1. You must not include the complete path to the device, just its name.

Every sequence you want to recognize needs a name; the example (Listing 2) used just one, named openclosessh. Options and their parameters can be written in upper-, lower- or mixed case:

  • Sequence is used to specify the desired series of knocks—for example, 7005,7007:udp,7003. Knocks are usually TCP, but you can opt for UDP.

  • One_Time_Sequences=/path/to/file allows you to specify a file containing “use once” sequences. After each sequence is used, it will be erased. You just need a text file with a sequence (in the format above) in each line.

  • is the maximum time for completing a sequence. If you take too long to knock, you won't be able to get in.

  • Start_Command=some.command specifies what command (either a single line or a full script) must be executed after recognizing a knock sequence. If you include the %IP% parameter, it will be replaced at runtime by the knocker's IP. This allows you, for example, to open the firewall port but only for the knocker and not for anybody else. This example uses an iptables command to open the port (see Resources for more on this).

  • lets you execute a second command a certain time after the start command is run. You can use this to close the port; if the knocker didn't log in quickly enough, the port will be closed.

  • Stop_Command=some.other.command is the command that will be executed after the second timeout.

  • TCPFlags=list.of.flags lets you examine incoming TCP packets and discard those that don't match the flags (FIN, SYN, RST, PSH, ACK or URG; see Resources for more on this). Over an SSH connection, you should use TCPFlags=SYN, so other traffic won't interfere with the knock sequence.

For the purposes of this example (remotely opening and closing port 22), you didn't need more than a single sequence, shown in Listing 2. However, nothing requires having a single sequence, and for that matter, commands do not have to open ports either! Whenever a knock sequence is recognized, the given command will be executed. In the example, it opened a firewall port, but it could be used for any other functions you might think of—triggering a backup, running a certain process, sending e-mail and so on.

The knockd command accepts the following command-line options:

  • -c lets you specify a different configuration file, instead of the usual /etc/knockd.conf.

  • -d makes knockd run as a dæmon in the background; this is the standard way of functioning.

  • -h provides syntax help.

  • -i lets you change which interface to listen on; by default, it uses whatever you specify in the configuration file or eth0 if none is specified.

  • -l allows looking up DNS names for log entries, but this is considered bad practice, because it forces your machine to lose stealthiness and do DNS traffic, which could be monitored.

  • -v produces more verbose status messages.

  • -D outputs debugging messages.

  • -V shows the current version number.

In order to send the required knocks, you could use any program, but the knock command that comes with the knockd package is the usual choice. An example of its usage is shown above (knock 7005) for a TCP knock on port 7005. For a UDP knock, either add the -u parameter, or do knock 7005:udp. The -h parameter provides the (simple) syntax description.