Linux-сети: от iptables к nftables

linuxnetworkingiptablesnftables

NAT и DNAT: маппинг портов через iptables/nftables

Если вы администрируете Linux-серверы, вы неизбежно столкнётесь с файрволом. Долгие годы стандартом де-факто был iptables, но ему на смену пришёл nftables. В этой статье разберём оба инструмента: как работает iptables, почему nftables лучше и как мигрировать без даунтайма.

iptables: фундамент, который нужно знать

Даже если вы планируете использовать только nftables, понимание iptables необходимо. Большинство существующих серверов, документации и Stack Overflow ответов всё ещё используют iptables. Кроме того, nftables наследует многие концепции из iptables.

Таблицы и цепочки

iptables организован в таблицы (tables), каждая из которых содержит цепочки (chains) с правилами.

Основные таблицы:

ТаблицаНазначение
filterФильтрация пакетов (accept/drop). Таблица по умолчанию
natПреобразование адресов (SNAT, DNAT, MASQUERADE)
mangleМодификация заголовков пакетов (TTL, TOS, MARK)
rawОбход connection tracking

Основные цепочки в таблице filter:

  • INPUT — входящие пакеты, адресованные серверу
  • FORWARD — пакеты, проходящие через сервер (роутинг)
  • OUTPUT — исходящие пакеты от сервера

Базовые команды

Посмотреть текущие правила:

# Все правила с номерами строк
sudo iptables -L -n -v --line-numbers

# Правила в таблице nat
sudo iptables -t nat -L -n -v

Типичный вывод выглядит так:

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source       destination
1     1205  98K ACCEPT     all  --  lo     *       0.0.0.0/0    0.0.0.0/0
2    15.2M 2.1G ACCEPT     all  --  *      *       0.0.0.0/0    0.0.0.0/0    state RELATED,ESTABLISHED
3      412  24K ACCEPT     tcp  --  *      *       0.0.0.0/0    0.0.0.0/0    tcp dpt:22
4      287  17K ACCEPT     tcp  --  *      *       0.0.0.0/0    0.0.0.0/0    tcp dpt:80
5      193  11K ACCEPT     tcp  --  *      *       0.0.0.0/0    0.0.0.0/0    tcp dpt:443
6     8431 504K DROP       all  --  *      *       0.0.0.0/0    0.0.0.0/0

Типичная настройка файрвола

Вот минимальный набор правил для веб-сервера:

#!/bin/bash
# Сброс всех правил
sudo iptables -F
sudo iptables -X

# Политики по умолчанию
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT

# Разрешить loopback
sudo iptables -A INPUT -i lo -j ACCEPT

# Разрешить установленные соединения
sudo iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

# SSH (порт 22)
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# HTTP и HTTPS
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Разрешить ICMP (ping)
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

# Логировать отброшенные пакеты (опционально)
sudo iptables -A INPUT -j LOG --log-prefix "IPT_DROP: " --log-level 4

Проброс портов (DNAT)

Частая задача — пробросить порт с внешнего интерфейса на внутренний сервис. Например, перенаправить трафик с порта 8080 на порт 80:

# Включить IP forwarding
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

# DNAT: перенаправить внешний порт 8080 на локальный 80
sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 127.0.0.1:80

# Разрешить форвардинг для этого трафика
sudo iptables -A FORWARD -p tcp --dport 80 -j ACCEPT

Для перенаправления диапазона портов (полезно, например, для UDP-сервисов):

# Перенаправить UDP-порты 20000-40000 на порт 443
sudo iptables -t nat -A PREROUTING -p udp --dport 20000:40000 -j DNAT --to-destination :443

Rate limiting

Защита от брутфорса SSH:

# Не более 3 новых SSH-подключений за 60 секунд с одного IP
sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW 
  -m recent --set --name SSH

sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW 
  -m recent --update --seconds 60 --hitcount 4 --name SSH -j DROP

Почему nftables?

iptables работает, но у него накопились проблемы:

  1. Архитектура. Для разных протоколов нужны разные утилиты: iptables (IPv4), ip6tables (IPv6), arptables (ARP), ebtables (Ethernet bridging). В nftables всё в одном инструменте.

  2. Производительность. iptables обрабатывает правила линейно — O(n). nftables использует множества (sets) и карты (maps), что даёт O(1) для поиска по большим спискам IP-адресов.

  3. Синтаксис. Правила iptables — это длинные строки с кучей флагов. nftables использует более читаемый структурированный синтаксис.

  4. Атомарные обновления. В iptables каждая команда iptables -A — отдельный системный вызов. Между командами есть окно, когда правила в несогласованном состоянии. nftables позволяет применять набор правил атомарно.

