Внутри компьютера, между процессами
Сначала давайте посмотрим, как один компьютер различает одновременные соединения.
Большинство транспортных протоколов, таких как TCP, UDP, SCTP, используют два порта, источник и пункт назначения, то есть один на любом конце соединения. То есть пакеты не просто проходят через порт; вместо этого они путешествуют из порта X в порт Y.
Назначения порт, как правило, хорошо известен (80 для HTTP, 53 для DNS ...), но исходный порт обычно случайным образом выбираются самой ОС, которая также гарантирует, что сочетание SRC / ДСТ является уникальным.
Поэтому, когда ваш браузер устанавливает несколько соединений «с портом Yahoo 80», все они на самом деле имеют разные исходные порты, а ОС хранит таблицу сокетов, такую как:
PROCESS PROTO LOCAL REMOTE STATE 9894/firefox tcp 192.168.6.175:39163 google.server:80 established 9894/firefox tcp 192.168.6.175:52909 yahoo.server:80 established 17463/chrome tcp 192.168.6.175:64981 yahoo.server:80 established 9894/firefox udp 192.168.6.175:4984 8.8.8.8:53 --
Поэтому, когда ОС получает пакет TCP от yahoo.server:80
локального порта 52909, она может сопоставить его с конкретным соединением, установленным Firefox.
Важно отметить, что это не имеет ничего общего с NAT еще и происходит точно так же, даже если вы непосредственно связаны. (NAT будет использовать его, хотя.)
(Вы можете увидеть эту таблицу, используя netstat -n
различные графические инструменты в Windows. Часто «локальный / удаленный» помечается как «источник / назначение», хотя это не совсем точно.)
В сети NATed, между компьютерами
Ответ на ваш вопрос о NAT очень похож, только все сделано в большем масштабе.
Маршрутизатор, выполняющий NAT, хранит таблицу «состояний», содержащую как внутренние, так и внешние адреса и порты. Например, если два ваших HTTP-запроса использовали отдельные TCP-соединения, они могут быть отслежены как:
PROTO ORIG-SRC ORIG-DST REPLY-SRC REPLY-DST 6/tcp 192.168.6.42:52909 yahoo.server:80 yahoo.server:80 your.public.ip.addr:52909 6/tcp 192.168.6.175:39163 yahoo.server:80 yahoo.server:80 your.public.ip.addr:39163 6/tcp 192.168.6.175:52909 yahoo.server:80 yahoo.server:80 your.public.ip.addr:28330 17/udp 192.168.6.175:4984 8.8.8.8:53 8.8.8.8:53 your.public.ip.addr:4984
Когда маршрутизатор получает пакет от REPLY-SRC (Yahoo), адресованный REPLY-DST (ваш публичный IP-адрес), он знает, что реальное место назначения должно быть взято из столбца ORIG-SRC для отмены NAT.
(Если нет соответствующего состояния, то обрабатываются настроенные вручную правила переадресации порта. Если все еще нет соответствия, тогда пакет действительно предназначался для самого маршрутизатора.)
Обратите внимание, что таблица состояний содержит адреса и порты, что позволяет различать несколько подключений к одному серверу по комбинации портов. В моем примере два компьютера случайно использовали одну и ту же комбинацию портов, поэтому для 2-го соединения также были переведены порты.
(На самом деле, некоторые NAT смотрят только на порт и полностью игнорируют адрес источника; это уменьшает количество возможных соединений, но значительно упрощает одноранговым программам выполнение «пробивки NAT».)
Такое состояние сохраняется даже для протоколов без установления соединения, таких как UDP или ICMP, поэтому срок действия записей истекает через некоторый интервал бездействия, даже если нет явного пакета «закрытое соединение». (Таблица состояний на самом деле является частью брандмауэра, поэтому даже если NAT не завершен, маршрутизатор все равно может использовать его для различения «активных» соединений и паразитных пакетов.)
(Если ваш маршрутизатор основан на Linux conntrack -L
или cat /proc/net/nf_conntrack
покажет эту таблицу. Для OpenBSD или pfSense попробуйте pfctl -s state
.)