- [Вступление](#вступление) - [Минусы](#минусы) - [Главная боль №1](#главная-боль-1) - [Боль №2](#боль-2) - [Боль №3](#боль-3) - [Боль №4](#боль-4) - [Плюсы](#плюсы) - [Плюс №1, главный](#плюс-1-главный) - [Плюс №2](#плюс-2) - [Плюс №3](#плюс-3) - [Плюс №4](#плюс-4) - [Плюс №5](#плюс-5) - [Выводы](#выводы) # Вступление `nftables` - это технология, пришедшая на замену `iptables`. В ней собрали все, что относилось к различным `iptables`. А их немало. `iptables`, `ip6tables`, `ebtables`, `arptables`, `ipset`. Весь код из разрозненных, но похожих компонент, собрали в одно целое с единым синтаксисом. Добавили различные конструкции языка, позволяющие писать правила более лаконично, не повторяя одни и те же команды с небольшими различиями. На `nftables` можно сделать почти все, что можно было сделать на `iptables`. Есть то, что можно сделать на `nftables`, но нельзя на `iptables`. Есть и наоборот. # Минусы К сожалению, не обошлось и без боли. ## Главная боль №1 Очень серьезная, актуальная для OpenWrt, и решения не видно. ipset-ы позволяли загонять пересекающиеся интервалы IP адресов или подсетей. nftables sets это не позволяют. Любое пересечение вызывает ошибку. Есть auto-merge, но это работает только в user mode в процессе `nft`, при условии, что весь блок адресов загоняется одной командой и нет пересечений с уже имеющимся контентом в set. Это не было бы критической проблемой, поскольку скрипты `zapret` и так загоняют ipset целиком. Проблема в катастрофическом расходе памяти при операции загона больших интервальных листов, то есть с подсетями и диапазонами. Чтобы загнать 100000 IPv4 записей, едва хватает 300 Mb памяти устройства. При успехе операции в ядре список столько не занимает, но суть дела это не меняет. Для традиционных Linux систем это не проблема, но почти все роутеры загнутся. Приемлемого решения не просматривается. Сделать записи непересекающимися в листах - задача непростая. Потребуется переписать алгоритм auto-merge из `nft`, но с пониженным расходом памяти. Загонять записи по одному отдельными вызовами `nft`, игнорируя ошибки, займет вечность. Загонять блоком отдельных команд, игнорируя ошибки, - `nft` такого не умеет. Похоже, при любой ошибке происходит откат всего скрипта. К тому же при таком подходе будут неточности в итоговом результате. Swap позволяет немного сгладить проблему, но лишь незначительно. Скажем, если вдруг list загоняется без ошибок с 300 Mb памяти и с падением на 256 MB, то swap спасает. Если памяти становится 200 MB, то swap уже не спасет. Все равно вызывается OOM killer, заодно убивая и другие процессы, кроме `nft`, а это уже совсем плохо. Может быть убито что-то важное. ## Боль №2 Не смертельная, но тоже не айс. Какие-то нерациональные алгоритмы разбора таблиц в `nft`. Например, есть 1 большой set на 100000 элементов и 1 маленький на 2 элемента. Чтобы просто пролистать мелкий set или добавить туда еще что-то `nft` будет мусолить несколько секунд. Что он делает за это время? Тащит из ядра огромный блоб, в котором все в куче, и разбирает его, чтобы выделить искомую мелочь? В какой-то мере удается это сгладить, объединяя несколько команд в единый скрипт. ## Боль №3 Система `nftables` построена на виртуальной машине. Правила, которые вы пишите, переводятся в псевдокод VM. Чтобы потом их показать, `nft` декомпилирует код и переводит в читаемый язык. Это довольно сложно, и регулярно случаются баги, связанные с неверным отображением. Кроме этого, часто встречаются и баги парсера. Например, все версии `nft` вплоть до 1.0.1 имеют баг, который не разрешает названия интерфейсов в кавычках в определении flowtable. Без кавычек нельзя вставить интерфейсы, имя которых начинается с цифры. OpenWrt решает эту проблему отдельным патчем в snapshot версии, но на традиционных системах и в OpenWrt 21.x- его нет. Почему бы не наплевать на интерфейсы, начинающиеся с цифры? Потому что для OpenWrt 6to4-6to4, 6in4-he-net - обычное явление. На текущий момент этой проблемы в OpenWrt уже нет, если использовать актуальную версию. Но тем не менее, хоть `nft` и давно перешел отметку 1.0, всякая мелочь, особенно на не совсем стандартных правилах, регулярно всплывает. Потому чем новее у вас будет версия `nft`, тем больше там выловлено проблем. Здесь обновления важны, чтобы потом не мучиться из-за давно исправленного велосипеда. ## Боль №4 Невозможно, не копаясь в других таблицах и хуках, ничего не зная об их содержании, предотвратить DROP или REJECT. Нельзя написать такое правило, которое что-то важное ACCEPT нет, игнорируя остальные хуки во всех таблицах. Если у вас есть какой-то фаервол, и он что-то дропает, то как от этого отказаться, если надо временно что-то принять? Это особенность `netfilter`, он так работает, но в `iptables` есть лишь стандартные таблицы с их хуками, куда можно вставить ACCEPT. Здесь хуков может быть сколько угодно в каких угодно таблицах. Эта проблема частично ломает кайф от независимого управления таблицами. # Плюсы ## Плюс №1, главный `iptables` хороши, когда ими пользуется кто-то один. Иначе это проходной двор. Когда есть система управления фаерволом, то приходится как-то к ней прикручиваться, чтобы не нарушить ее работу и управлять правилами синхронно. Нужно уметь внести и удалить отдельные правила когда это нужно, не трогая все остальное. Некоторые системы управления фаерволом вообще не предполагают, чтобы кто-то еще лез в `iptables`, и это очень сильно портит жизнь. У `iptables` есть предопределенный набор хуков `netfilter` с фиксированным приоритетом. В `nftables` хуков можно создать неограниченное количество с выбранным приоритетом, управляя ими независимо в отдельных таблицах. Система управления фаерволом может работать в одной таблице (`fw4` в случае OpenWrt) и не трогать все остальное. `zapret` может работать в другой таблице и не трогать систему управления фаерволом. Они друг другу не мешают. Это снимает множество боли. Но есть и исключение. `nfset`-ы - аналог `ipset`-ов - нельзя использовать из другой таблицы. Потому если вам нужен `ipset`, создаваемый `zapret` скриптами, вам понадобится писать правила в той же таблице. Но нет никакой необходимости влезать в цепочки `zapret`. Создаете свои цепочки и хуки и делаете в них что угодно. ## Плюс №2 Возможность выбора приоритета хука позволяет легко решить проблему хаотической и принудительной дефрагментацией L3 IPv6, без танцев с загрузкой модулей ядра со специальными параметрами или перекомпиляцией `nftables-nft`. Это же позволяет перехватить трафик после SNAT/MASQUERADE, что на `iptables` невозможно. Атаки на проходящий трафик, ломающие NAT, крайне затруднены на `iptables`. ## Плюс №3 Наличие множеств (anonymous/named sets) позволяет не писать кучу однообразных правил там, где в `iptables` их пришлось бы написать. ## Плюс №4 Если у вас есть `nftables`, то там наверняка есть уже все или почти все. Нет кучи разных модулей ядра и .so плагинов для `iptables` user-mode процесса. Отдельные модули ядра есть, но их меньше, чем в `iptables`, и OpenWrt их делит на меньшее число пакетов, большинство из которых и так ставятся по умолчанию. user-mode процесс `nft` и вовсе неделим. EXE-шник + lib. ## Плюс №5 Пишут, что `nftables` работают быстрее. Но это не точно и зависит от много чего. В целом - чем меньше правил, тем выше скорость. Но в `nftables` правил можно писать меньше, значит скорость тоже может быть выше. У разработчиков есть идея перевести backend `nftables` на BPF, а это наверняка будет существенно быстрее. # Выводы Без больших листов все почти прекрасно. Но большие ip листы убивают все. Не для домашних это роутеров. А ipset-ы к `nftables` не прикрутить. Зато есть возможность задействовать более продвинутые атаки, конфликтующие с NAT, которые на `iptables` могут быть невозможны. Делать нечего. Openwrt отошел от `iptables`. С этим придется как-то жить. Поэтому пришлось сделать для OpenWrt поддержку и `iptables`, и `nftables` (только с версии OpenWrt 21.xx, в более старых будут проблемы). `iptables` можно задействовать на любой OpenWrt версии. Если используется `fw3`, применяется старый механизм интеграции в `fw3`. Если он не используется, то правилами `iptables` управляем как в традиционных Linux системах - то есть с возможностью запуска и остановки, а скрипт запуска вносит в том числе и правила `iptables`. На новых OpenWrt возможно снести `nftables` и `firewall4` и установить `firewall3` и `iptables`. Если вам никак без больших IP листов на слабой системе, это может быть единственным спасением.