1. 理解 iptables
的基本结构
在深入扩展之前,请确保您理解 iptables
的基本框架:
-
Tables(表): 用于特定功能的链的集合。最常用的是
filter
(过滤)、nat
(网络地址转换)和mangle
(数据包修改)。 -
Chains(链): 规则的有序列表,存在于表中。例如
INPUT
、OUTPUT
、FORWARD
。 -
Rules(规则): 定义了对数据包进行匹配和处理的指令。
-
Matches(匹配): 规则中用于筛选数据包的条件。
-
Targets(目标): 当数据包匹配一条规则时,要执行的动作(如
ACCEPT
、DROP
、REJECT
)。
语法概览:
iptables -t <table> -A <chain> [matches] -j <target>
-
-t <table>
: 指定表,默认为filter
。 -
-A <chain>
: 向链末尾追加一条规则。 -
[matches]
: 一个或多个匹配条件。 -
-j <target>
: 跳转到目标。
2. 常用扩展模块详解与实例
大多数扩展模块通过 -m
选项加载。
2.1 state
– 连接状态跟踪
这是最重要的模块之一,实现了“状态防火墙”,极大地简化了规则配置。
-
模块名:
state
-
常用匹配:
--state
-
状态类型:
-
NEW
: 新建立的连接。 -
ESTABLISHED
: 已建立的连接,即该连接的后续包。 -
RELATED
: 与已建立连接相关的连接,如 FTP 的数据连接或 ICMP 错误消息。 -
INVALID
: 无法识别的或无效的数据包。
-
实例1: 允许出站流量及其回包
# 允许本机发起的出站流量(NEW 状态) iptables -A OUTPUT -m state --state NEW,ESTABLISHED -j ACCEPT # 允许属于已建立连接的回包进入(ESTABLISHED, RELATED 状态) iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
这是防火墙配置的基础,确保了如果你从内部发起请求,响应包可以回来。
实例2: 允许 SSH 入站连接
# 允许外部发起的 NEW 状态的 SSH 连接进入 iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j ACCEPT # 注意:你仍然需要上面的 ESTABLISHED 规则来处理 SSH 连接的后续通信
2.2 multiport
– 多端口匹配
允许在一条规则中匹配多个不连续的端口。
-
模块名:
multiport
-
常用匹配:
-
--dports
: 目标端口列表。 -
--sports
: 源端口列表。
-
实例: 允许访问多个服务
# 允许访问 HTTP(80), HTTPS(443), 和 SSH(22) 端口 iptables -A INPUT -p tcp -m multiport --dports 22,80,443 -m state --state NEW -j ACCEPT
这比写三条独立的规则更简洁、高效。
2.3 limit
– 速率限制
用于限制匹配规则的速率,常用于防止洪水攻击。
-
模块名:
limit
-
常用匹配:
-
--limit
: 平均速率(如10/second
,5/minute
,2/hour
)。 -
--limit-burst
: 初始突发包数量。
-
实例: 限制 ICMP (Ping) 请求
# 前 5 个 Ping 请求正常通过(burst) iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/second --limit-burst 5 -j ACCEPT # 超过限制的 Ping 请求将被丢弃(不记录,因为上一条规则已经“处理”了它们,只是限速) iptables -A INPUT -p icmp --icmp-type echo-request -j DROP
这样,别人对你的服务器进行 Ping 时,前5个很快,之后就会被限制在每秒1个。
2.4 connlimit
– 连接数限制
限制每个客户端 IP 地址到特定服务的并发连接数。
-
模块名:
connlimit
-
常用匹配:
-
--connlimit-above [n]
: 当连接数超过n
时匹配。
-
实例: 防止 SSH 暴力破解
# 限制每个 IP 地址同时只能有 3 个 SSH 连接 iptables -A INPUT -p tcp --dport 22 -m connlimit --connlimit-above 3 -j REJECT
这可以有效减缓攻击者尝试多个密码的速度。
2.5 recent
– 动态列表
这是一个非常强大的模块,可以动态地创建和管理一个 IP 地址列表。常用于应对扫描和暴力攻击。
-
模块名:
recent
-
常用参数:
-
--name [listname]
: 指定列表名称。 -
--set
: 将源 IP 添加到列表。 -
--rcheck
: 检查 IP 是否在列表中。 -
--update
: 同--rcheck
,但会更新时间戳。 -
--seconds [n]
: 与--rcheck
或--update
一起使用,指定时间窗口。 -
--hitcount [n]
: 在时间窗口内命中的次数。
-
实例: 端口敲门 (Port Knocking) 或防扫描
# 目标:如果某个 IP 在 60 秒内对超过 5 个不同的端口发送 SYN 包,则封禁该 IP 5 分钟。 # 1. 创建一个名为 'portscan’ 的列表,记录扫描者 IP iptables -A INPUT -p tcp --tcp-flags SYN,ACK,FIN,RST SYN -m recent --name portscan --set -j DROP # 2. 检查该 IP 在 60 秒内是否已经尝试连接了超过 5 次(--hitcount 6) iptables -A INPUT -m recent --name portscan --rcheck --seconds 60 --hitcount 6 -j LOG --log-prefix "Portscan blocked: " iptables -A INPUT -m recent --name portscan --rcheck --seconds 60 --hitcount 6 -j DROP # 3. 可选: 600 秒后将该 IP 从列表中移除 # (这通常由 `recent` 模块自动管理,但可以通过 `/proc/net/xt_recent/` 手动操作)
2.6 string
– 字符串匹配
可以在数据包负载(Payload)中搜索特定字符串。
-
模块名:
string
-
常用匹配:
-
--string "[pattern]"
: 要匹配的字符串。 -
--algo [algorithm]
: 匹配算法,如bm
(Boyer-Moore) 或kmp
。
-
实例: 屏蔽含有 “blocked-site.com” 的 HTTP 请求
# 假设服务器是透明代理。阻止访问特定域名的 HTTP 请求。 iptables -A FORWARD -p tcp --dport 80 -m string --string "Host: blocked-site.com" --algo bm -j DROP
注意: 此模块对性能有较大影响,且不适用于加密流量(HTTPS)。
2.7 iprange
– IP 范围匹配
匹配一个范围内的 IP 地址,比使用子网掩码更灵活。
-
模块名:
iprange
-
常用匹配:
-
--src-range
: 源 IP 范围。 -
--dst-range
: 目标 IP 范围。
-
实例: 允许内部一个 IP 段访问
# 允许 192.168.1.10 到 192.168.1.50 的 IP 访问 MySQL iptables -A INPUT -p tcp --dport 3306 -m iprange --src-range 192.168.1.10-192.168.1.50 -j ACCEPT
3. 高级功能与表
3.1 nat
表 – 网络地址转换
用于修改数据包的源或目标地址。
-
SNAT
(Source NAT): 修改出站数据包的源地址。常用于共享上网。-
-j SNAT --to-source [ip]
-
-
DNAT
(Destination NAT): 修改入站数据包的目标地址。常用于端口转发。-
-j DNAT --to-destination [ip]:[port]
-
-
MASQUERADE
:SNAT
的一种特殊形式,用于动态获取 IP 的接口(如 PPPoE、DHCP)。
实例1: 共享上网 (网关服务器)
# 启用 IP 转发 sysctl -w net.ipv4.ip_forward=1 # 对从内网 (eth1) 发出,前往外网 (eth0) 的流量进行源地址转换 iptables -t nat -A POSTROUTING -o eth0 -s 192.168.1.0/24 -j MASQUERADE
实例2: 端口转发 (将公网 IP 的 8080 转发到内网 Web 服务器)
# 在 PREROUTING 链中,将到达本机 8080 端口的流量目标改为内网服务器 iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.100:80 # 在 POSTROUTING 链中,修改源地址,让回包能正确返回 iptables -t nat -A POSTROUTING -p tcp -d 192.168.1.100 --dport 80 -j MASQUERADE # 同时需要在 filter 表的 FORWARD 链中允许此流量 iptables -A FORWARD -p tcp -d 192.168.1.100 --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A FORWARD -p tcp -s 192.168.1.100 --sport 80 -m state --state ESTABLISHED -j ACCEPT
3.2 mangle
表 – 数据包修改
用于修改数据包的 TTL、TOS 等字段,或结合 MARK
目标打标记,用于高级路由策略。
-
常用目标:
-j MARK --set-mark [value]
实例: 对特定端口的流量打标记,用于策略路由
# 给 SSH 流量 (端口 22) 打上标记 1 iptables -t mangle -A OUTPUT -p tcp --dport 22 -j MARK --set-mark 1
然后,你可以在路由规则(ip rule
)中使用 fwmark 1
来让这些数据包走不同的路由表。
4. 综合实战: 一个简单的 Web 服务器防火墙
#!/bin/bash # 重置所有规则 iptables -F iptables -t nat -F iptables -X # 删除用户自定义链 # 设置默认策略(谨慎使用 DROP,可能导致自己被锁在外面) iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT ACCEPT # 允许本地回环接口 iptables -A INPUT -i lo -j ACCEPT # 允许已建立和相关的连接进入(这是状态防火墙的核心) iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # 允许 ICMP (Ping),但加以限制 iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/second -j ACCEPT # 允许 SSH,但限制每个 IP 最多 3 个连接 iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m connlimit --connlimit-above 3 -j REJECT iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j ACCEPT # 允许 HTTP 和 HTTPS iptables -A INPUT -p tcp -m multiport --dports 80,443 -m state --state NEW -j ACCEPT # 记录并丢弃所有其他流量(可选) iptables -A INPUT -j LOG --log-prefix "IPTables-Dropped: " iptables -A INPUT -j DROP echo "Firewall rules applied."
5. 重要提示
-
测试规则: 在应用任何可能断开你连接的规则(尤其是默认
DROP
)之前,务必在本地控制台测试,或者设置一个cron
job 在几分钟后恢复规则。 -
规则顺序:
iptables
规则按顺序匹配,第一条匹配的规则生效。请合理安排顺序。 -
持久化: 上述规则在重启后会丢失。请使用
iptables-save > /etc/iptables.rules
保存,并在启动脚本中通过iptables-restore < /etc/iptables.rules
恢复。不同发行版有不同工具(如iptables-persistent
)。 -
从
iptables
到nftables
:iptables
正在被nftables
取代。建议新项目学习nftables
,但其概念和功能与iptables
一脉相承。
这份教程涵盖了 iptables
最实用和强大的部分。通过组合使用这些模块和功能,你可以构建出非常精细和强大的防火墙策略。