# nftables

Nástupce [iptables](iptables) a to, co by ses měl učit, když začínáš dnes. Na moderních distribucích už běží pod kapotou, i když píšeš `iptables`.

## Proč je lepší

**Jedna syntaxe pro IPv4 i IPv6.** Rodina `inet` řeší obojí naráz. Konec zapomenutého `ip6tables`, který je nejčastější díra v jinak slušně zajištěných serverech.

**Jeden nástroj místo pěti.** iptables, ip6tables, arptables a ebtables jsou v nftables sloučené.

**Množiny a slovníky.** Místo padesáti pravidel pro padesát portů napíšeš jedno.

**Atomické změny.** Celá sada se nahraje naráz, nebo vůbec. Nemůže se stát, že po půlce načtení zůstane firewall v nesmyslném stavu.

**Čitelná konfigurace.** Soubor, který se dá číst a verzovat, ne posloupnost příkazů.

## Struktura

Podobná iptables, ale všechno si vytváříš sám — žádné předdefinované tabulky:

- **tabulka** patří do rodiny (`inet`, `ip`, `ip6`, `arp`, `bridge`)
- **řetězec** má typ, hook a prioritu
- **pravidlo** je uvnitř řetězce

Rodina `inet` je ta, kterou chceš. Pokrývá IPv4 i IPv6 zároveň.

## Kompletní konfigurace serveru

Soubor `/etc/nftables.conf`:

```
#!/usr/sbin/nft -f
flush ruleset

table inet filter {
    set povolene_tcp {
        type inet_service
        elements = { 22, 80, 443 }
    }

    set duveryhodne {
        type ipv4_addr
        flags interval
        elements = { 192.168.1.0/24, 10.10.0.0/24 }
    }

    chain input {
        type filter hook input priority 0; policy drop;

        iif lo accept
        ct state established,related accept
        ct state invalid drop

        # ICMP, ať funguje ping a hlavně PMTU
        ip protocol icmp accept
        ip6 nexthdr icmpv6 accept

        # veřejné služby
        tcp dport @povolene_tcp accept

        # správa jen z důvěryhodných sítí
        ip saddr @duveryhodne tcp dport { 8006, 9090 } accept

        # ochrana proti hrubé síle na SSH
        tcp dport 22 ct state new limit rate 10/minute accept

        counter comment "zahozeno"
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
        ct state established,related accept
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}
```

Načtení a ověření:

```bash
nft -c -f /etc/nftables.conf     # jen kontrola syntaxe, nic neaplikuje
nft -f /etc/nftables.conf        # aplikace
systemctl enable nftables        # načte se po restartu
```

Ten přepínač `-c` používej vždycky. Ušetří ti to jeden zámek za rok.

## Co za tím stojí za vysvětlení

**`policy drop`** znamená, že co neprojde žádným pravidlem, se zahodí. Bezpečnější než povolovat všechno a zakazovat výjimky, protože na co zapomeneš, to je zakázané, ne otevřené.

**`iif lo accept`** musí být první. Bez toho si rozbiješ komunikaci mezi procesy na stroji — a projeví se to nečekaně, třeba tím, že databáze nevidí sama sebe.

**`ip6 nexthdr icmpv6 accept`** není volitelné. V IPv6 stojí na ICMPv6 objevování sousedů i zjišťování MTU. Když ho zablokuješ, [IPv6](Jak-funguje-IPv6) přestane fungovat způsobem, který se hledá strašně těžko: něco jde, něco ne, velké soubory se zaseknou v půlce.

**`counter`** na konci ti dá číslo, kolik paketů propadlo až sem. Užitečné při ladění — když je nula, všechno prošlo dřív.

**`limit rate 10/minute`** je jednoduchá ochrana proti hrubé síle. Sofistikovanější je [fail2ban](Fail2ban-a-CrowdSec), ale tohle stojí jeden řádek.

## Množiny

Největší praktická výhoda proti iptables. Množinu upravíš za běhu bez načítání celé sady:

```bash
nft add element inet filter povolene_tcp { 8080 }
nft delete element inet filter povolene_tcp { 8080 }
nft list set inet filter duveryhodne
```

Dynamická množina s časovým omezením — sem si může fail2ban odkládat blokované adresy:

```
set blokovani {
    type ipv4_addr
    flags timeout
    timeout 1h
}
```

## NAT

```
table inet nat {
    chain prerouting {
        type nat hook prerouting priority -100;
        iif eth0 tcp dport 443 dnat ip to 192.168.1.10:443
    }
    chain postrouting {
        type nat hook postrouting priority 100;
        oif eth0 masquerade
    }
}
```

Stejně jako u iptables platí, že DNAT sám nestačí — provoz musí ještě projít řetězcem `forward`, kde ho `policy drop` zahodí:

```
chain forward {
    type filter hook forward priority 0; policy drop;
    ct state established,related accept
    ip daddr 192.168.1.10 tcp dport 443 accept
}
```

## Diagnostika

```bash
nft list ruleset                 # kompletní stav včetně toho, co tam dal někdo jiný
nft list ruleset -a              # s handles pro mazání
nft list table inet filter
nft monitor trace                # živé sledování, kudy paket prochází
```

Ten `nft list ruleset` je nejcennější příkaz na téhle stránce. Ukáže ti **všechno**, včetně pravidel, která přidal Docker nebo Proxmox a o kterých ti [ufw](ufw) neřekne.

Pro sledování konkrétního paketu:

```bash
nft add rule inet filter input tcp dport 8080 meta nftrace set 1
nft monitor trace
```

## Převod ze starých pravidel

```bash
iptables-save > stara.rules
iptables-restore-translate -f stara.rules > nova.nft
```

Výsledek projdi ručně. Překlad je mechanický a nevyužije množiny ani rodinu `inet`, takže dostaneš funkční, ale ošklivou konfiguraci. Ber ji jako výchozí bod k přepsání.

## Docker

Docker si i na nftables systémech zapisuje pravidla přes `iptables-nft` a tvoje `table inet filter` obchází. Viz [Docker a firewall](Docker-a-firewall) — bez toho ti nftables konfigurace vytvoří falešný pocit bezpečí.
