Firewall a NAT
Netfilter
nftables
Podíváme se teď na ta samá pravidla pro nftables. To má výhodu, že nftables mají konfigurační soubor s pravidly /etc/nftables.conf
a k tomu utilitu nft
, která umí konfigurační soubor načíst pomoci nft -f /etc/nftables.conf
.
Naše pravidla tedy budou vypadat takto:
table ip filter {
chain INPUT {
type filter hook input priority filter; policy drop;
iifname "lo" counter accept
ip saddr 192.168.1.10 counter drop
iifname "eth0" meta l4proto tcp ip saddr 192.168.1.0/24 tcp dport {22,80,443} accept
meta l4proto icmp counter accept
}
}
Tato pravidla se čtou mnohem snáz, nicméně je tu několik koncepčních změn: v první řadě slovo counter
vyjadřuje, že pro pravidlo, které má toto slovo před akcí (accept
nebo drop
) se bude počítat počet packetů a bytů v packetech, které měly s pravidlem shodu.
Další poměrně důležitá koncepční změna je meta l4proto icmp
resp. meta l4proto tcp
: nftables umožňují sice napsat ip protocol icmp
a v tomto případě by to nevadilo. Problém vzniká u IPv6, kde v políčku Next Header může být hodnota pro ICMP a nebo tam může být hodnota identifikující následující IPv6 extension header. V tomto případě by se pak pravidlo ip6 nexthdr icmpv6
neshodovalo s packetem i když by za hlavičkou IPv6 extension header byl ICMPv6 datagram. A to se opravdu stává - Hop-by-Hop Extension Header se používá pro MLD - Multicast Listener Discovery. A když nefunguje MLD, nemusí fungovat ani Neighbor Discovery, takže nakonec nebude fungovat v podstatě nic.
Jestli má IPv6 nějakou chybu, která způsobuje jeho trochu pošramocenou pověst - že se záhadně rozbíjí a nikdo neví proč, tak tohle je přesně příklad věci, která funguje u IPv6 trochu složitěji, než u IPv4 a na kterou si člověk snadno naběhne a celé to začne dávat smysl až po delší chvíli čtení, studia a diskuzí, proč to stálo za to udělat trochu složitější, než u IPv4. Na druhou stranu nftables je moderní a zavedlo meta l4proto
pro IPv4 i IPv6, aby se zjednodušila situace s výchozím a doporučované nastavení bylo správně pro IPv4 i pro IPv6.
Poté, co pravidla instalujeme do kernelu pomocí nft -f /etc/nftables.conf
je můžeme snadno zobrazit i s aktuálními countery:
root@c1:~# nft list ruleset
table inet filter {
chain input {
type filter hook input priority filter; policy accept;
}
chain forward {
type filter hook forward priority filter; policy accept;
}
chain output {
type filter hook output priority filter; policy accept;
}
}
table ip filter {
chain INPUT {
type filter hook input priority filter; policy drop;
iifname "lo" counter packets 180 bytes 14996 accept
ip saddr 192.168.1.10 counter packets 0 bytes 0 drop
iifname "eth0" meta l4proto tcp ip saddr 192.168.1.0/24 tcp dport { 22,80,443} counter packets 0 bytes 0 accept
meta l4proto icmp counter packets 1 bytes 93 accept
}
chain FORWARD {
type filter hook forward priority filter; policy accept;
}
chain OUTPUT {
type filter hook output priority filter; policy accept;
}
}
Všimněte si, že pravidla v předchozích případech nebyla úplně praktická - nepovolovala například spojení navázaná z našeho serveru kamkoliv do Internetu. Přesně řečeno: V OUTPUT řetězci sice bylo vše povoleno, takže odchozí packety by odešly. Ale odpovědi od serverů v Internetu by byly zahozeny, ledaže by matchovaly jedno z povolujících pravidel a to v našem případě znamená jen jedno pravidlo, které povoluje spojení na HTTP, HTTPS a SSH server. Můžeme to zachránit bezstavově tak, že pro protokol TCP povolíme všechny příchozí packety (TCP segmenty), krom těch, které navazují nové spojení a tedy mají nastaven flag SYN=1. To uděláme v iptables takto:
iptables -A INPUT -p tcp ! --syn -j ACCEPT
A pro nftables to bude v tabulce ip filter
v řetězci INPUT
pravidlo:
meta l4proto tcp tcp flags & (fin|syn|rst|ack) != syn counter accept
Jenže to sebou přece jen přináší problémy: z hlediska bezpečnosti to je nedokonalé. Umožňuje to útočníkům posílat TCP segmenty mimo normální pořadí, napadat běžící spojení a zkoušet se do nich vmísit a vůbec celé rozlišení, co jsou odpovědi na spojení navázané ven a co je pokračování spojení zvenčí, je od třetího packetu prakticky nemožné. U protokolu UDP nic, jako SYN flag není, takže tam jsou možnosti ještě víc omezené - prakticky můžete jen matchovat kombinací zdrojových a cílových adres a portů a jen podle nich datagram buď propustíte a nebo zahodíte.
Dejme tomu, že v příchozím směru by to bezstavově s protokolem TCP ještě šlo, za cenu složitějších pravidel a ústupků z bezpečnosti. V odchozím směru je to ale problém - tam už opravdu nerozlišíte, co je další segment běžícího spojení od vás ven a co je odpověď na nově navázané spojení zvenčí. Nemluvě o NATu, což je disciplína, ve které Linux vyniká, ovšem jen díky stavovému zpracování packetů - conntracku.
Zatím jsme se zabývali jen nejjednodušším případem - filtrování packetů v tabulce filter v řetězci INPUT. Netfilter má však mnoho výchozích řetězců a vedle toho umožňuje definovat vlastní řetězce uživateli. Průchod packetu firewallem je mnohafázový proces a rozebereme jej podrobněji v závěrečné kapitole.
Odkazy: