背景
这几天在做开发联调的时候,出现了这样一种情况:我的应用本身开启的是24100端口,但别的应用却是调用我的80的端口。
本来我把端口重新配置一下,编译重启应用就OK的事情。但想想UED还在用我的24100端口,真是个棘手的事情。
由于时间紧急,所以就弄了一个最简单的方案:把 httpd 停掉,在配置文件中新增一个80端口的监听,重启 httpd。
事后想想,看有没有别的方法解决此问题,后来想了想,还有两种解决方案:
- 再新启一个httpd,监听80端口,并且在80端口做一个代理
- 使用 iptables 把端口从80 透明的改成 24100
由于第二种方案从来没有试过,之前对 iptables 也只是听说过,所以决定便决定研究一下。
iptables是什么
之前隐隐约约知道iptables是一个防火墙,到防火墙到底是个什么东西,能做什么,iptables又是怎么会是,我还是一知半解的。
借着这个机会,也简单的查找了一下:
iptables包含在 2.4以后的内核中,它可以实现防火墙、NAT(网络地址翻译)和数据包的分割等功能。
说白了, iptables还不仅仅是个简单的防火墙,他还能进行NAT和数据包的分割。
iptables的工作机制
如下图:这是从51cto找到的图。
- iptables是由表,链,规则,目标组成,每个表中有几条链,每条链有几条规则,每条规则如果被匹配,这可以指定到特定目标
- iptables默认有三个表,分别是: mangle, nat, filter
- mangle 默认有5条链,分别是: PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING
- nat 默认有3条链,分别是:PREROUTING, OUTPUT, POSTROUTING
- filter默认有3条链,分别是: INPUT, FORWARD, OUTPUT
一个网络包在iptables旅游的过程:
- 当一个包在网络中被网卡接受到的时候,会先经过iptables的mangle表的PREROUTING链
- 然后再经过nat表的PREROUTING链
- 然后经过路由判断,该包是进行转发,还是接受到本机。
- 如果是转发,则经过 mangle表的FORWARD链,再经过 filter 表的 FORWARD 链,最后再经过 mangle表的 POSTROUTING链和nat的POSTROUTING链。
- 如果不转发,则进入本机,再进入本机之前,要经过 filter表的INPUT链,和mangle的INPUT链。经过本机处理后,再进入 mangle,nat,filter表中的OUTPUT链(注意表的顺序)
- 然后再路由该包,最后经过 mangle和nat的 POSTROUTING链条
有了上边的图和解释,对iptables就应该有大致的理解了:)
解决最初的问题
有了以上的概念,要解决最初的问题,就知道我们大概要在哪里“做手脚”了。呵呵
就是在 nat表的PREROUTING中加上一个规则,如果端口是80的话,就对该包做端口转发,就是把目标端口改为24100。
具体的命令如下:
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 24100
其中:
- -t nat 指定表为nat
- -A PREROUTING 是在PREROUTING中append一条规则
- -p tcp 匹配tcp协议
- --dport 80 表示匹配目标端口为80
- -j REDIRECT 表示跳转(jump)到 REDIRECT这个目标,REDIRECT所作的事情,就是把做端口转向
- --to-ports 24100 则是把端口号转到24100上
这样,在内网上的其他机器,使用80端口访问我应用的时候,就会被指向到24100这个端口上。
同时,iptables还是很聪明的把响应回来的包也相应做一次转换。
新的问题
虽然这解决内网上不同机器能够访问我的80端口,但我自己的机器却不能访问80端口,很郁闷……
在CU论坛上问了一下,发现时本机机器访问本地机器时,是不走PREROUTING的……
怪不得,连这条链都没有经过,怎么会做端口转发呢。
解决思路
取巧使用了如下方法:
- 本地访问另外一个局域网IP,80端口。
- 在iptables的nat表OUTPUT链中作DNAT转换,让目的IP变成本机IP,并且端口有80变成24100端口
命令如下:
iptables -t nat -A OUTPUT -p tcp -d 10.19.14.129 --dport 80 -j DNAT -to 10.19.14.128:24100
其中 10.19.14.129是其他内网IP, 10.19.14.128是本机IP。
经过实验,问题总算是解决了。
心得
linux系统中的工具真是强大,只有想不到,没有做不到。
附上iptables的一个学习网址: