Limit Annoying Connection Sources That Try to Access to Our Server With Iptables + Hashlimit

I will introduce the method to limit the number of connections per fixed time with using iptables. For example, you can restrict the brute force attack on your server to reduce the efficiency of the attack. This is effective when the attacker cannot be identified by the IP address, when it is not possible to limit the IP address due to the nature of the service such as SMTP, or when you do not want to affect the legitimate user.

Example scenario:

Explanation:

If you want to restrict the whole (eg, if you want to restrict the communication to port 22 all at once) then use limit, but if you want to control individually based on the client IP address then use hashlimit

The hashlimit control flow looks something like this:

Remarks: Words such as ticket and target group are added for explanation, not general names.

Example configuration:

root@vagrant:/home/vagrant# iptables -N HASHCHECK
root@vagrant:/home/vagrant# iptables -A HASHCHECK -m hashlimit --hashlimit-name hashcheck_t \
--hashlimit 1/m --hashlimit-burst 30 --hashlimit-mode srcip,dstport \
--hashlimit-htable-expire 120000 -j ACCEPT

Explanation:

-m hashlimit: use the hashlimit module

--hashlimit-name hashcheck_t:set the hash table name to hashcheck_t

--hashlimit 1/m: set the number of connections per hour to “1/min”

--hashlimit-burst 30 : set the burst value (number of connections that can ignore the above — hashlimit value and connect) to 30

--hashlimit-mode srcip,dstport: identify the restriction target by source IP address and destination port

--hashlimit-htable-expire 120000 :set the record retention period in the hash table to 120000 milliseconds

root@vagrant:/home/vagrant# iptables -A HASHCHECK -m limit --limit 1/s -j LOG --log-prefix '[IPTABLES HASH DROP] : '
root@vagrant:/home/vagrant# iptables -A HASHCHECK -j DROP
root@vagrant:/home/vagrant# iptables -A INPUT -p icmp -j HASHCHECK

When actually using it, it is better to perform the following processing before limiting with HASHLIMIT.

Checking configuration

