Открываем порты за NAT при помощи NAT-PMP и UPnP IGD



Ранее я много раз слышал, что UPnP каким-то образом умеет самостоятельно открывать порты (производить Port Forwarding на роутере) по запросу от хоста из локальной сети. Однако, то, каким именно образом это происходит, и какие протоколы для этого используются, доселе было покрыто для меня пеленой тумана.

В данной статье я хочу кратко рассказать, как работают два механизма для проброса портов, а именно NAT Port Mapping Protocol и Internet Gateway Device (IGD) Protocol, входящий в набор протоколов UPnP. К своему удивлению я обнаружил, что в рунете информация по данному вопросу более чем скудна, что и сподвигло меня на написание данной заметки.

Для начала приведу краткий FAQ:

Q: Для чего нужны данные протоколы?
A: Для формирования на маршрутизаторе правила проброса определенного TCP/UDP порта (Port Forwarding) не вручную, а «автоматически», т.е. по запросу от хоста во внутренней сети.

Q: Как это реализуется?
A: Устройство за NAT отправляет маршрутизатору запрос с указанием внутреннего и внешнего номеров портов и типа протокола (TCP/UDP). Если указанный внешний порт свободен, маршрутизатор формирует у себя правило трансляции и рапортует запросившему компьютеру об успешном выполнении запроса.

Q: Проводится ли на маршрутизаторе аутентификация/авторизация запросов на открытие порта?
A: Нет, не проводится.

Теперь же рассмотрим работу данных протоколов более подробно (под катом).

Port Mapping Protocol


NAT-PMP описан в RFC 6886. Для своей работы он использует UDP-порт сервера 5351.

Рассмотрим работу протокола на конкретном примере — торрент-клиенте Vuze 5.7 для Windows 7.

Примечание: NAT-PMP во Vuze по умолчанию выключен. Его необходимо активировать в настройках плагинов.

1. Запускаем Wireshark. В строке фильтра вводим nat-pmp
2. Запускам Vuze.
3. Останавливаем перехват пакетов, смотрим результаты.

У меня получилось следующее:



Всего видим 6 пакетов (3 запроса и 3 ответа).

Первые 2 это запрос внешнего адреса маршрутизатора и ответ с указанием этого самого адреса. Не будем на них подробно останавливаться и лучше рассмотрим, как происходит маппинг портов на примере пакетов 3-4.

Запрос:



Здесь мы видим, что запрашивается проброс внешнего UDP порта 48166 на такой же внутренний порт. Интересно, что внутри протокола не указывается адрес хоста, на который должна происходить трансляция (Inside Local в терминологии Cisco). Это означает, что маршрутизатор должен взять адрес источника пакета из IP-заголовка и использовать его в качестве Inside Local.

Параметр Requested Port Mapping Lifetime ожидаемо означает время жизни записи в таблице трансляций.

Ответ:



Как мы видим, маршрутизатор предполагаемо создал запрашиваемую трансляцию и ответил кодом Success. Параметр Seconds Since Start of Epoch означает время с момента инициализации таблицы трансляций (т.е. с момента последней перезагрузки роутера).

Маппинг TCP-портов происходит точно также и отличается только значением поля Opcode.

После того, как приложение прекратило использовать данные порты, оно может послать маршрутизатору запрос на удаление трансляции.
Главное отличие запроса на удаление от запроса на создание заключается в том, что параметр Lifetime устанавливается в ноль.

Вот что произойдет, если мы закроем Vuze.

Запрос:



Ответ:



На этом рассмотрение NAT-PMP закончено, предлагаю перейти к несколько более «мудреному» UPnP IGD.

Internet Group Device Protocol


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

Однако, в отличие от NAT-PMP, IGD не использует фиксированный номер порта сервера, поэтому перед тем, как обмениваться сообщениями, нужно сперва этот порт узнать. Делается это при помощи протокола SSDP (данный протокол является частью UPnP и используется для обнаружения сервисов).

Запускаем торрент-клиент. Он формирует SSDP-запрос и отсылает его на мультикастовый адрес 239.255.255.250.



Маршрутизатор формирует ответ и отправляет его уже юникастом:



Внутри ответа мы можем увидеть URL для взаимодействия с маршрутизатором по протоколу IGD.

Далее Vuze подключается к маршрутизатору по указанному URL и получает XML с информацией о данном устройстве, в том числе содержащую набор URI для управления некоторыми функциями маршрутизатора. После того, как нужный URI найден в rootDesc.xml, Vuze отправляет SOAP-запрос на содание NAT-трансляции по найденному URI.

Примечание: до того, как запросить создание трансляции, Vuze заставил маршрутизатор перечислить все имеющиеся Port Forwarding'и. Для чего это было сделано, я могу лишь догадываться.

SOAP-запрос на создание трансляции UDP-порта:



Как говорилось ранее, нужный URI (идет сразу после POST) Vuze взял из rootDesc.xml. Для добавления трансляции используется функция с названием AddPortMapping.

Также можно отметить, что, в противоположность NAT-PMP, Inside Local-адрес указывается внутри самого протокола.

Аналогично NAT-PMP, при закрытии торрент-клиента маппинги проброшенных портов удаляются. Делается это функцией DeletePortMapping:



Можно заметить, что для удаления правила достаточно указать только тип протокола (UDP) и номер внешнего порта, не указывая остальные параметры.

Заключение


В данной статье мы рассмотрели два достаточно простых способа по созданию на домашнем роутере правил Port Forwarding по команде от хоста из локальной сети. Остается лишь отметить, что если вы считаете работу данных протоколов угрозой безопасности вашей домашней сети, то их можно попытаться выключить (хотя, конечно, гораздо лучше доверить вопросы безопасности утилите, которая для этого предназначена — файрволу). В случае моего Zyxel Giga II, на котором, к слову, и проводились все тесты, это делается CLI-командой no service upnp (примечательно, что в веб-интерфейсе опция включения/отключения UPnP отсутствует).
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 14

    0
    Как я понимаю uPNP не будет работать за двумя роутерами?

    В частности
    ПК IP 192.168.1.100 шлюз 192.168.1.1
    Домашний роутер 192.168.1.1, WAN PPPoE IP 10.7.6.2 шлюз 10.7.6.2, uPNP включен, порт 22333 в списке проброшеных виден
    Внешний IP 80.90.110.190 (изменен)
    Маршрут до 8.8.8.8
    1 192.168.1.1
    2 80.90.110.190

    Снаружи 80.90.110.190:22333 — недоступен

    Как я думаю 80.90.110.190 это роутер провайдера там или uPNP не работает или uPNP не работает через 2 роутера.
      0
      Мультикаст по умолчанию, грубо говоря, работает в пределах одного Broadcast-сегмента, так что если ваш маршрутизатор не ретранслирует мультикаст до провайдера, то не заработает.
        0
        Оборудование уровня Enterprise/ISP как правило не поддерживает UPnP, поэтому вам вряд ли удастся повлиять на маршрутизатор провайдера при помощи описанных в статье протоколов.

          0
          У провайдера смайл так же порты не пробросить. PPPoE c ip из частного сегмента адресов, пробрасываешь порты на роутере, а снаружи они закрыты. Маршрутизатор провайдера не обрабатывает их.
        0
        Вот, вопрос в тему:
        Есть 2 скрипта на питоне, которые гоняют данные через сеть (по tcp или udp — не важно, можно переписать).
        Работают они на машинах, каждая из которых за 2 натами (провайдер+роутер), либо одна за 2мя, а вторая за одним (usb-свисток).
        За всё время существования проекта перепробовал тучи разных примочек — от ipv6 туннеля и openvpn-на-vps до специализированных сервисов вроде ngrok, но хотелось бы реализовать прямую передачу без костылей с прогоном трафика через сервер.
        Кто нибудь может расписать, как сделать udp hole punching «для чайников»? (или что мне подойдёт лучше всего)
          0
          Наличие сервера (т.е. того, кто слушает порт) обычно предполагает наличие реального IP. Если у вас обе стороны коммуникации находятся за провайдерским натом, причем оба провайдера разные, причем оба не предоставляют сервисов по пробросу портов (либо получению реального IP), то мне сложно представить, как можно организовать их коммуникацию без участия 3 стороны.
            0
            Как уже выше обозначили, если 2 компьютера находятся за NAT-ом, то для прямого соединения необходима третья сторона. Не обязательно, чтобы это был ваш выделенный сервер. Достаточно любого IM, например xmpp. Задача: доставить каждой из машин данные для подключения, т.е. IP (белый который NAT, и порт).
            Но надо иметь ввиду, что не каждый NAT позволяет провести UDP hole punch. Не стоит его рассматривать как гарантированный канал.
            Можно попробовать соединиться с помощью примера icedemo из комплекта PJSIP. После этого понять стоит ли в эту строну копать или нет.
            Интересный вариант: организовать канал через toxcore, но в случае с Tox децентрализация дает о себе знать — соединение происходит не мгновенно.
            Есть аналог hamachi — ZeroTier, можно глянуть в его сторону, но он, вроде, в альфе еще.
            0
            На своём маршрутизаторе отключил NAT-PMP на всякий случай после того, как в его реализации на многих роутерах нашли уязвимость, позволяющую злоумышленнику перехватывать весь трафик.
            На работе торрент-клиентов это, вроде, не сказалось, тот же uTorrent нормально пробрасывает порт при включенном UPnP, но без NAT-PMP.
            +1
            до того, как запросить создание трансляции, Vuze заставил маршрутизатор перечислить все имеющиеся Port Forwarding'и. Для чего это было сделано, я могу лишь догадываться
            Могу предположить, это для того, чтобы не создавать уже существующий (не закрытый ранее — например, из-за грохнувшегося приложения) проброс. Тут, правда, возникает вопрос — что лучше, пытаться повторно использовать потенциально чужой проброс или захламлять маршрутизатор всё новыми пробросами.
              0
              «Потенциально чужим пробросом» на свободный локальный порт можно и воспользоваться.
              0
              Прошу прощение за возможно идиотский вопрос — на cisco (ASA и первое поколение роутеров) вообще никак? Попадались мне какие-то tcl-костыли, но не осилил. Может кто знает правильный путь?
                0
                Где-то на форумах циски встречался фидбэк от инженера — «несекурно, этого у нас не будет никогда».
                Правильный путь — руками прописать статический port-forward, и на торент-клиенте не использовать случайный порт)
                  0
                  Зато Juniper сделал поддержку PCP.

              Only users with full accounts can post comments. Log in, please.