Многоуровневая архитектура и инкапсуляция
В теме 1 сеть была описана «снаружи»: узлы, каналы, протоколы, метрики задержки и пропускной способности. Остался открытым вопрос о том, как устроена работа протоколов внутри узла. Чтобы браузер получил веб-страницу, нужно решить множество задач разной природы: найти адрес сервера по имени, доставить пакет через десяток независимых сетей, восстановить потерянные данные и их порядок, передать биты по кабелю или радиоэфиру, согласовать формат запроса и ответа. Если бы одна программа решала все эти задачи сразу, любое изменение — новый тип кабеля, новое приложение — требовало бы её переписывания.
Ответ, который дала сетевая инженерия, — многоуровневая архитектура (англ. layered architecture). Задача разбивается на уровни, каждый из которых решает свою часть, пользуется услугами нижележащего уровня и предоставляет услуги вышележащему. Механизм, с помощью которого уровни совместно передают данные, называется инкапсуляцией: каждый уровень добавляет к данным свой заголовок, а на приёмной стороне соответствующий уровень его снимает.
Тема построена следующим образом. Сначала обсуждается, зачем нужны уровни и что такое сервис, протокол и интерфейс. Затем рассматриваются две эталонные модели — семиуровневая модель OSI и стек TCP/IP — и их соотношение. Центральный раздел посвящён инкапсуляции: на реальном кадре, захваченном в учебной топологии, байт за байтом прослеживается, где лежит каждый заголовок, и подсчитываются накладные расходы. Далее излагаются принципы, на которых построен Интернет: принцип «из конца в конец», «песочные часы» с узкой талией IP, цели проектирования по Кларку и принцип робастности. Сквозной пример — путь веб-запроса через стек — связывает всё это вместе и намечает содержание последующих тем. Завершает тему практическое руководство по чтению RFC. Подробности конкретных протоколов — Ethernet, IP, TCP, DNS, HTTP — здесь намеренно опускаются: важно лишь, «где лежит» каждый заголовок и «что он означает в целом».
Зачем сети нужны уровни
Декомпозиция сложной задачи
Многоуровневая организация — частный случай общего инженерного приёма декомпозиции, знакомого по операционным системам и компиляторам. Удобную аналогию предлагает обычная почта 1. Автор письма пишет текст и кладёт его в конверт с адресом. Почтовое отделение сортирует конверты по направлениям и складывает в мешки. Мешки перевозятся самолётом или поездом. В пункте назначения последовательность повторяется в обратном порядке: мешки разгружаются, конверты сортируются по отделениям, почтальон доставляет конверт, адресат читает письмо. Каждый участник решает свою задачу и не интересуется задачами остальных: пилот не читает писем, автор не знает расписания поездов. Если поезд заменить грузовиком, ничего, кроме перевозки, не изменится.
В сети происходит то же самое. Каждый уровень (англ. layer) решает ограниченную задачу — доставку бит по одному кабелю, доставку пакета через цепочку сетей, надёжную передачу потока байтов между программами — и строится на услугах уровня ниже. Получающиеся выгоды:
- сложность обозрима: каждый уровень можно проектировать, реализовывать и проверять отдельно;
- реализации уровня взаимозаменяемы: Ethernet можно заменить на Wi-Fi, не меняя ни браузера, ни веб-сервера;
- одна нижележащая технология обслуживает множество вышележащих: по одному IP работают и веб, и почта, и видеосвязь.
Сервис, протокол и интерфейс
Для точного разговора об уровнях понадобятся три различных понятия, введённые в модели OSI 3 и ставшие общепринятыми 2.
Сервис (англ. service) — набор операций, которые уровень предоставляет вышележащему уровню: например, «доставить этот блок данных узлу с таким-то адресом» или «установить соединение и передавать поток байтов надёжно и по порядку». Сервис описывает, что делает уровень, но не как.
Протокол (англ. protocol) — правила, по которым взаимодействуют одноимённые уровни на разных узлах — равноправные сущности (англ. peer entities). Протокол транспортного уровня определяет, какими сообщениями обмениваются транспортные уровни клиента и сервера; уровень, реализующий этот протокол, «разговаривает» только со своим партнёром на другом узле, хотя физически его сообщения проходят через все нижележащие уровни.
Интерфейс (англ. interface) — граница между соседними уровнями одного узла, через которую вышележащий уровень обращается к сервису нижележащего. Точка, в которой происходит обращение, называется точкой доступа к сервису (англ. service access point, SAP). Примеры интерфейсов — программный интерфейс сокетов между приложением и транспортным уровнем (тема 12) и интерфейс драйвера сетевой карты.
Важное следствие: протокол можно заменить, не меняя сервиса. Если два протокола предоставляют одинаковый сервис, вышележащий уровень не заметит подмены. Это обстоятельство систематически используется: например, протокол QUIC (тема 16) предоставляет приложению сервис, сходный с TCP, но реализован поверх UDP.
С понятиями связана и терминология блоков данных. Данные, которые вышележащий уровень передаёт нижележащему через интерфейс, называются сервисным блоком данных (англ. service data unit, SDU). Нижележащий уровень добавляет к SDU свою управляющую информацию — заголовок — и получает протокольный блок данных (англ. protocol data unit, PDU), которым и обменивается с партнёром. PDU уровня N становится SDU уровня N − 1. На этом соотношении и основана инкапсуляция, которой посвящён один из следующих разделов.
Цена многоуровневости
Уровни — не бесплатная абстракция. Во-первых, каждый уровень добавляет свой заголовок, и при малых сообщениях заголовки могут занимать больше места, чем данные (это будет подсчитано ниже). Во-вторых, строгая изоляция мешает оптимизации: уровню бывает полезно знать о состоянии соседнего. Например, протокол TCP, не знающий, что потеря вызвана помехами в радиоканале, а не перегрузкой, неоправданно снижает скорость (темы 13 и 20). В-третьих, некоторые функции дублируются на нескольких уровнях: контрольные суммы есть и в Ethernet, и в IP, и в TCP.
Эти соображения изложены в RFC 3439 с характерным заголовком раздела «Layering Considered Harmful» — «многоуровневость считается вредной» 12. Авторы не призывают отказаться от уровней, а предостерегают от их чрезмерного умножения: каждый новый промежуточный уровень добавляет сложность, которая со временем оборачивается ошибками и неустойчивостью. Принципы архитектуры Интернета, изложенные в RFC 1958, формулируют ту же мысль положительно: следует стремиться к простоте и не вводить механизмы, без которых можно обойтись 13.
Эталонные модели: OSI и TCP/IP
Семь уровней модели OSI
В конце 1970-х годов Международная организация по стандартизации (англ. International Organization for Standardization, ISO) начала разработку архитектуры взаимосвязи открытых систем (англ. Open Systems Interconnection, OSI). Её эталонная модель (англ. reference model), представленная Циммерманом в 1980 году 3 и закреплённая стандартом ISO/IEC 7498-1 4, делит сетевое взаимодействие на семь уровней. Модель OSI — не протокол и не программа, а словарь и система координат: именно из неё пришли выражения «коммутатор второго уровня», «балансировщик седьмого уровня», «атака на уровне 3».
| Уровень | Название | Англ. | Задача | Примеры технологий |
|---|---|---|---|---|
| 7 | Прикладной | Application | сервисы для пользовательских программ | HTTP, SMTP, DNS |
| 6 | Представления | Presentation | согласование формата и кодировки данных, сжатие, шифрование | ASN.1, кодировки, TLS (частично) |
| 5 | Сеансовый | Session | установление, синхронизация и завершение сеансов диалога | RPC, контрольные точки сеанса |
| 4 | Транспортный | Transport | передача данных между процессами, надёжность, управление потоком | TCP, UDP, QUIC |
| 3 | Сетевой | Network | доставка пакетов между сетями, адресация узлов, маршрутизация | IP, ICMP |
| 2 | Канальный | Data link | передача кадров между соседними узлами одной среды, обнаружение ошибок | Ethernet, Wi-Fi, PPP |
| 1 | Физический | Physical | передача бит сигналами по среде | витая пара, оптика, радио |
Нижние три уровня реализуются на каждом узле пути, включая маршрутизаторы; уровни с четвёртого по седьмой — только на конечных узлах. Поэтому уровни 4–7 называют сквозными (англ. end-to-end), а 1–3 — уровнями, работающими на каждом участке (англ. hop-by-hop). Разграничение принципиально и будет использовано в разделе о принципах архитектуры.
Стек TCP/IP
Протоколы Интернета развивались параллельно с OSI, но не по её модели, а «снизу вверх» — от работающих реализаций. Требования к хостам Интернета, изложенные в RFC 1122, выделяют четыре уровня 5:
- уровень канала (англ. link layer) — передача пакетов в пределах одной сети, без уточнения технологии;
- межсетевой уровень (англ. internet layer) — протокол IP, доставка пакетов между сетями;
- транспортный уровень (англ. transport layer) — протоколы TCP и UDP, сквозная связь между процессами;
- прикладной уровень (англ. application layer) — все протоколы приложений.
Большинство учебников, в том числе этот курс, пользуется гибридной пятиуровневой моделью 12: уровень канала стека TCP/IP разделяется на физический и канальный, поскольку это действительно разные задачи с разными стандартами (тема 3 и тема 4). Блоки данных уровней имеют устоявшиеся названия, приведённые в таблице.
| Уровень пятиуровневой модели | Номер по OSI | Название PDU | Англ. | Адрес |
|---|---|---|---|---|
| Прикладной | 7 (5–7) | сообщение | message | имя (DNS), URL |
| Транспортный | 4 | сегмент (TCP), датаграмма (UDP) | segment, datagram | номер порта |
| Сетевой | 3 | пакет, или IP-датаграмма | packet, datagram | IP-адрес |
| Канальный | 2 | кадр | frame | MAC-адрес |
| Физический | 1 | бит, символ | bit, symbol | — |
Терминология не вполне единообразна: в RFC блок данных IP называют датаграммой, а в повседневной речи словом «пакет» обозначают PDU любого уровня. В курсе используется таблица выше, а слово «пакет» без уточнения означает PDU сетевого уровня.
Соотношение моделей и критика
Соотношение моделей показано на рисунке ниже. Нижние уровни соответствуют друг другу почти точно. Наибольшее расхождение — в верхней части: сеансовый уровень и уровень представления OSI в стеке TCP/IP отдельно не выделяются, их функции выполняет само приложение или библиотеки, которыми оно пользуется.
Протоколы OSI, разработанные в 1980-х годах, проиграли протоколам Интернета, хотя за ними стояли правительства и крупнейшие компании. Танненбаум называет причины: неудачный момент — стандарты появились, когда TCP/IP уже широко применялся в университетах; сложность — семь уровней с неравномерной нагрузкой (сеансовый уровень почти пуст, а канальный и сетевой перегружены); первые реализации, громоздкие и медленные; восприятие OSI как проекта, навязанного бюрократией 2. TCP/IP, напротив, распространялся вместе с бесплатной реализацией в операционной системе BSD UNIX. Модель OSI при этом выжила как словарь, а протоколы TCP/IP — как практика.
Реальные протоколы не всегда помещаются в одну клетку модели, и спорить о «правильном» уровне протокола бессмысленно, если не понимать, чем он пользуется и кому служит. Несколько характерных случаев:
- протокол разрешения адресов ARP (тема 7) переносится в кадрах Ethernet, но служит сетевому уровню, сопоставляя IP-адреса и MAC-адреса; его относят то ко второму, то к третьему уровню;
- протоколы маршрутизации решают задачу сетевого уровня, но OSPF переносится непосредственно в IP, а BGP — поверх TCP, то есть формально является прикладным протоколом (темы 9 и 10);
- TLS (тема 17) шифрует данные между транспортным и прикладным уровнями и выполняет функции уровней 5 и 6 OSI;
- MPLS (тема 21) располагает свою метку между заголовками канального и сетевого уровней и иногда называется уровнем «2,5»;
- туннели (тема 19) помещают пакет одного уровня внутрь PDU того же или более высокого уровня, нарушая простую картину «один уровень — один заголовок».
Модель — инструмент рассуждения, а не закон природы; её ценность в том, что она позволяет задать правильные вопросы: какой сервис нужен протоколу, кто его партнёр, какие заголовки он добавляет.
Инкапсуляция
Заголовки, полезная нагрузка и демультиплексирование
Рассмотрим, что происходит при отправке данных. Приложение передаёт транспортному уровню сообщение, например HTTP-запрос. Транспортный уровень добавляет к нему заголовок TCP, получая сегмент. Сетевой уровень добавляет заголовок IP — получается пакет. Канальный уровень добавляет заголовок Ethernet и в конце — контрольную последовательность кадра (англ. frame check sequence, FCS), получая кадр. Физический уровень передаёт биты кадра сигналами. Этот процесс называется инкапсуляцией (англ. encapsulation): PDU верхнего уровня становится полезной нагрузкой (англ. payload) PDU нижнего. На приёмной стороне происходит обратный процесс — декапсуляция: каждый уровень проверяет и снимает свой заголовок и передаёт содержимое выше. Схема инкапсуляции с длинами заголовков приведена на рисунке ниже.
Как приёмная сторона узнаёт, какому вышележащему протоколу передать полезную нагрузку? Для этого в каждом заголовке есть поле, указывающее на содержимое. Выбор получателя по такому полю называется демультиплексированием (англ. demultiplexing):
| Заголовок | Поле | Значения (примеры) | Что выбирается |
|---|---|---|---|
| Ethernet | EtherType, 16 бит | 0x0800 — IPv4, 0x86DD — IPv6, 0x0806 — ARP | протокол сетевого уровня |
| IPv4 | Protocol, 8 бит | 1 — ICMP, 6 — TCP, 17 — UDP | протокол транспортного уровня |
| TCP, UDP | порт назначения, 16 бит | 53 — DNS, 80 — HTTP, 443 — HTTPS | процесс-приложение |
Значения этих полей — общие для всех реализаций числа, реестры которых ведут IEEE (EtherType) и IANA (номера протоколов и портов). Цепочка «EtherType → Protocol → порт» позволяет одному кабелю одновременно переносить данные десятков протоколов и сотен приложений; на передающей стороне соответствующий процесс — объединение потоков многих приложений в один — называется мультиплексированием.
Заметим, что заголовок каждого уровня читает и интерпретирует только партнёр этого уровня. Маршрутизатор читает заголовки Ethernet и IP, но в заголовок TCP не заглядывает (по крайней мере, по принципу; межсетевые экраны и трансляторы адресов это правило нарушают — темы 14 и 18). Приложение не видит ни одного заголовка, кроме своего.
Разбор реального кадра байт за байтом
Абстракция становится понятной, если проследить её на реальных байтах. В учебной топологии лабораторной работы 2 клиент h1 (адрес 10.1.0.10) обращается через маршрутизатор r1 к веб-серверу srv (адрес 10.2.0.20) по имени www.nsu.example. Захват трафика на интерфейсе клиента выполнен утилитой tcpdump, а вывод с ключом -XX показывает кадр целиком в шестнадцатеричном виде:
tcpdump -nn -XX -r web.pcap 'tcp[tcpflags] & tcp-push != 0' -c 1
12:57:37.059007 IP 10.1.0.10.48006 > 10.2.0.20.80: Flags [P.], seq 1:80, ack 1, win 502, options [nop,nop,TS val 2963218683 ecr 1007754503], length 79: HTTP: GET / HTTP/1.1
0x0000: 0200 0000 0101 0200 0000 0110 0800 4500 ..............E.
0x0010: 0083 81fd 4000 4006 a457 0a01 000a 0a02 ....@.@..W......
0x0020: 0014 bb86 0050 925b 6c03 df53 a872 8018 .....P.[l..S.r..
0x0030: 01f6 1496 0000 0101 080a b09f 20fb 3c11 ..............<.
0x0040: 1d07 4745 5420 2f20 4854 5450 2f31 2e31 ..GET./.HTTP/1.1
0x0050: 0d0a 486f 7374 3a20 7777 772e 6e73 752e ..Host:.www.nsu.
0x0060: 6578 616d 706c 650d 0a55 7365 722d 4167 example..User-Ag
0x0070: 656e 743a 2063 7572 6c2f 372e 3831 2e30 ent:.curl/7.81.0
0x0080: 0d0a 4163 6365 7074 3a20 2a2f 2a0d 0a0d ..Accept:.*/*...
0x0090: 0a .
Кадр имеет длину 0x91 = 145 байт. Левый столбец — смещение от начала кадра, затем 16 байт в шестнадцатеричном виде, справа — те же байты как символы ASCII (непечатаемые заменены точками). Разберём его по уровням.
Заголовок Ethernet, байты 0–13. Первые 6 байт 02:00:00:00:01:01 — MAC-адрес получателя кадра, следующие 6 байт 02:00:00:00:01:10 — MAC-адрес отправителя, затем 2 байта 0x0800 — EtherType, сообщающий, что внутри пакет IPv4. Существенная деталь: адрес получателя …:01:01 принадлежит не серверу, а маршрутизатору r1. Кадр живёт только на одном участке — от клиента до маршрутизатора; на следующем участке будет построен новый кадр с другими MAC-адресами.
Заголовок IPv4, байты 14–33. Байт 0x45 содержит два поля по 4 бита: версия 4 и длина заголовка 5 слов по 32 бита, то есть 20 байт. Далее 0x00 — поле класса обслуживания, 0x0083 = 131 — полная длина пакета в байтах, 0x81fd — идентификатор, 0x4000 — флаги (установлен флаг «не фрагментировать»), 0x40 = 64 — время жизни TTL, 0x06 — протокол TCP, 0xa457 — контрольная сумма заголовка, 0a 01 00 0a — адрес источника 10.1.0.10, 0a 02 00 14 — адрес назначения 10.2.0.20. В отличие от MAC-адресов, IP-адреса указывают на конечные узлы и на пути не меняются. Подробно заголовок IP разбирается в теме 7.
Заголовок TCP, байты 34–65. 0xbb86 = 48006 — порт источника, выбранный операционной системой клиента произвольно, 0x0050 = 80 — порт назначения, порт HTTP. Далее 4 байта порядкового номера 0x925b6c03 и 4 байта номера подтверждения 0xdf53a872. Старшие 4 бита байта 0x80 — длина заголовка 8 слов, то есть 32 байта: 20 байт обязательной части и 12 байт параметров (англ. options). Байт 0x18 — флаги PSH и ACK, 0x01f6 = 502 — окно, 0x1496 — контрольная сумма, 0x0000 — указатель срочности. Последние 12 байт 01 01 08 0a … — два пустых параметра NOP и параметр временных меток (англ. timestamps). Смысл этих полей — предмет тем 12 и 13.
Данные приложения, байты 66–144. Оставшиеся 79 байт — текст HTTP-запроса: GET / HTTP/1.1, заголовок Host: www.nsu.example, User-Agent: curl/7.81.0, Accept: */* и пустая строка; строки разделены парой байтов 0d 0a (возврат каретки и перевод строки). Дамп снят с curl 7.81.0 (Ubuntu 22.04); в Ubuntu 24.04 (curl 8.5.0) строка User-Agent короче на один байт, поэтому длины данных и пакета, а с ними и контрольные суммы, будут отличаться на несколько байтов.
Проверка согласованности: 14 + 20 + 32 + 79 = 145 байт — ровно длина кадра; поле полной длины IP 131 = 20 + 32 + 79. Захват не содержит преамбулы и FCS: сетевая карта отбрасывает их до передачи кадра операционной системе.
Тот же разбор автоматически выполняет Wireshark, показывая дерево полей (англ. packet details) с подсветкой соответствующих байтов в шестнадцатеричной панели 14. Ручной разбор хотя бы одного кадра полезен тем, что он показывает: в кадре нет ничего, кроме последовательности байтов, а «уровни» — это соглашения о том, как эти байты читать.
Накладные расходы заголовков
Каждый заголовок занимает место, которое могло бы быть отдано данным. Посчитаем долю полезных данных для сегмента TCP в кадре Ethernet. Заголовки: Ethernet 14 байт, IPv4 20 байт, TCP 20 байт и обычно ещё 12 байт параметров временных меток — итого 66 байт. Кроме того, на кабеле перед каждым кадром передаются преамбула и разделитель начала кадра (8 байт), после кадра — FCS (4 байта), а между кадрами выдерживается межкадровый интервал, эквивалентный 12 байтам (тема 4). Получается 66 + 24 = 90 байт служебной нагрузки на каждый сегмент.
При максимальном размере кадра Ethernet данные IP-пакета не превышают 1500 байт (это значение называется MTU, англ. maximum transmission unit), значит, данных приложения в сегменте не более 1500 − 20 − 32 = 1448 байт. Доля полезных данных:
1448 / (1448 + 90) = 1448 / 1538 ≈ 0,941
то есть около 94 % — при самых благоприятных условиях. Для маленького сообщения картина обратная. Сообщение длиной 10 байт порождает кадр 76 байт, который вместе с преамбулой, FCS и интервалом занимает на кабеле 100 байт, — полезная доля 10 %. Если на каждое такое сообщение получатель отвечает отдельным подтверждением (кадр 66 байт, 90 байт на кабеле), доля падает до 10/190 ≈ 5 %.
Эти расчёты подтверждаются измерением в учебной топологии. Скрипт pcap_layers.py из окружения лабораторной работы 2 подсчитывает байты каждого уровня в захвате. Для 100 сообщений по 10 байт, отправленных с паузой 10 мс:
Кадров: 206; байт в захвате: 14612; на проводе: 19556
L2 (Ethernet) 2884 байт 19.7 %
L3 (IP/ARP) 4120 байт 28.2 %
L4 (TCP/UDP/ICMP) 6608 байт 45.2 %
L7 (данные) 1000 байт 6.8 %
Доля полезных данных: 6.8 % от захваченных байт, 5.1 % от байт на проводе
Для одного сообщения 100 000 байт:
Кадров: 125; байт в захвате: 108266; на проводе: 111266
L2 (Ethernet) 1750 байт 1.6 %
L3 (IP/ARP) 2500 байт 2.3 %
L4 (TCP/UDP/ICMP) 4016 байт 3.7 %
L7 (данные) 100000 байт 92.4 %
Доля полезных данных: 92.4 % от захваченных байт, 89.9 % от байт на проводе
Разница больше чем на порядок. В первом случае на каждое 10-байтовое сообщение пришлось два кадра (данные и подтверждение), а также кадры установления и закрытия соединения. Отсюда практический вывод, многократно встречающийся в курсе: протоколы стремятся объединять мелкие сообщения (алгоритм Нейгла и отложенные подтверждения в TCP — тема 13), а протоколы для маломощных устройств сжимают заголовки.
Одна оговорка касается самого захвата. Современные операционные системы и сетевые карты для экономии процессорного времени передают по стеку «сверхкадры» до 64 КиБ и разрезают их на сегменты размером в MTU лишь при выдаче в кабель (англ. TCP segmentation offload, TSO; generic segmentation offload, GSO) или, наоборот, склеивают принятые сегменты (англ. generic receive offload, GRO). Захват видит такие сверхкадры длиной в десятки килобайт, и подсчёт накладных расходов по ним занижает число заголовков. В лабораторной работе эти механизмы для точности измерения ограничиваются.
Адресация на разных уровнях
Каждый уровень решает задачу доставки в своих границах и пользуется своими адресами, как показывает таблица.
| Адрес | Уровень | Длина | Что идентифицирует | Область действия | Пример |
|---|---|---|---|---|---|
| MAC-адрес | канальный | 48 бит | сетевой интерфейс | одна сеть канального уровня | 02:00:00:00:01:10 |
| IP-адрес | сетевой | 32 бита (IPv4), 128 бит (IPv6) | интерфейс узла в межсетевом пространстве | весь Интернет (кроме частных адресов) | 10.1.0.10 |
| Номер порта | транспортный | 16 бит | процесс (сокет) на узле | один узел | 80 |
| Доменное имя | прикладной | до 253 символов | ресурс, сервис, узел | глобально | www.nsu.example |
Для доставки нужны все четыре вида адресов, и между ними устанавливаются соответствия. Имя преобразуется в IP-адрес системой DNS (тема 15). IP-адрес следующего узла на пути преобразуется в MAC-адрес протоколом ARP (тема 7). Номер порта сервера обычно известен заранее: он стандартен для протокола (80 для HTTP) или указан в URL. Различие в области действия объясняет, почему MAC-адреса меняются на каждом участке пути, а IP-адреса — нет: кадр канального уровня по определению живёт в пределах одной сети. Каким образом адреса выделяются и почему их структура такова, рассматривается в темах 4, 6, 11 и 15.
Принципы архитектуры Интернета
Принцип «из конца в конец»
В 1984 году Зальцер, Рид и Кларк сформулировали аргумент, ставший одним из основных принципов архитектуры Интернета 6. Рассмотрим передачу файла с диска одного компьютера на диск другого. Ошибки возможны на многих этапах: при чтении с диска, в памяти, при копировании в буферы, в сети, при записи. Можно сделать надёжным каждое звено — например, обеспечить в сети гарантированную доставку с подтверждениями на каждом участке. Но и в этом случае ошибка в памяти маршрутизатора или в программе получателя может испортить данные. Единственный способ убедиться, что файл записан верно, — проверка из конца в конец: получатель вычисляет контрольную сумму записанного файла и сравнивает с суммой отправителя, а при расхождении запрашивает повтор.
Отсюда аргумент: функция, которая может быть полностью и правильно реализована только с участием приложений на концах соединения, не может быть полностью реализована внутри сети. Реализация её внутри сети может служить лишь оптимизацией производительности, но не заменяет проверку на концах. Если сеть теряет один пакет из миллиона, повторная передача из конца в конец обходится дёшево. Если же сеть — например, радиоканал — теряет каждый десятый пакет, имеет смысл повторять передачу на канальном уровне, иначе сквозные повторы станут слишком частыми. Так и устроен Wi-Fi (тема 20).
Принцип объясняет устройство Интернета: сеть делает простую работу — пытается доставить пакет, не гарантируя ни доставки, ни порядка, ни отсутствия дублей (такая доставка называется доставкой с наилучшим старанием, англ. best effort), а надёжность, порядок, шифрование реализуются на хостах. Это позволило сети оставаться простой и быстрой, а новым приложениям — появляться без согласия операторов сети. Современные устройства в середине пути — трансляторы адресов, межсетевые экраны, балансировщики, — вмешивающиеся в транспортный уровень, нарушают этот принцип; последствия этого обсуждаются в темах 14 и 18.
«Песочные часы» и узкая талия IP
Если изобразить протоколы Интернета по уровням, получится фигура, похожая на песочные часы, как показано на рисунке ниже. Внизу — множество технологий канального и физического уровней: Ethernet, Wi-Fi, сотовые сети, оптические линии. Вверху — тысячи приложений и протоколов. Посередине, в «талии», один протокол — IP, а над ним немногочисленные транспортные протоколы, прежде всего TCP и UDP.
Узкая талия — источник гибкости. Любая новая технология передачи становится частью Интернета, как только для неё определено, как переносить пакеты IP, и все существующие приложения сразу начинают через неё работать. Любое новое приложение, использующее IP, работает поверх всех технологий передачи сразу. Иначе потребовалось бы M × N адаптаций между M приложениями и N технологиями; с узкой талией их M + N. Обратная сторона — изменить саму талию чрезвычайно трудно: переход с IPv4 на IPv6, начатый в 1990-х годах, не завершён до сих пор (тема 11). Исследования эволюции стеков протоколов показывают, что форма песочных часов возникает естественно: протоколы средних уровней, обслуживающие много протоколов сверху, вытесняют конкурентов 11. С этим связано и современное явление «окостенения» транспортного уровня: устройства в середине пути пропускают только TCP и UDP, поэтому новый транспортный протокол QUIC был построен поверх UDP (тема 16).
Цели проектирования по Кларку
В 1988 году Дэвид Кларк опубликовал статью «Философия проектирования протоколов DARPA Internet», в которой задним числом восстановил цели, которыми руководствовались создатели Интернета, и их порядок важности 7. Главная цель — эффективное использование существующих взаимосвязанных сетей с мультиплексированием. Остальные, в порядке убывания важности:
- Связь должна сохраняться, несмотря на потерю сетей или шлюзов.
- Интернет должен поддерживать разные типы сервисов связи.
- Архитектура должна вмещать разнообразные сети.
- Должно быть возможно распределённое управление ресурсами.
- Архитектура должна быть экономически эффективна.
- Подключение хоста должно требовать небольших усилий.
- Используемые ресурсы должны поддаваться учёту.
Порядок объясняет многие решения. Живучесть стоит первой — поэтому состояние соединения хранится не в сети, а на хостах (Кларк называет это «разделением судьбы», англ. fate-sharing: состояние теряется лишь вместе с самим хостом). Учёт ресурсов стоит последним — и в Интернете действительно до сих пор нет общего механизма учёта и оплаты трафика по пакетам. Кларк подчёркивает, что порядок отражает военное происхождение проекта: сеть, изначально создаваемая для коммерческого использования, расставила бы цели иначе, и учёт ресурсов оказался бы среди первых. Стоит подчеркнуть: в списке нет безопасности. Это не упущение автора, а отражение реальности 1970-х годов, последствия которой рассматриваются в темах 17–19.
Принцип робастности и его пересмотр
Ещё один принцип, сформулированный Джоном Постелом в спецификациях IP и TCP, называют принципом робастности, или законом Постела: реализация должна быть консервативна в том, что она отправляет, и либеральна в том, что она принимает 8. Смысл — способствовать совместимости: если сообщение партнёра немного отклоняется от спецификации, но понятно, его следует принять, а самому строго соблюдать стандарт. Требования к хостам RFC 1122 подробно развивают этот принцип 5.
В ранний период принцип облегчил стыковку многочисленных независимых реализаций. Однако со временем выяснились его издержки. Если принимающие реализации терпят отклонения, ошибочные отправители не исправляются, отклонения накапливаются и становятся «стандартом де-факто», которому вынуждены следовать все новые реализации. Терпимость к неожиданным входным данным, кроме того, нередко открывала уязвимости. В 2023 году Совет по архитектуре интернета (англ. Internet Architecture Board, IAB) опубликовал RFC 9413, рекомендующий иной подход: протоколы следует активно сопровождать, явно определять реакцию на ошибки и не полагаться на молчаливую терпимость 10. История закона Постела — хороший пример того, что принципы архитектуры не догма, а обобщение опыта, которое пересматривается вместе с опытом.
Путь веб-запроса через стек
От адреса в браузере к DNS-запросу
Соберём изложенное в сквозной пример. Пользователь узла h1 учебной топологии запрашивает страницу http://www.nsu.example/. Топология состоит из трёх узлов: клиента h1 в сети 10.1.0.0/24, маршрутизатора r1, соединяющего две сети, и сервера srv в сети 10.2.0.0/24, на котором работают веб-сервер и DNS-сервер. Все кадры ниже — фрагменты реального захвата на интерфейсе h1, выведенные командой tcpdump -nn -e -r web.pcap (адреса в метках времени опущены).
Приложению известны имя узла и, из схемы URL, номер порта — 80. Чтобы отправить пакет, нужен IP-адрес. Библиотека разрешения имён читает адрес DNS-сервера из файла /etc/resolv.conf и отправляет ему запрос по протоколу UDP на порт 53. Сервер 10.2.0.20 находится в другой сети, поэтому по таблице маршрутизации h1 пакет должен уйти маршрутизатору 10.1.0.1. MAC-адрес маршрутизатора h1 пока не знает, и первым в захвате оказывается обмен ARP:
02:00:00:00:01:10 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Request who-has 10.1.0.1 tell 10.1.0.10, length 28
02:00:00:00:01:01 > 02:00:00:00:01:10, ethertype ARP (0x0806), length 42: Reply 10.1.0.1 is-at 02:00:00:00:01:01, length 28
После этого уходят DNS-запросы и приходят ответы. Библиотека запрашивает одновременно запись типа A (адрес IPv4) и запись типа AAAA (адрес IPv6):
02:00:00:00:01:10 > 02:00:00:00:01:01, ethertype IPv4 (0x0800), length 75: 10.1.0.10.34238 > 10.2.0.20.53: 8665+ A? www.nsu.example. (33)
02:00:00:00:01:10 > 02:00:00:00:01:01, ethertype IPv4 (0x0800), length 75: 10.1.0.10.34238 > 10.2.0.20.53: 2775+ AAAA? www.nsu.example. (33)
02:00:00:00:01:01 > 02:00:00:00:01:10, ethertype IPv4 (0x0800), length 91: 10.2.0.20.53 > 10.1.0.10.34238: 8665* 1/0/0 A 10.2.0.20 (49)
02:00:00:00:01:01 > 02:00:00:00:01:10, ethertype IPv4 (0x0800), length 75: 10.2.0.20.53 > 10.1.0.10.34238: 2775 0/0/0 (33)
Здесь хорошо видна инкапсуляция в упрощённом варианте: сообщение DNS длиной 33 байта, заголовок UDP 8 байт, IP 20 байт, Ethernet 14 байт, итого 75 байт. Заголовок UDP, в отличие от TCP, не содержит ни номеров, ни подтверждений: потерянный запрос просто будет повторён библиотекой по тайм-ауту. Ответ на запрос A содержит одну запись — адрес 10.2.0.20; ответ на запрос AAAA пуст. Подробно протокол DNS рассматривается в теме 15.
Соединение TCP и HTTP-запрос
Получив адрес, приложение создаёт сокет TCP и устанавливает соединение с 10.2.0.20:80. Установление соединения — трёхэтапное рукопожатие (англ. three-way handshake, тема 12), три сегмента без данных с флагами SYN, SYN+ACK и ACK:
10.1.0.10.48006 > 10.2.0.20.80: Flags [S], seq 2455464962, win 64240, options [mss 1460,sackOK,TS val 2963218683 ecr 0,nop,wscale 7], length 0
10.2.0.20.80 > 10.1.0.10.48006: Flags [S.], seq 3746801777, ack 2455464963, win 65160, options [mss 1460,sackOK,TS val 1007754503 ecr 2963218683,nop,wscale 7], length 0
10.1.0.10.48006 > 10.2.0.20.80: Flags [.], ack 1, win 502, options [nop,nop,TS val 2963218683 ecr 1007754503], length 0
Только после этого уходит сегмент с HTTP-запросом, разобранный выше байт за байтом, а сервер отвечает двумя сегментами: заголовками ответа (184 байта) и телом страницы (503 байта). Затем соединение закрывается обменом сегментами с флагом FIN. Всего на загрузку страницы длиной 503 байта ушло 18 кадров: 2 кадра ARP, 4 кадра DNS, 3 кадра установления соединения, 6 кадров обмена данными и подтверждений и 3 кадра закрытия, из которых лишь 7 несли данные приложений — 4 кадра DNS (запросы и ответы), HTTP-запрос и два сегмента HTTP-ответа. Эта статистика — ещё одна иллюстрация накладных расходов многоуровневой передачи, на этот раз не по байтам, а по числу обменов, и каждый обмен стоит одного RTT. Как TLS и протоколы HTTP/2 и HTTP/3 борются с этими задержками, обсуждается в темах 16 и 17.
Через маршрутизатор: что меняется на каждом участке
Путь пакета через стеки узлов изображён на рисунке ниже. На клиенте данные проходят все уровни сверху вниз. Маршрутизатор принимает кадр, снимает заголовок Ethernet, по адресу назначения IP выбирает исходящий интерфейс, уменьшает время жизни TTL на единицу, пересчитывает контрольную сумму заголовка IP и строит новый кадр с собственным MAC-адресом в качестве отправителя и MAC-адресом сервера в качестве получателя. Поднимаются в маршрутизаторе пакеты только до сетевого уровня. На сервере данные проходят все уровни снизу вверх, и каждый уровень по полю демультиплексирования выбирает получателя: EtherType 0x0800 — IPv4, Protocol 6 — TCP, порт 80 — процесс веб-сервера.
Следы работы маршрутизатора видны в захвате на клиенте. Пакеты от клиента уходят с TTL=64 — начальным значением в Linux, — а пакеты от сервера приходят с TTL=63: по пути их обработал ровно один маршрутизатор. MAC-адрес отправителя во всех пакетах от сервера — 02:00:00:00:01:01, адрес маршрутизатора, а не сервера: MAC-адрес сервера клиент не узнаёт никогда. Сравнение заголовков одного и того же пакета на двух участках приведено в таблице.
| Поле | Участок h1 — r1 | Участок r1 — srv |
|---|---|---|
| MAC отправителя | 02:00:00:00:01:10 (h1) | 02:00:00:00:02:01 (r1, eth1) |
| MAC получателя | 02:00:00:00:01:01 (r1, eth0) | 02:00:00:00:02:20 (srv) |
| IP отправителя | 10.1.0.10 | 10.1.0.10 |
| IP получателя | 10.2.0.20 | 10.2.0.20 |
| TTL | 64 | 63 |
| Порты TCP | 48006 → 80 | 48006 → 80 |
Ответ: обратный путь
Ответ сервера проходит тот же путь в обратном порядке: веб-сервер записывает ответ в сокет, транспортный уровень сервера формирует сегменты, сетевой — пакеты с адресом назначения клиента, канальный — кадры для маршрутизатора r1, и так далее. На клиенте транспортный уровень по номерам портов находит сокет приложения, по порядковым номерам собирает данные в правильном порядке и передаёт их приложению, которое видит лишь поток байтов, начинающийся со строки состояния HTTP/1.1 200 OK. Каждый механизм, задействованный в этом обмене, — предмет отдельной темы курса: физическая передача (тема 3), Ethernet и коммутация (темы 4, 5), адресация и ARP (темы 6, 7), маршрутизация (темы 8–10), TCP (темы 12, 13), DNS (тема 15), HTTP (тема 16).
Как читать RFC
Структура документа и статус
Стандарты Интернета публикуются в серии RFC (тема 1), и умение читать их — профессиональный навык. Документ начинается с шапки, в которой указаны номер, авторы, дата, категория (Standards Track, Informational, Experimental, Best Current Practice) и связи с другими документами: Obsoletes — какие документы заменены этим, Updates — какие дополнены. На странице документа на сайте rfc-editor.org показываются и обратные связи (Obsoleted by, Updated by), а также известные ошибки — исправления (англ. errata). Прежде чем ссылаться на RFC, следует проверить, не заменён ли он: например, RFC 793 (TCP, 1981) заменён RFC 9293 (2022), а RFC 2616 (HTTP/1.1) — сначала серией RFC 7230–7235, а затем RFC 9110–9112.
Далее следуют аннотация, оглавление, введение с терминологией, основная часть, раздел «Соображения безопасности» (англ. Security Considerations, обязателен) и раздел «Соображения IANA» (англ. IANA Considerations) — какие номера и значения нужно зарегистрировать в реестрах. Для первого знакомства с протоколом полезно читать введение и обзор, затем — диаграммы форматов, и лишь потом — подробные правила обработки.
Ключевые слова требований
В тексте стандартов встречаются слова, набранные прописными буквами: MUST, SHOULD, MAY. Их смысл определён в RFC 2119 9 и уточнён в RFC 8174, согласно которому специальное значение имеют только слова, набранные прописными:
| Ключевое слово | Значение |
|---|---|
| MUST, REQUIRED, SHALL | абсолютное требование спецификации |
| MUST NOT, SHALL NOT | абсолютный запрет |
| SHOULD, RECOMMENDED | требование, от которого можно отступить при веских причинах, полностью понимая последствия |
| SHOULD NOT, NOT RECOMMENDED | запрет, который можно нарушить при веских причинах |
| MAY, OPTIONAL | действительно необязательная возможность |
Различие между MUST и SHOULD практически важно. Если RFC говорит, что реализация SHOULD поддерживать некоторый механизм, то реализация без него соответствует стандарту, и при диагностике нельзя исходить из того, что механизм заведомо есть. Например, RFC 1122 указывает, что хост SHOULD реализовать отложенные подтверждения TCP, а задержка подтверждения MUST быть меньше 0,5 с 5. Второе — жёсткая граница, первое — рекомендация, которой большинство реализаций следует.
Диаграммы заголовков
Форматы заголовков в RFC традиционно изображаются символами ASCII. Диаграмма выровнена по 32-битным словам; над ней — шкала номеров бит, причём бит 0 — самый старший бит первого байта (сетевой порядок байтов: старший байт передаётся первым, англ. big-endian). Пример — заголовок UDP из RFC 768, изображённый в его оригинальном виде:
0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| Source | Destination |
| Port | Port |
+--------+--------+--------+--------+
| | |
| Length | Checksum |
+--------+--------+--------+--------+
|
| data octets ...
+---------------- ...
Каждая клетка шириной 8 позиций — один байт; поле Source Port занимает биты 0–15 первого слова (2 байта), Destination Port — биты 16–31, и т. д. Заголовок UDP имеет фиксированную длину 8 байт. Сопоставим диаграмму с DNS-запросом из учебного захвата, в котором заголовок UDP занимает байты 34–41 кадра:
0022 85 be 00 35 00 29 14 5b
Поле Source Port = 0x85be = 34238, Destination Port = 0x0035 = 53 (DNS), Length = 0x0029 = 41 — длина заголовка UDP вместе с данными: 8 + 33 байта, Checksum = 0x145b. Значения в точности совпадают с тем, что показал tcpdump. Более новые RFC используют диаграммы с номерами всех 32 бит (как в RFC 791 для IP и RFC 9293 для TCP), а часть документов описывает форматы в табличном или псевдокодовом виде; принцип чтения один и тот же.
Итоги темы
Сеть строится из уровней, каждый из которых решает свою часть задачи, пользуется сервисом нижележащего уровня через интерфейс и взаимодействует со своим партнёром на другом узле по протоколу. Разделение сервиса, протокола и интерфейса позволяет заменять реализации уровня независимо от остальных, а соотношение SDU и PDU — то, что PDU верхнего уровня становится полезной нагрузкой нижнего, — составляет суть инкапсуляции.
Модель OSI с семью уровнями дала профессии словарь, а стек TCP/IP — работающие протоколы. Курс пользуется пятиуровневой моделью: физический, канальный, сетевой, транспортный и прикладной уровни, с PDU — битами, кадрами, пакетами, сегментами или датаграммами и сообщениями. Реальные протоколы не всегда помещаются в одну клетку модели, и вопрос «на каком уровне протокол» полезно заменять вопросами «чьим сервисом он пользуется и кому служит».
Инкапсуляция видна в каждом захваченном кадре: заголовок Ethernet с полем EtherType, заголовок IP с полем Protocol, заголовок TCP или UDP с номерами портов, данные приложения. Демультиплексирование по этим полям позволяет одному каналу переносить данные множества приложений. Цена — накладные расходы: при максимальном размере кадра полезная доля не превышает примерно 94 %, а для мелких сообщений падает до единиц процентов. Каждый уровень имеет свои адреса — MAC, IP, порт, имя, — с разной областью действия: MAC-адреса меняются на каждом участке, IP-адреса и порты сохраняются из конца в конец.
Интернет следует принципу «из конца в конец»: сеть с наилучшим старанием доставляет пакеты, а надёжность обеспечивают хосты. Узкая талия IP связывает многообразие технологий передачи с многообразием приложений, но сама почти не поддаётся изменению. Цели Кларка объясняют приоритеты архитектуры, а история закона Постела показывает, что принципы пересматриваются. Наконец, стандарты, в которых записаны все эти механизмы, читаются по устойчивым правилам: статус и связи документа, ключевые слова RFC 2119, диаграммы заголовков.
Со следующей темы курс поднимается по стеку снизу вверх. Тема 3 начинает с самого нижнего уровня — с того, как биты превращаются в сигналы и какие физические пределы ограничивают скорость их передачи.
Литература
- Kurose J. F., Ross K. W. Computer Networking: A Top-Down Approach. 8th ed. — Pearson, 2021.
- Tanenbaum A. S., Feamster N., Wetherall D. J. Computer Networks. 6th ed. — Pearson, 2021.
- Zimmermann H. OSI Reference Model — The ISO Model of Architecture for Open Systems Interconnection. — IEEE Transactions on Communications, 1980, Vol. 28, No. 4, С. 425–432, DOI: 10.1109/TCOM.1980.1094702.
- ISO/IEC 7498-1:1994. Information technology — Open Systems Interconnection — Basic Reference Model: The Basic Model. — ISO/IEC, 1994.
- Braden R. (ed.) Requirements for Internet Hosts — Communication Layers. — RFC 1122, IETF, 1989. https://www.rfc-editor.org/rfc/rfc1122
- Saltzer J. H., Reed D. P., Clark D. D. End-to-End Arguments in System Design. — ACM Transactions on Computer Systems, 1984, Vol. 2, No. 4, С. 277–288, DOI: 10.1145/357401.357402.
- Clark D. D. The Design Philosophy of the DARPA Internet Protocols. — Proceedings of ACM SIGCOMM '88, 1988, С. 106–114, DOI: 10.1145/52324.52336.
- Postel J. Internet Protocol. — RFC 791, IETF, 1981. https://www.rfc-editor.org/rfc/rfc791
- Bradner S. Key words for use in RFCs to Indicate Requirement Levels. — RFC 2119, IETF, 1997. https://www.rfc-editor.org/rfc/rfc2119
- Thomson M., Schinazi D. Maintaining Robust Protocols. — RFC 9413, IAB, 2023. https://www.rfc-editor.org/rfc/rfc9413
- Akhshabi S., Dovrolis C. The Evolution of Layered Protocol Stacks Leads to an Hourglass-Shaped Architecture. — Proceedings of ACM SIGCOMM 2011, 2011, DOI: 10.1145/2018436.2018460.
- Bush R., Meyer D. Some Internet Architectural Guidelines and Philosophy. — RFC 3439, IETF, 2002. https://www.rfc-editor.org/rfc/rfc3439
- Carpenter B. (ed.) Architectural Principles of the Internet. — RFC 1958, IETF, 1996. https://www.rfc-editor.org/rfc/rfc1958
- Wireshark User's Guide. — Wireshark Foundation, 2025. https://www.wireshark.org/docs/wsug_html_chunked/