关于169.254.0.0/16地址的一点笔记

一年之前

年轻的Nova在为语音楼计算机教室配置网络的时候,由于配置失误,所有的计算机都无法访问到网络,挑了几台计算机ipconfig了一下发现清一色的都是169.254开头的IP,且做tracert的时候全部断在第一跳,于是我在未经求证的情况下武断的认为:在Windows系统下,所有没有分配到IP的计算机不会像Linux一样不显示IP,而是显示成169.254开头的一个IP。

昨天

在程序设计大赛团队赛打酱油的时候,老师在投影上给出了pc2server的IP地址竟然也是一个169.254的IP地址。“机智的我”一下子就看出了“其中的问题”,并立刻举起了手向全班宣布了这个IP是个不可达的IP的消息,老师倒也不惊讶,淡淡地说道:我刚刚测试的一台电脑是可以连接的,你那边是不是网线没插上?

不行,我必须解释这一切,说着我打开了cmd开始一边输入ping <那个IP地址>一边解释这个IP是微软的系统在没有分到IP的时候自动给自己分的一…话还没说完,ping的结果就出来了,4个包全部到达,延迟<1ms。

“哦哦,没问题,了,老师…”

然后就看到身旁的妹子(然而并不是我的)和其他队的成员诧异看着我…

169.254.0.0/16的来历

有了昨天被快速打脸的经历后,我决定探索一下这个IP的来历和昨天事件的本质。

首先很显然,169.254这个IP是一个保留地址,如果你去ip.cn上面查询的话,会告诉这个是“非Internet地址”,当然,这个不是我们想要的结果。

根据RFC 3927,如果一个网络接口被配置了DHCP但是DHCP服务器并没有为其分配IP的话,这个接口就会自动给自己分配这个称为link-local IPv4 address的地址,或者用微软的叫法称为Automatic Private Internet Protocol Addressing (APIPA).

高中自学CCNA的时候听说过令牌环网这么个东西,不过一直没有见到过实际应用场景,就没有去深究,现在想想RFC 3927定义的这个link-local地址不正是一个令牌环网的原型么?如果一个子网内的机器都找不到DHCP服务器,那干脆自成一派,全部给自己分配成一个网段(也就是169.254开头的IP),在实际场景,比如学校的机房中,所有的计算机都是连接在一个L2交换机上,这样在一个被隔离的网段中的计算机通过计算发现对方IP与自身的子网掩码相同从而将自己的数据包交给交换机进行转发,达到内网互通的效果。

然后我就在考虑一个新的问题:既然机房的计算机全部是一键安装的,那初始化的169开头IP应该会是同一个而导致冲突才对啊?

仔细阅读了RFC之后才发现自己naïve了,原文如下:

When a host wishes to configure an IPv4 Link-Local address, it selects an address using a pseudo-random number generator with a uniform distribut on in the range from 169.254.1.0 to 169.254.254.255 inclusive.
If the host has access to persistent information that is different for each host, such as its IEEE 802 MAC address, then the pseudo-random number generator SHOULD be seeded using a value derived from this information.

这样看来有两重保证,首先这个/16的B类地址段可以保证有一个65536的池供选择,其次可以通过几乎全球唯一的标识符(比如MAC地址,UTC时间)来生成自己IP地址的后两位做到冲突的避免,除此之外,为了保险起见,每个地址生成之后还需要有一个check的操作,RFC原文如下:

A host probes to see if an address is already in use by broadcasting an ARP Request for the desired address. The client MUST fill in the ‘sender hardware address’ field of the ARP Request with the hardware address of the interface through which it is sending the packet. The ‘sender IP address’ field MUST be set to all zeroes, to avoid polluting ARP caches in other hosts on the same link in the case where the address turns out to be already in use by another host.

通过一个广播IP地址的ARP广播包来判断自己生成的IP是否被使用过,嗯,这个设计简直妙不可言~

总结 & 思考

  • 这件事情说明了什么?
    千万不要想当然地“理解”一个事物的本质,否则很容易自打脸
  • 为什么正常工作的机房网络会突然全部获取不到IP地址?
    可能是为了防止有人比赛的时候登录Drcom去网上查询吧,但是他们都有手机啊!!还有自己之前写过的代码

  • 是不是真的只有Windows才会有169.254这个IP呢?
    其实并不是,这个是RFC规范,所有的系统都会按照这个规范来操作,对于Linux而言,如果在这样的网络环境中,这个情况会以route的形式表现出来:

    Kernel IP routing table  
    Destination     Gateway         Genmask         Flags Metric Ref    Use Iface  
    ... (bunch of things) ...  
    169.254.0.0     0.0.0.0         255.255.0.0     U     1000   0        0 eth0
    192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0
    

参考资料

  1. Why 169.254.0.0 appears by default in the routing table?
  2. 169.254.0.0/16 addresses explained

我的博客使用了Disqus评论框,如果你看不到评论框,那么多半Disqus服务在你所在的地区被墙,请使用代理访问。