Назад | Перейти на главную страницу

Обратная связь с перенаправленным общедоступным IP-адресом из локальной сети - Hairpin NAT

Это Канонический вопрос про Шпильку NAT (Loopback NAT).

Общая форма этого вопроса:

У нас есть сеть с клиентами, сервером и NAT-маршрутизатором. На маршрутизаторе есть переадресация портов на сервер, поэтому некоторые из его сервисов доступны извне. У нас есть DNS, указывающий на внешний IP. Клиенты локальной сети не могут подключиться, но работают внешние.

На этот вопрос собраны ответы на несколько других вопросов. Первоначально они ссылались на FreeBSD, D-Link, Microtik и другое оборудование. Однако все они пытаются решить одну и ту же проблему.

Поскольку это было повышено до канонический вопрос по шпильке NAT, Я подумал, что, вероятно, у него должен быть более общий ответ, чем принятый в настоящее время, который (хотя и превосходный) относится конкретно к FreeBSD.

Этот вопрос относится к услугам, предоставляемым серверами в сетях IPv4 с адресом RFC1918, которые становятся доступными для внешних пользователей путем введения NAT назначения (DNAT) на шлюзе. Затем внутренние пользователи пытаются получить доступ к этим службам через внешний адрес. Их пакет отправляется от клиента к шлюзу, который перезаписывает адрес назначения и немедленно вводит его обратно во внутреннюю сеть. Именно этот резкий поворот пакета на шлюзе дает начало имени шпилька NAT, по аналогии с поворот шпильки.

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

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

Решение в том, что для пакетов, которым требуется такой NAT назначения, и которые достигают шлюза из внутренней сети, чтобы также выполнить NAT источника (SNAT) для входящего пакета, обычно путем переписывания адреса источника на адрес шлюза. Затем сервер считает, что клиент - это сам шлюз, и отвечает ему напрямую. Это, в свою очередь, дает шлюзу возможность уравновесить влияние DNAT и SNAT на входящий пакет путем перезаписи адресов источника и назначения в возвращаемом пакете.

Клиент думает, что разговаривает с внешним сервером. Сервер думает, что обращается к шлюзу. Все партии довольны. На этом этапе может быть полезна диаграмма:

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

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

iptables -t nat -A PREROUTING  -p tcp --dport 80 -j DNAT --to-destination 192.168.3.11

который включит простой DNAT для порта HTTP на внутренний сервер на 192.168.3.11. Но для включения закрепленного NAT также потребуется такое правило, как:

iptables -t nat -A POSTROUTING -d 192.168.3.11 -p tcp --dport 80 -j MASQUERADE

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

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

То, что вы ищете, называется "шпилька NAT". Запросы от внутреннего интерфейса на IP-адрес, назначенный внешнему интерфейсу, должны обрабатываться NAT, как если бы они поступали от внешнего интерфейса.

