Сети для самых маленьких. Часть 15: SLAAC

В четырнадцатой части роутер рассылал Router Advertisement, и в нём был префикс сегмента с флагом auto: «из этого префикса можно собрать себе адрес». Сегодня — о том, как хост это делает. Механизм называется SLAAC, Stateless Address Autoconfiguration, RFC 4862, и слово «stateless» в нём главное: никто не хранит, кому какой адрес выдан. Нет сервера, нет аренд, нет таблицы. Роутер говорит «префикс такой», хост сам придумывает вторую половину адреса, проверяет, что она свободна, и начинает работать. Для домашней сети и для телефонов это основной и часто единственный способ получить адрес IPv6.

Половину механизма мы уже знаем: RA и DAD из прошлой части. Осталось понять, откуда берётся вторая половина адреса и как адреса живут и умирают.


Адрес = префикс + идентификатор

В тринадцатой части глобальный адрес делился на 64 бита префикса и 64 бита идентификатора интерфейса (IID). SLAAC — это просто конкатенация:

 из RA, prefix info с флагом A:     2001:db8:1234:5678::/64
 придумал сам хост:                                     3e52:82ff:fe1a:2b3c
                                    ─────────────────────────────────────────
 адрес:                             2001:db8:1234:5678:3e52:82ff:fe1a:2b3c

Потому и требование «каждая сеть — /64»: SLAAC работает только с префиксом ровно в 64 бита, чтобы хосту оставалось ровно 64 на идентификатор. Префикс /80 в RA хосты проигнорируют.

Идентификатор хост придумывает один раз для link-local адреса (fe80:: + IID) и потом тот же или другие — для каждого префикса из RA. Как именно, есть три способа, и выбор между ними — это выбор между удобством и приватностью.

EUI-64: из MAC-адреса

Исходный способ 1998 года. Берём 48-битный MAC 3c:52:82:1a:2b:3c, вставляем посередине ff:fe, получаем 64 бита, и инвертируем бит U/L в первом байте (второй младший бит, тот самый из второй части):

MAC:              3c:52:82        :1a:2b:3c
вставить ff:fe:   3c:52:82:ff:fe:1a:2b:3c
3c = 0011 1100 → инвертировать бит U/L → 0011 1110 = 3e
IID:              3e52:82ff:fe1a:2b3c

Бит инвертируют, чтобы вручную назначенные адреса вроде ::1 оказались с «локальным» значением бита, а адреса из глобально уникальных MAC — с «глобальным»; практического значения это почти не имеет, но объясняет, почему 3c стал 3e. Узнать EUI-64 легко по ff:fe в середине.

Плюс — адрес предсказуем: зная MAC, знаешь адрес в любой сети. Минус — тот же: MAC-адрес виден каждому сайту, и один и тот же ноутбук узнаваем дома, в офисе и в кафе по младшей половине адреса. Поэтому EUI-64 сегодня используют в основном серверы и сетевое оборудование, а клиентские системы ушли от него.

Стабильный случайный

RFC 7217: идентификатор вычисляется хешем от префикса сети, имени интерфейса и секретного ключа машины. Результат стабилен в одной сети (при каждом подключении к офису адрес тот же: его можно прописать в DNS и файрвол) и разный в разных сетях (дом и офис дают разные идентификаторы, связать их нельзя). MAC в нём не участвует. Это умолчание в Linux (addr_gen_mode = 2, stable-privacy) и в Windows (randomizeidentifiers), и именно такие адреса без ff:fe в середине — норма на современных машинах.

Временный

RFC 8981, бывший 4941, «privacy extensions». Поверх стабильного адреса хост заводит ещё один с полностью случайным идентификатором, меняет его раз в сутки и использует как адрес отправителя для новых исходящих соединений. Стабильный адрес остаётся для входящих. Так сайт не может отслеживать машину дольше суток даже внутри одной сети.

$ ip -6 addr show eth0 | grep global
    inet6 2001:db8:1234:5678:a1b2:c3d4:e5f6:789a/64 scope global temporary dynamic
       valid_lft 86153sec preferred_lft 14153sec
    inet6 2001:db8:1234:5678:4f3e:2d1c:0b9a:8877/64 scope global dynamic mngtmpaddr stable-privacy
       valid_lft 86153sec preferred_lft 86153sec

Пометки Linux: temporary — временный; mngtmpaddr — «от этого адреса порождаются временные»; stable-privacy — способ генерации. Временных может быть несколько: старый ещё доживает, новый уже работает, и в ip -6 addr на долгоживущей машине их бывает три-четыре.


Жизнь адреса

У каждого адреса из RA два срока, оба пришли в prefix info:

 получен    preferred_lft                      valid_lft
 ├──────────────┼─────────────────────────────────┤
 │ preferred    │ deprecated                      │ удалён
 │ для всего    │ существующие соединения живут,  │
 │              │ новые — с другого адреса        │
  • Preferred — адрес можно использовать для новых соединений.
  • Deprecated — срок preferred истёк, но valid ещё нет: адрес принимает пакеты, установленные соединения продолжаются, но новые соединения стек откроет с другого адреса, если он есть.
  • Valid истёк — адрес снимается с интерфейса.

