OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

nftables: динамические sets для блоклистов и быструю фильтрацию

Динамические sets в nftables позволяют держать сотни тысяч IP и CIDR и фильтровать трафик без длинных цепочек правил. Разбираем блоклисты, таймауты, vmap, временные баны из правил, атомарные обновления и безопасное внедрение на боевых серверах.
nftables: динамические sets для блоклистов и быструю фильтрацию

Если вы всё ещё поддерживаете длинные цепочки iptables или ipset ради блоклистов, самое время мигрировать на nftables. Наборы (sets) и карты (maps) в nftables дают быстрые поиски по IP/CIDR, удобные таймауты для временных банов, динамическое наполнение прямо из правил и атомарные обновления без «дребезга» и окон уязвимости. Ниже — практическая схема, проверенные паттерны и тонкости производительности для админов, которые хотят держать чёткий и быстрый firewall на проде.

Зачем sets в nftables и чем это лучше iptables/ipset

Главная боль классического подхода — большие списки адресов размножают правила и замедляют обработку. Nftables хранит элементы в наборах, а правило всего одно: обращаться к набору по ключу. Для десятков и сотен тысяч IP/CIDR это критично — lookup идёт в оптимизированных структурах (hash/rbtree), без линейного прохода цепочки.

В отличие от ipset, сеты и карты — это «первоклассные граждане» в синтаксисе nftables: вы объявляете их в таблице, используете в правилах, обновляете атомарно и можете добавлять элементы «на лету» из самих правил (dynset). Плюс поддержка timeout на элемент, объединение CIDR при флаге interval, конкатенированные ключи (например, IP+порт) и карты vmap до вердикта без цепочек.

Базовый каркас: таблица, цепочка, два блоклиста

Обычно удобно собирать всё в семейственном inet, чтобы одинаково ловить IPv4 и IPv6. Минимальная «скелетная» конфигурация:

table inet filter {
  sets {
    blacklist4 {
      type ipv4_addr
      flags interval
      timeout 1h
    }
    blacklist6 {
      type ipv6_addr
      flags interval
      timeout 1h
    }
  }

  chain input {
    type filter hook input priority 0;

    # Разрешения и allowlist — выше по цепочке
    # ...

    ip saddr @blacklist4 drop
    ip6 saddr @blacklist6 drop

    # Остальная политика
    # ...
  }
}

Здесь блоклисты поддерживают CIDR (флаг interval) и «горят» по таймауту, если элемент был добавлен как временный. Если вы импортируете статический список без сроков, можно не задавать timeout в определении набора, а указывать его только у конкретных элементов, где это нужно.

Для сценариев с несколькими исходящими IP при NAT посмотрите материал: управление SNAT с несколькими IP в nftables.

Пример конфигурации nftables с наборами для IPv4 и IPv6

Тип набора и флаги: что выбрать для задач

  • type ipv4_addr/ipv6_addr — адресный блоклист по IP.
  • flags interval — для списков с подсетями: ядро объединяет смежные интервалы и экономит память и операции.
  • timeout — дефолтный срок жизни элементов. Можно переопределять на уровне добавляемого элемента.
  • Конкатенация ключей: type ipv4_addr . inet_service или type ipv4_addr . ipv4_addr — удобно для правил «IP+порт», «источник+назначение» и т.п.

Операции с наборами: добавить, убрать, посмотреть

# Добавить сетевой префикс и одиночный IP
nft add element inet filter blacklist4 { 192.0.2.0/24, 203.0.113.5 }

# Временный бан на 2 часа с комментарием
nft add element inet filter blacklist4 { 198.51.100.10 timeout 2h comment "abuse" }

# Удалить элементы
nft delete element inet filter blacklist4 { 203.0.113.5, 192.0.2.0/24 }

# Просмотр содержимого
nft list set inet filter blacklist4

# Проверить наличие конкретного адреса
nft get element inet filter blacklist4 { 198.51.100.10 }

Все эти операции атомарны на уровне netlink: вы не «поймаете» момент, когда набор наполовину обновлён. Это особенно важно для больших импортов.

Динамические баны из правил (dynset)

Nftables позволяет добавлять элементы в набор прямо из правила при совпадении условия. Это удобно для примитивной самозащиты: слишком частые соединения, невалидные флаги TCP, подозрительные пробы портов. Пример временного бана для грубой силы на SSH по скорости новых соединений:

