iptables
{Back to Index}  

Table of Contents

1 概述

1.1 命令格式

iptables [ -t 表名] 命令选项 [链名] [匹配] [-j 目标动作或跳转]

1.1.1 表 (操作维度)

在 iptables 中,每种表对应不同的功能(操作),由相应的内核模块提供支持:

  1. filter (iptables_filter)

    默认表,主要用于控制包是否被接受、丢弃或转发(过滤功能)

  2. nat (iptable_nat)

    用于地址转换,比如端口转发、SNAT、DNAT 等(修改目的地址/源地址)

  3. mangle (iptable_mangle)

    用于修改包的服务类型、TTL、打标记等(包的内容修改或打标)

  4. 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 四表五链

overview.png

Figure 1: 链与表的分布

overview_update.png

Figure 2: iptables/netfilter 整体架构

通过以下命令设置主机支持转发功能:

echo 1 > /proc/sys/net/ipv4/ip_forward

2 应用场景 1

2.1 NAT

nat.png

Figure 3: 网络地址映射

使用 NAT 技术一定会发生两次 IP 地址的转换(下面以内网访问外网为例):

  1. 内部网络的报文发送出去时,报文的源 IP 会被修改,也就是源地址转换(SNAT)
  2. 外部网络的报文响应时,响应报文的目标 IP 会再次被修改,也就是目标地址转换(DNAT)

上述过程被称为 SNAT ,是因为先发生了 SNAT。如果先使用 DNAT (比如外网穿透内网的场景,下面会讲到),则整个过程被称为 DNAT 。

也就是说,NAT 属于 SNAT 还是 DNAT ,取决于整个过程的最先使用了 SNAT 还是 DNAT 。

2.1.1 SNAT

snat.png

Figure 4: SNAT 网络拓扑

只是配置 SNAT 的话,并不用手动配置 DNAT ,iptables 会自动维护 NAT 表,自动执行 DNAT 将响应报文的目标地址转换回来。

2.1.2 DNAT

可用于从外部访问内部设备。

dnat.png

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

可以修改目标地址和端口,实现类似中间人攻击的效果。

output_dnat.png

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

Footnotes:

Author: Hao Ruan (ruanhao1116@gmail.com)

Created: 2021-01-08 Fri 12:08

Updated: 2025-04-11 Fri 09:12

Emacs 27.2 (Org mode 9.4.4)