Сети для самых маленьких. Часть 1: модели OSI и TCP/IP

Это первая статья серии «Сети для самых маленьких». «Для самых маленьких» — не про возраст читателя, а про точку старта: рассказывать буду с нуля и не буду предполагать ничего, кроме умения открыть терминал. Серия для тех, кто пишет программы, администрирует серверы или просто хочет понять, что происходит между нажатием Enter в адресной строке и появлением страницы.

У серии один принцип: о каждом протоколе — не только зачем он нужен, но и как он работает. Какие байты идут по проводу, кто на них отвечает, что происходит, когда что-то ломается. Поэтому почти в каждой части будут заголовки пакетов, команды и вывод tcpdump. Чтобы повторять примеры, хватит любой Linux-машины (подойдёт и WSL) с установленным tcpdump и Wireshark на рабочем компьютере.

План такой: сначала основа — модели, Ethernet, Wi-Fi и PPPoE; затем IPv4 с ARP и ICMP; транспорт — UDP и TCP; служебные протоколы DHCP и DNS; отдельным блоком IPv6 с Neighbor Discovery, SLAAC и DHCPv6; в конце — VLAN, VXLAN, IPsec с IKEv2 и разговор о том, чем VPN отличается от прокси. Статьи выходят по одной, и в конце каждой написано, что будет в следующей.


Задача, которую решает сеть

Две программы на разных компьютерах хотят обменяться байтами. Между ними — кабель или радио, коммутаторы, роутеры, несколько провайдеров и половина земного шара. Чтобы байты дошли, кто-то должен ответить на целый список вопросов:

  • как закодировать биты в электрический сигнал, свет или радиоволну;
  • как среди десятка устройств на одном кабеле передать данные именно соседу;
  • как найти машину на другом конце планеты, не зная, через какие сети к ней идти;
  • как убедиться, что данные дошли целиком и в правильном порядке, и повторить потерянное;
  • какой из сотни процессов на той машине должен получить эти байты.

Можно написать одну большую программу, которая решает всё сразу. Так и делали в 1970-х, и каждая сеть получалась несовместимой с соседней: протокол для коаксиального кабеля ничего не знал о радио, а программа, написанная под одну сеть, не работала в другой.

Решение, к которому пришли, — разделить задачу на уровни. Каждый уровень решает одну из задач списка выше, пользуется услугами уровня под собой и предоставляет услугу уровню над собой. Уровень N на одной машине «разговаривает» с уровнем N на другой и не знает, как нижние уровни доставляют его данные. Транспортный уровень не знает, идут ли данные по Wi-Fi или по оптике; Wi-Fi не знает, несёт он TCP или UDP.

Из этой идеи выросли две модели, которыми описывают сети: OSI и TCP/IP.


Модель OSI

Модель OSI (Open Systems Interconnection) опубликована ISO в 1984 году. У неё семь уровней, считают снизу вверх:

№ Уровень За что отвечает Единица данных Примеры
7 Прикладной (Application) Протокол самой программы: что означают передаваемые данные данные, сообщение HTTP — браузер запрашивает у сервера страницы; SMTP — серверы передают друг другу почту; SSH — удалённый терминал; DNS — превращает имена в адреса (часть 12)
6 Представления (Presentation) Кодировки, сжатие, шифрование данных приложения данные отдельного протокола в TCP/IP нет; сюда условно относят TLS — шифрование поверх TCP, на котором работает HTTPS
5 Сеансовый (Session) Установление и завершение сеансов, восстановление диалога данные отдельного протокола нет: сеансом управляет само приложение
4 Транспортный (Transport) Доставка данных конкретному процессу; надёжность и порядок, если нужны сегмент (TCP), датаграмма (UDP) UDP — только порты, без гарантий (часть 9); TCP — с доставкой, порядком и повторами (часть 10)
3 Сетевой (Network) Адресация машин во всей сети и выбор пути между сетями пакет IPv4 (части 5–6), IPv6 (часть 13), ICMP (часть 8)
2 Канальный (Data Link) Передача данных между соседями в одном сегменте: адреса соседей, кадры, обнаружение ошибок кадр Ethernet (часть 2), Wi-Fi (часть 3), PPP (часть 4), VLAN (часть 17)
1 Физический (Physical) Биты в сигнал: уровни напряжения, частоты, разъёмы, кабели биты витая пара, радио Wi-Fi, оптическое волокно

Полезно видеть, что на каждом уровне свой вид адреса:

