TimVin

nftables — современный фреймворк фильтрации пакетов Linux, заменяющий iptables, ip6tables, arptables и ebtables. Управление выполняется утилитой nft; правила объединяются в таблицы и цепочки.

1. Базовая модель nftables

Иерархия правил: family → table → chain → rule

  • Family — семейство протоколов: ip (IPv4), ip6 (IPv6), inet (IPv4 + IPv6), arp, bridge, netdev.
  • Table — логический контейнер цепочек и объектов.
  • Chain — последовательность правил. Бывает базовой (base chain, подключена к сетевому стеку через hook) или обычной (regular chain, вызывается через jump/goto).
  • Rule — условие и действие: tcp dport 22 accept, ip saddr 10.0.0.0/8 drop и т. п.

Для универсального firewall обычно используется family inet: одна таблица одновременно обслуживает IPv4 и IPv6.

2. Установка, служба и диагностика

# Debian/Ubuntu
sudo apt update
sudo apt install nftables
# Запустить и включить при старте
sudo systemctl enable --now nftables

# Проверить состояние службы
sudo systemctl status nftables

# Вывести весь активный ruleset
sudo nft list ruleset

# Вывести ruleset вместе с handle каждого правила
sudo nft -a list ruleset

# Проверить синтаксис файла без применения
sudo nft -c -f /etc/nftables.conf

В дистрибутивах с systemd обычно постоянная конфигурация хранится в /etc/nftables.conf, а сервис nftables загружает её при запуске.

3. Важные правила безопасного применения

Перед удалённой настройкой firewall:

  1. Откройте второе SSH-подключение или консоль через IPMI/iDRAC/Proxmox.
  2. Сначала добавьте правило, разрешающее текущий SSH-доступ.
  3. Проверяйте конфигурацию: sudo nft -c -f /etc/nftables.conf.
  4. Применяйте файл: sudo nft -f /etc/nftables.conf.
  5. Сразу проверьте: sudo nft -a list ruleset.

4. Таблицы: создание, просмотр, очистка, удаление

Создать таблицу

# Общая таблица для IPv4 и IPv6
sudo nft add table inet filter

# Только IPv4
sudo nft add table ip filter4

# Только IPv6
sudo nft add table ip6 filter6

Просмотреть таблицы

# Список таблиц
sudo nft list tables

# Содержимое конкретной таблицы
sudo nft list table inet filter

Очистить или удалить таблицу

# Удалить правила и цепочки из таблицы, но оставить таблицу
sudo nft flush table inet filter

# Полностью удалить таблицу
sudo nft delete table inet filter

flush table удаляет содержимое таблицы. delete table удаляет и саму таблицу.

5. Цепочки: base chain и regular chain

Base chain

Базовая цепочка подключается к одной из точек обработки пакета (hook) и получает пакеты от сетевого стека.

Основные hook для firewall:

Hook Направление Назначение
input Входящие на локальный хост SSH, веб-сервер, DNS на самом сервере
forward Транзит через хост / роутер VPN-шлюз, Docker-хост, межсетевой экран
output Исходящие с локального хоста Ограничение исходящих соединений
prerouting До выбора маршрута NAT/DNAT, ранняя фильтрация
postrouting После выбора маршрута NAT/SNAT/masquerade

Создать базовые цепочки фильтрации

# Input: пакеты, адресованные самому хосту
sudo nft add chain inet filter input '{ type filter hook input priority 0; policy drop; }'

# Forward: транзитные пакеты
sudo nft add chain inet filter forward '{ type filter hook forward priority 0; policy drop; }'

# Output: пакеты, созданные локально
sudo nft add chain inet filter output '{ type filter hook output priority 0; policy accept; }'

policy drop действует только если ни одно правило в базовой цепочке не выдало окончательный verdict (accept, drop, reject).

Создать обычную цепочку

Обычная цепочка не имеет type, hook и priority. Она вызывается из другой цепочки.

# Цепочка для SSH
sudo nft add chain inet filter ssh_in

# Цепочка для сервисов веб-сервера
sudo nft add chain inet filter web_in

Разница между jump и goto

# jump: выполнить ssh_in и вернуться к следующему правилу текущей цепочки
sudo nft add rule inet filter input tcp dport 22 jump ssh_in

