Внутри компьютера, между процессами
Сначала давайте посмотрим, как один компьютер различает одновременные соединения.
Большинство транспортных протоколов, таких как TCP, UDP, SCTP, используют два порта, источник и пункт назначения, то есть один на любом конце соединения. То есть пакеты не просто проходят через порт; вместо этого они путешествуют из порта X в порт Y.
Порт назначения обычно хорошо известен (80 для HTTP, 53 для DNS…), но порт источника обычно выбирается случайным образом самой ОС, что также гарантирует уникальность комбинации src/dst.
Поэтому, когда ваш браузер устанавливает несколько соединений «с портом 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
.)