IPv6的NAT原理

在亿万互联网用户享受着Internet带来便利的同时,IPv4地址即将耗尽的问题却早在20年前就被网络专家们意识到了,并采取了措施延缓IPv4的消耗,这项措施就是NAT(网络地址转换)技术。NAT主要作用在于节约IP地址,而非所谓的增加IP的方向性以及隐藏私有IP,且IPv4的NAT打破了互联网本身的“互联”特性,使得一部分IP地址不再双向可达,NAT为无方向的IP协议增加了一个方向,特别是stateful的NAT类型。此时,IPv6时代已逐渐到来。
而IPv6的标准中不建议使用NAT,这是何缘由呢?我们已知IPv6地址数量巨大,只要在地球上,都可为蚂蚁配置IP设备,因此IPv4的一些修补手段将不再需要,为了保持协议本身以及相关标准的纯洁性,在IPv6中几乎不再建议使用NAT。虽然不再建议使用,但在某些必要情况下,还是可能需要实现IPv6的NAT。在RFC6296的标题是IPv6-to-IPv6 Network Prefix Translation中,描述了IPv6下的NAT的实现要点,给出了一个合理的建议,既保持了IP的无方向性,又可以满足NAT的语义,这就是IPv6之NAT stateless的缘由。
IPv6地址有将近128个可随意调配的位,其庞大的地址空间,一般的单位都会被分配到一个拥有很大量地址的网段,此网段拥有足够多的地址来和内网主机进行映射,即可用于映射的IP地址池容量巨大,且既然不想再使用非IP层的信息来保持信息,又要保持映射,那就要用纯IP层的信息,这样对上层影响最小。对于IPv6而言,NAT利用checksum算法来保持流标识信息,丝毫不管这个checksum是谁的checksum,因为它根本就不改变数据包的checksum…
接下来给大家讲解一下checksum无关性和自动转换,就是考虑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。
既然IPv6的NAT机制“自动”为一个连接选择了一个IP地址,那么当返回包到来的时候,如何把地址转换为原地址呢?IPv6的NAT把地址“转换回去”这件事完全靠算法本身,而算法本身就能将转换后的地址再转回原来的,具有解的唯一性,在IPv6的NAT实现中,算法只针对IP地址中16位的地址信息进行自动生成,而其它的则需要手工显式配置,由于内网IPv6地址可以使用MAC地址映射成唯一的地址,且转换后的地址是唯一的,将这一切反过来,最后还是能映射回原始的IP地址的。
如果抛开地址转换这一说,仅仅考虑算法本身,那还是可以给出一个实际可以运行的代码的,该代码使用了计算checksum的算法:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//以下2个函数就是计算校验码的,具体的原理请参RFC1071/RFC1624/RFC1141。
static inline u_int16_t add16(
u_int16_t a,
u_int16_t b)
{
a += b;
return a + (a < b);
}

static inline u_int16_t csum16(const u_int16_t *buf, int len)
{
u_int16_t csum = 0;
while(len–) csum = add16(csum, *buf++);
return csum;
}

int main(int argc, char **argv)
{

u_int16_t buf[18] = {0};
int i = 0;
memcpy(buf, "efghhijk", 8);
memcpy(buf+4, "12345678", 8);
memcpy(buf+8, "xxyywert", 8);
memcpy(buf+12, "zxcvkljh", 8);
//正确做法是打印16进制数据,此处为了简单,打印了字符串
printf("原始数据:%s  长度:%d\n", (char*)buf, strlen((char*)buf));    
printf("原始数据的校验码:%X\n", csum16(buf, 16));    

u_int16_t tip[3] = {0};
memcpy(tip, "#$!%", 4);
u_int16_t tip_sum = csum16(tip, 2);
printf("\nNAT规则: efghhijk1234/12 -〉efghhijk#$!%/12\n\n");
printf("固定从第9个字节开始修改4个字节为:%s 其校验码为:%X\n", (char*)tip, tip_sum);

//定位固定修改后的动态修改的初始地址,注意,我们仅仅修改16位信息
u_int16_t* pcsum = buf + 4+2;  

//计算动态修改的值
*pcsum = ~add16(
    add16(
        ~(*pcsum),
        ~csum16(buf+4, 2)
    ),
    tip_sum
);
printf("动态修改的值为:%X\n", *pcsum);
memcpy(buf+4, tip, 4); //完成修改

printf("当前数据:%s  长度:%d\n", buf, strlen((char*)buf));    
printf("当前校验码:%X\n", csum16(buf, 16));    
printf("-------------以下是还原操作-------------\n");
printf("\n反向NAT规则: efghhijk#$!%/12 -〉efghhijk1234/12\n\n");

u_int16_t tip2[3] = {0};
    memcpy(tip2, "1234", 4);
printf("我们只需要记住原始数据被固定修改前的:%s\n", tip2);

u_int16_t tip_sum2 = csum16(tip2, 2);

u_int16_t* pcsum2 = buf+6;

*pcsum2 = ~add16(
    add16(
        ~(*pcsum2),
        ~csum16(buf+4, 2)
    ),
    tip_sum2
);
//还原
memcpy(buf+4, tip2, 4);

printf("原始数据:%s\n", (char *)buf);
printf("原始校验码:%X\n", csum16(buf, 16));    

}

运行结果如下:
在这里插入图片描述
把以上的原理套用在IPv6的NAT上,就是一种实现。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值