Перейти до вмісту

IPv6

Ви підняли сайт і переконалися, що він відкривається. А колега в іншій країні каже, що на його телефоні сторінка відкривається помітно повільніше, ніж на ноутбуці. Телефон сидить у мобільній мережі, де IPv4 працює через NAT провайдера, а IPv6 видається напряму. У DNS вашого сайту є запис AAAA, але сервер нікого не слухає на IPv6-адресі. Телефон пробує IPv6 першим, не отримує відповіді й лише після паузи переходить на IPv4. Ви цієї помилки не бачите, бо з вашого боку IPv6 не використовується.

Такі історії трапляються все частіше: дедалі більша частина інтернету, особливо мобільного, дістається через IPv6, і для частини користувачів це основний протокол. Адміністратор, який не вміє подивитися на IPv6-адресу інтерфейсу, прочитати ip -6 route чи зрозуміти, чому localhost ніби працює, а з’єднання відмовляє, програє на рівному місці.

Другий привід вивчити IPv6: він розв’язує цілу низку проблем, які в IPv4 доводилося латати окремо. Адрес вистачає на всіх, тож NAT зникає; хост налаштовує сам себе без DHCP, а комутатор не заливає мережу широкомовними запитами.

Передумови. IPv4, CIDR і підмережі (модуль 6), таблиця маршрутів (модуль 7), ARP (модуль 5), DHCP і NAT (модуль 9). Фрагментацію й Path MTU Discovery для IPv4 розібрано в модулі 6.

IPv4-адреса має 32 біти, отже близько чотирьох мільярдів значень. Для початку 1980-х цього вистачало з запасом, а для світу з мільярдами смартфонів уже ні. Центральний реєстр (IANA) роздав останні великі блоки регіональним реєстраторам у 2011 році, а згодом і регіональні реєстратори почали вичерпуватися. Відтоді адреси IPv4 купують і орендують.

Тимчасово рятують NAT і CGNAT (модуль 9): вони дозволили багатьом пристроям ховатися за однією адресою ціною втрати наскрізного з’єднання. Справжнім розв’язком став новий протокол із 128-бітними адресами, IPv6. Кількість адрес у ньому близько 3,4·10³⁸. Це настільки багато, що постає питання не «скільки адрес видати», а «як зручніше їх розкласти».

Заодно IPv6 прибрав те, що в IPv4 виявилося зайвим чи незручним:

  • Заголовок має фіксований розмір 40 байтів. У IPv4 його довжина змінна (через необов’язкові поля), і маршрутизатору доводиться її розбирати. У IPv6 необов’язкове винесено в окремі розширювальні заголовки, а основний завжди однаковий.
  • Контрольної суми в заголовку немає. Її перевіряють канальний рівень і транспорт (у TCP і UDP сума покриває псевдозаголовок із адресами), тож маршрутизатору не треба перераховувати суму на кожному переході після зменшення TTL.
  • TTL перейменовано на Hop Limit. Функція та сама: зменшується на кожному маршрутизаторі, і на нулі пакет відкидається. Просто назва тепер чесна: це кількість переходів, а не час.
  • Маршрутизатори не фрагментують пакети. Про це нижче.

IPv6-адресу пишуть як вісім груп по чотири шістнадцяткові цифри через двокрапку:

2001:0db8:0000:0000:0000:ff00:0042:8329

Писати так довго, тому адресу скорочують.

  1. У кожній групі можна прибрати ведучі нулі: 0db8 стає db8, 0042 стає 42, 0000 стає 0.
  2. Одну найдовшу послідовність груп, що складаються лише з нулів, можна замінити на ::. Тільки один раз на адресу, інакше незрозуміло, скільки нулів у кожному пропуску.

Застосовуємо обидва: 2001:db8::ff00:42:8329. Адресу з кількома послідовностями нульових груп скорочують по найдовшій, а за рівних по першій. Так, 2001:db8:0:0:1:0:0:1 стає 2001:db8::1:0:0:1, а не 2001:db8:0:0:1::1. Одну групу нулів за стандартом радять писати просто 0, а не ::.

