Технология NAT Loopback, которую в обиходе называют ещё и hairpin NAT, решает одну из самых обидных задачек домашнего сетевика: сервер поднят, порт проброшен, коллега из другого города заходит на внешний адрес без малейших проблем, а сам владелец из собственной квартиры наблюдает только бесконечное ожидание ответа и в итоге таймаут. Проблема при этом не в сервере, не в провайдере и не в криво написанном правиле проброса, а в том, как обычная трансляция адресов обращается с пакетом, который выходит наружу и тут же возвращается обратно на тот же самый внешний адрес. Ниже разбираются механика трансляции, точная причина отказа, порядок диагностики и целый набор обходных путей, от настройки прошивки роутера до раздельного DNS и перевода сети на IPv6.

Как работает обычный NAT и где именно ломается обратный ход

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

Теперь ситуация с петлёй. Домашний ноутбук с адресом 192.168.1.60 обращается к публичному адресу своего же роутера, потому что имя сайта разрешается именно туда. Пакет попадает на маршрутизатор через внутренний интерфейс, а правило проброса написано для внешнего. Чтобы запрос всё же дошёл до сервера и ответ вернулся корректно, роутер обязан выполнить двойную работу: переписать адрес назначения на внутренний адрес сервера и одновременно подменить адрес источника на свой собственный внутренний адрес. Без второй подмены случается классическая асимметрия: сервер видит, что клиент 192.168.1.60 сидит с ним в одной сети, и отвечает напрямую, минуя роутер. Ноутбук при этом ждёт ответ от внешнего адреса, а получает привет от совершенно чужого, с его точки зрения, узла 192.168.1.50, и честно отбрасывает его как непрошеный. Соединение рассыпается ещё на этапе рукопожатия.

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

Диагностика или снаружи работает а внутри молчит

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

Порядок проверки строится просто:

  1. С внешней стороны, например с телефона, отключённого от домашнего wifi и работающего через мобильную сеть, открыть адрес и убедиться, что сервис отвечает.
  2. Изнутри обратиться к тому же внешнему адресу и порту, зафиксировать таймаут или отказ в соединении.
  3. Изнутри обратиться к внутреннему адресу сервера и убедиться, что сам сервис жив и слушает порт.
  4. Заглянуть в настройки роутера и поискать пункт с именем NAT Loopback, NAT Reflection или Hairpin, заглянув заодно в раздел перенаправления портов.

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

Включение loopback в прошивке роутера

Самый честный путь - заставить роутер выполнять отражение как положено. В аппаратных решениях класса MikroTik это делается одним дополнительным правилом маскарада для трафика, идущего из внутренней сети на внутренний адрес сервера: источник подменяется на адрес роутера, пакет после ответа гарантированно возвращается через него же, и соединение склеивается без асимметрии. В прошивках семейства OpenWrt в настройке перенаправления портов стоит отдельная галка NAT reflection, которую легко пропустить, потому что по умолчанию она выключена. Некоторые фирменные прошивки крупных брендов включают петлю молча и без объявлений, и владелец годами не догадывается, что ему просто повезло с железкой.

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

Раздельный DNS как самый элегантный обход

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

Настройка сводится к статической записи в локальном резолвере. В dnsmasq это одна строка, привязывающая имя к приватному адресу, в MikroTik - статическая запись во встроенном DNS, в серверных Windows - обычная зона прямого просмотра. Требование только одно, но жёсткое: клиенты должны пользоваться именно этим внутренним резолвером, иначе вся механика разваливается. Тут есть современная тонкость: браузеры всё чаще ходят за адресами через собственный защищённый DNS поверх шифрованного канала и игнорируют системные настройки, поэтому на домашних машинах эту опцию приходится выключать или внимательно настраивать. Протоколы с привязкой к имени, прежде всего TLS, работают при раздельном DNS нормально, потому что имя в запросе нигде не меняется - меняется только адрес, на который это имя указывает, а сертификат остаётся тем же самым.

Файл hosts и его подводные камни

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

Добавляет перца и сама механика разрешения имён: современные программы всё чаще игнорируют hosts, потому что тащат собственные резолверы и собственные представления о правильном DNS, и тщательно вписанная строка просто не срабатывает, а у Admина остаётся полное ощущение, что система взбунтовалась. Годится способ исключительно как временный костыль для стационарного компьютера, который никогда не покидает домашнюю сеть, и только при аккуратном понимании того факта, что hosts имеет приоритет над честным резолвом и молча перекрывает любые изменения на DNS серверах.

Внутренний посредник, статический NAT и IPv6

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

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

Почему каждый домашний админ спотыкается об это в первый раз

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

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