看本篇文章之前,请确保已经阅读完了 【iptables(1)之防火墙与iptables相关概念】。
之前已经提到过,iptables 其实就是一个存在于用户空间的工具(应用程序),我们使用它来编写规则,规则会自动发往内核空间中的 netfilter 立即生效。
iptables 在 Linux 中是以一个命令的形式存在,我们可以使用它来对规则进行添加、修改、删除、显示等操作,并且它带有语法检查的功能,下面我们就来看一下 iptables 这个工具具体怎么使用。
基本语法
iptables
命令基本语法如下:
iptables [-t TABLE] COMMAND CHAIN CRETIRIA -j TARGET
-t TABLE:指定做什么表操作,不指定时默认操作 filter 表,可选值有 nat、mangle、raw、filter。
COMMAND:子命令,子命令可分为如下几个类型
对指定表上的链进行操作:
-F:flush,清空指定链上的所有规则,如果省略链,表示清空指定表上的所有链;
-N:new,创建新的自定义规则链;
-X: drop,删除自定义的空链(无规则);
-Z:zero,计数器归零;
-P:policy,设置默认策略(这里的策略指的是上一篇文章中的处理动作),对 filter 表来讲,默认规则为 ACCEPT 或 DROP;
-E:rename,重命名自定义链,已被引用的自定义链无法改名,而无法删除;
对指定表上的指定链中的规则进行操作:
-A:append,将新规则追加于指定链的尾部;
-I:insert,将新规则按编号插入指定链上的指定位置,编号省略时默认添加到第一条;
-D:delete,删除指定链上的指定规则,有如下两种指定方式:
1) 指定匹配条件;
2) 指定规则的编号;
-R:replace,替换指定链上的指定规则;
查看:
-L:list,列出指定链上的所有规则,在使用它时还可与下面选项一起使用:
-n:数字格式显示主机地址和端口(不反解);
-v:详细格式,-vv, -vvv,v 越多,显示越详细;
--line-numbers:显示规则编号;
-x:exactly,不要对计数器的计数结果做单位换算,而显示其精确值;
链管理
例 1:查看指定表上的所有链信息。
# 不指定表,默认查看 filter 表上的所有链。
$ iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
# 使用 -t 指定查看 filter 表上的所有链,当然,这里还可以指定 nat、mangle、raw。
$ iptables -t filter -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
例 2:不反解 IP 查看指定表上链的详细信息。
# 使用 -n 指定不反解,-v 指定查看详细信息。
$ iptables -L -nv
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
492 48203 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
...
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
...
这里还可以指定
-vv
来查看更详细的信息,查看详细信息时,如果匹配到的报文的数量或报文的字节数总和数值很大有可能会默认做单位换算,此时可以使用-x
来指定查看精确值不做单位换算。其中各列含义如下:
pkts
:记录着规则或链所匹配到的报文的个数;bytes
:记录着规则或链匹配到的所有报文大小之和;target
:目标;prot
:协议;opt
:选项;in
:流入的接口;out
:流出的接口;source
:源地址;destination
:目标地址;首先我们要知道,规则是需要添加在链上的,当报文经过指定链时如果匹配到了我们添加的规则,则会相应执行我们指定的表的策略。
其实规则和链是有计数器的,计数器记录着当规则启用生效时到当前时间匹配到了多少个数据包等。
每一个链默认有两个计数器,对应着如上pkts
和bytes
两个字段。
还可以看到链旁边的括号如Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
中也有俩计数器,它们俩是默认规则匹配的计数器,但凡不能被本地指定的规则所匹配的报文,都被默认规则所检查,如果默认规则能匹配,那么默认规则的计数器也会相应的计数。
例 3:在指定表上创建自定义链。
# 在 raw 表上创建自定义链 IN_public
$ iptables -t raw -N IN_public
例 4:重命名指定表上的自定义链。
# 修改 raw 表上名为 IN_public 的自定义链名称为 OUT_public
$ iptables -t raw -E IN_public OUT_public
例 5:修改指定表上指定链的默认策略。
# 修改 filter 表上的 FORWARD 链默认规则为 DROP。
$ iptables -t filter -P FORWARD DROP
例 6:删除指定表中的自定义链。
# 删除 raw 表上的自定义链 OUT_public
$ iptables -t raw -X OUT_public
自定义链中没有规则、且自定义链没有被引用时才可被删除。
例 7:清空指定表上的所有自定义空链。
# 使用 -X 清空 raw 表上的所有自定义空链。
$ iptables -t raw -X
规则管理
在本系列开篇概念中就有说到,所谓规则其实就是匹配报文的条件,在 iptables 中可分为基本匹配和扩展匹配两种匹配模式。
在看两种匹配模式之前,我们先要看一下规则的处理动作(target),在之前有说过,处理动作指的是当链上的规则匹配到相应报文后所要做的动作。
在 iptables 命令中 target 可以通过 -j
选项指定,此处列出一些常用的动作:
ACCEPT
:允许数据包通过;DROP
:直接丢弃数据包,不给任何回应信息,这时候客户端会感觉自己的请求泥牛入海了,过了超时时间才会有反应;REJECT
:拒绝数据包通过,必要时会给数据发送端一个响应的信息,客户端刚请求就会收到拒绝的信息;SNAT
:源地址转换,解决内网用户用同一个公网地址上网的问题;MASQUERADE
:地址伪装,是 SNAT 的一种特殊形式,适用于动态的、临时会变的 IP 上。DNAT
:目标地址转换;REDIRECT
:端口重定向,即在本机做端口映射;LOG
:在 /var/log/messages 文件中记录日志信息,然后将数据包传递给下一条规则,也就是说除了记录以外不对数据包做任何其他操作,仍然让下一条规则去匹配;RETURN
:返回调用链;MARK
:做防火墙标记;
target 还可以是一个自定义链,指定由自定义链上的规则继续做匹配检查。
在定义规则之前我们先来看一下规则的通用操作。
查看规则
例 1:查看指定表上链的规则编号。
$ iptables -L -n --line-numbers
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
2 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
3 INPUT_direct all -- 0.0.0.0/0 0.0.0.0/0
4 INPUT_ZONES_SOURCE all -- 0.0.0.0/0 0.0.0.0/0
5 INPUT_ZONES all -- 0.0.0.0/0 0.0.0.0/0
6 DROP all -- 0.0.0.0/0 0.0.0.0/0 ctstate INVALID
7 REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
Chain FORWARD (policy ACCEPT)
num target prot opt source destination
1 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
2 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
3 FORWARD_direct all -- 0.0.0.0/0 0.0.0.0/0
4 FORWARD_IN_ZONES_SOURCE all -- 0.0.0.0/0 0.0.0.0/0
5 FORWARD_IN_ZONES all -- 0.0.0.0/0 0.0.0.0/0
6 FORWARD_OUT_ZONES_SOURCE all -- 0.0.0.0/0 0.0.0.0/0
7 FORWARD_OUT_ZONES all -- 0.0.0.0/0 0.0.0.0/0
8 DROP all -- 0.0.0.0/0 0.0.0.0/0 ctstate INVALID
9 REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
...
删除规则
例 1:清空链上所有的规则。
# 使用 -F 清空 raw 表上所有链中的规则。
$ iptables -t raw -F
例 2:根据链上的规则编号删除指定规则。
# 使用 -D 选项指定删除 FORWARD 链上的第 8 条规则
$ iptables -t filter -D FORWARD 8
保存及重载规则
例 1:保存规则到指定文件。
# 以保存当前规则到 /tmp/iptables.1 为例。
$ iptables-save > /tmp/iptables.1
例 2:从指定文件重载规则。
# 以重新加载 /tmp/iptables.1 中的规则为例。
$ iptables-restore < /tmp/iptables.1
在 CentOS 6 下保存及重载的操作还可使用如下方式来实现:
service iptables save
:相当于iptables-save > /etc/sysconfig/iptables
;service iptables restart
:相当于iptables-restore < /etc/sysconfig/iptables
;
定义基本匹配规则
先看一下常用的定义基本匹配规则的选项:
[!] -s, --src, --source IP|Netaddr
:检查报文中源 IP 地址是否符合此处指定的地址范围;[!] -d, --dst, --destination IP|Netaddr
:检查报文中目标 IP 地址是否符合此处指定的地址范围;[!] -p, --protocol {tcp|udp|icmp}
:检查报文中的协议,即 IP 首部中的 protocols 所标识的协议;[!] -i, --in-interface IFACE
:数据报文的流入接口,仅能用于PREROUTING
、INPUT
及FORWARD
链上;[!] -o, --out-interface IFACE
:数据报文的流出接口;仅能用于FORWARD
、OUTPUT
、POSTROUTING
链上;
!
表示可做范围的取反操作。
ping
命令默认使用的就是 icmp 协议。
要注意这里的-s
指定的源 IP 地址和-d
指定的目标 IP 地址是相对报文流向而言的:
- 以外部的请求报文经过本机
INPUT
链为例,此时发起请求的主机的 IP 就是源 IP,而本机 IP 则是目标 IP;- 以本机的请求报文经过本机
OUTPUT
链为例,此时发起请求的本机的 IP 就是源 IP,而目标主机的 IP 则是目标 IP;
下面是使用基本匹配规则的几个案例。
例 1:允许目标主机为本机(10.0.1.200)的 tcp 报文通过。
$ iptables -t filter -A INPUT -d 10.0.1.200 -p tcp -j ACCEPT
$ iptables -L -nv
Chain INPUT (policy ACCEPT 1 packets, 69 bytes)
pkts bytes target prot opt in out source destination
55 5164 ACCEPT tcp -- * * 0.0.0.0/0 10.0.1.200
...
例 2:允许本机(10.0.1.200)发出的任意 tcp 报文通过。
$ iptables -t filter -A OUTPUT -s 10.0.1.200 -p tcp -j ACCEPT
$ iptables -L -n
...
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- 10.0.1.200 0.0.0.0/0
例 3:仅允许目标主机为本机(10.0.1.200)tcp 报文和本机发出的任意 tcp 报文通过,其它报文一致丢弃。
$ iptables -t filter -A INPUT -d 10.0.1.200 -p tcp -j ACCEPT
$ iptables -t filter -A OUTPUT -s 10.0.1.200 -p tcp -j ACCEPT
$ iptables -t filter -P INPUT DROP
$ iptables -t filter -P OUTPUT DROP
$ iptables -t filter -P FORWARD DROP
这里首先定义了两条可放行的规则,然后修改 filter 表的所有链默认处理动作为丢弃。
注意这里命令的执行顺序哦,如果你此时使用 ssh 远程连接主机,并且先修改了默认的处理动作为丢弃,那么就悲催了,此时你使用 ssh 发的报文已经被主机默认丢弃,连接就会断开了,你就没有机会设定放行的策略了。
在重要环境中做 iptables 配置一定要小心!!!可以先整个定时任务每隔几分钟清理规则,如果我们真的不小心被自己写的规则拦在外面了,只要等几分钟定时任务执行了我们就可以重新连接了。
例 4:在例 3 的基础上允许 icmp 协议通过。
$ iptables -A INPUT -d 10.0.1.200 -p icmp -j ACCEPT
$ iptables -A OUTPUT -s 10.0.1.200 -p icmp -j ACCEPT
可以使用
ping 10.0.1.200
命令测试。
例 5:在例 4 的基础上允许经过 eth0
接口的报文通过。
$ iptables -A INPUT -d 10.0.1.200 -i eth0 -j ACCEPT
$ iptables -A OUTPUT -s 10.0.1.200 -o eth0 -j ACCEPT
$ iptables -t filter -L -vn --line-numbers
Chain INPUT (policy DROP 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 619 61934 ACCEPT tcp -- * * 0.0.0.0/0 10.0.1.200
2 3 252 ACCEPT icmp -- * * 0.0.0.0/0 10.0.1.200
3 0 0 ACCEPT all -- eth0 * 0.0.0.0/0 10.0.1.200
Chain FORWARD (policy DROP 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
Chain OUTPUT (policy DROP 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 333 56121 ACCEPT tcp -- * * 10.0.1.200 0.0.0.0/0
2 3 252 ACCEPT icmp -- * * 10.0.1.200 0.0.0.0/0
3 0 0 ACCEPT all -- * eth0 10.0.1.200 0.0.0.0/0
定义扩展匹配规则
除了上述的基本匹配规则可以用于匹配,还有很多其他的条件可以用于匹配,这些条件泛称为扩展条件,这些扩展匹配规则,其实也是 netfilter 中的一部分,只是以模块的形式存在,如果想要使用这些条件,则需要依赖对应的扩展模块。
这些扩展模块文件的后缀为 .so
,可以通过 rpm -ql iptables
查看,下面列出部分:
/usr/lib64/xtables/libip6t_DNAT.so
/usr/lib64/xtables/libip6t_DNPT.so
/usr/lib64/xtables/libip6t_LOG.so
/usr/lib64/xtables/libip6t_MASQUERADE.so
/usr/lib64/xtables/libip6t_NETMAP.so
/usr/lib64/xtables/libip6t_REDIRECT.so
/usr/lib64/xtables/libip6t_REJECT.so
/usr/lib64/xtables/libip6t_SNAT.so
/usr/lib64/xtables/libipt_ah.so
/usr/lib64/xtables/libipt_icmp.so
/usr/lib64/xtables/libxt_tcp.so
/usr/lib64/xtables/libxt_udp.so
/usr/lib64/xtables/libxt_time.so
/usr/lib64/xtables/libxt_tos.so
/usr/lib64/xtables/libxt_u32.so
看起来有木有眼熟的感觉,这是因为 iptables 的 target (目标、动作)和匹配条件也是通过扩展模块来实现的。
如上列表中模块名称为大写的则是 target 扩展,小写的则是匹配规则的扩展。
这里我们又可以把扩展匹配规则又分为隐式扩展规则和显示扩展规则:
- 隐式扩展:无需我们明确指定扩展规则模块便可定义的扩展规则,如
-p {tcp|udp|icmp}
; - 显式扩展:需要我们通过
-m <扩展模块名>
明确指定使用的扩展规则模块才可使用的扩展规则;
下面列出一些扩展匹配规则常用的定义选项:
隐式扩展:
-p tcp:匹配 tcp 请求报文。
--dport PORT[-PORT]:目标端口,可以使单个端口或连续的多个端口;
--sport PORT[-PORT]:源端口,可以使单个端口或连续的多个端口;
--tcp-flags LIST1 LIST2:tcp 连接的标志位,检查 LIST1 中列出的所有标志位,存在于 LIST1 且存在于 LIST2 中的标志位值须为 1,存在于 LIST1 中但不存在于 LIST2 中的标志位值须为 0,可选标志位有 SYN、ACK、FIN、RST、PSH、URG。
--syn:相当于 --tcp-flags SYN,ACK,FIN,RST SYN,仅匹配 SYN 值为 1,ACK、FIN、RST 值为 0,RSH、URG 任意的报文,相当于匹配 TCP 三次握手的第一次;
-p udp:匹配 udp 请求报文。
--dport PORT[-PORT]:目标端口,可以使单个端口或连续的多个端口;
--sport PORT[-PORT]:源端口,可以使单个端口或连续的多个端口;
-p icmp:匹配 icmp 请求报文。
--icmp-type:用数字表示 icmp 报文类型,常用数字有 0 表示回送应答(echo-reply,ping 请求的响应),8 表示请求回送(echo-request,ping 请求);
显示扩展:
-m multiport:多端口扩展,以离散方式定义多端口匹配,最多指定 15 个端口。
[!] --source-ports,--sports port[,port|,port:port]...:指定多个源端口;
[!] --destination-ports,--dports port[,port|,port:port]...:指定多个目标端口;
[!] --ports port[,port|,port:port]...:指定多个端口,既能匹配源端口,也能匹配目标端口;
-m iprange:指明连续的 IP 地址范围时使用。
[!] --src-range from[-to]:指明连续的源 IP 地址范围;
[!] --dst-range from[-to]:指明连续的目标 IP 地址范围;
-m string:字符串扩展,可指定模式检查报文中是否出现了指定的字符串。
--algo {bm|kmp}:必须选项,指定字符串比对算法(bm = Boyer-Moore, kmp = Knuth-Pratt-Morris);
--from offset:从哪个位置开始匹配,以 --from 100 为例则是从第 101 个字符开始匹配,默认值为 0;
--to offset:指定结束匹配的位置,以 --to 100 为例,则是匹配到倒数第 101 个字符,默认值为 0;
[!] --string pattern:检查报文中是否存在匹配指定模式的内容;
[!] --hex-string pattern:以 16 进制格式检查报文中是否存在匹配指定模式的内容;
-m time:检查报文的到达时间是否在给定的时间范围内。
--datestart YYYY[-MM[-DD[Thh[:mm[:ss]]]]]:起始日期时间;
--datestop YYYY[-MM[-DD[Thh[:mm[:ss]]]]]:结束日期时间;
--timestart hh:mm[:ss]:起始时间;
--timestop hh:mm[:ss]:结束时间;
[!] --monthdays day[,day...]:仅在每月的指定日匹配,可能的值是 1 - 31,要注意的是,当指定 31 但月份没有 31 天时将不匹配,2 月的 28 天或 29 天也是如此;
[!] --weekdays day[,day...]:仅在给定的周几匹配,可选值有 Mon, Tue, Wed, Thu, Fri, Sat, Sun 或 1 - 7 之间的值,也可以使用两个字符的变体如 Mo,Tu 等;
-m connlimit:根据每客户端 IP(也可以是地址块)做并发连接数数量限制匹配。
--connlimit-upto n:匹配同一 IP 小于或等于 n 个连接数时指定相应动作,通常是 ACCEPT;
--connlimit-above n:匹配同一 IP 超过 n 个连接数时指定相应动作,通常是 REJECT 或 DROP;
--connlimit-mast prefix_length:指定地址块掩码;
--connlimit-saddr:指定源地址组;
--connlimit-daddr:指定目标地址组;
-m limit:基于令牌桶算法对收发报文的速率做限制(令牌桶中存在令牌时才可创建新连接)。
--limit rate[/second|/minute|/hour|/day]:指定每秒(或每分、或每小时、或每天)生成的令牌数;
--limit-burst number:指定令牌桶容量及令牌数初始值,默认值为 5;
-m state:状态扩展,根据连接追踪机制跟踪每一个连接请求来检查连接的状态。
[!] --state state:匹配指定状态的连接,可选值参见下方可追踪的连接状态;
这里的状态是 iptables 自己定义的状态,iptables 会在内核空间找一块内存来保存每个请求的源地址、目标地址、协议等信息,
iptables 会为每条信息进行倒计时,倒计时结束该条信息就会被清除失效。
相关文件:
/proc/sys/net/nf_conntrack_max:保存着追踪连接的最大数量,默认值为 65536,可直接修改调整;
/proc/net/nf_conntrack:记录着已经追踪到的所有连接,是连接追踪模板;
/proc/sys/net/netfilter/nf_conntrack_count:保存着已追踪的连接数量;
/proc/sys/net/netfilter/nf_conntrack_*_timeout_*:不同类型或协议的连接的追踪时长;
可追踪的连接状态:
NEW:新发出的请求,连接追踪模板中不存在此连接的相关信息条目,因此,将其识别为第一次发出的请求;
ESTABLISHED:NEW 状态后,连接追踪模板中为其建立的条目失效之前期间所进行的通信的状态;
RELATED:相关的连接,以 FTP 服务为例,有负责解析、执行命令的控制连接,当发送下载命令后,会建立一个实际下载的连接,即数据连接,它们就是相关的连接;
INVALIED:无法识别的连接;
要注意的是,有些类型的连接追踪是需要先装载模块才能使用的,如 FTP 连接追踪需要装载 nf_conntrack_ftp 模块。
CentOS 6 中直接使用
man iptables
即可查看到相关的扩展信息,而 CentOS 7 中需要使用man iptables-extenstions
。
详细 icmp 报文类型点击此处查看。
如果要让 iptables 在启动时自动装载某些模块,可以修改/etc/sysconfig/iptables-config
配置文件中的IPTABLES_MODULES
字段,将要装载的模块名放入值区域即可,多个模块以空格隔开。
下面是使用扩展匹配规则的一些案例。
例 1:放行对本机(10.0.1.200) SSH 服务(默认端口 22)的访问。
$ iptables -I INPUT -d 10.0.1.200 -p tcp --dport=22 -j ACCEPT
例 2:允许本机(10.0.1.200)ping 其它主机,对其它主机 ping 本机的报文不响应。
$ iptables -A INPUT -d 10.0.1.200 -p icmp --icmp-type 8 -j DROP
$ iptables -A OUTPUT -s 10.0.1.200 -p icmp --icmp-type 0 -j DROP
例 3:允许本机(10.0.1.201)的 22 和 80 端口接收并响应报文。
$ iptables -I INPUT -d 10.0.1.201 -p tcp -m multiport --dports 22,80 -j ACCEPT
$ iptables -I OUTPUT -s 10.0.1.201 -p tcp -m multiport --sports 22,80 -j ACCEPT
例 4:允许网段 10.0.1.1 - 10.0.1.120 访问本机(10.0.1.201)的 22、23、80 端口。
$ iptables -I INPUT -d 10.0.1.201 -p tcp -m multiport --dports 22:23,80 -m iprange --src-range 10.0.1.1-10.0.1.120 -j ACCEPT
$ iptables -I OUTPUT -s 10.0.1.201 -p tcp -m multiport --sports 22:23,80 -m iprange --dst-range 10.0.1.1-10.0.1.120 -j ACCEPT
例 5:拒绝响应报文中包含 Apache
的请求。
$ iptables -I OUTPUT -m string --algo bm --string "Apache" -j REJECT
例 6:允许在周末和周一访问。
$ iptables -I INPUT -m time --weekdays Sa,Su,Mon -j ACCEPT
例 7:允许在 2020 年 2 月 1 号到 2020 年 3 月 1 号访问。
$ iptables -I INPUT -m time --datestart 2020-2-1 --datestop 2020-3-1 -j ACCEPT
例 8:允许在每月的 22、23、24、25 日并且为周一的一天访问。
$ iptables -I INPUT -m time --weekdays Mon --monthdays 22,23,24,25 -j ACCEPT
例 9:每个客户端仅允许最多 2 个 SSH 连接。
$ iptables -A INPUT -p tcp --syn --dport 22 -m connlimit --connlimit-above 2 -j REJECT
例 10:限定每个 C 类网络(24 位掩码)的并行 HTTP 请求数量限制为 16 个
$ iptables -p tcp --syn --dport 80 -m connlimit --connlimit-above 16 --connlimit-mask 24 -j REJECT
例 11:限定初始令牌数量为 5,每 10 秒生成 1 个令牌。
$ iptables -A INPUT -d 10.0.1.201 -p icmp --icmp-type 8 -m limit --limit-burst 5 --limit 6/minute -j ACCEPT
$ iptables -A OUTPUT -s 10.0.1.201 -p icmp --icmp-type 0 -j ACCEPT
例 12:对 SSH 和 HTTP 服务放行 NEW
、ESTABLISHED
状态的请求,放行 ESTABLISHED
状态的响应。
$ iptables -I INPUT -d 10.0.1.201 -p tcp -m multiport --dports 22,80 -m state --state NEW,ESTABLISHED -j ACCEPT
$ iptables -I OUTPUT -s 10.0.1.201 -p tcp -m multiport --sports 22,80 -m state --state ESTABLISHED -j ACCEPT
例 13:优化例 12。
# 所有已建立连接直接放行。
$ iptables -I INPUT -m state --state ESTABLISHED -j ACCEPT
$ iptables -I OUTPUT -m state --state ESTABLISHED -j ACCEPT
# 放行 SSH 和 HTTP 服务的新连接。
$ iptables -I INPUT 2 -d 10.0.1.201 -p tcp -m multiport --dports 22,80 -m state --state NEW -j ACCEPT
例 14:在例 13 的基础上开放被动模式的 FTP 服务访问。
# 思路:匹配 21 端口的控制连接以及相关的数据连接即可。
$ iptables -L -n
Chain INPUT (policy DROP)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state ESTABLISHED
ACCEPT tcp -- 0.0.0.0/0 10.0.1.201 multiport dports 22,80 state NEW
Chain FORWARD (policy DROP)
target prot opt source destination
Chain OUTPUT (policy DROP)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state ESTABLISHED
# 1、装载支持 ftp 连接追踪的模块,路径为 /lib/modules/<内核版本>/kernel/net/netfilter/nf_conntrack_ftp,可使用 modinfo nf_conntrack_ftp 查看该模块信息,可使用 modprobe -l 查看可装载模块的列表,使用 lsmod 可以查看已装载的模块。
$ modprobe nf_conntrack_ftp
# 2、命令连接放行 NEW 和 ESTABLISHED 状态。
$ iptables -R INPUT 2 -d 10.0.1.201 -p tcp -m multiport --dports 21,22,80 -m state --state NEW -j ACCEPT
# 3、数据连接放行 RELATED 和 ESTABLISHED 状态(对数据连接的第一次请求的状态是 RELATED,后续的状态也是 ESTABLISHED)。
$ iptables -R INPUT 1 -m state --state ESTABLISHED,RELATED -j ACCEPT
例 15:添加规则开放被动模式的 FTP 服务访问。
# 放行请求报文。
$ iptables -A INPUT -d 10.0.1.201 -p tcp -dport 21 -m state --state NEW,ESTABLISHED -j ACCEPT
$ iptables -A INPUT -d 10.0.1.201 -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT
# 放行响应报文。
$ iptables -A OUTPUT -s 10.0.1.201 -p tcp -m state --state ESTABLISHED -j ACCEPT
黑白名单
前文中一直在强调一个概念:报文在经过 iptables 的链时,会匹配链中的规则,遇到匹配的规则时,就执行对应的动作,如果链中的规则都无法匹配到当前报文,则使用链的默认策略(默认动作),链的默认策略通常设置为 ACCEPT 或者 DROP。
那么,当链的默认策略设置为 ACCEPT 时,如果对应的链中没有配置任何规则,就表示接受所有的报文,如果对应的链中存在规则,但是这些规则没有匹配到报文,报文还是会被接受。
同理,当链的默认策略设置为 DROP 时,如果对应的链中没有配置任何规则,就表示拒绝所有报文,如果对应的链中存在规则,但是这些规则没有匹配到报文,报文还是会被拒绝。
所以,当链的默认策略设置为 ACCEPT 时,按照道理来说,我们在链中配置规则时,对应的动作应该设置为 DROP 或者 REJECT,为什么呢?
因为默认策略已经为 ACCEPT 了,如果我们在设置规则时,对应动作仍然为 ACCEPT,那么所有报文都会被放行了,因为不管报文是否被规则匹配到都会被 ACCEPT,所以就失去了访问控制的意义。
所以,当链的默认策略为 ACCEPT 时,链中的规则对应的动作应该为 DROP 或者 REJECT,表示只有匹配到规则的报文才会被拒绝,没有被规则匹配到的报文都会被默认接受,这就是“黑名单”机制。
同理,当链的默认策略为 DROP 时,链中的规则对应的动作应该为 ACCEPT,表示只有匹配到规则的报文才会被放行,没有被规则匹配到的报文都会被默认拒绝,这就是“白名单”机制。
如果使用白名单机制,我们就要把所有人都当做坏人,只放行好人。
如果使用黑名单机制,我们就要把所有人都当成好人,只拒绝坏人。
白名单机制似乎更加安全一些,黑名单机制似乎更加灵活一些。
那么,我们就来做一个简单的白名单吧,也就是说,只放行被规则匹配到的报文,其他报文一律拒绝,那么,我们先来配置规则。
假设,我想要放行 ssh 远程连接相关的报文,也想要放行 web 服务相关的报文,那么,我们在 INPUT 链中添加如下规则。
$ iptables -I INPUT -p tcp --dport 22 -j ACCEPT
$ iptables -I INPUT -p tcp --dport 80 -j ACCEPT
如上图所示,我们已经放行了特定的报文,只有上述两条规则匹配到的报文才会被放行,现在,我们只要将 INPUT 链的默认策略改为 DROP,即可实现白名单机制。
$ iptables -nL INPUT
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
$ iptables -P INPUT DROP
如上,我们已经将 INPUT 链的默认策略改为 DROP,并且已经实现了所谓的白名单机制,即默认拒绝所有报文,只放行特定的报文。
如果此时,我不小心执行了 iptables -F
操作,根据我们之前学到的知识去判断,我们还能够通过 ssh 工具远程到服务器上吗?
我想你已经判断出了正确答案,没错,按照上图中的情况,如果此时执行 iptables -F
操作,filter 表中的所有链中的所有规则都会被清空,而 INPUT 链的默认策略为DROP,所以所有报文都会被拒绝,不止 ssh 远程请求会被拒绝,其他报文也会被拒绝,这里可以自行实验一下。
这就是默认策略设置为 DROP 的缺点,在对应的链中没有设置任何规则时,这样使用默认策略为 DROP 是非常不明智的,因为管理员也会把自己拒之门外,即使对应的链中存在放行规则,当我们不小心使用 iptables -F
清空规则时,放行规则被删除,则所有数据包都无法进入,这个时候就相当于给管理员挖了个坑,所以,我们如果想要使用"白名单"的机制,最好将链的默认策略保持为 ACCEPT,然后将“拒绝所有请求”这条规则放在链的尾部,将“放行规则”放在前面,这样做,既能实现“白名单”机制,又能保证在规则被清空时,管理员还有机会连接到主机,示例如下。
$ iptables -P INPUT ACCEPT
如上所示,先将 INPUT 链的默认策略设置为 ACCEPT。
然后继续配置需要放行的报文的规则,如下图所示,当所有放行规则设置完成后,在 INPUT 链的尾部,设置一条拒绝所有请求的规则。
$ iptables -A INPUT -j REJECT
$ iptables -nL INPUT
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
上图中的设置,既将 INPUT 链的默认策略设置为了 ACCEPT,同时又使用了白名单机制,因为如果报文符合放行条件,则会被前面的放行规则匹配到,如果报文不符合放行条件,则会被最后一条拒绝规则匹配到,此刻,即使我们误操作,执行了 iptables -F
操作,也能保证管理员能够远程到主机上进行维护,因为默认策略仍然是 ACCEPT。
其实,在之前知识的基础上,理解所谓的黑白名单机制是很容易的,此处只是将最佳实践总结了一下。
评论区