Уровень Адрес Отвечает на вопрос
2 MAC-адрес 3c:52:82:1a:2b:3c какому соседу на этом кабеле отдать кадр
3 IP-адрес 192.168.1.10 какой машине в мире предназначен пакет
4 Порт 443 какому процессу на этой машине
7 Имя www.vitaliy.org, URL что именно нужно человеку

Главное, что нужно знать о модели OSI: в чистом виде её никто не реализует. У ISO был свой набор протоколов под каждый уровень (X.400, CLNP, TP4), и он проиграл TCP/IP ещё в 1990-х. Выжила сама схема — как общий язык. Когда говорят «L2-коммутатор», «L3-свитч», «балансировщик L7», «файрвол L4», имеют в виду уровни именно из этой таблицы: устройство смотрит на заголовки этого уровня и ниже и не трогает то, что выше.

Уровни 5 и 6 в реальных сетях размыты. Классический вопрос «на каком уровне TLS?» не имеет точного ответа: он лежит между транспортом и приложением, его называют и L5, и L6, и «L4.5». На практике это неважно: все эти функции живут внутри приложения или его библиотек.


Модель TCP/IP

Модель, по которой сети устроены на самом деле, описана в RFC 1122 и у неё четыре уровня:

TCP/IP Что внутри Уровни OSI
Прикладной (Application) Протокол приложения, включая кодировки, сеансы и TLS 7, 6, 5
Транспортный (Transport) TCP, UDP 4
Межсетевой (Internet) IP, ICMP, маршрутизация 3
Канальный (Link) Всё, что доставляет IP-пакет соседу: Ethernet, Wi-Fi, PPP вместе с физикой 2, 1

Разница с OSI одна: TCP/IP не делит на части то, что в реальных системах и так неделимо. Приложение само решает, шифровать ли ему данные и как держать сеанс, а сетевая карта вместе с драйвером отвечает и за кадры, и за сигнал в кабеле.

Дальше в серии я буду пользоваться нумерацией OSI (L2, L3, L4), потому что так говорят все, а по устройству следовать TCP/IP, потому что так всё работает.


Инкапсуляция: как пакет выглядит на проводе

Самая важная идея этой статьи. Каждый уровень берёт данные от уровня выше, приписывает к ним свой заголовок и отдаёт вниз. На проводе оказывается матрёшка из заголовков.

Возьмём запрос к сайту по HTTPS. Браузер отдал TLS-библиотеке HTTP-запрос, та зашифровала его и передала байты в TCP-сокет. Дальше по стеку:

                                        ┌───────────────────┐
прикладной:                             │ TLS-запись (HTTP) │
                                        └───────────────────┘
                           ┌────────────┬───────────────────┐
транспортный (TCP):        │ TCP 20 Б   │ данные            │
                           │ порты,     │                   │
                           │ seq, ack   │                   │
                           └────────────┴───────────────────┘
              ┌────────────┬────────────┬───────────────────┐
сетевой (IP): │ IPv4 20 Б  │ TCP        │ данные            │
              │ адреса,    │            │                   │
              │ TTL, proto │            │                   │
              └────────────┴────────────┴───────────────────┘
 ┌────────────┬────────────┬────────────┬───────────────────┬───────┐
 │ Ethernet   │ IPv4       │ TCP        │ данные            │ FCS   │
 │ 14 Б: MAC, │            │            │                   │ 4 Б   │
 │ EtherType  │            │            │                   │       │
 └────────────┴────────────┴────────────┴───────────────────┴───────┘
 ← это и уходит в кабель, слева направо

Размеры здесь минимальные: у заголовков IPv4 и TCP бывают опции, и тогда они длиннее 20 байт. Для кадра Ethernet без опций получаем 14 + 20 + 20 + данные + 4 байта контрольной суммы, которую считает сетевая карта.

На приёмной стороне матрёшка разбирается в обратном порядке, и здесь есть вопрос, без которого схема не работает: откуда уровень знает, что лежит внутри? Получив кадр, сетевой стек должен понять, отдать его содержимое IPv4, IPv6 или ARP. Получив IP-пакет — TCP, UDP или ICMP. Получив сегмент TCP — какому из процессов.

Ответ: в заголовке каждого уровня есть поле, которое говорит, что внутри. Это называется демультиплексированием.

Уровень Поле Значения
Ethernet EtherType (2 байта) 0x0800 IPv4, 0x86DD IPv6, 0x0806 ARP, 0x8100 VLAN
IPv4 / IPv6 Protocol / Next Header (1 байт) 1 ICMP, 6 TCP, 17 UDP, 50 ESP (зашифрованный пакет IPsec, часть 19), 58 ICMPv6 (часть 14)
TCP / UDP порт назначения (2 байта) 443 HTTPS, 53 DNS, 22 SSH; в общем случае — что слушает процесс

