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

SLAAC из прошлой части даёт хосту адрес, шлюз и DNS без единого сервера, и для дома этого достаточно. Но у безсерверности есть цена: никто не знает, какой адрес у какого устройства, набор параметров ограничен, а роутер абонента должен откуда-то получить свой блок префиксов. Для этого в IPv6 есть DHCPv6, RFC 8415. Название обещает «тот же DHCP», но это другой протокол: у него свой формат, свои идентификаторы клиентов, свои режимы и, главное, он не заменяет Router Advertisement, а дополняет. Без RA из четырнадцатой части DHCPv6-клиент даже не начнёт работать.

Чтобы было с чем сравнивать, держите под рукой DHCPv4.


Чем отличается от DHCPv4

DHCPv4 DHCPv6
Транспорт UDP 68 → 67, broadcast 255.255.255.255 от 0.0.0.0 UDP 546 → 547, multicast ff02::1:2 с link-local адреса: он у клиента уже есть
Как клиент узнаёт, нужен ли DHCP всегда пробует по флагам M и O в RA
Кто такой клиент MAC-адрес или client-id DUID — идентификатор машины, а не интерфейса
Что выдаётся один адрес IA — контейнер с одним или несколькими адресами или префиксами, у каждого свои сроки
Маска опция 1 нет: префикс и on-link — из RA
Шлюз опция 3 нет и не будет: только из RA
Обмен DISCOVER, OFFER, REQUEST, ACK Solicit, Advertise, Request, Reply; с rapid commit — два сообщения
Сроки один lease preferred и valid, как в SLAAC
Инициатива сервера нет Reconfigure: сервер может велеть клиенту обновиться
Выдача префиксов роутерам нет prefix delegation
Режим «только опции» INFORM Information-Request, штатный stateless-режим

Отсутствие опции шлюза — не недосмотр, а решение: роутер лучше знает, что он роутер, и объявляет это сам; DHCP-сервер может стоять где угодно и про топологию сегмента не знает. В IPv4 этот аргумент тоже верен, но там уже было поздно.


DUID и IA

DUID (DHCP Unique Identifier) — то, чем клиент себя называет. Он один на всю машину, не на интерфейс, генерируется при первом запуске и хранится на диске. Три формата: DUID-LLT — MAC-адрес плюс время создания (самый частый), DUID-LL — только MAC, DUID-UUID — UUID машины из прошивки. Сервер ведёт резервирования по DUID, и это вызывает практическую боль: DUID не написан на наклейке, и чтобы завести резервирование для нового ноутбука, его сначала нужно включить и подсмотреть DUID в логе сервера. Переустановка системы обычно меняет DUID. Relay-агенты могут добавлять в запрос MAC клиента (опция 79), и современные серверы умеют резервировать по нему, но это обход, а не правило.

IA (Identity Association) — контейнер, в котором клиент просит, а сервер выдаёт адреса. У каждого IA есть IAID — номер, который клиент выбирает для интерфейса, — и сроки T1/T2 для продления. Три вида:

  • IA_NA (опция 3) — обычные адреса; внутри одна или несколько записей IA Address (опция 5) с preferred и valid lifetime;
  • IA_TA (опция 4) — временные адреса, аналог privacy extensions; используется редко, временные адреса делает SLAAC;
  • IA_PD (опция 25) — префиксы: внутри IA Prefix (опция 26) с длиной и сроками.

Клиент может прислать несколько IA в одном запросе — например, IA_NA для адреса на WAN-интерфейсе и IA_PD для блока на LAN, — и сервер ответит на каждый отдельно с кодом статуса.


Сообщение

Заголовок — 4 байта, дальше опции в формате «код (2 байта), длина (2 байта), значение»:

 байты:   1          3
        ┌────────┬────────────────┐
        │ msg-   │ transaction-id │   затем опции
        │ type   │                │
        └────────┴────────────────┘
msg-type Сообщение Смысл
1 Solicit клиент: «кто тут сервер и что предложите»
2 Advertise сервер: предложение
3 Request клиент: «беру у этого сервера»
4 Confirm клиент после сна или переподключения: «мои адреса ещё годятся в этом сегменте?»
5 Renew продление у своего сервера (T1)
6 Rebind продление у любого (T2)
7 Reply ответ сервера на всё, кроме Solicit
8 Release клиент отдаёт адреса
9 Decline адрес не прошёл DAD
10 Reconfigure сервер: «обновись», требует аутентификации
11 Information-Request клиент: «только опции, адрес у меня свой»
12, 13 Relay-Forward, Relay-Reply обёртки relay-агента