Кілька особливих адрес:

Адреса Що це
::1 петля (аналог 127.0.0.1)
:: «адреса не задана», аналог 0.0.0.0
::/0 маршрут за замовчуванням
2001:db8::/32 діапазон для документації й прикладів

У URL адресу беруть у квадратні дужки, бо двокрапка інакше плутається з портом: http://[2001:db8::1]:8080/. Адресу link-local (про неї далі) доповнюють назвою інтерфейсу: fe80::1%eth0. Без цього незрозуміло, в який із інтерфейсів її слати.

Префікс і будова адреси

Section titled “Префікс і будова адреси”

Маска в IPv6 пишеться лише як довжина префікса: 2001:db8:abcd:12::/64. Звичайна одноадресна адреса ділиться на дві половини по 64 біти: верхні 64 біти визначають мережу, нижні 64 ідентифікують інтерфейс у ній. Верхню половину поділено далі: провайдер видає клієнтові префікс (типово /48, /56 або /64), а решту до 64 біт клієнт розкладає на підмережі самостійно.

Будова IPv6-адреси: префікс маршрутизації, номер підмережі, ідентифікатор інтерфейсу128 біт2001:0db8:abcdпрефікс маршрутизації48 біт, видає провайдер0012підмережа16 біт, ваші0211:22ff:fe33:4455ідентифікатор інтерфейсу64 біти, хостмережа /64: 65 536 підмереж на одну видану /48У /64 вміщається 2⁶⁴ адрес: перебір підмережі безглуздий.
Адреса з префіксом /48 від провайдера: решта 16 біт верхньої половини дає 65 536 власних підмереж /64. Нижні 64 біти ідентифікують хост усередині підмережі.

Практичне правило: підмережа завжди /64. Вона незручна з погляду економії (у ній 18 квінтильйонів адрес і ніколи не буде стільки хостів), але на цій межі тримаються SLAAC і NDP. Підмережу меншого розміру можна використати лише в окремих випадках (точка-точка між маршрутизаторами), а звичайному сегменту дають /64.

В IPv6 немає широкомовлення, замість нього працюють цільовіші механізми. Адреси бувають одноадресні (unicast), багатоадресні (multicast) і anycast (адреса, яку мають кілька вузлів, а пакет іде до найближчого).

Діапазон Тип Де діє
2000::/3 глобальна одноадресна (global unicast) весь інтернет, аналог публічних IPv4
fe80::/10 link-local лише в межах одного сегмента, не маршрутизується
fc00::/7 (на практиці fd00::/8) unique local (ULA) у межах організації, аналог приватних діапазонів
ff00::/8 multicast за областю дії в другому октеті

Link-local є на кожному інтерфейсі без жодного налаштування. Хост сам складає адресу fe80::... одразу після підняття інтерфейсу. Вона потрібна службовому обміну: маршрутизатори між собою, хост із шлюзом. Більшість служб NDP і маршрутизації працюють саме на link-local, і default-шлюз у таблиці маршрутів зазвичай записано як link-local адресу.

ULA створено для внутрішніх мереж. У діапазоні fd00::/8 40 біт після префікса вибирають випадково, щоб дві організації, які потім об’єднаються, майже напевно не мали збігу. Назовні такі адреси не маршрутизуються. На відміну від приватних IPv4, вони не потребують NAT для виходу в інтернет: у хоста зазвичай є ще й глобальна адреса, а ULA служить стабільною внутрішньою.

Multicast замінив широкомовлення. Найважливіші групи в межах сегмента:

Адреса Кому
ff02::1 усі вузли сегмента
ff02::2 усі маршрутизатори сегмента
ff02::1:ffXX:XXXX solicited-node: група для розв’язання адрес (NDP)
ff02::1:2 усі DHCPv6-сервери й relay

Група solicited-node будується так: до префікса ff02::1:ff00:0/104 дописують останні 24 біти унікастної адреси. Для 2001:db8::211:22ff:fe33:4455 це ff02::1:ff33:4455. Завдяки цьому на запит про адресу реагує лише кілька вузлів (зазвичай один), а решта мережевих карт фільтрують його апаратно, не будячи процесор.

