强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

iptables 完全指南 / 第 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 目标(推荐)

NFLOGLOG 的替代方案,它将日志通过 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 的性能影响:高频日志会显著影响系统性能。务必配合 limithashlimit 模块限速。

⚠️ 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 的状态机和高级用法。