Опции, которые встречаются постоянно: 1 Client ID (DUID клиента), 2 Server ID (DUID сервера), 3 IA_NA, 5 IA Address, 6 Option Request (что клиенту нужно, аналог 55 в DHCPv4), 7 Preference (сервер с большим значением выигрывает у клиента, 255 — «бери меня, других не жди»), 8 Elapsed Time (сколько клиент уже пытается, для резервных серверов), 13 Status Code, 14 Rapid Commit, 23 DNS-серверы, 24 домены поиска, 25 IA_PD, 26 IA Prefix, 39 FQDN (имя клиента для регистрации в DNS), 56 NTP-серверы.


Stateful: четыре сообщения

RA с флагом M = 1. Клиент, получив такой RA, запускает DHCPv6:

   клиент fe80::3e52:…                                        сервер fe80::da47:…
     │                                                               │
     ├── Solicit ─────────── на ff02::1:2 (MAC 33:33:00:01:00:02) ──►│  всем серверам и relay
     │   Client ID, IA_NA (IAID 1), Option Request: DNS, domains     │
     │                                                               │
     │◄── Advertise ──────── unicast на мой link-local ──────────────┤  от каждого сервера
     │   Server ID, IA_NA: адрес, сроки; DNS; Preference             │
     │                                                               │
     ├── Request ──────────── на ff02::1:2 ─────────────────────────►│  с Server ID выбранного
     │                                                               │
     │◄── Reply ─────────────────────────────────────────────────────┤  подтверждение
     │                                                               │
     │  DAD адреса, затем в работу; Renew в T1, Rebind в T2          │
  1. Solicit уходит с link-local адреса на ff02::1:2 — группу всех DHCPv6-серверов и relay-агентов в сегменте. Внутри DUID клиента, пустой IA_NA («хочу адрес, любой») и список нужных опций. У клиента есть адрес отправителя, поэтому ответ приходит unicast, без трюков с MAC из DHCPv4.
  2. Advertise от каждого сервера с предложенным адресом внутри IA_NA и сроками. Клиент ждёт секунду, собирает все предложения и берёт сервер с наибольшим Preference. При Preference 255 ждать не нужно.
  3. Request снова в multicast (чтобы остальные серверы увидели выбор), но с Server ID победителя.
  4. Reply — подтверждение с теми же IA и опциями. Клиент назначает адрес, проверяет его DAD и при конфликте шлёт Decline.

Если сервер в ответ на Solicit поддерживает Rapid Commit (опция 14 в Solicit и в ответе), он сразу отвечает Reply, и обмен укладывается в два сообщения. Для сетей с одним сервером это норма.

В tcpdump:

$ sudo tcpdump -i eth0 -n 'udp port 546 or udp port 547'
IP6 fe80::3e52:82ff:fe1a:2b3c.546 > ff02::1:2.547: dhcp6 solicit (xid=1a2b3c (client-ID hwaddr/time type 1 time 700000000 3c52821a2b3c) (IA_NA IAID:1 T1:0 T2:0) (option-request DNS-server DNS-search-list) (elapsed-time 0))
IP6 fe80::da47:32ff:fe0a:b0c.547 > fe80::3e52:82ff:fe1a:2b3c.546: dhcp6 advertise (xid=1a2b3c (client-ID hwaddr/time type 1 time 700000000 3c52821a2b3c) (server-ID hwaddr/time type 1 time 650000000 d847320a0b0c) (IA_NA IAID:1 T1:3600 T2:5760 (IA_ADDR 2001:db8:1234:5678::1001 pltime:7200 vltime:14400)) (DNS-server 2001:db8:1234:5678::1) (preference 255))
IP6 fe80::3e52:82ff:fe1a:2b3c.546 > ff02::1:2.547: dhcp6 request (xid=1a2b3c (client-ID ...) (server-ID ... d847320a0b0c) (IA_NA IAID:1 ...) (option-request ...))
IP6 fe80::da47:32ff:fe0a:b0c.547 > fe80::3e52:82ff:fe1a:2b3c.546: dhcp6 reply (xid=1a2b3c ... (IA_NA IAID:1 T1:3600 T2:5760 (IA_ADDR 2001:db8:1234:5678::1001 pltime:7200 vltime:14400)) (DNS-server ...))

