iptablesFilter and NAT packets with netfilter rules
iptables manages the kernel's packet-filtering rules: which incoming, outgoing and forwarded packets are accepted, dropped or rewritten (NAT). Even where nftables, ufw, firewalld, Docker or Kubernetes write the rules for you, iptables is how you read and debug them.
iptables [-t TABLE] -A|-I|-D|-R CHAIN [N] RULE-SPEC -j TARGET | iptables -L|-S [CHAIN] [-n -v --line-numbers] | -P CHAIN POLICYBefore touching a server's firewall, see what rules exist and which chain policies apply.
sudoReading and changing rules both need root (CAP_NET_ADMIN).
Netfilter is a set of hooks in the kernel's network path. A packet arriving on an interface passes PREROUTING (where DNAT happens), then the routing decision: if it's addressed to this host it goes through INPUT and on to the local socket; if not, and forwarding is on, through FORWARD and POSTROUTING (where SNAT/MASQUERADE happens) and out. Packets the host itself sends go through OUTPUT and POSTROUTING. Each hook has chains in several tables (filter for accept/drop, nat for address rewriting, mangle and raw). Rules in a chain are checked top to bottom and the first one whose matches all fit decides with its target; if none matches, the chain's policy (ACCEPT or DROP) applies. Connection tracking (conntrack) lets one rule accept all packets of ESTABLISHED connections, so you only write rules for new ones. Rules live only in kernel memory: iptables-save dumps them and something must restore them at boot.
Incoming packets pass PREROUTING, the routing decision, then INPUT (for this host) or FORWARD; rules are checked top down and the first match wins.
A client at 198.51.100.23 opens an SSH connection. The packet enters through ens5 and hits the PREROUTING hook, where conntrack sees it as a NEW connection and nat rules could rewrite its destination.
-L [CHAIN] -n -vList rules numerically with packet/byte counters and interfaces--line-numbersShow rule positions (for -I N and -D N)-S [CHAIN]Print rules as the commands that create them-A CHAINAppend a rule at the end-I CHAIN [N]Insert a rule at position N (default 1, the top)-D CHAIN N|RULEDelete a rule by number or by exact specification-P CHAIN ACCEPT|DROPSet the chain's default policy-F [CHAIN]Flush (delete) all rules in a chain or table-t nat|mangle|rawWork on another table (default filter)-p, --dport, -s, -d, -i, -oMatch protocol, port, source, destination, in/out interface-m conntrack --ctstateMatch connection state: NEW, ESTABLISHED, RELATED, INVALID-j ACCEPT|DROP|REJECT|LOGWhat to do with matching packets-ZZero the packet and byte countersiptables-save / -restoreDump all rules to text / load them back atomicallysudo iptables -P INPUT DROP before adding an ACCEPT rule for SSH (or for ESTABLISHED)Your own SSH session's packets match nothing and are dropped instantly: you're locked out.
Add lo, ESTABLISHED,RELATED and SSH ACCEPT rules first, set the policy last; or schedule a rollback (e.g. at now + 5 min: iptables-restore < backup)iptables -A INPUT -s BAD_IP -j DROP to block an attacker-A appends after your ACCEPT rules, and since the first match wins, the attacker's traffic is accepted before reaching it.
iptables -I INPUT 1 -s BAD_IP -j DROPRelying on INPUT rules to protect ports published by DockerPublished ports are DNATed and pass through FORWARD, so INPUT never sees them; Docker's own rules accept them.
Put filters in the DOCKER-USER chain, or bind published ports to 127.0.0.1.Configuring rules and forgetting to save themRules exist only in kernel memory and disappear at reboot, often unnoticed until the next maintenance window.
netfilter-persistent save (Ubuntu) or iptables-save > /etc/sysconfig/iptables (RHEL)Mixing raw iptables commands with ufw or firewalld on the same hostThe managers rewrite the rule set on reload and your manual rules vanish or conflict.
Pick one tool per host and make all changes through it.Try these on a Linux machine of your own. Each task has a hint and a solution.
List the filter table's rules with numeric output, counters and line numbers.
Add a rule that rejects (not drops) TCP connections to port 8081 with a TCP reset, then show the INPUT chain as commands.
Insert a rule at the top of INPUT that drops everything from 192.0.2.66, then delete it again by its number.
Save the current rules to /tmp/rules.v4 and show the file.
iptablesFilter and NAT packets with netfilter rules
iptables manages the kernel's packet-filtering rules: which incoming, outgoing and forwarded packets are accepted, dropped or rewritten (NAT). Even where nftables, ufw, firewalld, Docker or Kubernetes write the rules for you, iptables is how you read and debug them.
iptables [-t TABLE] -A|-I|-D|-R CHAIN [N] RULE-SPEC -j TARGET | iptables -L|-S [CHAIN] [-n -v --line-numbers] | -P CHAIN POLICYBefore touching a server's firewall, see what rules exist and which chain policies apply.
sudoReading and changing rules both need root (CAP_NET_ADMIN).
Netfilter is a set of hooks in the kernel's network path. A packet arriving on an interface passes PREROUTING (where DNAT happens), then the routing decision: if it's addressed to this host it goes through INPUT and on to the local socket; if not, and forwarding is on, through FORWARD and POSTROUTING (where SNAT/MASQUERADE happens) and out. Packets the host itself sends go through OUTPUT and POSTROUTING. Each hook has chains in several tables (filter for accept/drop, nat for address rewriting, mangle and raw). Rules in a chain are checked top to bottom and the first one whose matches all fit decides with its target; if none matches, the chain's policy (ACCEPT or DROP) applies. Connection tracking (conntrack) lets one rule accept all packets of ESTABLISHED connections, so you only write rules for new ones. Rules live only in kernel memory: iptables-save dumps them and something must restore them at boot.
Incoming packets pass PREROUTING, the routing decision, then INPUT (for this host) or FORWARD; rules are checked top down and the first match wins.
A client at 198.51.100.23 opens an SSH connection. The packet enters through ens5 and hits the PREROUTING hook, where conntrack sees it as a NEW connection and nat rules could rewrite its destination.
-L [CHAIN] -n -vList rules numerically with packet/byte counters and interfaces--line-numbersShow rule positions (for -I N and -D N)-S [CHAIN]Print rules as the commands that create them-A CHAINAppend a rule at the end-I CHAIN [N]Insert a rule at position N (default 1, the top)-D CHAIN N|RULEDelete a rule by number or by exact specification-P CHAIN ACCEPT|DROPSet the chain's default policy-F [CHAIN]Flush (delete) all rules in a chain or table-t nat|mangle|rawWork on another table (default filter)-p, --dport, -s, -d, -i, -oMatch protocol, port, source, destination, in/out interface-m conntrack --ctstateMatch connection state: NEW, ESTABLISHED, RELATED, INVALID-j ACCEPT|DROP|REJECT|LOGWhat to do with matching packets-ZZero the packet and byte countersiptables-save / -restoreDump all rules to text / load them back atomicallysudo iptables -P INPUT DROP before adding an ACCEPT rule for SSH (or for ESTABLISHED)Your own SSH session's packets match nothing and are dropped instantly: you're locked out.
Add lo, ESTABLISHED,RELATED and SSH ACCEPT rules first, set the policy last; or schedule a rollback (e.g. at now + 5 min: iptables-restore < backup)iptables -A INPUT -s BAD_IP -j DROP to block an attacker-A appends after your ACCEPT rules, and since the first match wins, the attacker's traffic is accepted before reaching it.
iptables -I INPUT 1 -s BAD_IP -j DROPRelying on INPUT rules to protect ports published by DockerPublished ports are DNATed and pass through FORWARD, so INPUT never sees them; Docker's own rules accept them.
Put filters in the DOCKER-USER chain, or bind published ports to 127.0.0.1.Configuring rules and forgetting to save themRules exist only in kernel memory and disappear at reboot, often unnoticed until the next maintenance window.
netfilter-persistent save (Ubuntu) or iptables-save > /etc/sysconfig/iptables (RHEL)Mixing raw iptables commands with ufw or firewalld on the same hostThe managers rewrite the rule set on reload and your manual rules vanish or conflict.
Pick one tool per host and make all changes through it.Try these on a Linux machine of your own. Each task has a hint and a solution.
List the filter table's rules with numeric output, counters and line numbers.
Add a rule that rejects (not drops) TCP connections to port 8081 with a TCP reset, then show the INPUT chain as commands.
Insert a rule at the top of INPUT that drops everything from 192.0.2.66, then delete it again by its number.
Save the current rules to /tmp/rules.v4 and show the file.