Правильный NAT Loopback/HairPin NAT в MikroTik

Правильный NAT Loopback/HairPin NAT в MikroTik

Смысл технологии NAT loopback (NAT hairpinning) в том, что когда из внутренней сети приходит запрос на внешний IP-адрес маршрутизатора, он считается пришедшим извне — а значит, работают правила брандмауэра, относящиеся ко внешним соединениям. Таким образом, правила проброса портов извне также будут активны и корректно обрабатываться на запросах, пришедших из локальной сети. В этой статье разберем различные методы реализации этой схемы.

Немного теории

NAT

Технология NAT – Network Address Translation (а точнее один из его подвидов PAT – Port Address Translation) позволяет использовать один внешний адрес для создания подключений несколькими устройствами в локальной сети. Разберем как это работает.

Упрощенная схема прохода пакетов в Linux/MikroTik (PacketFlow)

Возьмем стандартную сеть и маршрутизатор MikroTik:

Схема сети для примеров

Когда компьютер в локальной сети хочет получить доступ до ресурса и посылает запрос в интернет, маршрутизатор создает новую запись в таблице трансляции адресов (NAT connections table), присваивает метку new на этапе connection tracking. Далее следует этап routing decision, где маршрутизатор присваивает пакету выходной интерфейс (как правило WAN – ether1), после прохода цепочки forward, в post routing происходит замена адреса источника на адрес выходного интерфейса динамически (action: masquerade) либо на заранее заданный статически (action: src-nat – to-address). Таким образом пакет уходит в интернет с внешним IP адресом маршрутизатора с исходным адресом назначения.

В виде правил MikroTik механизм выглядит примерно так:

/ip firewall nat
add action=masquerade chain=srcnat out-interface-list=ether1
Первый этап прохождения NAT: запрос из LAN в WAN

Для того, чтобы идентифицировать данное соединение в таблице трансляции адресов создается запись, где содержатся параметры соединения: адрес источника (в локальной сети), адрес назначения, порт назначения, порт источника. В MikroTik эту таблицу можно посмотреть в IP – Firewall – Connections. Данные записи содержат дополнительные поля, такие как: наличие fasttrack, есть ли ответные пакеты, активность правил цепочек src-nat и dst-nat и другие. Если NAT в MikroTik не включен (отсутствуют работающие правила таблицы NAT), то connection tracking автоматически отключается за ненадобностью.

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

Второй этап прохождения NAT: ответ из WAN в LAN

Проброс портов

Ключевой особенностью является то, что новые запросы могут создавать только в одну сторону: из локальной сети в интернет, но не наоборот. «NAT не является firewall», однако в стандартной конфигурации из-за специфики работы он запрещает все новые соединения с внешнего интерфейса в локальную сеть. При отсутствии подходящего правила для обратной трансляции пакет переходит в цепочку input — то есть пакетов, которые адресованы самому маршрутизатору. Если не найдена подходящая служба на маршрутизаторе, прослушивающая соединения на порту, пакет отбрасывается.

Иногда возникает потребность принимать новые соединения из интернета, на компьютере в локальной сети за NAT. Для этого потребуется правило “обратного NAT”, которое сработает в цепочке prerouting и заменит адрес назначения на требуемый.

/ip firewall nat 
add chain=dstnat dst-port=80,443 protocol=tcp action=dst-nat to-addresses=192.168.88.5

Как видно из правила, оно сработает на все пакеты, проходящие через роутер, у которых порт назначения 80 или 443 и перепишет их адрес на 192.168.88.5. Но так как работа этого правила распространяется и на пакеты, идущие из локальной сети, то устройства в локальной сети больше не смогут получать доступ к web ресурсам интернета потому что маршрутизатор начнет заменять адрес назначения на 192.168.88.5 на всех пакетах, соответствующих условию. Чтобы такого не произошло, необходимо добавить условия адреса назначения или интерфейса назначения.

/ip firewall nat 
add chain=dstnat in-interface=ether1 dst-port=80,443 protocol=tcp action=dst-nat to-addresses=192.168.88.5

Данное правило будет полноценно работать и перенаправлять новые соединения из интернета на устройство в локальной сети.

NAT Loopback / Hairpin NAT

Проблема

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

  • Если в условии использовался внешний интерфейс, то правило не сработает и пакет будет отброшен маршрутизатором – соединение не состоится.
  • Если в условии использовался внешний адрес маршрутизатора, то правило сработает, но соединение не установится. Рассмотрим этот сценарий подробнее.
Пакет будет отброшен инициатором соединения

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

