Добрый день, коллеги.
Некоторое время назад я заинтересовался этой темой.
Поиск дал много материала, в ходе изучения которого возник ряд вопросов и хотелось проверить некоторые теоретические положения на практике.
Если кому-то интересно, сделайте это.
Для тех, кто не в курсе, краткое описание, что такое Symmetric NAT.
Рассмотрим простую схему, в которой
хост1, хост2 — хосты пользователей за NAT
NAT1, NAT2 — периферийные устройства, обеспечивающие NAT
Когда хост1 инициирует исходящее соединение (TCP или UDP) к определенному реальному_IP, устройство NAT1 заменяет исходный IP в исходящем пакете на свой (не обязательно на свой, но мы примем это для простоты и ясности), а также обычно заменяет PORT_SRC на случайный PORT_SRC1. хост1 ____ PORT_SRC, PORT_DST ---> устройство NAT1 PORT_SRC1, PORT_DST ----> real_IP
Таким образом, NAT будет симметричным, если ответный пакет real_IP от хоста передается устройством NAT1 тогда и только тогда, когда исходный IP-адрес в таком ответном пакете равен real_IP, исходный порт будет PORT_DST, а порт назначения — PORT_SRC1. То есть real_IP будет отвечать со своего адреса, с того же порта, к которому было осуществлено подключение, и на тот же порт, с которого было осуществлено исходящее подключение от устройства NAT1. Нетрудно заметить, что термин «симметрия» здесь вставлен не просто так.
Что мы имеем, когда стоит задача «пробить» симметричный NAT и позволить хостам за ним общаться напрямую? В общем случае имеем следующую простую схему.
хост1 ----> NAT1 SRC1_случайный, DST1_необязательный ---->
< — DST2_optional, SRC2_random НАТ2 < - host2
SRC1_random — исходный порт после подмены NAT устройством NAT1;
DST1_optional — порт назначения для исходящего соединения, установленного с хоста1 через NAT1, может быть выбран нами;
DST2_optional — порт назначения для пакета, отправляемого с хоста2 через NAT2 на NAT1, может быть выбран нами;
SRC2_random — исходный порт после подмены NAT устройством NAT2.
Если внимательно присмотреться к этой схеме, то трудности при «пробое» очевидны.
Для того чтобы обмен трафиком работал, должно выполняться следующее: SRC1_random = DST2_optional и DST1_optional = SRC2_random.
Устройства хост1 и хост2 не могут управлять портами SRC1_random и SRC2_random. В общем, они будут действительно случайными, плюс будут зависеть от IP-адреса и порта назначения.
Множество материалов, найденных поиском по этой теме, игнорировали этот простой факт, полагая, что для выяснения этих неизвестных достаточно простого STUN-сервера.
Как будто да.
Если взять NAT, организованный, скажем, с помощью iptables, то конструкции типа -t nat -A POSTROUTING -j МАСКАРАД или -t nat -A POSTROUTING -j SNAT --to-source заменит только исходный IP, исходящий порт останется таким же, как на клиенте.
Таким образом, задача значительно упрощается и множество статей, описывающих роль посредника для этой технологии обхода NAT, начинают попадать в цель.
Но это частный и простейший случай.
Для тех же iptables указанные конструкции можно заменить на -t nat -A POSTROUTING -j МАСКАРАД… --random или -t nat -A POSTROUTING -j SNAT --к источнику.
--random и ситуация станет менее веселой.
Исходящий порт начнет выбираться случайным образом во время преобразования NAT. Итак, после внимательного рассмотрения приведенных выше диаграмм мы имеем следующие проблемы.
Ни хост1, ни хост2 не знают о SRC1_random и SRC2_random; они могут влиять на них только косвенно, например, меняя исходный порт для своих исходящих пакетов или устанавливая достаточный таймаут между отправкой данных, чтобы записи для NAT-трансляций на NAT-устройствах успели устареть и сброситься.
Host2 должен, помимо прочего, узнать DST1_optional (в общем случае порт можно согласовать заранее, но мы будем рассматривать худший вариант).
Не вдаваясь в длинные объяснения необходимости посредника, сразу опишу примерный алгоритм действий для всех участников обмена.
1. Строго необходим посредник, с которым хост1 и хост2 устанавливают полноценные управляющие соединения со свободным двусторонним потоком трафика.
Инициаторами таких сеансов управления являются хосты за NAT. Посредник распространяет информацию об их белых IP-адресах конечным хостам.
2. Допустим, инициатором целевого соединения/клиента будет хост1, а для хоста2 соединение будет входящим, т.е.
он будет выполнять роль сервера.
3. Хост1 начинает отправлять пакеты на реальный адрес NAT2, выбрав DST1_optional.
4. Хост1 через управляющее соединение сообщает посреднику о выбранном DST1_optional и продолжает отправлять пакеты с теми же параметрами (порт источника, порт назначения) для поддержания постоянной трансляции в NAT1, чтобы SRC1_random не менялся.
Задержку между посылками можно определить экспериментально; ввиду тривиальности проблемы я ее не описываю и не включаю в этот текст.
5. Посредник сканирует NAT1, заменяя IP источника на адрес NAT2, предоставляя порт источника DST1_по желанию и пробуя порт назначения в диапазоне от 1024 (или весь диапазон 65535?) и выше.
Все это необходимо, ведь ранее мы решили, что NAT не зря называется симметричным.
Когда в результате перебора (если нас к этому времени не забанили на NAT1) мы наконец отправляем пакет с портом назначения SRC1_random, то такой пакет, если только не какие-то особо хитрые механизмы защиты, выходящие за рамки NAT функциональность мешает, будет передана на хост1. Это то, что он обнаруживает и затем уведомляет посредника по каналу управления, и посредник запоминает угаданное значение SRC1_random.
6. Брокер сообщает о канале управления хосту 2 SRC1_random.
7. Хост2 начинает отправлять пакеты на внешний адрес NAT1, порт назначения в этих пакетах должен быть DST2_optional = SRC1_random. Он будет вынужден это делать до тех пор, пока SRC2_random, выбранный устройством NAT2, не совпадет с DST1_optional.
Когда произойдет это долгожданное совпадение, возможны два варианта.
Первый.
Такой пакет дойдет до хоста1, который уведомит посредника, посредник уведомит хост2 и «счастливый» сеанс продолжится.
Второй.
Хост2, не желая лишний раз злить NAT1 «слотированием», изменил IP-ttl в своих исходящих пакетах на такое значение, чтобы они проходили через NAT2, но не доходили до NAT1. В этом случае трансляции создаются на NAT2, пакеты не доходят до NAT1, но при создании заветной трансляции пакет идет от хоста1 (причем мы не забыли, что он поддерживает свою трансляцию описанным ранее методом, а именно «долбится» на NAT2 с постоянными параметрами) дойдет до хоста2, который в свою очередь оповестит посредника и так далее.
Как видите, в общем случае пробить симметричный NAT — не такая уж простая и быстрая задача.
На определенных реализациях (вспомните iptables) это можно существенно упростить и превратить в процедуру с гарантированным успехом, но, повторюсь, не в общем случае.
Каковы наиболее «узкие места» описанного алгоритма? 1. Необходимость подмены в пункте 5. У посредника должен быть такой метод доступа к сети, который бы позволял это сделать, не вызывая проблем у провайдера.
2. Сканирование большого диапазона портов в пункте 5. Еще раз повторюсь, в случае «правильного» NAT хост1 не может просто установить соединение с посредником и считать, что SRC1_random в случае подключения к NAT2 будет то же самое, при прочих равных условиях.
Изменение адреса назначения приведет к изменению SRC1_random. Сканирование, конечно, можно проводить как достаточно быстро и агрессивно, так и более тщательно, но дольше.
В любом случае это слабое место.
3. Действия из пункта 7 могут занять неопределенно долгое время.
Именно этот момент пробудил во мне любопытство и желание попробовать.
4. И конечно, тот, кому надоело читать столько писем, может сказать: «Какого черта это надо, гоните весь целевой трафик через посредника и всё!» Здесь, конечно, трудно спорить; перед теми прошу прощения за время, отнятое этим текстом.
Теперь попрактиковаться.
Возможно разочарую тех, кто интересовался темой, но я не писал посредника :) Его роль сыграл tcpdump в нужном месте и в нужное время, а также глаза и руки автора :) Но я все же получили некоторые интересные результаты.
Так.
У нас есть рабочая станция Windows с 3G = хост1. Модемное соединение показало серый адрес 10.140.80.130. Это внутренний адрес хоста 1 за NAT. У нас есть роутер AT AR-750s с белым адресом xx.xx.xx.xx и хостом2 непосредственно за этим роутером.
Выбираем произвольный DST1_ по желанию, в моем случае он был равен 21393.
Начинаем отправлять UDP-пакеты с хоста1 на xx.xx.xx.xx:21393 с интервалом в 10 секунд.
Минуя этап злого сканирования, мы передаем на хост2 «секретную» информацию о порте 21393, а также «шпионскую» информацию о том, что SRC1_random за NAT сотового оператора у нас 45499 (ну и IP с которого нас съедает NAT тоже = гг.
гг.
гг.
гг).
С хоста2 начинаем «ломать» на yy.yy.yy.yy:45499 и ждем, пока нам повезет и наш исходящий пакет получит исходный порт за NAT, равный 21393. С ttl не баловался, определил факт поломки со снифферами на хосте1 и хосте2. Скорость генерации пакетов с хоста2 составила ~5 пакетов в секунду.
При этом маршрутизатор NAT2 был слегка загружен посторонним (пользователи бы это услышали) трафиком.
Первая «поломка» произошла примерно через 8 часов после начала эксперимента.
Потом их было еще несколько, потому что всю эту технику оставили работать на ночь.
Последующие стали происходить в несколько раз быстрее, тут можно пофантазировать о влиянии «постороннего» трафика.
Вот так выглядел «прорыв».
Вывод является выборочным и включает только «счастливые» пакеты с необходимым совпадением.
Вывод сниффера на «хитрой» точке сбора трафика, где он (трафик) виден после NAT на внешнем интерфейсе роутера AR-750
02:19:05.060809 IP xx.xx.xx.xx.21393 > yy.yy.yy.yy.45499: UDP, длина 0
05:07:00.178149 IP xx.xx.xx.xx.21393 > yy.yy.yy.yy.45499: UDP, длина 0
06:28:35.355623 IP xx.xx.xx.xx.21393 > yy.yy.yy.yy.45499: UDP, длина 0
07:16:29.764069 IP xx.xx.xx.xx.21393 > yy.yy.yy.yy.45499: UDP, длина 0
11:28:06.899109 IP xx.xx.xx.xx.21393 > yy.yy.yy.yy.45499: UDP, длина 0
Вывод сниффера на хосте1, на котором обнаружен сбой (время не синхронизировано, отсюда и некоторое несоответствие временных меток и распечатки из дампа трафика хоста2).
02:18:20.480468 IP xx.xx.xx.xx.21393 > 10.140.80.130.2429: UDP, длина 0
05:06:15.496093 IP xx.xx.xx.xx.21393 > 10.140.80.130.2429: UDP, длина 0
06:27:50.464843 IP xx.xx.xx.xx.21393 > 10.140.80.130.2429: UDP, длина 0
07:15:44.839843 IP xx.xx.xx.xx.21393 > 10.140.80.130.2429: UDP, длина 0
11:27:21.589843 IP xx.xx.xx.xx.21393 > 10.140.80.130.2429: UDP, длина 0
Еще был результат дампа непосредственно на хост2, в котором было видно, что пакеты из пункта 4, поддерживающие неизменную трансляцию в NAT1, начали доходить до хоста2, но я его сбросил.
Это такой не совсем честный эксперимент. Но он показал, что даже при относительно низкой частоте перебора в пункте 7 желаемого результата можно достичь за относительно разумное время.
Он может стать еще умнее с помощью более агрессивной грубой силы.
Для «промышленного» использования он, конечно, не пригоден, но… Но это возможно.
Описанный алгоритм и эксперимент дают пищу для размышлений на тему ускорения-оптимизации-многопоточности_подхода и так далее.
UPD: Забыл упомянуть, что с хоста2 пакеты отправлялись со сменой порта-источника, чтобы порт-источник тоже менялся за NAT2, ждать, пока сдохнет трансляция на NAT2, слишком дорого.
Теги: #сети #НАТ #информационная безопасность
-
Персонализируйте Готовые Макеты Myspace
19 Dec, 24 -
Режим Snark В Sudo!
19 Dec, 24 -
Как Работает Штрих-Код?
19 Dec, 24 -
Самые Яркие Гаджеты 2014 Года
19 Dec, 24 -
Взгляд На Блог «По-Старому»
19 Dec, 24 -
Встреча На Эльбе?
19 Dec, 24