Port knocking is a fun tactic for exposing otherwise hidden services to a client that can present a shared secret in the form of a correct series of particular packets. Since the server end of the scheme is typically implemented with Netfilter the number of ways the authentication can be complicated is limited only by Netfilter's capacity to filter packets. For example you could choose to implement a scheme that requires packets of various sizes, header configurations or payloads. In its simplest and most common form the client sends a tcp SYN packet to a series of ports at the destination address in a specific sequence known only to the client and server. This allows an authorized user to gain access from virtually any machine equipped with any number of TCP based, port-configurable clients including telnet, avoiding the inherent problems of requiring specialty software or custom scripts.
#!/bin/sh
#
# http://foxpa.ws/port-knocking/
#
# Uncomment LOG rules to monitor client activity via syslog.
PORT1=1111
PORT2=2222
PORT3=3333
PORT4=4444
PROTECTED=22
TIMEOUT=60
iptables -N KNOCKP1
iptables -A KNOCKP1 -m recent --name KNOCKP1 --set
#iptables -A KNOCKP1 -j LOG --log-prefix "KNOCK PHASE1: "
iptables -N KNOCKP2
iptables -A KNOCKP2 -m recent --name KNOCKP1 --remove
iptables -A KNOCKP2 -m recent --name KNOCKP2 --set
#iptables -A KNOCKP2 -j LOG --log-prefix "KNOCK PHASE2: "
iptables -N KNOCKP3
iptables -A KNOCKP3 -m recent --name KNOCKP2 --remove
iptables -A KNOCKP3 -m recent --name KNOCKP3 --set
#iptables -A KNOCKP3 -j LOG --log-prefix "KNOCK PHASE3: "
iptables -N KNOCKP4
iptables -A KNOCKP4 -m recent --name KNOCKP3 --remove
iptables -A KNOCKP4 -m recent --name KNOCKP --set
#iptables -A KNOCKP4 -j LOG --log-prefix "KNOCK PHASE4: "
iptables -N KNOCK
iptables -A KNOCK -p tcp -m tcp --dport $PORT1 -m conntrack --ctstate NEW -j KNOCKP1
iptables -A KNOCK -p tcp -m tcp --dport $PORT2 -m conntrack --ctstate NEW -m recent --rcheck --seconds $TIMEOUT --reap --name KNOCKP1 -j KNOCKP2
iptables -A KNOCK -p tcp -m tcp --dport $PORT3 -m conntrack --ctstate NEW -m recent --rcheck --seconds $TIMEOUT --reap --name KNOCKP2 -j KNOCKP3
iptables -A KNOCK -p tcp -m tcp --dport $PORT4 -m conntrack --ctstate NEW -m recent --rcheck --seconds $TIMEOUT --reap --name KNOCKP3 -j KNOCKP4
iptables -A INPUT ! -s 127.0.0.1/8 -j KNOCK
iptables -A INPUT -p tcp -m tcp -dport $PROTECTED -m conntrack --ctstate NEW -m recent --rcheck --seconds $TIMEOUT --name KNOCK --reap -j ACCEPT
iptables -A INPUT -p tcp -m tcp -dport $PROTECTED -m conntrack --ctstate NEW -j REJECT
We can use netcat or nmap to send our knocks:
$ nc -z -w1 hostname port
$ nmap -Pn --host_timeout 1 --max-retries 0 -p port hostname
It's easy to create a one-liner using shell loops:
$ for x in 1111 2222 3333 4444; do nc -z -w1 hostname $x && sleep 1; done && ssh hostname
You can add this to your OpenSSH client configuration at ~/.ssh/config (create the file if it does not exist) so that it runs every time you attempt to connect to host.alias:
Host host.alias
HostName hostname
ProxyCommand sh -c "for x in 1111 2222 3333 4444; do nc -z -w1 %h $x; done && nc %h %p"