DHCP无类型静态路由──一个摆设

引子

过年回到老家,连着2.4GHz Wi-Fi,在电视里过年的歌曲和相声,与长辈们的麻将声中,和争分夺秒在14天里打完一个寒假的游戏的小孩们抢总共不到100M的网速;不止如此,爱看的网站个个都是CONNECTION_RESETDNS_PROBE_FINISHED_NXDOMAINERR_NAME_NOT_RESOLVED,着实感觉生活不易。我翻出我好久之前买的树莓派,打算搭一个单臂路由,来解决众多设备的上网难题,作为软路由的替代。

但是单臂路由就有一个问题。只要把网关指向单臂路由而不是主路由,数据就要在单臂路由的臂上往返。之前买的4B版网络还算行,但找不到了,3B版的有线网速度就比较让人着急了。相当于总的带宽被树莓派的收发速率所限制,而且单臂的做法,也使得原本的全双工互不干扰的传输变成实质上的半双工传输,上传和下载的带宽共同占据同一个带宽。

但是办法总比问题多,配一个路由表,有些网站直接从主路由出去,有些网站走树莓派,分流了效果不就好了吗?主路由想想也是NetGe*r, Mercu*y, T*-link这种主流厂家的产品,现在都是买路由器当摆件的年代了,支持路由表想必不太现实。而用户端的路由表,看着我手上这些设备,能手动配置路由表的都寥寥无几。

不让用户配,总得让网络有一个配置方法吧。毕竟路由表是三层网络的核心部件,总不能靠设备自己猜网关在哪儿啊。DHCP提供了Router选项,用来配置该网络的网关。而同样由DHCP提供的121 Classless-Static-Route,RFC3442 [1]写明了是用于配置无类型网络(CIDR)静态路由的。打开Wireshark抓个包,看到本机发出的DHCP request包里面带了这个选项,内心一片窃喜。如果能够把路由表通过DHCP配置到每个设备中,就可以显著降低树莓派的流量了。

选项121:无类型静态路由

DHCP协议想必读者们都不陌生,但通常也就止步于通过DHCP用于获取本机的IP地址、子网掩码和网关信息,用于配置IPv4协议栈,也就是第一个广播Discover包和返回的Offer包。实际上,客户端会接收到相关配置信息的Offer时,会再次广播一个DHCP Request包用于向整个网络确认。这一IP如果被确认,就会返回一个ACK包。

实际上,除了获取常见的网络参数,DHCP上还承载了更多的功能。DHCP通过选项,对这些功能进行分类。除了IP地址、子网掩码等之外,还有一些不常见的功能,例如指定DNS服务器、LDAP服务器、POP3和日志服务器,还提供了TFTP选项和用于PXE网络启动的各种参数等。

参数的数量非常多,DHCP采用请求机制。即客户端将需要获取的选项字段记录在request包中,DHCP服务器对应这一请求返回有效的字段的内容。

Linux上常用的DHCP服务端在发出DHCP request时,会请求编号为121和249的选项,这些选项的目的是配置无类型静态路由。编号121是RFC3442指定的,而249则被早期微软的DHCP服务器所使用。因为我没有Windows的设备,我们侧重在121选项上,249选项的配置方法应该是类似的。

RFC3442指定,如果121选项有效,则以其中的内容覆盖网关配置和已被废弃的选项33:有状态静态路由配置。选项是以String,或者说uint8数组存储的。每一个条目按照一下方式排布:

1
子网前缀长度,网络地址的显著位,网关地址

即,例如12.34.56.0/23的网关在192.168.1.1192.0.0.0/7的网关在192.168.1.2,而0.0.0.0/0(默认网关)在192.168.1.1,则需要写为:

1
2
3
23, 12,34,56, 192,168,1,1,
7, 192, 192,168,1,2,
0, 192,168,1,1

逗号、空格和换行是用于分隔8位无符号整数的,不会加入数组。上面的部分总共有19个数,在包中会以

1
2
3
-----------------------------------------
| 121 | 19 | 23 | 12 | 34 | 56 | 192 | ....
-----------------------------------------

的形式存储。前两位的121是选项编号,19是数组长度。

问题:溢出

如您所见,数组长度也是用一个8位无符号整数来存储的,这意味着最多只能够表示255个字符。我们看到,一个前缀长度为24的条目就需要占用8个字符,255个字符能够表述的条目数量可能大概在30-40条左右。相比于分配给中国的网络数量(APNIC大概在8000条左右,做了进一步的聚合之后大概在5000条左右),简直是杯水车薪。

