闲谈IPv6-从ICMP的视角形而上地分析IPv6

又是周六的大清早。意义在时间中流逝,剩下的只有沉淀的污秽,但是也没有办法,这就是生命终将消逝的本质原因。只有感叹,然后做点什么。


ICMP可谓是IP协议的首席助力协议,是IP协议的带内信令协议,如果我们把IP协议按照数据,控制,管理三个平面划分的话,那么IP协议本身自然属于数据面,而ICMP和IGP/BGP则分别属于控制面和管理面。

可是,ICMP在IPv4版本中并没有发挥其应该发挥的作用(ICMPv4中的很多功能被阉割,甚至废除!)。这也许是因为当时的网络协议各方面技术都不完善。

互联网伊始一切靠摸索当然会走很多的弯路,然而现在,大家都只想着短平快解决问题,30年后回望现在,也并不是什么都是对的,后人哀之而不鉴之,亦使后人而复哀后人也,呜呼!

然而我认为,之所以ICMP在IPv4中大部分功能夭折,那安全是因为IPv4固有的缺陷所导致,并不是ICMP协议本身的锅!你看,ICMPv6不是已经大张旗鼓了么。让我们拭目以待!


IPv4的地址空间是平坦的,本身没有严格的scope的概念,一切都是靠路由:

  • 数据发送,源地址选择靠路由
  • 数据传输,逐跳转发靠路由
  • 数据最后一跳,ARP解析靠路由
  • 数据到达,本地投递靠路由

也就是说,只要你掌握了一些技巧,一些trick,哪怕再崎岖的路径,也能够配通了,让IPv4报文从这一端到达那一端。

从安全的角度来看,这种灵活性并不能带来便利,反而会带来风险和一系列的问题。


我在《闲谈IPv6》系列文章中提到过很多IPv6的很好玩的技术,比如无状态自动配置,Anycast,源地址选择等等,如果我们从IPv6回望到IPv4,问自己, 这些特性可以在IPv4协议上实现吗?

答案是, 完全可以!

只是地址空间缩小了而已,如果1980年代前后在设计IP协议的时候,人们按照IPv6的思维来设计IPv4,想象一下是不是很酷!

  • 强制按照可聚合规则规划地址分配;
  • 15.0.0.0/9是本地链路地址,不能跨三层;
  • 采用224.0.0.X/24本地组播来进行地址解析(IANA早就拥有00-00-5e这个OUI了);
  • 使用ICMPv4进行路由器发现和自动配置;

如果真的这样实现IPv4的话,到了互联网大爆发的纪元,IPv4面临的问题就真的仅仅是地址不够用这么简单了,到时候升级到IPv6简单地把地址空间一放大,保持前向兼容,就平滑过度了,但是事实上,IPv4当初并没有如我们事后所愿那般被设计出来,上述列举的特性一个也没有实现…

不过想想也是,如果IPv4真的当初是按照我们现在的IPv6的思想设计的,只是地址空间小到32位的话,到了互联网爆发的纪元,遇到的问题肯定也不再仅仅是地址不够用这么简单,肯定还会有更多别的问题,在那条假象的时间线上,IPv4的发展轨迹我们可以猜测一下:

  • 强依赖自动配置,DHCP或许不会被设计出来,至少弱化很多;
  • ARP不会出现,不会有广播,这反过来会影响交换机的设计以及STP协议的设计;
  • 聚合路由表项非常少,路由器复杂度会降低很多;
  • 路由通告非常简单,BGP/IGP会简单很多;
  • 聚合地址分配,天生无环,所有路由协议复杂性降低;
  • 思科,华为这种设备公司在设备上的投入会降低;
  • 底层网络解放出来的人可能会涌入到应用层,互联网更猛烈地爆发

我们想象一下,当前有多少越来越复杂的网络技术是为了弥补IPv4的设计缺陷的,不胜枚举,太多了,然而却正是这些复杂的技术支撑了整个产业!

另一方面,如果真的如上所诉,在那条另外的时间线上,IPv4的简单导致底层技术的简单,人力资源涌入上层,互联网更猛烈的爆发后,一切被IPv4的精简设计掩盖的问题将还是会暴露出来,因此这些问题还是要被解决,这就是那条时间线上IPv6的任务!

因此,那条时间线上的IPv6自然也不会是我们现在的IPv6这个样子咯,它会把我们的现实时间线的IPv4的发展轨迹重新走过。

这就是历史,历史不容假设!因为你避开的东西早晚会在后面让你再遇到,所谓的不同时间维度,只是遇见的先后顺序变了变而已。这就是我的历史观。