# goto: перейти в ssh_in и не возвращаться в текущую цепочку
sudo nft add rule inet filter input tcp dport 22 goto ssh_in

Практически для модульных firewall-конфигураций чаще используют jump.

Просмотр, очистка и удаление цепочек

# Вывести одну цепочку
sudo nft list chain inet filter input

# Вывести правила и handles
sudo nft -a list chain inet filter input

# Удалить все правила из цепочки, оставив цепочку
sudo nft flush chain inet filter ssh_in

# Удалить пустую regular chain
sudo nft delete chain inet filter ssh_in

# Удалить base chain: сначала очистить её и удалить обращения jump/goto
sudo nft flush chain inet filter input
sudo nft delete chain inet filter input

Цепочку нельзя удалить, пока в ней есть правила или на неё ссылаются правила jump/goto. Для удаления сначала удалите ссылки, затем очистите цепочку.

6. Правила: добавление, вставка, замена, удаление

Добавить правило в конец цепочки

# Разрешить SSH
sudo nft add rule inet filter input tcp dport 22 accept

# Разрешить HTTP/HTTPS
sudo nft add rule inet filter input tcp dport { 80, 443 } accept

# Разрешить ICMP и ICMPv6
sudo nft add rule inet filter input ip protocol icmp accept
sudo nft add rule inet filter input meta l4proto ipv6-icmp accept

Вставить правило в начало цепочки

Это важно для SSH-исключения, если ниже уже есть drop.

# Вставить правило первым
sudo nft insert rule inet filter input tcp dport 22 accept

Вставить правило перед/после конкретного handle

# Показать handles
sudo nft -a list chain inet filter input

# Вставить правило перед правилом с handle 12
sudo nft insert rule inet filter input position 12 tcp dport 443 accept

# Добавить правило после handle 12
sudo nft add rule inet filter input position 12 tcp dport 443 accept

Заменить правило

# Сначала посмотреть handle
sudo nft -a list chain inet filter input

# Заменить правило с handle 7
sudo nft replace rule inet filter input handle 7 tcp dport 22 ct state new limit rate 10/minute accept

Удалить правило по handle

# Найти handle
sudo nft -a list chain inet filter input

# Пример вывода:
# tcp dport 22 accept comment "SSH" # handle 5

# Удалить правило
sudo nft delete rule inet filter input handle 5

handle — идентификатор конкретного правила в текущем активном ruleset. После перезагрузки/пересоздания ruleset номера handle могут измениться, поэтому всегда получайте их заново перед удалением.

7. Основные выражения и verdict

Состояние соединения conntrack

# Пропускать established и related трафик
sudo nft add rule inet filter input ct state established,related accept

# Разрешать только новые SSH-соединения
sudo nft add rule inet filter input tcp dport 22 ct state new accept

# Отбрасывать invalid-пакеты
sudo nft add rule inet filter input ct state invalid drop

Адреса и подсети

# Разрешить SSH только с одного IPv4-адреса
sudo nft add rule inet filter input ip saddr 192.168.1.10 tcp dport 22 accept

# Разрешить PostgreSQL только из внутренней подсети
sudo nft add rule inet filter input ip saddr 10.10.10.0/24 tcp dport 5432 accept

# Разрешить IPv6-подсеть
sudo nft add rule inet filter input ip6 saddr 2001:db8:10::/64 tcp dport 22 accept

# Заблокировать IP
sudo nft add rule inet filter input ip saddr 203.0.113.25 drop

Интерфейсы

# Разрешить loopback
sudo nft add rule inet filter input iifname "lo" accept

# Разрешить SSH только через eth0
sudo nft add rule inet filter input iifname "eth0" tcp dport 22 accept

# Forward из LAN в WAN
sudo nft add rule inet filter forward iifname "lan0" oifname "wan0" accept

Порты и протоколы

# Один TCP-порт
sudo nft add rule inet filter input tcp dport 22 accept

# Несколько TCP-портов
sudo nft add rule inet filter input tcp dport { 22, 80, 443 } accept

# Диапазон TCP-портов
sudo nft add rule inet filter input tcp dport 6000-6010 accept

# DNS UDP и TCP
sudo nft add rule inet filter input udp dport 53 accept
sudo nft add rule inet filter input tcp dport 53 accept

Действия (verdict)

