DHCP与Option基本概念启蒙

2020-06-04

关键字:Option60、新增Option、插入一个Option


 

1、DHCP是什么?

 

DHCP 全称 Dynamic Host Configuration Protocol,动态主机配置协议。

 

说人话就是用于路由器给各个电脑、手机、网络设备分配各种地址以使设备能访问网络用的,同时它还兼有管理某一局域网内设备的功能。

 

DHCP 的前身是 BOOTP,即 Bootstrap Protocol。

 

DHCP 是一种基于 UDP 协议的局域网通讯协议。

 

2、Option是什么?

 

DHCP 协议其实就是一段字节流,不同位置的字节数据代表着不同的含义。它大体上可以分成以下两个组成部分:

1、正文部分

2、附加选项部分

 

正文部分就是一个DHCP包中必不可少的数据。

 

附加选项是可选的,即 Option。通常会根据实际的场景需求来决定是否添加。Option部分是直接插在DHCP包的末尾的,它仍旧属于DHCP包。

 

Option 的作用就是用以扩展 DHCP 的功能的。因为 DHCP 协议除了简单的分配地址外还要实现管理设备的功能,而不同应用场景往往又会催生出不同的需求,为了满足这些客制化的需求,就需要这种可以由用户自定义内容的“Option”可选项了。

 

Option 的格式简单,大体可以分成三个组成部分:

1、Option代码

1个字节。

2、内容长度

1个字节。

3、内容

内容长度个字节。

其格式如下图所示:

 

因为 Option 代码就是用来区分不同用途的标识符。因为它占 1 个字节,因此 Option 总共有 256 种(0 ~ 255,事实上只有 254 种可以使用的值,因为 0 和 255 是保留值)

 

在一个 DHCP 包中可以插入多个 Option 字段。例如,我们以一个 携带了 Option 字段的 DHCP 报文为例,其 Option 数量与位置如下图所示:

 

Option 代码的值从 0 ~ 255 都代表了不同的含义,或者说代表了不同的控制类型。每一个代码的详细说明请各位同学自行参阅相关文档,这里给出文档链接如下:

https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xml

 

3、Option60

 

Option60 就是指 Option 的代码为 0x3c 的字段值。它通常用于携带设备标识符信息以供 DHCP 服务器鉴权使用。从理论上来说,任何设备都可以接入到 DHCP 服务器并请求获得相应资源。但如果我们的 DHCP 所提供的这种服务是被“商业化”了的,那当然就需要这种鉴权机制了。鉴权不通过,我 DHCP 服务器就可以忽略掉这个设备的服务请求。这种鉴权,通常就是交由 Option60 来实现的。

 

Option60 的格式如下图所示:

 

 

Option60 的配置在 Android4.4 中们于如下代码文件:

.\frameworks\base\core\java\android\net\EthernetDataTracker.java

在系统起来以后开始 DHCP 获取 DHCP 时会调用 runDhcp() 方法:

private void runDhcp()

然后会在这里读取是否有开启 Option60 的标志以及要携带的数据信息。 Option60 的开启标志与数据信息通常可以在设置APK中设定。因为 Option60 常用于鉴权,因为有些设备是往 Option60 中填写一个通行证信息,并会做适当的加密操作。

 

runDhcp() 方法中随后会通过 NetworkUtils.runDhcpPlus() 方法来将相应参数传递下去。这个方法是一个 native 方法,它的最终实现位于:

.\frameworks\base\core\jni\android_net_NetUtils.cpp
    static jboolean android_net_utils_runDhcpCommon(...)

随后又会调用 dhcp_do_request() 函数继续传递参数,如下图所示:

 

 

随后就到以下代码中了:

.\system\core\libnetutils\dhcp_utils.c

 

这个 dhcp_do_request() 函数所做的事情,基本就是:根据参数组装启动 dhcpcd 服务的命令以及将参数信息写到系统属性中去。如下图所示:

 

再然后就是 dhcpcd 服务登场了。dhcpcd 服务代码目录如下:

./external/dhcpcd/

 

dhcpcd 服务在爬起来以后就会跑以下代码的 main() 函数:

.\external\dhcpcd\dhcpcd.c
    int main(int argc, char **argv)

然后在如下图所示的函数中解析有哪些 Option 是要添加组装要携带的信息的:

 

 

.\external\dhcpcd\if-options.c

 

 

这里还是以 Option60 为例,它在 parse_option() 中的解析如下图所示:

 

 

再接下来就到真正的发送 DHCP 数据报文的时候了。这个操作于 dhcp.c 代码中实现:

.\box\external\dhcpcd\dhcp.c
  ssize_t make_message(struct dhcp_message **message, const struct interface *iface, uint8_t type)

关于 Option60 的组装如下图所示。

 

这个指针 p 就是记录 DHCP 报文字节流用的了。

 

再往下就是将报文送到网卡驱动发送出去了。

 

4、如何在DHCP网络包中插入一个新的Option?

 

在 Android 系统中一般都会有 Option60 的完整实现,用户只需在设置APK中设置相应信息即可自动实现 Option60 的字段携带。

 

但如何新增一个系统尚不支持的字段呢?

 

其实也很简单。

 

前面第 3 节介绍的 Option60 的调用组装流程照着来一次就行的了。这里就以新增一个 Option156 来简单说说如何在 DHCP 中插入一个新的 Option字段。

 

首先的是应用层将相应信息传递下来的流程。这个就不多说了,同学根据自己的实际需求实现就好。

 

然后我们可以关注 EthernetDataTracker.java 中的 runDhcp() 方法。可以依照 Option60 的做法将 Option156 的信息传递到这里来。如下图所示:

 

 

然后,笔者为了偷懒,就直接将 Option156 的信息在这里写到系统属性中去了。这种做法不太好,因为按照常,我们应该将 Option156 的信息一步步传到 C 代码层,根据参数来组装启动 dhcpcd 服务的参数的。

 

但笔者偷懒了。

 

就这样吧。

 

再然后就到 if-option.h 中去新增用于保存 Option156 信息的结构体变量:

.\external\dhcpcd\if-options.h

 

 

接下来是去 if-options.c 中解析 Option156 的信息,并将它拷贝到结构体中。直接复制 Option60 的做法来就行了:

.\external\dhcpcd\if-options.c

 

 

最后去到 dhcp.c 的 make_message() 函数中完成最后的拼装:

.\external\dhcpcd\dhcp.c

 

 

如此,开机时抓一个 DHCP 的网络包,就可以发现笔者新增的 Option156 字段信息了,如下图所示:

 

 

上图网络包 wireshark 提示了笔者添加的 Option156 值错误的警告。它的意思是说 Option156 这个字段的“内容”的长度只允许是 1。但笔者在这里给它携带了一个长度为 19 个字节的字符串。因为违反了规范,所以 wireshark 给出了警告。但这其实并不重要。只要你的 DHCP 服务器能解析出来,就没有问题。

 


参考资料:

  http://www.360doc.com/content/15/1130/09/8335678_516871788.shtml

  https://blog.csdn.net/zzd_zzd/article/details/88372014

  https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xml

  https://tools.ietf.org/rfc/rfc6926.txt

posted @ 2020-06-04 16:56  大窟窿  阅读(13710)  评论(0编辑  收藏  举报