linux 防火墙
linux 防火墙
Netfilter
Netfilter是Linux 2.4内核引入的全新的包过滤引擎,位于Linux内核中的包过滤功能体系,基于内核控制,实现防火墙的相关策略。Netfilter 由一些数据包过滤表组成,这些表包含内核用来控制信息包过滤的规则集。Netfilter在数据包必须经过且可以读取规则的位置,设有5个控制关卡。这5个关卡处的检查规则分别放在5个规则链中叫钩子函数(hook functions)。也就是说5条链对应着数据包传输路径中的5个控制关卡,链中的规则会在对应的关卡检查和处理。任何一个数据包,只要经过本机,必然经过5个链中的某个或某几个。
Netfilter中的五个规则链
规则链 | 作用 |
---|---|
PREROUTING | 数据包刚进入网络接口之后,路由之前 |
INPUT | 数据包从内核流入用户空间 |
FORWARD | 在内核空间中,从一个网络接口进入,到另一个网络接口去。转发过滤。 |
OUTPUT | 数据包从用户空间流出到内核空间 |
POSTROUTING | 路由后,数据包离开网络接口前 |
链其实就是包含众多规则的检查清单,每一条链中包含很多规则。当一个数据包到达一个链时,系统就会从链中第一条规则开始检查,看该数据包是否满足规则所定义的条件。如果满足,系统就会根据该条规则所定义的方法处理该数据包;否则就继续检查下一条规则,如果该数据包不符合链中任何一条规则,系统就会根据该链预先定义的默认策略来处理数据包。五条链中最常用的是 INPUT 和 OUTPUT 链。因为,我们的主机一般都是判断该是否接收数据,而转发流量一般较少。
数据包的传输过程
- 当一个数据包进入网卡时,它首先进入PREROUTING链,内核根据数据包目的IP判断是否需要转送出去。
- 如果数据包就是进入本机的,它就会沿着图向下移动,到达INPUT链。数据包到了INPUT链后,任何进程都会收到它。本机上运行的程序可以发送数据包,这些数据包会经过OUTPUT链,然后到达POSTROUTING链输出。
- 如果数据包是要转发出去的,且内核允许转发,数据包就会如图所示向右移动,经过FORWARD链,然后到达POSTROUTING链输出。
可以看出,刚从网络接口进入的数据包尚未进行路由决策,还不知道数据要走向哪里,所以进出口处没办法实现数据过滤,需要在内核空间设置转发关卡、进入用户空间关卡和离开用户空间关卡。
iptables
iptables是用来管理防火墙的的工具,属于静态防火墙,我们通过 iptables 将过滤规则写入内核,然后 Netfilter 再根据规则进行过滤数据包。所以实际上iptables是通过调用 Netfilter 来进行防火墙管理的,它本身不具备过滤数据包的功能。iptables程序位于 /sbin/iptables
,配置文件位于 /etc/sysconfig/iptables
。在Rhel7之前,防火墙是用 iptables
iptables中也有和netfilter中一模一样的5种规则链,还多了4个规则表。规则表的作用是容纳各种规则链。规则表的划分依据是防火墙规则的作用。四个表中常用的是 filter 表。最常用的链是 INPUT 和 OUTPUT 链
不指定表名时,默认指定 filter 表
iptables中的四个规则表
规则表 | 作用 |
---|---|
raw表 | 确定是否对该数据包进行状态跟踪 kernel2.6之后加进去的 |
mangle表 | 为数据包设置标记 |
nat表 | 修改数据包中的源、目标ip或端口 |
filter表 | 确定是否放行该数据包(过滤) |
规则表之间的匹配顺序: raw –>mangle–>nat–>filter
规则链之间的顺序:
入站:PREROUTING –> INPUT
出站:OUTPUT–>POSTROUTING
转发:PREROUTING–>FORWARD–>POSTROUTING
规则链的匹配顺序:
按顺序依次检查, 匹配到了即停止(LOG策略例外)
若找不到相匹配的规则,则按该链的默认策略处理
数据包的常见控制类型:
- ACCEPT:允许通过
- DROP:直接丢弃,不给出任何回应
- REJECT:拒绝通过,必要时会给出提示
- LOG:记录日志信息,然后传给下一条规则继续匹配
iptables的基本语法
语法构成:iptables 【-t 表名】 选项 链名 条件 【-j 控制类型】
iptables [-t 表名] 管理选项 [链名] [匹配条件] [-j 控制类型]
1.不指定表名时,默认指filter表
2.不指定链名时,默认指表内的所有链
3.除非设置链的默认策略,否则必须指定匹配条件
4.选项、链名、控制类型使用大写字母,其余均为小写
- 不指定链名时,默认指定表内的所有链
- 除非设置链的默认策略,否则必须指定匹配条件
- 选项、链名、控制类型使用大写字母,其余均为小写
常用的控制类型
ACCEPT 允许数据包通过。
DROP 直接丢弃数据包,不给出任何回应信息。
REJECT 拒绝数据包通过,会给数据发送端一个响应信息。
SNAT 修改数据包的源地址。
MASQUERADE 伪装成一个非固定公网IP地址。
DNAT 修改数据包的目的地址。
PNAT 目标端口转换 端口修改
LOG 在/var/log/messages文件中记录日志信息,然后将数据包传递给下一条规则。LOG只是一种辅助动作,并没有真正处理数据包。
规则的匹配条件
通用匹配:可直接使用,不依赖于其他条件或扩展。包括网络协议、ip地址、网络接口等
- 协议匹配:-p 协议名
iptables -A INPUT -p icmp -j DROP
- 地址匹配:-s 源地址 、-d 目的地址
iptables -A INPUT -s 192.168.10.0/24 -j DROP
- 接口匹配:-i 入站网卡 、-o 出站网卡
iptables -A INPUT -i eth0 -p icmp -j DROP
隐含匹配:要求以特定的协议匹配作为前提,包括端口、TCP标记、ICMP类型等条件
- 端口匹配:–sport 源端口 、–dport 目的端口
iptables -A INPUT -p tcp --dprot 20:21 -j ACCEPT
- TCP标记匹配:–tcp-flags 检查范围 被设置的标记
- ICMP类型匹配:–icmp-type ICMP类型
显式匹配:要求以 “ -m 扩展模块” 的形式明确指出类型,包括多端口、MAC地址、IP范围、数据包状态等
- 多端口匹配:-m multiport –sport 源端口列表 -m multiport –dport 目的端口列表
iptables -A INPUT -p tcp -m multiport --dport 25,80,110,143 -j ACCEPT
- IP范围匹配:-m iprange –src-range IP范围
iptables -A FORWARD -p tcp -m iprange --src-range 192.168.4.21-192.168.4.28 -j ACCEPT
- MAC地址匹配: -m mac –mac-source MAC地址
iptables -A INPUT -m mac --mac-source 00:0c:29:c0:55:3f -j DROP
添加新的规则:
-A:在链的末尾追加一条规则
-I :在链的开头(或指定序号插入)一条规则
iptables -t filter -A INPUT -p tcp -j ACCEPT
iptables -A INPUT -p tcp -j ACCEPT
iptables -I INPUT -p udp -j ACCEPT
iptables -I INPUT 3 -p icmp -j ACCEPT
在filter表中的INPUT链中的第3条加入一条允许所有icmp协议的规则
删除,清空规则(暂时,重启失效)
-D:删除链内指定序号的一条规则
-F:清空所有的规则
iptables -D INPUT 3
iptables -t raw -F
iptables -F
查看规则列表
-L:列出所有的规则条目 (默认查看的是filter表)
-n:以数字形式显示地址、端口等信息 (地址用数字表示)
-v:以更详细的方式显示规则信息(显示比特流,发包的数量等信息)
–line-numbers:查看规则时,显示规则的序号
iptables -L
iptables -nvL
设置默认规则
-P:为指定的链设置默认规则
iptables -t nat -P OUTPUT ACCEPT
规则的备份和还原
导出( 备份规则):iptables-save > /tmp/xie/1.txt
//将iptables配置文件保存到 /tmp/xie/1.txt文件中
还原规则:iptables-restore < /tmp/xie/1.txt
规则永久生效:
iptables不是一个守护进程,我们修改只是当前的修改,重启服务或重启系统就会失效。要想使规则永久生效,需要保存规则: service iptables save ,使我们当前的配置保存到配置文件 /etc/sysconfig/iptables 中,然后重启服务或者重启主机,使规则加载到内存,才能使配置永久生效。防火墙的运行需要建立在网络配置正常的前提下。
services iptables start / stop / restart
开启/停止/重启 iptables服务
chkconfig --level 5 iptables on / off
iptables做本地端口转发
开启数据转发功能:/etc/sysctl.conf
设置 net.ipv4.ip_forward=1
1 | iptables -t nat -L #查看端口转发记录 |
做本地端口转发,将本地2222端口的流量转发给22端口
示例
SNAT
源地址转换 (Source Network Address Translation)
实现内网主机通过防火墙进行上网,需要使用SNAT(源地址转换POSTROUTING)
1 |
|
MASQUERADE
伪装
1 | 当外网源地址为动态获取的地址时,MASQUERADE可自行判断要转换为的外网地址 |
DNAT
目标地址转换 (Destination Network Address Translation)
实现外网主机通过防火墙访问内部主机80端口,需要通过DNAT(目标地址转换PREROUTING)
1 | 地址映射【DNAT】 |
PNAT
目标端口转换
1 | 端口映射【DNAT】 |
Firewalld
Firewalld自身并不具备防火墙的功能,而是和iptables一样需要通过内核的Netfilter来实现,也就是说firewalld和iptables一样,他们的作用都是用于维护规则,而真正使用规则干活的是内核的Netfilter,只不过Firewalld和iptables的结构以及使用方法不一样罢了。iptables是动态防火墙 dynamic firewall daemon 。支持ipv4和ipv6。Rhel7中默认将防火墙从iptables升级为 firewalld。firewalld相对于iptables主要的优点有:
- firewalld在使用上要比iptables人性化很多,即使不明白“四张表五条链”而且对TCP/IP协议也不理解也可以实现大部分功能。
firewalld的配置模式
firewalld的配置文件以xml格式为主(主配置文件firewalld.conf例外),他们有两个存储位置
- /etc/firewalld/services/ 用户自定义配置文件
- /usr/lib/firewalld/services/ 系统配置文件,预置文件,尽量不要修改
过滤规则集合:zone
一个zone就是一套过滤规则,数据包必须要经过某个zone才能入站或出站。不同zone中规则粒度粗细、安全强度都不尽相同。可以把zone看作是一个出站或入站必须经过的安检门,有的严格、有的宽松、有的检查的细致、有的检查的粗略。
每个zone单独对应一个xml配置文件,在目录
/usr/lib/firewalld/services/
每个zone都有一个默认的处理行为,包括:default(省缺)、 ACCEPT、REJECT、DROP
firewalld提供了9个zone:
- drop 任何流入的包都被丢弃,不做任何响应。只允许流出的数据包。
- block 任何流入的包都被拒绝,返回
icmp-host-prohibited
报文(ipv4)或icmp6-adm-prohibited
报文(ipv6)。只允许由该系统初始化的网络连接 - public 默认的zone。部分公开,不信任网络中其他计算机,只放行特定服务。
- external 只允许选中的服务通过,用在路由器等启用伪装的外部网络。认为网路中其他计算器不可信。
- dmz 允许隔离区(dmz)中的电脑有限的被外界网络访问,只允许选中的服务通过。
- work 用在工作网络。你信任网络中的大多数计算机不会影响你的计算机,只允许选中的服务通过。
- home 用在家庭网络。信任网络中的大多数计算机,只允许选中的服务通过。
- internal 用在内部网络。信任网络中的大多数计算机,只允许选中的服务通过。
- trusted 允许所有网络连接,即使没有开放任何服务,那么使用此zone的流量照样通过(一路绿灯)。
防火墙默认只激活public区域,不指定区域,默认是 public 区域
防火墙状态监测
firewall-cmd --list-all
//列出所有的已配置接口的配置信息firewall-cmd --state
//查看防火墙的状态firewall-cmd --get-active-zones
//查看防火墙激活的zone区域firewall-cmd --get-services
//查看防火墙预定义的服务firewall-cmd --get-default-zone
//查看防火墙默认的zone区域firewall-cmd --set-default-zone=home
//将防火墙默认的区域设置为home区域firewall-cmd --get-service --permanent
//查看永久生效的服务firewall-cmd --list-rich-rules
//列出所有的富规则
防火墙的配置
在区域中添加服务或端口:
临时设置:firewall-cmd -zone=public --add-service=mysql
firewall-cmd --add-port=8080-8081/tcp
//不写区域的话默认是public区域
在区域中移除服务或端口:
临时设置:firewall-cmd --remove-service=https
firewall-cmd --remove-port=8080-8081/tcp
在区域中永久添加和移除服务或端口(–permanent参数):
永久设置:firewall-cmd --permanent --add-service=mysql
firewall-cmd --permanent --remove-port=8080-8081/tcp
firewall-cmd --reload
//重载,永久设置需要重载配置文件才能生效
富规则:富规则允许你创建更复杂的配置
firewall-cmd --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.10.0/24" service name=ssh accept "
//zone区域添加一个富规则,允许来自源网段192.168.10.0/24 的数据firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.10.0/24" port protocol="tcp" port="8080" accept"
//在zone区域中永久添加一个富规则,允许来自源网段 192.168.10.0/24 的tcp协议的8080端口的数据firewall-cmd --zone=public --remove-rich-rule="rule family="ipv4" source address="192.168.10.0/24" service name="http" accept "
//移除zone区域的富规则–来自192.168.10.0/24网段的http服务
防火墙的选择
Rhel7中既有iptables防火墙,又有firewalld防火墙。但是同一时刻只能开一个,所以必须得关闭其中一个防火墙。一般我们都是关闭iptables防火墙,而打开firewalld防火墙,因为firewalld比iptables强大太多了。
开启firewalld防火墙,并且使其开机自启动,关闭iptables防火墙
systemctl mask iptables.service
//屏蔽iptables服务systemctl start firewalld.service
systemctl enable firewalld.service
打开路由转发功能 :
echo 1 > /proc/sys/net/ipv4/ip_forward
sysctl -w net.ipv4.ip_forward=1
vim /etc/sysctl.conf
, 将net.ipv4.ip_forward=0
改为 =1,然后sysctl -p /etc/sysctl.conf
使之生效 (永久开启IP转发)
端口转发:
1 | 将外部访问本机10000端口的流量转发至本机22号端口 |
示例
工作流图
下面这张图描述了一个L3的IP封包如何通过iptables:
对于此图的说明:
- Iptables和内核路由的关系:执行完PREROUTING链之后,会进行路由表的查询
- 通过lo接口的封包,不走PREROUTING的DNAT表
- 出站封包在OUTPUT链之前就进行了路由处理。但是如果OUTPUT进行了DNAT,则会进行重新选路
- 入站封包,如果使用了隧道,则会经由PREROUTING - INPUT链逐层的解除隧道
- 出站封包,如果使用了隧道,则会经由OUTPUT -POSTROUTING链逐层的进行隧道封装
下面的图示意了更接近实际的流程:
基础
iptables是用户空间命令,通过netlink和内核的netfilter模块进行交互,在L3/L4操控封包。
规则链
netfilter是Linux网络安全大厦的基石,从2.4开始引入。它提供了一整套Hook函数机制,IP层的5个钩子点对应了iptables的5个内置链条:
- PREROUTING,在此DNAT
- POSTROUTING,在此SNAT
- INPUT,处理输入给本地进程的封包
- OUTPUT,处理本地进程输出的封包
- FORWARD,处理转发给其他机器、其他网络命名空间的封包
对于从网络接口入站的IP封包,首先进入PREROUTING链,然后进行路由判断:
- 如果封包路由目的地是本机,则进入INPUT链,然后发给本地进程
- 如果封包路由目的地不是本机,并且启用了IP转发,则进入FORWARD链,然后通过POSTROUTING链,最后经过网络接口发走
对于本地进程发往协议栈的封包,则首先通过OUTPUT链,然后通过POSTROUTING链,最后经过网络接口发走
表
除了链条,iptables还包含一个正交的概念,表是用于分类管理iptables规则的。不同的表,通常用作不同的目的:
- filter表:用于控制到达某条链条上的数据包如何处理,是放行(Accept)、丢弃(Drop)还是拒绝(Reject)。如果不指定-t参数,这是默认操控的表格
- nat表:用于修改源地址,或者目的地址。该表格在某个创建了新连接的封包出现时生效
- mangle表:该表格用于修改封包的内容
- raw表:具有高优先级,可以对接收到的封包在连接跟踪(Connection Tracking,为了支持NAT,iptables会对每个L4连接进行跟踪,也就是维护每个L4连接的状态)前进行处理(也就是取消跟踪),可以应用在那些不需要做NAT的情况下提高性能。例如高访问的Web服务,可以不让iptables做80端口封包的连接跟踪
- security表:用于强制访问控制(Mandatory Access Control),很少使用
表的优先级
表的优先级从高到低为 raw ⇨ mangle ⇨ nat ⇨ filter ⇨ security。用户不能自定义新表。
封包会依次经过相关的链,在每个链中,会根据表的优先级,依次遍历各个表中的规则。任何表中的规则都有机会拒绝封包。
表和链的关系
需要注意,不是任何链条上可以挂任何表:
- raw可以挂在PREROUTING、OUTPUT
- mangle可以挂在任何链上
- nat(SNAT)可以挂在POSTROUTING、INPUT
- nat(DNAT)可以挂在PREROUTING、OUTPUT
- filter可以挂在FORWARD、INPUT、OUTPUT
- security可以挂在FORWARD、INPUT、OUTPUT
mangle表
用于修改封包。某些目标只能用在mangle表中,包括:
- TOS,此目标设置封包的Type Of Servier字段,以便影响封包的处理策略,例如如何进行路由
- TTL,设置封包的Time To Live字段
- MARK,给封包添加一个标记值(数字),iproute2能够识别此mark并且进行特殊的路由处理。此外基于MARK还可以进行带宽限制、基于Class的排队
nat表
应当仅仅用于网络地址转换。也就是使用以下目标:
- DNAT:用在你有一个公共地址,别人访问此地址时,你需要将访问重定向到防火墙背后的某个服务时
- SNAT:允许隐藏在防火墙背后的内网机器访问外部网络
- MASQUERADE:类似SNAT,不同之处在于每次都需要动态计算使用什么作为转换后的源地址。用在主机地址不固定的情况下
- REDIRECT:类似于DNAT,但是新的目的地址被锁定为接收封包的那个网卡地址,同时端口改为随机的或指定的值
上面这些目标都会改变IP封包的首部。
filter表
用于过滤封包,使用ACCEPT、DROP之类的目标
规则
表中存放的是一个个规则,规则由匹配+目标组成。目标包括:
- ACCEPT,允许封包通过,如果在子链ACCEPT,则相当于在父链也ACCEPT了,不会继续遍历父链后续规则
- RETURN,从当前链返回,行为类似于编程语言函数中的return。如果当前:
- 位于子规则链,则返回到父链调用子链的那个规则的下一条规则处执行
- 不位于子规则链,则执行默认策略
- DROP,直接丢弃数据包,不进行后续处理
- REJECT,返回connection refused或者destination unreachable报文
- QUEUE,将数据包放入用户空间的队列,供用户空间应用程序处理
- JUMP,跳转到用户自定义链继续执行
- LOG 让内核记录匹配的封包
- AUDIT 对封包进行审计
- DNAT 目标地址映射
- SNAT 源地址映射
- MASQUERADE 源地址映射,用于本机地址是动态获取的情况下
通常情况下,一旦匹配了某个规则,就会执行它的目标。同时,不再检查同规则链、同表的后续规则,这意味着规则的顺序非常重要。某些目标是例外,例如LOG、MARK,会继续遍历后面的规则
如果内置规则链执行到结尾****,或者内置规则链中的某个目标是RETURN的规则匹配封包,那么规则链策略(Chain Policy)中定义的目标将决定如何处理当前封包。
封包遍历步骤
目的地是本机的
步骤 | 表 | 链 | 说明 |
---|---|---|---|
1 | 封包在网络上 | ||
2 | 封包进入本机网卡 | ||
3 | mangle | PREROUTING | 在此修改封包,例如改变TOS。连接跟踪发生在这个链上 |
4 | nat | PREROUTING | 主要用于DNAT。避免在此进行封包过滤,某些情况下可能被bypass |
5 | 路由决策:封包目的地是本机,还是需要被转发,转发到哪里 | ||
6 | mangle | INPUT | 路由决策之后,发送到本机进程之前修改封包 |
7 | filter | INPUT | 针对所有目的地是本地的封包进行过滤,不管它来自什么网络接口 |
8 | 封包到达本地进程 |
从本机发起的
步骤 | 表 | 链 | 说明 |
---|---|---|---|
1 | 本地进程发送封包 | ||
2 | 路由决策:使用什么源地址,什么出口网卡,收集一些其它信息 | ||
3 | mangle | OUTPUT | 修改封包。不要在此进行封包过滤,因为具有副作用。本地生成的连接跟踪也在此进行 |
4 | nat | OUTPUT | 对出站封包进行NAT |
5 | 再次路由决策,因为mangle或nat可能导致需要重新路由 | ||
6 | filter | OUTPUT | 对本机发出的封包进行过滤 |
7 | mangle | POSTROUTING | 在路由决策之后,发送出网卡之前,修改封包 |
8 | nat | POSTROUTING | 在此进行SNAT。不要在此进行封包过滤,即使默认策略设置为DROP也可能导致某些封包溜走 |
9 | 到达网卡 | ||
10 | 进入网线 |
需要转发的
步骤 | 表 | 链 | 说明 |
---|---|---|---|
1 | 封包在网线上 | ||
2 | 封包到达入口网卡 | ||
3 | mangle | PREROUTING | 修改封包 |
4 | nat | PREROUTING | 进行DNAT |
5 | 路由决策 | ||
6 | mangle | FORWARD | 仅用于特殊场景下,在初始路由决策之后修改封包 |
7 | filter | FORWARD | 对转发封包进行过滤 |
8 | 最终路由决策 | ||
9 | mangle | POSTROUTING | 所有路由决策完成之后,修改封包 |
10 | nat | POSTROUTING | 进行SNAT |
11 | 到达出口网卡 | ||
12 | 进入网线 |
连接跟踪状态机
连接跟踪(Connection tracking )的目的是,让Netfilter框架能够知晓每个连接的状态。你可以使用 –state来匹配状态。
注意,为了更加准确的跟踪TCP连接,内核还维护一系列的内部状态。这些内部状态不能用来匹配。
在iptables中,每个封包都可能和一个被跟踪的连接相关联。连接可以处于4种不同的状态:
状态 | 说明 |
---|---|
NEW | 说明看到的封包是连接的第一个封包。导致此状态的例子:TCP协议的SYN包 |
ESTABLISHED | 当双向封包都监测到之后,进入此状态。导致此状态的例子:TCP协议的应答SYN/ACK |
RELATED | 如果连接和另外一个ESTABLISHED状态的连接相关,则它进入此状态如果主连接产生一个新连接,这个新连接就是RELATED的。例如FTP数据连接是相关于FTP控制连接的 |
INVALID | 无法识别的状态,可能由于系统内存耗尽、不响应已知连接的ICMP报文导致 |
在内核中,连接跟踪由conntrack模块负责。
除了本地生成的包,在OUTPUT中跟踪之外,所有连接跟踪都在PREROUTING链中进行。例如:
- 本地发起一个连接的初始封包,则在OUTPUT链中,连接变为NEW
- 当接收到上述封包的应答包后,在PREROUTING链中,连接变为ESTABLISHED
如果外部发起初始封包,则NEW状态是在PREROUTING中产生的。
命令
格式
1 | iptables [-t table] {-A|-C|-D} chain rule-specification |
输出
带-n参数时,0.0.0.0/0表示匹配任何地址(anywhere)
不带-n参数时,所有保留私有地址都会显示为bogon
选项
选项被分为若干组:
指定表
-t –table table 指定命令操控的表格的名称,如果内核被配置为自动模块加载方式,并且相应模块不存在,将尝试自动加载适当的模块
子命令
该组选项指定期望执行的动作,仅其中一个可以在命令行中指定
-A –append chain rule-specification 附加一个或者多个规则到目标规则链。如果源/目标名称解析到多于一个地址,那么规则将会添加到每个可能的地址组合
-C –check chain rule-specification 检查目标规则链是否具有匹配的规则,该命令与-D的逻辑类似,但是不会修改当前的iptables配置,使用其退出码来指示是否成功
-D –delete chain rule-specification 从目标规则链中删除一个或者多个规则,需要指定规则的匹配规则
-D –delete chain rulenum 从目标规则链中删除一个或者多个规则,需要指定从1开始的个数
-I –insert chain [rulenum] rule-specification 插入一个或者多个规则到目标规则链的指定位置,如果rulenum是1则插到最前面,举例: -I FORWARD 1
-R –replace chain rulenum rule-specification 替换目标规则链中的一个或者多个规则。如果源/目标名称解析到多个地址,该命令将失败
-L –list [chain] 列出选中规则链中的所有规则,如果不指定规则链,则列出全部规则链,与其他命令不同,该命令仅应用到特定的表格,因此如果想列出NAT表的全部规则,需要使用:iptables -t nat -n -L。该命令一般与-n联用,以避免耗时的DNS查找,指定-Z选项也是合法的
-S –list-rules [chain] 打印选定规则链中的所有规则,该命令仅应用到特定的表格
-F –flush [chain] 刷空选定规则链中的所有规则(如果不指定规则链,则应用到表格中全部的规则链),等价于一条条删除规则
-Z –zero [chain [rulenum]] 将封包、字节计数器置零
-N –new-chain chain 创建一个用户自定义的规则链,名称为chain,chain必须不是任何已经存在的target
-X –delete-chain [chain] 删除可选的、用户定义的规则链
-P –policy chain target 设置某个规则链的策略(没有规则匹配封包时的默认行为)为target。仅内置规则链可以设置策略,策略的目标不得是任何规则链,举例:
1 | iptables --policy INPUT DROP # 设置INPUT的规则链策略为DROP |
-E –rename-chain old-chain new-chain 重命名用户定义的规则链
参数
以下的参数用来组成一个rule specification
[!] -p, –protocol protocol 用来检查的规则或者封包的协议。支持的值包括:tcp, udp, udplite, icmp, icmpv6,esp, ah, sctp, all。叹号用来反转测试,默认all
[!] -s, –source address[/mask][,…] 封包来源规则,address可以是网络名、主机名、IP地址(附加/掩码)、或者普通IP地址。主机名仅仅会在规则提交到内核前解析一次。叹号用来反转地址规则。指定多个地址是可以的,但是会被分解为多个规则,或者导致多个规则被删除(-D)
[!] -d, –destination address[/mask][,…] 封包目标规则,类似来源规则
-m –match match 指定使用的match,所谓match是用来测试特定属性的扩展模块
-j –jump target 指定规则的目标,即:当规则匹配的时候要做什么。目标可以是用户定义的规则链、一个特殊的内置目标(立即决定封包命运)、或者一个扩展。如果某个规则不设置该选项,那么匹配后将对封包不构成任何影响,但是规则的计数器会增加
-g –goto chain 仅仅用在用户定义的规则链中,指示重定向到另外一个链继续处理。和-j不同,-j后子链完成匹配后会跳转到父链,-g则不会跳转,如果子链没有匹配的规则则按子链的默认策略处理
[!] -i, –in-interface name 仅用于进入INPUT, FORWARD, PREROUTING链的封包。限制接收到封包的网络接口名称,如果名称后面跟着+号,所有以该名称开头的接口都被匹配
[!] -o, –out-interface name 仅用于进入FORWARD, OUTPUT, POSTROUTING链的封包。限制封包将被送出的网络接口名称,如果名称后面跟着+号,所有以该名称开头的接口都被匹配
[!] -f, –fragment 对于分片的IP数据报,该规则将仅仅用于第二个或者以后的的分片。仅用于IPv4
-c –set-counters packets bytes 在INSERT, APPEND, REPLACE规则时,用于初始化封包、字节计数器
其他选项
-v –verbose 冗长输出,list命令将输出接口名称、规则选项、TOS掩码、包以及字节计数器。对于附加、插入、删除、替换规则的操作,该选项导致规则的详细信息被打印
-w –wait 等待xtables锁被解开,为了防止多个进程同时修改,iptables具有锁定机制
-n –numeric 数字化输出,IP地址和端口将使用数字格式
-x –exact 仅与-L命令有关,显示精确的封包、字节计数,使用1024而不是1000作为倍率
–line-numbers 列出规则时,显示行号
–modprobe=command 当添加、删除规则时,使用命令command加载必要的模块(目标、匹配-m扩展等)
应用举例
透明代理
1 | 发送任何目的端口为25的封包给在127.0.0.1:10025上监听的进程 |
网关
1 | 对于准备从wlan0出去的封包,进行源地址映射 |
防火墙
1 | 列出filter表(可用于实现防火墙)内容。注意默认网卡信息不显示,需要加 -v |
优化输出
1 | 显示Filter表的详细信息,格式化输出 |
源地址映射
1 | 作为VPN服务器的主机,启用ipv4转发 |
目的地址映射
1 | 把针对本机192.168.0.89的7777端口的请求全部转换为对虚拟机172.16.87.132的80端口的请求 |
编写规则
很多iptables命令都要求提供一个规则的规格(rule-specification,后面简称规则)。规则实际上就是一系列iptables命令选项,大部分选项都用来说明如何匹配封包的, -j
用于指定目标。
添加注释
要为规则添加注释,参考:
1 | iptables -m comment --comment "comment here" |
可以看到,注释以匹配扩展的形式被支持。
注释最多256字符,执行 iptables -L
命令时会以 /* */打印在规则尾部。
一般匹配
这些匹配选项的值,前面都可以加 !表示反向匹配。
选项 | 说明 |
---|---|
-p, –protocol | 匹配协议,可选值 TCP, UDP, ICMP等 |
-s, –src, –source | 匹配源地址。地址形式192.168.0.0/24 |
-d, –dst, –destination | 匹配目的地址。地址形式192.168.0.0/24 |
-i, –in-interface | 匹配入站网络接口,仅用于INPUT, FORWARD, PREROUTING链。eth+表示匹配任何以太网卡 |
-o, –out-interface | 匹配出站网络接口,OUTPUT, FORWARD, POSTROUTING链。eth+表示匹配任何以太网卡 |
-f, –fragment | 用于匹配分片的封包的非首分片。取反需要 ! -f |
隐式匹配
用于TCP的匹配
选项 | 说明 |
---|---|
–sport, –source-port | 源端口。支持端口范围: --source-port 22:80 |
–dport, –destination-port | 目的端口。支持端口范围 |
–tcp-flags | 匹配TCP标记,可用的标记SYN, ACK, FIN, RST, URG, PSH ,还有两个特殊的值ALL, NONE分别匹配具有任何标记的封包、没有任何标记的封包 |
–syn | 匹配设置了SYN位,但是没有设置ACK,RST位的封包 |
–tcp-option | 基于TCP选项来匹配 |
举例:
1 | 匹配SYN标记被设置,ACK,FIN,RST没有被设置的封包 |
用于UDP的匹配
选项 | 说明 |
---|---|
–sport, –source-port | 源端口匹配 |
–dport, –destination-port | 目的端口匹配 |
用于ICMP的匹配
选项 | 说明 |
---|---|
–icmp-type | 匹配ICMP报文类型 |
显式匹配
所谓显式匹配,是指必须明确通过 -m或 –match选项加载的匹配。
conntrack
内核中基于netfilter框架实现的连接跟踪模块即conntrack。在DNAT时,conntrack使用状态机来跟踪连接的状态,记住目的地址被从什么改成了什么,这样才能将回程包的源地址改回来
基于连接跟踪的匹配。使用 -m conntrack加载,可以接额外选项:
子选项 | 说明 |
---|---|
–ctstate | 匹配封包状态,可选值:INVALID 匹配无法识别或没有任何状态的数据报 ESTABLISED 匹配连接请求的响应,以及后续的包。此时conntrack知道封包属于哪个连接 NEW 匹配连接的第一个包,conntrack此时对连接一无所知,通常发生在SYN时 RELATED 当一个连接和另外一个ESTABLISHED状态的连接相关时,则前一个连接为此状态 SNAT 已被SNAT DNAT 已被DNAT要匹配多个状态,用逗号分隔: -m conntrack --ctstate ESTABLISHED,RELATED 取反需要在匹配模块名之后: -m conntrack ! --ctstate ESTABLISHED,RELATED |
–ctproto | 匹配封包协议。示例 -m conntrack ! --ctproto TCP |
–ctorigsrc | 匹配封包源地址。示例 -m conntrack --ctorigsrc 192.168.0.0/24 |
–ctorigdst | 匹配封包目的地址 |
iprange
使用IP地址范围进行匹配。使用 -m iprange加载,可以接额外选项:
子选项 | 说明 |
---|---|
–src-range | 源地址范围。示例 -m iprange --src-range 192.168.1.13-192.168.2.19 |
–dst-range | 目的地址范围。示例 -m iprange --dst-range 192.168.1.13-192.168.2.19 |
length
第三层载荷匹配。该扩展用于根据网络层载荷,即传输层封包的长度进行匹配
用法: -m length [!] –length length[:length] TCP/UDP包的长度
limit
可以用于限制特定规则的日志记录的频度。使用 -m limit加载,可以接额外选项:
子选项 | 说明 |
---|---|
–limit | 指定平均匹配速率。如果指定单位时间内匹配的封包超过数量,则不再匹配示例: -m limit –limit 3/hour。每小时最多匹配3次可用单位:/second /minute /hour /day |
–limit-burst | 指定最大匹配速率 |
mac
根据源地址的MAC地址进行匹配,只能用在PREROUTING, FORWARD,INPUT
规则链。
示例: -m mac --mac-source 00:00:00:00:00:01
mark
根据关联当前封包的netfilter标记进行匹配。mark是一个特殊字段,无符号整数(unsigned int),仅仅在内核中维护(不会嵌入在封包里)。封包在通过主机时,标记可以和它关联。
很多内核例程都会使用mark,从而完成流量塑形(Traffic Shaping)、过滤等工作。
要设置一个mark,可以使用iptables的MARK目标。由于以前在ipchains的FWMARK目标中设置,现在仍然会使用FWMARK这个术语。
示例: -m mark --mark 1986
,匹配具有1986标记的封包。你还可以指定标记的掩码,也就是 -m mark –mark 1/1这种形式,这样 / 后面的数字,会与netfilter标记先进行逻辑与,得到的值再和 / 前面的值进行比较 —— 这可以仅仅关注fwmark的某个位
multiport
多端口匹配。该扩展只能用于以下协议:tcp, udp, udplite, dccp, sctp。最多指定15个端口
指定端口的语法: port[,port|,port:port]
使用 -m multiport加载,可以接额外选项:
子选项 | 说明 |
---|---|
–source-port | 根据源端口匹配,示例 -m multiport –source-port 22,53,80,110 |
–destination-port | 根据目的端口匹配 |
–port | 根据源或目的端口匹配 |
owner
根据创建封包的进程的身份来匹配封包,很明显,只能用于本机产生的封包上,你只能在OUTPUT链中使用该匹配。
使用 -m owner加载,可以接额外选项:
子选项 | 说明 |
---|---|
–uid-owner | 如果封包是由指定的User ID创建,则匹配可能的应用场景:仅仅允许Apache通过80端口发出数据 |
–gid-owner | 如果封包是由指定的Group ID中的用户创建,则匹配 |
–pid-owner | 如果创建封包的进程具有指定的PID,则匹配 |
–sid-owner | 如果创建封包的进程具有指定的Session,则匹配 |
pkttype
根据链路层类型匹配。用法 -m pkttype [!] --pkt-type {unicast|broadcast|multicast}
state
和内核中的连接跟踪代码配合工作。此匹配会从连接跟踪状态机中读取封包的状态。
示例: -m state --state RELATED,ESTABLISHED
tcpmss
根据TCP的Maximum Segment Size来匹配,仅仅针对SYN或SYN/ACK包。
示例: iptables -A INPUT -p tcp --tcp-flags SYN,ACK,RST SYN -m tcpmss --mss 2000:2500
tos
根据Type Of Service来匹配。示例: iptables -A INPUT -p tcp -m tos --tos 0x16
ttl
根据Time To Live来匹配。示例: iptables -A OUTPUT -m ttl --ttl 60
addrtype
通过封包的地址类型进行匹配,可用的地址类型包括:
地址类型 | 说明 |
---|---|
UNSPEC | 未指定的地址,例如0.0.0.0 |
UNICAST | 单播地址 |
LOCAL | 本地地址(任何分配到任一本地网络接口的地址,包括loopback地址、ipvs虚拟地址) |
BROADCAST | 广播地址 |
ANYCAST | 选播地址 |
MULTICAST | 黑洞地址 |
UNREACHABLE | 不可达地址 |
PROHIBIT | 禁止地址 |
使用 -m addrtype加载,可以接额外选项:
子选项 | 说明 |
---|---|
[!] –src-type type | 根据源地址类型匹配地址类型:LOCAL:不是指loopback地址,而是指任何分配给本机某个网络接口的IP地址(包括loopback地址、ipvs虚拟地址) |
[!] –dst-type type | 根据目标地址类型匹配 |
–limit-iface-in | 限制检查的入站网络接口,仅支持PREROUTING, INPUT, FORWARD规则链 |
–limit-iface-out | 限制检查的出站网络接口,仅支持POSTROUTING, OUTPUT, FORWARD规则链 |
connbytes
根据某个连接到目前为止发送的字节数、封包数,或者每封包平均字节数进行匹配,计数器64位长。
该扩展可以用来检测维持了很长时间的下载,并将其安排到低优先级,以进行带宽控制。
使用 -m connbytes加载,可以接额外选项:
子选项 | 说明 |
---|---|
[!] –connbytes from[:to] | 指定匹配的封包/字节数范围 |
–connbytes-dir {original|reply|both} | 统计哪种类型的封包 |
–connbytes-mode {packets|bytes|avgpkt} | 统计模式,封包数、字节数、平均每封包的字节数 |
connlimit
可用于限制一个客户端可以连接到某个服务的并发连接数。可以接额外选项:
子选项 | 说明 |
---|---|
–connlimit-upto n | 如果连接数低于或者等于n则匹配 |
–connlimit-above n | 如果连接数大于n则匹配 |
–connlimit-mask prefix_length | 统计哪些IP的总和连接数,prefire_length指定分组的IP前缀 |
–connlimit-saddr | 限制源地址组,默认值 |
–connlimit-daddr | 限制目的地址组 |
示例:
1 | 允许每个客户端主机开启两个telnet连接 |
connmark
基于关联到连接的netfilter mark字段进行匹配,此mark由CONNMARK目标来设置。
用法: -m connmark [!] --mark value[/mask]
示例:
1 | 匹配所属连接被标记为123的封包 |
connlabel
类似于connmark,但是标签是按位的(每个标签占一个bit),全系统支持最多128个标签
socket
匹配条件:
- 针对包进行套接字查找(Socket lookup),如果发现存在打开的TCP/UDP套接字,也就是说SRC_IP:SRC_PORT:DST_IP:DST_PORT作为已建立的(established)套接字存在于本地TCP/IP栈,则匹配
- 存在established的监听套接字,则匹配
- 存在非零绑定的监听套接字(non-zero bound listening socket),甚至在非本地地址上监听,则匹配。所谓zero bound应该就是指绑定到0.0.0.0
简而言之,就是匹配应当由本地TCP/IP栈处理(而非转发)的封包。进行套接字查找时,使用packet元组,或者嵌入在 ICMP/ICPMv6错误报文中的原始TCP/UDP头
可以接额外选项:
子选项 | 说明 |
---|---|
–transparent | 仅仅匹配透明套接字。透明套接字意味着地址不是本机的任何网络接口上配置的地址 |
–nowildcard | 不忽略绑定到ANY地址(0.0.0.0)的套接字默认情况下不匹配zero-bound的监听套接字,其目的是让本地服务能够监听请求而不是统统被转发 |
这个匹配扩展+MARK+策略路由,就能够实现全功能的non-locally bound套接字。常常用于配合优化透明代理。通常是匹配后进行MARK,然后具有此MARK的封包路由设置到lo。
从各种文档中看到关于socket match的说明,都不是非常明朗,导致理解起TPROXY拦截模式下Istio的iptables规则有些困难:
1 | mangle表 |
这是一个启用了TPROXY拦截模式的Pod的iptables,LOG目标是我添加用于分析socket match的行为的。此Pod的地址是172.27.121.156。可以看到它在监听:
1 | # netstat -nlt |
现在我们从另一个客户端 172.27.155.65
上访问 curl http://172.27.121.156
。
这会发起一个TCP连接,它的SYN包,是否匹配socket扩展呢?我们回顾一下它的匹配条件:
- 套接字查找成功,这个不满足。因为是新连接
- 已经建立的监听套接字,这个不满足,监听套接字还没有收到SYN,谈不上建立
- 存在non-zero bound listening socket。这个说的让人费解。但是肯定隐含着在SYN包的目的地址上监听。此SYN包的目的地址是172.27.121.156:80,我们知道Pod在0.0.0.0:80上监听了,那么172.27.121.156作为它的本地地址,自然也在其上监听。那么,这个监听套接字,是不是non-zero bound的呢?网上很难找到相关信息,我的理解,zero bound就是指绑定到0.0.0.0。在这种猜测之下,是不匹配socket的
根据iptables日志来验证一下。客户端curl之后,在Pod的内核看到一下日志:
1 | 客户端发来的SYN,可以看到不匹配socket,直接走到TPROXY,这证明了上述猜测 |
set
IPSet扩展,可以匹配一组IP。使用 -m set
加载,额外选项:
子选项 | 说明 |
---|---|
–match-set ipsetname | 匹配的IP Set, [!] --match-set setname flag[,flag]... 形式此选项必须,flag是IPSet的字段iptables -A FORWARD -m set --match-set test src,dst 表示:如果test是ipportmap,则当封包的源地址、目的端口对可以在test中发现时,匹配。如果test是ipmap,则当封包的源地址可以在test中发现时,匹配。 |
–return-nomatch | 如果指定此选项并且目标IPSet的类型支持nomatch,则反转匹配结果 |
bpf
使用Linux Socket Filter来过滤,需要提供十进制形式的(由nfbpf_compile生成)BPF字节码。
示例:
1 | iptables -A OUTPUT -m bpf --bytecode '4,48 0 0 9,21 0 1 6,6 0 0 1,6 0 0 0' -j ACCEPT |
cpu
根据处理封包的CPU来匹配。示例:
1 | 如果是第一个核心处理了封包,则重定位到8080端口 |
time
根据封包到达时间来匹配。
目标
使用选项 -j来指定目标,除了本节要介绍的各种目标外,该选项的值还可以是:
- 自定义链的名称,这导致跳转到自定义的链继续执行
ACCEPT
接收封包,不再遍历当前链的其它规则、也不会在遍历当前表中的任何规则。但是,在一个链中被接收的封包,可能仍然需要经过其它表中的链,仍然可能被DROP。
在子链中ACCEPT的效果,等价于在父链中被ACCEPT。
RETURN
停止遍历当前链:
- 如果当前位于子链,则回到父链,继续执行后面的规则
- 如果当前位于主链,则执行默认策略
DROP
静默的丢弃封包,不会在对它进行任何后续处理。
可能会导致对方主机上出现一个僵尸套接字,最好用REJECT代替。
REJECT
用于发送一个错误报文给匹配封包的发送者,其它方面,该目标的行为与DROP一致:丢弃封包,终止规则遍历。
该目标仅用于INPUT, FORWARD, OUTPUT规则链中,或者从这两规则链调用的用户自定义规则链。
额外选项:
子选项 | 说明 |
---|---|
–reject-with type | 错误报文的类型: icmp-net-unreachable icmp-host-unreachabl icmp-port-unreachable(默认) icmp-proto-unreachable icmp-net-prohibited icmp-host-prohibite icmp-admin-prohibited |
AUDIT
允许创建命中目标的封包的审计记录,用来记录被接受的、丢弃的、拒绝的封包。
用法: -j AUDIT –type {accept|drop|reject}
示例:
1 | 添加一个规则链到默认表格 |
LOG
这是一个非终止性目标,后续规则总是会被执行。如果你希望LOG后DROP,在此规则后面紧跟着一个相同匹配的目标为DROP的规则。
让内核记录匹配的封包。内核将会打印匹配的封包的信息,包括大部分IP头字段。这些日志可以在dmesg/syslog中看到。
额外选项:
选项 | 说明 |
---|---|
–log-level level | 日志级别:emerg, alert, crit, error, warning, notice, info, debug |
–log-prefix prefix | 日志前缀,29个字符最多 |
–log-tcp-sequence | 记录TCP序列号 |
–log-tcp-options | 记录TCP选项 |
–log-ip-options | 记录IP选项 |
–log-uid | 记录生成封包的UID |
关于容器中的iptables logging:
- 默认情况下,来自容器(非全局网络命名空间)的iptable logging被忽略,你无法在 dmesg -w中看到
- 要改变此行为,你需要较新版本的内核,并且设置: echo 1 > /proc/sys/net/netfilter/nf_log_all_netns
DNAT
仅用于nat表的PREROUTING,OUTPUT规则链,或者从这两规则链调用的用户自定义规则链。
该目标指定封包的目的地址应当被修改(且该连接上所有以后的封包应当执行同样的操作),规则应当停止检查。
应用场景:HTTP服务放置在内网主机上,前端有个防火墙配置公网IP,互联网用户通过此公网IP访问内网主机上的HTTP服务,这种情况需要DNAT
额外选项:
子选项 | 说明 |
---|---|
–to-destination | –to-destination [ipaddr[-ipaddr]][:port[-port]]指定单个目的IP地址或者一个地址范围。如果指定了以下协议:tcp, udp, dccp, sctp,则可以指定一个端口范围。如果不指定端口,那么目的端口不会被改写。如果不指定IP地址,则仅仅会修改端口 |
–random | 随机化端口映射 |
–persistent | 对于一个客户端连接,给予相同的映射 |
举例:
1 | 如果公网客户端访问本防火墙的80端口 |
SNAT
仅用于nat表的POSTROUTING,INPUT规则链,或者从这两规则链调用的用户自定义规则链。
该目标指定封包的源地址应当被修改(且该连接上所有以后的封包应当执行同样的操作),规则应当停止检查。
应用场景:局域网前端有个防火墙配置公网IP,内网主机通过该IP访问公网,为了内网主机能够访问外网,需要SNAT。
额外选项:
子选项 | 说明 |
---|---|
–to-source | –to-source [ipaddr[-ipaddr]][:port[-port]]指定单个源IP地址或者一个地址范围。如果指定了以下协议:tcp, udp, dccp, sctp,则可以指定一个端口范围。如果不指定端口范围,那么小于512的源端口映射到512以下;512-1023之间的源端口映射到1024以下;其它源端口映射到1024以上。如果可能,则不去修改端口 |
–random | 随机化端口映射 |
–persistent | 对于一个客户端连接,给予相同的映射 |
举例:
1 | 对于来自192.168.0.0网段的所有出站请求 |
MASQUERADE
仅用于nat表的POSTROUTING规则链。应当用于动态分配IP的网络连接,静态网络连接应当使用SNAT目标。该目标会自动从网络接口上获取当前IP地址,用来做源地址的SNAT
应用场景:本主机具有动态分配的公网地址,有客户端通过PPP连接(VPN)到本主机,并通过本主机上网。这时需要将客户端封包的源地址(PPP对端地址)转换为公网地址,但是由于本主机的公网地址是动态获取的,因此不能使用SNAT,只能使用MASQUERADE
额外选项:
子选项 | 说明 |
---|---|
–to-ports port[-port] | 指定一组转换后使用的源端口。仅当协议指定为tcp, udp, dccp, sctp时可用 |
–random | 随机化端口映射 |
举例:
1 | iptables -t nat -A POSTROUTING |
TPROXY
仅可用在mangle的PREROUTING链(或者从该链调用的用户自定义链)。此目标能够重定向包到一个本地套接字,但却不修改包头的任何信息。 它还能够改变封包的mark,进而辅助后续的策略路由。
额外选项:
子选项 | 说明 |
---|---|
–on-port port | 重定向到的本地套接字的目标端口,0表示新的目标端口与原始端口相同 |
–on-ip address | 重定向到的本地套接字的目标IP地址,默认情况下是入口网卡的地址。仅仅当规则指定了-p tcp或-p udp时可用 |
–tproxy-mark value[/mask] | 为封包添加标记,以便选择正确的路由表,这里设置的fwmark可以用于高级路由。透明代理必须要此选项正确设置,否则封包将被转发走 |
REDIRECT
可以认为是一种DNAT。
仅用于nat表的PREROUTING,OUTPUT规则链,或者从这两规则链调用的用户自定义规则链。该目标重定向封包到当前主机本身,通过把目的地址改写为入站网卡的主地址(本地生成的封包映射到localhost地址,对于IPv4即127.0.0.1)。
额外选项:
子选项 | 说明 |
---|---|
–to-ports port[-port] | 重定向到的目的端口,或者目的端口的范围如果不指定此选项,则目的端口不变 |
–random | 随机化端口映射 |
CONNMARK
在连接上设置netfilter标记。标记为32bit。
额外选项:
子选项 | 说明 |
---|---|
–set-xmark | –set-xmark value[/mask]如果指定mask,则将mask提供的bit归零,并和value 异或,得到最终的ctmark |
–save-mark | –save-mark [–nfmask nfmask] [–ctmask ctmask]拷贝封包标记(nfmark)为连接标记(ctmark)。算法:ctmark = (ctmark & ~ctmask) ^ (nfmark & nfmask) |
–restore-mark | –restore-mark [–nfmask nfmask] [–ctmask ctmask]拷贝连接标记为封包标记。算法:nfmark = (nfmark & ~nfmask) ^ (ctmark & ctmask) 此选项仅能用于mangle表 |
–and-mark bits | 等价于 –set-xmark 0/invbits,invbits是bits取反 |
–or-mark bits | 等价于–set-xmark bits/bits |
–xor-mark bits | 等价于–set-xmark bits/0 |
–set-mark value[/mask] | 仅仅mask中设置的那些bit,对应value中的bit的设置 |
MARK
在封包上设置netfilter标记。标记为32bit。
常常和基于fwmark的路由(需要iproute2)联用,这种情况下你需要在PREROUTING链mangle表中使用,以影响路由策略。
额外选项:
子选项 | 说明 |
---|---|
–set-xmark value[/mask] | 如果指定mask,则将当前nfmark中mask提供的bit归零,并和value 异或,得到最终的nfmark |
–set-mark value[/mask] | 如果指定mask,则将当前nfmark中mask提供的bit归零,并和value或,得到最终的nfmark |
–and-mark bits | 和nfmark进行二进制与 |
–or-mark bits | 和nfmark进行二进制或 |
–xor-mark bits | 和nfmark进行二进制异或 |
CHECKSUM
只能用于mangle表,可以为封包添加缺失的校验和
IDLETIMER
可以用于识别某个网络接口已经空闲一定的时间
NETMAP
允许静态的把整个网络的IP地址映射到另外一个网络的IP地址
NFLOG
用于记录匹配包的日志
NOTRACK
禁止匹配规则的封包的连接跟踪。你无法通过conntrack命令看到这样的连接
TCPMSS
修改TCP的SYN封包的MSS值,用来控制连接的最大单个段的大小,一般限制到出站网络接口MTU-40
TTL
该目标用于修改封包的TTL
高级
conntrack和NAT
假设内网客户端机器IP地址为10.0.0.1;NAT网关内网地址10.0.0.2,外网地址10.4.80.14;外网服务器地址为9.135.102.75。
我们可以通过conntrack命令,在NAT网关上查看相关事件:
1 | conntrack -E --proto tcp -d 9.135.102.75 |
NAT表的特殊之处在于,仅新连接的第一个封包会经过此表。第一个封包的地址转换结果,会应用到连接的所有后续封包。
NAT网关接收到新连接后,创建conntrack条目:
10.0.0.1:56736->9.135.102.75:36000, 9.135.102.75:36000-> 10.0.0.1:56736
在iptables中,NAT网关的POSTROUTING钩子中的SNAT规则,会修改conntrack的应答目的地址
10.0.0.1:56736->9.135.102.75:36000, 9.135.102.75:36000->10.4.80.14:56736
这时,就到达上面命令输出的[NEW]状态了。请求/应答报文进行地址转换所需的信息已经完备。
iptables规则所做的事情,仅仅是修改conntrack规则而已。所有其它事情,包括请求封包的源地址修改,是由内核中的conntrack模块(nf_conntrack、nf_conntrack_ipv4)以及nat模块(nf_nat、nf_nat_ipv4)等负责的。
当NAT网关接收到应答报文后,会检索conntrack中的条目,并将匹配的条目关联到该封包( skb->_nfct)。这个条目将用于目的地址的还原。
注意以下几点:
- iptables不是netfilter本身,它是netfilter的用户。而conntrack和nat模块是netfilter的一部分
- 无法在POSTROUTING钩子+NAT表看到检查到应答报文,因为NAT表仅仅对新连接调用一次
- 连接跟踪、NAT转换的大部分工作由相应内核模块,而不是iptables完成
关于xtables锁
实现方式
在iptables新老版本中,xtables锁的实现不同。在1.4.x中,锁基于abstract unix domain socket实现;1.6.x中则基于普通文件。
1 | func grabIptablesLocks(lockfilePath string) (iptablesLocker, error) { |
加锁失败时的错误
尝试修改iptables时,可能会因为锁被占用导致报错。这种报错没有专门的退出码,因此只能比对stderr输出来判定。
正常情况下,出现锁争用的概率比较低,可以使用下面的命令显式占用xtables锁:
1 | 1.4.x加锁 |
保持运行上述两个命令的Terminal打开,然后插入iptables规则。可以看到报错信息如下:
- v1.4.21版本:
- 不带-w参数:Another app is currently holding the xtables lock. Perhaps you want to use the -w option?
- 带有-w参数:Another app is currently holding the xtables lock; still 21s 0us time ahead to have a chance to grab the lock… Another app is currently holding the xtables lock. Stopped waiting after 30s.
- v1.6.0版本:报错同上
实际上,K8S中就是基于上述输出信息进行判断的:
1 | func IsProxyLocked(err error) bool { |