# Разрешить
accept

# Молча отбросить
drop

# Отклонить с ICMP/ICMPv6 ответом
reject

# Перейти в regular chain
jump ssh_in

# Перейти без возврата
goto ssh_in

# Вернуться из regular chain
return

8. Логирование, счётчики и rate limit

# Логировать и отбросить трафик
sudo nft add rule inet filter input log prefix "nft-input-drop: " flags all counter drop

# Добавить счётчик к разрешающему правилу
sudo nft add rule inet filter input tcp dport 443 counter accept

# Ограничить новые SSH-соединения: 10 в минуту, bursts до 15
sudo nft add rule inet filter input tcp dport 22 ct state new limit rate 10/minute burst 15 packets accept

# Логировать не чаще 5 сообщений в секунду
sudo nft add rule inet filter input limit rate 5/second log prefix "nft-drop: " counter drop

# Посмотреть срабатывания counter
sudo nft list chain inet filter input

Логи обычно попадают в kernel journal:

sudo journalctl -k -f
# или
sudo dmesg -w

9. Sets: списки адресов и портов

Sets делают конфигурацию компактной и удобной для сопровождения.

# Создать IPv4 set
sudo nft add set inet filter trusted_v4 '{ type ipv4_addr; flags interval; }'

# Добавить адреса и подсети
sudo nft add element inet filter trusted_v4 '{ 10.0.0.0/8, 192.168.10.0/24, 203.0.113.10 }'

# Разрешить SSH только доверенным адресам
sudo nft add rule inet filter input ip saddr @trusted_v4 tcp dport 22 accept

# Посмотреть set
sudo nft list set inet filter trusted_v4

# Удалить элемент
sudo nft delete element inet filter trusted_v4 '{ 203.0.113.10 }'

# Удалить set: сначала убрать все ссылки на него из правил
sudo nft delete set inet filter trusted_v4

Set портов

# Создать set TCP-портов
sudo nft add set inet filter allowed_tcp_ports '{ type inet_service; }'

# Заполнить портами
sudo nft add element inet filter allowed_tcp_ports '{ 22, 80, 443 }'

# Использовать в правиле
sudo nft add rule inet filter input tcp dport @allowed_tcp_ports accept

10. NAT: DNAT, SNAT и masquerade

Таблица и base chain для NAT

sudo nft add table ip nat
sudo nft add chain ip nat prerouting '{ type nat hook prerouting priority dstnat; policy accept; }'
sudo nft add chain ip nat postrouting '{ type nat hook postrouting priority srcnat; policy accept; }'

Примеры NAT

# DNAT: проброс WAN:443 на внутренний сервер 10.10.10.20:8443
sudo nft add rule ip nat prerouting iifname "wan0" tcp dport 443 dnat to 10.10.10.20:8443

# SNAT: статический публичный адрес
sudo nft add rule ip nat postrouting oifname "wan0" ip saddr 10.10.10.0/24 snat to 198.51.100.10

# Masquerade: адрес на WAN динамический
sudo nft add rule ip nat postrouting oifname "wan0" ip saddr 10.10.10.0/24 masquerade

Для маршрутизации также включите IPv4 forwarding:

sudo sysctl -w net.ipv4.ip_forward=1

# Постоянно: создать файл /etc/sysctl.d/99-forwarding.conf
printf 'net.ipv4.ip_forward=1\n' | sudo tee /etc/sysctl.d/99-forwarding.conf
sudo sysctl --system

11. Постоянная конфигурация: /etc/nftables.conf

Ниже — минимальный рабочий конфиг сервера. Перед применением замените интерфейс/порты и убедитесь, что SSH-порт указан корректно.

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

