iptables工作原理及iptables命令行使用介绍
iptables原理
iptables中的五链
实际上,iptables 只是一个操作 Linux 内核 Netfilter 子系统的“界面”。顾名思义,Netfilter 子系统的作用,就是 Linux 内核里挡在“网卡”和“用户态进程”之间的一道“防火墙”。它 们的关系,可以用如下的示意图来表示:
图片来自张磊极客时间专栏(侵删)
可以看到,这幅示意图中,IP 包“一进一出”的两条路径上,有几个关键的“检查点”,它们 正是 Netfilter 设置“防火墙”的地方。在 iptables 中,这些“检查点”(每个检查点都可以设置iptables规则对数据包进行过滤或修改)被称为:链 (Chain)。这是因为这些“检查点”对应的 iptables 规则,是按照定义顺序依次进行匹配 的。这些“检查点”的具体工作原理,可以用如下所示的示意图进行描述:
可以看到,当一个 IP 包通过网卡进入主机之后,它就进入了 Netfilter 定义的流入路径(Input Path)里。在这个路径中,IP 包要经过路由表路由来决定下一步的去向。而在这次路由之前,Netfilter 设 置了一个名叫 PREROUTING 的“检查点”。在 Linux 内核的实现里,所谓“检查点”实际上 就是内核网络协议栈代码里的 Hook(比如,在执行路由判断的代码之前,内核会先调用 PREROUTING 的 Hook)。
而在经过路由之后,IP 包的去向就分为了两种:
- 第一种,继续在本机处理;
- 第二种,被转发到其他目的地。
数据包在Linux内核的流转过程
- 当一个数据包进入网卡时,数据包首先进入PREROUTING链, 内核根据数据包目的IP判断是否需要转发出去。
- 如果数据包就是进入本机的,数据包就会沿着图继续向上层协议栈流动,这时候,数据包将继续向上层协议栈流动。在它进入传输层之前,Netfilter 会设置一个名叫 INPUT 的“检查点”。到这里,数据包流入路径(Input Path) 结束。接下来,这个 数据包通过传输层进入用户空间,交给用户进程处理。而处理完成后,用户进程会 通过本机发出返回的 数据包。这时候,这个数据包就进入了流出路径(Output Path)。此时,数据包首先还是会经过主机的路由表进行路由。路由结束后,Netfilter 就会设置一个名叫 OUTPUT 的“检查点”。然后,在 OUTPUT 之后,再设置一个名叫 POSTROUTING“检查点”。在流出路径设置两个检查点的原因见下方黄色字体。
- 如果数据包是要转发出去的,且内核允许转发,在这种情况下,这个 数据包不会进入传输层,而是会继续在网络层流动,从而进入到转发路径 (Forward Path)。在转发路径中,Netfilter 会设置一个名叫 FORWARD 的“检查点”。而在 FORWARD“检查点”完成后,IP 包就会来到流出路径。而转发的 IP 包由于目的地已经确定,它就不会再经过路由,也自然不会经过 OUTPUT,而是会直接来到 POSTROUTING“检 查点”。
上述五条链,其实就是五个检查点,那么为什么要设置这五个检查点呢?我猜是因为每个检查点针对的数据包的作用域不一样,如下表所示。
链名 | 作用域 |
---|---|
PREOUTING | 所有进入本机的数据包 |
INPUT | 继续在本机处理,向上层协议栈流入的数据包,交由本机进程处理 |
FORWARD | 被转发到其他目的地的数据包 |
OUTPUT | 经过本机进程处理流出的数据包 |
POSTROUTING | 所有流出本机的数据包(包括从从Forward Path流出的数据包以及从Output Path流出的数据包) |
POSTROUTING 的作用,其实就是上述两条路径(Output Path和Forward Path),最终汇聚在一起的“最终检查点”,对两条路径上的数据包进行统一的检查和处理。
**总结:**上文涉及到了三条路径Input Path、Output Path、Forward Path来详细说明数据包的流转过程,在这个流转过程中设置了一些检查点(chain),使得用户可以在这些检查点上设置一定的规则来将匹配到的数据包进行处理。
iptables的四表
建议将上图原图链接打开,放大观看。前文所讲的就是上图绿色的部分,也就是Network Layer中的iptables工作流程,每一个白色的“检查点”上,还有一个绿色的“标签”,比如:raw、 nat、filter 等等。在 iptables 里,这些标签叫作:表。比如,同样是 OUTPUT 这个“检查点”,filter Output 和 nat Output 在 iptables 里的语法和参数,就完全不一样,实现的功能也完全不同。
每个表的功能如下所示:
名称 | 功能 |
---|---|
filter | 一般的过滤功能,这个是默认的 table |
nat | 用于nat功能(端口映射,地址映射等),这个表格主要在进行来源与目的之 IP 或 port 的转换,与 Linux 本机较无关,主要与 Linux 主机后的局域网络内计算机较有相关 |
mangle | 主要功能是根据规则修改数据包的一些标志位,以便其他规则或程序可以利用这种标志对数据包进行过滤或策略路由。简单来讲就是给数据包打标签。 |
raw | 涉及到数据包的跟踪处理功能,设置raw时一般是为了不再让iptables做数据包的链接跟踪处理,即设置NOTRACK动作提高性能 |
raw表中所说的跟踪状态指的是被跟踪连接的四种不同状态有关的。它们分别是NEW,ESTABLISHED,RELATED和INVALID。具体请看参考文献,此处不再细说。
下图所示是Netfilter中表和链的对应关系。表的处理优先级:raw>mangle>nat>filter。
总结: iptables 表的作用,就是在某个具体的“检查点”(比如 Output)上,按顺序执行几个不同的检查动作(比如,先执行 nat,再执行 filter),在这些检查动作中包含了一系列的iptables规则,匹配到相应规则的数据包则会执行相应的处理动作。以上就是iptables中的四表五链,有错误,欢迎指正。
iptables命令掌握
iptables命令语法
iptables -t table command chain rules -j target
- table ------- 指定表名(raw表、mangle表、nat表、filter表)
- command ------- 对链的操作命令(-A:追加规则(最下面进行追加规则)、-I:插入(一般在相应的哪条规则前后插入))
- chain ------- 链名(prerouting链、forward链、input链、output链、postrouting链,以及若干自定义链)
- rules ------- 定义一系列的规则来选择匹配到的数据包,比如可以通过协议,端口号,等等来匹配过滤数据包。
- target ------- 对rules匹配到的数据包进行处理,比如接收请求,丢弃请求等等。
-j jump,指的是跳转到何种动作上。
table
表选项用于指定命令应用于哪个iptables内置表,iptables内置包括:filter表、nat表、mangle表和raw表
使用的参数为: -t + 表名,如果不使用-t参数,默认是使用filter表
command
- -P或–policy + <链名>: 定义默认策略
- -L或–list + <链名>: 查看iptables规则列表
- -A或–append + <链名>: 在规则列表的最后增加1条规则
- -I或–insert + <链名>: 在指定的位置插入1条规则
- -D或–delete + <链名> + number: 从规则列表中删除1条规则
- -R或–replace + <链名> + number: 替换规则列表中的某条规则
- -F或–flush + <链名> :清除所有制定的规则
- -X或–delete-chain + <用户自定义的链名>: 删除表中所有规则(注意:无法清空默认规则)
- -Z或–zero + <链名> :将表中数据包计数器和流量计数器归零
- -N或 --new-chain + <用户自定义的链名>:新建一个用户自定义的链,且链名必须跟内置那些链名不同
实例:
清除iptables规则:
iptables -F
#清除所有制定的规则
iptables -X
#清除用户自定义的chain
iptables -Z
#将所有流量统计归0
但是并非执行后就万事大吉了。你仍然需要检查规则是不是真的清空了,因为有的linux发行版上这个命令不会清除NAT表中的规则,此时只能手动清除:iptables -t NAT -F
chain
默认五条链
自定义链
rules
rules主要是制定一定的规则,匹配到符合规则的数据包,进行处理。
基本匹配条件:
匹配条件当中出现"!"是取反的意思
- -s --source + <源地址或子网>: 指定数据包匹配的源地址。
iptables -A OUTPUT -s 192.168.1.1
#指定该规则与源地址为192.168.1.1的数据包匹配。
iptables -A OUTPUT -s 192.168.0.0/24
#指定该规则与源地址为192.168.0.0/24子网下的网络包匹配
iptables -A OUTPUT -s ! 203.16.1.89
#指定该规则将与 除来自源地址 203.16.1.89 外的任何信息包匹配。
- -d --destination + <目标地址或子网>: 指定数据包匹配的目标地址
- -i --in-interface + <网络接口名>: 指定数据包从哪个网络接口进入,如ppp0、eth0和eth1等。注意:该参数只能用于INPUT、FORWARD、PREROUTING这三个链
- -o --out-interface + <网络接口名>: 指定数据包从哪块网络接口输出,如ppp0、eth0和eth1等。注意:该参数只应用于FORWARD、OUTPUT、POSTROUTING链
- -p --protocol + < 协议类型>: 指定数据包匹配的协议, 如tcp, udp, icmp, icmpv6, udplite,esp, ah, sctp等。
扩展匹配条件:
man iptables-extensions
查看帮助文档
隐式扩展
在使用-p选项指明了特定的协议时,无需再用-m选项 指明扩展模块的扩展机制,不需要手动加载扩展模块
- tcp协议的扩展选项
--source-port, --sport port[:port]:匹配报文源端口, 可为端口范围
--destination-port,--dport port[:port]:匹配报文目标 端口,可为范围
--tcp-flags mask comp
mask 需检查的标志位列表,用,分隔 例如 SYN,ACK,FIN,RST;
comp 在mask列表中必须为1的标志位列表,无指定则必须为0,用,分隔
实例:
--tcp-flags SYN,ACK,FIN,RST SYN
#表示要检查 的标志位为SYN,ACK,FIN,RST四个,其中SYN必须为1,余下的必须为0
- udp协议的扩展选项
--source-port, --sport port[:port]:匹配报文的 源端口;可以是端口范围
--destination-port,--dport port[:port]:匹配报 文的目标端口;可以是端口范围
显示扩展
必须使用-m选项指明要调用的扩展模块的扩展 机制,要手动加载扩展模块
-m matchname
学会使用帮助文档,由于扩展是很多的,不可能介绍完所有的,所以学会查询帮助文档是而非常有必要的。
#查看addrtype扩展的帮助文档
iptables -m addrtype --help
1.multiport扩展
iptables -A INPUT -s 172.16.0.0/16 -d 172.16.100.10 -p tcp -m multiport --dports 20:22,80 -j ACCEPT
#以离散方式定义多端口匹配,最多指定15个端口,用","分隔。
#上述命令中表明源地址为172.16.0.0/16,目标地址为172.16.100.10的数据包中,目的端口为20-22范围之间的以及80号端口,都接收。
#":"表示一个范围,比如20:22,表示是20到22之间的所有端口。
2.iprange扩展
--src-range from[-to] 源IP地址范围
--dst-range from[-to] 目标IP地址范围
#实例
iptables -A INPUT -d 172.16.100.10 -p tcp --dport 80 -m iprange --src-range 172.16.100.5172.16.100.10 -j DROP
#指明连续的(但一般不是整个网络)ip地址范围
3.mac扩展
#实例:
iptables -A INPUT -s 172.16.0.100 -j REJECT
#指明源MAC地址
4.string扩展
#对报文中的应用层数据做字符串模式匹配检测
--algo {bm|kmp}:字符串匹配检测算法
bm:Boyer-Moore
kmp:Knuth-Pratt-Morris
--from offset 开始偏移
--to offset 结束偏移
--string pattern:要检测的字符串模式
#实例
iptables -A OUTPUT -s 172.16.100.10 -d 0/0 -p tcp --sport 80 -m string --algo bm --string “google" -j REJECT
5.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...]
--weekdays day[,day...]
#实例:
iptables -A INPUT -s 172.16.0.0/16 -d 172.16.100.10 -p tcp --dport 80 -m time --timestart 14:30 --timestop 18:30 --weekdays Sat,Sun --kerneltz -j DROP
6.connlimit扩展
根据每客户端IP做并发连接数数量匹配,可防止CC(Challenge Collapsar挑战黑洞)攻击,通常分别与默认的拒绝或允许策略配合使用。
--connlimit-upto n:连接的数量小于等于n时匹配
--connlimit-above n:连接的数量大于n时匹配
#示例:
iptables -A INPUT -d 172.16.100.10 -p tcp --dport 22 -m connlimit --connlimit-above 2 -j REJECT
7.limit扩展
基于收发报文的速率做匹配 令牌桶过滤器
--limit rate[/second|/minute|/hour|/day]
--limit-burst number
示例:
iptables -I INPUT -d 172.16.100.10 -p icmp --icmptype 8 -m limit --limit 3/minute --limit-burst 5 -j ACCEPT
8.state扩展
根据”连接追踪机制“去检查连接的状态,较耗资源 ,状态有如下几种:
- NEW:新发出请求;连接追踪信息库中不存在此连接的 相关信息条目,因此,将其识别为第一次发出的请求
- ESTABLISHED:NEW状态之后,连接追踪信息库中为 其建立的条目失效之前期间内所进行的通信状态
- RELATED:新发起的但与已有连接相关联的连接,如: ftp协议中的数据连接与命令连接之间的关系
- INVALID:无效的连接,如flag标记不正确
- UNTRACKED:未进行追踪的连接,如raw表中关闭追踪
CentOS7 需要加载模块: modprobe nf_conntrack
--state state
#示例:
iptables -A INPUT -d 172.16.100.10 -p tcp -m multiport -dports 22,80 -m state --state NEW,ESTABLISHED -j ACCEPT
9.comment扩展
为任何规则添加注释(最多256个字符),主要是为了解释说明该规则。
iptables -A INPUT -i eth1 -m comment --comment "my local LAN"
target
target可以是一个"动作",target也能是一个"自定义链",当target为一个动作时,表示报文按照指定的动作处理,当target为自定义链时,表示报文由自定义链中的规则处理。具体见下文中自定义链的使用。
targetname | 解释说明 |
---|---|
ACCEPT | 接受数据包 |
DROP | 丢弃数据包 |
REDIRECT | 通过改变目标IP和端口,将接受的包转发至不同端口 --to-ports port[-port] |
SNAT | 源地址转换,即改变数据包的源地址。 |
DNAT | 目标地址转换,即改变数据包的目的地址。 |
MASQUERADE | MASQUERADE是用发送数据的网卡上的IP来替换源IP,因此,对于那些IP不固定的场合,比如拨号网络或者通过dhcp分配IP的情况下,就得用MASQUERADE。效果和SNAT相似。 |
LOG | 日志功能,将符合规则的数据包的相关信息记录在日志中,以便管理员的分析和排错 |
NOTRACK | 取消跟踪功能,一般用于在raw表设置,提高WEB服务器的效率。 |
常见问题
- SNAT 和 MASQUERADE 的区别:SNAT 是明确指定修改的源地址,而 MASQUERADE 会自动获取出口接口(根据路由表)的 IP 地址。性能方面比 SNAT 几乎忽略不计,而无需明确指定 IP 地址,所以在 DHCP 和 PPPOE 的动态 IP 环境下(也就是IP不固定的时候)使用特别方便。
iptables -t nat -A POSTROUTING -o $WAN -j MASQUERADE
iptables -t nat -A POSTROUTING -o $WAN -j SNAT --to-source $IP
- DNAT 和 REDIRECT 的区别:这组动作和上面的刚好相反,是用来修改目的地址的。DNAT 是明确指定修改的目的地址,而 REDIRECT 会把要转发的包的目的地址改写为入口接口的 IP 地址。
iptables -t nat -A PREROUTING -i $WAN -p tcp --dport 80 -j REDIRECT --to-ports 3128
iptables -t nat -A PREROUTING -i $WAN -p tcp --dport 80 -j DNAT --to-destination $IP --to-ports 3128
iptables命令案例
为数据包设置trace
实验环境(centos7)
监控所有相关icmp包的流转变化。
iptables -t raw -A OUTPUT -p icmp -j TRACE
iptables -t raw -A PREROUTING -p icmp -j TRACE
modprobe nf_log_ipv4
#加载所需模块儿
然后你就可以在/var/log/messages看到包追踪信息了。
关闭
删除掉TRACE规则即可:
iptables -t raw -D PREROUTING 1
开启路由转发功能
1.直接配置到内存中,但是只是当前生效
echo 1 > /proc/sys/net/ipv4/ip_forward
2.写到配置文件当中
cat <<EOF > /etc/sysctl.d/forward.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system
#加载/etc/sysctl.d/*.conf配置文件
#net.ipv4.ip_forward标识着是否转发,为1代表开启转发功能
#net.bridge.bridge-nf-call-iptables 标志着二层网桥的包是否被主机的iptables过滤,为1代表也就意味着二层的网桥在转发包时也会被iptables的FORWARD规则所过滤,为0即iptables不对bridge的数据进行处理。
设置自定义链
为什么还需要自定义链呢?
原因如下:
当默认链中的规则非常多时,不方便我们管理。
想象一下,如果INPUT链中存放了200条规则,这200条规则有针对httpd服务的,有针对sshd服务的,有针对私网IP的,有针对公网IP的,假如,我们突然想要修改针对httpd服务的相关规则,难道我们还要从头看一遍这200条规则,找出哪些规则是针对httpd的吗?这显然不合理。
所以,iptables中,可以自定义链,通过自定义链即可解决上述问题。
设置自定义链有以下几个步骤:
- 创建自定义链
- 在自定义链中配置规则
- 在默认链中引用自定义链
示例如下:
示例来自朱双印的博客,连接在文章下文,侵删
1.创建一条名为IN_WEB的自定义链。
2.在这条自定义链上设置一定的规则。
3.现在,自定义链中已经有了一些规则,但是目前,这些规则无法匹配到任何报文,因为我们并没有在任何默认链中引用它。既然IN_WEB链是为了针对web服务的入站规则而创建的,那么这些规则应该去匹配入站的报文,所以,我们应该用INPUT链去引用它。当然,自定义链在哪里创建,应该被哪条默认链引用,取决于实际的工作场景,因为此处示例的规则是匹配入站报文,所以在INPUT链中引用自定义链。
前文提到过,自定义链可以作为target进行跳转
这种自定义链的做法在K8s的网络模型中,以及service的实现方式上都有一定的体现。
配置NAT
nat表的target: SNAT MASQUERADE DNAT REDIRECT
SNAT:一般用于固定IP
--to-source [ipaddr[-ipaddr]][:port[-port]]
--random
#示例:
iptables -t nat -A POSTROUTING -s 10.0.1.0/24 ! – d 10.0.1.0/24 -j SNAT --to-source 172.18.100.6-172.18.100.9
MASQUERADE:用于动态ip环境中,如拨号网络
--to-ports port[-port]
--random
#示例:
iptables -t nat -A POSTROUTING -s 10.0.1.0/24 ! – d 10.0.1.0/24 -j MASQUERADE
DNAT:
--to-destination [ipaddr[-ipaddr]][:port[-port]]
#示例
iptables -t nat -A PREROUTING -s 0/0 -d 172.18.100.6 -p tcp --dport 80 -j DNAT --to-destination 10.0.1.22:8080
REDIRECT
使用REDIRECT动作可以在本机上进行端口映射,REDIRECT规则只能定义在PREROUTING链或者OUTPUT链中。
--to-ports port[-port]
#示例:
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080
#当别的机器访问本机的80端口时,报文会被重定向到本机的8080端口上。
iptables规则查看
iptables -L
#这种命令输出的
iptables-save
#该条命令会将iptables规则输出到标准输出,其输出的形式和当初添加的形式是一样的,这样就让熟悉iptables命令的人很好识别出来。
参考文献
-
张磊,极客时间专栏《深入剖析Kubernetes》
-
鸟哥linux私房菜