Маршрут VPN или правило брандмауэра: что отбрасывает пакет?
Маршрут выбирает путь, а фильтр решает, разрешено ли. Проверьте оба для одного и того же источника, назначения и направления, прежде чем расширять правило брандмауэра.
С одним и тем же пакетом происходят два независимых решения, и любое из них может тихо завершить запрос. Поиск маршрута выбирает интерфейс и следующий хоп, затем фильтр пакетов решает, разрешена ли эта комбинация. Тайм-аут сообщает вам, что отказал один из двух, а не какой. Пройдите этапы по порядку, и исправление обычно перестаёт быть догадкой.
Два решения, один пакет, два владельца
Поиск маршрута сначала обращается к правилам политики, затем к таблице, на которую они указывают, и выбирает самый конкретный префикс, совпадающий с назначением. Клиент, установивший маршрут туннеля, владеет этим решением, и ничто в правиле брандмауэра не может его заменить. Когда поиск указывает на неожиданное место, каждый следующий этап работает с неправильным пакетом.
Фильтрация отдельна. На хосте Linux хуки netfilter разделяют трафик по тому, для кого пакет: выход покидает машину, вход завершается на ней, форвард проходит через неё. Шлюзу, который принимает клиентов VPN и направляет их в LAN, нужен путь форварда, и это ровно та цепочка, которую большинство конфигураций по умолчанию оставляют пустой.
Выбор источника относится к тому же решению, и именно здесь прячется большинство несоответствий. Ядро выбирает адрес источника с исходящего интерфейса, если маршрут не указывает его, поэтому правило фильтра, написанное для подсети LAN, никогда не совпадает с пакетом, уходящим с адресом туннеля.
Прочитайте, что поиск выбрал на самом деле
Напечатайте решение, а не выводите его. Команда ниже разрешает маршрут, который ядро использовало бы для этого назначения, включая интерфейс и источник, который оно выбрало бы:
ip route get 10.8.0.5 ip route get 10.8.0.5 from 192.0.2.44 ip rule show ip route show table all | sed -n '1,40p'
Клиенты VPN часто устанавливают правила политики с приоритетами ниже основной таблицы, поэтому чистая основная таблица сама по себе ничего не доказывает. Сравните приоритеты правил с таблицами, которые они выбирают, и проверьте, переживает ли маршрут туннеля переподключение, а не добавляется ли вручную один раз.
IPsec на основе политики добавляет третий этап сопоставления, который маршрутизация не покрывает, как описывают заметки strongSwan о форвардинге для туннельных и транспортных конфигураций. Политика безопасности выбирает трафик по префиксу и протоколу, а маршрут лишь решает, куда уйдёт незащищённый пакет. Подсеть, которая маршрутизируется, но не имеет подходящего селектора, либо остаётся незащищённой, либо отбрасывается, в зависимости от конфигурации, и ни один из результатов не выглядит как проблема брандмауэра. Напечатайте политику и сравните её селекторы с префиксами, которые вы ожидали от туннеля.
Фильтрация применяется на хуке, а не на маршруте
Правило, разрешающее слушатель VPN, — это правило о трафике, адресованном самому шлюзу. Оно ничего не говорит о клиентах, достигающих хостов за этим шлюзом, потому что форвардируемый трафик проходит через другую цепочку. Чтение набора правил как одного плоского списка — обычная причина того, что выглядящее правильным правило никогда не срабатывает.
Счётчики быстро решают вопрос. Правило с нулевым счётчиком пакетов никогда не было достигнуто, что указывает на неверную цепочку, неверный интерфейс или более ранний сброс. Правило с растущим счётчиком при политике сброса — это та граница, которую вы искали, и пакет отбрасывается, а не маршрутизируется неверно.
Отправьте зонд по пути, который использует клиент
Тесты, выполняемые на самом шлюзе, проходят через выход и вход с собственным адресом источника шлюза. Это другой путь, чем форвардируемый запрос клиента, поэтому успешный локальный curl доказывает меньше, чем кажется. Проверяйте с машины, которая терпит неудачу, или явно закрепите интерфейс и источник.
nc -vz -w 3 10.8.0.5 443 ping -c 3 -W 1 10.8.0.5 tcpdump -ni any host 10.8.0.5 and port 443 iptables -vnL FORWARD --line-numbers nft list ruleset | sed -n '1,60p'
Захват на обоих концах разделяет оставшиеся случаи. SYN, который покидает клиента и никогда не приходит, означает маршрутизацию, шифрование или список доступа выше по потоку. SYN, который приходит и не получает ответа, означает службу или её фильтр хоста, и туннель никогда не был проблемой.
Обратный трафик заслуживает отдельного взгляда. Асимметричная маршрутизация плюс фильтрация обратного пути отбрасывают ответы, приходящие на неверный интерфейс, что проявляется как одностороннее соединение, а не как заблокированный порт. Проверьте значение sysctl, прежде чем винить брандмауэр в симптоме, который он не вызывал.
Логирование работает как второе мнение, а не первый шаг. Временный оператор журнала на цепочке форварда называет интерфейс и адреса, которые его задели, и его легко убрать потом. Оставьте его навсегда, и вы построили проблему объёма журналов вместо ответа.
Поместите каждое изменение туда, где оно переживёт переподключение
Маршрут, добавленный через ip route add, живёт до падения интерфейса. Сохраните его в профиле соединения: NetworkManager принимает дополнительные маршруты на соединении, а netplan сохраняет их между загрузками. То же правило касается исключения брандмауэра на стороне клиента, которое исчезает после следующей перезагрузки правил.
Правила на стороне сервера принадлежат файлу конфигурации, который служба загружает при запуске, а не интерактивной сессии, которая заканчивается, когда вы её закрываете. Напишите правило, перезагрузите и подтвердите, что счётчик сдвинулся, потому что перезагрузка, отвергшая синтаксис, молча оставляет старый набор правил на месте.
Затем повторите исходный запрос приложения от начала до конца и запишите, какой уровень изменился. Исправление маршрута, которому также требовалось изменение фильтра, всё равно провалится, и вторую неудачу читать гораздо легче, когда вы знаете, что первой больше нет. Запишите дату и версию клиента рядом с результатом, поскольку значения по умолчанию для маршрутизации и фильтрации меняются между версиями. Держите эту заметку в заявке, чтобы следующий человек начал там, где вы остановились, а не повторял двухэтапный путь.