Звідки береться адреса

Section titled “Звідки береться адреса”

Ідентифікатор інтерфейсу

Section titled “Ідентифікатор інтерфейсу”

Нижні 64 біти треба чимось заповнити. Перший і найстаріший спосіб EUI-64: узяти MAC-адресу, вставити посередині ff:fe і інвертувати сьомий біт першого байта. MAC 52:54:00:12:34:56 дає ідентифікатор 5054:00ff:fe12:3456. Перевірте: 52 у двійковому вигляді 01010010, інверсія сьомого біта дає 01010000, тобто 50.

Біда в тому, що ідентифікатор залежить від пристрою й лишається таким самим у будь-якій мережі, куди ви його принесете: за нижньою половиною адреси можна стежити за пристроєм по всіх мережах. Сучасні системи генерують ідентифікатор інакше. Він може бути випадковим, але стабільним у межах мережі (він обчислюється зі секретного ключа, префікса й інтерфейсу, тому в кожній мережі різний, а в одній і тій самій завжди однаковий). Крім того, є тимчасові адреси (temporary addresses, privacy extensions), які випадкові й міняються періодично; їх використовують для вихідних з’єднань, щоб зовнішні сайти не бачили постійного ідентифікатора. Про це докладніше в розділі про приватність.

SLAAC (stateless address autoconfiguration) дозволяє хосту налаштувати адресу без жодного сервера. Слово «безстанова» означає, що ніхто не веде реєстр виданих адрес: хост складає адресу сам, а сегмент лише повідомляє йому префікс.

SLAAC: від link-local адреси до глобальноїХостМаршрутизатор1. Neighbor Solicitation (DAD)хост перевіряє, чи вільна його fe80:: адресагрупа solicited-node2. Router Solicitationхто тут маршрутизатор? хочу префіксff02::2 (усі маршрутизатори)3. Router Advertisementпрефікс 2001:db8:1::/64, прапорці, час життя шлюзуff02::1 (усі вузли)4. Neighbor Solicitation (DAD)перевірка складеної глобальної адресигрупа solicited-nodeРезультат: адреса 2001:db8:1::ідентифікатор, шлюз за замовчуванням fe80::адреса маршрутизатора.
Маршрутизатор повідомляє префікс, а решту хост складає сам. Обидві адреси, link-local і глобальна, проходять перевірку унікальності (DAD), перш ніж стати робочими.
  1. Інтерфейс піднявся. Хост складає link-local адресу fe80:: + ідентифікатор інтерфейсу й перевіряє її унікальність механізмом DAD (duplicate address detection): шле Neighbor Solicitation на адресу, яку сам збирається використати. Якщо хтось відповість, адреса зайнята.

  2. Хост шле Router Solicitation на ff02::2: «є тут маршрутизатори?» Чекати на періодичне оголошення не треба.

  3. Маршрутизатор відповідає Router Advertisement (RA): префікс мережі, прапорці з підказками (як одержати решту налаштувань), час життя як шлюзу за замовчуванням. RA маршрутизатор розсилає й сам періодично на ff02::1.

  4. Хост складає глобальну адресу з префікса й ідентифікатора, знову перевіряє DAD і призначає адресу. Адреса шлюзу береться з джерела RA (link-local адреса маршрутизатора).

Прапорці в RA підказують, що робити далі. M (managed) каже: «адресу бери з DHCPv6». O (other) каже: «адресу склади сам, а решту (наприклад, DNS) візьми з DHCPv6». Якщо обидва скинуті, вистачить самого RA, який теж вміє розповсюджувати адреси DNS-серверів (опція RDNSS). Кожен префікс в RA має прапорець A (autonomous): за ним хост має право самостійно скласти адресу, і прапорець L (on-link): префікс досяжний напряму, без шлюзу.

DHCP в IPv6 теж існує, хоча призначення в нього інше. DHCPv6 працює поверх UDP (клієнт слухає порт 546, сервер 547). У режимі stateful він видає адреси й веде їхній облік, як DHCP у IPv4, а в режимі stateless лише роздає додаткові налаштування (DNS, домен), а адреса в цей час береться через SLAAC.

