iptables defines tables, which group features:
- filter: use it to filter traffic
- nat: use it to implement NAT
- raw: use it to define which connections iptables should track (stateful firewall)
- mangle: use it to change some fields in packets (e.g., TTL)
- security: use it to define access control
For each table, several chains exist. You can define your own chains too. Predefined chains come with a default target (see below). Typically, the following predefined chains exist:
- INPUT: incoming packets
- FORWARD: packets routed through the system
- OUTPUT: packets originating from the system
Each chain is a list of rules. If a chain is processed, iptables walks through the rules from top to bottom until a rule matches. If no rule matches, the default target applies. A rule may also tell iptables to jump to another chain. If the end of that chain is reached without anything matching, iptables jumps back into the original chain. Each rule has:
- one or more matches: define which packets match the rule (e.g., packets with source IP 10.10.10.15 with protocol TCP)
- one target: the action to take if the rule applies. Either a real action (DROP, ACCEPT, ...) or a jump to another chain.
Traversal of tables and chains looks roughly like this:
iptables is a stateful filewall. It tracks connections to allow for more sophisticated filtering rules. States can be:
- NEW: first package of any new connection
- ESTABLISHED: at least one reply has been sent to the NEW package for this connection. All other now have ESTABLISHED state.
- RELATED: packets are connected to another connection (e.g., FTP data traffic could be related to the control traffic)
- INVALID: means that iptables is confused
- UNTRACKED: the packet was marked as NOTRACK in the raw table
iptables -L -n -v --line-numbers
Add single rules by specifying:
- one chain (INPUT, FORWARD, OUTPUT)
- one or more matches (e.g., -s 10.10.10.1 to match by source IP)
- one target (e.g., DROP to drop the packets)
iptables -A INPUT -s 10.10.10.1 -j DROP
By default, you append to the chain. To insert, e.g., at position 4, run:
iptables -I INPUT 4 -s 10.10.10.1 -j DROP
Delete everything and start from scratch:
iptables -F
Delete single rule by line number:
iptables -L --line-numbers # get number of line to delete
iptables -D INPUT <line_number> # then delete it
Delete single rule by specification
iptables -S # shows iptables commands which were used to add current rules
iptables -D ... # paste the command from above, but without the -A
Save current rules to file
iptables-save > /etc/sysconfig/iptables
Load rules from file (must be set up to happen on boot, possibly manually by admin)
iptables-restore < /etc/sysconfig/iptables
Block single IP
iptables -A INPUT -s 10.10.10.1 -j DROP
Allow incoming SSH from IP range
iptables -A INPUT -p tcp -s 10.10.0.0/24 --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
Allow outgoing DNS requests only on interface eth0
iptables -A OUTPUT -p udp -o eth0 --dport 53 -j ACCEPT
iptables -A INPUT -p udp -i eth0 --sport 53 -j ACCEPT
Port forwarding to machine on private network (e.g., connect to firewall on port 2222 and be forwarded to other machine on 22)
iptables -t nat -A PREROUTING -p tcp -d 10.10.10.1 --dport 2222 -j DNAT --to 192.168.0.100:22
An example configuration for incoming SSH connections. Protects against brute forcing and limits parallel connections.
# delete all rules and custom chains
iptables -F
iptables -X
# drop incoming traffic by default
iptables -P INPUT DROP
# accept established connections
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# SSH to init chain
iptables -N ssh_init
iptables -A INPUT -p tcp --dport 22 --syn -j ssh_init
# SSH traffic init chain
# maintains a list of IP addresses trying to establish SSH connections (--set).
# Drops packets if IP tried it more than 3 times in last 60 seconds.
# --rttl ensures we match both IP and TTL of the packets so that nobody can (too easily) spoof our IP and DoS us.
iptables -A ssh_init -m recent --name ssh_ip_list --rcheck --seconds 60 --hitcount 3 --rttl -j DROP
iptables -A ssh_init -m recent --name ssh_ip_list --set -j RETURN
# SSH traffic to throttle ssh
iptables -N ssh_throttle
iptables -A INPUT -p tcp --dport 22 --syn -j ssh_throttle
# SSH traffic throttle chain
# ensures we can have an SSH connection only every 20 secs and max 3 at a time
iptables -A ssh_throttle -m connlimit --connlimit-above 3 -j DROP
iptables -A ssh_throttle -m limit --limit 3/m --limit-burst 1 -j ACCEPT
- ArchLinux, good docs: https://wiki.archlinux.org/index.php/Simple_stateful_firewall
- Extensive (and old) tutorial: https://www.frozentux.net/iptables-tutorial/iptables-tutorial.html