DHCP 协议分析及实现 - Ⅰ
背景⌗
最近因工作需要接触了 H3C
的 iNode
客户端, 参考其官网对 iNode
的描述:
iNode智能客户端是H3C公司自行设计开发的基于Windows的多业务接入客户端软件,提供802.1x、Portal、VPN等多种认证方式,可以与H3C以太网交换机、路由器、VPN网关等网络设备共同组网,实现对局域网、广域网、VPN、无线接入的用户认证,是对用户终端进行身份验证、安全状态评估以及安全策略实施的主体,可以按照企业接入安全策略的要求,实现基于角色/身份的权限和安全控制。
以此为发端, 本来主要讨论 DHCP
协议的设计与实现, 以期最后通过修改 DHCP
协议实现 私有
的 DHCP
协议, 实现一定条件下限制网络访问的目的.
同时亦声明本文仅就技术上讨论一种私有协议实现的可能性, 只有如何实现以及是否可行并不在本文讨论范围内.
分析⌗
DHCP
协议前身是 BOOTP
协议, 当前关于 DHCP
最新的信息可在 RFC 2131
中查阅, 另外 DHCPv6
则可在 RFC 3315
中定义. 不过本文当前仅讨论 DHCPv4
. DHCP
全称 Dynamic Host Configuration Protocol
, 即 动态主机配置协议
, 是一种使网络管理员能够集中管理和自动分配 IP
地址的通信协议. 在 IP
网络中每个连接 Internet
的设备都需要分配唯一的 IP
地址, DHCP
协议可使得网络管理员采用中心化的方式分配 IP
地址, 并对 IP
地址的使用进行必要的管理, 当某台计算机移动到网络其他位置时, 能自动收到新的 IP
地址请求.
同时 DHCP
使用了 租约
的概念, 这使得在局域网中可以最大化地使用有限的 IP
地址资源, 同时 DHCP
也支持为计算机分配静态地址.
DHCP
协议是一种基于UDP
之上的应用层协议, 主要是因为在依据DHCP
获取IP
地址前计算机尚无有效的IP
地址, 此时客户端
可利用UDP
的广播特性向局域网内广播DHCP
报文, 同时DHCP 服务器
亦采用广播的形式向局域网内响应对应请求.DHCPv4
定义了以下几种消息:DHCPDISCOVER
消息用于客户端
广播以确定局域网内服务器
.DHCPOFFER
消息用于服务端响应客户端的DHCPDISCOVER
消息并向客户端提供配置参数.DHCPREQUEST
消息主要用于客户端依据服务端提供的配置参数向服务端请求IP
地址.DHCPACK
消息用于服务端向客户端依据配置参数确认分配的IP 地址
.DHCPNAK
消息用于服务端通知客户端网络地址错误或客户端地址过期等.DHCPDECLINE
消息用于客户端向服务端指示已拥有网络地址.DHCPRELEASE
消息用于客户端告知服务端释放对应的网络地址.DHCPINFORM
消息用于客户端向服务端请求本地配置.
RFC 2131
在定义 DHCP
的几种消息的同时也定义了 DHCP
报文格式:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| op (1) | htype (1) | hlen (1) | hops (1) |
+---------------+---------------+---------------+---------------+
| xid (4) |
+-------------------------------+-------------------------------+
| secs (2) | flags (2) |
+-------------------------------+-------------------------------+
| ciaddr (4) |
+---------------------------------------------------------------+
| yiaddr (4) |
+---------------------------------------------------------------+
| siaddr (4) |
+---------------------------------------------------------------+
| giaddr (4) |
+---------------------------------------------------------------+
| |
| chaddr (16) |
| |
| |
+---------------------------------------------------------------+
| |
| sname (64) |
+---------------------------------------------------------------+
| |
| file (128) |
+---------------------------------------------------------------+
| |
| options (variable) |
+---------------------------------------------------------------+
op
字段定义了消息的方向1
为客户端
向服务端
发生请求,2
则为服务端
发回的响应.htype
字段定义了硬件地址类型
,1
为10mb
以太网, 具体定义可参见RFC 1700
, 在DHCP
中一般使用1
.hlen
字段表示硬件地址长度
, 依据htype
定义当htype
为1
, 即以太网
时, 该字段为6
, 也即MAC
地址长度.hops
字段表示DHCP
协议经过的节点数, 客户端在初始发送DHCP
请求时将其设置为0
,DHCP
协议的中继
节点可选地增加该字段的值.xid
字段表示事务 ID
, 客户端选择一个随机数, 并在其后客户端发送或是服务端发回响应过程中使用该值.secs
字段为客户端获取IP
到进行地址续约
时所经历的秒数.flags
字段当前在DHCP
协议中仅采用了高 1 位, 后续的 15 位当前都是保留的, 使用的 1 位主要用于提示DHCP
服务端
或中继
节点是否将广播信息发送到客户端所在的子网.ciaddr
字段为客户端
IP 地址
, 仅当客户端在BOUND
,RENEW
或者REBINDING
状态时才填充该字段.yiaddr
字段表示your
客户端
IP 地址
.siaddr
字段为下一服务端
节点IP
, 仅当在DHCPOFFER
和DHCPACK
请求中填充该字段.giaddr
字段为中继节点
IP 地址
.chaddr
字段为客户端
硬件地址
, 一般为MAC 地址
.sname
字段为可选的服务器主机名
, 并且以null
字符串结束, 也即0x00
.file
字段为启动文件名
, 在DHCPDISCOVER
消息中以常规文件名或null
表示, 在DHCPOFFER
消息中以全限定路径名表示.options
字段是变长的可选项. 其中首 4 位为固定的magic cookie
- [0x63, 0x82, 0x53, 0x63].
Server Client Server
(not selected) (selected)
v v v
| | |
| Begins initialization |
| | |
| _____________/|\____________ |
|/DHCPDISCOVER | DHCPDISCOVER \|
| | |
Determines | Determines
configuration | configuration
| | |
|\ | ____________/ |
| \________ | /DHCPOFFER |
| DHCPOFFER\ |/ |
| \ | |
| Collects replies |
| \| |
| Selects configuration |
| | |
| _____________/|\____________ |
|/ DHCPREQUEST | DHCPREQUEST\ |
| | |
| | Commits configuration
| | |
| | _____________/|
| |/ DHCPACK |
| | |
| Initialization complete |
| | |
. . .
. . .
| | |
| Graceful shutdown |
| | |
| |\ ____________ |
| | DHCPRELEASE \|
| | |
| | Discards lease
| | |
v v v
上图展示了局域网内 DHCP
信令通信的流程.
- 客户端在本地局域网内广播
DHCPDISCOVER
消息, 如果DHCP
服务端与客户端不处于同一物理网段则可通过可选的中继
节点进行中继转发. - 局域网内所有服务端都可能通过
DHCPOFFER
消息对DHCPDISCOVER
消息进行响应, 同时在DHCPOFFER
消息内通过yiaddr
字段指示可用的网络地址, 同时也在options
字段内包含额外的参数. - 客户端可能会从一或多个服务端收到收到一或多个
DHCPOFFER
消息. 客户端根据在DHCPOFFER
消息内包含的参数通过广播DHCPREQUEST
消息选择一个服务端进行响应, 并通过服务端标识
(server identifier
) 指示具体选择的服务器. 同时在yiaddr
字段内保存欲请求的IP
. - 对于未被选中的服务端收到
DHCPREQUEST
广播时(根据server identifier
字段)明确客户端拒绝了其预分配的IP
地址. 针对被选中的服务端则内部提交并将对应网络地址与客户端相绑定, 同时通过DHCPACK
消息通知客户端. 在DHCPACK
消息内的yiaddr
字段同时包含选择的网络地址. 如果被选中的服务端无法响应DHCPREQUEST
消息(如待分配的网络地址已被使用)则应当通过DHCPNAK
向客户端响应. - 客户端收到
DHCPACK
时需根据options
字段内配置的参数进行最后的检查(如通过ARP
检查分配的网络地址是否可用), 如果客户端发现该网络地址已被使用则应当通过DHCPDECLINE
向服务端进行响应并重启以上配置流程. 为防止过多的网络流量客户端应当至少等待10s
再次进行配置. 如果客户端收到DHCPNAK
则立即重启配置流程. - 客户端可通过在
DHCPRELEASE
消息的client identifier
或chaddr
字段内包含标识以告知服务端其已放弃对网络地址的租用.
客户端可能收到来自服务端的 DHCPOFFER
, DHCPACK
和 DHCPNAK
三种消息; 服务端可收到来自客户端的 DHCPDISCOVER
, DHCPREQUEST
, DHCPDECLINE
, DHCPRELEASE
和 DHCPINFORM
五种消息. 下图则详细描述了 DHCP
客户端的状态间流转:
-------- -------
| | +-------------------------->| |<-------------------+
| INIT- | | +-------------------->| INIT | |
| REBOOT |DHCPNAK/ +---------->| |<---+ |
| |Restart| | ------- | |
-------- | DHCPNAK/ | | |
| Discard offer | -/Send DHCPDISCOVER |
-/Send DHCPREQUEST | | |
| | | DHCPACK v | |
----------- | (not accept.)/ ----------- | |
| | | Send DHCPDECLINE | | |
| REBOOTING | | | | SELECTING |<----+ |
| | | / | | |DHCPOFFER/ |
----------- | / ----------- | |Collect |
| | / | | | replies |
DHCPACK/ | / +----------------+ +-------+ |
Record lease, set| | v Select offer/ |
timers T1, T2 ------------ send DHCPREQUEST | |
| +----->| | DHCPNAK, Lease expired/ |
| | | REQUESTING | Halt network |
DHCPOFFER/ | | | |
Discard ------------ | |
| | | | ----------- |
| +--------+ DHCPACK/ | | |
| Record lease, set -----| REBINDING | |
| timers T1, T2 / | | |
| | DHCPACK/ ----------- |
| v Record lease, set ^ |
+----------------> ------- /timers T1,T2 | |
+----->| |<---+ | |
| | BOUND |<---+ | |
DHCPOFFER, DHCPACK, | | | T2 expires/ DHCPNAK/
DHCPNAK/Discard ------- | Broadcast Halt network
| | | | DHCPREQUEST |
+-------+ | DHCPACK/ | |
T1 expires/ Record lease, set | |
Send DHCPREQUEST timers T1, T2 | |
to leasing server | | |
| ---------- | |
| | |------------+ |
+->| RENEWING | |
| |----------------------------+
----------
OPTIONS⌗
options
定义为 2 字节的 Code
和 1 字节的 Len
, 而后则依据 Len
包含指定长度字节的数据体. 由于当前 options
众多当前仅列举一些比较重要的 options
.
magic cookie
, 正如前文所述, 在DHCP
报文内包含 4 字节的magic cookie
, 其值为 [0x63, 0x82, 0x53, 0x63].DHCP Message Type
该选项编码为53
, 其后在Len
内定义了 1 字节的数据体, 即Type
, 而Type
在为0x01 ~ 0x08
若干种不同的DHCP
消息类型.Value Message Type ----- ------------ 1 DHCPDISCOVER 2 DHCPOFFER 3 DHCPREQUEST 4 DHCPDECLINE 5 DHCPACK 6 DHCPNAK 7 DHCPRELEASE 8 DHCPINFORM Code Len Type +-----+-----+-----+ | 53 | 1 | 1-9 | +-----+-----+-----+
Client-identifier
该选项编码为61
, 其后在Len
内定义了n
字节长度的数据体, 其中包含Type
1 字节和Client-Identifier
n-1
字节. 其中Client-Identifier
主要用于服务端在其数据库内鉴别查找客户端, 在DHCP
语义环境下Type
通常为0x01
即硬件地址
(MAC
), 同时Client-Identifier
至少为 2 字节, 如果为MAC
地址的话则为 6 字节.Code Len Type Client-Identifier +-----+-----+-----+-----+-----+--- | 61 | n | t1 | i1 | i2 | ... +-----+-----+-----+-----+-----+---
Requested IP Address
该选项用于客户端在DHCPDISCOVER
消息中向服务端请求指定的IP
.Code Len Address +-----+-----+-----+-----+-----+-----+ | 50 | 4 | a1 | a2 | a3 | a4 | +-----+-----+-----+-----+-----+-----+
Parameter Request List
该选项用于DHCP
客户端向服务端请求特定的配置.Code Len Option Codes +-----+-----+-----+-----+--- | 55 | n | c1 | c2 | ... +-----+-----+-----+-----+---
当前可选的配置有:
Subnet Mask - 0x01 Router Option - 0x03 Domain Name Server Option - 0x06 Network Time Protocol Servers Option - 0x42
End Option
该选项为结束标识, 用于标识消息体的结束, 对应客户端发送的消息可立即结束于此处, 对应服务端发回的消息RFC
要求options
字段需填充至少312
且至多576
字节.Code +-----+ | 255 | +-----+
Pad Option
该选项主要用于字段填充.Code +-----+ | 0 | +-----+
Subnet Mask
该选项用于指示客户端子网掩码, 其Len
为固定 4 字节(DHCPv4
), 后续 4 字节为对应的子网掩码值. 同时如果服务端同时提供了router option
则Subnet Mask
应该位于前部.Code Len Subnet Mask +-----+-----+-----+-----+-----+-----+ | 1 | 4 | m1 | m2 | m3 | m4 | +-----+-----+-----+-----+-----+-----+
Router Option
该选项主要用于列举当前网络可路由的IP
地址, 同时其Len
最少为 4 且永远为 4 的倍数.Code Len Address 1 Address 2 +-----+-----+-----+-----+-----+-----+-----+-----+-- | 3 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... +-----+-----+-----+-----+-----+-----+-----+-----+--
Renewal (T1) Time Value
该选项主要用于指示从客户端获取IP
地址到续期该IP
所需间隔时间.T1 Interval
为 4 字节 32 位整数, 单位为秒
.Code Len T1 Interval +-----+-----+-----+-----+-----+-----+ | 58 | 4 | t1 | t2 | t3 | t4 | +-----+-----+-----+-----+-----+-----+