# DHCP - Dynamic Host Configuration Protocol _Сеть: L4 и выше · LinuxLab Knowledge Base_ **TL;DR:** DHCP выдаёт хосту IP-адрес, маску, шлюз и DNS через broadcast. 4 пакета: DORA = Discover (клиент), Offer (сервер), Request (клиент), Ack (сервер). Аренда продлевается за 50% TTL. ## Зачем DHCP Когда новый хост попадает в [[broadcast-domain|сеть]], он не знает свой IP, адрес шлюза, маску, DNS. Можно прописать руками - но в офисе на 200 машин это безумие. DHCP-сервер слушает запросы и раздаёт настройки динамически. ## DORA - 4 пакета ``` Client (без IP) DHCP server | | | ── Discover ─────► | (broadcast 255.255.255.255:67) | "кто-нибудь дайте IP" | | | | ◄── Offer ───────── | (broadcast 255.255.255.255:68) | "предлагаю 10.0.0.42" | | | | ── Request ─────► | (broadcast - чтобы другие серверы видели) | "беру 10.0.0.42" | | | | ◄── Ack ────────── | | "ок, IP твой на 1 час" | | | v v IP=10.0.0.42, GW, DNS заданы ``` - **Discover** - L2-broadcast (`ff:ff:ff:ff:ff:ff`), L3-broadcast (`255.255.255.255`), src-IP `0.0.0.0`. Other DHCP-серверы в сети тоже видят. - **Offer** - сервер резервирует IP и предлагает его клиенту. Несколько серверов могут offer'нуть одновременно. - **Request** - клиент выбирает один из offer'ов и говорит «беру», явно указывая server-ID. Остальные серверы видят и освобождают свои offer'ы. - **Ack** - окончательное подтверждение. С этого момента IP клиента. ## Транспорт - всегда UDP TCP не работает по [[broadcast-domain|broadcast]]. UDP-порты: - **67** - DHCP-сервер слушает - **68** - DHCP-клиент слушает Без [[udp-basics|UDP]] DHCP в принципе невозможен - TCP-handshake требует уже установленного IP. ## Lease - аренда IP Каждый IP выдаётся **на TTL** - например, 24 часа. Клиент должен: - в **T1 = 50% TTL** прислать `Request` тому же серверу: «продли мне» - в **T2 = 87.5% TTL** broadcast'ом: «любой сервер - продли» - если до конца TTL не подтвердили - клиент теряет IP, идёт в Discover Зачем TTL: ноуты уезжают/приезжают, IP надо переиспользовать. На серверах TTL обычно ставят выше или резервируют по MAC. ## DHCP-options В пакете Offer/Ack идут **опции** с настройками: | Option | Что | |--------|-----| | 1 | subnet mask (255.255.255.0) | | 3 | routers ([[default-gateway|default gateway]]) | | 6 | DNS-серверы | | 12 | hostname | | 15 | domain name | | 51 | IP lease time | | 53 | message type (DISCOVER, OFFER, …) | | 54 | server identifier | | 66 | TFTP-server (для PXE-boot) | | 121 | classless static routes | Опция 121 особенно полезна для VPN-офисов: «весь трафик в 10.0.0.0/8 ходит через 192.168.1.1, остальное - в default». ## Что в Linux ```bash # Узнать lease на интерфейсе cat /var/lib/dhcp/dhclient.eth0.leases # Перезапросить аренду sudo dhclient -r eth0 # release sudo dhclient eth0 # renew # Современная сеть = systemd-networkd / NetworkManager, DHCP внутри systemctl status systemd-networkd nmcli device show eth0 | grep -i dhcp ``` Lease-файл живёт обычно в `/var/lib/dhcp/` или `/run/systemd/netif/leases/`. ## DHCP-relay В большой сети DHCP-сервер один на много VLAN. На каждом L3-устройстве настраивается **DHCP-relay**: услышал broadcast от клиента - переслал unicast'ом серверу, добавив `giaddr` (gateway IP) чтобы сервер знал, в какой подсети клиент. Без relay'я broadcast'ы не пересекают [[broadcast-domain|broadcast-домен]]. ## DHCPv6 - другой протокол IPv6 имеет SLAAC (auto-configure через RA), но и DHCPv6 для опций: DNS, домен. Порты UDP/546-547. Не путать. ## Когда что-то пошло не так - **No DHCP offers received** - проверь что сервер живой; relay настроен; нет «лишних» DHCP-серверов в сети - **Got IP but no internet** - опция 3 (gateway) или опция 6 (DNS) забыта на сервере - **Lease conflict** - два сервера выдают пересекающиеся пулы; arping видит два хоста (две MAC-записи), отвечающих на один IP - **Rogue DHCP** - кто-то воткнул свой роутер; защита - DHCP snooping на свитче - **DUID changed** - после переустановки ОС хост получает новый IP, хотя MAC не менялся: client-ID по дефолту = DUID, не MAC ## Команды ```bash sudo dhclient -v eth0 ``` Verbose DHCP-аренда: видно DISCOVER, OFFER, REQUEST, ACK в логе ```bash tcpdump -i eth0 -nn 'port 67 or port 68' ``` Поймать DHCP-трафик. Стандартный кейс - перезапустить интерфейс ```bash nmcli connection show eth0 | grep -E 'dhcp|method' ``` NetworkManager: DHCP включён или статика? ```bash cat /var/lib/dhcp/dhclient.eth0.leases | grep -E 'fixed|router|domain-name' ``` Что прописал DHCP-сервер в текущей аренде ```bash ip addr show eth0 | grep -A1 'inet ' ``` Текущий IP/маска - результат DHCP, можно проверить что совпадает с lease ## См. также - [UDP - User Datagram Protocol](/kb/udp-basics.md) - [IPv4-адресация и CIDR](/kb/ipv4-addressing.md) - [Default gateway - выход из своей сети](/kb/default-gateway.md) - [DNS resolution](/kb/dns-resolution.md) - [Broadcast-домен - что это и кто в нём живёт](/kb/broadcast-domain.md)