Linux如何做到将外来数据包DNAT到Loopback


前面写了篇文章《使用iptables为何不能将外部进入的包NAT到127.0.0.1》,牵扯到了很多知识,最终的结论就是不能那么做。这个结论让人有些不舒服,说了半天就是阐述它为何做不到,如果我非要将包NAT到loopback呢。比如为了不将端口以及地址暴露给外部,我就是想让代理服务侦听127.0.0.1这个地址,有没有什么办法做到呢?

因为你用的是Linux,答案无疑是肯定的,所要做的无非就是把路由时候的限制条件给去掉。我们知道,在进和出两个方向,有两个路由查找逻辑,一个是

  1. ip_route_input_slow,另一个是ip_route_output_slow,其中前一个函数的限制在:  
  2. if (ipv4_is_lbcast(daddr) || ipv4_is_zeronet(daddr) ||  
  3.         ipv4_is_loopback(daddr))  
  4.     goto martian_destination;  

而后一个函数限制在其调用的__mkroute_output中:

  1. if (ipv4_is_loopback(fl->fl4_src) && !(dev_out->flags&IFF_LOOPBACK))  
  2.     return -EINVAL;  

我们到底应该怎么绕过去呢?如今我们知道,NAT逻辑已经将目标地址改成了127.0.0.1,而源地址保持不变,这种数据包在进入的时候会被ip_route_input_slow拦截并且由于源地址非loopback而目标为loopback而丢弃,丢弃的时候注意还没有查找路由呢?现在我们假设这个包已经过去了,那么返回包能不能顺利通过ip_route_output_slow呢?答案无疑也是否定的,由于标准路由是基于目标地址的,对于返回包的目标地址其实就是正向包的源地址,路由查找无疑是可以通过的,但是路由前由于还不知道目标设备,因此不能简单地丢弃,只有到了路由之后确定目标设备非loopback之后才能丢弃。
        以上就是Linux协议栈路由模块对待“火星地址”的逻辑。总结一下就是:
1.对于进入包,若是loopback发来的包则不通过路由查找逻辑,凡是通过路由查找的,都是外来包,路由前知道源地址和目标地址,可以根据目标地址是否loopback而判断是否丢弃;
2.对于发出包,无条件(考虑下路由cache,意义是一样的)都要经过路由查找,路由前不一定知道源地址,即使知道源地址也不能确定目标设备是否是loopback设备,只有通过路由查找(local表命中的目标设备为loopback设备)才可以知道全部信息,因此在路由后,生成路由cache之前判断源地址是loopback地址而却是发往非loopback设备而决定丢弃之。

  • 1
  • 2
  • 3
  • 下一页

相关内容