ICMP port knocking in OpenWRT
I had to climb a lot of resources. I also thought of writing scripts to track LOG or ULOG events from iptables in the system log. I even came across a project - Specter , with which you can implement a reaction (script execution) to iptables ULOG events, which is not in ulogd. Herea large selection of old projects for implementing Port knocking, but I did not want to compile on a router or virtual machine at all. When searching for a solution, I often came up with tips about the speed and convenience of ipsets, so as not to pile up iptables with a bunch of “identical” rules. And in them the keys "--match-set" and "--add-set" were noticed, further searches led to a solution.
In general, it was decided to use ipsets, as no need to track anything and write reactions to events outside iptables.
So, the solution is implemented using purely iptables and ipset. For simplicity of perception, the combination of “knocks” will be the same as in the mentioned article. Let me remind you this - 2 ICMP packets in a row with a size of 70 bytes and after them 2 ICMP packets in a row with a size of 100 bytes.Well, do not forget about the size of the header of the ICMP parquet (28 bytes) .
In my case, after the corresponding “knocks”, a connection is allowed on port 1194 / tcp for the OpenVPN server for the IP address from which the “knocks” were made. The instructions for setting up an OpenVPN server on OpenWRT can be found on the official Wiki , as This is beyond the scope of this article.
Preparing ipsets
It is worth noting that the support for the rules for creating ipsets in the OpenWRT firewall settings file appeared only with the release of Attitude Adjustment, although the revision r36349 did not work ( When applying the rules, it issued a warning that datatype was not specified for ipsets ).
But ipsets can be created with pens, it is advisable to create them at boot time, for example: register in /etc/rc.local.
ipset create knock1 hash:ip
ipset create knock2 hash:ip
ipset create knock3 hash:ip
ipset create AllowedVPN hash:ip
If fw3 supports the creation of ipsets (fw3 is the OpenWRT firewall management tool itself, a detailed description of the settings can be found on the official Wiki ), then the following items are added to the firewall settings file / etc / config / firewall :
config ipset
option enabled 1
option name knock1
option storage hash
option match src_ip
config ipset
option enabled 1
option name knock2
option storage hash
option match src_ip
config ipset
option enabled 1
option name knock3
option storage hash
option match src_ip
config ipset
option enabled 1
option name AllowedVPN
option storage hash
option match src_ip
ICMP packet sequencing logic
Catch the first knock
icmptype 8 length 98 ! match-set knock1 src ! match-set knock2 src ! match-set knock3 src ! match-set AllowedVPN src add-set knock1 srcThe outgoing ICMP packet address of 98 bytes is entered in ipset knock1, if it is not in other ipsets.
We catch the second knock
icmptype 8 length 98 match-set knock1 src ! match-set knock2 src ! match-set knock3 src ! match-set AllowedVPN src add-set knock2 src
The outgoing ICMP packet address of 98 bytes is entered in ipset knock2, if it is already in ipset knock1 and not in the rest.Catch the third knock
icmptype 8 length 128 match-set knock1 src match-set knock2 src ! match-set knock3 src ! match-set AllowedVPN src add-set knock3 src
The outgoing ICMP packet address of 128 bytes is entered in ipset knock3, if it is also present in ipset knock1 and knock2, but not in AllowedVPN.We catch the fourth knock
icmptype 8 length 128 match-set knock1 src match-set knock2 src match-set knock3 src ! match-set AllowedVPN src add-set AllowedVPN src
The outgoing address of the 128-byte ICMP packet is entered in ipset AllowedVPN, if it is also present in ipset knock1, knock2 and knock3.
In order for the sequence to be caught correctly, the rules in iptables must be entered in the reverse order . Otherwise, the first “knock” will be caught by the first and second rules immediately, just as the third “knock” will be caught by the third and fourth rules immediately.
Additional checks for absence in other ipsets are indicated to clearly trigger a sequence of “knocks” .
The following is a sequence of iptables commands to put in the input_rule chain (a specially created chain in the OpenWRT firewall for user rules) is added to /etc/firewall.user .
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set ! --match-set AllowedVPN src -j SET --add-set AllowedVPN src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j SET --add-set knock3 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98 -m limit --limit 10/s -m set --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j SET --add-set knock2 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98 -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j SET --add-set knock1 srciptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set ! --match-set AllowedVPN src -j LOG --log-prefix "(KNOCK4 O) "
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set ! --match-set AllowedVPN src -j SET --add-set AllowedVPN src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j LOG --log-prefix "(KNOCK3 O) "
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j SET --add-set knock3 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98 -m limit --limit 10/s -m set --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j LOG --log-prefix "(KNOCK2 O) "
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98 -m limit --limit 10/s -m set --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j SET --add-set knock2 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98 -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j LOG --log-prefix "(KNOCK1 O) "
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98 -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j SET --add-set knock1 srcThe most important rule
It is this rule that allows an incoming connection to port 1194 / tcp, if the IP address from which the connection is made is located in the ipset AllowedVPN.
config 'rule'
option enabled 1
option 'target' 'ACCEPT'
option 'name' 'VPN'
option 'src' 'wan'
option 'proto' 'tcp'
option 'dest_port' '1194'
option 'extra' '-m set --match-set AllowedVPN src'
Otherwise, it can be written in /etc/firewall.user
iptables -A input_rule -p tcp --dport 1194 -m set --match-set AllowedVPN src -j ACCEPT
Port knocking
You can perform Port knocking on Windows with the command:
ping readyshare.mydomain.ua -l 70 -n 2 && ping readyshare.mydomain.ua -l 100 -n 2

Close access
I will not completely paint the logic, because it is very similar to the one described above, just the verification logic in the rules is inverted and there is a deletion from ipsets. Well, and accordingly, if the IP address is not in ipset-e AllowedVPN, then there is no access.
The sequence of “knocks” is the same as when opening access.
The following is a sequence of iptables commands to chain to input_rule, file /etc/firewall.user
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set --match-set AllowedVPN src -j SET --del-set AllowedVPN src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j SET --del-set knock3 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98 -m limit --limit 10/s -m set ! --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j SET --del-set knock2 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98 -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j SET --del-set knock1 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set --match-set AllowedVPN src -j LOG --log-prefix "(KNOCK4 C) "
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set --match-set AllowedVPN src -j SET --del-set AllowedVPN src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j LOG --log-prefix "(KNOCK3 C) "
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j SET --del-set knock3 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98 -m limit --limit 10/s -m set ! --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j LOG --log-prefix "(KNOCK2 C) "
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98 -m limit --limit 10/s -m set ! --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j SET --del-set knock2 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98 -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j LOG --log-prefix "(KNOCK1 C) "
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98 -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j SET --del-set knock1 src
I hope my experience is useful to others.
A good presentation on Chris Cooper's ipsets from QC Co-Lab, from which I started to build on the solution.