IPv6的标准中不建议使用NAT,个中缘由何在?这是一个问题,正如我很早之前解释的那样,IPv4的NAT打破了互联网本身的“互联”特性,使得一部分IP地址不再双向可达,NAT为无方向的IP协议增加了一个方向,特别是stateful的NAT类型。然而IPv4的NAT旨在节约IP地址,而非所谓的增加IP的方向性以及隐藏私有IP,这些只是一种难以摆脱的副作用罢了。
IPv6的时代已经到来,只要不扩展到外太空,地球上的蚂蚁都可以使用IP设备了。IPv4的一些修补手段将不再需要,为了保持协议本身以及相关标准的纯洁性,IPv6几乎不再提起NAT。虽然不再提起,并不是说“你已不是你”,实现IPv6的NAT还是可能的,并且在某些情形下还是必要的。
RFC6296的标题是
IPv6-to-IPv6 Network Prefix Translation,描述了IPv6下的NAT的实现要点,给出了一个合理的建议,既保持了IP的无方向性,又可以满足NAT的语义,这就是IPv6之NAT stateless的缘由,你不能再指望像IPv4的NAT那样只需要配置一条rule,然后反方向的rule动态生成,IPv6情况下,两个方向的rule都需要你自己手工来配置。
IP地址可以划分为几个段,包括网络前缀,子网标识,主机标识,这在IPv4和IPv6中没有什么不同。IPv4的NAT为了节约IP地址,也就是说,可供映射的IP地址pool中的地址小于或者远远小于其内部主机的数量,因此很有可能多个内部主机被映射成了同一个外部IP地址,这如何来区分它们,因此不得不引入诸如第四层协议,端口等信息了,也就是我们熟知的五元组信息,因此IPv4的NAT实现大多数都是基于五元组流的,这样就保证了内核保持的NAT信息项的唯一性,同时也引入了很多副作用。
IPv6地址持有将近128位可随意调配的位,鉴于地址空间的庞大,一般的单位都会被分配到一个拥有很大量地址的网段,此网段拥有足够多的地址来和内网主机进行一一映射,也就是说可用于映射的IP地址pool容量巨大无比,关键是这个一一映射如何来保持,既然不想再使用非IP层的信息来保持信息,那就要用纯IP层的信息了,这样对上层影响最小。对于IPv4,经典NAT使用了五元组来保持流标识信息,而对于IPv6,则更加绝妙,它利用(而不是使用)了checksum的算法,丝毫不管这个checksum是谁的checksum,因为它根本就不改变数据包的checksum...
IP标识一台主机,而MAC标识一个网络接口,它们其实是一对多的关系,然而现实中,一个IP往往会和一块网卡相关联,其中一个缘由就是可以自动生成链路层的路由信息。这是很方便的,然而对于IPv4,地址是自己配置或者通过DHCP来分配的,管理过程十分复杂,一不小心就会有地址冲突,不得不依靠ARP广播/RARP等技术来检测,之所以出现这种状况,一则因为分层理念太教条,谁说IP和链路层就不能有关联,谁说IP标示主机就不能关联网卡;二则因为IPv4地址空间太小,而MAC地址长度一般都会超过IP地址,虽然满足了RFC标准上的一对多的关系,但是使用起来很不方便。
IPv6解决了这个问题,使得地址冲突问题减缓以致几乎消失。我们知道,MAC地址标示了一块物理设备,是看得见摸得着的,有时你摸一下还会碰到静电,MAC地址和你的身份证号码一样不会重复,IPv6将MAC地址映射到IPv6地址解决了IP地址冲突的大问题,同时这对于NAT也是有益的,这会影响到地址的自动转换,每一个不会重复的内部地址转换为一个不会重复的外部地址,这一切都要归功于IPv6的地址空间的巨大,可以随意杂耍。
这个很好解释,小学毕业就应该能理解。考虑
a+b+c+d=X
其中X就是checksum,我们把a,b当成源IP地址的两部分,c,d当成目的IP地址的两部分,我们作源地址转换,将a和b都改变,比如a改变成了A,试问将b改成多少才能保持checksum的值X不变,这其实很简单,就是一个简单的一元一次方程求解的问题。IPv6的建议NAT实现也是这个原理,只不过上面的一元一次方程是实数域的,而这个是计算机布尔数域。既然可以不触动第四层的checksum值,那么NAT对第四层协议的影响也就减小了,虽然它还是解决不了诸如ESP/AH等穿越NAT的问题。
基于以上算法,IPv6在做NAT的时候,在给定的子网网段内,可以自动生成一个新的IP地址供映射之用,从算法本身来看,冲突的可能性非常之小致于0,上述的做法对于IPv4几乎是不可能的,因为IPv4地址空间太小了,每个单位保有的地址池容量也有限,你不能指望一个算法为你生成一个IP地址,因为这种生成的地址要不根本就不属于自己,地址冲突,要么就是重复,和其它的映射冲突。
既然IPv6的NAT机制“自动”为一个连接选择了一个IP地址,那么当返回包到来的时候,如何来把地址转换回原来的呢?我们知道,IPv6的NAT已经不再使用五元组来维护NAT映射信息,也不在内核维护这种信息,那么“转换回去”这件事就要完全靠算法本身了,恰恰就是算法本身能将转换后的地址再转回原来的,其依据就是本小节最开始处给出的一元一次方程解的唯一性,在IPv6的NAT实现中,算法只针对IP地址中16位的地址信息进行自动生成,而其它的则需要手工显式配置,由于内网IPv6地址可以使用MAC地址映射成唯一的地址,由于一元一次方程解的唯一性,那么转换后的地址也是唯一的,将这一切反过来,最后还是能映射回原始的IP地址的。
如果抛开地址转换这一说,仅仅考虑算法本身,那还是可以给出一个实际可以运行的代码的,该代码使用了计算checksum的算法: