Netfilter & nftables
基本结构
prerouting
、input
、forward
、output
、postrouting
。drop
、accept
、dnat
、snat
、log
、reject
、masquerade
等)。常见命令行
sudo nft add table
:创建表sudo nft add chain { ... }
:创建链,指定类型、hook、priority、policy 等sudo nft add rule
:添加规则sudo nft list ruleset
:查看当前完整配置sudo nft delete rule/chain/table ...
:删除对应对象sudo nft flush ruleset
:清空所有规则(谨慎操作)协议族 (family)
ip
(仅 IPv4),ip6
(仅 IPv6),inet
(同时管理 IPv4/IPv6),arp
,bridge
等。inet
统一管理 IPv4/IPv6 防火墙规则(但NAT 通常只能使用 ip
或 ip6
)。常见 hook
prerouting
:数据包刚进来,还没决定路由input
:发往本机的数据包forward
:要转发给其他目的地的数据包output
:本机发出的数据包postrouting
:数据包即将离开本机,常用于 SNATingress
:更早阶段的过滤,在协议栈处理之前(见场景六)默认策略 (policy)
accept
:默认放行drop
:默认丢弃input
、forward
等)上设置 policy drop
,然后再加特定的放行规则(白名单式)。优先级 (priority)
priority
,以决定规则生效的先后顺序。prerouting
(DNAT)常用 priority -100
filter
(如 input
、forward
)常用 priority 0
postrouting
(SNAT)常用 priority 100
在一台常见的服务器上,你可能只想开放 SSH、HTTP、HTTPS,其他都拒绝,并且对本地回环 (lo
) 和已建立连接 (established
) 要放行。这是典型的应用场景。
# 创建一个名为 "firewall" 的表,协议族 "inet"(同时管IPv4+IPv6)
sudo nft add table inet firewall
# 在该表下创建一个链,类型 filter,挂到 input 阶段,优先级 0,默认策略为 drop
sudo nft add chain inet firewall input {
type filter hook input priority 0;
policy drop;
}
# 允许本地回环接口 (主要是127.0.0.1)
sudo nft add rule inet firewall input iifname "lo" accept
# 允许已建立(ESTABLISHED)或相关(RELATED)状态的连接继续
sudo nft add rule inet firewall input ct state established,related accept
# 允许 SSH (tcp/22)、HTTP (tcp/80)、HTTPS (tcp/443)
sudo nft add rule inet firewall input tcp dport {22,80,443} accept
# IPv4情况下:允许ICMP ping
sudo nft add rule inet firewall input ip protocol icmp icmp type echo-request accept
# IPv6情况下:允许ICMPv6 ping
sudo nft add rule inet firewall input ip6 nexthdr icmpv6 icmpv6 type echo-request accept
# 对于其他想要“显式拒绝”的端口或协议,
# 可以考虑用 reject 动作:
# sudo nft add rule inet firewall input tcp dport 23 reject with tcp reset
# (比 drop 动作更“可见”,会返回 RST 给对端)
# 以上未匹配到的流量(因为policy=drop)均丢弃
这样就完成了一个最常见的服务器防火墙规则:只允许某些常用端口和已建立的连接,其他丢弃。
如果你的机器同时扮演网关角色,需要做源地址转换 (SNAT/MASQUERADE) 和目的地址转换 (DNAT),则可以在 prerouting
/ postrouting
阶段进行 NAT 配置。
注意:NAT 功能通常仅在
ip
或ip6
family 下使用。常见的是ip nat
(IPv4)。
如果网关对外网的 IP 是 203.0.113.5
,内网网卡为 eth1
,外网网卡为 eth0
,要让内网 192.168.1.x
的流量通过网关统一 NAT 成 203.0.113.5
:
sudo nft add table ip nat
# 创建 chain: postrouting,用于 SNAT
sudo nft add chain ip nat postrouting {
type nat hook postrouting priority 100;
policy accept;
}
# SNAT 规则
sudo nft add rule ip nat postrouting \
oifname "eth0" \
snat to 203.0.113.5
如果外网 IP 不是固定的,比如 PPPoE 拨号或 DHCP,会用 masquerade
动作,而不是手动指定 IP:
sudo nft add rule ip nat postrouting oifname "eth0" masquerade
这样系统会自动使用 eth0
当前的 IP 做 NAT,无需频繁修改。
如果外网访问 203.0.113.5:80
,想转发到内网 192.168.1.10:8080
:
sudo nft add chain ip nat prerouting {
type nat hook prerouting priority -100;
policy accept;
}
sudo nft add rule ip nat prerouting \
tcp dport 80 \
dnat to 192.168.1.10:8080
这样,访问网关 203.0.113.5
的 80 端口时,会重定向到内网服务器 192.168.1.10:8080
。
提示:在做 DNAT 后,别忘了在防火墙
forward
链里适当放行该流量,或使用policy accept
(视安全策略而定)。
当你需要屏蔽大量可疑 IP,或者放行某些特定网段时,一条条写规则会非常繁琐。nftables 提供了 set
/ map
等数据结构,可一次性管理多值。
# 在 table inet firewall 下创建一个黑名单 set
sudo nft add set inet firewall blacklist {
type ipv4_addr;
flags interval; # 可以使用网段
}
# 往黑名单里添加元素
sudo nft add element inet firewall blacklist { 1.2.3.0/24, 5.6.7.8 }
# 在 input 链的规则中引用这个 set
sudo nft add rule inet firewall input ip saddr @blacklist drop
这样就不用写多条 ip saddr X drop
,以后只要
sudo nft add element inet firewall blacklist { <IP 或网段> }
即可。
nftables 允许给 set 中的元素添加 “timeout” 参数,实现自动过期。适合类似“fail2ban”的场景:
sudo nft add set inet firewall blacklist {
type ipv4_addr;
timeout 1h; # 每个元素默认过期时间
}
# 往里面加元素时,也可以自定义过期时长
sudo nft add element inet firewall blacklist { 1.2.3.4 timeout 10m }
到期后 1.2.3.4
会自动从黑名单中移除。
如果只想允许一批 IP,其余全部丢弃,可以把默认策略设为 drop
,然后在规则里写:
# 创建一个名为 whitelist 的 set
sudo nft add set inet firewall whitelist {
type ipv4_addr;
flags interval;
}
# 为了演示,先加几个IP
sudo nft add element inet firewall whitelist { 192.168.1.0/24, 10.10.10.10 }
# 在 input 链中
sudo nft add rule inet firewall input ip saddr @whitelist accept
因为链的 policy=drop
,不在白名单的全部拒绝。
除了 set,还可以用 map
来进行“值 → 动作”的映射(或“值 → 值”的映射),进一步简化配置。例如,根据 IP 地址直接映射到不同动作:
sudo nft add map inet firewall action_map {
type ipv4_addr : verdict;
}
sudo nft add element inet firewall action_map {
1.2.3.4 : drop,
10.0.0.0/8 : accept
}
# 一条规则即可处理多种动作
sudo nft add rule inet firewall input ip saddr vmap @action_map
这样比多条 if (saddr=...) drop; if (saddr=...) accept;
要简洁得多。
有时你想记录所有被丢弃的数据包或特定攻击流量,用 log
动作即可。示例:
sudo nft add rule inet firewall input ip saddr 1.2.3.4 log prefix "BLOCKED_IP " drop
prefix "BLOCKED_IP "
:出现在日志的前缀journalctl -k
、dmesg
或 /var/log/syslog
中查看(具体路径与发行版相关)。如果不想每个数据包都写日志,比如要限制日志过于频繁,可以:
sudo nft add rule inet firewall input ip saddr 1.2.3.4 \
limit rate 3/second \
log prefix "BLOCKED_IP " \
drop
limit rate 3/second
:表示只有在这个速率以内的包才会触发日志动作,超出速率时跳过日志动作(但 drop
依然执行)。nftables 支持更丰富的“状态计数”功能,如 meter、quota 等,用来做连接数限制或带宽配额等更复杂的场景。例如:
sudo nft add rule inet firewall input meter ddos_meter {
ip saddr limit rate 10/second
} log prefix "DOS_ATTEMPT " drop
meter
可以对特定字段(如 IP)进行自定义统计,超过阈值时执行特定动作等,适合抵御 DDOS 或限流。
常见于服务器多网卡环境,如内网网卡 eth1
、外网网卡 eth0
,只允许某些流量从内网进来:
sudo nft add rule inet firewall input iifname "eth1" accept
sudo nft add rule inet firewall input iifname "eth0" drop
或者要反过来,拦截除了 eth0
外所有接口,就用:
sudo nft add rule inet firewall input iifname != "eth0" drop
nftables 同样使用连接跟踪机制,可以区分数据包是 new
、established
、related
、invalid
等。
# 只允许已建立或相关连接
sudo nft add rule inet firewall input ct state established,related accept
# 拒绝无效连接
sudo nft add rule inet firewall input ct state invalid drop
# 允许新建连接访问 80 端口
sudo nft add rule inet firewall input ct state new tcp dport 80 accept
如果你的 Linux 服务器做“二层交换/桥接”或者管理 VLAN,需要用到 bridge
family 或 VLAN 相关匹配:
sudo nft add table bridge brtable
sudo nft add chain bridge brtable forward {
type filter hook forward priority 0;
policy drop;
}
# 例如 只允许从特定源MAC地址通过
sudo nft add rule bridge brtable forward ether saddr aa:bb:cc:dd:ee:ff accept
需要注意的是,在桥接场景下,你必须在 bridge
family 下创建表/链,否则无法拦截二层包。此外,如果需要在桥上查看/过滤 IP 层的信息,通常还需要内核模块 br_netfilter
并启用 net.bridge.bridge-nf-call-iptables=1
等相关 sysctl。
# 过滤 VLAN ID=100 的数据包
sudo nft add rule bridge brtable forward vlan id 100 drop
或者更细的匹配:vlan pcp
等等。
nftables 也支持 ingress hook(基于 TC ingress 机制),可以在数据包进入协议栈之前进行过滤,适合DDoS防护等需要尽早丢包的场景。例如:
sudo nft add chain inet firewall ingress {
type filter hook ingress device eth0 priority -500;
policy drop;
}
sudo nft add rule inet firewall ingress ip saddr 1.2.3.4 drop
ingress 上无法使用部分连接跟踪特性,请根据需求确认可行性。
若你在 IPv6 环境下部署防火墙,可以:
使用 inet
family:同时管理 IPv4/IPv6
ip
(仅针对 IPv4)或 ip6
(仅针对 IPv6),或者直接用通用条件(如 tcp dport 80
)同时生效。ICMPv6 规则非常重要
sudo nft add rule inet firewall input \
icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert } accept
NAT in IPv6?
snat/dnat
之类,只是场景较少。ip6 nat
family 并在 prerouting/postrouting
钩子上加 NAT 规则即可(写法与 IPv4 类似)。查看当前所有规则
sudo nft list ruleset
这会打印所有表、链和规则的完整结构。
查看指定表 / 链
sudo nft list table inet firewall
sudo nft list chain inet firewall input
查看规则的 handle ID
sudo nft list chain inet firewall input -a
-a
会显示每条规则的 handle 编号,便于定向删除或修改。
删除规则
sudo nft delete rule inet firewall input ip saddr 1.2.3.4 drop
# 先查看 handle
sudo nft list chain inet firewall input -a
# 假设要删 handle=10 的那条
sudo nft delete rule inet firewall input handle 10
删除链 / 表
sudo nft delete chain inet firewall input
sudo nft delete table inet firewall
清空/刷新整个规则集
sudo nft flush ruleset
实时监控 (monitor)
sudo nft monitor
可以动态观察规则的添加、删除、修改操作。
脚本批量加载
.nft
文件中,然后通过 -f
参数一次性加载:sudo nft -f /path/to/your_rules.nft
现代发行版默认使用 “nftables 后端”的 iptables
iptables -L
时,可能实际上调用的是 iptables-nft,会影响 nftables 规则集。语法思维差异
-A
、-I
、-D
等,nftables 采用 nft add rule
/ nft insert rule
/ nft delete rule
的方式。nft
,只是在创建链时指定 type nat
或 type filter
。Docker / Container / Kubernetes 环境
服务自启动 / 持久化
/etc/iptables/rules.v4
或 rules.v6
中写规则,那么在 nftables 下可以改为 /etc/nftables.conf
。systemctl enable nftables
+ systemctl start nftables
来管理开机启动;或者编辑 /etc/default/nftables
、/etc/nftables.conf
等。# 将当前规则输出到配置文件
sudo nft list ruleset > /etc/nftables.conf
# 确保开机加载
sudo systemctl enable nftables
flowtable(可选的高性能转发)
nft add table inet xflow
nft add chain inet xflow forward {
type filter hook forward priority 0; policy accept;
}
nft add rule inet xflow forward ip protocol tcp \
flow offload @DEV { eth0, eth1 } accept
man nft
手册
man nft
或 nft --help
sudo nft list ruleset
确认最终规则dmesg
或 journalctl -k
查看日志nftables
服务、Red Hat 系的 nftables.conf
位置等),请查看对应发行版的官方指南。input
、prerouting
、postrouting
、ingress
等)。accept
, drop
, reject
, snat
, dnat
, masquerade
, log
等。set
(批量黑白名单)、map
(值→动作映射)、log
(记录日志)、limit
/meter
(限速或计数)能够减少重复规则,提高可读性和性能。通过以上 场景化 的例子与高级用法扩展,相信你能更准确地定位自己的需求,然后套用相应的链、规则写法来部署 nftables。祝一切顺利!