table inet filter {
  sets {
    ssh_abusers {
      type ipv4_addr
      timeout 1h
    }
  }

  chain input {
    type filter hook input priority 0;

    # Сначала проверяем бан
    ip saddr @ssh_abusers drop

    # Если слишком часто стучатся в 22/tcp — добавить в бан на 1 час
    tcp dport 22 ct state new limit rate over 20/minute add @ssh_abusers { ip saddr timeout 1h } drop

    # ... остальной трафик
  }
}

Не превращайте dynset в IDS: держите условия простыми, задавайте явный таймаут и обязательно проверяйте allowlist раньше автобанов.

vmap: карты до вердикта для «плоских» блоклистов

Если список большой и его задача — однозначно дать вердикт, используйте карту до вердикта. Правило будет короче, а ядро придёт к решению без дополнительных сравнений:

table inet filter {
  sets {
    blackmap4 {
      type ipv4_addr : verdict
      elements = { 203.0.113.5 : drop, 192.0.2.0/24 : drop }
    }
  }

  chain input {
    type filter hook input priority 0;
    ip saddr vmap @blackmap4
  }
}

Карта вернёт drop для совпадающих источников и «ничего» — для остальных, т.е. управление пойдёт дальше по цепочке. Удобно для плоских чёрных/белых списков портов, IP и префиксов.

Импорт больших блоклистов: атомарно и без простоев

Главные правила большого импорта: делать его атомарно и не разрушать рабочий набор до готовности нового. Базовый рецепт:

  1. Создайте новый временный набор с теми же параметрами (blacklist4_new).
  2. Залейте элементы в blacklist4_new пачками.
  3. Поменяйте местами наборы (swap set), чтобы правила увидели новый контент мгновенно.
  4. Удалите старый набор.
# Шаг 1: завести временный набор
nft add set inet filter blacklist4_new { type ipv4_addr; flags interval; }

# Шаг 2: загрузить элементы (примерно)
nft add element inet filter blacklist4_new { 192.0.2.0/24, 203.0.113.0/24, 203.0.113.5 }

# Шаг 3: атомарная ротация
nft swap set inet filter blacklist4 blacklist4_new

# Шаг 4: подчистить
nft delete set inet filter blacklist4_new

Скрипт импорта должен удалить дубликаты и валидировать синтаксис адресов до попадания в nft. Для CIDR включайте флаг interval — ядро само оптимизирует пересечения.

Атомарная ротация наборов в nftables при импорте блоклистов

Структурирование: allowlist над блоклистом

На боевых серверах держите набор допустимых источников отдельно и проверяйте его раньше всех блокировок. Это спасёт вас от случайной самоблокировки при широких масках и даст понятный механизм исключений.

sets {
  allowlist4 { type ipv4_addr; flags interval; }
}

chain input {
  ip saddr @allowlist4 accept
  ip saddr @blacklist4 drop
  # ...
}

Производительность: hash против interval, IPv4/IPv6, размер

В общих чертах: одиночные адреса «без интервалов» оптимально ложатся в хеш; когда вы включаете flags interval и работаете с CIDR/диапазонами, ядро применяет дерево интервалов. На ядрах LTS (5.10+) сотни тысяч элементов обрабатываются предсказуемо и быстро, а разница в латентности lookup — единицы микросекунд по сравнению с «пустым» firewall, на типичных VDS/серверных конфигурациях это не заметно. Куда легче «подстрелить» производительность — сложной логикой в цепочках до проверки набора. Сначала наборы, потом всё остальное.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Конкатенированные ключи: IP + порт и не только

Когда задача — не просто забанить IP, а заблокировать конкретный сервис/порт от некоторых источников, используйте конкатенацию типов ключа:

set bad_http {
  type ipv4_addr . inet_service
}

chain input {
  tcp dport 80 ip saddr . tcp dport @bad_http drop
}

Так вы получите точечный контроль без дублирования логики и без длинных списков «если порт — то бан» в правилах.

Мониторинг и отладка

  • nft list ruleset — общий дамп правил и наборов.
  • nft -a list ruleset — то же с хэндлами для точечного редактирования.
  • nft list set inet filter blacklist4 — содержимое набора.
  • nft monitor — поток изменений в живую, удобно видеть, как dynset пополняется.

Если сомневаетесь — применяйте файлы с --check, проверяя синтаксис без внесения изменений: сначала проверка, затем применение. Это дешёвая страховка от опечаток.

Бэкап и персистентность

Держите базовую структуру в основном конфиге (/etc/nftables.conf), а большие наборы подключайте отдельными файлами с include. Обновление выполняйте атомарно: сначала положили новый файл, затем применили его одной командой. Это снизит риск инцидента при деплое и упростит откат.

