细说IP映射的那些事

作者:金龙

1 概述

之前有一篇文章专门说了下NAT之后的源IP识别问题,详情查看链接: 《代理、转发等多种场景下,如何获取用户真实IP?》 ,这次针对NAT细节进行一些补充。

如果IPA想来黑IPB,那IPB可以用iptables把流量全部转到IPC,也就是如果IPA打攻击流量给IPB,那IPB可以把流量转移走甚至是直接再转给IPA,把IPC改为IPA即可。

2 NAT概念

我们平常工作中说的nat,一般就是两个概念:

1、 办公网需要通过nat进行ip转换,转为公网ip才可以上网

2、 端口转发,比如以前的游戏BGP端口转发来增加端口连通性

更细一点说是

1、 数据包用一个私网IP通过NAT设备变为一个公网IP出公网,数据包回来经过NAT设备的时候会再改为原先的私网IP完成一个生命周期。

2、 用户A访问NAT设备的BIP的B端口,NAT设备会转发到CIP的C端口,数据包回来时候再根据之前的NAT表信息返回到用户A完成一个生命周期。

对网络不熟悉的人也得记住,很多场景可能用到,或者是一些解决方案会用到基于这些原理的扩展版。

3 NAT设备

除了那些网络设备,我们的Linux服务器对NAT的支持也非常好,比如直接用iptables就可以实现了(net.ipv4.ip_forward = 1开启数据转发),非常经典和实用的方法,而且比路由器更灵活。

有多灵活呢,经常用网络设备的同学应该知道,很多网络设备是在Linux基础上加了几层壳来实现的,最起码是3个壳,一个是把内核隐藏起来,用自己的命令方式来调用,然后加个web界面,最重要的就是换了个外观硬壳,一般都是好几个性能强悍的网卡和含有自己LOGO的铝合金壳。

但是能被调用的就已经限制死了,比如在复杂的网络架构里面想用有ACL的NAT来做一些映射,加上调试方式(tcpdump抓包),远没有在Linux上面方便,不过如果产品加的壳足够好的话,比如国内一些上网行为管理系统,在常规的场景用起来还是非常顺手的。

当然不常规的场景也是多着,比如需要屏蔽掉某个关键词W1,或者需要对C1这个IP的基础上屏蔽关键词W1,甚至是对IP段1走韩国出口,对IP段2走香港出口。这里说的关键词不只是普通的http字符串,可能是某些产品自带的特征码,比如的MicroMessenger和号之类的屏蔽等,这些还是直接用iptables自己做更灵活靠谱。

4 细节4.1 简单NAT

最简单的NAT场景细节:

当内网用户10.10.10.2通过网关NAT之后变为45.45.45.45这个IP去访问15.182.52.1这个IP。

可以看到数据包在NAT设备进入和出去时候的区别:

  

可以看到首先会进行SNAT操作,也就是linux里面的POSTROUTING操作,把自己的内网IP改为45.45.45.45这个公网IP,然后出去,公网上的源IP和目的IP都是公网IP。

到了公网服务器回来再经过NAT设备时候就是这样子: 

NAT设备记录好了之前这个会话,然后进行DNAT操作,也就是linux的PREROUTING操作,把目的IP变回之前的10.10.10.2然后到内网。这样先SNAT修改源地址,再DNAT修改目的地址就完成了一次完整的私网IP经过NAT访问公网IP的情况。

如果是公网服务器主动来访问45.45.45.45这个IP,情形就反过来了,第一次到达NAT设备的时候,先DNAT,修改目的地址为内网IP,然后再SNAT,改回之前的公网IP,再回到服务器完成一次公网IP访问私网IP的情况。

上述是最简单的NAT情况。

用cisco路由器来做的话,需要在接口上指定nat属性,然后加静态映射:

ip nat inside source static 10.10.10.2 45.45.45.45