Так что сетевой стек — это по сути цепочка switch-ов: прочитать заголовок, посмотреть в поле «что внутри», снять заголовок, отдать следующему обработчику.

Вот как это выглядит в tcpdump для первого пакета TCP-соединения к веб-серверу. Ключ -e просит показать и заголовок Ethernet:

$ sudo tcpdump -i eth0 -n -e 'tcp port 443' -c 1
12:00:01.123456 3c:52:82:1a:2b:3c > d8:47:32:0a:0b:0c, ethertype IPv4 (0x0800), length 74:
    192.168.1.10.51234 > 203.0.113.10.443: Flags [S], seq 1234567890, win 64240,
    options [mss 1460,sackOK,TS val 100 ecr 0,nop,wscale 7], length 0

Разбираем по уровням:

  • L2: кадр от MAC 3c:52:82:1a:2b:3c (моя сетевая карта) к d8:47:32:0a:0b:0c (это роутер, а не сервер — почему, через раздел), EtherType 0x0800, то есть внутри IPv4. Длина кадра 74 байта: 14 Ethernet + 20 IPv4 + 40 TCP (20 заголовка и 20 опций). Контрольную сумму tcpdump не показывает: её снимает сетевая карта.
  • L3: от 192.168.1.10 к 203.0.113.10, протокол TCP — иначе tcpdump не разобрал бы порты.
  • L4: с порта 51234 на порт 443, флаг S (SYN, начало соединения), данных 0 байт.

Про названия единиц данных. Строго говоря, на L2 это кадр (frame), на L3 — пакет (packet), на L4 — сегмент у TCP и датаграмма у UDP. В разговоре всё называют пакетами, и я буду так же, когда уровень неважен. Когда важен — буду говорить «кадр» или «сегмент».


Кто что обрабатывает по пути

Пакет из примера выше пройдёт примерно такой путь:

ноутбук ──► коммутатор ──► домашний роутер ──► роутер провайдера ──► … ──► сервер
  L1–L7        L2               L3                   L3                        L1–L7

Каждое устройство на пути разбирает матрёшку только до своего уровня:

  • Коммутатор читает заголовок Ethernet, по MAC-адресу назначения выбирает порт и отправляет кадр туда, не меняя в нём ни байта. Что внутри — IPv4, IPv6, ARP — ему всё равно. Это устройство L2.
  • Роутер снимает заголовок Ethernet целиком, читает заголовок IP, по адресу назначения находит в своей таблице маршрутов следующий роутер (next hop), уменьшает TTL на единицу, пересчитывает контрольную сумму заголовка IP и упаковывает пакет в новый кадр: с собственным MAC-адресом отправителя и MAC-адресом следующего роутера в поле получателя. Если следующий интерфейс не Ethernet, а, скажем, PPPoE (часть 4) или сотовая сеть — пакет уедет в кадр совсем другого формата. IP-пакету это безразлично. Это устройство L3.
  • Сервер разбирает всё до приложения.

Отсюда таблица того, что меняется по дороге:

Что Меняется ли
MAC-адреса в кадре на каждом участке между роутерами — новые
IP-адреса не меняются от отправителя до получателя (исключение — NAT, часть 6)
TTL в заголовке IP минус один на каждом роутере
TCP-заголовок и данные не трогаются (исключения — NAT и файрволы, тоже часть 6)

Теперь понятно, почему в tcpdump кадр шёл на MAC роутера, а не сервера: MAC-адрес — это адрес соседа на этом кабеле, IP-адрес — адрес конечного получателя. Ноутбук знает, что 203.0.113.10 не в его сети, значит, кадр надо отдать роутеру, а уж тот разберётся дальше. Как ноутбук узнаёт MAC роутера — тема части 7 про ARP; как решает, что адрес «не в его сети» — части 5.

Это же отвечает на вопрос, который задают все начинающие: зачем два адреса, если есть IP? Потому что они про разное. IP-адрес глобален и не зависит от среды передачи; MAC-адрес живёт в пределах одного сегмента Ethernet и ничего не знает о сетях за роутером. У Wi-Fi есть MAC-адреса, у PPP их нет вовсе, а IP работает поверх и того и другого.


Зачем нужна независимость уровней и где она протекает

