1419 words
7 minutes
nftables

Install#

  • 在archlinux上:
Terminal window
sudo pacman -S nftables
  • 查看有其他防火墙服务是否在运行,如果有先禁用:
Terminal window
sudo systemctl list-units --type=service | grep -E "firewalld|ufw"
sudo iptables -L -n -v # 谁有输出就禁用
  • 启动防火墙:
Terminal window
sudo systemctl enable --now nftables.service
sudo systemctl status nftables.service #查看防火墙状态

安装nft的补全脚本#

Terminal window
sudo curl -o /etc/bash_completion.d/nft \
https://raw.githubusercontent.com/Zulugitt/bash_completion/main/nft-completion
  • 重新加载:
Terminal window
source /etc/bash_completion.d/nft

Usage#

  • 查看当前所有规则:
Terminal window
sudo nft list ruleset
  • 清空当前的规则
Terminal window
sudo nft flush ruleset
  • 加载配置文件
Terminal window
sudo nft -f /path/to/filename # nftables的配置文件

Table#

  • nftbles没有内置表。每个表只能有一个地址簇。有六个簇。未指定为ip簇。
nftables familymeaning
ip处理IPv4数据包
ip6处理IPv6数据包
inet同时处理IPv4和IPv6数据包
arp处理ARP数据包
bridge处理二层桥接数据包
netdev处理网络设备ingress(入站)数据包
  • 创建表
Terminal window
sudo nft add table family_type table_name
  • 列出表
Terminal window
sudo nft list tables
  • 列出表中的链和规则
Terminal window
sudo nft list table family_type table_name
  • 删除表
Terminal window
sudo nft delete table family_type table_name
  • 刷新表
Terminal window
sudo nft flush table family_type table_name

Chains#

  • 链的用途是包含规则
  • 链有两种类型。分别是基本链(Base chain)常规链(Regular chain)。区别主要在是否挂接到内核网络堆栈
    • 基本链:入口点,必须有hook,直接处理数据包。
    • 常规链:辅助链,没有hook,作为跳转目标,用来组织规则。

Base chain#

  • 添加基本链:
Terminal window
sudo nft add chain family_type table_name chain_name { type chain_type hook hook_type priority priority_value ; policy policy ;}
# type: filter / nat /route
# hook: preouting / input / forward /output / postrouting /ingress # ip ip6 family
# priority: 名字或整数,可以为负
# policy accept / drop
  • 添加常规链:
Terminal window
sudo nft add chain family_type table_name chain_name
  • 编辑链:
Terminal window
sudo nft chain family_type table_name chain_name { } # 可以修改 policy 命名集合的元素,计数器,限速器,等状态对象。

Ruler#

  • 规则由匹配条件(Expressions)动作(Statements)组成。条件和动作从左到右顺序应用。
  • 规则中的条件在逻辑上连接在一起(AND运算符)。所有的条件必须全部匹配,才能执行相应的动作。否则,将执行下一条规则。
  • 添加规则:
Terminal window
sudo nft add rule family_type table_name chain_name handle handle_value ruler
# handle 一个唯一的ID 用来删除、替换、插入的。

Expression#

  1. 常见的匹配条件:
expressionexample
metaiif lo oifname "eth0"
ip / ip6ip saddr 192.168.0.0/16 / ip6 daddr fe80::/10
tcp / udp / sctptcp dport 22 / udp sport 53
icmp / icmp6icmp type echo-request / icmpv6 type nd-neighbor-solicit
ctct state established,related / ct state new
sets / mapstcp dport {22,80,443} / ip saddr vmap { 192.168.1.1 : drop,192.168.1.2 : accept }
  1. 更多的expression具体信息可以使用 nft describe 查询或者man nft

Statements#

  • 常见的动作:
statementsmeaning
accept放行
drop丢弃
reject拒绝并返回ICMP/ICMPv6错误
queue交给用户空间程序处理
return返回到调用链
log记录日志
counter计数
masquerade / snat / dnatNAT动作
limit / meter限速 / 限流
set / add / delete / element动态修改集合

Sets#

  • 集合可以是匿名,命名的。它可以用来存放一组元素,然后在规则中引用。
    • 匿名集:直接写在规则里,不能修改
    • 命名集:单独定义,可动态更新
  • example 自动拉黑
Terminal window
table inet ssh_protect {
# 定义一个动态黑名单集合
set ssh_blacklist {
type ipv4_addr
flags dynamic, timeout
timeout 1h
size 65536
}
chain input {
type filter hook input priority 0; policy accept;
ip saddr @ssh_blacklist drop
# 如果源 IP 在黑名单中,直接丢弃
tcp dport 22 ct state new \
# 检测 SSH 新连接,超过速率限制则加入黑名单
limit rate over 10/minute burst 5 packets \
add @ssh_blacklist { ip saddr timeout 1h } \
accept
}
}

Maps#

  • maps是sets的一种扩展形式。 基本语法:
Terminal window
map map_name {
type key_type: value_type
elements = { key : value, key1 : value1 }
}
  1. example 1 端口重定向
Terminal window
table ip nat {
map port_redirect {
type inet_service : inet_service
elements = { 80 : 8080, 443 : 8443 }
}
chain prerouting {
type nat hook prerouting priority dstnat;
tcp dport @port_redirect dnat to 192.168.1.10 : @port_redirect
}
}
# 访问本机的80 / 443 端口会被转发到 192.168.0.10 的 8080 / 8443 端口上
  1. example 2 服务端口分类
Terminal window
table inet filter {
map service_dispatch {
type inet_service : verdict
elements = {
22 : jump ssh_chain,
23122 : jump ssh_chain,
80 : jump web_chain,
443 : jump web_chain
}
}
chain input {
type filter hook input priority 0; policy drop ;
tcp dport vmap @service_dispatch
}
chain ssh_chain {
tcp dport 22 drop
tcp dport 23122 accept
}
chain web_chain {
tcp dport {80,443} accept
}
}
# 把不同的端口映射到不同的链上
  1. example 3 基于不同IP的策略
Terminal window
table inet filter {
map ip_policy {
type ipv4_addr : verdict
elements = {
192.168.1.100 : accept,
10.0.0.5 : drop
}
}
chain input {
type filter hook input priority 0; policy drop ;
ip saddr vmap @ip_policy
}
}
# 不同来源的IP走不同的链

Objects#

  1. counter
  2. quota
  3. limit
  4. ct helper
  5. flowtable

例子#

Terminal window
flush ruleset
table inet myfw {
# 黑名单集合
set ssh_blacklist {
type ipv4_addr
flags dynamic, timeout
timeout 1h
}
# 对象:计数器 + 限速器
counter ssh_counter
limit ssh_limit { rate 10/minute burst 5 }
chain input {
type filter hook input priority 0; policy drop;
# 基础放行
ct state established,related accept
iif lo accept
# 黑名单
ip saddr @ssh_blacklist drop
# SSH 防护:速率限制 + 计数 + 自动拉黑
tcp dport 22 ct state new limit name ssh_limit counter name ssh_counter \
add @ssh_blacklist { ip saddr timeout 1h } drop
# 允许 Web 服务
tcp dport {80,443} accept
}
}
  • 流程图
flowchart TD A[Packet enters input chain] --> B{ct state established,related?} B -- yes --> Z[ACCEPT established/related] B -- no --> C{iif lo?} C -- yes --> Z C -- no --> D{Source IP in ssh_blacklist?} D -- yes --> X[DROP blacklist] D -- no --> E{tcp dport 22 and state new?} E -- no --> F{tcp dport 80 or 443?} E -- yes --> G[Count ssh_counter + Limit ssh_limit] G --> H[Add source IP to ssh_blacklist 1h] H --> X[DROP SSH over limit] F -- yes --> Z[ACCEPT Web service] F -- no --> X[DROP default policy]

如何写一条规则#

  1. 要实现什么功能,确定在哪个表和链里写。
  2. 写匹配条件。如协议,端口,地址等等。
  3. 写动作。如 accept,drop,log等。

Finally#

更多内容请查看nftables官网

nftables
https://infini.cv/posts/nftable/nftables/
Author
infini
Published at
2025-10-07
License
CC BY-SA 4.0

Some information may be outdated