Принципова відмінність від IPv4: DHCPv6 не повідомляє шлюз за замовчуванням. Шлюз приходить лише з RA, і без працюючого маршрутизатора, що розсилає RA, сервер DHCP хосту в IPv6-мережі не допоможе.

Ще одна можливість, якої в IPv4 не було: делегування префікса (prefix delegation). Домашній роутер просить у провайдера цілу підмережу (наприклад, /56) і сам роздає /64 своїм сегментам. Так адреси з’являються у вашій локальній мережі без участі NAT.

Мета та сама, що в ARP (модуль 5): дізнатися канальну адресу сусіда за його IP. В IPv6 цим займається NDP (neighbor discovery protocol), який працює всередині ICMPv6.

Повідомлення NDP мають такі типи ICMPv6:

Тип Повідомлення Навіщо
133 Router Solicitation хост шукає маршрутизатор
134 Router Advertisement маршрутизатор повідомляє префікс і параметри
135 Neighbor Solicitation «яка в тебе MAC-адреса?», а також DAD
136 Neighbor Advertisement відповідь із MAC-адресою
137 Redirect «є кращий шлях через іншого сусіда»

Від ARP він відрізняється суттєво. Запит Neighbor Solicitation іде не широкомовно, а на адресу solicited-node цільового вузла, тож решта хостів його навіть не бачать. ICMPv6 входить до самого IPv6, і NDP проходить крізь ті самі засоби IPv6, що й решта трафіку, включно з файрволом. А всі NDP-пакети відправляються з Hop Limit = 255: отримувач відкидає пакет із меншим значенням, бо такий пакет прийшов через маршрутизатор, а не від сусіднього вузла.

Сусідів ядро тримає в таблиці зі станами: REACHABLE (нещодавно підтверджено), STALE (давно не перевіряли, але користуватися можна), DELAY і PROBE (перевіряємо), FAILED. Їх видно командою ip -6 neigh.

Розширювальні заголовки

Section titled “Розширювальні заголовки”

Основний заголовок IPv6 містить поле Next Header: що йде далі. Якщо далі TCP, це 6, якщо UDP 17, якщо ICMPv6 58. Але там може стояти й розширювальний заголовок, який у свою чергу вказує на наступний. Виходить ланцюжок: основний, потім необов’язкові заголовки (hop-by-hop, routing, fragment, destination options, AH, ESP), потім транспорт.

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

Фрагментація тільки у відправника

Section titled “Фрагментація тільки у відправника”

У IPv4 маршрутизатор, якому пакет не влазить у наступну ланку, міг розрізати його на частини (якщо не стоїть DF). В IPv6 маршрутизатори пакети не фрагментують зовсім. Фрагментувати може лише відправник, і він використовує для цього розширювальний заголовок фрагментації.

Потрібний розмір відправник дізнається через Path MTU Discovery, і в IPv6 цей механізм обов’язковий. Відправник шле пакет максимального розміру. Маршрутизатор, для якого він завеликий, відкидає його й повертає відправникові ICMPv6 Packet Too Big із MTU своєї ланки. Відправник зменшує розмір і повторює. Мінімальний MTU в IPv6 становить 1280 байтів: кожна ланка мусить такий пропускати без фрагментації.

Якщо десь на шляху відкидають ICMPv6 Packet Too Big, то коротенькі пакети (рукостискання) проходять, а великі зникають безслідно: відправник не дізнається, що треба менше. З’єднання встановлюється й відразу «зависає» на першій же сторінці. Такий збій називають чорною дірою PMTUD, і в IPv6 він трапляється частіше, ніж у IPv4, саме через недбале блокування ICMPv6.

Вимкнути IPv4 і ввімкнути IPv6 в один день не вийде, тож основний шлях переходу dual stack: хост, сервер і мережа підтримують обидва протоколи одночасно. У DNS ім’я має два записи: A (IPv4) і AAAA (IPv6). Клієнт отримує обидві адреси й має вибрати.

