IPTABLES
Authorized use only. Offensive reference for systems you own or are explicitly permitted to test. You are responsible for staying within the law.
Iptables is the traditional Linux firewall tool for packet filtering. Note: nftables is the successor, but iptables remains widely used.
BASIC CONCEPTS#
Tables: filter, nat, mangle, raw, security Chains: INPUT, OUTPUT, FORWARD, PREROUTING, POSTROUTING Targets: ACCEPT, DROP, REJECT, LOG, MASQUERADE, SNAT, DNAT Default table is 'filter' with chains: - INPUT: Incoming packets destined for local - OUTPUT: Outgoing packets from local - FORWARD: Packets routed through
VIEW RULES#
iptables -L # List filter rules iptables -L -v # Verbose (packets/bytes) iptables -L -n # Numeric (no DNS lookup) iptables -L -v -n # Verbose + numeric iptables -L --line-numbers # Show rule numbers iptables -L INPUT # Specific chain iptables -S # Show rules as commands iptables -t nat -L # List NAT rules iptables -t mangle -L # List mangle rules
BASIC RULE SYNTAX#
iptables -A CHAIN -j TARGET # Append rule iptables -I CHAIN -j TARGET # Insert at top iptables -I CHAIN 3 -j TARGET # Insert at position 3 iptables -D CHAIN -j TARGET # Delete by specification iptables -D CHAIN 3 # Delete by number iptables -R CHAIN 3 -j TARGET # Replace rule 3 iptables -F # Flush all rules iptables -F CHAIN # Flush specific chain iptables -X # Delete user chains iptables -Z # Zero counters
MATCH OPTIONS#
-p protocol # tcp, udp, icmp, all -s source # Source IP/network -d destination # Destination IP/network -i interface # Input interface -o interface # Output interface --sport port # Source port --dport port # Destination port -m module # Load match module
BASIC FILTERING#
# Allow established connections iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # Allow loopback iptables -A INPUT -i lo -j ACCEPT # Allow SSH iptables -A INPUT -p tcp --dport 22 -j ACCEPT # Allow HTTP/HTTPS iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j ACCEPT # Allow ping iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT # Drop all other incoming iptables -A INPUT -j DROP # Allow all outgoing iptables -A OUTPUT -j ACCEPT
ALLOW BY SOURCE#
# Allow from specific IP iptables -A INPUT -s 192.168.1.100 -j ACCEPT # Allow from network iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT # Allow SSH from specific network iptables -A INPUT -p tcp -s 10.0.0.0/8 --dport 22 -j ACCEPT
BLOCK TRAFFIC#
# Block IP iptables -A INPUT -s 192.168.1.100 -j DROP # Block network iptables -A INPUT -s 10.10.10.0/24 -j DROP # Block port iptables -A INPUT -p tcp --dport 23 -j DROP # Reject (sends response) vs Drop (silent) iptables -A INPUT -p tcp --dport 23 -j REJECT iptables -A INPUT -p tcp --dport 23 -j DROP
PORT RANGES#
# Multiple ports iptables -A INPUT -p tcp -m multiport --dports 80,443,8080 -j ACCEPT # Port range iptables -A INPUT -p tcp --dport 1000:2000 -j ACCEPT # Source port range iptables -A OUTPUT -p tcp --sport 1024:65535 -j ACCEPT
STATE MATCHING#
# Connection states iptables -A INPUT -m state --state NEW -j ACCEPT iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT iptables -A INPUT -m state --state RELATED -j ACCEPT iptables -A INPUT -m state --state INVALID -j DROP # Or using conntrack (newer) iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
RATE LIMITING#
# Limit SSH connections
iptables -A INPUT -p tcp --dport 22 -m limit --limit 3/minute --limit-burst 3 -j ACCEPT
# Limit ICMP
iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/second -j ACCEPT
# Hashlimit per source IP
iptables -A INPUT -p tcp --dport 80 -m hashlimit \
--hashlimit 50/second --hashlimit-burst 100 \
--hashlimit-mode srcip --hashlimit-name http -j ACCEPT
LOGGING#
# Log before dropping iptables -A INPUT -j LOG --log-prefix "DROPPED: " --log-level 4 iptables -A INPUT -j DROP # Log specific traffic iptables -A INPUT -p tcp --dport 22 -j LOG --log-prefix "SSH: " # Limit logging iptables -A INPUT -m limit --limit 5/minute -j LOG --log-prefix "LIMIT: "
NAT - NETWORK ADDRESS TRANSLATION#
# Enable IP forwarding first echo 1 > /proc/sys/net/ipv4/ip_forward # MASQUERADE (dynamic source NAT) iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE # SNAT (static source NAT) iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 203.0.113.1 # DNAT (port forwarding) iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.1.100:80 # Redirect (local port redirect) iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
PORT FORWARDING EXAMPLE#
# Forward external port 8080 to internal 192.168.1.100:80 iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.100:80 iptables -A FORWARD -p tcp -d 192.168.1.100 --dport 80 -j ACCEPT
SET DEFAULT POLICIES#
iptables -P INPUT DROP # Default drop incoming iptables -P FORWARD DROP # Default drop forwarded iptables -P OUTPUT ACCEPT # Default allow outgoing
SAVE AND RESTORE#
# Save rules iptables-save > /etc/iptables.rules iptables-save > /etc/iptables/rules.v4 # Debian/Ubuntu # Restore rules iptables-restore < /etc/iptables.rules # Persistent (Debian/Ubuntu) apt install iptables-persistent netfilter-persistent save netfilter-persistent reload # Persistent (RHEL/CentOS) service iptables save systemctl enable iptables
CUSTOM CHAINS#
# Create chain iptables -N MYCHAIN # Add rules to chain iptables -A MYCHAIN -s 192.168.1.0/24 -j ACCEPT iptables -A MYCHAIN -j DROP # Jump to chain iptables -A INPUT -p tcp --dport 22 -j MYCHAIN # Delete chain (must be empty and unused) iptables -F MYCHAIN iptables -X MYCHAIN
COMPLETE FIREWALL EXAMPLE#
#!/bin/bash
# Flush existing rules
iptables -F
iptables -X
iptables -t nat -F
# Default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# Allow loopback
iptables -A INPUT -i lo -j ACCEPT
# Allow established
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow SSH (with rate limit)
iptables -A INPUT -p tcp --dport 22 -m state --state NEW \
-m limit --limit 3/min --limit-burst 3 -j ACCEPT
# Allow HTTP/HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# Allow ping (limited)
iptables -A INPUT -p icmp --icmp-type echo-request \
-m limit --limit 1/second -j ACCEPT
# Log dropped packets
iptables -A INPUT -m limit --limit 5/min -j LOG \
--log-prefix "iptables dropped: " --log-level 7
# Drop everything else (already default, but explicit)
iptables -A INPUT -j DROP
BRUTE FORCE PROTECTION#
# SSH brute force protection using recent module
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent \
--update --seconds 60 --hitcount 4 --name SSH -j DROP
BLOCK INVALID PACKETS#
iptables -A INPUT -m state --state INVALID -j DROP iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP iptables -A INPUT -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP iptables -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
IP6TABLES (IPv6)#
# Same syntax, use ip6tables ip6tables -L ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT
DEBUGGING#
# Watch rules in action watch -n 1 'iptables -L -v -n' # Trace packet (requires raw table) iptables -t raw -A PREROUTING -p tcp --dport 22 -j TRACE # View in: dmesg or /var/log/kern.log # Test rule without saving iptables -A INPUT -s 1.2.3.4 -j DROP # Then: iptables -D INPUT -s 1.2.3.4 -j DROP
QUICK REFERENCE#
iptables -L -v -n # List rules iptables -A INPUT -j ACCEPT # Append rule iptables -I INPUT -j ACCEPT # Insert at top iptables -D INPUT 3 # Delete rule 3 iptables -F # Flush all iptables -P INPUT DROP # Set policy iptables-save > rules # Save iptables-restore < rules # Restore