When working with iptables firewall rules, the limit
module provides crucial traffic shaping capabilities. Let's dissect the two example rules from CentOS 5.x systems:
-A RH-Firewall-1-INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT
-A RH-Firewall-1-INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s --limit-burst 3 -j ACCEPT
The --limit 1/s
parameter specifies that the rule will match at an average rate of 1 packet per second. This is implemented using a token bucket algorithm where tokens are added to the bucket at the specified rate.
The --limit-burst
parameter (defaulting to 5 when unspecified) determines:
- Initial capacity of the token bucket
- Maximum burst capacity before rate limiting engages
- Number of packets that can arrive in quick succession
For the first rule (without explicit burst):
Time Action Tokens
0s Packet 1 4 (5-1)
0.1s Packet 2 3
0.2s Packet 3 2
0.3s Packet 4 1
0.4s Packet 5 0
0.5s Packet 6 Rejected (bucket empty)
1.0s Token added 1 (rate replenishment)
For the second rule (burst=3):
Time Action Tokens
0s Packet 1 2 (3-1)
0.1s Packet 2 1
0.2s Packet 3 0
0.3s Packet 4 Rejected
1.0s Token added 1
These rules apply globally to all ICMP echo requests, not per-host. For per-host limiting, you'd need additional matches:
-A RH-Firewall-1-INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s --limit-burst 2 -m hashlimit --hashlimit-mode srcip --hashlimit-above 1/s -j DROP
Combining with logging for debugging:
-A RH-Firewall-1-INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s --limit-burst 3 -j LOG --log-prefix "ICMP_ACCEPT: "
-A RH-Firewall-1-INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s --limit-burst 3 -j ACCEPT
-A RH-Firewall-1-INPUT -p icmp --icmp-type echo-request -j LOG --log-prefix "ICMP_DROP: "
-A RH-Firewall-1-INPUT -p icmp --icmp-type echo-request -j DROP
For SSH rate limiting (more practical example):
-A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH
-A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 --rttl --name SSH -j DROP
The limit module adds minimal overhead as it uses kernel-level counters. However, for high-traffic systems, consider:
- Using
hashlimit
for per-IP scaling - Combining with
connlimit
for connection-based throttling - Testing rules with
-j LOG
before production deployment
The Linux kernel's netfilter framework (accessed via iptables) includes a powerful limit
match module that implements token bucket filtering. Here's the technical breakdown:
-m limit --limit [rate] --limit-burst [number]
The token bucket algorithm works by:
- Filling a "bucket" with tokens at the specified rate (--limit)
- Each packet consumes one token
- When tokens are exhausted, packets stop matching
Your first example:
-A RH-Firewall-1-INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT
This means:
- Allow 1 ICMP echo request per second on average
- Uses default burst of 5 packets (when unspecified)
- Tokens replenish at 1 per second
The second example with explicit burst:
-A RH-Firewall-1-INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s --limit-burst 3 -j ACCEPT
Key differences:
- Initial burst capacity of 3 packets
- After burst, limits to 1 packet per second
- Burst bucket refills at 1 token per second
These limits apply globally to all matching traffic, not per-source IP. For per-IP limiting, combine with the hashlimit
module:
-A RH-Firewall-1-INPUT -p icmp --icmp-type echo-request \
-m hashlimit --hashlimit-name ICMP \
--hashlimit-mode srcip --hashlimit 1/s \
--hashlimit-burst 3 -j ACCEPT
Verify your rules with these commands:
# Watch rule hits in real-time:
watch -n1 'iptables -L RH-Firewall-1-INPUT -v --line-numbers'
# Generate test traffic (from another host):
ping -f [target_ip] # Flood ping
ping -i 0.5 [target_ip] # 2 packets/sec
Expected behavior with --limit 1/s --limit-burst 3:
- First 3 pings succeed immediately
- Subsequent pings limited to 1 per second
- After 3 seconds of no traffic, burst refills to 3
For more precise control, combine with logging:
-A RH-Firewall-1-INPUT -p icmp --icmp-type echo-request \
-m limit --limit 1/s --limit-burst 3 -j ACCEPT
-A RH-Firewall-1-INPUT -p icmp --icmp-type echo-request \
-j LOG --log-prefix "ICMP Flood: "
-A RH-Firewall-1-INPUT -p icmp --icmp-type echo-request -j DROP
This configuration will:
- Allow bursts of up to 3 ICMP requests
- Then permit 1 request per second
- Log and drop any excess requests
Remember that these rules process in order, so place your rate-limited ACCEPT rule before your DROP rules.