如果是华为路由器做的话,需要加在nat instance里面定义,然后把nat策略nat bind绑定在接口上:

nat server global 45.45.45.45 inside 10.10.10.2

如果是防火墙的话,一般都会复杂点,需要配置好trust和untrust区域,比如华为防火墙做:

nat server s3 zone untrust global 45.45.45.45 inside 10.10.10.2 unr-routenat server s3_lan zone trust global 45.45.45.45 inside 10.10.10.2 unr-route

Juniper做的话,命令多点,在security policies允许之后加nat:

set security nat static rule-set test_ip from zone untrustset security nat static rule-set test_ip rule test_ip match destination-address 45.45.45.45set security nat static rule-set test_ip rule test_ip then static-nat prefix 10.10.10.2

听的最多的NAT设备应该是路由器了,不过做NAT最厉害的不是路由器,而是防火墙,像我们原先的openstack集群就因为NAT性能不好而用防火墙来替代了。 

4.2 IP流量转移

上面那个简单的NAT情况如果给Linux服务做也是两个命令就可以了,很明了:

-A PREROUTING -d  45.45.45.45 -j DNAT --to-destination 10.10.10.2-A POSTROUTING -s  10.10.10.2 -j SNAT --to-source 45.45.45.45

这里有个有趣的问题,假如公网IPA访问公网IPB的时候,其实也IPB可以做个全转发,让实际上是访问的是公网的IPC。

-A PREROUTING -s  IPA  -d  IPB  -j DNAT --to-destination  IPC-A POSTROUTING -s IPA  -j SNAT --to-source IPB

如果IPA想来黑IPB,那IPB可以把流量全部转到IPC,也就是如果IPA打攻击流量给IPB,那IPB可以把流量转移走甚至是直接再转给IPA,把IPC改为IPA即可。

不过IPC识别到的流量是IPB的而已,并不能把IPA的流量直接跳转到IPC。纯恶作剧的时候有用 -_-。

假如IPA通过ssh IPB “shutdown” 这样ssh远程登录到IPB执行关机命令的时候,IPB把这份流量乾坤大挪移到IPA自身,那IPA自身就关机了。

4.3 转移细节1

这种转移IP流量的方式其实在线上也偶尔用到,特别是局部网络故障的时候,假如广州用户访问北京的时候,经过武汉这条线路故障了,可以让广州用户访问上海,然后上海这个中转机把IP流量转发到北京即可。

看似简单,但能解决问题,但是真正解决问题的时候,可能会有人发现了不足之处。

1. 首先就是上海入向和出向的流量增加了,这里有额外的小费用。

2. 然后就是应用层了,北京识别到的广州用户IP居然是上海那台中转机的IP。

为什么会是上海的IP呢?

因为上面有个POSTROUTING操作,也就是SNAT操作,修改源IP,如果不修改源IP的情况,就是上海机房需要用广州的IP去访问北京IP,那肯定是不行的,上海机房分发不了广州的IP。

如图: 

160.154访问45.187的时候,45.187把流量转到141.183,如果不做SNAT修改源IP,就变成了在45.187这个服务器用160.154这个IP去访问141.183,肯定是路由不通的。如果做了SNAT的情况呢?变成了这样子:

160.154访问45.187的时候,45.187把流量做DNAT修改目的地址转到141.183,但是同时SNAT到了45.187这个IP出去,所以可以正常出去,然后第三行流量正常回来,回来到45.187这个NAT机器时候,通过NAT表再还原回之前的源和目的地址,顺利回到了160.154 。

可以看到虽然160.154访问到了141.183,但是是用的45.187这个IP去访问的,所以识别到的就是45.187这个IP了,没毛病。

4.4 转移细节2

如果一定要识别到广州的IP呢,可以在两个服务器之间拉一条专线,把两个内网卡连接起来,然后就成了这样子:

-A PREROUTING -d  IPB  -j DNAT --to-destination IPC_LAN-A POSTROUTING -s  IPC_LAN  -j SNAT --to-source IPB

