Уильям Стивенс - UNIX: разработка сетевых приложений
Мы отделяем IP-адрес от номера порта символом «:», потому что это обозначение используется в HTTP и часто встречается в других местах. Программа netstat отделяет номер порта от IP-адреса точкой, но иногда это приводит к затруднениям, потому что точки используются как в доменных именах (freebsd.unpbook.com.21), так и в записи IPv4 (12.106.32.254.21).
Когда мы обозначаем звездочкой локальный IP-адрес, такое обозначение называется универсальным адресом, а звездочка — символом подстановки (wildcard). Если узел, на котором запущен сервер, поддерживает множественную адресацию (как в нашем примере), сервер может указать, что он хочет принимать входящие соединения, которые приходят только для одного определенного локального интерфейса. Сервер должен выбрать либо один определенный интерфейс, либо принимать запросы от всех интерфейсов, то есть сервер не может задать список, состоящий из нескольких адресов. Локальный адрес, заданный с помощью символа подстановки, соответствует выбору произвольного адреса из определенного множества. В листинге 1.5 перед вызовом функции bind произвольный IP-адрес в структуре адреса сокета задан с помощью константы INADDR_ANY.
Через некоторое время на узле с IP-адресом 206.168.112.219 запускается клиент и выполняет активное открытие соединения с IP-адресом сервера 12.106.32.254. В этом примере мы считаем, что динамически назначаемый порт, выбранный клиентом TCP, — это порт 1500, что отражено на рис. 2.12. Под клиентом мы показываем его пару сокетов.
Рис. 2.12. Запрос на соединение от клиента к серверу
Когда сервер получает и принимает соединение клиента, он с помощью функции fork создает свою копию, давая возможность дочернему процессу обработать запрос клиента, как показано на рис. 2.13 (функцию fork мы описываем в разделе 4.7).
Рис. 2.13. Параллельный сервер, дочерний процесс которого обрабатывает запрос клиента
На этом этапе мы должны провести различие между прослушиваемым сокетом и присоединенным сокетом на сервере. Заметьте, что присоединенный сокет использует тот же локальный порт (21), что и прослушиваемый сокет. Также заметьте, что на многоадресном сервере локальный адрес заполняется для присоединенного сокета (206.62.226.35), как только устанавливается соединение.
При выполнении следующего шага предполагается, что другой клиентский процесс на клиентском узле запрашивает соединение с тем же сервером. Код TCP клиента задает новому сокету клиента неиспользованный номер динамически назначаемого порта, скажем 1501. Мы получаем сценарий, представленный на рис. 2.14. На сервере различаются два соединения: пара сокетов для первого соединения отличается от пары сокетов для второго соединения, поскольку TCP клиента выбирает неиспользованный порт (1501) для второго соединения.
Рис. 2.14. Второе соединение клиента с тем же сервером
Из этого примера видно, что TCP не может демультиплексировать входящие сегменты, просматривая только номера портов назначения. TCP должен обращать внимание на все четыре элемента в паре сокетов, чтобы определить, какая конечная точка получает приходящий сегмент. На рис. 2.14 представлены три сокета с одним и тем же локальным портом (21). Если сегмент приходит с IP- адреса 206.168.112.219, порт 1500 и предназначен для IP-адреса 12.106.32.254, порт 21, он доставляется первому дочернему процессу. Если сегмент приходит с IP- адреса 206.168.112.219, порт 1501 и предназначен для IP-адреса 12.106.32.254, порт 21, он доставляется второму дочернему процессу. Все другие сегменты TCP, предназначенные для порта 21, доставляются исходному серверу с прослушиваемым сокетом.
2.11. Размеры буфера и ограничения
Существуют несколько ограничений, устанавливающих максимальный размер дейтаграмм IP. Сначала мы опишем эти ограничения, а затем свяжем их вместе, чтобы показать, как они влияют на данные, которые может передавать приложение.
■ Максимальный размер дейтаграммы IPv4 — 65 535 байт, включая заголовок IPv4. Это связано с тем, что размер дейтаграммы ограничен 16-разрядным полем общей длины (см. рис. А.1).
■ Максимальный размер дейтаграммы IPv6 — 65 575 байт, включая 40-байтовый заголовок IPv6. Это ограничение связано с 16-разрядным полем длины полезных данных на рис. А.2. Заметьте, что поле длины IPv6 не включает размер заголовка IPv6, в то время как в случае IPv4 длина заголовка включается.
IPv6 поддерживает возможность передачи полезных данных увеличенного объема (jumbo payload), при этом поле длины полезных данных расширяется до 32 бит, но эта функция поддерживается только на тех канальных уровнях, на которых максимальная единица передачи (MTU) превышает 65 535. Это свойство разработано для соединений между двумя узлами, таких как HIPPI (High-Performance Parallel Interface — высокоскоростной параллельный интерфейс), у которых часто нет собственных ограничений на MTU.
■ Во многих сетях определена MTU (maximum transmission unit — максимальная единица передачи), величина которой диктуется возможностями оборудования. Например, размер MTU для Ethernet равен 1500 байт. Другие канальные уровни, такие как соединения «точка-точка» с использованием протокола PPP, имеют конфигурируемую MTU. Более ранние соединения по протоколу SLIP (Serial Line Internet Protocol — межсетевой протокол для последовательного канала) часто использовали MTU, равную 296 или 1006 байт.
Минимальная величина канальной MTU (link MTU) для IPv4 — 68 байт. Это сумма размера заголовка IPv4 максимальной длины (20 байт фиксированных полей и 30 байт параметров) и фрагмента минимального размера (сдвиг фрагмента должен быть кратен 8 байтам). Минимальная величина MTU для IPv6 — 1280 байт. IPv6 может работать и в сетях с меньшей MTU, но при условии фрагментации и последующей сборки на канальном уровне, чтобы извне сеть казалась имеющей большую MTU (RFC 2460 [27]).
■ Наименьшая величина MTU в пути между двумя узлами называется транспортной MTU (path MTU). В настоящее время MTU Ethernet, равная 1500 байт, часто является и транспортной MTU. Величина транспортной MTU между любыми двумя узлами не обязательно должна быть одинаковой в обоих направлениях, поскольку маршрутизация в Интернете часто асимметрична [90]. То есть маршрут от А к В может отличаться от маршрута от В к А.
■ Если размер дейтаграммы превышает канальную MTU, и IPv4 и IPv6 выполняют фрагментацию (fragmentation). Сборка (reassemble) фрагментов обычно не выполняется, пока они не достигнут конечного места назначения. Узлы IPv4 выполняют фрагментацию дейтаграмм, которые они генерируют, а маршрутизаторы IPv4 выполняют фрагментацию передаваемых ими дейтаграмм. Но в случае IPv6 дейтаграммы фрагментируются только узлами, а маршрутизаторы IPv6 фрагментацией не занимаются.
■ Если в заголовке IPv4 (см. рис. А.1) установлен бит DF (don't fragment — не фрагментировать), это означает, что данная дейтаграмма не должна быть фрагментирована ни отправляющим узлом, ни любым маршрутизатором на ее пути. Маршрутизатор, получающий дейтаграмму IPv4 с установленным битом DF, размер которой превышает MTU исходящей линии, генерирует сообщение об ошибке ICMPv4 «Необходима фрагментация, но установлен бит DF» (см. табл. А.5).
Поскольку маршрутизаторы IPv6 не выполняют фрагментации, можно считать, что во всех дейтаграммах IPv6 установлен бит DF. Когда маршрутизатор IPv6 получает дейтаграмму, размер которой превышает MTU исходящей линии, он генерирует сообщение об ошибке ICMPv6 «Слишком большой пакет» (см. табл. А.6).
ПРИМЕЧАНИЕБудьте внимательны при использовании данной терминологии. Узел, помеченный как маршрутизатор IPv6, может все равно выполнять фрагментацию, но только для дейтаграмм, которые этот маршрутизатор генерирует сам. Он никогда не фрагментирует передаваемые им дейтаграммы. Когда этот узел генерирует дейтаграммы IPv6, он на самом деле выступает в роли узла (а не маршрутизатора). Например, большинство маршрутизаторов поддерживают протокол Telnet, используемый администраторами для настройки. Дейтаграммы IP, генерируемые сервером Telnet маршрутизатора, считаются порождаемыми маршрутизатором, поэтому он может выполнять их фрагментацию.
Вы можете заметить, что в заголовке IPv4 (см. рис. А.1) существуют поля для выполнения IPv4-фрагментации, но в заголовке IPv6 (см. рис. А.2) полей для фрагментации нет. Поскольку фрагментация скорее исключение, чем правило, IPv6 может содержать дополнительный заголовок с информацией о фрагментации.
Некоторые межсетевые экраны, обычно выполняющие по совместительству функции маршрутизаторов, могут собирать фрагментированные пакеты, чтобы проверять их содержимое целиком. Это позволяет предотвратить атаки определенного рода за счет дополнительного усложнения устройства экрана. Кроме того, для этого требуется, чтобы конкретный экран был единственной точкой соединения сети с внешней сетью, что сокращает возможности по обеспечению избыточности.