Начиная с Debian 10 (Buster) и Ubuntu 20.04, nftables является файрволом по умолчанию. Утилита iptables во многих дистрибутивах — это уже обёртка iptables-nft, которая транслирует команды в nftables.

Проверить, что используется на вашей системе:

# Если вывод содержит "nf_tables" — используется nftables-бэкенд
sudo iptables -V
# iptables v1.8.9 (nf_tables)

# Или напрямую проверить
sudo nft list ruleset

nftables: основы

Структура правил

В nftables иерархия такая: таблицы → цепочки → правила. Но в отличие от iptables, таблицы и цепочки нужно создавать явно.

Базовый конфиг файрвола:

#!/usr/sbin/nft -f

# Очистить все правила
flush ruleset

# Создать таблицу для IPv4 и IPv6
table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;

        # Разрешить loopback
        iif "lo" accept

        # Разрешить установленные соединения
        ct state established,related accept

        # Разрешить ICMP и ICMPv6
        ip protocol icmp accept
        ip6 nexthdr icmpv6 accept

        # SSH
        tcp dport 22 accept

        # HTTP и HTTPS
        tcp dport { 80, 443 } accept

        # Логировать и отбросить остальное
        log prefix "NFT_DROP: " counter drop
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
    }

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

Обратите внимание: table inet обрабатывает и IPv4, и IPv6 одновременно. Больше не нужно дублировать правила.

Сравнение синтаксиса

Вот как одни и те же правила выглядят в iptables и nftables:

Задачаiptablesnftables
Открыть порт 80iptables -A INPUT -p tcp --dport 80 -j ACCEPTtcp dport 80 accept
Открыть несколько портовiptables -A INPUT -p tcp -m multiport --dports 80,443,8080 -j ACCEPTtcp dport { 80, 443, 8080 } accept
Блокировать IPiptables -A INPUT -s 10.0.0.1 -j DROPip saddr 10.0.0.1 drop
Блокировать подсетьiptables -A INPUT -s 10.0.0.0/24 -j DROPip saddr 10.0.0.0/24 drop
DNATiptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to 10.0.0.2:80tcp dport 8080 dnat to 10.0.0.2:80
Masqueradeiptables -t nat -A POSTROUTING -o eth0 -j MASQUERADEoifname "eth0" masquerade
Rate limitiptables -A INPUT -p tcp --dport 22 -m limit --limit 3/min -j ACCEPTtcp dport 22 limit rate 3/minute accept

NAT в nftables

Настройка NAT для сервера, выступающего шлюзом:

table inet nat {
    chain prerouting {
        type nat hook prerouting priority -100;

        # Проброс порта 8080 -> внутренний сервер 10.0.0.2:80
        tcp dport 8080 dnat to 10.0.0.2:80

        # Проброс диапазона UDP-портов на один порт
        udp dport 20000-40000 dnat to :443
    }

    chain postrouting {
        type nat hook postrouting priority 100;

        # Masquerade для исходящего трафика через eth0
        oifname "eth0" masquerade
    }
}

Множества (sets) — киллер-фича nftables

В iptables для блокировки 1000 IP-адресов нужно 1000 правил (или ipset как отдельный инструмент). В nftables множества — встроенная функциональность:

table inet filter {
    # Именованное множество IP-адресов
    set blocked_ips {
        type ipv4_addr
        flags interval
        elements = {
            192.168.1.100,
            10.0.0.0/8,
            172.16.0.0/12
        }
    }

    # Множество с автоматическим удалением элементов через таймаут
    set bruteforce {
        type ipv4_addr
        flags dynamic,timeout
        timeout 5m
    }

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

        # Блокировать IP из множества
        ip saddr @blocked_ips drop

        # Защита от брутфорса SSH
        tcp dport 22 ct state new 
            limit rate over 3/minute 
            add @bruteforce { ip saddr } drop

        ip saddr @bruteforce drop

        # ... остальные правила
    }
}

Множество bruteforce динамически пополняется: если с одного IP приходит больше 3 новых SSH-подключений в минуту, адрес автоматически блокируется на 5 минут.

Добавлять и удалять элементы множества можно на лету:

