Одно правило может удержать допущенный пул VPN в стороне от диапазона назначения, не мешая ничему другому, что делает шлюз. Само правило короткое; решают, будет ли оно работать, хук, в котором оно живёт, и его позиция в цепочке. Ошибка в этих двух вещах даёт межсетевой экран, который выглядит правильно и ведёт себя непоследовательно. Начните с того, что делает пакет, когда правило его видит.

Что правило на самом деле сопоставляет

Правило сопоставляет три вещи сразу: входной интерфейс, префикс источника и префикс назначения. Все три должны быть истинны, прежде чем применится drop, и именно это делает его узким. Читать его как одно выражение проще, чем как три отдельные политики.

Сопоставление интерфейса отличает перенаправленный клиентский трафик от собственных соединений шлюза. Без него правило, называющее только пул источника, затронуло бы и пакеты, которые шлюз сам создаёт с этого адреса, если такое когда-либо происходит. Префикс источника ограничивает политику допущенными клиентами, а префикс назначения — одним диапазоном. Читайте правило как пересечение, а не как список.

Запишите три значения, прежде чем что-либо менять: имя туннельного интерфейса, пул, который выдаёт сервер, и префикс, который вы собираетесь отклонить. Опечатка в любом из них даёт правило, которое чисто разбирается и ничего не защищает. Держите эти три значения в записи об изменении рядом с правилом.

Хук решает, на кого распространяется правило

Цепочка netfilter прикреплена к хуку, и именно хук решает, какие пакеты цепочка вообще видит. Хук forward видит трафик, маршрутизируемый через шлюз, а это и есть трафик от клиента к назначению. Всё остальное в цепочке нацелено на другую аудиторию.

Хук input видит трафик, адресованный самому шлюзу, поэтому правило, размещённое там, управляет доступом к его собственным службам, а не транзитом. Хук output видит трафик, который шлюз порождает сам, и это противоположность тому, что нужно политике пула клиентов. Имена цепочек — произвольные метки, выбранные тем, кто писал набор правил, поэтому не выводите хук из имени. Проверьте, куда прикреплена цепочка, прежде чем предполагать, что она может сопоставить.

HookTraffic it seesRight for this policy
inputAddressed to the gatewayNo, that is the host's own services
forwardRouted through the gatewayYes, for client-to-destination traffic
outputGenerated by the gatewayNo, that is the opposite direction

Чтение прикрепления — проверка в одну строку, которая не даёт правилу попасть в цепочку, никогда не видящую пакет.

Разместите правило перед широким accept

Правила оцениваются по порядку, и первый вердикт побеждает. Широкий accept выше в цепочке завершает оценку для пакетов, которые он сопоставляет, поэтому drop, добавленный позже, для них никогда не выполняется. Это правило порядка — вся причина, по которой правильно выглядящее правило может не давать эффекта.

Вставьте правило перед accept, а не добавляйте его в конец. Если цепочка уже содержит общий accept для туннельного интерфейса, новое правило должно стоять перед ним, иначе оно лишь украшение. Проверяйте получившийся порядок, а не файл, который вы правили, потому что набор правил, собранный из нескольких файлов, может не соответствовать ни одному из них. Затем подтвердите тестовым пакетом из пула.

sudo nft list chain inet filter forward
sudo nft insert rule inet filter forward iifname "tun0" ip saddr 10.90.0.0/24 ip daddr 198.51.100.0/24 drop
sudo nft -c -f /etc/nftables.conf

Третья команда разбирает файл, не применяя его, и ловит синтаксические ошибки до того, как они станут сбоем. Применяйте с планом отката, потому что ошибочное правило в цепочке forward может перерезать туннель, через который вы работаете.

Существующие потоки не обращают внимания на ваше новое правило

Запись conntrack, созданная до появления правила, продолжает соответствовать прежнему accept. Поэтому новый drop иногда выглядит работающим для новых соединений и ничего не делает для того, которое проверяют.

Прочитайте сопоставление состояния в начале цепочки. Если оно принимает трафик established и related до вашего правила, каждый уже идущий поток продолжает течь, пока не закроется. Обычно именно это и нужно для аварийного правила, и это сбивает с толку, когда вы ждёте немедленного обрыва. Решите, какой эффект вам нужен, прежде чем разворачивать. Тест, который повторно использует открытое соединение, расскажет вам неверную историю.

sudo conntrack -L -s 10.90.0.14 -d 198.51.100.20
sudo nft list ruleset | grep -n -A3 'ct state'

Первая команда показывает, существует ли поток, а вторая — продолжает ли раннее правило состояния его принимать. Обе только для чтения и безопасны во время инцидента.

Чем это правило не является

Правило не является чёрным списком доменов, политикой IPv6 или ограничением для отдельной учётной записи приложения.

Каждому из этого нужен свой механизм. Блокировка домена должна разрешать имена, чего фильтр пакетов не делает. Трафику IPv6 нужно собственное сопоставление, потому что выражение ip ничего не говорит о пакетах ip6. Ограничение на уровне приложения относится к службе или аутентифицированному прокси, а не к сопоставлению префикса. Именно разделение этих требований не даёт взвалить четыре задачи на одно узкое правило.

Контракт, который даёт это правило, точен: трафик из допущенного пула к одному префиксу назначения отклоняется, а несвязанный трафик шлюза сохраняет свою текущую политику. Запишите это предложение рядом с правилом, и следующий человек узнает, для чего оно было.

Похожие статьи