互联网本身就是进化出来的而不是设计出来的,这就是自然的东西,历史即自然!

看看我们自己的身体,或粗糙或细腻的皮肤后面,总是藏着那些绕成一团团乱麻的血管,肠道以及里面包裹着的代谢物,如果捅破这层我们自己看起来还过得去的表皮,里面真实的汁液或会流出,红色,绿色,黄色,人也就容易一命呜呼,我们看起来还华丽的外表竟然由这些看起来很污的汁液支撑,我们并没有那种 其构成本应该如此坚固和简单 的躯体,相反,我们的躯体非常脆弱和复杂,且携带非常多的看起来是缺陷的东西,但这就是进化,这就是历史,杂乱即美。

举一个和互联网IP协议升级相对的例子,那就是通信领域的固定电话号码升位,我靠,完全兼容啊!一夜间之后醒来,你只要在原7位电话号码前面简单加拨一个6或者8,就能打通!电话就是一个 功能纯粹的被设计出来的 的东西,它是被设计的,因为没有促进它进化的动力,没有丰富的应用,没有太多人们可以折腾的内容…


让我们回到ICMP协议继续扯。

其实,在早期,RARP和ICMP路由器发现以及ICMP路由器通告一起合力,便可以实现IPv4的 无状态自动配置 ,详情参见:
ICMP Router Discovery Protocol: https://en.wikipedia.org/wiki/ICMP_Router_Discovery_Protocol
此外,ICMPv4还具有超级多的其它功能,比如前缀查询,翻阅早期的RFC,我们发现看起来是IPv6特有的特性,其实在IPv4早期早就可以被支持,但是最终这些都被废弃了:
CAPEC-294: ICMP Address Mask Request: https://capec.mitre.org/data/definitions/294.html
Formally Deprecating Some ICMPv4 Message Types: https://tools.ietf.org/html/rfc6918

这些强大方便的功能特性,在IPv4看来是不合时宜的,或许看来太超前了,IPv4并没有构建出足以支撑这些特性的底层基础设施。最终,DHCP被设计出来,取代了ICMP,ARP成了地址解析的标准。

如今,我们能在Linux内核中看到一份列表,看看哪些ICMP是被废弃的:

/*
 *	This table is the definition of how we handle ICMP.
 */
static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = {
	[ICMP_ECHOREPLY] = {
		.handler = ping_rcv,
	},
	[1] = { 
		.handler = icmp_discard,
		.error = 1,
	},
	[2] = {
		.handler = icmp_discard,
		.error = 1,
	},
	[ICMP_DEST_UNREACH] = {
		.handler = icmp_unreach,
		.error = 1,
	},
	[ICMP_SOURCE_QUENCH] = {
		.handler = icmp_unreach,
		.error = 1,
	},
	[ICMP_REDIRECT] = {
		.handler = icmp_redirect,
		.error = 1,
	},
	[6] = { // Alternate Host Address
		.handler = icmp_discard,
		.error = 1,
	},
	[7] = { 
		.handler = icmp_discard,
		.error = 1,
	},
	[ICMP_ECHO] = {
		.handler = icmp_echo,
	},
	[9] = { // Router Advertisement
		.handler = icmp_discard,
		.error = 1,
	},
	[10] = { // Router discovery/selection/solicitation
		.handler = icmp_discard,
		.error = 1,
	},
	[ICMP_TIME_EXCEEDED] = {
		.handler = icmp_unreach,
		.error = 1,
	},
	[ICMP_PARAMETERPROB] = {
		.handler = icmp_unreach,
		.error = 1,
	},
	[ICMP_TIMESTAMP] = {
		.handler = icmp_timestamp,
	},
	[ICMP_TIMESTAMPREPLY] = {
		.handler = icmp_discard,
	},
	[ICMP_INFO_REQUEST] = { // Information Request
		.handler = icmp_discard,
	},
	[ICMP_INFO_REPLY] = { // Information Reply
		.handler = icmp_discard,
	},
	[ICMP_ADDRESS] = { // Address Mask Request
		.handler = icmp_discard,
	},
	[ICMP_ADDRESSREPLY] = { // Address Mask Reply
		.handler = icmp_discard,
	},
};

一大半都被废弃了!原因肯定有,安全原因或者必要性原因都存在。

以自动地址配置为例,DHCP目前竟然成了显然的协议,不断有人问为什么IPv6不用DHCP协议而非要用其自带的无状态自动配置,也许人们早就已经习惯了DHCP协议,但其实,DHCP才是晚到的。(PS:IPv6也是有DHCP的,也经常被使用,只是在大多数简单的情况,自动配置更简便高效)