实际情况是这样子:

52.226访问IPB的时候,IPB转发到IPC的内网IP 86.59,IPC加一条策略路由,让从内网网卡进来的流量再从内网网卡出去,而不是走默认路由从公网出去:

ip route add default via IPB_LAN  dev em2 table 200ip rule add from IPC_LAN  table 200

这样因为是内网同一个段的通信,不经过机房的路由器,可以直接从内网到达86.59,然后86.59的数据回来时候,目的地址是52.226,经过NAT设备的时候会进行POSTROUTING的SNAT操作,把这个内网地址转为公网IPB,完成一个数据轮回。这样一来,IPC机器识别到的就是未经SNAT修改的DNAT转发,这样就识别到了广州用户的源IP了。

4.5 转移细节3

但是实际情况不可能有很多公司去专门拉一条专线,所以有个软路由的方式来解决,就是拨一条VPN,在两个机器之间弄一个可以直接访问的隧道,也就是之前说的这个图:

关键点就是数据包的公网源IP和公网目的IP不要经过机房的路由器,机房没法帮你广播非自己的IP。而是把DNAT的IP改为对方机器的VPN私网IP就可以了。

需要注意的是,由于IPC这个机器默认是走公网IP出去,如果内网的流量从内网卡进来,默认还是会走公网路由出去,这里需要加一条策略路由:

/sbin/ip route add default via IPB_LAN  dev em2 table 300/sbin/ip rule add from IPC_LAN  table 300

意思就是从IPC_LAN这个内网卡进来的流量,把下一跳改为em2的IPB_LAN这个ip。网络的同学应该经常听到:让数据从哪里来,往哪里回去。

4.6 转移细节4

现实中我们还有些更复杂的情况很折腾,但是还是可以做的,就是拉专线之后,两个机房的内网不是同一个网段,中间经过了一个三层设备(一台Linux服务器)。

用户访问NAT服务器,然后经过路由服务器到达IPC机器,走向也比较明了:

-A PREROUTING -d 1.201.56.17  -j DNAT --to-destination 172.16.0.2-A POSTROUTING -s 172.16.0.2  -j SNAT --to-source 1.201.56.17

但是NAT服务器是192.168段,所以首先就得加路由让172.16的段走192.168:

route add -net 172.16.0.0/16 gw 192.168.0.1

同理,IPC也是需要加上面说的“从哪里来,往哪里回去”的这个策略路由。

而且路由服务器需要加路由,让用户NAT的流量有地方走,也就是加默认路由走192.168.0.2

route add default gw 192.168.0.2

这样经过我们自己的一层路由,IPC服务器就可以正常识别到流量的来源了,而不是只知道是NAT服务器过来的。

4.7 转移细节5

我们现实中情况稍微再复杂一点。

就是做NAT的情况不只是下面的NAT服务器转发流量到上面去,而且还需要支持反着来。

就是黑色箭头的那些,需要在IPC机器那里也做NAT,把一大堆公网IP,经过路由服务器NAT到图例下面的机房。

问题不大,NAT配置很简单,但是路由服务器就复杂了,原先默认流量是直接走192.168.0.2就可以了,现在反着的流量又需要走172.16.0.2这个NAT机器的内网。

需要配置稍微复杂的策略路由了。

文字需求:

从192.168来的NAT流量先转发到172.16段,然后回来的时候需要把来源172.16的流量经过172.16.0.1转发到192.168.0.2这个NAT机器。

从172.16来的NAT流量先经过路由服务器转发到192.168段,然后192.168回来的流量从192.168.0.1进来,转发到172.16.0.2这个NAT机器。

逻辑貌似简单,策略其实复杂了很多:

