iptables 是 Linux 中一个非常重要的安全工具,用于配置内核防火墙。
参考自:Arch Wiki - iptables
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| XXXXXXXXXXXXXXXXXX XXX Network XXX XXXXXXXXXXXXXXXXXX + | v +-------------+ +------------------+ |table: filter| <---+ | table: nat | |chain: INPUT | | | chain: PREROUTING| +-----+-------+ | +--------+---------+ | | | v | v [local process] | **************** +--------------+ | +---------+ Routing decision +------> |table: filter | v **************** |chain: FORWARD| **************** +------+-------+ Routing decision | **************** | | | v **************** | +-------------+ +------> Routing decision <---------------+ |table: nat | | **************** |chain: OUTPUT| | + +-----+-------+ | | | | v v | +-------------------+ +--------------+ | | table: nat | |table: filter | +----+ | chain: POSTROUTING| |chain: OUTPUT | +--------+----------+ +--------------+ | v XXXXXXXXXXXXXXXXXX XXX Network XXX XXXXXXXXXXXXXXXXXX
|
Basic
iptables 用于检查、修改、转发、丢弃 IP 数据包,其中每一步的详细工作通过 tables 和 chains 这两个结构来完成。
上面那张图的完整情况是这个样子的:
每个节点上的小写字母表示 table ,下面的大写字母表示 chain ,可以把每个节点理解成很多设定好的规则。每一个 IP 数据包都要从上到下经过这样一整个工作流的检查(有的数据包从外面进来到 Local Process 就结束了,有的是从 Local Process 里面产生然后发送到外面去)。
Tables
iptables 中包含5个 tables:
通常情况下常用的是 filter 和 nat ,其他的用于更复杂的情况,所以上面手画的流图里面只画出了这两个 tables 。
Chains
tables 由 chains 组成,例如 filter 表中就有 INPUT 、 OUTPUT 、 FORWARD 3条内建的 chains ,这三条 chains 作用在数据包过滤过程的不同时间点上(参见上面的流程图)。 nat 表包含 PREROUTING 、 POSTROUTING 、 OUTPUT 这三条 chains 。
Configuration
在 Arch Linux 和 CentOS 上 iptables 的启动和关闭都在服务里配置(话说 CentOS 7 已经改用 firewalld 来管理防火墙了):
然后不同的发行版设置的 iptables 的记录文件的位置还不一定一样,比如 Arch 里面是在 /etc/iptables/iptables.rules
, CentOS 就是直接放在 /etc/sysconfig/iptables
这个文件里了, Ubuntu … 恕我没找到。
管理和配置 iptables 可以在 root 权限下用 iptables
命令,或者直接修改配置文件,然后重启 iptables 也行。一般我比较喜欢改文件,一目了然,不容易出错,,,不过像 Ubuntu 这种我没找到写在哪的就坑了。
具体的 iptables
命令还是用的时候 man iptables
慢慢查吧,这里简单记一下几个常用命令的用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 向 chain 中附加一条规则 rule
检查 chain 中是否存在规则 rule
从 chain 中删除规则 rule
向 chain 中插入一条规则 rule 这个跟 -A 的区别是 -A 是加入到 chain 的末尾 -I 如果不指定插入的序号的话则默认序号为1,即插入到 chain 的开头
打印 chain 中的所有规则,不指定 chain 的话就是所有 chain
列出 chain 中的所有规则,不指定 chain 的话就是所有 chain
|
上面的每条命令还可以加 -t table
来指定当前的操作对某个特定的表 table 进行。
-A 和 -I 的不同在于, iptables 检查规则时是从上往下按 rules 的顺序依次进行,一旦匹配到一条 rule 那就直接跳出当前 chain 了,因此同样的一些 rules 插入到 iptables 里之后可能因为顺序的不同会有不同的结果。
Rules
比较坑的是我在好几个 wiki 上查了 iptables ,但是上面很少有讲 rules 具体怎么写的, man iptables
返回的信息是在 PARAMETERS 这段中有讲。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| [!] -p, --protocol protocol 指定协议,可以是 tcp/udp/udplite/icmp/icmpv6/esp/ah/sctp/mh/all 加了 ! 则表示除了该协议以外,下同
[!] -s, --source address[/mask][,...] 指定源地址
[!] -d, --destination address[/mask][m...] 指定目标地址
[!] -i, --in-interface name 指定数据包进入的网卡设备
[!] -o, --out-interface name 指定数据包流出的网卡设备
-j, --jump target 指定当前 rule 要跳转到的目标,可以是 ACCEPT/DROP/REJECT/LOG ACCEPT 和 LOG 都是让数据包通过当前的 chain ,区别是 LOG 会记录日志信息 DROP 直接把包从这里丢弃不做任何操作, REJECT 丢弃包并且向源地址发送拒绝响应
-g, --goto chain 跳到某条 chain 中继续执行
|
Example
列个示例吧,下面是一台 VPN 服务器 iptables 文件的一部分内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] -A INPUT -i enp7s0 -j ACCEPT -A INPUT -i ppp+ -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT -A INPUT -p tcp -m tcp --dport 1723 -j ACCEPT -A INPUT -p udp -m udp --dport 1194 -j ACCEPT -A INPUT -p udp -m udp --dport 4500 -j ACCEPT -A INPUT -p esp -j ACCEPT -A INPUT -p gre -j ACCEPT -A INPUT -p icmp -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -j REJECT --reject-with icmp-host-prohibited -A FORWARD -d 202.38.64.59/32 -i ppp+ -j DROP COMMIT
*nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] -A POSTROUTING -o enp7s0 -j MASQUERADE COMMIT
|
默认规则后面的 [0:0] 是用 iptables-save
命令保存当前的 iptables 配置到文件后写的,表示当前收发了多少数据包。我这里是手写的所以就直接设成 0 了,其实没什么用。
数据包进入某个 table 之后是从上往下遍历所有规则,最后再走默认规则。
事实上上面这个文件写的是有问题的,所有输入的数据包的 INPUT 链在网卡这里就直接被 ACCPET 了,所以后面写的一堆规则其实没啥用…
比较好的写法是把默认规则设成 DROP ,然后再写一些需要用的 ACCPET 规则,让数据包从上到下一条一条匹配,如果没有匹配到任何一条规则,那就说明这个包不是我们想要的,默认 DROP 掉。
filter 表的 FORWARD 链这里这条规则表示:从 ppp+ 这些网卡(PPTP 服务生成的虚拟网卡,对应了每个 VPN 的连接)来的,要到 202.38.64.59 这个地址去的数据包全部丢掉,这样 VPN 进来的连接就不能通过这台机子的转发来访问这个地址了。
下面的 nat 表, MASQUERADE 表示动态地址伪装,即 VPN 链接过来的数据从服务器出去的时候把数据包的源地址改成服务器的地址,用于 NAT 转换。
话说其实应该找时间开个虚拟机好好测试一下的…
To be continued…