Варианты решения

Подмена на уровне DNS

Если приложение использует DNS для определения IP адреса сервиса назначения (например, сайт), то самым правильным способом будет использование в локальной сети DNS-сервера, который будет отдавать внутренний IP адрес для домена. В случае использовании MikroTik DNS-сервера, правило будет выглядеть примерно так:

/ip dns static
add address=192.168.88.5 name=example.com

Таким образом настройка NAT Loopback не потребуется в принципе. Клиент будет напрямую обращаться на сервер назначения по локальной сети без использования маршрутизатора, а сервер назначения, в свою очередь, увидит настоящий адрес источника в локальной сети

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

Официальный

Многие ресурсы, включая wiki.mikrotik.com, предлагают примерно одни и те же варианты решения:

/ip firewall nat
add chain=srcnat src-address=192.168.88.0/24 \
  dst-address=192.168.88.5 protocol=tcp dst-port=80,443 \
  out-interface=LAN action=masquerade

Этим правилом задаем, что: всем пакетам, которые идут из локальной сети, на адрес 192.168.88.5, на порты 80 и 443 и выходят с интерфейса LAN мы меняем адрес источника на адрес маршрутизатора в локальной сети.

Таким образом, соединение успешно устанавливается, однако есть несколько ограничений:

  • На каждое правило проброса порта потребуется еще одно правило для поддержки NAT Loopback
  • Можно легко попасться на граблю, не указав фильтр источника пакетов (src-address=192.168.88.0/24). Все запросы (включая те, что идут из интернета) на сервер назначения будут идти от адреса маршрутизатора, что в итоге может сломать фильтрацию на базе адресов источника на сервере назначения.
  • Серверу назначения, которому в итоге придет запрос не будет видно IP адрес источника, так как им будет являться маршрутизатор

Дополненный официальный способ

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

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

Первым этапом нужно промаркировать (new-packet-mark=nat-loopback) те пакеты, которые пришли на внешний адрес маршрутизатора (dst-address=203.0.113.5) из локальной сети (in-interface=LAN) и являются новыми соединениями (connection-state=new).

/ip firewall mangle
add chain=prerouting comment="NAT Loopback detect" dst-address=203.0.113.5 in-interface=LAN connection-state=new action=mark-packet new-packet-mark=nat-loopback passthrough=yes

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

/ip firewall nat
add chain=srcnat packet-mark=nat-loopback action=masquerade comment="NAT Loopback replace address" 

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

Таким образом, появляется возможность писать правила проброса портов в обычном виде по одному на порт или несколько портов. Они будут работать как и в классическом сценарии (при поступлении извне), так и в случае поступления запросов из локальной сети.

/ip firewall nat
add chain=dstnat dst-address=203.0.113.5 protocol=tcp dst-port=80,443 action=dst-nat to-addresses=192.168.88.5
add chain=dstnat dst-address=203.0.113.5 protocol=tcp dst-port=8080   action=dst-nat to-addresses=192.168.88.20
add chain=dstnat dst-address=203.0.113.5 protocol=tcp dst-port=25,143 action=dst-nat to-addresses=192.168.88.100