说说邻居解析吧。

IPv4的ARP在设计上是独立于IP协议的,你看ARP报文就不是用IP来封包的,这么做考虑以下两点:

  1. IPv4网段规模和以太网规模使得使用广播比使用组播更加简单便捷;
  2. IPv4地址没有强制scope,一切靠路由,为了本地链路解析,使用非IP封包可以阻止ARP广播跨越IP路由器。

但是IPv6的邻居地址解析却与此不同,IPv6采用ICMPv6报文封装解析请求,使用 本地组播 作为目标。这意味着:

  1. IPv6的地址解析报文是一个普通的IPv6封装的报文,就是一个IP包;
  2. IPv6的本地组播本身就无法跨越路由器。

使能IPv6的网卡是无条件接收组播报文的,而且每一个配置的IPv6地址都会加入一个组播组,这意味着所有接收到的组播都会被 本地处理。

由于邻居解析报文就是一个普通的IPv6报文,所以说它对IPv6协议头和ICMPv6协议体里的被解析对象IP地址没有任何强制的关联要求:
在这里插入图片描述
以下是回复报文:
在这里插入图片描述

IPv6收到邻居请求报文时(可以是组播,也可以是单播,都可以被接收),就像收到一个普通的IP报文那般处理,它检查接收网卡上配置的IP地址,只要这块网卡上配置被请求的IP地址,那么就会回复其MAC地址,这里和IPv4的ARP处理有大不同。

IPv4的邻居概念上就和IPv6有大不同:

  • IPv4的邻居是主机,是设备
  • IPv6的邻居只是网卡

以上的大不同造成了实现复杂度上的大不同。

IPv4内网的主机可能会请求同网段路由器的外网地址的MAC,按照规范,路由器也应当回复,因此,在收到IPv4的ARP请求报文后,只要被请求的IP地址是本机的地址,就有可能会回复,实现这个的方法只有查找路由,以Linux为例,即查找Local表的路由,Local表的路由目的地都是本地地址。

在路由查询过程中,有可能还会有rp_filter的校验,这需要你必须有一条到达源IP的路由,在路由查询后,还要有arp_ignore,arp_filter配置的校验,这里能实现超级多的trick…你把IP地址从Local表里删掉,看看还能被解析吗?

IPv6就没有这么麻烦,它的处理逻辑超乎寻常地简单:

  1. 接收到邻居请求报文;
  2. 查看接收网卡上配置的IP地址是否有被解析的地址;
  3. 如果有,则回复MAC,如果没有,什么都不做。

再看路由器发现的ICMPv6报文。

在IPv4年代,一个远程设备可能会发出一个ICMP Address Request报文去嗅探远程路由器的地址前缀信息,如果你没有规范强大的ACL来防范,这将是一个严重的安全隐患。

换句话说,IPv4的Address Request要靠外部的额外ACL来框定其有效范围,这对网络管理员是一个挑战。

在IPv6时代,这一切自然而然由地址scope来解决。

既然路由器解析报文只是一个普通的IP报文,我们不能规定数据报文的发送者必须做,即便规定了他们也不一定会遵守,特别是那些持有恶意的人,那么IPv6的路由器发现规定(RFC4861),路由器发现报文的回应报文,即路由器通告报文的源IP必须是link-local地址:
在这里插入图片描述

我不能控制请求,但我可以控制回应!这个link local scope限制了该报文的范围,它是不能跨越路由器的。IPv4的问题在IPv6中用这种标准化的方式得到了解决。


IPv6很多特性之所以让事情变得简单便捷,其根源在于IPv6地址本身。我总结三点:

  1. IPv6地址在分配前,规定了地址scope,人们可以用这些scope来做很多的约束;
  2. IPv6地址在分配时,规定了地址聚合分配,从而实现了路由的简单;
  3. IPv6地址分配只管到子网,不管主机。
    这个需要解释一下。如果你看到类似2402:ff:1000:0010/56这样的表示,不要惊讶。你只要把/64作为地址分配的终点就好了,在IPv4中,我们不是经常见到192.168.188.123/24的表示吗?

还有别的吗?


最后,来个答疑。

问题:如果IPv6报文添加了 路由头 ,那么在某个中间路由器上,该报文将经过哪些Netfilter HOOK点呢?

答:IPv6的路由头将 逐跳转发 变成了 接力转发 ,每一个经过的路由头列表里的中间路由器都将作为目标地址,因此数据报文经过的HOOK为:
PREROUTING–>INPUT–>FORWARD–>POSTROUTING


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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值