While iptables technically supports hostnames in rules, the manual explicitly warns against it. The primary concerns are:
- DNS resolution timing: Rules are evaluated for every packet, and DNS lookups would introduce significant latency
- Rule instability: IP addresses behind hostnames can change, potentially breaking your firewall logic
- Boot-time issues: Rules are loaded before network/DNS is available during system startup
Here are several approaches I've used successfully in production environments:
1. IP Set Method (Recommended)
Create an IP set that automatically updates:
# Create IP set
ipset create allowed_sites hash:ip family inet hashsize 1024 maxelem 65536
# Add domains (run periodically via cron)
for domain in google.com example.org; do
for ip in $(dig +short $domain); do
ipset add allowed_sites $ip
done
done
# Reference in iptables
iptables -A zone_lan_forward -m set --match-set allowed_sites dst -j ACCEPT
2. Pre-resolved IP Lists
Maintain a file with resolved IPs and load it at boot:
# /etc/iptables/allowed_ips
1.2.3.0/24
11.12.13.0/24
101.102.103.0/24
# Load script
while read -r ip; do
iptables -A zone_lan_forward -d "$ip" -j ACCEPT
done < /etc/iptables/allowed_ips
3. Hybrid Approach with Fail2ban
Combine static rules with dynamic updates:
# Main rule
iptables -A zone_lan_forward -p tcp -m multiport --dports 80,443 -j ALLOWED_SITES
# Custom chain
iptables -N ALLOWED_SITES
iptables -A ALLOWED_SITES -m recent --name allowed --rcheck --seconds 86400 -j ACCEPT
iptables -A ALLOWED_SITES -j LOG --log-prefix "Blocked site: "
iptables -A ALLOWED_SITES -j DROP
# Update script (run via cron)
for domain in google.com example.org; do
for ip in $(dig +short $domain); do
iptables -I ALLOWED_SITES 1 -d "$ip" -j ACCEPT
iptables -I ALLOWED_SITES 1 -m recent --name allowed --set --destination "$ip"
done
done
When implementing these solutions:
- IP sets provide O(1) lookup time versus iptables' linear search
- Batch updates are better than individual rule additions
- Consider connection tracking (-m state --state RELATED,ESTABLISHED) to reduce rule evaluations
For production systems, I recommend:
#!/bin/bash
# Weekly update script
TMPFILE=$(mktemp)
for domain in google.com example.org; do
dig +short $domain >> "$TMPFILE"
done
# Convert to CIDR ranges (optional)
cat "$TMPFILE" | aggregate -q > /etc/iptables/allowed_ips_new
# Validate before applying
if [ -s /etc/iptables/allowed_ips_new ]; then
mv /etc/iptables/allowed_ips_new /etc/iptables/allowed_ips
systemctl restart iptables
fi
While iptables technically supports hostnames in rules, the manual explicitly warns against it. The primary concerns are:
- DNS resolution delays: Each packet triggering a hostname-based rule requires DNS lookup
- Potential failures: If DNS is unavailable, even legitimate traffic might get blocked
- Rule instability: IP addresses behind hostnames can change without your firewall updating
The most robust solution is using ipset
, which allows creating dynamic sets of IP addresses that can be referenced in iptables:
# Create an IP set for Google
ipset create google_ips hash:net
# Add Google's IP ranges (example addresses)
ipset add google_ips 1.2.3.0/24
ipset add google_ips 11.12.13.0/24
ipset add google_ips 101.102.103.0/24
# Reference the set in iptables
iptables -A zone_lan_forward -p tcp -m set --match-set google_ips dst -j ACCEPT
iptables -A zone_lan_forward -p udp -m set --match-set google_ips dst -j ACCEPT
For dynamic hostnames, create a script to periodically update the IP sets:
#!/bin/bash
# Update Google IPs
hosts=("google.com" "youtube.com" "googleapis.com")
for host in "${hosts[@]}"; do
ips=$(dig +short $host | grep -E '^[0-9]')
ipset flush google_ips
for ip in $ips; do
ipset add google_ips $ip
done
done
Consider using higher-level tools that abstract iptables complexity:
- Firewalld: Provides zones and services concepts
- UFW: Ubuntu's simplified firewall interface
- Shorewall: Configuration file-based management
When dealing with large rule sets:
- Place frequently matched rules higher in the chain
- Use
-m recent
for rate limiting instead of complex rules - Consider connection tracking (
-m conntrack
) for stateful rules
For production environments, I recommend:
- Use ipset for whitelisting domains
- Implement a cron job to update IP sets
- Document all rules with comments
- Consider using configuration management (Ansible, Puppet) for rule deployment