DUID типа 1 — LLT: «hwaddr/time». Адрес ::1001 из пула сервера, с preferred 7200 и valid 14400, продление в T1 = 3600.

Продление — Renew в T1 с Server ID, Rebind в T2 без него; оба тоже уходят на ff02::1:2, если сервер явно не разрешил unicast опцией 12. Confirm клиент шлёт, проснувшись из сна: «адрес ::1001 ещё годится в этом сегменте?» — сервер проверяет по префиксу и отвечает статусом. Release — при аккуратном отключении.

Что сервер не выдал: шлюз и префикс. Маршрут по умолчанию и 2001:db8:1234:5678::/64 dev eth0 хост взял из того же RA, что принёс флаг M. Если роутер объявит M = 1, но не пришлёт RA с prefix info, хост получит адрес и не будет знать, что соседи — соседи: каждый пакет уйдёт на роутер, который вернёт его обратно с Redirect. Схема «DHCPv6 без RA» не существует.


Stateless: только опции

RA с M = 0, O = 1: адрес делайте по SLAAC, а за остальным идите в DHCPv6. Клиент шлёт Information-Request без IA, сервер отвечает Reply с опциями: DNS, домены поиска, NTP, что угодно ещё. Сервер ничего не запоминает: нет аренд, нет таблицы, нет DUID в базе. Это самый дешёвый способ раздать параметры, которых в RA нет, и до появления RDNSS это был единственный способ сообщить хосту адрес DNS.

С RDNSS в RA stateless DHCPv6 нужен реже: для серверов времени, адреса АТС у IP-телефонов (они говорят по SIP — протоколу установления звонков, и им нужно знать, куда регистрироваться), параметров загрузки. Но клиенты по-прежнему отрабатывают флаг O, и в корпоративных сетях он обычно стоит.


Prefix delegation

Самая важная роль DHCPv6 — та, которой нет в DHCPv4 вовсе. Домашний роутер должен получить у провайдера блок адресов, чтобы раздать по /64 каждой своей сети. Делается это через IA_PD, и в схеме участвуют два роутера:

   провайдер (delegating router)                          домашний роутер (requesting router)           LAN
   2001:db8::/32                                          WAN eth1                                      eth0
        │                                                 │                                             │
        │◄── RS ──────────────────────────────────────────┤                                             │
        ├── RA: «шлюз — я», префикса для адресов нет ────►│ default via fe80::<провайдер>               │
        │                                                 │                                             │
        │◄── Solicit: IA_PD (IAID 0, хочу /56) ───────────┤                                             │
        ├── Advertise, затем Reply: IA_PD с IA Prefix ───►│                                             │
        │   2001:db8:1200::/56, pltime, vltime            │ из /56 берём /64 на каждую сеть             │
        │                                                 │                                             │
        │ маршрут: 2001:db8:1200::/56 via fe80::<роутер>  ├── RA: prefix 2001:db8:1200::/64, флаг A ───►│ SLAAC
        │                                                 │                                             │
  1. На WAN-интерфейсе роутер абонента получает RA от провайдера: маршрут по умолчанию через link-local адрес провайдерского роутера. Префикса с флагом A там может и не быть: WAN-интерфейсу глобальный адрес не обязателен, достаточно link-local.
  2. Роутер шлёт Solicit с IA_PD, в котором может подсказать желаемую длину (/56). Провайдер отвечает IA Prefix: 2001:db8:1200::/56 со сроками.
  3. Провайдерский роутер ставит у себя маршрут на этот /56 через link-local адрес абонента: теперь весь блок маршрутизируется в квартиру.
  4. Роутер абонента берёт из блока /64 для каждой своей сети (2001:db8:1200:0::/64 для LAN, 2001:db8:1200:1::/64 для гостевой) и объявляет их в RA, как в прошлой части. Хосты собирают адреса по SLAAC.

Продление IA_PD — те же Renew/Rebind. Если провайдер при переподключении выдаст другой /56 (так бывает у провайдеров, не закрепляющих префикс за абонентом), роутер отзовёт старый префикс в RA и объявит новый, и все хосты перенумеруются за минуты — именно для этого SLAAC устроен через сроки. Удобно и неудобно одновременно: адреса устройств дома меняются, и записи в DNS и правила файрвола приходится писать на ULA или через динамическое обновление.

