Сети для самых маленьких. Часть 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
- Интерфейс поднялся. Хост собрал link-local
fe80::+ IID и запустил DAD: NS от::в solicited-node группу кандидата. Секунда тишины — link-local рабочий. - С link-local адреса хост шлёт Router Solicitation на все роутеры.
- Роутер отвечает RA. В нём префикс с флагом A, сроки, RDNSS, MTU, hop limit, и сам RA пришёл с link-local адреса роутера.
- Хост делает из префикса два адреса — стабильный и временный — и запускает 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). - Первый пакет наружу: 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, которым провайдер выдаёт роутеру целый блок сетей.
Оставить комментарий могут только зарегистрированные пользователи.
Войдите на сайт или зарегистрируйтесь, чтобы оставить комментарий.