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

Оба направления маршрутизируются отдельно

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

Это соглашение — вторые ворота. В strongSwan селекторы трафика — это leftsubnet и rightsubnet, и пакет, чей источник или назначение выходит за пределы согласованной пары, не шифруется, что бы ни говорила таблица маршрутизации. Префикс, маршрутизированный в туннель, но отсутствующий в селекторах, — тихий односторонний отказ: маршрут выглядит правильным, пакет всё равно уходит открытым или отбрасывается, и только журнал charon жалуется.

Удалённый хост ничего не знает о вашем туннеле

Внутри удалённой локальной сети ответ — обычный пакет, адресованный вашему клиенту. Хост назначения не видит заголовка IPsec и не имеет причин предпочитать VPN-шлюз; он ищет ваш префикс, не находит ничего конкретнее своего маршрута по умолчанию и следует ему. Если маршрут по умолчанию указывает на основной межсетевой экран, у него либо есть маршрут обратно в туннель, либо нет. Когда нет, вы получаете тихий сброс, ICMP unreachable или ответ, который уходит через интерфейс в сторону интернета и умирает.

Второго интерфейса достаточно, чтобы это сломать, даже когда маршрут существует. NAS с каналом управления в другом VLAN, сервер с резервным uplink, правило политики, отправляющее один диапазон источников во вторую таблицу: любое из этого может перехватить ответ. В Linux ip rule show и ip route show table all показывают правила и таблицы, которые скрывает обычный список.

Прочитайте решение на машине, которая отправляет ответ

Спросите ядро, прежде чем что-то менять, и дайте ему адрес источника, потому что правила, зависящие от источника, меняют ответ.

ip route get 10.10.5.10 from 10.20.30.15
ip rule show
ip route show table all
ss -tn state established "( sport = :445 )"

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

В Windows эквиваленты — Find-NetRoute -RemoteIPAddress 10.10.5.10 для решения и Get-NetRoute для таблицы. Маршрут, добавленный через New-NetRoute с метрикой выше стандартной, тихо проигрывает, поэтому читайте столбец метрики, а не запись. Затем подтвердите пакетами: tcpdump -ni any "host 10.10.5.10 and tcp port 445" на удалённом интерфейсе LAN показывает запрос, а тот же фильтр на стороне туннеля показывает, вернулся ли ответ. Запрос виден, ответа нет — значит ответ был маршрутизирован в другое место или отброшен; ответ на неверном интерфейсе выдаёт виновника до того, как вы тронете маршрут.

Когда шлюз сервера не является конечной точкой VPN

Многие площадки ставят межсетевой экран между серверами и концентратором. Этот экран пересылает ответ, поэтому ему нужен маршрут для префикса вашего клиента в сторону VPN-шлюза и политика пересылки в обоих направлениях. Устройства с состоянием усугубляют: запрос прошёл через экран от хоста LAN, которому он разрешил, ответ теперь приходит с другого направления, а запись отслеживания соединений больше не совпадает, поэтому пакет отбрасывается как недействительный, а не как запрещённый. Вот почему журнал политики выглядит пустым, пока трафик исчезает.

У шлюза есть собственный второй фильтр. Обратная проверка пути в Linux отбрасывает пакеты, источник которых недостижим через интерфейс, на который они пришли, и это в точности форма законного асимметричного обратного пути. руководство strongSwan по пересылке требует net.ipv4.ip_forward и ослабленный net.ipv4.conf.all.rp_filter именно поэтому. Строгое значение 1 на любом из шлюзов тихо ломает правильный маршрут, и nstat -az показывает отбрасывания, если знать, куда смотреть.

SymptomWhere the reply is most likely lost
Gateway ping works, LAN host silentSource address the far host cannot place in its table
SYN arrives, no SYN-ACK, tunnel counters flatNo route to the client prefix on the far host or its gateway
Reply counted on the internet-facing interfaceDefault route or policy rule on the far host
Firewall reports invalid stateAsymmetric path through a stateful device
Worked until a link failed overNew path is asymmetric, or rp_filter now rejects it

Маршрутизируйте или транслируйте, затем проверьте в обоих направлениях

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

iptables -t nat -A POSTROUTING -o eth1 -s 10.20.30.0/24 -j MASQUERADE

Выбирайте это осознанно: как только клиенты начинают выглядеть как адрес шлюза, ACL на основе источника перестают их различать, и conntrack должен удерживать соответствие, чтобы ответ записывался обратно в туннель. Если селекторы по-прежнему исключают префикс клиента, NAT ничего не меняет, потому что запрос так и не вошёл в туннель.

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

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