В Linux на роутере всё это делает dhcpcd (одна строка ia_pd 1 eth0/0 — «проси префикс, первый /64 на eth0») или odhcpd в OpenWrt; у домашних роутеров — пункт «DHCPv6-PD» или «получить префикс автоматически».


Relay

Как и в DHCPv4, сервер может стоять в другом сегменте. Роутер-relay ловит multicast на ff02::1:2 и заворачивает сообщение клиента в Relay-Forward: внутри — исходное сообщение целиком (опция 9 Relay Message), а в заголовке relay — link-address, адрес relay в сегменте клиента (аналог giaddr: по нему сервер выбирает пул), и peer-address, link-local адрес клиента. Relay может добавить Interface-ID (опция 18, с какого порта) и Remote-ID (опция 37, идентификатор абонента у провайдера). Сервер отвечает Relay-Reply с ответом внутри, relay разворачивает и доставляет клиенту. Несколько relay подряд вкладывают сообщения друг в друга, и счётчик hop-count в заголовке растёт.


На сервере

Самый короткий stateful-сервер — dnsmasq, который заодно рассылает RA:

enable-ra
dhcp-range=2001:db8:1234:5678::100,2001:db8:1234:5678::1ff,64,12h
dhcp-option=option6:dns-server,[2001:db8:1234:5678::1]
dhcp-host=id:00:01:00:01:29:b8:f0:00:3c:52:82:1a:2b:3c,[2001:db8:1234:5678::50],printer

Резервирование — по DUID (id:…), как и обещано. Kea, преемник ISC dhcpd, описывает то же в JSON и умеет prefix delegation для провайдеров:

"subnet6": [{
  "subnet": "2001:db8:1234:5678::/64",
  "pools": [{ "pool": "2001:db8:1234:5678::100-2001:db8:1234:5678::1ff" }],
  "pd-pools": [{ "prefix": "2001:db8:1200::", "prefix-len": 48, "delegated-len": 56 }]
}]

Какие флаги ставить в RA, решает администратор, и это решение стоит принимать сознательно: M = 1 без A даёт полный учёт, но оставляет без адреса Android; A = 1 и M = 1 дают каждому хосту два адреса; A = 1 с O = 1 — компромисс «адреса сами, параметры с сервера».


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

Флаги в RA — первое, что проверять, если DHCPv6 «не работает»: клиент его просто не запустит без M или O:

$ sudo rdisc6 eth0 | grep -i stateful
Stateful address conf.    :          Yes
Stateful other conf.      :          Yes

DUID клиента — в файле его клиента: /var/lib/dhcpcd/duid, /var/lib/dhcp/dhclient6.leases, /var/lib/systemd/network/; на Windows — ipconfig /all, строка «DUID клиента DHCPv6». Там же видно, выдан ли адрес и какие сроки.

Запросить руками: sudo dhcpcd -6 -T eth0 (тест без применения) или sudo dhclient -6 -v eth0. И захват на портах 546/547 из раздела про stateful: если Solicit уходит, а Advertise не приходит — сервера в сегменте нет или relay не настроен; если приходит Reply со Status Code NoAddrsAvail — пул исчерпан или не подходит под link-address.

На провайдерском или тестовом роутере — маршруты, появившиеся от delegation: ip -6 route | grep -v 'proto kernel' покажет /56 через link-local соседа.


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

  • DHCPv6 — другой протокол: UDP 546/547, multicast ff02::1:2 с link-local адреса, DUID вместо MAC, IA с несколькими адресами и своими сроками, Rapid Commit на два сообщения.
  • Запускается только по флагам RA: M — адреса (stateful, Solicit/Advertise/Request/Reply), O — параметры (stateless, Information-Request/Reply). Шлюза и префикса в DHCPv6 нет, они всегда из RA.
  • Prefix delegation: роутер абонента просит IA_PD, получает /56 или /48, провайдер ставит на него маршрут, роутер раздаёт /64 своим сетям через RA.
  • Relay заворачивает сообщения в Relay-Forward с link-address для выбора пула.
  • Резервирования по DUID, который узнаётся после первого включения; Android DHCPv6 не поддерживает, поэтому SLAAC остаётся обязательным.

На этом блок про IPv6 закончен. Дальше — сегментация и туннели, и первая тема — VLAN: как одна физическая сеть становится несколькими логическими, четыре байта тега 802.1Q в кадре, access и trunk порты, native VLAN, маршрутизация между VLAN через роутер и L3-коммутатор, и VLAN на Linux одной командой.

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

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