iptables 使用学习
Linux 防火墙分为 应用层防火墙 和 包过滤防火墙,iptables 属于包过滤防火墙,底层使用的是 Linux 内核模块 netfilter,性能佳稳定性好。
原理简析
iptables 基本结构:
iptables -> 规则表 -> 规则链 -> 具体规则
可以看出 iptables 通过参数 t 指定要操作的规则表,使用命令(如添加、删除、替换、清空、查看等)控制规则链,再指定规则的条件,最后使用参数 j 控制数据包的行为。
iptables 用的最多的是 filter 表和 nat 表。filter 表用于数据过滤,nat 表用于网络地址转换。
filter 表有 INPUT、OUTPUT 和 FORWARD 等规则链。INPUT 链控制数据包的流入,PUTPUT 链控制数据包的流出,FORWARD 链控制数据的转发。
nat 表有 PREROUTING、POSTROUTING 和 OUTPUT 规则链,PREROUTING 链用来修改数据包的目标端口和地址,POSTROUTING 链用来修改数据的源端口和地址,OUTPUT 链作用类似 PREROUTING 链,不过是用来修改本机发出的数据的 目标端口和地址。
这几个规则链的关系如下:
当外面的数据包进入本机,首先会经过 PREROUTING 链,对修改后的目标地址进行路由判断,如果发现其目标就是本机,那就走 A 经过 INPUT 链的筛选,符合条件就放行至本应用处理;如果发现目标地址是其他主机,那就走 B 使用 FORWARD 链进行转发,最后通过 POSTROOUTING 链出去。POSTROUTING 链很重要的工作是修改来源地址为本机,并记录这个修改关系。数据回传的时候本机通过这个修改关系转发数据给源主机。
当本机要发出数据包,先经过路由判断进入 nat 表的 OUTPUT 链,用来修改目标主机,然后经过 filter 表的 OUTPUT 链的筛选,符合条件就放行到 POSTROUTING 链,修改源地址就包并发出。
用来修改目标地址的 PREROUTING 链必须放在最前面,放在路由后面将无法选择 A 还是 B。POSTROUTING 链必须放在最后,等到所有链判断完成后再修改源地址,如果放在前面,倘若数据包都出不来,提前修改源地址纯属浪费力气。所以这这个链的位置是有讲究的,并不是随意放置。
语法命令
iptables 语法格式:
iptables [-t 表名] 命令选项 [链名] [条件匹配] [-j 目标动作或跳转]
命令选项
iptables 常用的命令选项:
- -A:–append,在规则链的尾部插入规则
- -I: –insert,默认在规则链的头部插入规则,可以指定位置
- -D:删除规则链中指定规则
- -F:清空指定链的规则。不指定则清空所有链
- -L:–list,查看指定链的规则。不指定则显示所有链
- -v:查看规则时显示详细信息
- -n:不将 ip 地址反解析为域名
条件匹配
条件匹配分为基本匹配和扩展匹配,扩展匹配又可以分为隐式扩展匹配和显式扩展匹配。基本匹配命令:
- -p:指定协议规则,tcp、ip 和 icmp
- -s:指定数据包的源地址
- -d:指定数据包的目标地址
- -i :指定入站流量的网卡
- -o:指定出站流量的网卡
示例
放行 80 端口
1 | iptables -t filter -I INPUT --dport 80 -j ACCEPT |
iptables 默认操作 filter 表,因此可以省略;INPUT 表示流量流入,方向是客户机到本机,所以客户机 ip 是源 ip,放行的本地端口就是目标端口;可以增加参数 i 指定网卡,增加参数 s 指定客户机 ip。
允许来自 10.0.0.1 流量通过 80 端口
1 | iptables -A INPUT -s 10.0.0.1 -i eth0 -p tcp --dport 80 -j ACCEPT |
上面使用了参数 p,表示指定协议为 tcp。
查看规则
只要没有语法问题,设置了规则后 iptables 默认没有任何提示。当我们想要查看规则,可以使用命令 L 查看。结合参数 vn 就可以显示更为现实的规则信息并只显示 ip。
1 | iptables --line-numbers -vnL |
上面使用参数 –line-numbers 可以显示每条规则的编号,便于定位。
一般网上使用命令 iptables -F 来清空 iptables,认为 iptables 太复杂,直接清空不要防火墙了。虽然 -F 参数有清空的作用,但是情况前需要格外注意默认的规则。当我们使用 -vnL 显示规则时,在第一行会看到如下类似信息:
1 | Chain INPUT (policy REJECT 285 packets, 48260 bytes) |
上面表示 input 规则链的默认 policy 是 reject,这种情况下你胆敢 -F 清空 iptables,你就惊奇发现:怎么动不了了?
使用 -P 参数更改默认 policy 为 accept,再清空。或者直接卸载 iptables。。。
1 | iptables -P INPUT ACCEPT |
高级模块
再看看比较高级的模块。如果想要限制连接数量,使用 –connlimit,例如只允许最多 5 个用户使用 ssh 连接主机:
1 | iptables -A INPUT -p tcp --dport 22 -m connlimit --connlimit-above 5 -j DROP |
使用 –limit 来限制连接频率,例如限制 ping 速度。
1 | iptables -A INPUT -p icmp -m limit --limit 10/s --limit-burst 12 -j ACCEPT |
不过我测试 limit 好像限制不了 icmp,听说就是这样?
除了 limit,还可以使用 recent 模块。recent 涉及到地址列表,首先使用 –set 参数将连接到本机的 源ip 加入到地址列表里,将地址列表取名为 restricted-ping。
1 | iptables -A INPUT -m --set --name restricted-ping |
因为目的还没有达到,就不用 -j 指定操作。然后使用参数 name 指定上面的地址列表,使用 –seconds 参数指定时间,使用 –hitcount 指定次数,来实现频率限制。例如在半个小时内只允许 10 个用户连接 ssh。
1 | iptables -A INPUT -p tcp --dport 22 -m recet --rcheck --seconds 1800 --hitcount 10 |