Lab 14: Firewall with iptables

Time: 30 minutes | Level: Practitioner | Docker: docker run -it --rm ubuntu:22.04 bash


Overview

iptables is the classic Linux packet filtering framework that has powered Linux firewalls for 25+ years. UFW is a frontend for iptables. This lab goes deeper — you'll directly manipulate chains and rules, understand the ACCEPT/DROP/REJECT targets, save/restore rulesets, and get an introduction to nftables (the modern replacement).

⚠️ Docker Note: Run with docker run -it --privileged --rm ubuntu:22.04 bash for live iptables commands. The verified outputs below are from --privileged mode.


Step 1: Install iptables and View Default Chains

apt-get update -qq && apt-get install -y iptables
iptables --version
iptables -L

💡 iptables has three built-in tables: filter (default), nat, and mangle. Each table has chains: INPUT (inbound to this host), OUTPUT (outbound from this host), FORWARD (routed through). By default all chains have ACCEPT policy — everything passes.

📸 Verified Output (--privileged):

iptables v1.8.7 (nf_tables)

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Step 2: Append Rules with -A

-A appends a rule to the end of a chain.

💡 Always allow lo (loopback) and ESTABLISHED,RELATED before setting a default DROP policy. Without these, services that make outbound connections can't receive the replies! The -m state match uses connection tracking.

📸 Verified Output:


Step 3: DROP and REJECT Targets

💡 DROP vs REJECT: DROP silently discards — attacker can't tell if host exists (more secure, but slower for legitimate timeout scenarios). REJECT sends back an error (ICMP port-unreachable or TCP-RST) — connections fail fast. For public-facing servers, DROP is preferred. For internal networks, REJECT gives better diagnostics.

📸 Verified Output:


Step 4: Delete and Insert Rules (-D, -I, -F)

💡 -I without a position number inserts at position 1 (top). Rule order matters: iptables processes rules top-to-bottom and stops at the first match. Always insert more specific rules before general ones. -F flush is non-destructive to the default policy — the policy remains.

📸 Verified Output:


Step 5: Source IP and Protocol Matching

💡 -p tcp/udp selects protocol; --dport is destination port (traffic arriving at this port); --sport is source port. -s matches source IP/CIDR. The -m limit module enables rate limiting — critical for preventing DoS/DDoS via ICMP floods or connection floods.

📸 Verified Output:


Step 6: Logging with -j LOG

💡 -j LOG does NOT stop processing — packets continue to the next rule. Always add LOG before ACCEPT/DROP. --log-prefix adds a searchable tag. --log-level 4 = warning (levels 0-7 match syslog). Kernel logs appear in dmesg and /var/log/kern.log. High-traffic logging can flood logs — use -m limit with LOG in production.

📸 Verified Output:


Step 7: Save and Restore Rules + nftables Intro

💡 iptables-save/restore is critical for persistence — iptables rules are lost on reboot unless saved. Install iptables-persistent on Ubuntu for auto-restore: apt install iptables-persistent. nftables is the kernel 3.13+ successor: single tool, better performance, atomic rule updates, and cleaner syntax. Ubuntu 22.04 ships both.

📸 Verified Output (iptables-save):


Step 8: Capstone — Build a Complete Firewall Ruleset

Scenario: Configure a production web server firewall from scratch: allow SSH from management network only, web traffic from anywhere, block all else, log dropped packets.

💡 This is a stateful firewall: rule 2 (ESTABLISHED,RELATED) allows reply packets for outbound connections (like apt-get, curl). Without it, outbound connections would fail at the response phase. In production, also add OUTPUT rules to restrict what the server can connect to.

📸 Verified Output:


Summary

Command
Purpose

iptables -L

List all rules (filter table)

iptables -L CHAIN -v --line-numbers

List chain with counters and numbers

iptables -A CHAIN rule -j TARGET

Append rule to chain

iptables -I CHAIN N rule -j TARGET

Insert rule at position N

iptables -D CHAIN N

Delete rule by line number

iptables -D CHAIN rule

Delete rule by specification

iptables -F

Flush all rules (chain optional)

iptables -P CHAIN POLICY

Set default chain policy

-j ACCEPT

Allow packet through

-j DROP

Silently discard packet

-j REJECT

Discard + send error to sender

-j LOG --log-prefix "TAG"

Log packet to kernel log

-p tcp --dport N

Match TCP destination port

-s IP/CIDR

Match source address

-m state --state EST,REL

Stateful connection tracking

-m limit --limit N/s

Rate limiting

iptables-save > FILE

Save rules to file

iptables-restore < FILE

Restore rules from file

nft list ruleset

nftables: show all rules

Last updated