IPv4 і адресація
Навіщо це
Section titled “Навіщо це”ping до сервера проходить, ssh заходить, а сайт не відкривається: сторінка
починає вантажитися й зависає. Або навпаки: маленькі запити працюють, а
завантаження файлу зупиняється на першому ж мегабайті. Типова причина
таких випадків, і саме про неї цей модуль:
пакет завбільшки 1500 байтів не пролазить через якусь вузьку ланку, а
повідомлення про це загубилося по дорозі.
Щоб до цього дійти, доведеться розібратися з IPv4 і ICMP: з чого складається пакет, як хост вирішує, чи адресат «свій», і що означають відповіді, які приходять від маршрутизаторів.
Передумови. Кадр, MAC-адреса, MTU — модуль 4. ARP і таблиця
сусідів — модуль 5. Двійкова система: вміння записати
число 77 як 01001101.
Адреса і мережа
Section titled “Адреса і мережа”IPv4-адреса складається з 32 бітів. Їх пишуть як чотири десяткові числа від 0 до 255
через крапку: 192.168.10.77. Кожне число — один байт, тому й називається
октетом.
Адреса нічого не означає без знання, де закінчується «мережа» і починається
«вузол у ній». Хост має це знати, бо від цього залежить вибір: якщо
адресат у тій самій мережі, кадр адресується йому напряму (через ARP);
якщо в іншій, кадр іде на шлюз. Межу задає префікс: число лівих бітів,
які належать мережі. Запис 192.168.10.77/26 каже, що перші 26 біт адреси —
номер мережі, а останні 6 — номер вузла всередині неї.
Той самий префікс записують і маскою: 26 одиниць і 6 нулів, тобто
255.255.255.192. Щоб з адреси дізнатися мережу, достатньо побітового «І»
адреси й маски.
Для 192.168.10.77/26 звідси виходить:
- Адреса мережі — біти вузла всі нулі:
192.168.10.64. Вона ідентифікує мережу й вузлу не призначається. - Широкомовна адреса — біти вузла всі одиниці:
192.168.10.127. Пакет на неї адресований усім у підмережі. Її теж не призначають. - Вузлів у цій підмережі
2⁶ − 2 = 62: від192.168.10.65до192.168.10.126. Кожен додатковий біт префікса вдвічі зменшує розмір підмережі.
Розбити 10.0.0.0/24 на чотири рівні підмережі означає взяти два біти зі
сфери вузла: 10.0.0.0/26, 10.0.0.64/26, 10.0.0.128/26, 10.0.0.192/26.
Кожна має по 62 вузли. Не треба ділити в десятковому записі: достатньо
подивитися, де в двійковому записі закінчується префікс.
Навіщо префікс, а не класи
Section titled “Навіщо префікс, а не класи”До 1993 року межа визначалася самою адресою: «клас A» (/8), «клас B» (/16),
«клас C» (/24). Організації, яким не вистачало 254 адрес класу C, отримували
цілий клас B на 65 тисяч і марнували решту. Тому вигадали CIDR
(classless inter-domain routing): префікс може мати довільну довжину, а
маршрутизатори пересилають пакети за префіксами, не зважаючи на класи. Це також
дозволило об’єднувати сусідні мережі в один запис в таблицях інтернету.
Про вибір запису в таблиці маршрутів — модуль 7.
Спеціальні діапазони
Section titled “Спеціальні діапазони”Не кожна адреса придатна для інтернету. Запам’ятайте ті, що траплятимуться:
| Діапазон | Призначення |
|---|---|
10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 |
приватні мережі (RFC 1918): не маршрутизуються в інтернеті, кожна організація користується ними вільно |
100.64.0.0/10 |
спільна адресація операторів (CGNAT, RFC 6598), про неї в модулі 9 |
127.0.0.0/8 |
loopback: пакет ніколи не залишає хост; 127.0.0.1 зазвичай називається localhost |
169.254.0.0/16 |
link-local (RFC 3927): хост сам обирає адресу, якщо не отримав ніякої, і вона діє лише в межах сегмента |
192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 |
для документації й прикладів (RFC 5737); саме їх використовує цей курс |
224.0.0.0/4 |
multicast |
255.255.255.255 |
обмежене широкомовлення: «усім у цьому сегменті» |
0.0.0.0 |
«невизначена адреса»: «будь-яка» для сервера, що слухає, або «ще не маю адреси» |
Якщо хост несподівано має адресу з 169.254.0.0/16, значить, DHCP-сервера
він не знайшов. Це перше, що варто перевіряти.
Заголовок IPv4
Section titled “Заголовок IPv4”Кожен пакет IPv4 починається з заголовка мінімум 20 байтів.
Справжній заголовок пакета ping, знятий tcpdump -x (шістнадцяткові байти),
читається так:
45 00 0054 d7b5 4000 40 01 4bf0 0a00 0102 0a00 02024— версія,5— довжина заголовка в 32-бітних словах (5 × 4 = 20 байтів);00— DSCP і ECN (пріоритет і позначка перевантаження);0054— повна довжина пакета: 84 байти (20 заголовка + 64 ICMP);d7b5— ідентифікатор, за ним збирають фрагменти;4000— прапорці й зсув:010у старших трьох бітах — встановлений DF (don’t fragment), зсув нуль;40— TTL 64;01— протокол верхнього рівня: 1 — ICMP, 6 — TCP, 17 — UDP;4bf0— контрольна сума заголовка;0a00 0102— адреса відправника10.0.1.2;0a00 0202— отримувача10.0.2.2.
Контрольна сума покриває лише заголовок, не дані. Її складають у 16-бітових словах
з перенесенням старшого розряду, і коректний заголовок дає 0xffff. Кожен
маршрутизатор зменшує TTL, тож мусить перерахувати суму. Контрольну суму даних перевіряють протоколи вище (TCP, UDP), а
для IPv6 її в заголовку взагалі прибрали.
TTL (time to live) кожен маршрутизатор зменшує на одиницю, і коли значення стає нулем, пакет відкидається. Так пакет не ходитиме мережею вічно, якщо утворилася маршрутна петля. Початкове значення кожна ОС обирає свою, для Linux це 64. За TTL у відповіді можна грубо оцінити, скільки маршрутизаторів вона пройшла, якщо знати, з якого значення вона стартувала.
ICMP: мережа відповідає про себе
Section titled “ICMP: мережа відповідає про себе”Пакет може не дійти, і мережа має повідомити про це відправника. Для цього є ICMP (internet control message protocol). Це окремий протокол із номером 1, що їде всередині IP. Хост чи маршрутизатор, який щось не зміг зробити, надсилає ICMP-повідомлення відправникові. Повідомлення про помилку містить початок пакета, через який воно виникло, щоб отримувач зіставив його з власним потоком.
Важливі типи:
| Тип | Значення | Коли виникає |
|---|---|---|
| 8 / 0 | echo request / echo reply | саме їх використовує ping |
| 3 | destination unreachable | код 0 — мережа недоступна, 1 — хост, 3 — порт (UDP-порт закритий), 4 — потрібна фрагментація, але встановлено DF |
| 11 | time exceeded | код 0 — TTL дійшов до нуля дорогою; код 1 — не вдалося зібрати фрагменти вчасно |
| 5 | redirect | маршрутизатор радить використати інший шлюз |
Даних ICMP не переносить, він потрібен для діагностики. Проте коли файрволи його блокують, з’являються дивні поломки, про них нижче.
Як працює traceroute
Section titled “Як працює traceroute”Задача: дізнатися, через які маршрутизатори пройшов пакет до адресата. Жоден вузол не
повідомляє про себе, тому traceroute хитрує з TTL.
-
Надіслати пакет із TTL 1. Перший маршрутизатор зменшить його до нуля, відкине пакет і відповість ICMP
time exceededзі своєї адреси. Це перший рядок виводу. -
Надіслати пакет із TTL 2. Перший маршрутизатор пропустить, другий відкине й відповість. Другий рядок.
-
Так далі, поки пакет не дійде до адресата. За замовчуванням
tracerouteвідправляє UDP на високий порт, який ніхто не слухає (починаючи з 33434). Адресат відповідає ICMPport unreachable, і за цією відповіддюtracerouteрозуміє, що дійшов.
З висновками з виводу краще не поспішати. Маршрутизатор відповідає зі своєї адреси на інтерфейсі, до якого потрапив
пакет, а зворотна дорога пакета може бути зовсім іншою. Рядок із зірочками
* * * означає, що відповіді не було: маршрутизатор нічого не надіслав (файрвол
або обмеження швидкості ICMP, яке ядро Linux вмикає за замовчуванням:
net.ipv4.icmp_ratelimit дорівнює 1000 мс, тому при швидких повторних
запусках відповіді можуть губитися), але це не значить, що пакети через
нього не йдуть. Якщо в мережі кілька рівноцінних маршрутів, різні пакети одного
трасування можуть піти різними шляхами.
Фрагментація і Path MTU Discovery
Section titled “Фрагментація і Path MTU Discovery”Модуль 4 закінчився тим, що кадр Ethernet несе до 1500 байтів
навантаження, а пакет IP може мати розмір до 65 535 байтів. Коли пакет
більший за MTU ланки, куди його треба відправити, IPv4 дозволяє
фрагментацію: маршрутизатор розрізає пакет на частини, які
влізають, і надсилає кожну окремим пакетом IP. Усі фрагменти мають однаковий
Identification. Поле Fragment Offset (у вісімках байтів) каже, де фрагмент
стояв у початковому пакеті, а прапорець MF (more fragments) — що за ним є ще.
Склеює фрагменти лише адресат, не проміжні вузли. Подивіться, як виглядає
відповідь на ping -s 3000 у tcpdump -v:
IP (ttl 64, id 34195, offset 0, flags [+], proto ICMP (1), length 1500)IP (ttl 64, id 34195, offset 1480, flags [+], proto ICMP (1), length 1500)IP (ttl 64, id 34195, offset 2960, flags [none], proto ICMP (1), length 68)З фрагментацією багато клопоту. Один втрачений фрагмент означає втрату всього пакета, бо решту доведеться чекати даремно. Адресат мусить тримати фрагменти в пам’яті, що давало простір для атак. Файрволи й NAT, які дивляться на порти, не бачать їх у фрагментах, крім першого. Сучасні програми фрагментації уникають.
Її можна й не допустити: відправник виставляє біт DF і дізнається, яким має бути розмір. Так працює Path MTU Discovery (PMTUD):
-
Відправник посилає пакети з DF, за розміром свого MTU.
-
Якщо якась ланка має менший MTU, маршрутизатор не може ні передати пакет, ні фрагментувати його, тож відкидає й надсилає ICMP: тип 3, код 4 («потрібна фрагментація, але встановлено DF»). У повідомленні вказано MTU, який підходить.
-
Відправник запам’ятовує цей MTU для шляху до адресата й надалі шле пакети меншого розміру. TCP для цього зменшує розмір сегмента.
«Чорна діра» PMTUD
Section titled “«Чорна діра» PMTUD”Увесь механізм тримається на тому, що ICMP-повідомлення доходить. Якщо
якийсь файрвол відкидає весь ICMP «заради безпеки», відправник ніколи не
дізнається про малий MTU. TCP-з’єднання при цьому встановлюється, бо
пакети рукостискання малі. Потім великі пакети тихо зникають, відповіді нема, і після
вичерпання спроб з’єднання зависає. ping працює, бо його пакети теж малі,
і виходить та сама картина, що у вступі.
Найчастіше так буває там, де MTU менший за 1500: тунелі VPN, PPPoE (типове значення MTU 1492), обгортки на кшталт GRE чи VXLAN (модуль 18), де додаткові заголовки з’їдають частину кадра. Що з цим роблять:
- Не блокувати ICMP тип 3 код 4. Решта ICMP може бути заблокована, цей обов’язково ні.
- MSS clamping: маршрутизатор на вузькій ланці переписує розмір сегмента в рукостисканнях TCP, і сторони самі не надсилають більших пакетів, ніж здатна пропустити ланка.
- Packetization-layer PMTUD (RFC 4821): TCP сам пробує розміри й визначає
межу за відсутністю підтвердження. У Linux вмикається параметром
net.ipv4.tcp_mtu_probing.
Як це насправді в Linux
Section titled “Як це насправді в Linux”Будуємо ланцюжок із двох хостів і двох маршрутизаторів у просторах імен
(команди ip netns, ip link add … type veth, ip addr, ip route — за
модулем 4; кожен маршрутизатор додатково потребує
sysctl -w net.ipv4.ip_forward=1, про це в модулі 7).
Топологія така:
h1 10.0.1.2 — 10.0.1.1 r1 10.0.12.1 — 10.0.12.2 r2 10.0.2.1 — 10.0.2.2 h2У h1 і h2 типовий маршрут веде на сусіднього маршрутизатора, а між r1 і r2
прописані маршрути до далеких підмереж. Перевіримо зв’язок і шлях:
sudo ip netns exec h1 traceroute -n 10.0.2.2traceroute to 10.0.2.2 (10.0.2.2), 30 hops max, 60 byte packets 1 10.0.1.1 0.019 ms 0.003 ms 0.019 ms 2 10.0.12.2 0.188 ms 0.004 ms 0.003 ms 3 10.0.2.2 0.010 ms 0.008 ms 0.004 msТри рядки — три стрибки, кожен відповів зі своєї адреси. Якщо додати -I,
traceroute шлє ICMP echo замість UDP. Подивіться на TTL: ping -c1 -t 1 10.0.2.2
закінчується повідомленням Time to live exceeded від першого маршрутизатора.
Тепер підберемо розмір. Зменшимо MTU ланки r1 — r2 до 1400 з обох боків
(ip link set c1 mtu 1400 на r1 і ip link set d1 mtu 1400 на r2) і
відправимо з h1 найбільший пакет, що влізає в 1500, із забороною фрагментації:
sudo ip netns exec h1 ping -c1 -M do -s 1472 10.0.2.2PING 10.0.2.2 (10.0.2.2) 1472(1500) bytes of data.From 10.0.1.1 icmp_seq=1 Frag needed and DF set (mtu = 1400)Тут розмір 1472 — це 1500 мінус 20 байтів заголовка IP і 8 байтів заголовка ICMP.
Маршрутизатор r1 відповів типом 3 кодом 4 і повідомив MTU. Ядро
h1 запам’ятало це значення:
sudo ip netns exec h1 ip route get 10.0.2.210.0.2.2 via 10.0.1.1 dev a1 src 10.0.1.2 uid 0 cache expires 599sec mtu 1400Запис із mtu 1400 живе близько десяти хвилин. Наступний ping -M do -s 1372
(1400 байтів разом із заголовками) проходить. Щоб побачити PMTUD самому,
є tracepath -n 10.0.2.2 (пакет iputils-tracepath): він збільшує TTL, як
traceroute, і водночас показує pmtu на кожному кроці. Виводить
pmtu 1400 на другому кроці й підсумок Resume: pmtu 1400 hops 3. Те саме
вміє traceroute --mtu.
А тепер зробимо чорну діру. На r1 заборонимо вихідні ICMP «destination
unreachable» і очистимо кеш у h1:
sudo ip netns exec r1 nft add table inet fsudo ip netns exec r1 nft 'add chain inet f out { type filter hook output priority 0; }'sudo ip netns exec r1 nft add rule inet f out icmp type destination-unreachable dropsudo ip netns exec h1 ip route flush cachesudo ip netns exec h1 ping -c2 -W1 -M do -s 1472 10.0.2.2sudo ip netns exec h1 ping -c2 -W1 -M do -s 1372 10.0.2.22 packets transmitted, 0 received, 100% packet loss, time 1003ms2 packets transmitted, 2 received, 0% packet loss, time 1011msВеликий пакет пропав без жодного повідомлення, а менший пройшов. Тепер
те саме з TCP: простий сервер на h2 читає дані, клієнт на h1 відсилає
спершу 10 байтів, а потім 20 000. Сервер отримав перші десять і більше нічого:
server got 10 bytes, then TimeoutErrorss -tin dst 10.0.2.2 на клієнті показує, що сокет застряг:
pmtu:1500, є повторні передачі (retrans, backoff), і в черзі лишилися
неподані байти. Ядро не знає про вузьку ланку й упирається в неї.
Для порядку про фрагментацію: ping -c1 -s 3000 -M dont 10.0.2.2 відправляє
пакет без DF. Якщо ви знімете його tcpdump -v на ланці з MTU 1400, то побачите
фрагменти (flags [+], offset). Лічильники nstat -az IpFragCreates IpReasmOKs
покажуть, скільки фрагментів створив маршрутизатор і скільки пакетів склав адресат.
Прибрати за собою: видаліть простори імен (sudo ip netns delete h1 тощо).
Типові помилки розуміння
Section titled “Типові помилки розуміння”«Маска /24 завжди означає 254 хости». Це арифметика для /24: 2⁸ − 2.
Для /26 виходить 62, для /30 лише 2. Число хостів дорівнює 2 у степені
кількості бітів вузла, мінус адреса мережі й широкомовна.
«Приватна адреса не може бути в інтернеті». Вона нікуди не заборонена, просто маршрутизатори провайдерів її не пересилають. Тому на межі організації потрібен NAT (модуль 9), а помилкове витікання приватних адрес назовні зазвичай означає, що пакет не дійде.
«TTL — це час у секундах». Назва історична. Фактично це лічильник стрибків. Кожен маршрутизатор віднімає одиницю незалежно від того, скільки пакет там простояв.
«traceroute показує шлях, яким піде мій трафік». Показує шлях
пробних пакетів, і то лише тих маршрутизаторів, що відповіли. Трафік може
ходити іншим шляхом, а зворотний маршрут взагалі не видно.
«ICMP небезпечний, його можна блокувати повністю». Повне блокування ICMP ламає PMTUD і призводить до тих самих «зависань великих передач». Потрібно пропускати хоча б тип 3 код 4 (і «time exceeded» для діагностики).
«Фрагментація — нормальне рішення для великих пакетів». У IPv4 вона можлива, але дорога й ненадійна, а в IPv6 проміжні маршрутизатори не фрагментують зовсім: лише відправник.
Перевір себе
Лабораторна
Section titled “Лабораторна”A2. Власні ping і traceroute: ви сформуєте заголовок IPv4 і ICMP вручну, порахуєте контрольну суму й зробите те, що описано в розділах про TTL і ICMP, на raw-сокетах.
B2. Linux як маршрутизатор: три підмережі, адреси, маршрути й NAT. Тут знадобиться вміння ділити підмережі.
A3. Розбір пакетів із pcap: ви розберете заголовок IPv4 за байтами, так само, як у розділі «Заголовок IPv4».
B7. Налагодження зламаної мережі: серед несправностей буде й MTU; тепер ви знаєте, як вона виглядає.
Джерела
Section titled “Джерела”- RFC 791 (IP), RFC 792 (ICMP), RFC 1191 (Path MTU Discovery), RFC 1918 (приватні адреси), RFC 4632 (CIDR), RFC 3927 (link-local), RFC 5737 (адреси для документації), RFC 6598 (спільна адресація)
- RFC 4821 (Packetization Layer Path MTU Discovery)
- Kurose, Ross, Computer Networking: A Top-Down Approach, розділ про мережевий рівень
- Stevens, TCP/IP Illustrated, Vol. 1, розділи про IP, ICMP і фрагментацію
man 8 ip-route,man 8 traceroute,man 8 tracepath,man 8 ping- Документація ядра Linux:
Documentation/networking/ip-sysctl.rst