Прошлый выпуск закрыл NAT — masquerade и port forwarding. Сегодня — два механизма nftables, которые обычно всплывают, когда базовый набор правил начинает разрастаться: limit rate для троттлинга и sets для проверки сразу против списка адресов.

limit ограничивает частоту совпадений — пакетов или байт в единицу времени, с опциональным всплеском (burst) сверх базовой ставки:

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

    # не больше 10 ICMP echo-request в секунду, с запасом в 2 пакета на всплеск
    icmp type echo-request limit rate 10/second burst 2 packets accept

    # соединения на 22 порт — не чаще 15 в минуту
    tcp dport 22 limit rate 15/minute accept
  }
}

Удобно переиспользовать лимит под несколько правил — для этого его объявляют отдельно как именованный limit, а не инлайном в каждом правиле:

limit lim_icmp { rate 400/minute; }

и дальше ссылаются на него через limit name "lim_icmp". Для разового inline-правила это не нужно, но если один и тот же лимит должен считаться общим для нескольких chain — без именованного limit не обойтись, инлайн-версии в разных правилах независимы друг от друга.

Второй механизм — sets. Пять правил ip saddr 1.2.3.4 drop, ip saddr 5.6.7.8 drop и так далее nftables обрабатывает последовательно, одно за другим; то же самое через set — одно сравнение с хеш-таблицей внутри ядра, независимо от того, пять там адресов или пять тысяч:

table inet filter {
  set blackhole {
    type ipv4_addr
    elements = { 192.168.1.4, 192.168.1.5 }
  }

  chain input {
    type filter hook input priority 0; policy accept;
    ip saddr @blackhole drop
  }
}

Добавить адрес в уже работающий набор — без перезагрузки всего рулсета:

nft add element inet filter blackhole { 10.0.0.9 }

Отдельный приём — typeof вместо явного type, набор наследует тип прямо из выражения, которое будет с ним сравниваться:

set myset {
  typeof ip daddr . tcp dport
  elements = { 1.1.1.4 . 22, 1.1.1.5 . 23 }
}

Это уже concatenation — набор из пары “адрес + порт” в одном элементе, проверка ip daddr . tcp dport @myset match’ит обе части сразу, без вложенных правил на каждую комбинацию.

#nftables