CentOS 7.x 默认安装的防火墙是 firewalld,因此如果要使用 iptables 的话,最好禁用 firewalld:
~$ sudo systemctl disable firewalld
~$ sudo systemctl stop firewalld
iptables 安装包中带了如下一些命令行程序:
~$ rpm -ql iptables
...
/usr/sbin/ip6tables
/usr/sbin/ip6tables-restore
/usr/sbin/ip6tables-save
/usr/sbin/iptables
/usr/sbin/iptables-restore
/usr/sbin/iptables-save
...
iptables/ip6tables 命令定义的规则并不会持久化,重启系统之后就会丢失,注意不要被 iptables-save/ip6tables-save 的名字所欺骗,这两个命令并不会保存(持久化)规则,它们仅用于导出所有已定义的规则到命令行的标准输出流中:
~# iptables-save
# Generated by iptables-save v1.4.21 on Wed Jan 16 10:20:15 2019
*filter
:INPUT ACCEPT [1395:138576]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [743:70251]
COMMIT
# Completed on Wed Jan 16 10:20:15 2019
如果要持久化,可以使用 iptables-save/ip6tables-save 导出规则到文件中,然后在上电的时候使用 iptables-restore/ip6tables-restore 从文件中加载规则(不管最初添加规则是通过 -A
还是 -I
,所有保存的规则都转成 -A
形式)。
导出、导入规则的工作可以使用前面提到的命令手工进行,也可以安装 iptables-services 包,通过它提供的辅助脚本完成这些工作。同时比较方便的是,通过 iptables-services 包带的 systemd 服务还可以实现上电自动加载规则:
~$ yum install iptables-services
...
~$ rpm -ql iptables-services
/etc/sysconfig/ip6tables
/etc/sysconfig/iptables
/usr/lib/systemd/system/ip6tables.service
/usr/lib/systemd/system/iptables.service
/usr/libexec/initscripts/legacy-actions/ip6tables
/usr/libexec/initscripts/legacy-actions/ip6tables/panic
/usr/libexec/initscripts/legacy-actions/ip6tables/save
/usr/libexec/initscripts/legacy-actions/iptables
/usr/libexec/initscripts/legacy-actions/iptables/panic
/usr/libexec/initscripts/legacy-actions/iptables/save
/usr/libexec/iptables
/usr/libexec/iptables/ip6tables.init
/usr/libexec/iptables/iptables.init
保存规则可以使用 sysv 脚本:
~# service iptables save
iptables: Saving firewall rules to /etc/sysconfig/iptables:[ OK ]
~# service ip6tables save
ip6tables: Nothing to save. [WARNING]
也可以直接使用 sysv 脚本所封装的底层脚本:
~# /usr/libexec/iptables/iptables.init save
iptables: Saving firewall rules to /etc/sysconfig/iptables:[ OK ]
~# /usr/libexec/iptables/ip6tables.init save
ip6tables: Nothing to save. [WARNING]
规则保存在如下的文件中:
/etc/sysconfig/ip6tables
/etc/sysconfig/iptables
注意 sysv 脚本仅提供了 save 命令,systemd 脚本仅提供了 start/stop/reload 命令(systemctl status iptables.service
/ ip6tables.service
呈现的是 systemd 服务的状态,而不是底层 iptables 规则)。
如果要实现规则的 stop/reload/status/restart 等完全控制,可以使用 /usr/libexec/iptables/iptables.init 或者 /usr/libexec/iptables/ip6tables.init 底层脚本,当然也可以直接使用最原始的 iptables-save/ip6tables-save、iptables-restore/ip6tables-restore 命令。
iptables 规则
可以使用 iptables/ip6tables 命令行工具定义(操作)防火墙规则。
注:由于 iptables 与 ip6tables 在规则定义上并没有本质差异,后文不再区分 iptables/ip6tables,命令也统一以 iptables 作为示例。
需要注意的是,iptables 命令添加的规则与 ip6tables 命令添加的规则是完全独立的,如果系统上同时存在 IPv4 地址和 IPv6 地址,那么即使是针对同一个端口的保护也需要同时使用 iptables 和 ip6tables 分别添加规则。
此外 IPv6 有大量的 ICMP 报文交互,因此需要注意特别添加 ICMP 相关的规则。
iptables 顾名思义,是表(table)的集合,使用 iptables 命令定义规则时需要通过 -t / --table
参数指定需要操作的表,总共有 filter
, nat
, mangle
, raw
, security
5 张表,而我们通常操作的都是 filter
表,因此如果在 iptables 命令行上不通过 -t / --table
参数显示指定,将默认使用 filter
这张表,本文的内容也仅限于该表。
查看规则
iptables -L [chain]
-L, --list
iptables -S [chain]
-S, --list-rules
注意前面提到的 -t / --table
参数,由于这里没有显式指定,因此查询的是默认的 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
INPUT
(入站规则)/FORWORD
(路由转发规则)/OUTPUT
(出站规则) 是 filter
表内置(built-in)的规则组(chain),也可以通过 iptables -N
/ iptables --new-chain
命令新建用户自定义的规则组用于 -j
/ -g
参数,规则都定义在规则组中,因此增删规则时需要显式指定。
防火墙策略(policy)或者规则(rule),这两个名词通常混用,但在 iptables 里策略即默认规则,当一个规则组中所有规则从上至下依次查找之后如果仍未能找到匹配的规则,则使用该默认规则,如上面默认 INPUT/FORWARD/OUTPUT
的策略都是 ACCEPT
,即默认放行报文(另一个选项是 DROP
,即丢弃报文)。
-S, --list-rules
以 iptables-save 的形式列出规则:
~# iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -p icmp -j ACCEPT
修改策略
iptables -P chain target
-P, --policy
Linux 机器开启路由转发功能需要启用如下选项:
~# sysctl net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
~# cat /proc/sys/net/ipv4/ip_forward
1
~# sysctl net.ipv6.conf.all.forwarding=1
net.ipv6.conf.all.forwarding = 1
~# cat /proc/sys/net/ipv6/conf/all/forwarding
1
但服务器通常都不会使用该功能,因此我们一般在防火墙中将路由转发规则(FORWARD
)配置成默认 DROP
:
~# iptables --policy FORWARD DROP
~# iptables --list
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy DROP)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
然后通常将入站规则(INPUT
)配置成默认 DROP
(即拒绝所有的外部报文),出站规则(OUTPUT
)配置成默认 ACCEPT
(即允许所有从本机发起的报文)。
配置策略为 DROP
时要特别小心,如果是使用 SSH 登陆系统进行配置,且没有显式定义允许 SSH 报文的规则,那么一定不要随意将 INPUT/OUTPUT
配置成 DROP
,否则 SSH 连接会断!
删除所有规则
iptables -F [chain]
-F, --flush
当开始一个新系统的配置,或者丢弃所有以前配置的规则时,可以使用该命令,注意该命令只删除规则,不会将策略(policy)重置为默认值。
追加规则
iptables -A chain rule-specification
-A, --append
~# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
~# iptables -A INPUT -p tcp --dport 22 -j ACCEPT
~# iptables -P INPUT DROP
~# iptables -L --line-numbers
Chain INPUT (policy DROP)
num target prot opt source destination
1 ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
2 ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
Chain FORWARD (policy ACCEPT)
num target prot opt source destination
Chain OUTPUT (policy ACCEPT)
num target prot opt source destination
在指定位置插入规则
iptables -I chain rulenum rule-specification
-I, --insert
~# iptables -I INPUT 1 -p tcp --dport 23 -j ACCEPT
~# iptables -L --line-numbers -n
Chain INPUT (policy DROP)
num target prot opt source destination
1 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:23
2 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
3 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
Chain FORWARD (policy ACCEPT)
num target prot opt source destination
Chain OUTPUT (policy ACCEPT)
num target prot opt source destination
修改指定位置的规则
iptables -R chain rulenum rule-specification
-R, --replace
~# iptables -R INPUT 1 -p tcp --dport 24 -j ACCEPT
~# iptables -L --line-numbers -n
Chain INPUT (policy DROP)
num target prot opt source destination
1 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:24
2 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
3 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
Chain FORWARD (policy ACCEPT)
num target prot opt source destination
Chain OUTPUT (policy ACCEPT)
num target prot opt source destination
删除指定位置规则
iptables -D chain rulenum
-D, --delete
~# iptables -D INPUT 1
~# iptables -L --line-numbers -n
Chain INPUT (policy DROP)
num target prot opt source destination
1 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
2 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
Chain FORWARD (policy ACCEPT)
num target prot opt source destination
Chain OUTPUT (policy ACCEPT)
num target prot opt source destination
注意:上面需要用到 rulenum 参数的命令,都是可以先通过 iptables -L --line-numbers
命令查询得到已有规则的编号,切记一旦规则进行增删,已有规则的序号就会发生变化,一定不要复用 iptables -L --line-numbers
命令的结果!
-n / --numeric
选项与 Linux 下大多数网络相关的工具中的 -n
选项类似,即不要对 IP 地址、端口等进行任何名字转义,直接使用数字方式进行输出。
删除指定规则
iptables -D chain rule-specification
-D, --delete
可以不需要使用规则编号,直接删除规则:
~# iptables -A OUTPUT -p tcp -m tcp --sport 20 -j DROP
~# iptables -D OUTPUT -p tcp -m tcp --sport 20 -j DROP
给规则增加注释
使用 comment 模块可以给 iptables 规则增加注释:
~# iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW -m comment --comment 'nginx'
~# iptables -L -nv | grep 80
0 0 tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 ctstate NEW /* nginx */
规则匹配定义
即上面命令中的 rule-specification
字段的定义。
一个完整的匹配规则可能包含如下的所有字段:
[[!] -i name] [[!] -o name] [[!] -p protocol] [[!] -s address/[mask][,...]] [[!] -d address[/mask][,...]] [[-m name [module-options...]],...] [-j target | -g chain]
-4, --ipv4
-6, --ipv6
-i, --in-interface
-o, --out-interface
-p, --protocol
-s, --source, --src
-d, --destination, --dst
-m, --match
-j, --jump
-g, --goto
各选项解释如下:
-4 / -6
,未在上述完整的匹配规则中体现,因为仅用于 iptables-restore / ip6tables-restore 命令,匹配规则中 ipv4 / ipv6 的差异应直接由命令行 iptables / ip6tables 自身进行区分;
-i / -o
,报文接收 / 发送所在的网口,本地环回口为 lo, -i
仅适用于 INPUT
, FORWARD
, PREROUTING
规则组,-o
仅适用于 OUTPUT
, FORWARD
, POSTROUTING
规则组;
如果使用 -i / -o
指定了网口,则 iptables -L 查看是需要加上 -v
参数才能把网口显示出来,因此平时查看规则时建议使用 iptables -L [chain] -n -v
;
-p
,报文协议类型,常见的包括 tcp
, udp
, icmp
, icmp6
,all
用于表示所有协议类型,如果不指定 -p
选项,则默认为 all
,更多协议类型可以参考 /etc/protocols;
-s / -d
,报文 IP 地址,可以是一个独立的 IP 地址,一个网段,多个地址/网段之间使用英文逗号(,
)分隔,如果指定多个地址/网段会被 iptables 命令解析成多条规则;
-m
,指定扩展模块,所有的模块及其选项可以通过 man iptables-extensions
手册页进行查看,常用的模块包括:conntrack
, state
, tcp
, udp
,一些比较可能有用的包括:addrtype
, connlimit
, iprange
, limit
, multiport
, pkttype
, quota
等;
state 模块 --state
选项允许的状态是 conntrack 模块 --ctstate
选项允许的状态的子集,常用的状态包括:NEW
, ESTABLISHED
, RELATED
;
状态的参数控制(特别是 UDP 流)可以参考 sysctl -a | grep net.netfilter
各系统配置参数(即 /proc/sys/net/netfilter/
);
三个状态 NEW
, ESTABLISHED
, RELATED
,iptables-extensions man 手册页的解释如下,更多信息可以阅读[4]:
NEW The packet has started a new connection or otherwise associated with a connection which has not seen packets in both directions.
ESTABLISHED The packet is associated with a connection which has seen packets in both directions.
RELATED The packet is starting a new connection, but is associated with an existing connection, such as an FTP data transfer or an ICMP error.
关于 NEW
的潜在问题可以阅读 [5];
关于 conntrack
的潜在问题以及 conntrack 工具可以阅读 [6][7];
通过 -p, --protocol
选项指定协议类型为 tcp
时会默认启用 tcp
模块,不需要要在规则中通过 -m, --match
选项显式启用 tcp 模块,但是一旦显式启用 tcp
模块,则必须通过 -p, --protocol
显式指定协议类型为 tcp
;
udp
模块的使用与 tcp
类似;
tcp/udp
模块常用的选项包括 [!] --sport port[:port]
, [!] --dport port[:port]
,连续的端口使用英文冒号(:
)进行分隔,也可以使用 multiport
扩展模块定义更复杂的端口规则;
--sport, --source-port
--dport, --destination-port
-j
,报文的下一步处理,可以是特殊值 ACCEPT
, DROP
, RETURN
,可以是用户自定义的规则组,也可以是 iptables-extensions 中定义的 TARGET EXTENSIONS
;
ACCEPT
和 DROP
在配置规则组(如 filter 表中的 INPUT
, OUTPUT
, FORWARDING
)策略(policy)时已经提到过,ACCEPT
即允许该报文接收/发送,DROP
即丢弃该报文;
内置(built-in)规则组中的规则如果 target 是 RETURN
,则该报文的处理结果由策略决定,要么 ACCEPT
,要么 DROP
;
用户自定义规则组中的规则如果 target 是 RETURN
,则停止当前规则组中规则的匹配,返回至调用者规则所在的规则组的下一条规则继续匹配;
常见的扩展 target 包括:AUDIT
, DNAT
, MASQUERADE
, REJECT
, SNAT
,其中 REJECT
与 DROP
唯一的差异在于 REJECT
还会发送 ICMP
报文告知错误原因(虽然这个错误是 iptables 配置的);
-g
,针对匹配的报文跳转到用户自定义的规则组做进一步处理,-j
和 -g
跳转到自定义规则时的处理方式有明显的差异,请参考后文 “选项 -j / -g 区别” 一节;
规则示例
前文提到过,在使用 SSH 登陆的情况下,不要随意将入站和出站规则的策略配置成 DROP
,下面以放行 SSH 报文为基础,以实例的形式介绍 iptables 的配置流程和规则定义。
- 首先将
INPUT
和OUTPUT
的策略配置成ACCEPT
,即放行所有报文;
~# iptables -P INPUT ACCEPT
~# iptables -P OUTPUT ACCEPT
这样 SSH 连接就不会受到 iptables 的影响而断掉,后面我们将修改 INPUT
的策略为 DROP
;
此外由于我们的服务器不会用来做路由器,因此,将 FORWARD
的策略配置成 DROP
;
~# iptables -P FORWARD DROP
- 删除所有已有的规则,从头开始定义规则;
~# iptables -F
注意前面提到的删除规则不会重置配置的策略
- 允许新建入站的 SSH 连接;
~# iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -j ACCEPT
- 允许已建立连接关系的 SSH 入站报文(这就是通常所谓的状态防火墙,而不是纯粹的包过滤防火墙);
~# iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state ESTABLISHED -j ACCEPT
- 此时可以安全的(即不会导致 SSH 连接中断)将
INPUT
策略配置为DROP
;
~# iptables -P INPUT DROP
- 很多应用都需要使用 127.0.0.1 之类的环回地址,因此通常需要允许 lo 网口的流量;
~# iptables -A INPUT -i lo -j ACCEPT
由于 OUTPUT
的策略为 ACCEPT
,因此这里只用为 INPUT
添加规则;
- 为了示例的完整性,我们将
OUTPUT
的策略也配置为DROP
,但在此配置之前,必须允许已建立连接关系的 SSH 出站报文;
~# iptables -A OUTPUT -p tcp -m tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
~# iptables -P OUTPUT DROP
注意此规则指定的报文源端口为 22,前面入站的规则中指定的是报文目的端口为 22;
前面 3, 4, 7 就实现了允许入向的 SSH 连接;
- 由于已经将
OUTPUT
策略配置成DROP
,因此前面为环回地址配置的规则还需要显式允许出站的流量;
~# iptables -A OUTPUT -o lo -j ACCEPT
- 允许对外的 SSH 连接;
~# iptables -A OUTPUT -p tcp -m tcp --dport 22 -m state --state NEW -j ACCEPT
~# iptables -A OUTPUT -p tcp -m tcp --dport 22 -m state --state ESTABLISHED -j ACCEPT
~# iptables -A INPUT -p tcp -m tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
- 允许对外的 ping;
~# iptables -A OUTPUT -p icmp -m icmp --icmp-type ping -j ACCEPT
~# iptables -A INPUT -p icmp -m icmp --icmp-type pong -j ACCEPT
- 允许入向的 ping;
~# iptables -A INPUT -p icmp -m icmp --icmp-type ping -j ACCEPT
~# iptables -A OUTPUT -p icmp -m icmp --icmp-type pong -j ACCEPT
总结前面的命令如下,实现的效果就是默认阻止任何报文的入站和出站,仅开放 SSH、ping 业务以及本地环回口的报文:
~# iptables -P INPUT ACCEPT
~# iptables -P OUTPUT ACCEPT
~# iptables -P FORWARD DROP
~#
~# iptables -F
~#
~# iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -j ACCEPT
~# iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state ESTABLISHED -j ACCEPT
~# iptables -P INPUT DROP
~#
~# iptables -A INPUT -i lo -j ACCEPT
~#
~# iptables -A OUTPUT -p tcp -m tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
~# iptables -P OUTPUT DROP
~#
~# iptables -A OUTPUT -o lo -j ACCEPT
~#
~# iptables -A OUTPUT -p tcp -m tcp --dport 22 -m state --state NEW -j ACCEPT
~# iptables -A OUTPUT -p tcp -m tcp --dport 22 -m state --state ESTABLISHED -j ACCEPT
~# iptables -A INPUT -p tcp -m tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
~#
~#
~# iptables -A OUTPUT -p icmp -m icmp --icmp-type ping -j ACCEPT
~# iptables -A INPUT -p icmp -m icmp --icmp-type pong -j ACCEPT
~#
~# iptables -A INPUT -p icmp -m icmp --icmp-type ping -j ACCEPT
~# iptables -A OUTPUT -p icmp -m icmp --icmp-type pong -j ACCEPT
iptables -L -n -v
显示的规则列表如下:
~# iptables -L -nv
Chain INPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
1 60 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 state NEW
243 16645 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 state RELATED,ESTABLISHED
0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
22 3997 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp spt:22 state RELATED,ESTABLISHED
1 84 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 0
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 8
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
134 12693 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp spt:22 state RELATED,ESTABLISHED
0 0 ACCEPT all -- * lo 0.0.0.0/0 0.0.0.0/0
1 60 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 state NEW
26 4445 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 state RELATED,ESTABLISHED
1 84 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 8
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 0
配置完备的防火墙规则,需要非常仔细的设计,而且由于规则的匹配是从上至下,因此还需要考虑报文处理效率的问题[8];
基于应用的防火墙配置会比单纯的包过滤规则更简单,但是 iptables 并不支持 :( [9];
给服务器简单配置防火墙的思路
- 配置默认策略
~# iptables -P INPUT DROP
~# iptables -P FORWARD DROP
~# iptables -P OUTPUT ACCEPT
- 作为服务端允许客户端接入
~# iptables -A INPUT -p tcp -m tcp --dport <svc port> -m state --state NEW -j ACCEPT
- 允许客户端的入向流量,以及允许自身作为客户端时服务端返回的流量
~# iptables -A INPUT -p tcp -m tcp --dport <svc port> -m state --state ESTABLISHED -j ACCEPT
~# iptables -A INPUT -p tcp -m tcp --sport <svc port> -m state --state ESTABLISHED -j ACCEPT
-
如果服务是 udp 业务,与上面 tcp 业务类似,同样使用 state 模块允许 udp 端口的流量
-
此外把 lo 的流量放开
~# iptables -A INPUT -i lo -j ACCEPT
- 然后放开一些如 ping 之类的非 tcp / udp 流量
~# iptables -A INPUT -p icmp -m icmp --icmp-type pong -j ACCEPT
~# iptables -A INPUT -p icmp -m icmp --icmp-type ping -j ACCEPT
最后通过 multiport
模块合并一些规则。
其中第 3 步除非是对安全有严格要求的系统,否则一般会去掉 --sport
的指定,而直接使用如下的规则[13][14][15]:
~# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
或者:
~# iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT
选项 -j / -g 区别
-j
/ -g
的参数都可以是自定义规则组,但两者得到处理有非常大的不同:
-
-j
,如果报文在自定义规则组中没能得到处理,将回到 caller 规则组中的下一条规则继续处理,类似于 C/C++ 中的函数调用; -
-g
,如果报文在自定义规则组中没能得到处理,将一直向上返回到非-g
类型 caller 规则组中的下一条规则继续处理,类似于 C/C++ 中的函数调用之后紧跟一条 return 语句;
下面以一台具有 192.168.20.41 和 192.168.21.41 两个 IP 地址的机器为例进行说明,请参考其中的注释。
ping 192.168.20.41 通,ping 192.168.21.41 不通
iptables -P INPUT ACCEPT
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
iptables -F
iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state ESTABLISHED -j ACCEPT
iptables -P INPUT DROP
iptables -X ceph-outer 2> /dev/null || true
iptables -X ceph-inner 2> /dev/null || true
iptables -N ceph-outer
iptables -N ceph-inner
iptables -A ceph-outer -p icmp -g ceph-inner
# 这里存在类似 C/C++ 的 return 语句
# 因此,下面的规则没有机会匹配到 ceph-inner 未处理的报文,返回到 caller 规则组 INPUT 继续处理
iptables -A ceph-outer -p icmp -j ACCEPT
iptables -A ceph-inner -d 192.168.20.41/32 -p icmp -j ACCEPT
iptables -A INPUT -p icmp -g ceph-outer
# 这里存在类似 C/C++ 的 return 语句
# 因此,下面的这条规则没有机会匹配到 ceph-inner 和 ceph-outer 未处理的报文,报文的继续处理由 INPUT 的策略控制,即 DROP
iptables -A INPUT -p icmp -j ACCEPT
ping 192.168.20.41 通,ping 192.168.21.41 通
iptables -P INPUT ACCEPT
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
iptables -F
iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state ESTABLISHED -j ACCEPT
iptables -P INPUT DROP
iptables -X ceph-outer 2> /dev/null || true
iptables -X ceph-inner 2> /dev/null || true
iptables -N ceph-outer
iptables -N ceph-inner
iptables -A ceph-outer -p icmp -g ceph-inner
# 这里存在类似 C/C++ 的 return 语句
# 因此,下面的这条规则没有机会匹配到 ceph-inner 未处理的报文,返回到 caller 规则组 INPUT 继续处理
iptables -A ceph-outer -p icmp -j ACCEPT
iptables -A ceph-inner -d 192.168.20.41/32 -p icmp -j ACCEPT
iptables -A INPUT -p icmp -j ceph-outer
# ceph-inner 和 ceph-outer 未处理的报文匹配到下面的这条规则,即 ACCEPT
iptables -A INPUT -p icmp -j ACCEPT
ping 192.168.20.41 通,ping 192.168.21.41 通
iptables -P INPUT ACCEPT
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
iptables -F
iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state ESTABLISHED -j ACCEPT
iptables -P INPUT DROP
iptables -X ceph-outer 2> /dev/null || true
iptables -X ceph-inner 2> /dev/null || true
iptables -N ceph-outer
iptables -N ceph-inner
iptables -A ceph-outer -p icmp -j ceph-inner
# ceph-inner 未处理的报文匹配到下面的这条规则,即 ACCEPT
iptables -A ceph-outer -p icmp -j ACCEPT
iptables -A ceph-inner -d 192.168.20.41/32 -p icmp -j ACCEPT
iptables -A INPUT -p icmp -g ceph-outer
# 这里存在类似 C/C++ 的 return 语句
# 但由于 ceph-outer 已经匹配到了 ceph-inner 未处理的报文,因此即使下面的这条规则规则没有机会匹配也无所谓
iptables -A INPUT -p icmp -j ACCEPT
nftables[10][11]
Linux 内核从 3.13 版本(2014 年 1 月 19 日)引入了 nftables 框架用于取代原有的 {ip,ip6,arp,eb}tables 等多个框架,其配置工具 nft 也将取代原有的 {ip,ip6,arp,eb}tables 等多个工具。
参考文档
[1] iptables 手册页
man iptables
man iptables-extensions
[2] IPTables
https://wiki.centos.org/HowTos/Network/IPTables
[3] What’s the difference between iptables “state” and “ctstate”?
https://superuser.com/questions/1071656/whats-the-difference-between-iptables-state-and-ctstate
[4] The state machine
https://www.frozentux.net/iptables-tutorial/chunkyhtml/c1276.html
[5] State NEW packets but no SYN bit set
https://www.linuxtopia.org/Linux_Firewall_iptables/x6193.html
[6] Caveats about Linux connection tracking and high traffic servers
https://i-admin.blogspot.com/2014/02/caveats-about-linux-connection-tracking.html
[7] CONNTRACK
http://conntrack-tools.netfilter.org/conntrack.html
[8] When using iptables firewall rules, why assert NEW state on all allowed ports?
[9] create iptables rule per process/service
https://stackoverflow.com/questions/4314163/create-iptables-rule-per-process-service
[10] nftables
https://en.wikipedia.org/wiki/Nftables
[11] nftables
https://wiki.archlinux.org/index.php/nftables
[12] A Deep Dive into Iptables and Netfilter Architecture
[13] iptables: difference between NEW, ESTABLISHED and RELATED packets
[14] Is accepting RELATED,ESTABLISHED for all sources in iptables considered “too open”?
[15] How to Make a Linux Stateless Firewall for Performance and Resilience
https://strongarm.io/blog/linux-stateless-firewall/
[16] nf_conntrack: table full, dropping packet
最后修改于 2019-02-03