Так ли страшен Symmetric NAT
Задача прямого соединения машин, находящихся за 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: Оставляйте, пожалуйста, ваши результаты в комментариях, даже если НАТ не симметричный. Ведь в любом случаю важно знать распиновку по типам.