# Добавить IP в множество
sudo nft add element inet filter blocked_ips { 203.0.113.50 }

# Удалить IP из множества
sudo nft delete element inet filter blocked_ips { 203.0.113.50 }

# Посмотреть содержимое множества
sudo nft list set inet filter blocked_ips

Миграция с iptables на nftables

Автоматическая конвертация

В пакете iptables есть утилита iptables-translate, которая переводит правила:

$ iptables-translate -A INPUT -p tcp --dport 22 -m state --state NEW 
    -m recent --update --seconds 60 --hitcount 4 -j DROP
# nft add rule ip filter INPUT tcp dport 22 ct state new 
#    limit rate over 3/minute drop

$ iptables-translate -t nat -A PREROUTING -p udp --dport 20000:40000 
    -j DNAT --to-destination :443
# nft add rule ip nat PREROUTING udp dport 20000-40000 dnat to :443

Для экспорта всего набора правил:

# Экспорт текущих iptables-правил в формате nftables
sudo iptables-save | sudo iptables-restore-translate

# Сохранить в файл
sudo iptables-save | sudo iptables-restore-translate > /etc/nftables-migrated.conf

Ручная миграция

Автоматическая конвертация не всегда работает идеально, особенно с нестандартными модулями. Рекомендуемый подход:

  1. Экспортировать текущие правила: sudo iptables-save > /tmp/iptables-backup.rules
  2. Написать эквивалентный nftables-конфиг
  3. Протестировать на staging-сервере
  4. Применить на продакшне с таймером безопасности

Таймер безопасности — критически важная штука. Если вы случайно заблокируете себе доступ к серверу, правила автоматически откатятся:

# Применить правила и автоматически откатить через 30 секунд,
# если не подтвердить
sudo nft -f /etc/nftables.conf && 
  echo "Правила применены. Подтвердите в течение 30 секунд..." && 
  sleep 30 && 
  sudo nft -f /tmp/nftables-backup.conf

Более элегантный вариант — использовать at:

# Запланировать откат через 5 минут
echo "nft -f /tmp/nftables-backup.conf" | sudo at now + 5 minutes

# Применить новые правила
sudo nft -f /etc/nftables.conf

# Если всё работает — отменить откат
sudo atrm $(atq | tail -1 | awk '{print $1}')

Персистентность правил

Главная боль новичков: правила iptables/nftables не переживают перезагрузку. Вот как это решить.

iptables: iptables-persistent

# Установить пакет
sudo apt install iptables-persistent

# Сохранить текущие правила
sudo netfilter-persistent save

# Правила сохраняются в:
# /etc/iptables/rules.v4
# /etc/iptables/rules.v6

При перезагрузке systemd-сервис netfilter-persistent автоматически загрузит правила.

nftables: встроенный механизм

В nftables персистентность реализована проще. Правила хранятся в /etc/nftables.conf и загружаются systemd-сервисом:

# Сохранить текущие правила в конфиг
sudo nft list ruleset | sudo tee /etc/nftables.conf

# Включить автозагрузку
sudo systemctl enable nftables.service

# Проверить, что сервис активен
sudo systemctl status nftables.service

Структура /etc/nftables.conf:

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;
        # ... ваши правила
    }
}

table inet nat {
    chain prerouting {
        type nat hook prerouting priority -100;
        # ... правила NAT
    }
}

Практический совет: отладка

Когда что-то не работает, а пакеты куда-то пропадают:

# nftables: включить счётчики для всех правил
sudo nft list ruleset -a

# Добавить трассировку для конкретного пакета
sudo nft add rule inet filter input 
    ip saddr 10.0.0.1 tcp dport 80 
    meta nftrace set 1

# Смотреть трассировку
sudo nft monitor trace

# tcpdump — всегда актуален
sudo tcpdump -i eth0 -n port 443
sudo tcpdump -i any -n udp port 20000-40000

Заключение

Если вы настраиваете новый сервер — используйте nftables. Синтаксис чище, множества работают из коробки, один инструмент для IPv4/IPv6, атомарные обновления правил.

Если у вас legacy-инфраструктура на iptables — не спешите мигрировать ради миграции. Но при следующей серьёзной переработке файрвола имеет смысл перейти на nftables. Утилита iptables-translate поможет с конвертацией, а iptables-nft обеспечит обратную совместимость на переходный период.

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

© 2026 Terminal Notes. Built with SvelteKit.