背景

最近因工作需要接触了 H3CiNode 客户端, 参考其官网对 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 字段定义了 硬件地址类型, 110mb 以太网, 具体定义可参见 RFC 1700, 在 DHCP 中一般使用 1.

  • hlen 字段表示 硬件地址长度, 依据 htype 定义当 htype1, 即 以太网 时, 该字段为 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, 仅当在 DHCPOFFERDHCPACK 请求中填充该字段.

  • 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 identifierchaddr 字段内包含标识以告知服务端其已放弃对网络地址的租用.

客户端可能收到来自服务端的 DHCPOFFER, DHCPACKDHCPNAK 三种消息; 服务端可收到来自客户端的 DHCPDISCOVER, DHCPREQUEST, DHCPDECLINE, DHCPRELEASEDHCPINFORM 五种消息. 下图则详细描述了 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.

  1. magic cookie, 正如前文所述, 在 DHCP 报文内包含 4 字节的 magic cookie, 其值为 [0x63, 0x82, 0x53, 0x63].

  2. 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 |
       +-----+-----+-----+
    
  3. 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 | ...
       +-----+-----+-----+-----+-----+---
    
  4. Requested IP Address 该选项用于客户端在 DHCPDISCOVER 消息中向服务端请求指定的 IP.

        Code   Len          Address
       +-----+-----+-----+-----+-----+-----+
       |  50 |  4  |  a1 |  a2 |  a3 |  a4 |
       +-----+-----+-----+-----+-----+-----+
    
  5. 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
    
  6. End Option 该选项为结束标识, 用于标识消息体的结束, 对应客户端发送的消息可立即结束于此处, 对应服务端发回的消息 RFC 要求 options 字段需填充至少 312 且至多 576 字节.

        Code
       +-----+
       | 255 |
       +-----+
    
  7. Pad Option 该选项主要用于字段填充.

        Code
       +-----+
       |  0  |
       +-----+
    
  8. Subnet Mask 该选项用于指示客户端子网掩码, 其 Len 为固定 4 字节(DHCPv4), 后续 4 字节为对应的子网掩码值. 同时如果服务端同时提供了 router optionSubnet Mask 应该位于前部.

        Code   Len        Subnet Mask
       +-----+-----+-----+-----+-----+-----+
       |  1  |  4  |  m1 |  m2 |  m3 |  m4 |
       +-----+-----+-----+-----+-----+-----+
    
  9. Router Option 该选项主要用于列举当前网络可路由的 IP 地址, 同时其 Len 最少为 4 且永远为 4 的倍数.

        Code   Len         Address 1               Address 2
       +-----+-----+-----+-----+-----+-----+-----+-----+--
       |  3  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
       +-----+-----+-----+-----+-----+-----+-----+-----+--
    
  10. Renewal (T1) Time Value 该选项主要用于指示从客户端获取 IP 地址到续期该 IP 所需间隔时间. T1 Interval 为 4 字节 32 位整数, 单位为 .

        Code   Len         T1 Interval
       +-----+-----+-----+-----+-----+-----+
       |  58 |  4  |  t1 |  t2 |  t3 |  t4 |
       +-----+-----+-----+-----+-----+-----+
    

REF

  1. RFC 2131 - Dynamic Host Configuration Protocol
  2. RFC 2132 - DHCP Options and BOOTP Vendor Extensions