CentOS6.5基于iptables实现单网卡端口转发

前端之家收集整理的这篇文章主要介绍了CentOS6.5基于iptables实现单网卡端口转发前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

一,情景再现
@H_403_6@

今早7点多接到客户的一个需求,要求做Linux下的单网卡的端口转发,给了如下一张图:@H_403_6@

wKioL1jNLyCwDexaAAEYl_wQZV8981.jpg-wh_50

@H_403_6@

这里假定左侧的IP为服务器A,右侧为服务器B,现在需要将到A服务器的某些IP和端口的访问转发至服务器B上的相关IP和端口,服务器A和服务器B不在同一网段(这里有个小坑,后面再说)。需求说完,下面我用一个实验来还原下这个需求的实现过程。@H_403_6@

二,实验拓扑@H_403_6@

wKiom1jNNWTz9x5OAABTalWJ0mA419.png-wh_50

@H_403_6@

这里说明一下,Server A就是负责转发的服务器,Server B上安装有Apache提供服务,现在让Client通过Server A的81端口来访问Server B的80端口,注意,这里虽然是内网环境,但原理跟客户的真实需求是一致的。@H_403_6@

三,实验过程@H_403_6@

(1) 首先在Server B上安装好Apache:@H_403_6@

  1. [root@serverB~]#yuminstallhttpd-y
  2. [root@serverB~]#rpm-qhttpd
  3. httpd-2.2.15-29.el6.centos.x86_64

(2)启动服务,创建测试页面:@H_403_6@

  1. [root@serverB~]#servicehttpdstart
  2. [root@serverB~]#echo"<h1>iptablesnattest.</h1>">/var/www/html/index.html

(3)客户端测试:@H_403_6@

wKioL1jNOR2gNyClAAAWDi6yku0701.png-wh_50

@H_403_6@

(4)开启Server A的ip转发功能,编写iptables规则:@H_403_6@

  1. [root@serverA~]#echo1>/proc/sys/net/ipv4/ip_forward

这一步一定要记得,之前被坑过好几次!!!@H_403_6@

  1. iptables-tnat-APREROUTING-d192.168.1.34-ptcp-mtcp--dport81-jDNAT--to-destination192.168.1.32:80
  2. iptables-tnat-APOSTROUTING-s192.168.1.32-jSNAT--to-source192.168.1.34

这两条规则就是我想当然的在生产服务器上敲得,做完之后发现不成功,于是开始排查原因:@H_403_6@

首先看第一条规则,这个规则是在服务器路由决策之前,将客户端发来的目的地址和端口改为192.168.1.32:80,从而达到访问服务器B的目的,这样看的话,这个规则是没有问题的,我来验证一下:
@H_403_6@

如果第一条语句生效,那么在Server B上将会收到来自Client端192.168.1.185的请求报文,我在Server B上用tcpdump抓包看一下:@H_403_6@

  1. [root@serverB~]#tcpdump-vv-nn-Xtcpport80
  2. tcpdump:listeningoneth0,link-typeEN10MB(Ethernet),capturesize65535bytes
  3. 05:58:58.681487IP(tos0x0,ttl127,id3204,offset0,flags[DF],protoTCP(6),length52)
  4. 192.168.1.185.61777>192.168.1.32.80:Flags[S],cksum0x15c0(correct),seq2693866233,win8192,options[mss1460,nop,wscale2,sackOK],length0
  5. 0x0000:450000340c8440007f066b16c0a801b9E..4..@...k.....
  6. 0x0010:c0a80120f1510050a09122f900000000.....Q.P..".....
  7. 0x0020:8002200015c00000020405b401030302................
  8. 0x0030:01010402....
  9. 05:58:58.838172IP(tos0x0,ttl64,id0,length52)
  10. 192.168.1.32.80>192.168.1.185.61777:Flags[S.],cksum0xb6a9(correct),seq4286269053,ack2693866234,win14600,sackOK,wscale6],length0
  11. 0x0000:45000034000040004006b69ac0a80120E..4..@.@.......
  12. 0x0010:c0a801b90050f151ff7b467da09122fa.....P.Q.{F}..".
  13. 0x0020:80123908b6a90000020405b401010402..9.............
  14. 0x0030:01030306....

没错,确实抓到了,说明第一条语句生效了,而且仔细看,会发现Server B也的确给Client回包,但为什么Client端访问失败呢?
@H_403_6@

我在客户端上用wireshark抓包看下@H_403_6@

wKiom1jNQlHSoM4eAABuqStNkag536.png-wh_50

@H_403_6@

发现客户端的回包中RST位置为1,表示异常中止,由于是TCP协议,所以Server B会有重传,结果也是一样,Client端全部拒收了。想了半天,原来Server B的回包地址和我请求的地址不一致,我请求的Server A的81端口,结果Server B的80端口给我回的包,作为Client当然不会接收了。@H_403_6@

原因找到了,接下来让我们看一下第二条规则错在哪里@H_403_6@

  1. iptables-tnat-APOSTROUTING-s192.168.1.32-jSNAT--to-source192.168.1.34

这条语句表示将源地址为192.168.1.32的数据包在路由决策后将要发送之前把它的源地址改为192.168.1.34,在本例中,由于是内网环境,Server B也没有将网关指向Server A(指了也没用,局域网通信靠的是MAC地址),因此,Server B在回包的时候并不会经过Server A,于是规则二并没有生效,接下来的解决思路就是要让,Server B的数据包一定要经过Server A,于是我们删除上述第二条规则,并添加一条新规则。@H_403_6@

  1. iptables-tnat-DPOSTROUTING1
  2. iptables-tnat-APOSTROUTING-d192.168.1.32-ptcp--dport80-jSNAT--to-source192.168.1.34

我们把访问Server B 80端口的源地址改成192.168.1.34,这样Server B在回包时就一定会经过Server A,然后通过查询连接跟踪表,找到请求的真正ip和端口进行回应。@H_403_6@

查看连接追踪表:@H_403_6@

  1. [root@serverA~]#cat/proc/net/nf_conntrack
  2. ipv42tcp6116TIME_WAITsrc=192.168.1.185dst=192.168.1.34sport=63612dport=81src=192.168.1.32dst=192.168.1.34sport=80dport=63612[ASSURED]mark=0secmark=0use=2
  3. ipv42tcp6431997ESTABLISHEDsrc=192.168.1.185dst=192.168.1.34sport=63613dport=81src=192.168.1.32dst=192.168.1.34sport=80dport=63613[ASSURED]mark=0secmark=0use=2

至此,Client的访问就应该可以了。@H_403_6@

wKioL1jNUHfDTmONAAAXkpkeuOU116.png-wh_50

@H_403_6@

通过这次实验,对iptables中nat表的理解又加深了一步,最后放一张关于netfilter处理顺序的图帮助理解。@H_403_6@

wKiom1jNUYLCwp6rAAC2EDs6ubg720.jpg-wh_50

@H_403_6@

猜你在找的CentOS相关文章