皮鞋湿,不会胖。下班本想找个地方思考,然而没有找到,直接回家吧,闭关,思考,自省,买皮鞋。

昨天写了一篇关于Loopback接口上配置IPv6地址的文章:
闲谈IPv6-Loopback网口上的IPv6地址:
https://blog.csdn.net/dog250/article/details/89333045
<https://blog.csdn.net/dog250/article/details/89333045>
随后有人咨询了一个比较有意思的问题:

我在lo上添加了10.0.1.1/24这个地址,为什么10.0.1.0/24整个段都可以在本机ping通呢?而且在本机telnet这个段任何地址的侦听0.0.0.0的端口也是通的,为什么?

答案似乎不难解释。 因为添加IPv4地址到lo口时,链路层路由就自动在Local表生成啊!

本文接着上面那篇继续写点儿细节。

比如,当我添加地址到lo口时:
[root@localhost ~]# ip addr add dev lo 10.0.1.1/24
按照IP路由规范,一条 链路层路由
将会自动生成,该路由项以添加地址前缀10.0.1.0/24为健值。由于地址是添加在lo口,而lo口的路由在IPv4关联了Local表,所以这条链路层路由被添加在了Local表中:
[root@localhost ~]# ip route show 10.0.1.0/24 dev lo tab local local
10.0.1.0/24 proto kernel scope host src 10.0.1.1
现在我们知道,当我们在lo口添加一个非32位长度掩码的地址时:

* 该前缀的链路层网段路由会被添加在Local表中。
看另一方面,当数据包进入IP路由逻辑时,会用目标地址为健值按照下面的顺序查询路由表(基于Linux实现):
[root@localhost ~]# cat /etc/iproute2/rt_tables 255 local 254 main 253 default
0 unspec
我们看得出来,Local表是最优先被查询的(注意:后面4.X高版本的内核,Local表只是默认最高优先级,即便是Local的优先级也是可以调到非最高优先级的!
):

* 只要在Local表命中路由的,数据包都会被导入到本机第四层去处理。

由此可见,如果在本机去ping或者telnet一个lo口上配置的地址段的其中一个地址,那么由于会命中Local表中链路层路由,所以数据自然而然会导入到本地四层。

在协议栈的实现中,导入到本地四层的数据包是 直接被处理的,不会再去check数据包的目标地址是不是真的被配置在本机的某个接口上!

所以说,按照上文中的10.0.1.1/24的配置,下面的telnet是成功的:
[root@localhost ~]# netstat -lntp tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1036/sshd
... [root@localhost ~]# telnet 10.0.1.123 Trying 10.0.1.123... telnet: connect
to address 10.0.1.123: Connection refused[root@localhost ~]# telnet 10.0.1.123
22 Trying 10.0.1.123... Connected to 10.0.1.123. Escape character is '^]'.
SSH-2.0-OpenSSH_7.4 ^]q telnet> q Connection closed.
然而,在我个人看来,这样实现是不对的!至少是不直观的。我还是觉得IPv6的做法更加合理!

IPv6的协议栈标准和实现中,当你添加一个前缀地址到lo口时:
- 该前缀的链路层网段路由会被添加在Local表中

* 该前缀的链路层网段路由不会被添加在Local表中而是添加在Main表中 且
* 添加到Main表中的链路层路由是unreachable的!
这样, 如果不是明确配置在lo口上的地址,就不会通! 比如配置下面的IPv6地址:
[root@localhost ~]# ip -6 addr add dev lo 2222:2222::1234/64
下面的路由会生成:
[root@localhost ~]# ip -6 route show tab main ... unreachable 2222:2222::/64
dev lo proto kernel metric 256 error -101...
下面的telnet是不会成功的:
[root@localhost ~]# telnet 2222:2222::1111 22 Trying 2222:2222::1111...
telnet: connect to address 2222:2222::1111: No route to host
整个 2222:2222::/64 段,只有你配置的那个地址 2222:2222::1234 会通:
[root@localhost ~]# telnet 2222:2222::1234 22 Trying 2222:2222::1234...
Connected to 2222:2222::1234. Escape character is'^]'. SSH-2.0-OpenSSH_7.4
但是,我在昨天的文章里也说了,这个只是一个默认的配置,并不是不可改变的。我们完全可以把unreachable路由从main表删除,然后把链路层路由 依然
添加到local表中,实现和IPv4一样的效果!以表示怀念或者说维持一种惰性!

IPv6取消了IPv4很多Trick般的玩法,变得规范自然了很多,比如IPv6就没有下面的参数:
net.ipv4.conf.all.route_localnet net.ipv4.conf.all.accept_local
net.ipv4.conf.all.arp_ignore net.ipv4.conf.all.arp_filter
net.ipv4.conf.all.rp_filter...
这些参数可以玩出很多中看不中用的炫技般的Trick,但是几乎没有什么实用性,实际的运维部署中,如果使用这些非规范的Trick,经理会哭的。


之所以IPv4会催生一系列的Trick而IPv6没有,除了IPv6目前使用并不广泛这种理由之外,我感觉还有很重要的一点,那就是IPv4年代很多东西真的就是模糊的,比如RFC826的ARP,IPv4横跨的时间轴太长了,30多年时间,很多技术进化的非常快,早就不是它们一开始被定义的时候的样子了。所以,当初未能考虑到的一些细节,到了最后就是
未定义 的,于是就可以随意去根据上下文来规范解释权了。于是也就有了很多把玩的空间…

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信