Каждый новый RA с тем же префиксом обновляет оба срока, поэтому в живой сети до deprecated не доходит: при valid 86400 и RA раз в десять минут отсчёт начинается заново каждые десять минут. Отсюда valid_lft 86153sec в выводе выше — 247 секунд назад пришёл RA.

Для временных адресов preferred заведомо короче (сутки или меньше), и смена адреса устроена именно через deprecated: за несколько минут до истечения preferred создаётся новый временный, старый становится deprecated, доживает свои соединения и удаляется через неделю (valid), не мешая никому.

Так же, через сроки, роутер отзывает префикс при смене провайдера: шлёт RA, в котором у старого префикса preferred = 0 (сразу deprecated) и valid небольшое, а рядом новый префикс. Хосты за минуты переезжают сами. Единственное ограничение: valid нельзя одним RA уменьшить ниже двух часов, если осталось больше, — защита от одного поддельного RA, который убил бы все адреса в сегменте.


Что происходит при подключении

Вся последовательность, от кабеля в розетке до рабочего адреса, за три секунды:

$ sudo tcpdump -i eth0 -n icmp6
0.000 IP6 :: > ff02::1:ff1a:2b3c: ICMP6, neighbor solicitation, who has fe80::3e52:82ff:fe1a:2b3c         (1) DAD link-local
1.000 IP6 fe80::3e52:82ff:fe1a:2b3c > ff02::2: ICMP6, router solicitation                                  (2) RS
1.004 IP6 fe80::da47:32ff:fe0a:b0c > ff02::1: ICMP6, router advertisement                                  (3) RA
1.005 IP6 :: > ff02::1:ff9a:8877: ICMP6, neighbor solicitation, who has 2001:db8:1234:5678:4f3e:2d1c:0b9a:8877   (4) DAD стабильного
1.005 IP6 :: > ff02::1:fff6:789a: ICMP6, neighbor solicitation, who has 2001:db8:1234:5678:a1b2:c3d4:e5f6:789a   (4) DAD временного
2.010 IP6 fe80::3e52:82ff:fe1a:2b3c > ff02::1:ff0a:b0c: ICMP6, neighbor solicitation, who has fe80::da47:32ff:fe0a:b0c   (5) NS к роутеру
2.010 IP6 fe80::da47:32ff:fe0a:b0c > fe80::3e52:82ff:fe1a:2b3c: ICMP6, neighbor advertisement, tgt is fe80::da47:32ff:fe0a:b0c
  1. Интерфейс поднялся. Хост собрал link-local fe80:: + IID и запустил DAD: NS от :: в solicited-node группу кандидата. Секунда тишины — link-local рабочий.
  2. С link-local адреса хост шлёт Router Solicitation на все роутеры.
  3. Роутер отвечает RA. В нём префикс с флагом A, сроки, RDNSS, MTU, hop limit, и сам RA пришёл с link-local адреса роутера.
  4. Хост делает из префикса два адреса — стабильный и временный — и запускает DAD для каждого. В таблицу маршрутов ложатся 2001:db8:1234:5678::/64 dev eth0 (флаг L: соседи напрямую) и default via fe80::da47:… proto ra (router lifetime > 0). DNS из RDNSS уходит в resolv.conf (через systemd-resolved или NetworkManager).
  5. Первый пакет наружу: NS к роутеру за его MAC, NA в ответ, пакет ушёл.

Ни одного сервера, ни одной записи где бы то ни было: роутер не знает, какие адреса у хостов, хосты не знают друг о друге. Потому и stateless.

Флаги, которые управляют поведением

Четыре флага в RA, которые хост читает, принимая решение:

Флаг Где Что значит
A (autonomous) prefix info из этого префикса можно собрать адрес по SLAAC
L (on-link) prefix info адреса из этого префикса — соседи, слать напрямую
M (managed) заголовок RA адреса получать по DHCPv6 (часть 16)
O (other) заголовок RA прочие параметры (DNS, если нет RDNSS) брать из DHCPv6

Сочетания: A = 1, M = 0, O = 0 — чистый SLAAC, самая частая домашняя схема; A = 0, M = 1 — адреса только через DHCPv6, корпоративная схема с учётом; A = 1, M = 1 — хост сделает адрес сам и ещё попросит у DHCPv6, получится два; A = 1, O = 1 — адрес сам, DNS у DHCPv6, схема до появления RDNSS. Флаг L отдельно от A: префикс может быть on-link, но без автоконфигурации (адреса выдаёт DHCPv6, но соседи всё равно соседи), и наоборот.

Маршрут по умолчанию при этом всегда приходит из RA — у DHCPv6, как увидим в следующей части, опции «шлюз» нет вовсе.


На роутере

На Linux RA рассылает демон radvd; у домашних роутеров то же самое спрятано за галочкой «IPv6: автоматически». Конфигурация, соответствующая захвату выше:

interface eth0 {
    AdvSendAdvert on;
    MinRtrAdvInterval 200;
    MaxRtrAdvInterval 600;
    AdvDefaultLifetime 1800;
    AdvLinkMTU 1500;

