Day 6: Firewall
Netfilter is a framework inside the Linux kernel that provides a standardized way to intercept, inspect, and modify network packets as they travel through the system.
Netfilter’s architecture can be broken down into three key components:
- Hooks: These are checkpoints embedded within the kernel’s network stack. When a packet passes one of these points, it triggers the execution of any functions registered there.
- Tables, Chains & Rules: These are the conceptual building blocks that userspace tools (like iptables/nftables) use to organize rules, which ultimately get turned into hook registrations. For example, the
filtertable is for basic packet filtering. - Userspace Tools: Utilities like
iptablesandnftablesprovide a user-friendly interface for writing rules that the kernel’s Netfilter framework then enforces.
Hooks: The “Where” (Fixed Locations)
Hooks are fixed points in the network stack where the kernel pauses to ask “Should I do anything with this packet?”
Think of them like checkpoints on a road:
- PRE_ROUTING - The moment a packet arrives, before deciding where it should go (to this computer? or forward it?).
- LOCAL_IN - After deciding “this packet is for me” (destination is this machine).
- FORWARD - After deciding “this packet is just passing through” (router mode).
- LOCAL_OUT - When this computer sends a packet (e.g., a web browser request).
- POST_ROUTING - Just before the packet leaves the computer, after final decisions like NAT.
Hooks are like the gates in a factory assembly line. The packet flows through gates in a fixed order. At each gate, the kernel can stop, look, and decide.
Rules: The “What” (Single Instructions)
A rule is one simple instruction: “If a packet matches X, then do Y.”
Example rules:
- “If the packet is coming from IP
1.2.3.4, then drop it.” - “If the packet is going to port 80 (web traffic), then accept it.”
- “If the packet is an SSH connection from inside, then allow.”
Each rule has:
- A match condition (e.g., source IP = 1.2.3.4)
- An action (e.g., ACCEPT, DROP, LOG)
A rule is like a bouncer’s checklist: “If the person is not on the guest list, deny entry.”
Actions & The Packet’s Journey
When a packet hits a hook, the registered functions can make several key decisions:
NF_ACCEPT: Allow the packet to continue to the next hook point or to its final destination.NF_DROP: Silently discard the packet, and no further processing is done.NF_QUEUE: Pass the packet to userspace for complex processing by a daemon.NF_REPEAT: Re-inject the packet at the same hook for another round of processing.NF_STOP: Accept the packet and halt all further Netfilter processing.
What is NF_STOP?
NF_STOP is a specific instruction that tells the kernel: “Stop processing this packet at this specific checkpoint and consider it accepted for now, but don’t check any more rules in this specific hook.”
Imagine you are entering a stadium and there are three layers of security guards at the “Entrance” gate:
- Guard A checks your ID.
- Guard B checks your bag.
- Guard C checks your ticket.
- **If Guard A gives you an
ACCEPT**: You move to Guard B. - **If Guard A gives you a
DROP**: You are kicked out of the stadium immediately. - **If Guard A gives you a
STOP**: He tells you, “You’re good to go. Skip Guard B and Guard C. Go straight into the stadium.
In a standard firewall, we usually want every packet to be checked by every rule to ensure total security. However, NF_STOP is used by the kernel or specialized modules (like certain VPN or tunneling modules) to optimize performance.
If a module has already “vetted” a packet and knows 100% that it is safe, it issues an NF_STOP. This saves the CPU from wasting cycles running that packet through 50 more rules in the same chain that aren’t going to change the outcome anyway.
Chains: The “Ordered List of Rules”
A chain is simply a list of rules, executed from top to bottom.
Why call it a “chain”? Because rules are linked together like links in a chain. The packet walks down the chain, checking each rule one by one until it finds a match or reaches the end.
Example chain (simplified):
1. If IP = 1.2.3.4 → DROP
2. If port = 22 → ACCEPT
3. If port = 80 → ACCEPT
4. Otherwise → DROPA chain is like a multi-step security procedure. First check ID, then bag scan, then metal detector - in that exact order.
Tables: The “Categories of Purpose”
A table is a collection of chains grouped by what kind of job they do.
Different tables exist because you don’t mix packet filtering with address rewriting - they’re separate concerns.
The main tables you’ll encounter:
| Table Name | Purpose |
|---|---|
| Filter | Basic firewalling: ACCEPT or DROP packets. |
| NAT | Rewriting source/destination IP addresses or ports. |
| Mangle | Changing packet headers (e.g., TTL, QoS marks). |
| Raw | Configuring exceptions for connection tracking. |
A table is like a department in a company:
- Filter department = Security guards (let in or reject)
- NAT department = Translators (rewrite addresses)
- Mangle department = Editors (tweak headers)
You wouldn’t ask security guards to translate addresses - that’s the translator’s job.
How They All Fit Together
Imagine a packet arriving at your Linux machine:
- It hits the PRE_ROUTING hook.
- The kernel looks at the table relevant to that hook (often
rawormanglefirst, thennat). - Inside that table, the packet walks down a chain (e.g.,
PREROUTINGchain). - The chain contains rules - each rule checks a condition, then decides: ACCEPT, DROP, or jump to another chain.
After finishing at that hook, the packet moves to the next hook (e.g., LOCAL_IN), and the same process repeats.
One Last Analogy - The Airport
| Netfilter Term | Airport Analogy |
|---|---|
| Hook | A checkpoint: Entry gate, security, passport control, boarding gate. |
| Table | A department: Security (Filter), Passport control (NAT), Baggage handlers (Mangle). |
| Chain | A checklist at a checkpoint: “Check ID → Scan bag → Pat down → OK.” |
| Rule | One item on that checklist: “If shoe beeps → remove shoes.” |
The passenger (packet) goes through checkpoints (hooks), each handled by a department (table) following their own procedure (chain) of specific steps (rules).
Stateless vs Stateful Firewall
Stateless Firewall (The “Memoryless” Bouncer)
A stateless firewall treats every single packet as a brand-new stranger. It doesn’t care if the packet is part of an ongoing conversation; it only checks if the packet matches a specific rule (like Source IP, Destination IP, or Port).
- Imagine a bouncer at a club who has a list: “Only people wearing red shirts can enter.” If you go inside to use the bathroom and try to come back out, he checks the list again. If you try to go back in, he checks the list again. He doesn’t remember you from five seconds ago.
- Pros: Extremely fast and uses very little CPU/RAM.
- Cons: Very difficult to manage for modern web traffic. If you allow a request to go out to a website, you have to manually write a rule to allow the response to come back in.
Stateful Firewall (The “Conversational” Bouncer)
A stateful firewall tracks the state of network connections. It uses a “State Table” to remember who is talking to whom. If you start a “conversation” (a connection) from inside the server to the outside world, the firewall remembers that and automatically allows the reply to come back in.
- This bouncer remembers faces. Once he lets you into the club, he makes a mental note: “Sergei is inside.” When you step out for air and come back, he doesn’t check the list again; he just nods and lets you through because he knows you already belong there.
- Pros: Much more secure and easier to configure. You only have to worry about how a connection starts.
- Cons: Uses slightly more memory to maintain the “State Table” (though modern hardware handles this easily).
In the modern Linux ecosystem, almost every frontend is Stateful by default because that is what 99% of users need. However, they handle them differently:
Firewalld & UFW (The High-Level Frontends)
- Stateful: Both are strictly stateful. When you run
ufw allow 80, they automatically handle the “Connection Tracking” (conntrack) in the background. You don’t have to tell them to “allow the response from the web browser”; they just do it. - Stateless: These tools aren’t really designed for stateless rules. You could force it by digging into the raw configuration, but it defeats the purpose of using them.
nftables & iptables (The Engines)
- Both: These tools give you total control.
- Stateful: You enable stateful tracking by adding a rule like
ct state established,related accept. This tells the kernel to look at its “memory” (the state table). - Stateless: If you omit the
ct statepart and just write rules based on IP and Port, you are running a stateless firewall. This is common in high-performance SRE scenarios where you want to block a massive DDoS attack at the “front door” without wasting memory on tracking every single malicious packet.
iptables is deprecated!
Here’s a short, focused overview of the three main Linux firewall front-ends and their relationship to the kernel.
Zones (firewalld zone-based firewall)
Think of zones like different security levels for different situations - exactly like the “security zones” you see in real life.
What Zones Actually Do
A zone is a predefined set of rules that says:
- Which incoming connections are allowed (e.g., SSH, HTTP, ping)
- Which are denied (everything else by default)
- Whether traffic can be forwarded (routing)
firewalld comes with several default zones:
| Zone Name | Typical Use | Incoming traffic |
|---|---|---|
drop | Dangerous networks (coffee shop Wi-Fi) | All dropped (not even responses) |
block | Similar, but rejects with ICMP message | All rejected |
public | Default for untrusted networks | Only specific allowed services (e.g., SSH) |
internal | Trusted internal LAN | More services (Samba, SSH, maybe HTTP) |
trusted | Fully trusted (home or management) | All traffic accepted |
You Don’t Write Rules - You Pick Zones
Instead of typing iptables -A INPUT -p tcp --dport 22 -j ACCEPT, you just:
# Assign your Wi-Fi interface to the "public" zone
sudo firewall-cmd --zone=public --add-interface=wlan0
# Allow SSH in the public zone
sudo firewall-cmd --zone=public --add-service=sshThe zone translates --add-service=ssh into the actual kernel rules (via nftables/iptables).
Why Zones Are Great
- Separation of concerns - Your laptop has Wi-Fi (public zone) and Ethernet (internal zone). You don’t mix rules.
- Reusable profiles - Define a zone once, apply it to many interfaces.
- No need to remember IP ranges - Zones are based on interfaces, not IP addresses.
- Dynamic changes - When you move from office Wi-Fi to home Wi-Fi, you can change the zone assignment instantly.
nftables
- Underlying engine: Directly uses the kernel’s Netfilter framework - it’s the successor to iptables.
- Architecture: Single, consistent syntax with a compact bytecode (nft) that replaces the old iptables/ip6tables/ebtables/arptables mess.
- User interface: Command-line (
nft) + native ruleset files (e.g.,/etc/nftables.conf). - Who it’s for: Administrators who want full, low‑level control without legacy bloat. Ideal for routers, servers, and firewalls where performance and transparency matter.
- Key strength: Atomic rule updates, better performance, simplified dual‑stack (IPv4/IPv6) management, and scripting friendly.
- Learning curve: Steep - you must understand Netfilter hooks, tables, chains, and sets.
Role: The modern system‑level firewall used directly by distros like Debian (default), Arch, and RHEL 9+.
firewalld
- Underlying engine: Uses
nftables(or legacyiptables) under the hood - it’s a dynamic daemon managing the kernel rules. - Architecture: Zone‑based security model. Interfaces and sources are assigned to zones (e.g.,
public,internal,dmz), each zone has its own rule set. - User interfaces:
firewall-cmdCLI, graphical tools (firewall-config), and D‑Bus API. - Who it’s for: Default on RHEL/Fedora and their derivatives. Great for desktops and servers where network environments change (e.g., laptop moving between Wi‑Fi networks).
- Key strength: Runtime and permanent configuration separation - changes apply instantly without reloading the whole ruleset; zones simplify policy management.
- Learning curve: Moderate - you need to understand zones, services, and rich rules.
Role: A high‑level dynamic manager that hides raw
nftablescomplexity while offering flexible per‑zone policies.
ufw (Uncomplicated Firewall)
- Underlying engine: A front‑end that generates
iptablesrules (and now also supportsnftablesin newer versions). - Architecture: Extremely simple, host‑based rule format:
allow,deny,reject, with optional application profiles (e.g.,ufw allow ssh). - User interface: Command‑line
ufwonly. No GUI by default. - Who it’s for: Beginners, desktop users, or anyone who wants a simple, no‑nonsense firewall for a single machine (especially Ubuntu and its derivatives).
- Key strength: Dead simple syntax -
ufw enable,ufw default deny,ufw allow from 192.168.1.0/24 to any port 22. Also integrates withgufw(GUI). - Learning curve: Very low.
Role: A user‑friendly wrapper aimed at uncomplicated personal or small‑server use.