A firewall is a packet filter enforcing a policy: which traffic is allowed, and which isn't. Every host has one — this page covers how its rules actually get evaluated, and how you write and modify them yourself.
A purely stateless filter examines every packet in isolation — you'd need one rule allowing your outbound request and a separate rule allowing the reply back in. Almost every real firewall instead uses connection tracking (conntrack): once a connection is approved going out, its replies are automatically recognized and let back in, without a matching rule for them. That's why a working ruleset usually just needs one rule near the top: allow anything ESTABLISHED or RELATED, then a handful of rules for genuinely new inbound connections.
Unlike routing, where the most specific match always wins regardless of table order, firewall rules are evaluated top to bottom and the first match wins — full stop. A broad ACCEPT rule sitting above a specific DROP rule makes that DROP unreachable, no matter how precisely it's written. Edit the chain below and test packets against it:
| # | Match | Action |
|---|
| Tool | What it is | Example: allow SSH, block one IP |
|---|---|---|
| iptables | The long-standing Linux packet filter frontend, still the most widely deployed. | iptables -A INPUT -p tcp --dport 22 -j ACCEPT iptables -A INPUT -s 198.51.100.5 -j DROP |
| nftables | iptables' designated successor, one unified tool for IPv4, IPv6, and more. | nft add rule inet filter input tcp dport 22 accept nft add rule inet filter input ip saddr 198.51.100.5 drop |
| ufw | "Uncomplicated Firewall" — a friendly frontend over iptables, standard on Ubuntu. | ufw allow 22/tcp ufw deny from 198.51.100.5 |
| firewalld | Zone-based management, standard on RHEL/Fedora/CentOS. | firewall-cmd --add-service=ssh --permanent firewall-cmd --add-rich-rule='rule family="ipv4" source address="198.51.100.5" reject' --permanent |
| Cloud security groups | AWS/Azure/GCP's built-in filtering — stateful, but allow-only: there's no explicit DROP/REJECT rule, anything not listed is denied by default. | Add inbound rule: TCP 22 from 203.0.113.0/24 → allow (there is no "deny 198.51.100.5" rule to add) |
Useful housekeeping commands: iptables -L INPUT --line-numbers to see rule positions, iptables -D INPUT 3 to delete rule 3, iptables -I INPUT 1 ... to insert at the very top (since, as above, position decides everything).