    prefix 2001:db8:1234:5678::/64 {
        AdvOnLink on;
        AdvAutonomous on;
        AdvValidLifetime 86400;
        AdvPreferredLifetime 14400;
    };

    RDNSS 2001:db8:1234:5678::1 { AdvRDNSSLifetime 600; };
    DNSSL example.com { AdvDNSSLLifetime 600; };
};

Роутер должен пересылать пакеты (net.ipv6.conf.all.forwarding = 1), и с этого момента Linux по умолчанию перестаёт принимать чужие RA на своих интерфейсах — роутеру не положено настраиваться от соседнего роутера. Если роутер сам получает аплинк по RA от провайдера, на внешнем интерфейсе ставят accept_ra = 2: «принимать, даже если я роутер».

Откуда у домашнего роутера префикс 2001:db8:1234:5678::/64? Провайдер выдал ему блок /56 через DHCPv6 prefix delegation (часть 16), а роутер выбрал из него один /64 для LAN и сам подставил в RA. В radvd для этого есть запись prefix ::/64: префикс берётся с адреса самого интерфейса, какой бы он ни был; но проще отдать всё dhcpcd или odhcpd, которые получают блок у провайдера и настраивают RA разом.


Чего SLAAC не умеет

Безсерверность — это и ограничение.

  • Нет учёта. Никто не записывает, у какого устройства какой адрес был вчера в 15:40. Для дома это неважно, для компании с требованием «найти, кто качал» — причина использовать DHCPv6, по крайней мере в дополнение.
  • Мало опций. RA несёт префиксы, MTU, hop limit, DNS, домены поиска и, по RFC 4191, дополнительные маршруты. Серверы времени, адрес сервера загрузки, параметры для телефонов — только через DHCPv6.
  • Нет регистрации имён. DHCP-сервер мог записать имя хоста в DNS; при SLAAC некому.
  • Нет контроля, какой адрес у хоста. Идентификатор выбирает хост, и временный адрес, с которого он ходит наружу, роутер не предскажет. Правила файрвола «этому хосту можно» пишутся на префикс или на стабильный адрес.

И обратное ограничение, из-за которого от SLAAC нельзя отказаться: Android не поддерживает DHCPv6. Сеть с A = 0 и M = 1 оставит телефоны без IPv6. Поэтому общая рекомендация — SLAAC с RDNSS для всех, а DHCPv6 сверху для тех, кому нужен учёт.


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

Как генерируется идентификатор и как ведут себя временные адреса — sysctl на каждом интерфейсе:

$ sysctl net.ipv6.conf.eth0.addr_gen_mode     # 0 EUI-64, 2 stable-privacy (умолчание), 1 — не делать link-local
$ sysctl net.ipv6.conf.eth0.use_tempaddr      # 0 нет, 1 есть, 2 есть и предпочитать для исходящих
$ sysctl net.ipv6.conf.eth0.temp_prefered_lft # 86400 — сутки
$ sysctl net.ipv6.conf.eth0.accept_ra         # 0 игнорировать RA, 1 принимать, 2 принимать даже роутеру
$ sysctl net.ipv6.conf.eth0.autoconf          # делать ли адреса из префиксов с A

На Windows: netsh interface ipv6 show global покажет Randomize Identifiers и Use Temporary Addresses, а netsh interface ipv6 set privacy state=disabled выключит временные адреса, если они мешают (например, серверу, у которого должен быть один известный адрес).

Посмотреть, какие адреса в каком состоянии, включая флаги tentative и deprecated:

$ ip -6 addr show eth0

Принудительно пережить всё заново, не трогая кабель: ip link set eth0 down && ip link set eth0 up и tcpdump на icmp6 в соседнем окне. Если после этого глобального адреса нет: rdisc6 eth0 покажет, приходит ли RA вообще и есть ли в нём префикс с Autonomous address conf.: Yes.


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

  • SLAAC: адрес = префикс /64 из RA с флагом A + идентификатор интерфейса, который хост придумывает сам, затем DAD. Никакого сервера, никакого состояния.
  • Идентификатор: EUI-64 из MAC (ff:fe в середине, бит U/L инвертирован) — предсказуем и отслеживаем; стабильный случайный — один в каждой сети, разный между сетями, умолчание; временный — случайный, меняется ежедневно, для исходящих соединений.
  • Два срока: preferred (для новых соединений) и valid (вообще). Deprecated-адрес дорабатывает старые соединения. Каждый RA сроки обновляет; роутер отзывает префикс, обнуляя preferred.
  • Флаги A и L в префиксе, M и O в заголовке решают, что делать самому, а что просить у DHCPv6. Шлюз всегда из RA.
  • SLAAC не даёт учёта, мало опций и не регистрирует имена; DHCPv6 его не заменяет, потому что Android умеет только SLAAC.

Дальше — Часть 16: DHCPv6: зачем он, если SLAAC есть, чем он отличается от DHCPv4 (DUID вместо MAC, multicast вместо broadcast, нет шлюза), stateful и stateless режимы, обмен Solicit, Advertise, Request, Reply, и prefix delegation, которым провайдер выдаёт роутеру целый блок сетей.

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

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