Правильный NAT Loopback/HairPin NAT в MikroTik: 46 комментариев

  1. шикарная статья!
    есть вопрос, а не разумнее было бы помечать только пакеты с connection state new?
    т.к. после установки соединения смотреть за этими пакетами нам особого смысла нет, а дело это достаточно ресурсозатратное.

  2. Уважаемый, а тестировали схему на практике? У меня маркированные пакеты попадают в INPUT, поскольку имеют адресом назначения роутер, и логично дропаются

    1. Добрый день, тестировали. В input они могут попасть только если правила prerouting dst-nat не работают

      1. Да, не обратил поначалу внимание, что Вы, хитрец, в правиле dst-nat входящий интерфейс опустили. Заработало, но теперь уже больше нравится вариант с двойным горизонтом DNS. Особенно когда сообразил, что на внутреннем интерфейсе IPv6 (у меня dual stack) Mikrotik тоже прекрасно резолвит

        1. DNS лучшее решение, если используются доменные имена и они известны, haipin nat своего рода костыль.
          Я в dst-nat указал dst-address. Тут кому больше нравится, можно и так и так

  3. Добрый день.
    А разве нельзя вот это ограничение: “На каждое правило проброса порта потребуется еще одно правило для поддержки NAT Loopback” обойти просто не указывая порты?

    /ip firewall nat
    add action=masquerade chain=srcnat out-interface=LAN src-address=192.168.88.0/24

    1. Добрый день, упоминал про это:
      > “Можно легко попасться на граблю, не указав фильтр источника пакетов (src-address=192.168.88.0/24). Все запросы (включая те, что идут из интернета) на сервер назначения будут идти от адреса маршрутизатора, что в итоге может сломать фильтрацию на базе адресов источника на сервере назначения.”

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

  4. подскажите пакеты маркеруются а в NAT не попадают. на одном роутере connection state – new а на другом пусто
    Loopback prerouting: in:bridge out:(unknown 0), connection-state:new src-mac 8e:22:75:74:e8:dd, proto TCP (SYN), 13123123:47488->123123123:5001, len 60 – работает

    LOOPBACK prerouting: in:All-Lan out:(unknown 0), src-mac 18:31:bf:b2:20:3d, proto TCP (SYN), 213123123:57804->123123123:80, len 52 – не работает

    1. проверьте, что метка одна и та же ставится (в mangle) и проверяется (в srcnat) и само правило проброса порта (в нем возможно указан внешний интерфейс)

  5. Для тех кто затупил, или домохозяйки.

    Тут два пункта только вписать в улучшенном варианте. IP белый (IP домена) и интерфейс локалки бридж=bridge1 (или как вы его переименовали).

  6. А что делать если мне необходимо обратиться к сайту (primer.moysite.ru), работающем в локальной сети на локальном днс (192.168.1.5) на ip 192.168.1.55 извне, используя белый айпи роутера (212.12.1.5)? Домен moysite.ru имеет А запись на хостере вида 22.22.22.5.

    1. Для домена primer.moysite.ru указываете А запись – ваш внешний адрес (тот, что дадут сервисы проверки, типа 2ip.ru) и пробрасываете порты tcp 80,443 на 192.168.1.55.
      Эта статья пригодится, если вы захотите на сайт в вашей локалки попасть из вашей же локалки

  7. Помогите.
    Не могу получить доступ по внешнему ip к web серверу. Вроде все делаю по инструкции!

    /ip address
    add address=192.168.146.254/24 interface=ether2-LAN network=192.168.146.0
    add address=10.128.20.7/24 interface=ether1-WAN network=10.128.20.0
    add address=172.16.146.254/24 interface=ether4-DMZ network=172.16.146.0
    /ip dns
    set allow-remote-requests=yes servers=10.128.20.1
    /ip firewall filter
    add action=accept chain=forward connection-state=established,related
    /ip firewall nat
    add action=src-nat chain=srcnat out-interface=ether1-WAN to-addresses=10.128.20.7
    add action=dst-nat chain=dstnat dst-address=10.128.20.7 dst-port=443 in-interface=ether1-WAN protocol=tcp to-addresses=172.16.146.252 to-ports=443
    add action=masquerade chain=srcnat dst-address=172.16.146.252 dst-port=443 out-interface=ether2-LAN protocol=tcp to-addresses=10.128.20.7
    /ip route
    add disabled=yes distance=1 dst-address=192.168.35.0/24 gateway=10.128.20.5
    add disabled=no dst-address=192.168.145.0/24 gateway=172.16.1.1
    add disabled=no dst-address=0.0.0.0/0 gateway=10.128.20.1

    1. В последнем правиле firewall nat у вас указан out-interface=ether2-LAN, хотя судя по ip adresses должен быть ether4-DMZ, также to-addresses= должен указывать на ip маршрутизатора в этой сети (172.16.146.254), а не внешний адрес

  8. Добрый день!
    Спасибо за статью.
    Можно немного разгрузить роутер, изменив второе правило
    /ip firewall nat
    add chain=srcnat packet-mark=nat-loopback action=masquerade comment=”NAT Loopback replace address”

    на правило
    /ip firewall nat
    add chain=srcnat packet-mark=nat-loopback action=src-nat to-addresses=”локальный адрес роутера”

  9. у меня wan динамический, использую следующий способ: ip – cloud включаем ddns, ставим нужный update interval, получаем dns name (xxx.sn.mynetname.net), в firewall – address list создаем список WAN_IP с адресом xxx.sn.mynetname.net. И теперь вместо dst-address=203.0.113.5 в правилах пишем dst-address-list=WAN_IP

    1. Можете просто указывать интерфейс wan вместо ip.
      in-interface=ether1, либо interface-list=WAN если из конфигурации по умолчанию

      1. Здравствуйте. А можно подробнее пожалуйста с динамическим адресом провайдера? Все понятно а тут зациклился.

  10. Не подскажешь за проброс порта, надо пробросить порт на адрес 192.168.1.10 через адрес 82.140.112.122 (https://ru.imgbb.com/)
    В микротике сделал проброс порта на второй конец туннеля + включил masquerade дальше указал dstnat на 192.168.168.2, дальше кинетик делает переадресацию на 192.168.1.10 тем самым входит на ssh server “192.168.1.10” но зато адрес у всех становится (192.168.168.1) – есть способ сделать нормальные IP адреса у подключившихся к ssh серверу?

    1. Если я правильно понял, то через внешний узел просто так нельзя прозрачно перенаправить трафик. В случае HTTP-based протоколов нужно проксировать L7 прокси сервером со всеми заголовками типа X-Forwarded-For.

      Если L7 протокол не поддерживает подобного (типа ssh), то вам необходимо построить туннель между keenetik и routeros, и маршрутизировать по внутренним адресам, примерно так: https://ibb.co/C0hGVZD
      Причем дополнительно, на keenetik потребуется организовать проверку, откуда пришло соединение: из WAN или из туннеля, и закреплять пакеты за ним. На ROS это можно сделать с помощью меток, на keenetic не знаю

      1. RouterOS не может пинговать 192.168.1.10, так что с чего ты взял что так прокатит?
        Чтобы RouterOS мог пинговать 192.168.1.10 для этого необходимо протянуть EOIP туннель с RouterOS до Keenetic(либо openwrt)
        Дальше на RouterOS запускается функция “скан IP адресов” указав интерфейс туннеля.
        Так же На keenetic запускаю функцию бриджа lan портов(https://ibb.co/HhmNT6G).
        Домашняя сеть это имеется ввиду подключенные устройства к роутеру keenetic.
        Так же на routeros даю интерфейсу EOIP адрес 192.168.1.11.

          1. Так keenetic могу заменить на openwrt, либо запустить виртуальную машину с routeros.

  11. Как сделать DST-NAT в другую подсеть за mikrotik?
    с R-01 протянут L3 туннель до R-02, 1: конец туннеля имеет адрес 192.168.160.9/24, 2: конец туннеля имеет адрес 192.168.160.10/24.
    Предполагается что на внешний IP R-01 будет заходить пакет а дальше отправляться во второй конец туннеля при помощи функций проброса порта, пакет попав на R-02 должен проброситься уже на машину с адресом 192.168.20.10
    https://ibb.co/1M6BBqf

    1. Также, как и обычный dst-nat, с указанием ip в другой подсети. Там проверок никаких не стоит, dst-nat это просто правило преобразования адресов, срабатывающее до маршрутизации. А уже на основании таблицы маршрутизации роутер определяет куда пойдет пакет. Если подходящая запись есть – туда и пойдет. Сложнее сделать, чтоб ответный пакет прошелся по такому же обратному пути, не сломав сессию (ее установление)

  12. Спасибо! Работает, при обращении по имени к веб-серверу, находящемуся в этой же локалке из локальной сети.

  13. Через packet mark не прокатило – слишком много других маркировок в mangle для построения queue tree. Попробовал сделать через connection mark – вроде бы работает…

  14. Вы лично делали как полностью говорит документация Микротика, копируя оную??
    “/ip firewall nat
    add chain=srcnat src-address=192.168.88.0/24 \
    dst-address=192.168.88.5 protocol=tcp dst-port=80,443 \
    out-interface=LAN action=masquerade”

    \\ Оно не_работает \\

    мудацкая документация микротика.
    out-interface=LAN – что за интерфейс такой?? есть interface list c таким именем, есть bridge (с локальными интерфейсами) . Bridge поставим – тож не будет работать.

    Рабочий вариант есть у них на форуме, но там в сумме правил для NAT не 2, а 3

    1. Автору – респект!
      Да тоже не сразу дошло про аут-интерфейс в микротике.
      В итоге для таблицы mangle нужно указать входящий интерфейс bridge, а в правило маскарадинга в NAt out-interface вообще не указывать.
      И всё работает замечательно.
      Да, локальные адреса маскируются маршрутизатором, но зато внешние nginx и faiil2ban прекрасно видят и фильтруют.

    2. > out-interface=LAN — что за интерфейс такой?? есть interface list c таким именем, есть bridge (с локальными интерфейсами) . Bridge поставим — тож не будет работать.

      У меня есть bridge с названием “LAN”, которые подразумевает локальную сеть. Замените на своё имя будет работать.

  15. Сделал через статический ДНС. Сколько же я мудохался прежде чем найти эту статью. Спасибо.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *