概述
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 使用
2.1 表和链
首先,iptables 命令操作比需要指定表,如果没有指定,就会缺省认定是 filter 表,比如
iptables -L -v
就会列出 filter 表中 INPUT/FORWARD/OUTPUT 三个链的规则,而要列出 nat 表的PREROUTING/POSTROUTING/OUTPUT 就要用
iptables -t nat -L -v
2.2 链的初始化
之后,在操作之前,可能会清除(flush)一个链上的所有规则,然后从零做起:
iptables -t nat -F PREROUTING
当然,如果之前的规则不能删除就不要这样了。
每个链会有一个缺省的策略,比如,INPUT 链是用来处理所有目的为本机的刚刚进入的包的,对于这个链,我们常常设置为缺省丢弃 (DROP),然后特殊的让一些包可以通过,这样比较安全一些:
iptables -P INPUT DROP
2.3 规则、INPUT 链
当然,这之后要开规则来允许某些包进来,比如,允许端口 23 的 tcp 访问:
iptables -A INPUT -p tcp --dport 23 -j ACCEPT
-A 参数是在某个链加规则,之后是规则的两个部分: 条件和执行的操作。首先是匹配条件:
-p tcp 是协议 tcp
--dport 23 是目的(destination) 端口 23
常见的匹配条件还有 -s (source ip), -d (destination ip) 等,详细的可以 man 一下,这次配置,我们还用了另一个匹配方式:
-m state --state ESTABLISHED
-m 参数用于加载一类非内建的匹配方式: 连接状态匹配,ESTABLISHED 用于对于建立了socket 连接的包进行匹配,常常用于这样的情况: 禁止从外到内的连接,但对于从内到外建立的 socket 连接,其进入的包可以允许通过。
然后是操作,也就是目标 (TARGET):
-j ACCEPT 是跳 (jump) 到目标 ACCEPT 上去,常用于 INPUT 的另一个目标是DROP,也就是丢包,对于不喜欢的包都可以丢掉
2.4 DNAT/端口映射
-----------------
所谓 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 了。
2.5 SNAT/IP伪装
本来我以为上面那样就可以了,不过事实证明不太成功,研究后认为具体原因是,到达真情的包的源地址是访问者的地址,所以发回去的 ip 包不会经过我们的 DNAT server, 到访客的包的源地址也不是他请求的目的地址,这个自然地无法成功建立 TCP 连接。
所以,挠头半小时后,我决定加上 SNAT,也是在中间的 server
iptables -t nat -A POSTROUTING -p tcp --dport 23 -d bupt.server.ip.addr -o eth0 -j MASQUERADE
这里有两点需要注意:
- 目的地址的匹配应该是最终地址和端口,因为前面地址 DNAT 已经变过了
- IP 伪装一定要指定出端口 (-o interface) 否则鬼知道伪装成什么 IP,没准是 127.0.0.1 呢,呵呵。
2.6 允许数据包转发
echo 1 > /proc/sys/net/ipv4/ip_forward
如果不允许转发 ip 包,所有配置都没用了,包不会被路由的,呵呵。
2.7 规则的删除:
iptables -D INPUT ...
这个后面的写法完全和 iptables -A 相一致,必须一字不差才能删除。
永久化我们的配置
iptables 配置如果没经过处理的话,在每次重启后都要失效,所以应该永久化一下。
如果是 rh ,里面已经提供了一项 iptables 服务了,运行
service iptables save
应该差不多就行了,不过我给兄弟们一个万能的方法:
- 在 /etc/init.d/ 之下建立一个脚本,加上执行权限
- 在脚本上写上我给出的那些东东:
- 用那句 echo 打开 ip_forward
- INPUT 上加三条规则(telnet,www 和那个 state 的)
- PREROUTING 上加两条规则 (telnet,www)
- POSTROUTING 也两条
- 在 /etc/rc[2-5].d/ 里面都加上到这个脚本的符号链接,如 S20buptnat.sh -> ../init.d/buptnat.sh (S20应该是可以的,理论上讲,过了 rcS.d 的 S40,网络功能就应该已经具备了,这是对 Debian 而言的,其它类似)
总结
好长,写完了,呵呵,都是命令的使用,难登大雅之堂,对大家有什么参考价值的话就再好不过了 :)