Просте «пробувати IPv6 першим, а якщо не вийшло, то IPv4» створює проблему: якщо IPv6-шлях зламаний, але адреса в DNS є, користувач чекатиме таймаут TCP (десятки секунд), перш ніж система перейде на IPv4. Щоб цього не було, клієнти застосовують алгоритм Happy Eyeballs. Він пробує IPv6 першим, але якщо з’єднання не встановилось за дуже короткий час (порядку чверті секунди), паралельно запускає спробу через IPv4 і бере те з’єднання, що встановилося першим. Через це зламаний IPv6 часто проявляється як «сайт відкривається, але вантажиться повільніше», а не як «сайт недоступний».

Для мереж, де IPv6 вже є, а IPv4 закінчується, є інші прийоми. NAT64 разом із DNS64 дозволяє хостам лише з IPv6 звертатися до серверів лише з IPv4: DNS64 синтезує для IPv4-сервера IPv6-адресу з особливого префікса, а шлюз NAT64 перекладає пакети між протоколами. У мобільних мережах це часто працює непомітно для користувача.

Без NAT, але не без файрвола

Section titled “Без NAT, але не без файрвола”

В IPv6 адрес вистачає, тому кожен пристрій може мати глобальну адресу, і NAT для економії адрес не потрібен. Повернулася наскрізна зв’язність: два пристрої можуть з’єднатися напряму без hole punching (модуль 9). Програмам не треба вигадувати обхідні шляхи.

З цим пов’язаний поширений страх: «якщо в кожного пристрою публічна адреса, усі побачать мій холодильник». За ним зазвичай стоїть переконання, що в IPv4 захищав NAT. Модуль 9 пояснює, що NAT ніколи не був файрволом. Захищає stateful-фільтр: приймати ззовні лише те, що належить з’єднанню, яке почалося зсередини, і закривати все інше. У хорошому IPv6-роутері саме така політика ввімкнена за замовчуванням. Якщо ви збираєте маршрутизатор самі, це ваше правило, і його треба написати: без нього кожен хост у мережі відкритий усім (докладніше в модулі 16).

NAT для IPv6 теж існує (перетворення префікса, NPTv6), але застосовують його рідко й для вузьких завдань, наприклад, коли треба підмінити префікс провайдера за багатодомної конфігурації.

Якщо нижні 64 біти адреси постійні (а для EUI-64 вони ще й прив’язані до заліза), то пристрій можна впізнати в будь-якій мережі й на будь-якому сайті. Це прямий наслідок того, що адреса тепер не ховається за NAT.

Захистом стали тимчасові адреси: система періодично створює нові випадкові ідентифікатори й використовує їх для вихідних з’єднань. Старі лишаються ще на якийсь час, щоб не обірвати вже відкриті сесії, а потім видаляються. Міняються вони зазвичай з періодом порядку доби. Окремо зберігається стабільна адреса, на яку можна заходити (наприклад, для SSH).

Тимчасові адреси приховують ідентифікатор пристрою, але не префікс. Верхні 64 біти однакові для всіх пристроїв домогосподарства, і за ними сайт упізнає, що запити приходять з одного дому (подібно до того, як сьогодні вас впізнають за публічною адресою IPv4). Деякі провайдери для цього періодично змінюють делегований префікс.

