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字节长度的数据体, 其中包含Type1 字节和Client-Identifiern-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 - 0x42End 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 | +-----+-----+-----+-----+-----+-----+