又一个Linux的双向stateless NAT
如果看一下iproute2的help,就会发现在route section中有一个nat action,其中via的参数给出了转换的地址。具体的配置就不说了,只提出两点,第一,iproute2的stateless nat需要policy routing的参与,第二,它在2.6内核中被去除了;具体信息可以参见文档。在2.6内核中,内核协议栈将一切的扩展都留给了Netfilter来实现,自己只实现标准的最小集。
如果按照上述的思路来实现nat route,根本不用policy routing,不需要配置ip rule,不需要配置两条规则,它的流程图如下,代码也比较好修改:
可以看出,这个实现使用了递归路由查询这个Linux根本就没有实现的东西。因此需要修改路由插入的部分代码,而我使用了几个flag来识别该条路由是做NAT用的,由于是stateless的双向NAT,因此当你插入一条NAT路由的时候,另外一个方向的就必须自动生成,比如你插入了一条以下的路由:
ip route add dnat x via y
指示所有的目标是x的都要转换成y,那么以下的路由必须自动生成:
ip route add snat y via x
指示所有源地址为y的都要转换为x。当然以下的这一条不应该手工配置,应该用auto标号指名它是自动生成的。
以上的需要说明是snat,原则上snat是在路由之后进行的,否则可能会做无用功,那流程图为何在路由前snat呢?这是为了最小化查询,否则也会做很多无用的查询,将要对所有的数据包都进行是否需要snat的查询,这里用到的一个技巧就是路由查询是基于最长前缀匹配的,如果有需要snat的,那么肯定会有一条明细的32位前缀的snat路由,如果没有,那就说明没有需要snat的。当然上面的流程图还可以优化,因为我们认识到,由于是双向的nat,那么只要有一个dnat,就会有一个snat,反过来也一样,都是成对出现的,基于这点是否能做点优化呢?