Окремий клас проблем живе у програмах. Сокет у Linux створюють із сімейством AF_INET (IPv4) або AF_INET6 (IPv6). Серверний сокет AF_INET6, прив’язаний до ::, за замовчуванням приймає і IPv6-з’єднання, і IPv4: IPv4-клієнти для нього виглядають як адреси виду ::ffff:192.0.2.7 (так звані IPv4-mapped адреси). Поведінку задає опція сокета IPV6_V6ONLY: якщо вона ввімкнена, сокет приймає лише IPv6, і для IPv4 треба відкрити другий сокет. За замовчуванням у Linux її вимкнено (змінна net.ipv6.bindv6only), але багато програм вмикають її явно, тож поведінка залежить від конкретного сервера.

  • Сервер, що слухає 0.0.0.0, недосяжний по IPv6, навіть якщо в DNS є AAAA. Щоб перевірити, що слухає, дивіться ss -tln: рядок 0.0.0.0:80 це лише IPv4, [::]:80 це IPv6 (і, за замовчуванням, IPv4 теж), 127.0.0.1:80 лише петля IPv4.
  • Програма, яка розбирає адреси регулярним виразом на чотири числа, не впізнає ::1 і відкине її як некоректну. Списки дозволених адрес (allowlist), правила в конфігах, журнали й база даних, де адреса записана в полі на 15 символів, теж мають бути готові до довших адрес.
  • Адреса з портом у текстовому вигляді потребує дужок ([2001:db8::1]:443), а без них розбір по останній двокрапці дасть абсурд.
  • Ім’я часто дає кілька адрес, і яку з них спробує програма першою, вирішує бібліотека розв’язання імен за власними правилами впорядкування. Тому два різні клієнти на одній машині можуть вести себе по-різному.

Коли IPv6 «раптово ламається» там, де в IPv4 усе було налагоджено роками, винен зазвичай не протокол: просто якийсь шар, від файрвола до бази даних, пам’ятає лише про чотири числа.

Terminal window
ip -6 addr show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
inet6 2001:db8:1:0:9d3c:41aa:7e52:b8c1/64 scope global temporary dynamic
valid_lft 86378sec preferred_lft 14378sec
inet6 2001:db8:1:0:5054:ff:fe12:3456/64 scope global dynamic mngtmpaddr proto kernel_ra
valid_lft 86378sec preferred_lft 14378sec
inet6 fe80::5054:ff:fe12:3456/64 scope link proto kernel_ll
valid_lft forever preferred_lft forever

Читаємо зверху вниз. Перша адреса temporary, випадкова, для вихідних з’єднань. Друга глобальна адреса, складена SLAAC із префікса 2001:db8:1::/64: dynamic означає, що вона отримана автоматично і має термін життя, а proto kernel_ra — що її склало саме ядро за Router Advertisement. Ідентифікатор 5054:ff:fe12:3456 це EUI-64 від MAC 52:54:00:12:34:56, і це видно за вставкою ff:fe. Третя link-local (proto kernel_ll), вона forever, бо не залежить від RA. Поле preferred_lft каже, скільки ще адреса «бажана» для нових з’єднань, а valid_lft скільки вона взагалі дійсна.

Terminal window
ip -6 route
2001:db8:1::/64 dev eth0 proto kernel metric 256 pref medium
fe80::/64 dev eth0 proto kernel metric 256 pref medium
default via fe80::1 dev eth0 proto ra metric 1024 expires 1790sec hoplimit 64 pref medium

Маршрут до власного префікса ядро ставить саме, як і для IPv4 (proto kernel). А маршрут за замовчуванням має proto ra: його поставлено за Router Advertisement, і він живе стільки, скільки маршрутизатор пообіцяв бути шлюзом (expires 1790sec), а RA, що надходять далі, продовжують цей строк. Якщо адресами керує NetworkManager чи systemd-networkd, proto і metric бувають іншими: вони ставлять маршрути самі. Шлюз за замовчуванням записано як link-local адресу: via fe80::1. Тому для IPv6 завжди треба вказувати інтерфейс: одна й та сама fe80::1 може існувати на кількох інтерфейсах.

Terminal window
ip -6 neigh
fe80::1 dev eth0 lladdr 52:54:00:aa:bb:cc router REACHABLE

Це аналог ip neigh для IPv4: сусід, його MAC, прапорець router (він оголошував себе маршрутизатором) і стан.

Terminal window
sudo tcpdump -i eth0 -nn -vv icmp6

Піднімаємо інтерфейс в іншому вікні. Ось що побачимо (скорочено):

fe80::5054:ff:fe12:3456 > ff02::2: ICMP6, router solicitation, length 16
source link-address option (1), length 8 (1): 52:54:00:12:34:56
fe80::1 > ff02::1: ICMP6, router advertisement, length 64
hop limit 64, Flags [none], pref medium, router lifetime 1800s
prefix info option (3), length 32 (4): 2001:db8:1::/64, Flags [onlink, auto], valid time 86400s, pref. time 14400s
source link-address option (1), length 8 (1): 52:54:00:aa:bb:cc

Хост шле RS на ff02::2 зі своєї link-local адреси. Маршрутизатор відповідає RA, у якому префікс 2001:db8:1::/64 із прапорцями onlink (L) і auto (A), термін життя шлюзу 1800 секунд і власна MAC-адреса в опції. Прапорців M і O тут немає (Flags [none]), тож хост складе адресу сам і більше ні в кого нічого не питатиме.

Перед цим у захопленні мають бути ще Neighbor Solicitation від хоста на адресу ff02::1:ff12:3456: це той самий DAD, у якому адреса-мета власна, а відповіді чекати не треба.

Terminal window
sysctl net.ipv6.conf.eth0.accept_ra
sysctl net.ipv6.conf.eth0.use_tempaddr
sysctl net.ipv6.conf.all.forwarding

accept_ra вирішує, чи слухає хост RA (за замовчуванням 1, але не для машини з увімкненим forwarding). use_tempaddr керує тимчасовими адресами: 0 вимкнено, 1 створювати, але надавати перевагу стабільній, 2 створювати й надавати перевагу тимчасовій. Саме ядро типово ставить 0; тимчасові адреси, як у прикладі вище, вмикають дистрибутиви (NetworkManager на десктопах ставить 2). Обережно з forwarding: коли Linux стає маршрутизатором, за замовчуванням він перестає приймати RA. Щоб шлюз і далі міг отримувати маршрут за замовчуванням від провайдера, треба accept_ra=2.

Linux як маршрутизатор IPv6

Section titled “Linux як маршрутизатор IPv6”

Щоб ваш Linux роздавав адреси через SLAAC, треба увімкнути пересилання й запустити щось, що розсилає RA. Мінімально для цього є radvd або той самий dnsmasq:

# dnsmasq: лише RA, без видачі адрес через DHCPv6
interface=br-lan
enable-ra
dhcp-range=2001:db8:1::,ra-only
radvd.conf
interface br-lan {
AdvSendAdvert on;
prefix 2001:db8:1::/64 {
AdvOnLink on;
AdvAutonomous on;
};
RDNSS 2001:db8:1::1 {};
};

Синтаксис конфіга dnsmasq можна перевірити командою dnsmasq --test -C файл. Для DHCPv6 зі станом (stateful) замість ra-only у dhcp-range задають діапазон адрес, наприклад 2001:db8:1::100,2001:db8:1::1ff,64,12h.

table inet filter {
chain input {
type filter hook input priority filter; policy drop;
ct state established,related accept
iifname "lo" accept
ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, packet-too-big,
time-exceeded, parameter-problem, nd-router-solicit, nd-router-advert,
nd-neighbor-solicit, nd-neighbor-advert } accept
ip protocol icmp accept
}
}

Таблиця сімейства inet охоплює IPv4 і IPv6 одночасно, тож одне правило діє на обидва протоколи. Політика drop закриває все, а виключення відкривають потрібне: відповіді на власні з’єднання, петлю й ICMPv6, без якого IPv6 не запрацює. Перевірити правила без застосування можна командою nft -c -f файл. Подібний ланцюжок forward для шлюзу пишеться за тим самим принципом, що й у модулі 9.

Terminal window
ping -6 -c3 2001:db8::1 # досяжність за IPv6
ping -6 -c3 fe80::1%eth0 # link-local: обов'язково з інтерфейсом
curl -6 -sS -o /dev/null -w '%{http_code}\n' https://example.com
curl -4 -sS -o /dev/null -w '%{http_code}\n' https://example.com
ss -6 -tln # хто слухає на IPv6
ip -6 route get 2001:db8::1 # який маршрут і яка вихідна адреса
getent ahosts example.com # в якому порядку система віддасть адреси

Пара curl -6 і curl -4 найшвидший спосіб виявити, що ламається лише один із протоколів. Якщо вони поводяться по-різному, проблема не в застосунку, а в шляху.

Типові помилки розуміння

Section titled “Типові помилки розуміння”

