Pull to refresh

Так ли страшен Symmetric NAT

Reading time 3 min
Views 36K
Задача прямого соединения машин, находящихся за NAT'ом стара как мир и я думаю, что многие слышали про UDP Hole Punching. Когда я только начинал интересоваться вопросом, я утвердился во мнении, что symmetric nat пробить невозможно и пытаться даже не стоит. Однако совсем недавно мне попалась статья в которой утверждалось, что симметричный нат — это не приговор.

Давайте разберемся.

Типы NAT


Традиционно во многих статьях в Интернете все NATы делят на четыре типа:
  • Full-cone NAT;
  • Address-restricted cone NAT;
  • Port-restricted cone NAT;
  • Symmetric NAT

На самом деле это неверно. Точнее не совсем верно. У любого NAT’a есть две основных характеристики:

1) фильтр входящих пакетов;
2) правило маппинга портов.

Первая характеристика как раз описана в большинстве статей и означает, какие входящие пакеты передавать машине за NAT’ом: все (no filter – Full cone), с конкретного адреса (address-restricted) или с конкретного адреса и порта (port-restricted).

Вторая характеристика же присуще только симметричному НАТ’у, так как первые три типа пытаются сделать отражение один в один. Например, если клиент посылает пакет с внутреннего адреса 192.168.10.24:62145, то от роутера пакет пойдет с адреса 1.2.3.4:62145. Причем вне зависимости от адреса получателя.

Symmetric NAT


А теперь детальнее про симметричный NAT. Сразу оговорюсь, что фильтры входящих пакетов тоже могут быть любые (no filter, address-restricted или port-restricted). И единственное отличие этого типа NAT’a от предыдущих как раз в выборе исходящего порта на роутере, он почти наверняка будет отличаться от исходного порта на клиенте. Вернувшись к предыдущему примеру отражение может быть таким: 192.168.10.24:62145 -> 1.2.3.4:1274.

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

  • Порт может оставаться всегда одним и тем же, в не зависимости от получателя (cone);
  • Порт может оставаться одним и тем же для конкретного адреса получателя (address);
  • Порт может оставаться одним и тем же лишь для конкретного адреса и порта получателя (port);


При этом есть еще и правила для выбора следующего порта:
Это может быть какая-то дельта (+1/-1 или +10/-10) или вообще каждый раз случайно.
Кроме того видел один NAT у которого каждый последующий порт отстоял от предыдущего на случайное число, но всегда кратное 4096.

Вместо заключения


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

Ну что же мы подобрались к сути и цели статьи. Ответу на вопрос

«Можно ли определить правило распределения портов и дельту, находясь за NAT’ом?»

Поможет нам в этом STUN, конечно. Наша задача сделать четыре запроса к разным адресам и портами используя один сокет (один локальный порт) и оценить результаты:
Мы сможем понять каким образом распределяются исходящие порты (адрес или порт) и попробовать рассчитать ту самую дельту.

И тут я призываю хабрасообщество мне помочь со статистикой. На просторах Интернета был найден простенький stun клиент, немножко допилен кувалдой и вот что получилось:

Исходник

Пользователи Линукса прекрасно знают как это скомпилировать.
Вот так
gcc -lpthread -o stun stun.c


Под винду отлично компилится студией, вот тут бинарник, если студии под рукой нет.

Да простит меня stun.counterpath.net за хабра эффект :)

Вот мои результаты, но у меня не симметричный НАТ и не интересно:

Results
tests: 1010
NAT present: 1
first preserved port: 1
preserves port: 0
type: Port restricted NAT
mapped ports: 55907 55907 55907 55907


Всем спасибо за помощь!

udp: Оставляйте, пожалуйста, ваши результаты в комментариях, даже если НАТ не симметричный. Ведь в любом случаю важно знать распиновку по типам.
Tags:
Hubs:
+13
Comments 14
Comments Comments 14

Articles