Клиент OpenVPN обращается к одному адресу, сервер отвечает с другого, и туннель так и не поднимается. Журнал сервера показывает приход пакета, а запись показывает уход ответа, поэтому вину возлагают на клиента. На хосте с несколькими интерфейсами или с несколькими адресами на одном интерфейсе стороны просто расходятся в том, какой адрес используется. Ответ корректен на уровне IP, но многие клиенты отбрасывают датаграмму, источник которой не совпадает с адресом, к которому они обращались.

Что видит клиент, когда меняется источник

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

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

Что на самом деле делает параметр multihome

Директива записывается как multihome в файле конфигурации и как --multihome в командной строке, и она заставляет UDP-сервер отвечать с адреса, до которого дошёл пакет клиента. Ядро при приёме передаёт исходный адрес назначения как дополнительные данные, и OpenVPN использует это значение как источник ответа. Так сервер, слушающий на общем адресе, local 0.0.0.0 для IPv4 или его эквивалент для IPv6, ведёт себя так, будто каждый клиент дошёл до отдельного слушателя. Клиенты, пришедшие через публичный адрес, получают ответы с публичного адреса, а клиенты на внутреннем адресе — с него. Ничего другого на пути пакета не меняется: маршрут, правила фильтрации и конфигурация туннеля остаются в точности такими, какими были.

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

Когда фиксированный локальный адрес — неверное значение по умолчанию

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

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

Докажите источник ответа снаружи

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

tcpdump -ni any udp port 1194
ss -lunp 'sport = :1194'
ip route get 203.0.113.10 from 198.51.100.20

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

Маршрутизация, обнаружение и фильтрация остаются раздельными

Сохранение источника ответа не устанавливает исходящий маршрут, не обновляет динамический DNS и не заставляет одну семью адресов принимать другую. На сервере с несколькими вышестоящими каналами обратный путь для каждого источника нужно согласовать намеренно, иначе ответы уходят через интерфейс, который фильтр клиента никогда не разрешал. Так же новый адрес после смены префикса должен доходить до клиентов через обнаружение и поддерживаемый поток переподключения, а не через старую запись.

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

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