em1: 192.168.0.1em2: 172.16.0.1ip route add 172.16.0.0/16 dev em2 src 172.16.0.1 table 100ip route add default via 192.168.0.2  dev em1 table 100ip route add 192.168.0.0/16 dev em1 src 192.168.0.1 table 200ip route add default via 172.16.0.1  dev em2 table 200ip rule add from  172.16.0.0/16  table 100ip rule add from  192.168.0.0/16   table 200

这样就完成了两个机房互相做NAT来达到IP备用的目的了。

其实我们线上更复杂一层。

因为引入了腾讯云的专线内网,然后和我们原先自己的专线内网混用,多个内网网段加上流量交叉,各种策略路由和不同网关,不忍直视。。

但是这个架构方案完成了IP互相备用的需求。

4.8 NAT配置细节

注意iptables配置NAT之后,需要注意测试下同网段的一些IP连通性,比如10.10.10.2映射到45.45.45.45之后,虽然外网可以ping通,其实自己是ping不通自己的,需要额外再加一些条目,比如:

-A PREROUTING -s 10.10.10.2 -d  45.45.45.45  -j DNAT --to-destination 10.10.10.2

意思就是自己ping自己的公网IP,再原路回去。

而且NAT服务器在做IP映射的时候,先需要把IP配置在自己的网卡子网上,而且支持批量配置,一般人应该都没配置过:

添加配置文件ifcfg-em1-range0,内容:

DEVICE="em1:1"NM_CONTROLLED="yesONBOOT="yes"BOOTPROTO=staticNETMASK=255.255.255.128TYPE=EthernetIPADDR_START=33.31.99.3IPADDR_END=33.31.99.126CLONENUM_START=1 ARPCHECK=no

这样就直接一次性加上了124个公网IP了,并特意加上了ARPCHECK=no这个参数,用来快速启动网卡,否则ifup em1的时候,需要每个IP都检查ARP,速度非常慢。

由于在子网卡上配置了N多个IP,所以需要在iptables这里把直接访问的流量禁用掉,否则没做NAT的IP也会访问到这个机器上。

*mangle:PREROUTING ACCEPT [160:18432]:INPUT DROP [11:1236]:FORWARD ACCEPT [0:0]:OUTPUT ACCEPT [140:17360]:POSTROUTING ACCEPT [140:17360]-A INPUT -d 33.31.99.2 -j ACCEPT-A INPUT -d 192.168.99.2 -j ACCEPTCOMMIT

本机只接受99.2这个机器的入向流量,其余DROP,但是接受所有的FORWARD转发流量。

然后就是网卡是否能扛得住包转发的量了,特别是数据小包的话更加累,大家认为的千兆网卡可能理所当然地认为是可以跑千兆,其实远不是这样,如果每个数据包都很小,是很难跑上几百兆的,升级硬件,把网卡升级,CPU升级,然后均匀调整下网卡的中断或许可以勉强解决。

5 结语

之前说的很多网络设备是基于linux加的一些壳,其实有些还支持进入这个内核,比如深信服可以直接ssh进入,Juniper可以通过start shell user root进入,还有cisco的ISE设备之类的都是如此,当然像xenserver和vmware之类的也都差不多,不过性能点的优化做的很不错。

引入了iptables来做网络的事情,大家可能可以联想到tc命令,tc可以来做网络质量相关的调控,比如模拟对应IP的若网环境,限速之类的,比较复杂,不细说了。

近期文章

“深入浅出”来解读Docker网络核心原理

运维开发三年之痒

一位运维眼中的AIOps

linux 系统 UDP 丢包问题分析思路

《MySQL自增ID》告诉你不为人知的“秘密”......

END

全中国只有不到1% 的人关注了运维军团

你是个有眼光的人!

(由于交流群人数已超100人,需要进群的小伙伴可以添加运维小编的:)

如果你喜欢我们的文章,请转发到朋友圈

 

如果你喜欢我们的文章,请转发到朋友圈  ywjtshare运维军团 专注运维技术与传承,分享丰富原创干货