Дрібні ping цілий день проходять крізь тунель, надходить банер SSH, і в момент початку передавання файлу сеанс завмирає. Цей шаблон указує на бюджет байтів, порахований на неправильному рівні, де зовнішній тунель був розмірений під власні накладні витрати, а внутрішній ніхто не відняв. Вкладений пакет IPIP для WireGuard — просто ще один IP-пакет, і саме тому він витрачає байти, які ви ніколи не резервували. Виправлення — арифметика, і воно вміщується в три команди та одну таблицю.

Симптом, який це викриває

Проблеми фрагментації заявляють про себе розміром, ніколи адресами. Ваш партнер годину відповідає на 56-байтовий ping, а потім замовкає на 1400 байтах, поки тунель залишається піднятим і жоден маршрут не змінився. Рукостискання вміщується, перше повне вікно TCP — ні, і передавання зупиняється через секунди після того, як виглядало здоровим.

Виміряйте стелю, перш ніж щось редагувати, бо невиміряна стеля — та, за якою ви будете гнатися двічі. Надішліть один зонд нижче підозрілого розміру з увімкненим бітом do-not-fragment, ping -M do -s 1000 10.9.0.2, потім повторіть його на розмірі, про який ви вже знаєте, що він завеликий. Коли перевертання йде за розміром корисного навантаження, а пункт призначення лишається незмінним, маршрутизація робить свою роботу, і в бюджеті бракує одного заголовка.

Лічіть кожен заголовок один раз, на правильному рівні

Почніть із найменшого MTU на шляху, а не з інтерфейсу тунелю, бо стіна стоїть вище обох кінців. WireGuard витрачає 60 байтів на зовнішній транспорт IPv4: 20 на IP, 8 на UDP і 32 на власний заголовок, і 80 байтів, коли цей транспорт — IPv6. wg0 розміром 1420 байтів тримає 20 байтів запасу під 1440, які шлях у 1500 байтів справді може доставити, і тому число, скопійоване з вікі досі тут пасує. Намалюйте весь стек на схемі, бо той, хто наступним змінить MTU, інакше вибере нове кругле число й успадкує вашу помилку.

LayerBytesRemaining
Path MTU on the wired linknone yet1500
WireGuard outer: IP, UDP, WG header601440
Slack kept for safety201420 (wg0)
IPIP header inside the tunnel201400 (ipip0)
Original IPv4 and TCP headers401360 payload

П'ятий рядок — це місце, де бюджети ламаються, бо 1400 байтів, які несе вкладений інтерфейс, уже містять власні 40 байтів заголовків початкового пакета. Лише 1360 із цих байтів доходять до процесу, що читає файл. Вважайте 1400 корисним навантаженням застосунку, як запрошує будь-яка схема без цієї колонки, і внутрішній пристрій виявляється на 40 байтів занадто щедрим перед стіною, що не зрушила.

Задайте два MTU окремо

Носій і вкладений пристрій — окремі об'єкти, тому кожен потребує власного значення. Застосуйте їх у цьому порядку, бо вкладений пристрій нічого не успадковує від носія:

ip link set wg0 mtu 1420
ip tunnel add ipip0 mode ipip remote 203.0.113.9 local 198.51.100.4
ip link set ipip0 mtu 1400

Правило, яке варто запам'ятати: внутрішній MTU = зовнішній MTU - 20, коли пакет, який несе тунель IPIP, — IPv4, і - 40, щойно будь-яка сторона внутрішнього пакета стає IPv6, бо вкладений заголовок зростає з 20 байтів до 40. Ніщо інше не входить у це віднімання. Накладні витрати WireGuard уже були витрачені, коли ви обрали 1420, а їхнє подвійне стягнення дає тунель, який працює бездоганно й залишається повільним, доки ніхто його не міряє. Розгортання, де обидва пристрої несуть круглі 1400, — це відбиток саме тієї помилки.

IPv6 на будь-якій стороні вкладеного пакета знецінює кожне число вище, тож перерахуйте, а не копіюйте число зі схожого сайту. Віднімні заголовки — по 40 байтів кожен, щойно IPv6 з'являється на зовнішньому шляху або в початковій датаграмі, і число корисного навантаження падає рівно на стільки.

Правило брандмауера, яке вам, імовірно, не потрібне

Між двома партнерами WireGuard єдине, що йде дротом, — UDP, тож вхідне правило для протоколу 4, номера, який RFC 2003 призначає інкапсуляції IPv4-в-IPv4, не створює вкладений шлях і не підтримує його. Заголовок IPIP живе всередині зашифрованого корисного навантаження, де його не бачить жоден межовий брандмауер. Відкриття протоколу 4 все одно не купує нічого, крім ще одного дозволеного шляху до хоста.

Політика, що згадує джерела й призначення початкового пакета, належить після декапсуляції, на інтерфейсах тунелю та в таблиці маршрутизації. Покладіть її туди, і межове правило може лишатися закритим.

Що WireGuard насправді перевіряє

AllowedIPs судить джерело пакета, який несе WireGuard, а несе він пакет, інкапсульований в IPIP. Дозволене джерело IPIP приймається навіть тоді, коли внутрішній заголовок називає хост, який ви воліли б не маршрутизувати. Отже, початкове джерело — не те, що партнер перевірив за вас, і цій внутрішній парі адрес потрібне власне забезпечення після декапсуляції.

Обгортка дає структуру маршрутизації, а не другий шар криптографії. Називати IPIP додатковим захистом усередині WireGuard — це описувати інший дизайн.

Перевіряйте драбиною, а не одним ping

Перевірте розміри, що охоплюють обчислену межу, потім підтвердьте, що ядро думає про обидва пристрої. Коли 1360 байтів корисного навантаження плюс 40 байтів заголовків дають 1400, перше відлуння нижче проходить, а друге сидить на байт за стелею:

ping -M do -s 1372 10.9.0.2
ping -M do -s 1373 10.9.0.2
wg show wg0
ip -d link show ipip0

Чистий прохід під стелею та збій на першому розмірі над нею означають, що арифметика тримається від початку до кінця. Потім знову запустіть передавання, яке спочатку застрягло, бо синтетичний зонд доводить бюджет і нічого не каже про власні розміри запису відправника. Якщо вкладений шлях усе ще ламається на розмірі, який ви довели як придатний, перевірте декапсуляцію та маршрути далекого кінця, перш ніж зрізати ще десять байтів з MTU.

Схожі статті