VPN за NAT, который вы не можете настроить: что всё ещё работает
Без проброса порта входящему пакету некуда идти. Пробивка отверстий, UPnP и релеи меняют это, но только при определённом поведении NAT.
Каждой конечной точке туннеля нужны адрес и порт, до которых может добраться другая сторона, и маршрутизатор, которым вы не управляете, — обычная причина, по которой это требование не выполняется. Интересно не то, что существуют трюки, а то, что каждый из них зависит от свойства таблицы отображения, которого вы не видите со стороны клиента. Два таких свойства решают почти всё: как создаётся отображение и принимает ли оно пакеты с адреса, с которым внутренняя сторона никогда не связывалась. Упорядочите среду по этим свойствам, и обходные решения перестанут быть фольклором.
Таблица отображения решает всё
Преобразование сетевых адресов ведёт таблицу, в которой внутренний адрес и порт записаны напротив публичного адреса и порта. Ответы, совпадающие с записью, преобразуются обратно, а пакет, приходящий снаружи без подходящей записи, вообще не имеет назначения. Это единственное поведение объясняет, почему слушатель за маршрутизатором недоступен из интернета. Оно же объясняет, почему первый пакет в каждом направлении должен исходить изнутри.
Посмотрите на таблицу со стороны маршрутизатора, и обходные решения становятся очевидными: либо что-то создаёт постоянную запись, либо создаёт временную и поддерживает её свежей, либо трафик вообще не идёт этим путём. Остальная часть статьи — эти три случая по порядку. Ничто здесь не зависит от функции производителя сверх того, что фиксирует таблица.
Что может и чего не может служба встреч
Пробивка UDP-отверстий использует исходящую запись как временное открытие, а не побеждает фильтр. Обе стороны обращаются к службе встреч, которая узнаёт каждую публичную конечную точку и сообщает другой стороне её точку. Затем обе отправляют навстречу друг другу, и каждый исходящий пакет создаёт или обновляет запись, пропускающую ответ внутрь. Порядок — то, что заставляет это работать, и порядок — то, что делает это хрупким: сторона, отправившая до того, как другая создала свою запись, просто отбрасывается, а повторная попытка мгновением позже удаётся. Сама служба не несёт VPN-трафик, поэтому её единственный рычаг — координируемое время.
Поведение отображения решает остальное, и RFC 4787 называет три формы: независимую от конечной точки, зависимую от адреса и зависимую от адреса и порта. При последней порт, на который должна целиться сторона, меняется с каждым назначением, поэтому предсказание перестаёт быть надёжным. Здесь техника упирается в тупик: NAT операторского уровня и строгий корпоративный межсетевой экран оба устраняют предсказуемость, нужную схеме, и никакое количество повторов её не возвращает.
Keepalive, перезагрузки и движущаяся конечная точка
Пробитый путь — это поток, а не слушатель, поэтому всё, что работает поверх него, должно переживать изменения. Оно должно поддерживать отображение живым периодическим трафиком, замечать, когда публичная конечная точка смещается, и восстанавливаться после перезагрузки маршрутизатора или переназначения адреса. Mesh VPN продукты помещают эту логику в свою плоскость управления, а обычный сервер оставляет её вам. Keepalive помогают только пока выживает то же отображение, и они расходуют батарею на мобильном клиенте, поэтому агрессивный интервал не бесплатен.
Ноутбук, спящий час, обычно возвращается на другой публичной конечной точке. Всё, что восстанавливает путь, должно снова работать изнутри, что возвращает то же требование клиенту.
Три способа обойти отсутствующий проброс
Первый способ просит маршрутизатор сам создать запись, через UPnP IGD, NAT-PMP или PCP, когда функция есть и включена. Второй передаёт трафик релею с публичным адресом, что всегда работает и всегда стоит пропускной способности плюс иной границы доверия. Третий переворачивает направление: внутренний хост открывает исходящий туннель к публичному серверу, и всё остальное едет внутри него.
[Peer]
PublicKey = 6yGj3kQ2wVb8sTn1pLx4dRc7hZa9mKf2uYe5oNq0iXw=
Endpoint = relay.corp.internal:51820
PersistentKeepalive = 25
AllowedIPs = 10.44.0.0/24
Конечная точка релея делает эту сделку видимой в конфигурации клиента, где конечная точка — релей, а не собственный адрес партнёра. Постоянный keepalive держит отображение тёплым, а разрешённые префиксы решают, что клиент может через него отправлять. Обратный туннель с внутреннего хоста — та же идея с другим владельцем, и он вообще не требует изменения NAT. Каждый из трёх убирает требование входящего трафика, не побеждая межсетевой экран, который по проекту блокирует нежелательный трафик, потому что трафик всё равно начинается изнутри.
Согласуйте обходное решение с владельцем маршрутизатора
Если вы администрируете маршрутизатор, статический проброс UDP проще проверить, чем любую схему пробивки, и он отказывает так, что это видно. Если нет, выясните, предлагает ли производитель релей или размещённую плоскость управления и позволит ли политика этим пользоваться. Если нет ни того ни другого, остаются обратный туннель или признание того, что конечная точка недоступна снаружи. Записать, какой вариант вы использовали, важнее, чем кажется, потому что варианты различаются тем, кто может наблюдать за трафиком и что произойдёт, если третья сторона что-то изменит.
Отметьте, был ли путь, к которому вы пришли, прямым или через релей, поскольку этот единственный факт предсказывает и задержку, и поведение при сбое. RFC 4787 остаётся справочником по поведению отображения под всем этим, и читать его раздел об отображении быстрее, чем последовательно проверять три обходных решения. Таблице всё равно, какой вариант вы выбрали; она фиксирует лишь то, что разрешено следующему пакету.