通过iptables进行基础防火墙与各种NAT的配置
这次面临的问题是:希望把对主机A的访问(不局限在某一端口上)以类似代理的方式转嫁到B上;AB都有公网的IP,而不是内网的关系。
经过连夜奋战,实现了这一功能,自己也学到了一些经验。
这里记录了基本所有的配置,顺带着把Netfilter/iptables也介绍了,希望对读者有帮助。
本文系笔者原创文章,一天前以 aptitude 帐号发布于北邮真情流露 BBS。
NetFilter 是 Linux 2.4 kernel 开始引入的一套核心态-用户态(kernel space/user space) 配合的灵活的包过滤防火墙/高级路由器支持iptables 就是一个用户态工具,可以用来修改 Netfilter 规则,两者配合,可以在用户态来修改核心高级路由功能,不仅无须重新编译内核,也完全不必重新启动系统,即时修改、即时生效,所以,是 2.4 内核的标志性特性之一,远胜于 2.2 的 ipchains。
作为包过滤防火墙 Netfilter 可以根据一系列条件放行或是丢弃这些包,或是放行到送到用户空间去处理;作为高级路由器,Netfilter 可以根据 IP 包的某些特征对 IP 包头数据进行修改 (主要是源/目的地址/端口),从而达到 IP 伪装、端口映射、负载均衡等功能,而这次我们的工作主要就是利用了这些功能。
Netfilter 的另一大优点就是极具可扩展性,可以通过编写内核模块增加新的匹配、处理功能,其内部本身支持了两张表 (filter/nat),用于上述两类功能,你也可以增加新的功能;而每张表又会有不同的链 (chains),对应于不同的处理阶段;一个包从进入到出去可能会经历若干个表的若干个链,每个链会包含若干规则,一一对进入链的包进行处理,下面就听我细细讲来 (没兴趣操作的话了解到这里就差不多了。):
首先,iptables 命令操作比需要指定表,如果没有指定,就会缺省认定是 filter 表,比如 iptables -L -v就会列出 filter 表中 INPUT/FORWARD/OUTPUT 三个链的规则,而要列出 nat 表的 PREROUTING/POSTROUTING/OUTPUT 就要用 iptables -t nat -L -v
之后,在操作之前,可能会清除(flush)一个链上的所有规则,然后从零做起: iptables -t nat -F PREROUTING当然,如果之前的规则不能删除就不要这样了。
每个链会有一个缺省的策略,比如,INPUT 链是用来处理所有目的为本机的刚刚进入的包的,对于这个链,我们常常设置为缺省丢弃 (DROP),然后特殊的让一些包可以通过,这样比较安全一些: iptables -P INPUT DROP
当然,这之后要开规则来允许某些包进来,比如,允许端口 23 的 tcp 访问: iptables -A INPUT -p tcp --dport 23 -j ACCEPT-A 参数是在某个链加规则,之后是规则的两个部分: 条件和执行的操作。首先是匹配条件:
常见的匹配条件还有 -s (source ip), -d (destination ip) 等,详细的可以 man 一下,这次配置,我们还用了另一个匹配方式:
-m state --state ESTABLISHED
-m 参数用于加载一类非内建的匹配方式: 连接状态匹配,STABLISHED 用于对于建立了socket 连接的包进行匹配,常常用于这样的情况: 禁止从外到内的连接,但对于从内到外建立的 socket 连接,其进入的包可以允许通过。
然后是操作,也就是目标 (TARGET)
所谓 NAT 是网络地址变换(翻译?),也就是在路由的同时修改源或目的地址/端口,来完成某种高级路由功能。比如,从 192.168.1.1/24 的网络出去,源地址是不合法的公网 IP 需要做一个调整,这个叫 SNAT,一般用网关的出口地址作为修改后的地址,这种情形更确切地被称为 IP 伪装 (MASQUERADE)。而另一种情况是吧访问到一台计算机的包重新送到另一台计算机/端口去,这个常常称为端口映射,规范地说,叫 DNAT,D 是destination 的意思。
DNAT 一般在包进入之后、被决定路由之前来进行,所以发生在 PREROUTING 链: iptables -t nat -A PREROUTING -p tcp --dport 23 \ -d dnat.server.ip.addr \ -j DNAT --to bupt.org.ip.addr:23如此,就把到公网主机的 telnet 访问的目的地址改变到了我们的 server 了。
本来我以为上面那样就可以了,不过事实证明不太成功,研究后认为具体原因是,到达真情的包的源地址是访问者的地址,所以发回去的 ip 包不会经过我们的 DNAT server, 到访客的包的源地址也不是他请求的目的地址,这个自然地无法成功建立 TCP 连接。
所以,挠头半小时后,我决定加上 SNAT,也是在中间的 server iptables -t nat -A POSTROUTING -p tcp --dport 23 \ -d bupt.server.ip.addr \ -o eth0 -j MASQUERADE这里有两点需要注意:
echo 1 > /proc/sys/net/ipv4/ip_forward
如果不允许转发 ip 包,所有配置都没用了,包不会被路由的,呵呵。
iptables -D INPUT ...
这个后面的写法完全和 iptables -A 相一致,必须一字不差才能删除
iptables 配置如果没经过处理的话,在每次重启后都要失效,所以应该永久化一下,昨天晕,忘了这个,不过暇不掩瑜,总算是基本配出来了,最后这个 ever 加一下吧。
如果是 rh ,里面已经提供了一项 iptables 服务了,运行 service iptables save应该差不多就行了,不过我给兄弟们一个万能的方法:
好长,写完了,呵呵,都是命令的使用,难登大雅之堂,对大家有什么参考价值的话就再好不过了 :)