同样考虑到条目大小的问题,在RFC3396[2]中,DHCP协议引入了编码长可变长度数组选项的连接(Concatenation-requiring)。简单来说,DHCP的条目线性连接,以255选项结束。DHCP每一个条目的长度不能超过255个字节,当出现多个同一选项的条目时,支持连接选项的客户端需要将这些条目的内容按照出现的先后顺序连接。例如客户端收到如下的选项:

1
2
3
Option MagicNum [length 2] 192,168;
...
Option MagicNum [length 3] 1,0,24;

将会按照顺序连接起来,并记录为MagicNum [length 5] 192,168,1,0,24

为了兼容性,该RFC还建议DHCP服务器确定客户端是否支持分段。例如,一旦DHCP客户端请求了需要分段的选项(如121选项),那么服务器就应该假定该客户端支持分段,并严格按照分段来发送,否则就不发送需要分段的选项。

我们观察到,Linux上的常见DHCP客户端与网络配置工具,均支持这一分段选项的接收(否则就不能请求需要分段的选项了)。但目前常见的Linux DHCP服务器,均不支持分段发送。尤其令人大跌眼镜的是ISC的dhcp,其配套的客户端支持这一分段选项,而服务器并非如此。例如一个长300字节的路由表,服务器会将长度标记为255(最大值),但将整个长为300字节的路由表接在后面,发生了选项越界溢出。多出来的这45个字节会被DHCP客户端解释为其他的选项。如果字节无意义还好,在解包的时候会认为发生错误并丢弃;如果恰好能够解释为特定的内容,就会导致非常奇怪的结果。

DHCP包的大小问题

就算通过一番奇技淫巧,把分段整出来了,还会面临另一个难关:DHCP包太小,路由表塞不下。

可是DHCP包设计之初就考虑到了大小问题,其长度字段是16位整数,即65536个字节。装这么个路由表绰绰有余。这其中的缘由,就又牵扯到实现问题上了。

DHCP包虽然是以UDP协议包裹的,但和UDP、TCP等常见协议不一样。因为其工作在非常特殊的阶段,此时客户端可能还没有建立一个完整的IPv4协议栈,最早发出的DHCP Discover/Offer包为了稳定不会分段,以防止一些客户端不能正确处理。在这里MTU就限制了DHCP包的最大大小。而一些程序为了省事,将这个大小进一步缩小为DHCP协议的最小长度576字节。

如果你仔细观察最初的DHCP Discover包的内容,就会发现,其请求的选项都是基础而必要的选项。而更长、可能超过MTU限制的选项则会放在第二次的Request中。此时的Request,按照规范,可以附有客户端能够接受的最大包长度,以供服务器按需排布恰当的内容。

但是有哪些客户端这样做了呢?几乎没有。为了对付这些无信息的客户端,DHCP服务器会设置一个可以接受的大小,以此为发送的上限。有些DHCP服务器会设置为与MTU相关的大小,而有些DHCP服务器则会按照576字节(最小值)来配置。ISC的DHCP服务器实现甚至限制最大值为1500,就算MTU设置得再大,客户端可以接受的包再大,也不会发出超过1500字节的包(甚至IP包都配置为Don’t Fragment)。需要注意的是,IP协议是有分段(fragmentation)的,除了Offer包的兼容性问题之外,其他包的大小并不会受到单个发包MTU的限制。

无用之物

DHCP能出这么多问题,也是因为DHCP客户端的实现过于奔放,跨越二十年,支持的字段各有不同,为了兼容性只能如此。

Android和iOS的客户端都不支持这一选项,这些设备的DHCP实现压根就不会请求121选项,即使收到这些选项也会忽略。这就使得这个功能比较鸡肋了。

虽然DHCP协议有足足255个选项,大部分的选项都分配了固定的语义,但因为DHCP协议客户端和服务端的设计者各自为政,真正使用的选项,也就只有几个而已。同时也因为网络本身的发展,诸如SDN等概念的提出和“越俎代庖”的各种网络设备,DHCP协议在未来网络中扮演的角色也会越来越边缘化。


  1. Ted L., Bernie V., et al. "The Classless Static Route Option for Dynamic Host Configuration Protocol (DHCP) version 4", RFC 3442, December 2002. ↩︎

  2. Ted L., Stuart C. "Encoding Long Options in the Dynamic Host Configuration Protocol (DHCPv4)", RFC 3396, November 2002. ↩︎

Ads by Google

Read our privacy policy on how these personalized advertisements are delivered to you.

For your reading experience, we provide full-text RSS feeds. Although math formulas cannot be displayed well, the interface can be adjusted as you like and there are no ads.