table inet filter {
  chain input {
    type filter hook input priority filter; policy drop;

    iifname "lo" accept
    ct state established,related accept
    ct state invalid drop

    # IPv4/IPv6 ICMP: ping, path MTU discovery и служебные сообщения
    ip protocol icmp accept
    meta l4proto ipv6-icmp accept

    # Управление и веб-сервисы
    tcp dport 22 ct state new accept
    tcp dport { 80, 443 } ct state new accept

    # Финальное логирование и блокировка
    limit rate 5/second log prefix "nft-input-drop: " flags all counter drop
  }

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

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

Применение:

# Проверить синтаксис
sudo nft -c -f /etc/nftables.conf

# Загрузить конфигурацию
sudo nft -f /etc/nftables.conf

# Посмотреть активные правила и handles
sudo nft -a list ruleset

# Обеспечить загрузку после перезагрузки
sudo systemctl enable nftables

flush ruleset в начале файла полностью очищает текущие правила перед загрузкой файла. Не смешивайте этот конфиг с правилами, которыми управляют UFW, Docker, Kubernetes или другой firewall-менеджер, без предварительной проверки интеграции.

12. Типовые сценарии

Веб-сервер

chain input {
  type filter hook input priority filter; policy drop;
  iifname "lo" accept
  ct state established,related accept
  ct state invalid drop
  ip protocol icmp accept
  meta l4proto ipv6-icmp accept
  tcp dport 22 ct state new accept
  tcp dport { 80, 443 } ct state new accept
  counter drop
}

Сервер PostgreSQL из внутренней сети

chain input {
  type filter hook input priority filter; policy drop;
  iifname "lo" accept
  ct state established,related accept
  ip saddr 10.10.10.0/24 tcp dport 5432 ct state new accept
  ip saddr 10.10.10.0/24 tcp dport 22 ct state new accept
  counter drop
}

Роутер: LAN → WAN с NAT

table inet filter {
  chain forward {
    type filter hook forward priority filter; policy drop;
    ct state established,related accept
    iifname "lan0" oifname "wan0" accept
  }
}

table ip nat {
  chain postrouting {
    type nat hook postrouting priority srcnat; policy accept;
    oifname "wan0" ip saddr 10.10.10.0/24 masquerade
  }
}

13. Удаление объектов: порядок действий

Если нужно удалить модульную конфигурацию, соблюдайте зависимости:

# 1. Посмотреть активную конфигурацию с handles
sudo nft -a list ruleset

# 2. Удалить правила, которые ссылаются на regular chain/set
sudo nft delete rule inet filter input handle 15

# 3. Очистить и удалить regular chain
sudo nft flush chain inet filter ssh_in
sudo nft delete chain inet filter ssh_in

# 4. Удалить set (если он больше нигде не используется)
sudo nft delete set inet filter trusted_v4

# 5. Очистить и удалить таблицу
sudo nft flush table inet filter
sudo nft delete table inet filter

14. Полезные команды диагностики

# Полный ruleset
sudo nft list ruleset

# С handles
sudo nft -a list ruleset

# В машинно-обрабатываемом JSON
sudo nft -j list ruleset

# Мониторинг изменений ruleset в реальном времени
sudo nft monitor ruleset

# Мониторинг трассировки пакетов (использовать осторожно)
sudo nft monitor trace

# Проверить загрузку systemd-конфига
sudo systemctl status nftables
sudo journalctl -u nftables -b

15. Быстрая шпаргалка

# Таблица
nft add table inet filter

# Base chain
nft add chain inet filter input '{ type filter hook input priority 0; policy drop; }'

# Regular chain
nft add chain inet filter ssh_in

# Правило
nft add rule inet filter input tcp dport 22 accept

# Посмотреть handles
nft -a list chain inet filter input

# Удалить правило по handle
nft delete rule inet filter input handle 5

# Очистить chain
nft flush chain inet filter input

# Удалить пустую chain
nft delete chain inet filter input

# Удалить таблицу
nft delete table inet filter

16. Частые ошибки

Симптом Возможная причина Проверка / решение
Потерян SSH после применения Нет разрешающего правила до policy drop Через консоль добавить nft insert rule inet filter input tcp dport 22 accept
No such file or directory Нет таблицы или цепочки Проверить nft list tables, затем создать нужный объект
Device or resource busy при удалении Есть правила или ссылки jump/goto Удалить ссылки, выполнить flush chain, затем delete chain
Не работает DNAT Нет разрешения в forward или выключен IP forwarding Добавить правило в forward, включить net.ipv4.ip_forward=1
Правила исчезли после reboot Конфигурация не сохранена / служба выключена Записать /etc/nftables.conf, выполнить systemctl enable --now nftables
Docker/Kubernetes ведут себя непредсказуемо Несогласованное управление правилами Не выполнять бездумный flush ruleset; проектировать интеграцию отдельно
Рубрики: Linux