Выключите кабель и включите Wi-Fi: IP-адрес может остаться тем же, TCP-соединения тем более ничего не узнают о смене среды (если адрес не поменялся). Поменяйте TCP на UDP: Ethernet не заметит. Это и есть выигрыш от уровней: за сорок лет сменилось несколько поколений физики, от коаксиала до 400-гигабитной оптики, а IP-пакет 1981 года в них всех одинаковый.

Но абстракция не абсолютна, и большая часть «интересных» сетевых проблем — там, где она протекает:

  • MTU. Размер кадра L2 ограничивает размер пакета L3: в Ethernet это 1500 байт. Пакет большего размера надо либо резать (фрагментация), либо узнать об ограничении заранее (Path MTU Discovery). Об этом в частях 6 и 8, а симптом «пинг ходит, сайт не открывается» растёт именно отсюда.
  • NAT. Домашний роутер, устройство L3, переписывает адреса в заголовке IP и порты в заголовке TCP/UDP, то есть лезет на уровень выше своего. Часть 6.
  • Файрволы и балансировщики принимают решения по портам и даже по содержимому HTTP, хотя стоят посреди сети.
  • Wi-Fi повторяет кадры при потерях на радио, и TCP над ним видит не потери, а странные задержки. Часть 3.

Понимание того, что уровни независимы по замыслу, но связаны на практике, — половина умения разбираться в сетевых проблемах.


Смотрим руками

На любой Linux-машине уровни видны прямо в командах. Каждая команда показывает свой этаж.

Канальный уровень — интерфейсы и их MAC-адреса:

$ ip link
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 3c:52:82:1a:2b:3c brd ff:ff:ff:ff:ff:ff

Сетевой уровень — IP-адреса и таблица маршрутов, по которой стек решает, кому отдать пакет:

$ ip addr show eth0
    inet 192.168.1.10/24 brd 192.168.1.255 scope global dynamic eth0

$ ip route
default via 192.168.1.1 dev eth0
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.10

Транспортный уровень — кто какие порты слушает:

$ ss -tlnp
State   Recv-Q  Send-Q  Local Address:Port   Peer Address:Port  Process
LISTEN  0       128           0.0.0.0:22          0.0.0.0:*      users:(("sshd",pid=812,fd=3))

И всё сразу — tcpdump. Запустите его в одном окне, а в другом откройте любой сайт:

$ sudo tcpdump -i eth0 -n -e -c 20

Ключи: -i — интерфейс, -n — не превращать адреса в имена (иначе tcpdump сам полезет в DNS и засорит вывод), -e — показывать заголовок Ethernet, -c — сколько пакетов поймать.

Ещё нагляднее Wireshark. Поймайте тем же tcpdump -w capture.pcap файл или запустите захват в самом Wireshark, откройте и щёлкните по любому пакету. Средняя панель — это ровно наша матрёшка, уровень за уровнем:

▸ Frame 1: 74 bytes on wire
▸ Ethernet II, Src: 3c:52:82:1a:2b:3c, Dst: d8:47:32:0a:0b:0c
▸ Internet Protocol Version 4, Src: 192.168.1.10, Dst: 203.0.113.10
▸ Transmission Control Protocol, Src Port: 51234, Dst Port: 443, Seq: 0, Len: 0

Раскройте каждый уровень: там все поля заголовка с значениями, а в нижней панели подсвечены байты, которым они соответствуют. В каждой следующей части серии мы будем смотреть на заголовки именно так.


Что запомнить

  • Сетевой стек разбит на уровни, каждый решает одну задачу и пользуется уровнем под собой. OSI — семиуровневая модель-язык (L2, L3, L7), TCP/IP — четырёхуровневая модель того, как всё устроено на самом деле.
  • Каждый уровень добавляет свой заголовок; на проводе — матрёшка Ethernet → IP → TCP/UDP → данные.
  • В каждом заголовке есть поле «что внутри»: EtherType, Protocol, порт. По ним принимающая сторона разбирает матрёшку.
  • Коммутатор смотрит на L2, роутер на L3, конечные машины — на всё. MAC-адреса меняются на каждом участке, IP-адреса доходят до конца.
  • Абстракция уровней протекает: MTU, NAT, файрволы. Там живут самые интересные проблемы.

Дальше — Ethernet: формат кадра по байтам, устройство MAC-адреса, что на самом деле делает коммутатор, почему минимальный кадр — 64 байта и что такое duplex mismatch.

Оставить комментарий могут только зарегистрированные пользователи.

Войдите на сайт или зарегистрируйтесь, чтобы оставить комментарий.