To practice the concepts in this lecture effectively, we will build a specific Virtual Lab. All examples in this course are adapted to fit this exact topology.
0.1 VirtualBox Lab Setup
Lab Topology Diagram
☁️WAN (Internet)(Bridged Adapter)
→
↓
"Router" VMXubuntu 24.04
WAN IF:enp0s3 (DHCP)
LAN IF:enp0s8 (10.0.2.1/24)
→
↓
"Client" VMAny OS
LAN IF:eth0 (10.0.2.100/24)
Gateway:10.0.2.1
Both Router (LAN) and Client are connected to the "CyberLab" NAT Network (Subnet: 10.0.2.0/24).
0.2 Critical Preparation: Disabling UFW
Xubuntu comes with UFW (Uncomplicated Firewall) enabled by default. UFW is a frontend that manipulates iptables. To learn iptables directly, we must disable UFW so it doesn't interfere with our manual rules.
# EXPLANATION:
# This set of commands stops the UFW service and ensures it doesn't start on boot.
# 1. Disable the UFW firewall logic
# This flushes UFW chains and sets default policies to ACCEPT
sudo ufw disable
# 2. Stop the systemd service
sudo systemctl stop ufw
# 3. Disable the systemd service (prevents autostart on reboot)
sudo systemctl disable ufw
# 4. Install iptables (usually pre-installed, but good to verify)
sudo apt-get update
sudo apt-get install iptables
# 5. Verify empty ruleset (Should be empty ACCEPT policies)
sudo iptables -L -n
0.3 Managing Rules via Scripts
Typing commands one by one into the terminal is risky; if you make a mistake (like dropping SSH), you might lock yourself out. The professional way to manage rules is using Bash Scripts.
How to create an iptables script:
Create a file: touch firewall_rules.sh
Make it executable: chmod +x firewall_rules.sh
Edit it: nano firewall_rules.sh
Run it: sudo ./firewall_rules.sh
0.4 Enabling and Testing Routing (IP Forwarding)
By default, a Linux system drops any packet that is not destined for itself. To act as a "Router," we must tell the kernel to forward packets from one interface to another.
Step 1: Enable Routing (The "Router" VM)
You can do this temporarily (lost on reboot) or permanently.
Temporary Method:
# Write '1' to the forwarding control file
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
Permanent Method (Recommended):
Edit the sysctl config: sudo nano /etc/sysctl.conf
Find the line #net.ipv4.ip_forward=1
Uncomment it (remove the # so it looks like net.ipv4.ip_forward=1)
Save and exit (Ctrl+O, Enter, Ctrl+X).
Apply changes: sudo sysctl -p
Step 2: Verify Routing is Enabled
Run the following command on the Router VM:
cat /proc/sys/net/ipv4/ip_forward
Output 0: Routing is OFF (Client cannot reach internet).
Output 1: Routing is ON (Packets will be passed between interfaces).
Step 3: Test Connectivity from the "Client" VM
Once routing is enabled on the Router (and MASQUERADE rules from Module 7 are applied), go to your Client VM and test:
Ping the Gateway (Router LAN IP):ping 10.0.2.1 (Proves LAN is working).
Ping an Internet IP:ping 8.8.8.8 (Proves Routing + NAT are working).
Ping a Domain Name:ping google.com (Proves DNS is working).
Module 1: The Evolution of Linux Firewalls – Why `iptables` Matters in 2025
1.1 The "Manual Transmission" Analogy
In the modern networking landscape, a common question arises: "Is iptables still important?". With the advent of newer technologies like nftables and cloud-native tools, one might assume iptables is obsolete. This is a dangerous misconception for any cybersecurity professional.
Think of iptables like a manual transmission car.
Modern cars (firewalls like UFW or Firewalld) often have automatic transmissions. They are easier to drive and handle most day-to-day tasks for you.
However, knowing how to drive a manual transmission gives you a fundamental understanding of how the engine applies power to the wheels.
Similarly, understanding iptables gives you deep insight into how the Linux kernel processes packets. Even when you use high-level tools like Docker or Kubernetes, they are often manipulating iptables rules in the background. If you don't understand the underlying mechanics, you cannot troubleshoot effectively when the "automatic" systems fail.
1.2 The Successor: `nftables`
It is important to acknowledge that iptables is being succeeded by nftables (nftables).
Performance:nftables uses a virtual machine inside the kernel, allowing for faster processing of large rule sets.
Unification: Unlike iptables, which has separate tools for IPv4, IPv6, and ARP (iptables, ip6tables, arptables), nftables unifies these into a single framework.
Current State: While the industry is moving toward nftables, iptables remains the ubiquitous standard found on almost every Linux server, embedded device, and enterprise gateway today.
1.3 Why We Still Use `iptables`
Ubiquity: It is pre-installed on virtually every Linux distribution.
The Backend Role: Tools like UFW (Uncomplicated Firewall) and Firewalld are essentially "front-ends" that generate iptables rules for you.
Containerization:Docker relies heavily on iptables to manage container networking and port forwarding.
Task: On your Router VM, check if the system is using legacy iptables or the nftables shim.
# EXPLANATION:
# This script checks the version of the iptables command.
# Check the version of the iptables command
sudo iptables --version
# Check if the 'iptables' command is actually a symbolic link to xtables-nft-multi
# 'ls' lists directory contents
# '-l' shows detailed info including link targets
# 'which' finds the path to the executable
ls -l $(which iptables)
# Output might look like: iptables -> /etc/alternatives/iptables -> /usr/sbin/iptables-nft
Module 2: The Architecture – Netfilter & Iptables
2.1 The Framework vs. The Tool
It is crucial to distinguish between the two key components:
Netfilter: This is a framework inside the Linux Kernel. It consists of "hooks" in the network stack that allow kernel modules to register callback functions. When a packet traverses the network stack, it hits these hooks, and Netfilter decides what to do with it. Netfilter does the actual work.
iptables: This is the user-space tool. It is the command-line utility you use to talk to Netfilter. You write rules in iptables, and it pushes them into the kernel's Netfilter hooks.
2.2 Packet Flow and Chains
When a packet enters a network interface (NIC), it doesn't just magically appear in an application. It traverses a specific path. Netfilter organizes these paths into CHAINS.
Netfilter Packet Flow Diagram
Incoming Packet (e.g., from WAN enp0s3)
↓
raw PREROUTING
↓
mangle PREROUTING
↓
nat PREROUTING (DNAT)
↓
Routing Decision
↓
(Destined for Router VM)
↓
mangle INPUT
↓
filter INPUT
↓
Local Process (e.g., SSH Server)
↓
(Destined for Client VM)
↓
mangle FORWARD
↓
filter FORWARD
↓
mangle POSTROUTING
↓
nat POSTROUTING (SNAT/MASQUERADE)
↓
Outgoing Packet (e.g., to LAN enp0s8)
Local Process (e.g., apt update)
↓
raw OUTPUT
↓
mangle OUTPUT
↓
nat OUTPUT
↓
filter OUTPUT
↓
(Routing Decision)
↓
mangle POSTROUTING
↓
nat POSTROUTING (SNAT)
↓
Outgoing Packet (e.g., to WAN enp0s3)
2.3 The Tables
To organize rules further, Netfilter uses TABLES. Each table serves a specific purpose.
filter (Default): This is where you make security decisions. Does the packet pass or get dropped?
Chains:INPUT, OUTPUT, FORWARD.
nat: Used for Network Address Translation. Modifying source or destination IPs.
Chains:PREROUTING, POSTROUTING, OUTPUT.
mangle: Used for specialized packet alteration (e.g., changing the TTL, TOS, or marking packets).
Chains: All 5 chains.
raw: Used to bypass connection tracking (NOTRACK). This is for high-performance needs where you don't want the overhead of tracking state.
Chains:PREROUTING, OUTPUT.
Task: Run this on the Router VM to see the empty tables after disabling UFW.
# EXPLANATION:
# This script lists all active rules to help us visualize the Tables and Chains structure.
# List rules in the default 'filter' table
# '-t filter' specifies the table (optional here as filter is default)
# '-L' lists the rules
# '-v' (verbose) shows packet/byte counters
# '-n' (numeric) prevents DNS lookups for speed
sudo iptables -t filter -L -v -n
# List rules in the 'nat' table
# We MUST specify '-t nat' here, otherwise it defaults to filter
sudo iptables -t nat -L -v -n
# List rules in the 'mangle' table to see packet alteration chains
sudo iptables -t mangle -L -v -n
Module 3: The `iptables` Command Syntax
The syntax of iptables can be daunting, but it follows a predictable pattern:
-I(Insert): Adds a rule to a specific position (default is the top). Important: Rules are processed top-to-bottom. The first match wins. Inserting at the top -I is often safer for "Allow" rules than appending -A.
-D(Delete): Removes a rule.
-F(Flush): Deletes all rules in a chain.
-P(Policy): Sets the default behavior for a chain if no rules match (e.g., DROP everything that isn't explicitly allowed).
3.2 The Importance of Order
Since rules are processed sequentially, a common mistake is placing a generic DROP rule before a specific ACCEPT rule. Once a packet matches a rule with a terminating target (like DROP or ACCEPT), processing stops (mostly).
Task: Create a script named lockdown.sh on the Router VM. This will secure the router itself.
#!/bin/bash
# EXPLANATION:
# This script resets the firewall to a secure state (Deny All by default).
echo "Applying Lockdown..."
# Flush (delete) all existing rules in the filter table
# This ensures we are starting from a clean slate
sudo iptables -F
# Delete all user-defined chains
# This cleans up any custom logic from previous configurations
sudo iptables -X
# Set the Default Policy for the INPUT chain to DROP
# This means: "If a packet comes in to the Router and doesn't match any specific rule, kill it."
sudo iptables -P INPUT DROP
# Set the Default Policy for the FORWARD chain to DROP
# We generally don't want to route traffic unless we explicitly allow it later
sudo iptables -P FORWARD DROP
# Set the Default Policy for the OUTPUT chain to ACCEPT
# We generally trust traffic originating from our own Router
sudo iptables -P OUTPUT ACCEPT
# Verify the policies
sudo iptables -L -n
echo "Lockdown Complete."
Module 4: Basic Matches – Identifying Traffic
To filter packets, we must describe them. We use "matches" to identify traffic based on Layer 3 (IP) and Layer 4 (TCP/UDP) headers.
4.1 IP Addresses
-s (--source): Match the source IP (who sent the packet).
-d (--destination): Match the destination IP (where is it going).
You can use single IPs (10.0.2.100) or CIDR notation (10.0.2.0/24).
4.2 Protocols and Ports
-p (--protocol): tcp, udp, icmp.
--dport (--destination-port): The port the packet is trying to reach (e.g., 80 for Web).
--sport (--source-port): The port the packet originated from (usually random for clients).
Note: You must specify -p tcp or -p udpbefore using --dport or --sport.
4.3 Interfaces
-i (--in-interface): The physical device the packet entered on.
In our Lab: enp0s3 (WAN) or enp0s8 (LAN).
-o (--out-interface): The physical device the packet is leaving on.
In our Lab: enp0s3 (WAN) or enp0s8 (LAN).
Task: Create access_control.sh on the Router VM. Allow SSH from the LAN Client (10.0.2.100) but block a "malicious" IP on the WAN.
#!/bin/bash
# EXPLANATION:
# This script configures basic access control for the Router.
# 1. Allow traffic on the loopback interface (localhost)
# Crucial for system services
sudo iptables -A INPUT -i lo -j ACCEPT
# 2. Block a known malicious subnet (Simulated)
# We put this *before* allow rules.
sudo iptables -A INPUT -s 203.0.113.0/24 -j DROP
# 3. Allow SSH (Port 22) ONLY from our LAN interface (enp0s8)
# We don't want the internet (enp0s3) SSHing into us.
# '-i enp0s8' ensures the request comes from inside.
# '-s 10.0.2.0/24' restricts it to the LAN subnet.
sudo iptables -A INPUT -i enp0s8 -s 10.0.2.0/24 -p tcp --dport 22 -j ACCEPT
# 4. Allow HTTP (80) and HTTPS (443) access to the router itself (if running a web server)
# '-m multiport' allows listing multiple ports
sudo iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT
Module 5: Advanced Matches – Connection Tracking & State
This is arguably the most important concept in modern firewalls. iptables is a Stateful Firewall. This means it remembers the context of a packet.
5.1 The State Machine
Instead of just looking at "Source IP 10.0.2.100", the firewall looks at the Connection State:
NEW: The first packet of a connection (e.g., a TCP SYN packet).
ESTABLISHED: Packets that are part of a connection that has already seen traffic in both directions.
RELATED: Packets that are starting a new connection but are associated with an existing one (Crucial for FTP or SIP).
INVALID: Packets that don't adhere to protocol standards.
5.2 Why Stateful is Better
If you only use static rules, you have to explicitly open high-numbered ports for return traffic, which is insecure. With stateful tracking, you simply say: "If I started this conversation (OUTPUT), allow the reply (INPUT ESTABLISHED) automatically."
Task: Update your rules on the Router VM. This allows the Router to update itself (apt-get) and ensures we don't break ongoing SSH sessions.
#!/bin/bash
# EXPLANATION:
# This script enables stateful inspection.
# 1. Drop invalid packets immediately
# '-m state' loads the state module
# '--state INVALID' matches broken packets
sudo iptables -A INPUT -m state --state INVALID -j DROP
# 2. The "Golden Rule": Allow traffic that is already part of a valid connection
# This allows the Router to browse the web (enp0s3 replies)
# and allows the Client to stay connected via SSH.
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 3. Limit concurrent SSH connections from the LAN
# '-i enp0s8' specifies LAN interface
# '-m connlimit' loads connection limit module
# '--connlimit-above 3' matches if the source IP has more than 3 active connections
# '-j REJECT' politely refuses extra connections
sudo iptables -A INPUT -i enp0s8 -p tcp --syn --dport 22 -m connlimit --connlimit-above 3 -j REJECT
Module 6: Targets – The Fate of the Packet
When a rule matches, the -j (jump) flag tells Netfilter what to do.
6.1 Terminating Targets
These stop processing in the current chain.
ACCEPT: Let the packet through.
DROP: Silently discard the packet. (Blackhole).
REJECT: Discard the packet but send an error message back (ICMP Destination Unreachable).
6.2 Non-Terminating Targets
These perform an action but continue to the next rule.
LOG: Writes packet details to kernel logs (dmesg or /var/log/kern.log).
TEE: Mirrors the packet to another device (great for IDS/NSM).
Task: Add logging to the Router VM INPUT chain to see when packets are blocked.
#!/bin/bash
# EXPLANATION:
# This script appends logging rules at the end of the INPUT chain.
# 1. Create a logging rule
# This must be the LAST rule before the implicit DROP logic
# '--log-prefix' adds a tag to the log file
# '--log-level 4' sets the syslog level (Warning)
sudo iptables -A INPUT -j LOG --log-prefix "IPTABLES_DROP: " --log-level 4
# 2. Explicitly Drop everything else
# Useful if your default policy isn't DROP, or just for clarity.
sudo iptables -A INPUT -j DROP
# To view these logs later, run this in a separate terminal:
# sudo tail -f /var/log/kern.log | grep "IPTABLES_DROP"
Module 7: NAT (Network Address Translation)
NAT involves re-writing IP addresses. This module transforms your Xubuntu VM into a real router.
7.1 SNAT (Source NAT) & MASQUERADE
This is used when the internal Client (10.0.2.100) needs to access the Internet. The Router (enp0s3) replaces the private source IP (10.0.2.100) with its own WAN IP.
7.2 DNAT (Destination NAT) / Port Forwarding
This is used if you want to run a Web Server on the Client (10.0.2.100) but access it from the outside world via the Router's WAN IP.
Task: Create router_enable.sh on the Router VM. This enables internet access for the Client VM.
#!/bin/bash
# EXPLANATION:
# This script configures the Xubuntu machine to forward traffic and perform NAT.
# 1. Enable IP Forwarding in the kernel
# Without this, Linux drops packets not destined for itself.
# We write '1' to the ip_forward system file.
# Note: This is temporary (lost on reboot). See Module 0.4 for permanent method.
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
# 2. Setup Masquerading (SNAT) for outbound traffic
# '-t nat' specifies the NAT table
# '-A POSTROUTING' - we modify the packet AFTER routing decisions
# '-o enp0s3' - match traffic leaving via the WAN interface (Bridged)
# '-j MASQUERADE' - rewrite source IP to the WAN IP of enp0s3
sudo iptables -t nat -A POSTROUTING -o enp0s3 -j MASQUERADE
# 3. Allow the forwarded traffic in the FILTER table
# By default, our FORWARD policy is DROP (Module 3). We must open it.
# Allow LAN (enp0s8) to go to WAN (enp0s3)
sudo iptables -A FORWARD -i enp0s8 -o enp0s3 -j ACCEPT
# Allow Established connections to come back from WAN to LAN
sudo iptables -A FORWARD -i enp0s3 -o enp0s8 -m state --state RELATED,ESTABLISHED -j ACCEPT
# 4. (Optional) Port Forwarding Example
# If we wanted to forward WAN Port 8080 to Client Port 80:
# sudo iptables -t nat -A PREROUTING -i enp0s3 -p tcp --dport 8080 -j DNAT --to-destination 10.0.2.100:80
# sudo iptables -A FORWARD -p tcp -d 10.0.2.100 --dport 80 -j ACCEPT