Изменение правила файрвола не работает: порядок правил и состояние соединения
Изменённое правило может оказаться за более ранним разрешением или быть пропущено отслеживанием соединений. Разделите два теста, используйте новый поток и оставьте путь назад.
Вы изменили правило, перезагрузили набор правил, а туннель ведёт себя точно так же, как раньше. У такого результата две частые причины, и им нужны разные тесты. Либо новое правило стоит после более раннего правила, которое уже приняло пакет, либо наблюдаемый обмен — это отслеживаемое соединение, которое изменение никогда не переоценивает. Правило в файле выражает намерение; судьбу пакета решает активный путь, на который он наталкивается. Пройдите проверки ниже по порядку и при этом держите открытым путь назад.
Порядок правил и состояние соединения — разные неисправности
Упорядоченные цепочки оцениваются сверху вниз, и первое правило, которое достигает окончательного вердикта, завершает проход по этой цепочке. Поставьте широкое разрешение выше аккуратно написанного правила блокировки, и правило блокировки станет документацией: оно есть в наборе, его счётчик равен нулю, и ни один пакет никогда до него не дойдёт. Тот же текст, применённый к другой цепочке, тоже ничего не доказывает. В nftables базовые цепочки привязываются к хукам по приоритетам, поэтому разрешение в одной цепочке не мешает другой цепочке на другом хуке или приоритете видеть тот же пакет.
Отслеживание соединений создаёт второй симптом, и снаружи он выглядит одинаково. Как только поток попадает в таблицу состояний, разрешение для established-or-related у вершины цепочки возвращается ещё до того, как ваше новое правило будет рассмотрено. У NAT-отображений то же свойство: трансляция зафиксировалась при старте потока, поэтому изменённое правило postrouting не переписывает уже идущую сессию. Именно поэтому изменение как будто работает в 09:00 для нового соединения и как будто ничего не делает для сессии, которую кто-то открыл в 08:55.
Облачные группы безопасности добавляют третью модель, которая ловит тех, кто учился на iptables. Их входящие правила — это список разрешений, оцениваемый как множество, а не как проход по первому совпадению, они хранят состояние, и удаление правила разрешения не прекращает уже отслеживаемые потоки. Предположение о семантике первого совпадения на платформе, где её нет, ведёт к уверенным, но неверным выводам.
Читайте активный набор правил, а не файл, который вы правили
Начните с того, что ядро применяет прямо сейчас. Сохранённая конфигурация, которая никогда не применялась, объясняет удивительно много неизменного поведения, и исключить её стоит одной команды:
nft list ruleset
iptables-saveЗатем спросите, достигается ли ваше правило вообще. Счётчики пакетов отвечают на это напрямую и отвечают лучше любых рассуждений о намерении:
iptables -L FORWARD -v -n --line-numbers
nft list chain inet filter forwardПравило блокировки с нулём пакетов после реальной попытки теста — это не проблема политики, а проблема позиции. Переместить его — изменение в одну строку, и синтаксис — именно то, что вызвало исходную ошибку. В iptables -I вставляет, а -A добавляет в конец; в nftables insert ставит правило в начало цепочки, а add добавляет в конец. Когда правило должно победить, скажите это явно, вместо того чтобы доверять порядку, который случайно загрузился.
Докажите, отслеживается ли поток
Прежде чем винить правило, проверьте, является ли трафик вообще отслеживаемым соединением. Спросите таблицу состояний о конкретном потоке, вместо того чтобы вываливать её целиком:
conntrack -L -p tcp --dport 1194
conntrack -E -p tcp --dport 1194Список показывает состояние и оставшийся срок, и именно так вы отличаете установленную сессию от свежей попытки; режим событий печатает обновления по мере их появления, что полезно, пока вы переподключаете клиента. Если поток присутствует в установленном состоянии ещё до того, как вы что-то тронули, никакая правка правил фильтрации не изменит его судьбу. Это не ошибка файрвола, это контракт фильтрации с состоянием.
Сопротивляйтесь соблазну очистить всю таблицу на производственном шлюзе. conntrack -F доступен, и он также уничтожает каждый отслеживаемый поток на машине, включая сессию управления, из которой вы работаете, и туннель, который несёт вашу оболочку. Отдельные записи можно удалять, когда это действительно нужно, но новый поток с нового исходного порта обычно даёт более чистый эксперимент.
Некоторые пути не отслеживаются, и они ведут себя наоборот. Трафик, помеченный notrack в таблице raw, некоторые туннели, обходящие обычные хуки, и асимметричная маршрутизация, разделяющая поток между двумя шлюзами, — все они дают пакеты, оцениваемые по одному, или состояние, которое никогда не создаётся на обоих концах. Если счётчики двигаются на каждом пакете, подозревайте такой путь раньше, чем порядок.
Тестируйте из нового потока с путём назад
Прежде чем тестировать правило, которое может отрезать удалённый доступ, создайте путь восстановления: консоль провайдера, последовательную консоль, адрес управления вне полосы или второй интерфейс, который правило не сможет затронуть. Таймер отката — разумный спутник, потому что он восстановит предыдущий набор правил, даже если ваша сессия умрёт посреди теста.
Затем тестируйте обменом, который не мог быть уже покрыт состоянием. Отключите и снова подключите клиента, чтобы создалась новая пятёрка, и наблюдайте за обоими концами, пока это происходит:
tcpdump -ni eth0 'tcp port 1194'
journalctl -k -n 50 --no-pagerПроведите тест в обоих направлениях. Правило, блокирующее новое входящее рукопожатие, всё ещё может пропускать путь ответа, или наоборот, и односторонний результат — обычная причина того, что блокировка работает наполовину. Переподключитесь ещё раз после теста, чтобы подтвердить устойчивое состояние, и проверьте, что законный доступ управления уцелел; правило, написанное под один порт, имеет привычку совпадать с более широким диапазоном, чем задумано.
Записывайте цель и позицию вместе с правилом
Правило без записанной цели — это правило, которое никто не решается удалить. Рядом с каждой записью блокировки храните поток, который она защищает, цепочку и хук, в которых она живёт, позицию, которую она должна занимать относительно более широких разрешений, и тест, который это доказал. Когда через полгода кто-то изменит окружающий набор правил, эта заметка будет единственным предупреждением, что позиция была намеренной.
Прежде чем закрыть изменение, подтвердите четыре вещи: работающий набор правил соответствует файлу, у нового правила после свежей попытки ненулевые счётчики, обратное направление и доступ управления по-прежнему работают, и вы один раз переподключились, чтобы доказать устойчивое состояние, а не состояние сессии, которая старше изменения. Если хоть что-то из этого не проверено, изменение не завершено, что бы ни делал туннель.