iptables
iptables
Klasika, kterou najdeš ve všech starších návodech. Na moderních distribucích je to už jen překladová vrstva nad nftables, ale příkazy fungují a znát je se vyplatí — velká část internetu je pořád psaná v nich.
Pokud stavíš něco nového, zvaž rovnou nftables. Tahle stránka je hlavně proto, abys rozuměl tomu, co už běží.
Struktura
Tři úrovně: tabulky obsahují řetězce a ty obsahují pravidla.
| Tabulka | K čemu |
|---|---|
filter |
povolit a zakázat. Výchozí, když tabulku neuvedeš. |
nat |
přepis adres, DNAT a SNAT |
mangle |
úpravy hlaviček, TTL, značkování |
raw |
obejití sledování stavu |
Doma potřebuješ filter a nat. Zbytek téměř nikdy.
Řetězce a to, kudy paket letí, jsou popsané v Linux firewall.
Čtení současného stavu
iptables -L -n -v --line-numbers # tabulka filter
iptables -t nat -L -n -v # tabulka nat
iptables-save # všechno v podobě k obnovení
Přepínač -n je zásadní — bez něj se iptables snaží překládat IP na jména a při každém výpisu čekáš.
Sloupce pkts a bytes ukazují, kolik provozu daným pravidlem prošlo. Neocenitelné při ladění: pravidlo s nulou se nikdy nepoužilo, což obvykle znamená, že je špatně umístěné nebo že ho něco výš zachytilo dřív.
Základní sada pro server
# výchozí politika
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# nezablokovat sám sebe
iptables -A INPUT -i lo -j ACCEPT
# stavovost: odpovědi na vlastní spojení
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
# ping (užitečné pro diagnostiku)
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
# služby
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
Pořadí je podstatné. Pravidla se vyhodnocují shora dolů a první shoda vyhraje. Řádek s lo musí být nahoře, jinak si rozbiješ lokální komunikaci mezi procesy.
Omezení podle zdroje
SSH jen z domácí sítě a z VPN:
iptables -A INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -s 10.10.0.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP
NAT
Masquerade, tedy překlad na adresu odchozího rozhraní. Tohle dělá router:
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
DNAT, tedy port forwarding dovnitř:
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to-destination 192.168.1.10:443
iptables -A FORWARD -p tcp -d 192.168.1.10 --dport 443 -j ACCEPT
Ta druhá řádka se zapomíná pořád. DNAT jen přepíše adresu — paket pak musí ještě projít řetězcem FORWARD, kde ho výchozí politika DROP zahodí.
A aby forwarding vůbec fungoval:
sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
Vkládání na správné místo
-A přidává na konec, -I na začátek. Když máš na konci DROP a použiješ -A, tvoje nové pravidlo se nikdy neuplatní.
iptables -I INPUT 3 -p tcp --dport 8080 -j ACCEPT # vloží na třetí pozici
iptables -D INPUT 3 # smaže třetí pravidlo
Čísla zjistíš přes --line-numbers.
Přetrvání po restartu
Pravidla v paměti zmizí při restartu. Na Debianu a Ubuntu:
apt install iptables-persistent
netfilter-persistent save
Uloží do /etc/iptables/rules.v4 a rules.v6.
Ručně:
iptables-save > /etc/iptables/rules.v4
iptables-restore < /etc/iptables/rules.v4
IPv6 je zvlášť
Tohle je klasická díra. iptables řeší jen IPv4. Pro IPv6 je samostatný příkaz:
ip6tables -L -n -v
Server, který má IPv6 a zajištěný jen iptables, je z internetu otevřený dokořán. Každé pravidlo, které píšeš, si napiš i v ip6tables — nebo použij nftables, který umí obojí naráz.
Logování
iptables -A INPUT -j LOG --log-prefix "IPTABLES-DROP: " --log-level 4
iptables -A INPUT -j DROP
Log pravidlo musí být před tím zahazovacím, jinak se nic nezaloguje.
Zprávy jdou do journalctl -k nebo /var/log/kern.log. Nenechávej to zapnuté napořád na pravidle chytajícím provoz z internetu — zaplníš disk během dní.
Když se to chová divně
Pravidlo nemá žádné pakety (-v ukazuje nuly) → něco výš ho zachytilo dřív, nebo je paket ve špatném řetězci.
Funguje to na hostiteli, ale ne v kontejneru → Docker si přidává vlastní pravidla a tvoje obchází. Viz Docker a firewall.
Po restartu je všechno pryč → chybí persistence.
Funguje IPv4, ale ne IPv6 → viz výše.
Systematický postup je v diagnostice.