root@vagrant:/home/vagrant# iptables -L -vn
Chain INPUT (policy ACCEPT 7 packets, 520 bytes)
pkts bytes target prot opt in out source destination
0 0 HASHCHECK icmp -- * * 0.0.0.0/0 0.0.0.0/0
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 4 packets, 544 bytes)
pkts bytes target prot opt in out source destination
Chain HASHCHECK (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 limit: up to 1/min burst 30 mode srcip-dstport htable-expire 120000
0 0 LOG all -- * * 0.0.0.0/0 0.0.0.0/0 limit: avg 1/sec burst 5 LOG flags 0 level 4 prefix "[IPTABLES HASH DROP] : "
0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0

Testing

Time to test our configuration 😊

root@vagrant:/home/vagrant# ping 192.168.123.123
PING 192.168.123.123 (192.168.123.123) 56(84) bytes of data.
64 bytes from 192.168.123.123: icmp_seq=1 ttl=64 time=0.030 ms
64 bytes from 192.168.123.123: icmp_seq=2 ttl=64 time=0.053 ms
64 bytes from 192.168.123.123: icmp_seq=3 ttl=64 time=0.064 ms
64 bytes from 192.168.123.123: icmp_seq=4 ttl=64 time=0.062 ms
64 bytes from 192.168.123.123: icmp_seq=5 ttl=64 time=0.063 ms
64 bytes from 192.168.123.123: icmp_seq=6 ttl=64 time=0.063 ms
64 bytes from 192.168.123.123: icmp_seq=7 ttl=64 time=0.051 ms
64 bytes from 192.168.123.123: icmp_seq=8 ttl=64 time=0.072 ms
64 bytes from 192.168.123.123: icmp_seq=9 ttl=64 time=0.062 ms
64 bytes from 192.168.123.123: icmp_seq=10 ttl=64 time=0.045 ms
64 bytes from 192.168.123.123: icmp_seq=11 ttl=64 time=0.062 ms
64 bytes from 192.168.123.123: icmp_seq=12 ttl=64 time=0.062 ms
64 bytes from 192.168.123.123: icmp_seq=13 ttl=64 time=0.062 ms
64 bytes from 192.168.123.123: icmp_seq=14 ttl=64 time=0.062 ms
64 bytes from 192.168.123.123: icmp_seq=15 ttl=64 time=0.044 ms
<- Ticket (burst) is exhausted here

As we can see in the log, connections are dropped

root@vagrant:/home/vagrant# tail -f /var/log/syslog
Jul 20 17:37:43 vagrant kernel: [ 217.601323] [IPTABLES HASH DROP] : IN=lo OUT= MAC=11:11:11:11:11:11:11:11:11:11:11:11:11:11 SRC=192.168.123.123 DST=192.168.123.123 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=40086 DF PROTO=ICMP TYPE=8 CODE=0 ID=750 SEQ=16
Jul 20 17:37:44 vagrant kernel: [ 218.624511] [IPTABLES HASH DROP] : IN=lo OUT= MAC=11:11:11:11:11:11:11:11:11:11:11:11:11:11 SRC=192.168.123.123 DST=192.168.123.123 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=40220 DF PROTO=ICMP TYPE=8 CODE=0 ID=750 SEQ=17
Jul 20 17:37:45 vagrant kernel: [ 219.648188] [IPTABLES HASH DROP] : IN=lo OUT= MAC=11:11:11:11:11:11:11:11:11:11:11:11:11:11 SRC=192.168.123.123 DST=192.168.123.123 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=40342 DF PROTO=ICMP TYPE=8 CODE=0 ID=750 SEQ=18
Jul 20 17:37:46 vagrant kernel: [ 220.672312] [IPTABLES HASH DROP] : IN=lo OUT= MAC=11:11:11:11:11:11:11:11:11:11:11:11:11:11 SRC=192.168.123.123 DST=192.168.123.123 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=40590 DF PROTO=ICMP TYPE=8 CODE=0 ID=750 SEQ=19
Jul 20 17:37:47 vagrant kernel: [ 221.696527] [IPTABLES HASH DROP] : IN=lo OUT= MAC=11:11:11:11:11:11:11:11:11:11:11:11:11:11 SRC=192.168.123.123 DST=192.168.123.123 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=40781 DF PROTO=ICMP TYPE=8 CODE=0 ID=750 SEQ=20
Jul 20 17:37:48 vagrant kernel: [ 222.721058] [IPTABLES HASH DROP] : IN=lo OUT= MAC=11:11:11:11:11:11:11:11:11:11:11:11:11:11 SRC=192.168.123.123 DST=192.168.123.123 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=40835 DF PROTO=ICMP TYPE=8 CODE=0 ID=750 SEQ=21
Jul 20 17:37:49 vagrant kernel: [ 223.744844] [IPTABLES HASH DROP] : IN=lo OUT= MAC=11:11:11:11:11:11:11:11:11:11:11:11:11:11 SRC=192.168.123.123 DST=192.168.123.123 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=41079 DF PROTO=ICMP TYPE=8 CODE=0 ID=750 SEQ=22
Jul 20 17:37:50 vagrant kernel: [ 224.768166] [IPTABLES HASH DROP] : IN=lo OUT= MAC=11:11:11:11:11:11:11:11:11:11:11:11:11:11 SRC=192.168.123.123 DST=192.168.123.123 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=41217 DF PROTO=ICMP TYPE=8 CODE=0 ID=750 SEQ=23
Jul 20 17:37:51 vagrant kernel: [ 225.792474] [IPTABLES HASH DROP] : IN=lo OUT= MAC=11:11:11:11:11:11:11:11:11:11:11:11:11:11 SRC=192.168.123.123 DST=192.168.123.123 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=41347 DF PROTO=ICMP TYPE=8 CODE=0 ID=750 SEQ=24
Jul 20 17:37:52 vagrant kernel: [ 226.816439] [IPTABLES HASH DROP] : IN=lo OUT= MAC=11:11:11:11:11:11:11:11:11:11:11:11:11:11 SRC=192.168.123.123 DST=192.168.123.123 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=41390 DF PROTO=ICMP TYPE=8 CODE=0 ID=750 SEQ=25
Jul 20 17:37:53 vagrant kernel: [ 227.840532] [IPTABLES HASH DROP] : IN=lo OUT= MAC=11:11:11:11:11:11:11:11:11:11:11:11:11:11 SRC=192.168.123.123 DST=192.168.123.123 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=41469 DF PROTO=ICMP TYPE=8 CODE=0 ID=750 SEQ=26
Jul 20 17:37:54 vagrant kernel: [ 228.864942] [IPTABLES HASH DROP] : IN=lo OUT= MAC=11:11:11:11:11:11:11:11:11:11:11:11:11:11 SRC=192.168.123.123 DST=192.168.123.123 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=41696 DF PROTO=ICMP TYPE=8 CODE=0 ID=750 SEQ=27
Jul 20 17:37:55 vagrant kernel: [ 229.888339] [IPTABLES HASH DROP] : IN=lo OUT= MAC=11:11:11:11:11:11:11:11:11:11:11:11:11:11 SRC=192.168.123.123 DST=192.168.123.123 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=41827 DF PROTO=ICMP TYPE=8 CODE=0 ID=750 SEQ=28
Jul 20 17:37:56 vagrant kernel: [ 230.912771] [IPTABLES HASH DROP] : IN=lo OUT= MAC=11:11:11:11:11:11:11:11:11:11:11:11:11:11 SRC=192.168.123.123 DST=192.168.123.123 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=41998 DF PROTO=ICMP TYPE=8 CODE=0 ID=750 SEQ=29
Jul 20 17:37:57 vagrant kernel: [ 231.936437] [IPTABLES HASH DROP] : IN=lo OUT= MAC=11:11:11:11:11:11:11:11:11:11:11:11:11:11 SRC=192.168.123.123 DST=192.168.123.123 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=42208 DF PROTO=ICMP TYPE=8 CODE=0 ID=750 SEQ=30

2 minute has passed since the start of new communication, 1 ticket was added and communication was possible.

64 bytes from 192.168.123.123: icmp_seq=62 ttl=64 time=0.051 ms
64 bytes from 192.168.123.123: icmp_seq=63 ttl=64 time=0.072 ms
64 bytes from 192.168.123.123: icmp_seq=64 ttl=64 time=0.062 ms
64 bytes from 192.168.123.123: icmp_seq=65 ttl=64 time=0.045 ms
64 bytes from 192.168.123.123: icmp_seq=66 ttl=64 time=0.062 ms
64 bytes from 192.168.123.123: icmp_seq=67 ttl=64 time=0.062 ms
64 bytes from 192.168.123.123: icmp_seq=68 ttl=64 time=0.062 ms
64 bytes from 192.168.123.123: icmp_seq=69 ttl=64 time=0.062 ms
64 bytes from 192.168.123.123: icmp_seq=70 ttl=64 time=0.044 ms

Thanks for reading!