第 09 章:扩展目标与动作
第 09 章:扩展目标与动作
本章目标:掌握 iptables 的各种扩展目标(Target),能够使用 LOG、REJECT、TEE、NFQUEUE 等高级动作实现日志记录、流量镜像、用户态处理等功能。
9.1 目标(Target)分类
9.1.1 基本目标 vs 扩展目标
| 类型 | 目标 | 说明 |
|---|---|---|
| 基本目标 | ACCEPT | 接受数据包(不需要加载模块) |
| 基本目标 | DROP | 丢弃数据包(不需要加载模块) |
| 基本目标 | RETURN | 返回调用链 |
| 扩展目标 | REJECT | 拒绝并返回错误(需要 ipt_REJECT 模块) |
| 扩展目标 | LOG | 记录日志(需要 ipt_LOG 模块) |
| 扩展目标 | MASQUERADE | 动态 SNAT |
| 扩本目标 | DNAT/SNAT | 目的/源地址转换 |
| 扩展目标 | REDIRECT | 端口重定向 |
| 扩展目标 | MARK | 设置标记 |
| 扩展目标 | TEE | 流量镜像 |
| 扩展目标 | NFQUEUE | 传递到用户态 |
| 扩展目标 | NOTRACK | 跳过连接跟踪 |
9.2 LOG 目标
9.2.1 用途
LOG 目标将匹配的数据包信息记录到系统日志,而不终止规则遍历(与 ACCEPT/DROP 不同)。这是调试防火墙规则的重要工具。
9.2.2 语法
# 基本日志记录
iptables -A INPUT -j LOG
# 带前缀的日志
iptables -A INPUT -p tcp --dport 22 -j LOG --log-prefix "SSH-ACCESS: "
# 指定日志级别
iptables -A INPUT -j LOG --log-level 4 # warning
# 同时记录 TCP 序列号(调试用)
iptables -A INPUT -j LOG --log-tcp-sequence
# 同时记录 IP 选项
iptables -A INPUT -j LOG --log-ip-options
# 同时记录 TCP 选项
iptables -A INPUT -j LOG --log-tcp-options
9.2.3 参数说明
| 参数 | 说明 | 默认值 |
|---|---|---|
--log-prefix | 日志前缀(最多 29 字符) | 空 |
--log-level | 日志级别(0-7) | 4 (warning) |
--log-tcp-sequence | 记录 TCP 序列号 | 关闭 |
--log-tcp-options | 记录 TCP 选项 | 关闭 |
--log-ip-options | 记录 IP 选项 | 关闭 |
--log-uid | 记录发起进程的 UID | 关闭 |
9.2.4 日志级别
| 级别 | 名称 | 说明 |
|---|---|---|
| 0 | emerg | 紧急 |
| 1 | alert | 警报 |
| 2 | crit | 临界 |
| 3 | err | 错误 |
| 4 | warning | 警告(推荐) |
| 5 | notice | 通知 |
| 6 | info | 信息 |
| 7 | debug | 调试 |
9.2.5 日志配置
# iptables 日志默认写入 /var/log/messages 或 /var/log/kern.log
# 可以通过 rsyslog 配置分离 iptables 日志
# 创建 /etc/rsyslog.d/iptables.conf
cat > /etc/rsyslog.d/iptables.conf << 'EOF'
:msg, contains, "IPT-" /var/log/iptables.log
& stop
EOF
# 重启 rsyslog
systemctl restart rsyslog
# 配合 logrotate 防止日志过大
cat > /etc/logrotate.d/iptables << 'EOF'
/var/log/iptables.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 0640 root root
postrotate
/usr/bin/systemctl reload rsyslog > /dev/null 2>&1 || true
endscript
}
EOF
9.2.6 业务场景
#!/bin/bash
# ═══════════════════════════════════════════════════
# 日志记录方案
# ═══════════════════════════════════════════════════
# 已建立的连接(不记录,减少日志量)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# 允许 SSH,记录登录尝试
iptables -A INPUT -p tcp --dport 22 --syn \
-j LOG --log-prefix "IPT-SSH-NEW: " --log-level 4
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# 记录被拒绝的 HTTP 请求
iptables -A INPUT -p tcp --dport 80 --syn \
-m hashlimit --hashlimit-above 50/sec --hashlimit-mode srcip \
--hashlimit-name http_log --hashlimit-burst 100 \
-j LOG --log-prefix "IPT-HTTP-RATE: " --log-level 4
# 记录所有被丢弃的数据包(限速,防止日志泛洪)
iptables -A INPUT \
-m limit --limit 10/min --limit-burst 20 \
-j LOG --log-prefix "IPT-INPUT-DROP: " --log-level 4
# 默认拒绝
iptables -P INPUT DROP
9.2.7 NFLOG 目标(推荐)
NFLOG 是 LOG 的替代方案,它将日志通过 Netlink 传递给用户态的 ulogd2 守护进程,性能更好、功能更强大:
# 使用 NFLOG 记录日志到 NFLOG group 1
iptables -A INPUT -j NFLOG --nflog-group 1 --nflog-prefix "IPT-DROP"
# ulogd2 配置可以将日志写入文件、数据库等
# 安装:apt install ulogd2
# 配置文件:/etc/ulogd.conf
| 特性 | LOG | NFLOG |
|---|---|---|
| 性能 | 较低(同步写入内核日志) | 高(异步 Netlink) |
| 目标 | syslog | ulogd2(可配置多种输出) |
| 格式 | 文本 | 可配置(文本、JSON、数据库) |
| 适用场景 | 简单日志需求 | 大规模日志收集 |
9.3 REJECT 目标
9.3.1 拒绝类型
# 默认拒绝(ICMP port unreachable)
iptables -A INPUT -p tcp --dport 8080 -j REJECT
# TCP RST 拒绝(适用于 TCP 协议)
iptables -A INPUT -p tcp --dport 8080 -j REJECT --reject-with tcp-reset
# ICMP 网络不可达
iptables -A INPUT -j REJECT --reject-with icmp-net-unreachable
# ICMP 主机不可达
iptables -A INPUT -j REJECT --reject-with icmp-host-unreachable
# ICMP 协议不可达
iptables -A INPUT -p tcp --dport 22 -j REJECT --reject-with icmp-proto-unreachable
9.3.2 拒绝类型一览
| 类型 | 说明 | 适用协议 |
|---|---|---|
icmp-net-unreachable | 网络不可达 | 所有 |
icmp-host-unreachable | 主机不可达 | 所有 |
icmp-port-unreachable | 端口不可达(默认) | 所有 |
icmp-proto-unreachable | 协议不可达 | 所有 |
icmp-net-prohibited | 网络被禁止 | 所有 |
icmp-host-prohibited | 主机被禁止 | 所有 |
icmp-admin-prohibited | 管理禁止 | 所有 |
tcp-reset | TCP RST | 仅 TCP |
9.3.3 DROP vs REJECT 选择指南
┌──────────────────┐
│ 使用场景? │
└────────┬─────────┘
┌─────┼──────┐
▼ ▼ ▼
生产环境 内部网络 调试/开发
外部接口 服务器间 环境
│ │ │
▼ ▼ ▼
DROP REJECT REJECT
(安全) (友好) (调试方便)
9.4 MASQUERADE 目标
9.4.1 与 SNAT 的对比
# SNAT(固定公网 IP)
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 \
-j SNAT --to-source 203.0.113.1
# MASQUERADE(动态 IP,如 DHCP 或拨号)
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 \
-j MASQUERADE
# MASQUERADE 指定端口范围
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 \
-j MASQUERADE --to-ports 1024-65535
9.5 TEE 目标
9.5.1 用途
TEE 目标将数据包的副本发送到另一个网关地址,实现流量镜像。原始数据包继续正常处理。
9.5.2 语法
# 将所有入站流量镜像到分析服务器
iptables -t mangle -A PREROUTING -i eth0 \
-j TEE --gateway 10.0.0.200
# 只镜像 HTTP 流量
iptables -t mangle -A PREROUTING -i eth0 -p tcp --dport 80 \
-j TEE --gateway 10.0.0.200
# 使用外部网关(跨网段需要路由可达)
iptables -t mangle -A PREROUTING -i eth0 \
-j TEE --gateway 192.168.100.1
9.5.3 业务场景
#!/bin/bash
# ═══════════════════════════════════════════════════
# 流量镜像到 IDS/IPS 入侵检测系统
# ═══════════════════════════════════════════════════
# 镜像所有入站流量到 Suricata/Snort 分析服务器
iptables -t mangle -A PREROUTING -i eth0 \
-m comment --comment "Mirror to IDS" \
-j TEE --gateway 10.0.0.200
# 只镜像特定端口的流量(减少分析服务器负载)
iptables -t mangle -A PREROUTING -i eth0 -p tcp \
-m multiport --dports 22,80,443,3306 \
-m comment --comment "Mirror critical ports to IDS" \
-j TEE --gateway 10.0.0.200
注意:TEE 需要目标网关在同一个广播域(二层可达),或者有路由可达。TEE 在 mangle 表中使用效果最佳。
9.6 NFQUEUE 目标
9.6.1 用途
NFQUEUE 将数据包传递到用户态程序进行处理。用户态程序可以决定接受(ACCEPT)、丢弃(DROP)或修改数据包。
9.6.2 语法
# 将数据包传递到队列 0
iptables -A INPUT -p tcp --dport 80 -j NFQUEUE --queue-num 0
# 传递到队列 0,不修改数据包(旁路模式)
iptables -A INPUT -j NFQUEUE --queue-num 0 --queue-bypass
# 多队列(多核并行处理)
iptables -A INPUT -p tcp --dport 80 -j NFQUEUE --queue-num 0
iptables -A INPUT -p tcp --dport 443 -j NFQUEUE --queue-num 1
9.6.3 用户态处理程序
#!/usr/bin/env python3
# 使用 nfqueue 库处理数据包
# 安装:pip3 install netfilterqueue
from netfilterqueue import NetfilterQueue
def packet_handler(packet):
"""处理每个数据包"""
print(f"Packet: {len(packet.get_payload())} bytes")
# 接受数据包
packet.accept()
nfqueue = NetfilterQueue()
nfqueue.bind(0, packet_handler) # 绑定队列 0
try:
nfqueue.run()
except KeyboardInterrupt:
nfqueue.unbind()
# 配置 iptables 规则
iptables -A INPUT -p tcp --dport 80 -j NFQUEUE --queue-num 0
# 运行用户态处理程序
sudo python3 nfqueue_handler.py
9.6.4 业务场景:WAF(Web 应用防火墙)
NFQUEUE 常用于实现用户态的 Web 应用防火墙,如基于 Python/Go 的自定义 WAF。它可以检查 HTTP 请求内容,识别并阻止 SQL 注入、XSS 等攻击。
9.7 CLASSIFY 目标
9.7.1 用途
CLASSIFY 目标为数据包设置 tc(traffic control)的类标识,配合 Linux 流量控制使用。
# 将 SSH 流量分类到高优先级类别
iptables -t mangle -A FORWARD -p tcp --dport 22 \
-j CLASSIFY --set-class 1:10
# 将 HTTP 流量分类到普通类别
iptables -t mangle -A FORWARD -p tcp --dport 80 \
-j CLASSIFY --set-class 1:20
# 将 P2P 流量分类到低优先级类别
iptables -t mangle -A FORWARD -p tcp --dport 6881:6889 \
-j CLASSIFY --set-class 1:40
9.8 SNAT 和 DNAT 的高级用法
9.8.1 多目标 NAT(负载均衡)
# 将 HTTP 流量随机分发到三台后端服务器
iptables -t nat -A PREROUTING -p tcp --dport 80 \
-m statistic --mode random --probability 0.33 \
-j DNAT --to-destination 10.0.0.10:80
iptables -t nat -A PREROUTING -p tcp --dport 80 \
-m statistic --mode random --probability 0.50 \
-j DNAT --to-destination 10.0.0.11:80
iptables -t nat -A PREROUTING -p tcp --dport 80 \
-j DNAT --to-destination 10.0.0.12:80
9.8.2 SNAT 端口范围
# 指定 SNAT 的源端口范围
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 \
-j SNAT --to-source 203.0.113.1:1024-65535
9.8.3 端口映射
# 将公网 8080 映射到内网 80
iptables -t nat -A PREROUTING -p tcp --dport 8080 \
-j DNAT --to-destination 10.0.0.10:80
# 将公网 2222 映射到内网 SSH 服务器的 22 端口
iptables -t nat -A PREROUTING -p tcp --dport 2222 \
-j DNAT --to-destination 10.0.0.5:22
# 映射整个端口段
iptables -t nat -A PREROUTING -p tcp --dport 5000:5100 \
-j DNAT --to-destination 10.0.0.10
9.9 自定义链作为目标
9.9.1 使用自定义链组织规则
#!/bin/bash
# ═══════════════════════════════════════════════════
# 使用自定义链的完整防火墙方案
# ═══════════════════════════════════════════════════
# 清空规则和自定义链
iptables -F
iptables -X
# ─── 创建自定义链 ───
# SSH 访问规则链
iptables -N SSH_CHAIN
iptables -A SSH_CHAIN -s 192.168.1.0/24 -j ACCEPT
iptables -A SSH_CHAIN -s 10.0.0.0/8 -j ACCEPT
iptables -A SSH_CHAIN -j LOG --log-prefix "IPT-SSH-DENY: "
iptables -A SSH_CHAIN -j DROP
# Web 访问规则链
iptables -N WEB_CHAIN
iptables -A WEB_CHAIN -p tcp -m multiport --dports 80,443 -j ACCEPT
iptables -A WEB_CHAIN -j DROP
# 数据库访问规则链
iptables -N DB_CHAIN
iptables -A DB_CHAIN -s 10.0.1.0/24 -p tcp --dport 3306 -j ACCEPT
iptables -A DB_CHAIN -s 10.0.1.0/24 -p tcp --dport 5432 -j ACCEPT
iptables -A DB_CHAIN -j LOG --log-prefix "IPT-DB-DENY: "
iptables -A DB_CHAIN -j DROP
# 日志链
iptables -N LOG_DROP
iptables -A LOG_DROP -m limit --limit 10/min --limit-burst 20 \
-j LOG --log-prefix "IPT-DROP: "
iptables -A LOG_DROP -j DROP
# ─── 主链规则 ───
# 已建立的连接
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# 回环接口
iptables -A INPUT -i lo -j ACCEPT
# SSH
iptables -A INPUT -p tcp --dport 22 -j SSH_CHAIN
# Web
iptables -A INPUT -j WEB_CHAIN
# 数据库
iptables -A INPUT -p tcp -m multiport --dports 3306,5432 -j DB_CHAIN
# 其他未匹配的包记录日志并丢弃
iptables -A INPUT -j LOG_DROP
# 默认策略
iptables -P INPUT DROP
9.10 注意事项
⚠️ LOG 不终止规则遍历:LOG 目标只是记录日志,数据包会继续匹配后续规则。如果同时有 LOG 和 DROP,需要分别写两条规则。
# 正确做法:LOG + DROP 分开
iptables -A INPUT -j LOG --log-prefix "IPT-DROP: "
iptables -A INPUT -j DROP
# 或使用自定义链
iptables -N LOG_AND_DROP
iptables -A LOG_AND_DROP -j LOG --log-prefix "IPT-DROP: "
iptables -A LOG_AND_DROP -j DROP
iptables -A INPUT -j LOG_AND_DROP
⚠️ LOG 的性能影响:高频日志会显著影响系统性能。务必配合
limit或hashlimit模块限速。
⚠️ TEE 的网络要求:TEE 需要目标网关在二层可达(同一广播域),否则需要配置 ARP 代理。
⚠️ NFQUEUE 的依赖:需要内核编译时启用
CONFIG_NETFILTER_XT_TARGET_NFQUEUE,并安装用户态库。
9.11 扩展阅读
| 资源 | 说明 |
|---|---|
man iptables-extensions | 所有扩展目标的手册 |
man ulogd2 | NFLOG 用户态守护进程 |
man tc | 流量控制工具 |
| Netfilter Queue | 用户态包处理库 |
本章小结
| 目标 | 功能 | 特点 |
|---|---|---|
| LOG | 记录日志 | 不终止遍历,继续匹配 |
| NFLOG | Netlink 日志 | 高性能,配合 ulogd2 |
| REJECT | 拒绝并回复 | 友好,暴露主机存在 |
| TEE | 流量镜像 | 副本发送到指定网关 |
| NFQUEUE | 用户态处理 | 灵活,适合 WAF/IDS |
| CLASSIFY | tc 分类 | 流量控制 |
下一章:第 10 章:连接跟踪机制,将深入学习 conntrack 的状态机和高级用法。