iptables Deep Knowledge β Chains, NAT, nftables, RZ-Regelwerk
Quellen
- RFC 793 β TCP
- RFC 768 β UDP
- Linux Kernel Netfilter Documentation
- nftables Wiki: https://wiki.nftables.org
- iptables man pages
Teil 1: Netfilter β Das Fundament
iptables ist nur das Userspace-Werkzeug. Die eigentliche Arbeit macht
Netfilter im Linux-Kernel. Netfilter ist ein Framework von Hooks
in den Netzwerk-Stack des Kernels.
Netfilter Hooks im Kernel:
ROUTING
DECISION
β
NETWORK βββΊ PREROUTING βββΊ (local?) βββΊ ββββΊ FORWARD βββΊ POSTROUTING βββΊ NETWORK
INTERFACE β β INTERFACE
βΌ βΌ
INPUT OUTPUT
β β
βΌ βΌ
LOCAL PROCESS (z.B. sshd, named)
Die fΓΌnf Netfilter-Hooks:
| Hook | Wann | Typischer Einsatz |
|---|---|---|
| PREROUTING | Paket kommt rein, vor Routing | DNAT, Redirect |
| INPUT | Paket fΓΌr lokalen Prozess | Eingehende Firewall-Regeln |
| FORWARD | Paket wird weitergeleitet (kein lokaler Prozess) | Router-Firewall |
| OUTPUT | Paket von lokalem Prozess | Ausgehende Regeln |
| POSTROUTING | Paket verlΓ€sst System, nach Routing | SNAT, Masquerade |
Teil 2: Tables und Chains
iptables organisiert Regeln in Tables (Tabellen) und Chains (Ketten).
Die vier Tabellen
filter β Standard-Tabelle, Pakete erlauben/verweigern
nat β Network Address Translation (SNAT, DNAT, Masquerade)
mangle β Pakete verΓ€ndern (TTL, TOS, Marking)
raw β Vor Connection Tracking (sehr frΓΌh, sehr schnell)
Welche Chains in welcher Tabelle
filter: INPUT, FORWARD, OUTPUT
nat: PREROUTING, OUTPUT, POSTROUTING
mangle: PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING
raw: PREROUTING, OUTPUT
Verarbeitungsreihenfolge (eingehendes Paket)
Netzwerk-Interface
β
βΌ
raw:PREROUTING β Connection Tracking Bypass mΓΆglich
β
βΌ
mangle:PREROUTING β Paket-Marking
β
βΌ
nat:PREROUTING β DNAT hier! (Ziel-IP Γ€ndern)
β
βΌ
ROUTING DECISION
β
βββ Lokaler Prozess?
β β
β βΌ
β mangle:INPUT
β β
β βΌ
β filter:INPUT β Haupt-Firewall fΓΌr eingehende Pakete
β β
β βΌ
β Lokaler Prozess (sshd, named, nginx...)
β
βββ Weiterleitung?
β
βΌ
mangle:FORWARD
β
βΌ
filter:FORWARD β Router-Firewall
β
βΌ
mangle:POSTROUTING
β
βΌ
nat:POSTROUTING β SNAT/Masquerade hier!
β
βΌ
Netzwerk-Interface
Teil 3: Regeln, Targets und Policy
Anatomie einer iptables-Regel
iptables -t filter -A INPUT -p tcp --dport 22 -s 10.0.0.0/19 -j ACCEPT
β β β β β β β
β Tabelle Chain Protokoll Ziel-Port Quell-IP Aktion
β (default: (tcp/udp/
β filter) icmp)
Befehl
-A = Append (anhΓ€ngen)
-I = Insert (vorne einfΓΌgen)
-D = Delete
-L = List
-F = Flush (alle Regeln leeren)
-P = Policy (Standard-Aktion)
-N = New chain
-X = Delete chain
Targets (Aktionen)
ACCEPT β Paket durch, keine weiteren Regeln
DROP β Paket still verwerfen (Absender bemerkt nichts, Timeout)
REJECT β Paket verwerfen + ICMP-Fehler senden (Absender weiΓ es sofort)
LOG β Paket loggen, weiter zu nΓ€chster Regel
RETURN β ZurΓΌck zur aufrufenden Chain
DNAT β Ziel-IP Γ€ndern (nur nat:PREROUTING, nat:OUTPUT)
SNAT β Quell-IP Γ€ndern (nur nat:POSTROUTING)
MASQUERADE β SNAT mit dynamischer Quell-IP (fΓΌr DHCP-Interfaces)
REDIRECT β Auf lokalen Port umleiten
MARK β Paket markieren (fΓΌr Routing-Entscheidungen)
Default Policy
# DROP vs REJECT als Policy:
iptables -P INPUT DROP # Stilles Verwerfen β empfohlen fΓΌr RZ
iptables -P INPUT REJECT # Mit ICMP-Fehler β einfacher zu debuggen
# β οΈ VORSICHT: Policy setzen BEVOR Regeln gelΓΆscht werden!
# Falsche Reihenfolge = sofortige Aussperrung!
# SICHERE Reihenfolge:
# 1. SSH-Regel sicherstellen
# 2. Policy setzen
# 3. Rest konfigurieren
Teil 4: Connection Tracking (conntrack)
Connection Tracking ist das GedΓ€chtnis von iptables.
Es merkt sich den Zustand jeder Verbindung.
Verbindungs-ZustΓ€nde:
NEW β Erstes Paket einer neuen Verbindung
ESTABLISHED β Antwortpakete einer bekannten Verbindung
RELATED β Verbindung die zu einer anderen gehΓΆrt (z.B. FTP-Daten)
INVALID β Passt zu keinem bekannten Zustand β DROP!
# Die wichtigste Regel ΓΌberhaupt β IMMER ganz oben:
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Warum?
# Ohne diese Regel blockiert DROP-Policy auch Antwortpakete!
# TCP-Handshake geht raus (OUTPUT ACCEPT) aber SYN-ACK kommt nicht rein
# UngΓΌltige Pakete verwerfen
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
# Conntrack-Tabelle anzeigen
conntrack -L
conntrack -L | grep ESTABLISHED | wc -l # Anzahl aktiver Verbindungen
# Conntrack-Limits (wichtig bei vielen Verbindungen!)
cat /proc/sys/net/netfilter/nf_conntrack_max
cat /proc/sys/net/netfilter/nf_conntrack_count # aktuell aktiv
Teil 5: NAT β Network Address Translation
DNAT β Destination NAT (eingehend)
# Eingehende Verbindungen auf Port 80 an internen Server weiterleiten
iptables -t nat -A PREROUTING \
-p tcp --dport 80 \
-j DNAT --to-destination 10.0.1.10:80
# Eingehend auf Port 2222 β intern auf SSH Port 22
iptables -t nat -A PREROUTING \
-p tcp --dport 2222 \
-j DNAT --to-destination 10.0.1.50:22
# β οΈ DNAT allein reicht nicht!
# FORWARD-Regel muss auch erlauben:
iptables -A FORWARD \
-p tcp --dport 80 \
-d 10.0.1.10 \
-m conntrack --ctstate NEW \
-j ACCEPT
SNAT β Source NAT (ausgehend, feste IP)
# Internes Netz hinter fester externer IP verstecken
iptables -t nat -A POSTROUTING \
-s 10.0.0.0/19 \
-o eth0 \
-j SNAT --to-source 203.0.113.10
MASQUERADE β SNAT mit dynamischer IP
# FΓΌr Interfaces mit wechselnder IP (DSL, DHCP)
iptables -t nat -A POSTROUTING \
-s 10.0.0.0/19 \
-o eth0 \
-j MASQUERADE
# Forwarding im Kernel aktivieren! (sonst funktioniert NAT nicht)
echo 1 > /proc/sys/net/ipv4/ip_forward
# Persistent in /etc/sysctl.conf:
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p
Teil 6: VollstΓ€ndiges RZ-Regelwerk
#!/bin/bash
# /etc/iptables/rz-rules.sh
# RZ-Server Basis-HΓ€rtung
# Anpassen: MGMT_NET, SSH_PORT, eigene Dienste
MGMT_NET="10.0.0.0/19" # Management-Netz
SERVER_NET="10.0.1.0/24" # Server-Netz
SSH_PORT="22"
IPT="iptables"
IP6T="ip6tables"
echo "[*] Lade iptables RZ-Regelwerk..."
# ββ Alles leeren ββββββββββββββββββββββββββββββββββββββββββββββ
$IPT -F
$IPT -X
$IPT -t nat -F; $IPT -t nat -X
$IPT -t mangle -F; $IPT -t mangle -X
$IPT -t raw -F; $IPT -t raw -X
# ββ IPv6 komplett sperren (wenn nicht genutzt) ββββββββββββββββ
$IP6T -F
$IP6T -P INPUT DROP
$IP6T -P FORWARD DROP
$IP6T -P OUTPUT DROP
# ββ Default Policy ERST NACH Basis-Regeln setzen! βββββββββββββ
# (sonst Aussperrung bei Fehler)
# ββ Loopback ββββββββββββββββββββββββββββββββββββββββββββββββββ
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
# ββ Connection Tracking β IMMER ZUERST βββββββββββββββββββββββ
$IPT -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
$IPT -A INPUT -m conntrack --ctstate INVALID -j DROP
# ββ ICMP ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
$IPT -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
$IPT -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
# ICMP Typ 3 (Unreachable) und Typ 11 (TTL exceeded) fΓΌr Traceroute:
$IPT -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT
$IPT -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT
# ββ SSH β nur aus Management-Netz βββββββββββββββββββββββββββββ
$IPT -A INPUT -p tcp --dport $SSH_PORT \
-s $MGMT_NET \
-m conntrack --ctstate NEW \
-j ACCEPT
# ββ DNS (falls dieser Server DNS-Server ist) ββββββββββββββββββ
# $IPT -A INPUT -p udp --dport 53 -s $MGMT_NET -j ACCEPT
# $IPT -A INPUT -p tcp --dport 53 -s $MGMT_NET -j ACCEPT
# ββ Monitoring (NRPE/Icinga2) βββββββββββββββββββββββββββββββββ
# $IPT -A INPUT -p tcp --dport 5666 -s $MGMT_NET -j ACCEPT
# $IPT -A INPUT -p tcp --dport 5665 -s $MGMT_NET -j ACCEPT
# ββ IPMI/BMC Interface (separates Interface) ββββββββββββββββββ
# Falls IPMI auf eigenem Interface:
# $IPT -A INPUT -i ipmi0 -s $MGMT_NET -j ACCEPT
# ββ Logging vor DROP ββββββββββββββββββββββββββββββββββββββββββ
$IPT -A INPUT -j LOG \
--log-prefix "iptables-DROP-INPUT: " \
--log-level 4 \
-m limit --limit 5/min --limit-burst 10
# ββ Default Policy setzen βββββββββββββββββββββββββββββββββββββ
$IPT -P INPUT DROP
$IPT -P FORWARD DROP
$IPT -P OUTPUT ACCEPT
echo "[+] Regelwerk geladen."
echo "[*] Aktuelle Regeln:"
$IPT -L -n -v --line-numbers
Regeln persistent machen
# Debian / Ubuntu
apt install iptables-persistent
iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6
systemctl enable netfilter-persistent
# RHEL / Rocky / AlmaLinux
dnf install iptables-services
iptables-save > /etc/sysconfig/iptables
systemctl enable iptables
systemctl start iptables
# Arch Linux
iptables-save > /etc/iptables/iptables.rules
systemctl enable iptables
systemctl start iptables
# FreeBSD β KEIN iptables! β pf (siehe unten)
Teil 7: Diagnose und Debugging
# Regeln anzeigen
iptables -L -n -v # alle filter-Chains, mit ZΓ€hlern
iptables -L INPUT -n -v --line-numbers # mit Zeilennummern
iptables -t nat -L -n -v # NAT-Tabelle
# Treffer-ZΓ€hler zurΓΌcksetzen
iptables -Z # alle ZΓ€hler
iptables -Z INPUT # nur INPUT-Chain
# Einzelne Regel lΓΆschen
iptables -D INPUT 5 # Regel Nr. 5 in INPUT lΓΆschen
iptables -D INPUT -p tcp --dport 22 -j ACCEPT # nach Inhalt lΓΆschen
# Live-Logging beobachten
journalctl -f | grep iptables-DROP
tail -f /var/log/kern.log | grep iptables # Debian ohne systemd-journal
# Pakete tracen (raw table)
iptables -t raw -A PREROUTING \
-s 10.0.1.50 \
-j TRACE
# Connection Tracking anzeigen
conntrack -L
conntrack -L --proto tcp | grep ESTABLISHED
conntrack -E # Events live beobachten
# HΓ€ufige Probleme:
# Problem: SSH-Verbindung bricht ab nach RegelΓ€nderung
# Ursache: ESTABLISHED-Regel fehlt oder falsche Reihenfolge
iptables -L INPUT -n --line-numbers | grep ESTABLISHED
# Problem: NAT funktioniert nicht
# Ursache: ip_forward nicht aktiviert
cat /proc/sys/net/ipv4/ip_forward # muss 1 sein
# Ursache: FORWARD-Chain blockiert
iptables -L FORWARD -n -v
# Problem: Port ist offen aber Verbindung kommt nicht an
# Diagnose:
iptables -L INPUT -n -v # Regel vorhanden?
ss -tlnp | grep :PORT # Dienst lauscht?
conntrack -L | grep PORT # Connection Tracking?
Teil 8: nftables β Der moderne Nachfolger
Warum nftables?
iptables: Seit 1998, separate Tools pro Protokoll
(iptables, ip6tables, arptables, ebtables)
Jede Regel = Kernel-Syscall
Kein atomisches Regelwerk-Update
nftables: Seit Linux 3.13 (2014), ein Tool fΓΌr alles
Regelwerke werden als Batch geladen (atomar)
Bessere Performance
Seit Debian 10 / RHEL 8 Standard-Backend
iptables vs nftables Syntax
# iptables:
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# nftables equivalent:
nft add rule inet filter input tcp dport 22 accept
nftables Grundstruktur
Tables β Families β Chains β Rules
Family: ip (IPv4), ip6 (IPv6), inet (beide), arp, bridge
# VollstΓ€ndiges nftables RZ-Regelwerk
# /etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# Loopback
iif lo accept
# Connection Tracking
ct state established,related accept
ct state invalid drop
# ICMP
ip protocol icmp accept
ip6 nexthdr icmpv6 accept
# SSH aus Management-Netz
ip saddr 10.0.0.0/19 tcp dport 22 ct state new accept
# Logging
log prefix "nft-DROP: " flags all counter drop
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
table ip nat {
chain prerouting {
type nat hook prerouting priority -100;
# DNAT Beispiel:
# tcp dport 80 dnat to 10.0.1.10:80
}
chain postrouting {
type nat hook postrouting priority 100;
# MASQUERADE Beispiel:
# ip saddr 10.0.0.0/19 oif eth0 masquerade
}
}
# nftables Befehle
nft list ruleset # alles anzeigen
nft list table inet filter # eine Tabelle
nft -f /etc/nftables.conf # Datei laden
nft flush ruleset # alles leeren
# Service
systemctl enable nftables
systemctl start nftables
systemctl restart nftables # lΓ€dt /etc/nftables.conf neu
iptables-nft β KompatibilitΓ€ts-Backend
# Modernes Debian/Ubuntu/RHEL nutzt iptables-nft:
# iptables-Syntax, aber nftables-Backend im Kernel
iptables --version
# iptables v1.8.x (nf_tables) β nftables Backend β gut
# iptables v1.8.x (legacy) β legacy iptables β alt
# Backend prΓΌfen und setzen (Debian)
update-alternatives --query iptables
update-alternatives --set iptables /usr/sbin/iptables-nft
update-alternatives --set ip6tables /usr/sbin/ip6tables-nft
# β οΈ NIEMALS mischen!
# iptables-legacy + iptables-nft gleichzeitig = Chaos
# iptables + nftables direkt gleichzeitig = doppelte Regeln
Teil 9: FreeBSD β pf statt iptables
FreeBSD hat kein iptables. Das Γquivalent ist pf (Packet Filter),
ursprΓΌnglich aus OpenBSD.
# /etc/pf.conf β Basis RZ-Regelwerk
# Interfaces definieren
ext_if = "em0" # externes Interface
mgmt_if = "em1" # Management-Interface
mgmt_net = "10.0.0.0/19"
# Standard: alles blockieren
set block-policy drop
block all
# Loopback
pass quick on lo0
# Eingehend: nur Etabliertes + SSH aus Management
pass in quick on $mgmt_if inet proto tcp \
from $mgmt_net to any port 22 keep state
pass in quick inet proto icmp all keep state
pass out quick all keep state
# pf aktivieren
# /etc/rc.conf:
pf_enable="YES"
pf_rules="/etc/pf.conf"
pflog_enable="YES"
# Befehle
pfctl -e # pf aktivieren
pfctl -d # pf deaktivieren
pfctl -f /etc/pf.conf # Regeln laden
pfctl -sr # Regeln anzeigen
pfctl -si # Statistiken
pfctl -ss # Verbindungs-States anzeigen
Teil 10: Distro-Unterschiede
| Aspekt | Debian/Ubuntu | RHEL/Rocky | Arch | FreeBSD |
|---|---|---|---|---|
| Default Firewall-Tool | iptables-nft / ufw | firewalld / iptables | iptables | pf |
| Persistenz-Paket | iptables-persistent |
iptables-services |
systemd unit | rc.conf |
| Config-Datei | /etc/iptables/rules.v4 |
/etc/sysconfig/iptables |
/etc/iptables/iptables.rules |
/etc/pf.conf |
| nftables Config | /etc/nftables.conf |
/etc/nftables.conf |
/etc/nftables.conf |
n/a |
| ufw | vorinstalliert (inaktiv) | nicht vorhanden | optional | n/a |
| firewalld | nicht Standard | Standard | optional | n/a |
| Backend | nf_tables | nf_tables | nf_tables | pf |
Ubuntu: ufw deaktivieren bei manuellem iptables
# β οΈ ufw UND manuelles iptables = Konflikt!
ufw disable
systemctl disable ufw
systemctl mask ufw
# Dann prΓΌfen ob keine ufw-Chains mehr in iptables:
iptables -L | grep ufw # sollte leer sein
RHEL: firewalld deaktivieren bei manuellem iptables
# β οΈ firewalld UND manuelles iptables = Konflikt!
systemctl disable firewalld
systemctl mask firewalld
systemctl enable iptables
systemctl start iptables
Teil 11: Wichtige Einzeiler fΓΌr den RZ-Alltag
# Alle aktiven Regeln mit Treffern anzeigen
iptables -L -n -v | grep -v "0 0"
# Welche Ports lauschen UND sind durch Firewall erlaubt?
ss -tlnp; echo "---"; iptables -L INPUT -n | grep ACCEPT
# IP sofort sperren (Angreifer!)
iptables -I INPUT 1 -s 1.2.3.4 -j DROP
# IP-Sperre wieder aufheben
iptables -D INPUT -s 1.2.3.4 -j DROP
# Alle Verbindungen von IP zΓ€hlen
conntrack -L | grep 1.2.3.4 | wc -l
# Port-Scan erkennen (viele NEW-States von einer IP)
conntrack -L | grep NEW | awk '{print $6}' | \
grep src | sort | uniq -c | sort -rn | head
# SYN-Flood Schutz
iptables -A INPUT -p tcp --syn \
-m limit --limit 1/s --limit-burst 3 \
-j ACCEPT
iptables -A INPUT -p tcp --syn -j DROP
# Alle Regeln auf einmal sichern
iptables-save > /root/iptables-backup-$(date +%Y%m%d).rules
# Schnell wiederherstellen
iptables-restore < /root/iptables-backup-20260327.rules
Wichtige Dateipfade
| Pfad | System | Inhalt |
|---|---|---|
/etc/iptables/rules.v4 |
Debian/Ubuntu | IPv4-Regeln persistent |
/etc/iptables/rules.v6 |
Debian/Ubuntu | IPv6-Regeln persistent |
/etc/sysconfig/iptables |
RHEL/Rocky | IPv4-Regeln persistent |
/etc/iptables/iptables.rules |
Arch | IPv4-Regeln persistent |
/etc/nftables.conf |
Alle Linux | nftables-Regelwerk |
/etc/pf.conf |
FreeBSD | pf-Regelwerk |
/proc/sys/net/ipv4/ip_forward |
Linux | NAT/Forwarding aktiv? |
/proc/net/nf_conntrack |
Linux | Connection-Tracking-Tabelle |
journalctl -k | grep iptables |
systemd | Kernel-Log Firewall-Drops |
Quellen / WeiterfΓΌhrend
man iptables,man iptables-extensionsman nftman pf.conf(FreeBSD)- Netfilter Project: https://www.netfilter.org
- nftables Wiki: https://wiki.nftables.org
- Arch Wiki: https://wiki.archlinux.org/title/iptables
- RHEL Security Guide: Firewall kapitel