2_iptables规则实战
1. 命令语法总览
一条 iptables 命令由四个部分组成:操作哪张表的哪条链、做什么操作、匹配什么条件、执行什么动作。
1 | iptables [-t 表名] 操作命令 [链名] [匹配条件] [-j 动作] |
示例拆解:
1 | iptables -t filter -I INPUT -s 192.168.1.1 -p tcp --dport 22 -j DROP |
1.1 操作参数
决定对规则做什么操作(增、删、改、查、清空)。
| 参数 | 全称 | 作用 | 示例 |
|---|---|---|---|
-I | Insert | 插入规则到链头部(或指定位置) | -I INPUT、-I INPUT 3 |
-A | Append | 追加规则到链尾部 | -A INPUT |
-D | Delete | 删除规则(按编号或条件) | -D INPUT 3、-D INPUT -s 1.1.1.1 -j DROP |
-R | Replace | 替换指定编号的规则 | -R INPUT 3 -s 1.1.1.1 -j ACCEPT |
-L | List | 列出规则 | -L、-L INPUT |
-F | Flush | 清空链中的所有规则 | -F、-F INPUT |
-X | 删除自定义链 | -X MY_CHAIN | |
-P | Policy | 设置链的默认策略 | -P INPUT DROP |
-N | New | 创建自定义链 | -N MY_CHAIN |
1.2 表和链参数
| 参数 | 作用 | 说明 |
|---|---|---|
-t | 指定操作的表 | filter(默认,可省略)、nat、mangle、raw |
| 链名 | 跟在操作参数后面 | INPUT、OUTPUT、FORWARD、PREROUTING、POSTROUTING |
1.3 匹配条件参数
决定规则 “ 抓什么包 “。多个条件同时使用时是 “ 与 “ 关系,所有条件都满足才匹配。
| 参数 | 作用 | 示例 |
|---|---|---|
-s | 源地址 | -s 192.168.1.0/24、-s 1.1.1.1,2.2.2.2 |
-d | 目标地址 | -d 10.0.0.1 |
-p | 协议 | -p tcp、-p udp、-p icmp |
-i | 入口网卡 | -i eth0 |
-o | 出口网卡 | -o eth1 |
-m | 加载扩展模块 | -m tcp、-m multiport、-m state |
--dport | 目标端口(需 -m 模块) | --dport 22、--dport 80:88 |
--sport | 源端口(需 -m 模块) | --sport 1024:65535 |
! | 取反 | ! -s 1.1.1.1、! --dport 22 |
1.4 动作参数
| 参数 | 作用 | 说明 |
|---|---|---|
-j ACCEPT | 放行 | 允许数据包通过 |
-j DROP | 丢弃 | 静默丢弃,不返回任何响应 |
-j REJECT | 拒绝 | 丢弃并返回错误信息(如 ICMP port unreachable) |
-j LOG | 记录日志 | 记录后继续匹配后续规则,不终止 |
-j SNAT | 源地址转换 | 用于 nat 表 POSTROUTING 链 |
-j DNAT | 目标地址转换 | 用于 nat 表 PREROUTING 链 |
-j MASQUERADE | 动态源地址转换 | 类似 SNAT,适用于动态 IP |
1.5 显示辅助参数
| 参数 | 作用 |
|---|---|
-n | 不做 DNS 反解,IP 直接显示为数字 |
-v | 显示详细信息(包计数、字节数等) |
--line-numbers | 显示规则编号 |
下面用一张图展示命令的组成结构:
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6', 'primaryTextColor': '#1E3A5F', 'primaryBorderColor': '#2563EB', 'lineColor': '#60A5FA', 'secondaryColor': '#10B981', 'tertiaryColor': '#F59E0B'}}}%%
flowchart LR
CMD["iptables"] --> TBL["-t 表名"]
CMD --> OP["操作参数"]
OP --> CHAIN["链名"]
CHAIN --> MATCH["匹配条件"]
MATCH --> ACTION["-j 动作"]
TBL -.- T1["filter"]
TBL -.- T2["nat"]
TBL -.- T3["mangle / raw"]
OP -.- O1["-I 插入"]
OP -.- O2["-A 追加"]
OP -.- O3["-D 删除"]
OP -.- O4["-L 查看"]
MATCH -.- M1["-s 源地址"]
MATCH -.- M2["-d 目标地址"]
MATCH -.- M3["-p 协议"]
MATCH -.- M4["-m 扩展模块"]
ACTION -.- A1["ACCEPT"]
ACTION -.- A2["DROP"]
ACTION -.- A3["REJECT"]
classDef primary fill:#3B82F6,stroke:#2563EB,color:#fff
classDef success fill:#10B981,stroke:#059669,color:#fff
classDef warning fill:#F59E0B,stroke:#D97706,color:#fff
classDef info fill:#0EA5E9,stroke:#0284C7,color:#fff
class CMD primary
class TBL,OP,CHAIN,MATCH,ACTION info
class T1,T2,T3,O1,O2,O3,O4,M1,M2,M3,M4,A1,A2,A3 success参数语法搞清楚后,接下来通过实际操作逐步掌握它们的用法。
2. 查看规则
动手之前,先学会看规则。
2.1 基础查看
1 | # 查看 filter 表所有链的规则(filter 是默认表,可省略 -t filter) |
-L 的输出信息太少,实际工作中几乎不用裸 -L。
2.2 详细查看
1 | iptables --line-numbers -nvL INPUT |
各选项含义:
| 选项 | 作用 |
|---|---|
--line-numbers(可简写 --line) | 显示规则编号,删除时需要 |
-n | 不做 DNS 反解,IP 显示为数字,速度更快 |
-v | 显示详细信息,包括计数器 |
-L INPUT | 只看 INPUT 链(也可以换成 FORWARD、OUTPUT 等) |
示例输出:
1 | Chain INPUT (policy ACCEPT 14M packets, 2062M bytes) |
2.3 输出字段解读
链头部信息:Chain INPUT (policy ACCEPT 14M packets, 2062M bytes)
| 字段 | 含义 |
|---|---|
policy ACCEPT | 默认策略为 ACCEPT:未被任何规则匹配到的包,默认放行 |
14M packets | 默认策略已匹配到 1400 万个包 |
2062M bytes | 这些包的总大小为 2062MB |
规则字段:
| 字段 | 含义 | 说明 |
|---|---|---|
num | 规则编号 | 删除规则时使用 |
pkts | 此规则匹配到的包数量 | 判断规则是否生效 |
bytes | 匹配到的包的总大小 | 同上 |
target | 动作 | ACCEPT / DROP / REJECT / 自定义链名 |
prot | 协议 | tcp / udp / icmp / all |
opt | 选项 | 一般为 -- |
in | 入口网卡 | * 表示任意 |
out | 出口网卡 | * 表示任意 |
source | 源地址 | 0.0.0.0/0 表示任意 |
destination | 目标地址 | 0.0.0.0/0 表示任意 |
用
pkts和bytes列判断规则是否生效。如果加了规则但计数器一直是 0,说明没有报文命中——要么匹配条件写错,要么规则被前面的规则抢先匹配。
查看规则掌握后,接下来学习规则的增删改操作。
3. 增加规则
3.1 第一条规则
先清空 filter 表的 INPUT 链,从零开始(生产环境慎用):
1 | iptables -F INPUT |
添加一条规则,禁止来自 123.117.179.97 的所有流量:
1 | iptables -t filter -I INPUT -s 123.117.179.97 -j DROP |
逐段拆解:
| 部分 | 含义 |
|---|---|
-t filter | 操作 filter 表(可省略,默认就是 filter) |
-I INPUT | 在 INPUT 链头部插入规则(Insert) |
-s 123.117.179.97 | 匹配条件:源地址为该 IP |
-j DROP | 动作:丢弃 |
验证:
1 | iptables -nvL INPUT |
3.2 -I 和 -A 的区别
1 | # -I:插入到链的头部(第 1 条),最先被匹配 |
3.3 规则顺序至关重要
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6', 'primaryTextColor': '#1E3A5F', 'primaryBorderColor': '#2563EB', 'lineColor': '#60A5FA', 'secondaryColor': '#10B981', 'tertiaryColor': '#F59E0B'}}}%%
flowchart TD
PKT(["数据包进入"]) --> R1{"规则1: 张三 -> 拒绝"}
R1 -->|"匹配"| DROP1["DROP: 拒绝张三"]
R1 -->|"不匹配"| R2{"规则2: 所有人 -> 放行"}
R2 -->|"匹配"| ACC["ACCEPT: 放行"]
R2 -->|"不匹配"| R3{"规则3: 李四 -> 拒绝"}
R3 -->|"匹配"| DROP2["DROP: 拒绝李四"]
R3 -->|"不匹配"| DEF["默认策略"]
classDef primary fill:#3B82F6,stroke:#2563EB,color:#fff
classDef success fill:#10B981,stroke:#059669,color:#fff
classDef danger fill:#EF4444,stroke:#DC2626,color:#fff
classDef decision fill:#F59E0B,stroke:#D97706,color:#fff
class PKT primary
class ACC success
class DROP1,DROP2 danger
class R1,R2,R3 decision
class DEF primary这是 iptables 最容易踩的坑。规则从上往下逐条匹配,命中第一条就执行动作并停止后续匹配。
类比保安查名单:
1 | 规则1:张三 → 拒绝 |
张三被规则 1 拦住。但规则 3 想拦李四?没用——李四在规则 2 就被放行了,根本走不到规则 3。
实际例子:
1 | # 错误:先放行所有 → 再拒绝某个 IP → 拒绝规则永远不会生效 |
规则的增加和顺序搞清楚后,还需要掌握规则的删除和修改。
4. 删除规则
两种方式:
1 | # 方式一:按编号删除(先查编号) |
⚠️ 如果默认策略是 DROP,执行
-F清空规则后,所有流量都会被拒绝——包括你的 SSH 连接。你会把自己锁在外面。
5. 修改规则
建议采用 “ 先删后加 “ 的方式,比 -R 更安全:
1 | # 不推荐:用 -R 修改(必须记住编号和原始匹配条件) |
修改默认策略(不是修改规则,是修改链的兜底动作):
1 | # 将 FORWARD 链的默认策略改为 ACCEPT |
增删改查都覆盖后,接下来深入匹配条件——它决定了规则 “ 抓什么包 “。
6. 匹配条件详解
匹配条件决定了规则筛选数据包的维度。第 1 章已列出所有参数速查,这里展开讲解每个条件的细节和注意事项。
6.1 源地址匹配 -s
1 | # 单个 IP |
取反的常见误区
! -s 1.1.1.6 -j ACCEPT 的含义:
- ✅ 正确理解:源 IP 不是 1.1.1.6 → 放行
- ❌ 错误理解:源 IP 是 1.1.1.6 → 拒绝
两者完全不同:源 IP 是 1.1.1.6 的包不匹配这条规则,它会继续往下走匹配后续规则,而不是被拒绝。
6.2 目标地址匹配 -d
1 | # 只丢弃从 1.1.1.7 发往本机 IP 1.1.1.8 的报文 |
- 不指定
-s:源地址默认0.0.0.0/0(任意) - 不指定
-d:目标地址默认0.0.0.0/0(任意) -d同样支持多 IP、网段、取反
多条件组合是 “ 与 “ 关系:
-s 1.1.1.7 -d 1.1.1.8表示源地址为 1.1.1.7 且目标地址为 1.1.1.8 的包才匹配。
6.3 协议匹配 -p
1 | # 拒绝来自 1.1.1.2 的 TCP 请求 |
支持的协议类型:tcp, udp, icmp, udplite, esp, ah, sctp(CentOS 7 还支持 icmpv6, mh)。
不指定 -p 时默认匹配所有协议,等同于 -p all。
6.4 网卡匹配 -i / -o
当服务器有多块网卡时,可以按网卡过滤:
1 | # 丢弃从 eth0 流入的 ICMP 报文 |
使用限制:
| 选项 | 含义 | 可用链 | 不可用链 |
|---|---|---|---|
-i | 报文从哪块网卡流入 | PREROUTING、INPUT、FORWARD | OUTPUT、POSTROUTING |
-o | 报文从哪块网卡流出 | FORWARD、OUTPUT、POSTROUTING | PREROUTING、INPUT |
数据包还没进来时,谈不上 “ 从哪个网卡出去 “;已经出去的包,也谈不上 “ 从哪个网卡进来 “。
6.5 扩展匹配模块
基本匹配条件之外,iptables 通过 -m 加载扩展模块来支持更丰富的匹配能力。
Tcp 扩展模块
1 | # 拒绝来自 1.1.1.2 的、目标端口为 22(SSH)的 TCP 请求 |
拆解 -p tcp -m tcp --dport 22:
| 部分 | 作用 |
|---|---|
-p tcp | 匹配 TCP 协议的报文 |
-m tcp | 加载 tcp 扩展模块 |
--dport 22 | tcp 模块提供的匹配条件:目标端口为 22 |
-p tcp和-m tcp不冲突:-p过滤协议,-m加载模块。只是碰巧模块也叫 tcp。
端口范围和源端口:
1 | # 目标端口 22~25 |
Multiport 扩展模块
tcp 模块只能指定连续端口范围。指定多个离散端口需要 multiport 模块:
1 | # 同时拒绝 22、80、443 端口 |
State 扩展模块
state 模块基于 netfilter 的连接跟踪(conntrack)机制,按连接状态过滤数据包。注意:这里的 “ 状态 “ 不是 TCP 协议的状态(SYN_SENT、TIME_WAIT 等),而是 conntrack 自己维护的一套状态,适用于 TCP、UDP、ICMP 等所有协议。
| 状态 | 含义 | 典型场景 |
|---|---|---|
NEW | 连接的第一个包 | 客户端发来的 SYN 包、第一个 UDP 包、第一个 ICMP echo-request |
ESTABLISHED | 已建立连接的后续包(双向都算) | TCP 三次握手后的数据包、UDP 收到过回包后的后续包 |
RELATED | 与已有连接相关的新连接 | FTP 数据通道(由控制通道协商产生)、ICMP 错误回复(如 port unreachable) |
INVALID | 无法识别或不属于任何已知连接的包 | 校验和错误、无法关联到任何 conntrack 条目的包 |
1 | # 放行已建立连接和相关连接的回包(几乎所有防火墙配置都需要这条) |
为什么 ESTABLISHED,RELATED 这条规则几乎必加?服务器主动发起的请求(如 curl 外部 API、DNS 查询、yum 更新),其响应包的状态是 ESTABLISHED。不加这条规则,服务器自身的对外请求也会被拦截。
各匹配条件总览:
| 分类 | 参数 | 作用 | 示例值 |
|---|---|---|---|
| 基本匹配 | -s | 源地址 | 单 IP、多 IP、网段、取反 |
| 基本匹配 | -d | 目标地址 | 同上 |
| 基本匹配 | -p | 协议 | tcp、udp、icmp |
| 基本匹配 | -i / -o | 入口/出口网卡 | eth0、eth1 |
| 扩展匹配 | -m tcp | tcp 模块 | --dport 22、--sport 80、--dport 22:25 |
| 扩展匹配 | -m multiport | 多端口模块 | --dports 22,80,443、--dports 22,80:88,443 |
| 扩展匹配 | -m state | 连接状态模块 | --state ESTABLISHED,RELATED,NEW |
匹配条件掌握后,看看如何将它们组织成完整的防护策略。
7. 黑白名单机制
两种策略的核心区别在于默认策略和规则动作的方向相反:黑名单默认放行、只拦已知威胁;白名单默认拒绝、只放明确允许的流量。
7.1 黑名单模式
- 默认策略:ACCEPT(放行一切)
- 规则动作:DROP / REJECT(只拦特定目标)
- 适合场景:大部分流量正常,只需拦截少量已知恶意 IP
类比:开放式公园,门口贴了几张通缉犯照片,只拦这些人,其他人自由进出。
7.2 白名单模式
- 默认策略:DROP(拒绝一切)
- 规则动作:ACCEPT(只放行明确允许的)
- 适合场景:安全要求高,只开放必要的端口和 IP
类比:私人会所,门口有一份邀请名单,名单上的才能进,其他人一律拒绝。
7.3 白名单的安全实践
⚠️ 不要直接用
-P DROP设置默认策略!
原因:执行 iptables -F 清空规则后(比如调试时手滑),默认策略 DROP 仍然生效,所有流量都被拒绝——包括 SSH,你会被锁在服务器外面。
安全做法:保持默认策略为 ACCEPT,在链的最后一条加上 “ 拒绝所有 “ 作为兜底:
1 | # 默认策略保持 ACCEPT(安全网) |
这样即使 iptables -F 清空规则,默认策略 ACCEPT 会保证 SSH 不断。
策略确定后,还要解决一个实际问题:规则怎么保存?
8. 规则持久化
iptables 规则存储在内核内存中,重启即丢失,必须手动保存。
8.1 CentOS / RHEL
1 | # CentOS 6 |
导出/导入方式:
1 | # 导出当前规则到文件 |
8.2 Ubuntu / Debian
1 | sudo apt-get install iptables-persistent |
所有基础操作都准备就绪,下面用一个完整案例把它们串起来。
9. 实战:Web 服务器防火墙配置
假设你有一台全新的云服务器,运行 Nginx(80/443)和 SSH(22),需要配置防火墙。
需求:
- 允许 SSH(端口 22)
- 允许 HTTP(端口 80)和 HTTPS(端口 443)
- 允许已建立连接的回包(如服务器主动请求外部 API 的响应)
- 允许本机回环通信(localhost)
- 拒绝其他一切入站流量
- 不限制出站流量
1 |
|
配置后验证:
1 | # 查看规则和计数器 |
10. 命令速查表
1 | # ========== 查看 ========== |
下一篇:iptables 进阶与连接跟踪 —— conntrack 连接跟踪原理,state 扩展、常用扩展模块、TCP 标志位匹配和自定义链管理。