Миграция с ipset: что нужно знать

IpSet исторически решал ту же задачу, но в связке с iptables. При миграции важно переосмыслить структуру: не переносите один-в-один, а используйте преимущества nftables — семейство inet, interval для CIDR, карты vmap, конкатенированные ключи. Скрипт миграции обычно:

  1. Экспортирует текущие списки ipset.
  2. Нормализует и чистит элементы (дубликаты, невалидные строки).
  3. Формирует nft-совместимый набор elements = { ... }.
  4. Заливает во временный набор и делает swap.

Выгода видна сразу: меньше правил, предсказуемая латентность и единый стек управления.

Паттерн безопасного деплоя на проде

  • Первым правилом в input — allowlist для вашего управления.
  • Правила, использующие наборы, поднимайте выше тяжёлых матчей.
  • Все большие изменения — только атомарно через временные наборы и swap.
  • Тестируйте конфигурацию на стенде, прогоняйте --check перед -f.
  • Заводите оповещение при срабатывании «автобанов» (dynset), чтобы видеть динамику и не закрыть важный трафик по ошибке.

Частые ловушки и как их избежать

  • Случайно забанили себя по широкому CIDR. Всегда держите allowlist выше и делайте dry-run импорта.
  • Дубли и «пыль» в списках. Нормализуйте источники, используйте interval и предварительную агрегацию префиксов.
  • Слишком «умные» правила до проверки набора. Переместите обращение к набору выше — это дешевле и надёжнее.
  • Разовая массовая очистка через flush set. На проде лучше «swap» с чистым набором, чтобы не ловить окно между очисткой и догрузкой.

Пример: единый каркас с allowlist, blacklist и dynset

table inet filter {
  sets {
    allow4 { type ipv4_addr; flags interval; }
    allow6 { type ipv6_addr; flags interval; }
    blacklist4 { type ipv4_addr; flags interval; }
    blacklist6 { type ipv6_addr; flags interval; }
    ssh_abusers { type ipv4_addr; timeout 2h; }
  }

  chain input {
    type filter hook input priority 0;

    # Управление всегда пропускаем
    ip saddr @allow4 accept
    ip6 saddr @allow6 accept

    # Блоклисты
    ip saddr @blacklist4 drop
    ip6 saddr @blacklist6 drop

    # Динамическая защита SSH
    ip saddr @ssh_abusers drop
    tcp dport 22 ct state new limit rate over 30/minute add @ssh_abusers { ip saddr timeout 2h } drop

    # Базовая политика (пример)
    ct state established,related accept
    tcp dport { 80, 443 } accept
    iif lo accept
    icmp type { echo-request, echo-reply, time-exceeded } accept
    ip6 nexthdr icmpv6 accept

    # Остальное — по вашей политике
    # drop или reject
  }
}

Сеты и карты в nftables — это современный, быстрый и удобный способ работать с блоклистами. Они позволяют держать огромные списки адресов, добавлять временные баны непосредственно из правил, обновлять их атомарно и при этом сохранять конфигурацию лаконичной. Ключ к успеху — простая структура, ранняя проверка наборов в цепочках, аккуратный импорт и безопасный процесс обновления. С таким подходом фильтрация останется быстрой и предсказуемой даже под высокой нагрузкой.

Поделиться статьей

Вам будет интересно

DMARC: rua, p=quarantine и p=reject — как включить без потери доставляемости OpenAI Статья написана AI (GPT 5)

DMARC: rua, p=quarantine и p=reject — как включить без потери доставляемости

Пошаговое руководство для админов: что такое DMARC и агрегированные отчёты rua, как правильно оформить rua=mailto, собрать XML-отч ...
Floating IP для Nginx: keepalived VRRP, healthcheck и быстрый failover OpenAI Статья написана AI (GPT 5)

Floating IP для Nginx: keepalived VRRP, healthcheck и быстрый failover

Пошагово строим отказоустойчивый фронтенд на двух серверах Nginx с общим floating IP. Настраиваем keepalived (VRRP), HTTP health c ...
SYNPROXY в nftables: защита VDS от TCP SYN flood пошагово OpenAI Статья написана AI (GPT 5)

SYNPROXY в nftables: защита VDS от TCP SYN flood пошагово

SYN flood забивает TCP-очереди и conntrack на VDS, съедая CPU. SYNPROXY в nftables отсекает мусор до TCP-стека. Разбираем принцип, ...