IPv6 це той самий IPv4, лише довші адреси. Змінилося більше. Немає широкомовлення й ARP, адресу хост складає сам, фрагментація лише в відправника, а на інтерфейсі зазвичай кілька адрес одночасно. Звичка з IPv4 «одна адреса на інтерфейс» ламається одразу.

Без NAT мій пристрій відкритий усьому інтернету. NAT ніколи не був файрволом. У розумно налаштованому роутері стоїть stateful-фільтр, що не пускає непрошені вхідні з’єднання, і його роль у IPv6 така сама, як в IPv4. Хто збирає шлюз сам, мусить написати це правило.

ICMPv6 можна блокувати, як і ICMP. Блокування ICMPv6 ламає NDP (хости не знаходять сусідів), RA (не працює автоналаштування) і Path MTU Discovery (великі пакети зникають). Це найчастіша причина «IPv6 ніби є, але нічого не працює».

Запис AAAA означає, що сайт доступний по IPv6. Запис лише обіцяє. Якщо сервер слухає тільки 0.0.0.0 або правило файрвола закриває порт для IPv6, клієнти з IPv6 отримують відмову чи таймаут, а Happy Eyeballs лише ховає це ціною затримки.

localhost це завжди 127.0.0.1. У багатьох системах localhost розв’язується і в ::1, і в 127.0.0.1. Якщо програма-клієнт бере першою IPv6-адресу, а сервер слухає лише IPv4, з’єднання відмовляється, хоча сервер «точно працює». Перевірте ss -tln і спробуйте curl http://127.0.0.1 та curl 'http://[::1]' окремо.

Адресу видно за MAC, тож приватності в IPv6 немає. Так було з EUI-64. Сучасні системи за замовчуванням генерують ідентифікатор інакше й використовують тимчасові адреси для вихідного трафіку. Префікс, щоправда, лишається ідентифікатором мережі, і в цьому сенсі приватність обмежена.

Перевір себе

1. Яка з форм запису адреси 2001:0db8:0000:0000:0001:0000:0000:0001 є канонічною скороченою (найдовша послідовність нулів, за рівних перша)?
2. У пакеті RA від маршрутизатора прапорці M і O скинуті. Що зробить хост?
3. Чому в IPv6 Neighbor Solicitation не заважає всім хостам сегмента, як широкомовний ARP-запит?
4. Зʼєднання за IPv6 встановлюється, рукостискання проходить, а перша ж сторінка зависає. У IPv4 усе працює. Що найімовірніше?
5. Чому домашня мережа з IPv6 і без NAT не стає відкритою для всього інтернету?
6. Сайт має і A, і AAAA записи, але сервер слухає тільки IPv4. Що побачить клієнт, який підтримує Happy Eyeballs?
7. Вам треба адресу для сервісу лише всередині організації, що не залежить від провайдера. Що обрати?

Окремої лабораторної для IPv6 немає, але в топологіях доріжки B його легко додати. У B2 та B3 можна дати інтерфейсам адреси з діапазону 2001:db8::/32, призначеного для документації, і повторити ті самі перевірки. Якщо IPv6 у ядрі вимкнено (так буває в контейнерах), це не запрацює: використовуйте віртуальну машину, описану на сторінці лабораторних.

  • Kurose, Ross, Computer Networking: A Top-Down Approach, розділ про мережевий рівень (IPv6)
  • Stevens, TCP/IP Illustrated, Vol. 1, розділи про IPv6 і ICMPv6
  • Peterson, Davie, Computer Networks: A Systems Approach
  • RFC 8200 (специфікація IPv6), RFC 4291 (архітектура адресації), RFC 4861 (Neighbor Discovery), RFC 4862 (SLAAC), RFC 4193 (ULA), RFC 8981 (тимчасові адреси; замінив RFC 4941), RFC 8415 (DHCPv6), RFC 8305 (Happy Eyeballs версії 2)
  • man ip(8), man sysctl(8), man radvd.conf(5), man dnsmasq(8), man nft(8)
  • Документація ядра Linux: Documentation/networking/ip-sysctl.rst