šŸ“œ ā¬†ļø ā¬‡ļø

ICMP port knocking in OpenWRT

Impressed with the article I decided to implement such a solution on a home router, running OpenWRT (Bleeding Edge r38381). The solution is probably not as elegant as on Mikrotik, but the main thing is that it is working and without scripts and cron. It can also be taken as a basis for implementation on other Linux operating systems. Who cares please under the cat.

I had to climb a lot of resources. I also thought of writing scripts by tracking LOG or ULOG events from iptables in the system log. I even came across a project - Specter , with which you can implement a reaction (execution of scripts) to ULOG events from iptables, which is not in ulogd. There is a large selection of old projects for implementing Port knocking, but I didn’t want to compile on a router or virtual server at all. When searching for a solution, I often came across tips about the speed and convenience of ipsets, so as not to pile on iptables with a bunch of ā€œidenticalā€ rules. And the keys "--match-set" and "--add-set" were noticed in them, further searches led to the solution.
In general, it was decided to use ipsets, since you do not need to monitor anything and write reactions to events outside of iptables.

So, the solution is implemented using purely iptables and ipset. For ease of perception, the combination of ā€œknocksā€ will be the same as in the above article. Let me remind you - 2 ICMP packets in a row of 70 bytes in size and 2 ICMP packets in a row of 100 bytes in size. Well, do not forget about the size of the header ICMP parquet (28 bytes) .
In my case, after the corresponding knocks, the 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 OpenVPN server on OpenWRT can be found on the official Wiki , because this is beyond the scope of this article.
')

Preparing ipsets


It should be noted that the support for the rules for creating ipsets in the OpenWRT firewall settings file appeared only from the Attitude Adjustment release, although in the r36349 revision did not work ( When applying the rules, it issued a warning that no datatype was specified for ipsets ).

But ipsets can be created by handles, it is desirable to create them when loading, for example: write 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 creating 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 sequence trapping 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 src 

The outgoing ICMP address of a packet of 98 bytes is entered in the ipset knock1, if it is not in the 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 address of an ICMP packet with a size of 98 bytes is entered into the ipset knock2, if it already exists in the 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 address of a 128-byte packet is recorded in the ipset knock3, if it is also present in the ipset-a knock1 and knock2, but not in AllowedVPN.

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 ICMP packet address of 128 bytes 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 at once, just as the third ā€œknockā€ will be caught by the third and fourth rules at once.
Additional checks for the absence of other ipsets are indicated for accurate triggering of the ā€œknockā€ sequence .

Below is a sequence of iptables commands for entering input_rule into the chain (a specially created chain in the OpenWRT firewall for user rules) are 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 src 

The same rules, but with logging to the system log
 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 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 src 


"The most important" rule


It is this rule that allows incoming connections on port 1194 / tcp, if the IP address from which the connection is made, is 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


To produce Port knocking in Windows, use the command
ping readyshare.mydomain.ua -l 70 -n 2 && ping readyshare.mydomain.ua -l 100 -n 2



Close access


Fully paint the logic will not, because it is very similar to the one described above, just the logic of the check in the rules is inverted and deletes from the ipsets. Well, accordingly, if there is no IP address in ipset-e AllowedVPN, then there is no access.
The sequence of "knocks" is the same as when opening access.
Below is a sequence of iptables commands for 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 

The same rules for blocking but logging to the system log
 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 will be useful to others.

A good presentation on Chris Cooper's ipset-am from QC Co-Lab, from which I began to make a start when building a solution.

Source: https://habr.com/ru/post/198108/


All Articles