Я вообще не знаком с FreeBSD, но читаю руководство "pf" для OpenBSD (http://www.openbsd.org/faq/pf/rdr.htmlПредлагаемые решения DNS с разделенным горизонтом, использование сети DMZ или TCP-проксирования приводят меня к мысли, что «pf» не поддерживает резкий NAT.

Я бы посмотрел на то, чтобы пойти по маршруту DNS с разделенным горизонтом и не использовать IP-адреса в URL-адресах внутри компании, а вместо этого использовать имена.

Проблема здесь в том, что ваш маршрутизатор не выполняет NAT адреса вашего внутреннего клиента. Таким образом, квитирование TCP не удается.

Предположим следующие IP-адреса

  • Клиент: 192.168.1.3
  • Сервер: 192.168.1.2
  • Внутренний маршрутизатор: 192.168.1
  • Маршрутизатор внешний: 123.123.123.1

Вот что происходит:

  1. Клиент (192.168.1.3) отправляет TCP-SYN на ваш внешний IP-адрес, порт 80 (123.123.123.1:80)
  2. Маршрутизатор видит правило переадресации портов и пересылает пакет на сервер (192.168.1.2:80) без изменения IP-адреса источника (192.168.1.3)
  3. Клиент ожидает SYN-ACK от внешнего IP-адреса
  4. Сервер отправляет свой ответ напрямую клиенту, потому что он находится в той же подсети. Он не отправляет пакет на маршрутизатор, который бы изменил NAT.
  5. Клиент получает SYN-ACK от 192.168.1.2 вместо 123.123.123.1. И отбрасывает это.
  6. Клиент по-прежнему ждет SYN-ACK от 123.123.123.1 и истекает время ожидания.

Почему бы не использовать везде DNS с разделением горизонта вместо жесткого кодирования IP-адресов? У вас должен быть ext.yourdomain, указывающий на 217.x.x.x снаружи, а затем на 192.x.x.x внутри.

Если это оригинальный маршрутизатор D-Link (т.е. не Rev. D / версия прошивки 1.00VG от Virgin Media), вы сможете изменить настройки, чтобы обойти это. (Однако я согласен с предложением предыдущего автора о DD-WRT по многим другим причинам!)

  1. Войдите в веб-интерфейс роутера.
  2. Щелкните вкладку Дополнительно вверху
  3. Щелкните вкладку Настройки брандмауэра слева.
  4. Щелкните значок Независимость от конечной точки переключатель под Фильтрация конечных точек TCP, как показано на скриншоте ниже (или см. эмулятор маршрутизатора на сайте D-Link)
  5. Сохранить изменения; ты закончил

Этот снимок экрана взят из модели Rev. C; ваш может немного отличаться.

Недавно ответил на аналогичный вопрос: Статический NAT Cisco не работает на стороне LAN и просто понял, что это канонический вопрос. Итак, позвольте мне резюмировать здесь решение.

Прежде всего: забудьте про NAT (если можете) - вопрос вовсе не в настройке NAT. Речь идет о доступе к серверу, расположенному за NAT, как из Интернета, так и из локальной сети. Использование двух зон DNS - жизнеспособная альтернатива, но не всегда решение. Но решение существует, и оно невероятно простое (хотя, вероятно, и не идеальное):

(1) на сервере: добавьте общедоступный IP-адрес в качестве вторичного IP-адреса на сетевом интерфейсе сервера с маской 255.255.255.255 (веб-служба или что-то еще, что вы хотите на сервере, также должно прослушивать этот IP-адрес); все современные операционные системы позволяют это делать (или вместо добавления вторичного IP-адреса к первичному интерфейсу можно использовать петлевой интерфейс с назначенным ему общедоступным IP-адресом).

(2) на узлах LAN: добавьте маршрут узла для общедоступного IP-адреса, например, для узлов Windows используйте следующую команду: route -p добавить маску 203.0.113.130 255.255.255.255 192.168.1.11 (вы также можете использовать параметр DHCP «статический маршрут» для распределения маршрута). Или, если между клиентами и выходящим в Интернет маршрутизатором есть (а) коммутатор (ы) / маршрутизатор (ы) L3, настройте маршрут этого хоста на этом (этих) промежуточных коммутаторах / маршрутизаторах, а не по клиентам.

Для тех, кто связан с трехсторонним подтверждением TCP: он будет работать нормально в предлагаемой конфигурации.

Пожалуйста, оставьте отзыв (хотя бы проголосуйте).

С технической точки зрения лучшим решением этой проблемы является включение IPv6 в вашей сети. Когда IPv6 включен, вам необходимо создать запись AAAA для вашего домена. Сохраните существующую запись A, указывающую на внешний IPv4 маршрутизатор. Создайте запись AAAA, указывающую на IPv6-адрес сервер.

IPv6 имеет достаточно адресов, чтобы избежать NAT, поэтому для IPv6 вам не понадобится фиксированный NAT. И как только вы включили IPv6 и создали записи AAAA, любой клиент, поддерживающий RFC 8305 попробует IPv6 перед IPv4. Это означает, что вам не нужен фиксированный NAT для IPv4, потому что клиенты не будут его использовать.

Вам по-прежнему потребуется существующий IPv4 NAT для исходящих подключений и переадресация портов для входящих подключений, пока большая часть мира также не включит IPv6.

Это тоже быстрее.

Использование IPv6 даст вам лучшую производительность, чем фиксированный NAT.

С помощью закрепленного NAT ваш клиент отправит пакет через коммутатор на маршрутизатор, затем маршрутизатор выполнит два цикла трансляции и, наконец, отправит пакет через коммутатор на сервер. Пакеты от сервера к клиенту будут проходить весь этот путь в обратном порядке.

С IPv6 вы избегаете NAT, вместо этого пакеты отправляются напрямую через коммутатор между клиентом и сервером. Это означает, что при обходе вы уменьшаете количество проходов через коммутатор с 4 до 2, и вы избегаете 2 проходов через маршрутизатор и 4 трансляций, которые маршрутизатор мог бы выполнить. Это означает лучшую производительность.

Это верно, даже если вы используете коммутатор, встроенный в тот же блок, что и маршрутизатор.

Что делать, если у интернет-провайдера нет IPv6?

Если вы используете ISP, который не поддерживает IPv6, я сомневаюсь, следует ли вам размещать серверы в этой сети. Это мои предложения о том, что делать, если интернет-провайдер в настоящее время не поддерживает IPv6.

Сначала скажите интернет-провайдеру, что вы необходимость IPv6. И, возможно, напомните им, что протокол IPv6 существует уже 20 лет, поэтому им уже давно пора его поддержать. Если этого недостаточно для того, чтобы интернет-провайдер воспринял вас серьезно, начните искать других интернет-провайдеров.

Если вы найдете провайдера с поддержкой IPv6, вы можете работать с обоими провайдерами в течение переходного периода. На маршрутизаторе, подключенном к новому интернет-провайдеру, вы можете отключить IPv4 на стороне LAN, а затем подключить стороны LAN обоих маршрутизаторов к одному коммутатору. IPv4 и IPv6 - два независимых протокола, и поэтому нет никаких проблем, если эти соединения проходят через разные маршрутизаторы. В качестве дополнительного преимущества это дает вам некоторую избыточность, если одно из соединений выходит из строя.

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

Перенос сервера на хостинг не даст вашим клиентам IPv6, но перемещение сервера означает, что вам больше не понадобится фиксированный NAT для доступа к нему.

Чего не следует делать

Не включайте IPv6 и не создавайте записи AAAA, если у вас нет способа маршрутизировать трафик IPv6. Если ваш интернет-провайдер не поддерживает IPv6, но вы все равно решили включить IPv6 в своей локальной сети (возможно, используя адреса RFC 4193) и создать записи AAAA, это будет работать для клиентов в вашей локальной сети, достигающих сервера в вашей локальной сети. Но для связи между вашей локальной сетью и внешним миром сначала будет использоваться IPv6 (что не сработает), и вы будете полагаться на возврат к IPv4, который в лучшем случае будет немного медленнее или в худшем случае не произойдет.

Я отвечу на свои вопросы, просто чтобы расширить кругозор для тех, у кого похожие проблемы.

Я связался с моим интернет-провайдером и попросил их попробовать решить мои проблемы. Они предложили мне еще один общедоступный IP-адрес только для сервера.Теперь у меня есть локальный трафик на стороне WAN FreeBSD, и мы сделали специальные каналы для более быстрой пропускной способности для локального трафика на общедоступный IP-адрес сервера.

Так как я тоже задавал этот вопрос (см. Как мне получить доступ к сетевой службе, защищенной NAT за брандмауэром, изнутри, используя ее внешний IP-адрес?) и был перенаправлен сюда, но ответы здесь не давали решение (в отличие от универсальных объяснения) позвольте мне предоставить мой Linux (iptables specific) здесь, чтобы сэкономить всем несколько часов экспериментов. Этот файл находится в iptables-restore формат и может быть прочитан непосредственно в iptables (конечно, после редактирования IP-адресов). Это для веб-сервера (порт 80) и только для IPv4 - правила для IPv6 и SSL (порт 443) аналогичны.


# Port forwarding for VM / Container access with „hairpin NAT“.
*nat
:PREROUTING ACCEPT [3:205]
:INPUT ACCEPT [59:670]
:OUTPUT ACCEPT [16:172]
:POSTROUTING ACCEPT [20:257]

# This was simple port forwarding - access works from outside but not from inside
#-A PREROUTING  -4 -p tcp -i eth0 --dport 80 -j DNAT --to web.local:80

# This is real hairpin NAT which allows „web.local“ to access itself via the VM hosts external IP.
# First we need to masquerade any traffic going out the external interface:
-A POSTROUTING -o eth0 -j MASQUERADE

# Then we need to reroute incoming traffic on the public IP to the local IP:
-A PREROUTING  -4 -p tcp -d web.public.com --dport  80 -j DNAT --to web.local:80

# And finally we need to tell the router that the source IP of any traffic
# coming from the LAN must be source-rewritten when going to the web server:
-A POSTROUTING -4 -p tcp -s lan.local/24 -d web.local --dport  80 -j SNAT --to-source web.public.com:80

COMMIT

Заменить lan.local , web.local и web.public.com с вашей локальной сетью (например, 10.0.x.0 / 24), локальным IP-адресом вашего веб-сервера (например, 10.0.1.2) и общедоступным IP-адресом вашего маршрутизатора (например, 4.5.6.7). В -4 просто разрешить правила IPv6 и IPv4 в одном файле (такие строки игнорируются ip6tables). Также не забудьте заключать IPv6-адреса в [скобки], когда они включают объявления портов, например [fe0a:bd52::2]:80.

Все это было причиной того, что я вырывал волосы, когда пытался воплощать в жизнь объяснения в этом вопросе. Надеюсь, я ничего не упустил.

Я добавлю здесь ответ, так как комментарии здесь не касались моей конкретной проблемы. Я подозреваю, что это потому, что я обнаружил неприятную ошибку ядра Linux. Настройка такова:

internet <--> modem 1.1.1.1/30 <--> switch <---> LAN 10.1.1.0/24
                                      ^
        +----------------------+      |
        |              /--eth0 o <----/
        |              |       |           
        | 10.1.1.1/24 br0      |           v (antenna)
        |  1.1.1.2/30  |       |           |
        |              \-wlan0 o ----------/
        +----------------------+ 

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

Наш шлюз все еще выполняет обязанности NAT для машин в локальной сети. Поскольку у него только 1 порт Ethernet, он вынужден выполнять закрепляющий NAT. Я подозреваю, что он должен просто работать с правилами iptables, приведенными в других комментариях здесь, но, по крайней мере, в ядре Linux 4.9 это не так. В версии 4.9 наш шлюз может получить доступ к Интернету, а машины в локальной сети, пытающиеся получить к нему доступ через NAT, не могут.

tcpdump показывает ответы на входящие пакеты, попадающие в eth0, но они не выходят из br0. Выполнение этой команды устраняет следующее:

ebtables -t brouter -A BROUTING -d 01:00:00:00:00:00/01:00:00:00:00:00 -j ACCEPT
ebtables -t brouter -A BROUTING -p IPv4 --ip-dst 10.1.1.0/24 -j ACCEPT
ebtables -t brouter -A BROUTING -p IPv4 --ip-src 10.1.1.0/24 -j ACCEPT
ebtables -t brouter -A BROUTING -p IPv4 -j DROP

Перед запуском этой команды входящие пакеты обрабатываются в соответствии с поведением ядра по умолчанию, которое заключается в том, чтобы передать их мосту, а затем передать им модули маршрутизации ядра. Команда заставляет пакеты, которые не из LAN, обходить мост и идти напрямую на маршрутизацию, что означает, что у моста нет возможности отбросить их. Широковещательные и многоадресные адреса должны быть соединены мостом, иначе такие вещи, как DHCP и mDNS, не будут работать. если вы используете IPv6, вы также должны добавить правила для него.

У вас может возникнуть соблазн решить проблему с помощью этого:

brctl hairpin br0 eth0 on
brctl hairpin br0 wlan0 on

Я, конечно, был так искушен - это была моя первая попытка. Как только я это сделал, машины в локальной сети получили доступ в Интернет, так что какое-то время это работает. Затем произошло следующее (и я не стал повторять эксперимент):

  1. Время пинга через локальную сеть до шлюза удваивается с интервалом примерно в 10 секунд, увеличиваясь с 0,1 мс до 0,2 мс, 0,4 мс, 0,8 мс, 2 мс и так далее, пока блок шлюза не станет недоступным из локальной сети. Пахло штормом пакетов, но STP был включен везде.
  2. Вскоре после этого умерли все точки беспроводного доступа.
  3. При попытке диагностировать происходящее с беспроводной сетью все IP-телефоны перезагрузились.
  4. Вскоре после этого подключенные к сети машины потеряли связь с локальной сетью.

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

Так как это канонический вопрос. Отвечу, если у вас роутер Sonicwall.

Выражение, которое нужно знать, это Политика обратной связи NAT

В этом документе описывается, как хост в локальной сети SonicWall может получить доступ к серверу в локальной сети SonicWall, используя общедоступный IP-адрес сервера для полного доменного имени. Представьте себе сеть NSA 4500 (SonicOS Enhanced), в которой первичная подсеть LAN - 10.100.0.0 / 24, а первичный IP-адрес WAN - 3.3.2.1. Допустим, у вас есть веб-сайт для ваших клиентов, и его имя хоста равно. Вы уже написали необходимые политики и правила, чтобы посторонние могли попасть на веб-сайт, но на самом деле он работает на частном сервере 10.100.0.2. Теперь представьте, что вы человек, использующий ноутбук на частной стороне с IP-адресом 10.100.0.200. Вы хотите подключиться к серверу, используя его публичное имя, потому что вы делаете то же самое, когда ваш ноутбук находится с вами в дороге. Если вы сидите на частной стороне и просите http://www.example.com>, loopback - это то, что позволяет этому работать, даже если сервер фактически находится рядом с вами на локальном IP-адресе.

Чтобы разрешить эту функцию, вам необходимо создать политику обратной связи NAT, также известную как отражение NAT или шпилька.

Политика обратной связи с использованием IP-адреса интерфейса WAN

Login to the SonicWall Management GUI.
Navigate to Manage | Rules | NAT Policies submenu.
Click on the Add button.
Create the following NAT Policy.
Original Source: LAN Subnets (or Firewalled Subnets if you want hosts in other zones to be included)
Translated Source: WAN Interface IP
Original Destination: WAN Interface IP
Translated Destination: (LAN server object)
Original Service: Any
Translated Service: Original
Inbound Interface: Any
Outbound Interface: Any

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

В FreeBSD с использованием PF это просто (в вашем файле pf.conf):

extif = "tun0"
intif = "em0"
{other rules}...
nat on $intif from any to 192.168.20.8 port 80 -> ($extif)

192.168.20.8 будет внутренним веб-сервером.