iptables
{Back to Index}
1 概述
1.1 命令格式
iptables [ -t 表名] 命令选项 [链名] [匹配] [-j 目标动作或跳转]
1.1.1 表 (操作维度)
在 iptables 中,每种表对应不同的功能(操作),由相应的内核模块提供支持:
filter (iptables_filter)
默认表,主要用于控制包是否被接受、丢弃或转发(过滤功能)
nat (iptable_nat)
用于地址转换,比如端口转发、SNAT、DNAT 等(修改目的地址/源地址)
mangle (iptable_mangle)
用于修改包的服务类型、TTL、打标记等(包的内容修改或打标)
raw (iptable_raw)
用于决定是否开启连接跟踪(conntrack)
优先级最高的表 ,设置 raw 时一般是为了不再做数据包的链接跟踪处理,以提高性能。因为优先级最高,从而可以对收到的数据包在连接跟踪前进行处理,即数据包在某个链上由 raw 表处理完后, 就意味着跳过了 nat 表(和 iptables_nat 模块中对 ip_conntrack 的处理,相当于不再做地址转换和数据包的链接跟踪处理了)
可以应用在那些 不需要做 nat 的情况下 ,以提高性能。如大量访问的 web 服务器,可以让 80 端口不再做数据包的链接跟踪处理, 以提高用户的访问速度。
同名链虽然存在于多个表中,但每个表的作用不同。需要根据规则目的选择合适的表:
- 控制访问权限 -> filter
- 做地址转换 -> nat
- 修改包参数 -> mangle
- 控制是否跟踪连接 -> raw
而且每张表参与处理的阶段不同,如果把一条控制"是否允许访问"的规则写到 nat 表,它并不会生效,因为 nat 主要用于地址转换,并不是"决定包是否允许"的地方。
1.1.2 链 (执行维度)
- PREROUTING
- raw, mangle, nat
- INPUT
- mangle, filter
- FORWARD
- mangle, filter
- OUTPUT
- raw, mangle, nat, filter
- POSTROUTING
- mangle, nat
数据包经过一个链的时候,会将当前链的所有规则都匹配一遍,但是 匹配是有顺序的 ,当 4 张表处于同一条链时,执行的优先级如下:
raw -> mangle -> nat -> filter
拥有 过滤功能 的链只有 3 条:INPUT, OUTPUT, FORWARD 。
1.1.3 命令选项
1.1.3.1 rule 管理
-A: 在指定链的末尾添加( --append )一条新的规则 -D: 删除( --delete )指定链中的某一条规则,按规则序号或内容确定要删除的规则 -I: 在指定链中插入( --insert )一条新的规则,默认在链的开头插入 -R: 修 改、替换( --replace )指定链中的一条规则,按规则序号或内容确定
1.1.3.2 链管理
-F: 清空( --flush )指定链中的所有规则,默认清空表中所有链的内容 -N: 新建( --new-chain )一条用户自己定义的规则链 -X: 删除指定表中用户自定义的规则链( --delete-chain ) -P: 设置指定链的默认策略( --policy ) -z: 置零计数器 -r [CHAIN]: 清空指定规则链,如果省略 CHAIN,则删除对应表中的所有链
1.1.3.3 查看信息
-L: 列出( --list )指定链中的所有的规则进行查看,默认列出表中所有链的内容 -n: 用数字形式( --numeric )显示输出结果,若显示主机的 IP 地址而不是主机名 -v: 查看规则列表时显示详细( --verbose )的信息 -x: 计数器取消近似 -line-numbers: 查看规则列表时,同时显示规则在链中的顺序号
1.1.4 匹配
1.1.4.1 通用匹配
-p {tcp|udp|icmp}: 指定隐含扩展,其余扩展(如 state)必须由 -m 指定 -s, --src: 指定源地址 -d, --dst: 指定目标地址 -i <INTERFACE>: 指定报文流入接口,仅适用于 PREROUTING,INPUT,FORWARD -o <INTERFACE>: 指定报文流出接口,仅适用于 OUTPUT,POSTROUTING,FORWARD
1.1.4.2 隐含匹配
-p tcp: --sport PORT|STARTPORT-ENDPORT: 源端口 --dport PORT|STARTPORT-ENDPORT: 目标端口 --tcp-flags <mask> <comp>: 检查<mask>中列出的标志位, <comp>中指明的必须为1,其余必须为零 如:--tcp-flags SYN,FIN,ACK,RST SYN,ACK --syn: 等效于 --tcp-flags SYN,FIN,ACK,RST SYN,ACK -p icmp: --icmp-type: 0(echo-reply), 8(echo-request) -p udp: --sport --dport
1.1.4.3 显式匹配
-m state: --state NEW|ESTABLISHED|RELATED|INVALID -m multiport: --source-ports --destination-ports -m iprange: --src-range --dst-range -m connlimit: --connlimit-above -m limit: --limit --limit-burst -m time: --datestart --datestop --timestart --timestop -m string: --algo: 用于指定匹配算法,可选的算法有 bm 与 kmp --string: 指定要匹配的字符串,如果报文中包含对应的字符串,则符合匹配条件
1.1.5 目标动作
ACCEPT
允许数据包通过。
DROP
直接丢弃数据包,不给任何回应信息。
REJECT
拒绝数据包通过,客户端刚请求会收到拒绝的信息。
SNAT
源地址转换,解决内网用户用同一个公网地址上网的问题。
MASQUERADE
是 SNAT 的一种特殊形式 , 适用于网关 NAT 的情况 ,例如:
iptables -t nat -A POSTROUTING -s 192.168.56.0/24 -o eth1 -j MASQUERADE
在网关上仅针对由内网到 Internet 的流量进行 NAT 转换:【10.0.0.0/8 为公司内部网段】
DNAT
目标地址转换。
REDIRECT
在本机做端口映射。
LOG
在
/var/log/messages
文件中记录日志信息,然后将数据包传递给下一条规则(除了记录以外不对数据包做任何其他操作,仍然让下一条规则去匹配)。
1.2 四表五链
Figure 1: 链与表的分布
Figure 2: iptables/netfilter 整体架构
通过以下命令设置主机支持转发功能:
echo 1 > /proc/sys/net/ipv4/ip_forward
2 应用场景 1
2.1 NAT
Figure 3: 网络地址映射
使用 NAT 技术一定会发生两次 IP 地址的转换(下面以内网访问外网为例):
- 内部网络的报文发送出去时,报文的源 IP 会被修改,也就是源地址转换(SNAT)
- 外部网络的报文响应时,响应报文的目标 IP 会再次被修改,也就是目标地址转换(DNAT)
上述过程被称为 SNAT ,是因为先发生了 SNAT。如果先使用 DNAT (比如外网穿透内网的场景,下面会讲到),则整个过程被称为 DNAT 。
也就是说,NAT 属于 SNAT 还是 DNAT ,取决于整个过程的最先使用了 SNAT 还是 DNAT 。
2.1.1 SNAT
Figure 4: SNAT 网络拓扑
只是配置 SNAT 的话,并不用手动配置 DNAT ,iptables 会自动维护 NAT 表,自动执行 DNAT 将响应报文的目标地址转换回来。
2.1.2 DNAT
可用于从外部访问内部设备。
Figure 5: On Gateway: iptables-legacy -t nat -I PREROUTING -d 10.0.1.3 -p tcp --dport 8080 -j DNAT --to-destination 172.0.1.2:8080
只是配置 DNAT 的话,并不用手动配置 SNAT ,iptables 会自动维护 NAT 表,自动执行 SNAT 将响应报文的源地址转换回来。
注意:
--to-destination
需要使用 iptables-legacy ,同时 /etc/modules
中需确保加载了 xt_nat 和 iptable_nat 模块(后者通常默认加载)。
BTW:
通过 find /lib/modules/$(uname -r)/kernel/ -type f -name '*.ko*'
可以查看所有可以加载的模块。
iptables-legacy 依赖的是一套基于 xtables 的内核模块,分为三类: - 表模块(如 iptable_filter) - match 模块(如 xt_statistic) - target 模块(如 xt_LOG、xt_REJECT)
2.1.2.1 OUTPUT DNAT
可以修改目标地址和端口,实现类似中间人攻击的效果。
Figure 6: On Host: iptables-legacy -t nat -I OUTPUT -d 192.168.1.0/24 -p tcp --dport 443 -j DNAT --to-destination 1.2.3.4:443
2.1.3 本地端口转发
iptables -t nat -A PREROUTING -d 10.74.107.200 -p tcp --dport 80 -j REDIRECT --to-port 8080 # 若 8080 监听于 localhost,则可能需要执行:sysctl -w net.ipv4.conf.all.route_localnet=1
注意:
确保 /etc/modules
中加载了 xt_REDIRECT
模块。
2.2 封堵端口
iptables -I INPUT -p tcp --dport <port> -j REJECT iptables -I OUTPUT -p tcp --sport <port> -j REJECT
2.2.1 REJECT 策略
iptables -A INPUT -p tcp --dport 2222 -j REJECT --reject-with tcp-reset
类型 | 协议 | 含义 |
---|---|---|
icmp-port-unreachable | ICMP | 表示端口不可达(默认) |
icmp-host-unreachable | ICMP | 表示主机不可达 |
icmp-net-unreachable | ICMP | 表示网络不可达 |
icmp-proto-unreachable | ICMP | 协议不可达(比如你发的是 UDP 结果我不支持)} |
icmp-admin-prohibited | ICMP | 拒绝访问,通常表示"被防火墙禁止" |
tcp-reset | TCP | 直接发送一个 RST(重置连接)包,而不是用 ICMP(适合 TCP 拒绝) |
echo-reply | ICMP | 回应一个 ICMP Echo(基本没啥实用价值) |
2.3 随机丢包
iptables -A OUTPUT -p tcp --dport 2222 -m statistic --mode random --probability 0.3 -j DROP
也可用 tc 来实现:(接口级别)
tc qdisc add dev lo root netem loss 30% # send to localhost tc qdisc del dev lo root # remove qdisc (Queueing Discipline)
2.4 禁止 SYN floods
# Limit the number of incoming tcp connections # Incoming syn-flood protection iptables -N syn_flood iptables -A INPUT -p tcp --syn -j syn_flood iptables -A syn_flood -m limit --limit 1/s --limit-burst 3 -j RETURN iptables -A syn_flood -j REJECT # --limit 1/s: Maximum average matching rate in seconds # --limit-burst 3: Maximum initial number of packets to match
2.5 限制连接数
iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 3 -j DROP # 超过 3 个连接则拒绝
2.6 限速
iptables -A INPUT -p tcp --dport 80 \
-m limit --limit 10/second --limit-burst 20 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j DROP
每秒只允许最多 10 个请求(突发最多 20 个),其余直接丢掉。
2.7 防止 DoS
利用 recent 和 state 模块限制单个 IP 在 300 秒内只能与本机建立 3 个新连接,被限制 5 分钟周恢复访问。
iptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH iptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 300 --hitcount 3 --name SSH -j DROP # --name: 指定记录名称 # --set: 记录数据包的来源 IP,若已存在,则更新 # --update: 每次建立连接都要更新记录 # --seconds: 必须与 --rcheck 或 --update 同时使用 # --hitcount: 必须与 --rcheck 或 --update 同时使用 # 记录保存于:/proc/net/ipt_recent/SSH
2.8 LOG
for c in PREROUTING OUTPUT; do iptables -t nat -I $c -d <dest-ip> -j LOG --log-prefix "DBG@$c: " --log-level 4 # log level: 0 - 7 [emerg,alert,crit,error,warning,notice,info,debug] # 4: standard syslog level (warning) done