皮鞋进水发胖之后怎样才会恢复原样?拥有八块腹肌的中国浙江温州小型皮鞋厂老板也没有办法。

今天花了太多时间聊一些形而上意义上的东西,所以本文形而下。

今天时间不多,直奔主题。

我准备两台虚拟机,设为主机A,主机B,分别用其eth0接口直连,配置如下:
# 主机A-eth0 直连 主机B-eth0 # 主机A eth0:1111:1111::101/64 # 主机B lo:1111:1111::110/64
eth0:1111:1111::123/64
如果如上述这般配置,那么协议栈显然会生成下面的相关路由(确实也是的):
# 主机A 1111:1111::/64 dev eth0 proto kernel metric 256 # 主机B
(两种情况,1111:1111::/64 的链路层路由和unreachable路由的先后顺序取决于eth0口和lo口上地址的添加顺序!)
1111:1111::/64 dev eth0 proto kernel metric 256 unreachable 1111:1111::/64 dev
lo proto kernel metric 256 error -101# 或者 unreachable 1111:1111::/64 dev lo
proto kernel metric 256 error -101 1111:1111::/64 dev eth0 proto kernel metric
256

现在,从主机A来ping主机B的lo口地址1111:1111::110,无论主机B的eth0口和lo口的地址添加顺序如何导致无论哪种路由表项顺序,都是可以ping通的。然而从主机B主动ping主机A的eth0地址1111:1111::101,两种路由表项顺序结果是不同的:

* unreachable路由在链路层路由前面,则ping不通。
* 链路层路由在unreachable路由前面,则能ping通。
有点儿意思。

这是为什么?

难道IP协议不是 无方向无连接无状态的 吗?答案当然是肯定的!那么为什么会出现上面不对称的结果?

仔细观察上述的两条路由:
unreachable 1111:1111::/64 dev lo proto kernel metric 256 error -101 # 和
1111:1111::/64 dev eth0 proto kernel metric 256
它们之间的不同点太多,但是仅有 metric 是标准IP路由认识的,遗憾的是,二者的metric相同,这让我们想不通的是:

* 在主机A ping主机B时,主机B收到主机A的ICMPv6 Echo
Request的时候,Linux内核协议栈到底check了哪些字段致使无论哪种路由排列都能ping通呢?
* 在主机B主动ping主机A时,两条路由中又是哪些字段让数据包优先匹配第一条匹配到的路由呢?
长篇大论无益,以后再说,这里直接说结论,关键的字段就是 dev ,即 路由项的出口网卡 字段。

以下简单解释。

首先几条路由可以等价为:
1111:1111::110/128 dev lo IN local 1111:1111::/64 dev lo unreachable
1111:1111::/64 dev eth0 onlink
当从主机A去ping主机B的时候,Echo Request数据包从主机B的eth0进入,显然目标地址会在Local路由表命中,然后主机B协议栈会回复Echo
Reply。

此时Reply的目标地址是 1111:1111::101 ,查询路由表。

如果按照目标地址为健值查询的话,即便从metric看,两条路由均将命中,那么到底选择哪一条呢?

这里,TCP/IP协议栈的实现者按照check source的原则,定制了默认规矩,即 数据包从哪个网卡进入,它的回包将会从哪个网卡出去!

于是乎,从过主机B接收到主机A的主动请求,无论是ping的Echo Request还是TCP的Syn,它们均将从eth0被收入,那么回复Echo
Response或者TCP的Syn/ack时,它们就理应从主机B的eth0出去,于是乎,在回包查询路由表时,自然而然就会加上“出口网卡是eth0”
这么一个约束!

这样答案不就明确了吗?如果是从主机A主动去ping主机B,那么回包的路由肯定会匹配到主机B关于 1111:1111::/64 的 dev eth0 链路层路由
,而不会匹配到unreachable路由,这也就解释了为什么A ping B总是通的。

那么从主机B主动去ping或者telnet 主机A呢?


很显然,此时在查询路由表之前,并不知道要从那块网卡出去,这个时候,关于1111:1111::/64的链路层路由和unreachable路由是完全等价的,当然是谁排在前面那就选谁咯!


更加细节且有趣的是,IPv6在Linux内核协议栈中的组织采用了Trie树数据结构,它不像链表那般稳定,因此两条路由的顺序,还真的不一定。这还只是Linux的实现,还没说BSD和Windows呢…

看下代码,便可安睡?嗯,对于我等码农而言,是的!不说ICMP,就说说更加激烈的TCP吧。


在一个TCP服务端收到TCP客户端主动的SYN报文的时候,会回复SYN/ACK报文,在这个SYN/ACK报文的回复前,需要查找路由,在初始化路由查找键的时候,就会把出口网卡给引入,它的值,便是SYN报文的入口网卡:


关于ICMPv6报文,请自行解析!

浙江温州皮鞋湿;
下雨进水不会胖。

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