004 《Linux Netfilter & nftables 权威指南:深度解析、实战与参数详解》


作者Lou Xiao, gemini创建时间2025-04-10 08:16:50更新时间2025-04-10 08:16:50

🌟🌟🌟本文案由Gemini 2.0 Flash Thinking Experimental 01-21创作,用来辅助学习知识。🌟🌟🌟

书籍大纲

▮▮▮▮ 1. chapter 1: Netfilter & nftables 技术概览
▮▮▮▮▮▮▮ 1.1 Netfilter 的前世今生
▮▮▮▮▮▮▮▮▮▮▮ 1.1.1 Netfilter 的诞生与演进
▮▮▮▮▮▮▮▮▮▮▮ 1.1.2 Netfilter 的核心组件:Hook 点、队列、连接追踪
▮▮▮▮▮▮▮ 1.2 为什么选择 nftables?
▮▮▮▮▮▮▮▮▮▮▮ 1.2.1 iptables 的局限性分析
▮▮▮▮▮▮▮▮▮▮▮ 1.2.2 nftables 的优势:性能、灵活性、统一语法
▮▮▮▮▮▮▮ 1.3 nftables 的核心概念
▮▮▮▮▮▮▮▮▮▮▮ 1.3.1 表(Tables)、链(Chains)、规则(Rules)
▮▮▮▮▮▮▮▮▮▮▮ 1.3.2 集合(Sets)、映射(Maps)、元素(Elements)
▮▮▮▮▮▮▮▮▮▮▮ 1.3.3 表达式(Expressions)与语句(Statements)
▮▮▮▮▮▮▮ 1.4 实验环境搭建与 nft 工具快速上手
▮▮▮▮▮▮▮▮▮▮▮ 1.4.1 Linux 环境准备:内核版本、nftables 工具安装
▮▮▮▮▮▮▮▮▮▮▮ 1.4.2 nft 命令行工具的基本操作:语法结构、常用命令
▮▮▮▮▮▮▮▮▮▮▮ 1.4.3 第一个 nftables 规则:允许 SSH 访问
▮▮▮▮ 2. chapter 2: nftables 基础:表、链与规则详解
▮▮▮▮▮▮▮ 2.1 表的创建与管理
▮▮▮▮▮▮▮▮▮▮▮ 2.1.1 表的类型:inetipip6arpbridgenetdevroute
▮▮▮▮▮▮▮▮▮▮▮ 2.1.2 创建、查看、删除表
▮▮▮▮▮▮▮ 2.2 链的深入解析
▮▮▮▮▮▮▮▮▮▮▮ 2.2.1 链的类型:filternatroute
▮▮▮▮▮▮▮▮▮▮▮ 2.2.2 基链(Base Chain)与普通链(Regular Chain)
▮▮▮▮▮▮▮▮▮▮▮ 2.2.3 链的 hook 点:ingressforwardinputoutputpostrouting
▮▮▮▮▮▮▮▮▮▮▮ 2.2.4 链的优先级(Priority)
▮▮▮▮▮▮▮▮▮▮▮ 2.2.5 创建、查看、删除链
▮▮▮▮▮▮▮ 2.3 规则的语法与结构
▮▮▮▮▮▮▮▮▮▮▮ 2.3.1 规则的组成:匹配条件(Match Criteria)与动作(Action/Target)
▮▮▮▮▮▮▮▮▮▮▮ 2.3.2 规则的添加、插入、替换、删除
▮▮▮▮▮▮▮▮▮▮▮ 2.3.3 规则的匹配顺序与执行流程
▮▮▮▮▮▮▮ 2.4 常用匹配条件详解
▮▮▮▮▮▮▮▮▮▮▮ 2.4.1 协议匹配:ip protocoltcpudpicmp
▮▮▮▮▮▮▮▮▮▮▮ 2.4.2 地址匹配:ip saddrip daddrip6 saddrip6 daddr
▮▮▮▮▮▮▮▮▮▮▮ 2.4.3 端口匹配:tcp sporttcp dportudp sportudp dport
▮▮▮▮▮▮▮▮▮▮▮ 2.4.4 接口匹配:iifnameoifnameiifoif
▮▮▮▮▮▮▮▮▮▮▮ 2.4.5 连接状态匹配:ct state
▮▮▮▮▮▮▮ 2.5 常用动作详解
▮▮▮▮▮▮▮▮▮▮▮ 2.5.1 acceptdropreject
▮▮▮▮▮▮▮▮▮▮▮ 2.5.2 log:日志记录
▮▮▮▮▮▮▮▮▮▮▮ 2.5.3 queue:数据包排队
▮▮▮▮▮▮▮▮▮▮▮ 2.5.4 gotojumpreturn:链跳转与返回
▮▮▮▮ 3. chapter 3: nftables 核心概念:集合(Sets)与映射(Maps)
▮▮▮▮▮▮▮ 3.1 集合(Sets)详解
▮▮▮▮▮▮▮▮▮▮▮ 3.1.1 集合的优势与应用场景
▮▮▮▮▮▮▮▮▮▮▮ 3.1.2 集合的类型:匿名集合、命名集合、动态集合、区间集合等
▮▮▮▮▮▮▮▮▮▮▮ 3.1.3 集合的创建、查看、修改与删除
▮▮▮▮▮▮▮▮▮▮▮ 3.1.4 集合的操作:添加元素、删除元素、更新元素
▮▮▮▮▮▮▮▮▮▮▮ 3.1.5 使用集合优化规则:IP 地址集合、端口集合、MAC 地址集合等
▮▮▮▮▮▮▮ 3.2 映射(Maps)详解
▮▮▮▮▮▮▮▮▮▮▮ 3.2.1 映射的优势与应用场景
▮▮▮▮▮▮▮▮▮▮▮ 3.2.2 映射的类型
▮▮▮▮▮▮▮▮▮▮▮ 3.2.3 映射的创建、查看、修改与删除
▮▮▮▮▮▮▮▮▮▮▮ 3.2.4 映射的操作:添加键值对、删除键值对、更新键值对、查找键值对
▮▮▮▮▮▮▮▮▮▮▮ 3.2.5 使用映射实现复杂策略:基于 IP 的流量控制、基于端口的策略路由等
▮▮▮▮▮▮▮ 3.3 集合与映射的组合应用
▮▮▮▮▮▮▮▮▮▮▮ 3.3.1 集合与映射的嵌套使用
▮▮▮▮▮▮▮▮▮▮▮ 3.3.2 使用集合和映射构建更灵活、更高效的规则集
▮▮▮▮ 4. chapter 4: nftables 高级特性与扩展
▮▮▮▮▮▮▮ 4.1 表达式(Expressions)进阶
▮▮▮▮▮▮▮▮▮▮▮ 4.1.1 payload 表达式:深入解析数据包载荷
▮▮▮▮▮▮▮▮▮▮▮ 4.1.2 meta 表达式:元数据匹配,如接口名称、数据包长度等
▮▮▮▮▮▮▮▮▮▮▮ 4.1.3 ct 表达式:连接追踪状态的精细控制
▮▮▮▮▮▮▮▮▮▮▮ 4.1.4 limit 表达式:速率限制与流量控制
▮▮▮▮▮▮▮▮▮▮▮ 4.1.5 rt 表达式:路由信息匹配
▮▮▮▮▮▮▮ 4.2 语句(Statements)扩展
▮▮▮▮▮▮▮▮▮▮▮ 4.2.1 counter:数据包计数器
▮▮▮▮▮▮▮▮▮▮▮ 4.2.2 meter:流量计量器
▮▮▮▮▮▮▮▮▮▮▮ 4.2.3 quota:流量配额
▮▮▮▮▮▮▮▮▮▮▮ 4.2.4 masqueradesnatdnat:NAT 相关语句详解
▮▮▮▮▮▮▮▮▮▮▮ 4.2.5 redirect:端口重定向
▮▮▮▮▮▮▮ 4.3 连接追踪(Connection Tracking)与 conntrack-ng
▮▮▮▮▮▮▮▮▮▮▮ 4.3.1 连接追踪原理与作用
▮▮▮▮▮▮▮▮▮▮▮ 4.3.2 nftables 与 conntrack-ng 的集成
▮▮▮▮▮▮▮▮▮▮▮ 4.3.3 使用 ct 表达式进行连接追踪控制
▮▮▮▮▮▮▮ 4.4 Flowtables:硬件加速与 Offloading
▮▮▮▮▮▮▮▮▮▮▮ 4.4.1 Flowtables 的概念与优势
▮▮▮▮▮▮▮▮▮▮▮ 4.4.2 配置和使用 Flowtables
▮▮▮▮▮▮▮ 4.5 模块化与规则组织
▮▮▮▮▮▮▮▮▮▮▮ 4.5.1 使用 include 文件组织规则
▮▮▮▮▮▮▮▮▮▮▮ 4.5.2 规则集的模块化设计与管理
▮▮▮▮▮▮▮ 4.6 事务(Transactions)与原子操作
▮▮▮▮▮▮▮▮▮▮▮ 4.6.1 nftables 事务机制
▮▮▮▮▮▮▮▮▮▮▮ 4.6.2 批量操作与原子性规则更新
▮▮▮▮ 5. chapter 5: nftables 实战:构建防火墙
▮▮▮▮▮▮▮ 5.1 基础防火墙策略设计原则
▮▮▮▮▮▮▮▮▮▮▮ 5.1.1 最小权限原则
▮▮▮▮▮▮▮▮▮▮▮ 5.1.2 默认拒绝策略
▮▮▮▮▮▮▮▮▮▮▮ 5.1.3 分层防御
▮▮▮▮▮▮▮ 5.2 构建基本的有状态防火墙
▮▮▮▮▮▮▮▮▮▮▮ 5.2.1 允许已建立连接和相关连接
▮▮▮▮▮▮▮▮▮▮▮ 5.2.2 开放常用服务端口:SSH、HTTP、HTTPS
▮▮▮▮▮▮▮▮▮▮▮ 5.2.3 阻止非法入站连接
▮▮▮▮▮▮▮ 5.3 高级防火墙功能实现
▮▮▮▮▮▮▮▮▮▮▮ 5.3.1 端口转发与 DMZ 设置
▮▮▮▮▮▮▮▮▮▮▮ 5.3.2 基于 IP 地址和地理位置的访问控制
▮▮▮▮▮▮▮▮▮▮▮ 5.3.3 DDoS 防护基础:SYN Flood 防御、连接数限制
▮▮▮▮▮▮▮ 5.4 防火墙日志记录与分析
▮▮▮▮▮▮▮▮▮▮▮ 5.4.1 配置 nftables 日志
▮▮▮▮▮▮▮▮▮▮▮ 5.4.2 使用 ulogd 或其他工具进行日志管理与分析
▮▮▮▮▮▮▮ 5.5 防火墙规则的测试与维护
▮▮▮▮▮▮▮▮▮▮▮ 5.5.1 使用 nft monitor 监控规则执行
▮▮▮▮▮▮▮▮▮▮▮ 5.5.2 规则备份与恢复
▮▮▮▮▮▮▮▮▮▮▮ 5.5.3 防火墙规则优化与性能调优
▮▮▮▮ 6. chapter 6: nftables 实战:网络地址转换(NAT)
▮▮▮▮▮▮▮ 6.1 NAT 原理与类型:SNAT、DNAT、Masquerade
▮▮▮▮▮▮▮▮▮▮▮ 6.1.1 源地址转换(SNAT)
▮▮▮▮▮▮▮▮▮▮▮ 6.1.2 目标地址转换(DNAT)
▮▮▮▮▮▮▮▮▮▮▮ 6.1.3 伪装(Masquerade)
▮▮▮▮▮▮▮ 6.2 使用 nftables 实现 SNAT
▮▮▮▮▮▮▮▮▮▮▮ 6.2.1 配置基本的 SNAT 规则
▮▮▮▮▮▮▮▮▮▮▮ 6.2.2 SNAT 的高级应用:多出口 IP 地址
▮▮▮▮▮▮▮ 6.3 使用 nftables 实现 DNAT
▮▮▮▮▮▮▮▮▮▮▮ 6.3.1 端口转发配置
▮▮▮▮▮▮▮▮▮▮▮ 6.3.2 负载均衡基础:DNAT 轮询
▮▮▮▮▮▮▮ 6.4 Masquerade 的应用场景与配置
▮▮▮▮▮▮▮▮▮▮▮ 6.4.1 动态 IP 环境下的网络共享
▮▮▮▮▮▮▮▮▮▮▮ 6.4.2 简化 NAT 配置
▮▮▮▮▮▮▮ 6.5 NAT 与连接追踪的交互
▮▮▮▮▮▮▮▮▮▮▮ 6.5.1 NAT 对连接追踪的影响
▮▮▮▮▮▮▮▮▮▮▮ 6.5.2 NAT 场景下的连接状态管理
▮▮▮▮▮▮▮ 6.6 NAT 故障排除与常见问题
▮▮▮▮ 7. chapter 7: nftables 实战:流量整形与 QoS
▮▮▮▮▮▮▮ 7.1 流量整形与 QoS 基础概念
▮▮▮▮▮▮▮▮▮▮▮ 7.1.1 流量整形(Traffic Shaping)与流量监管(Traffic Policing)
▮▮▮▮▮▮▮▮▮▮▮ 7.1.2 QoS 的目标与策略
▮▮▮▮▮▮▮ 7.2 使用 limit 表达式进行速率限制
▮▮▮▮▮▮▮▮▮▮▮ 7.2.1 基于连接数限制
▮▮▮▮▮▮▮▮▮▮▮ 7.2.2 基于数据包速率限制
▮▮▮▮▮▮▮ 7.3 使用 meterquota 进行流量控制
▮▮▮▮▮▮▮▮▮▮▮ 7.3.1 基于流量计量器的带宽控制
▮▮▮▮▮▮▮▮▮▮▮ 7.3.2 基于流量配额的资源管理
▮▮▮▮▮▮▮ 7.4 高级队列技术与 nftables 集成
▮▮▮▮▮▮▮▮▮▮▮ 7.4.1 Linux 流量控制(tc)框架简介
▮▮▮▮▮▮▮▮▮▮▮ 7.4.2 nftables 与 tc 的协同工作
▮▮▮▮▮▮▮▮▮▮▮ 7.4.3 使用 nftables 标记数据包,tc 进行队列管理
▮▮▮▮▮▮▮ 7.5 基于 nftables 的应用层 QoS
▮▮▮▮▮▮▮▮▮▮▮ 7.5.1 识别应用层协议
▮▮▮▮▮▮▮▮▮▮▮ 7.5.2 基于应用类型进行 QoS 策略配置
▮▮▮▮ 8. chapter 8: nftables 性能优化与最佳实践
▮▮▮▮▮▮▮ 8.1 nftables 性能优势深度剖析
▮▮▮▮▮▮▮▮▮▮▮ 8.1.1 内核数据结构优化
▮▮▮▮▮▮▮▮▮▮▮ 8.1.2 规则匹配算法优化
▮▮▮▮▮▮▮▮▮▮▮ 8.1.3 性能测试对比:nftables vs iptables
▮▮▮▮▮▮▮ 8.2 规则集优化策略
▮▮▮▮▮▮▮▮▮▮▮ 8.2.1 减少规则数量:集合与映射的应用
▮▮▮▮▮▮▮▮▮▮▮ 8.2.2 优化规则顺序:提高匹配效率
▮▮▮▮▮▮▮▮▮▮▮ 8.2.3 避免冗余规则和重复匹配
▮▮▮▮▮▮▮ 8.3 利用 Flowtables 提升性能
▮▮▮▮▮▮▮▮▮▮▮ 8.3.1 Flowtables 的适用场景
▮▮▮▮▮▮▮▮▮▮▮ 8.3.2 合理配置 Flowtables 加速网络处理
▮▮▮▮▮▮▮ 8.4 nftables 配置的监控与调优
▮▮▮▮▮▮▮▮▮▮▮ 8.4.1 使用 nft monitor 进行实时监控
▮▮▮▮▮▮▮▮▮▮▮ 8.4.2 性能瓶颈分析与定位
▮▮▮▮▮▮▮▮▮▮▮ 8.4.3 系统资源监控与调整
▮▮▮▮ 9. chapter 9: nftables 与现代网络技术融合
▮▮▮▮▮▮▮ 9.1 nftables 与容器技术(Docker、Kubernetes)
▮▮▮▮▮▮▮▮▮▮▮ 9.1.1 容器网络模型与 nftables
▮▮▮▮▮▮▮▮▮▮▮ 9.1.2 在 Docker 中使用 nftables
▮▮▮▮▮▮▮▮▮▮▮ 9.1.3 Kubernetes 网络策略与 nftables
▮▮▮▮▮▮▮ 9.2 nftables 与虚拟化技术(VMware、KVM)
▮▮▮▮▮▮▮▮▮▮▮ 9.2.1 虚拟网络环境下的 nftables 应用
▮▮▮▮▮▮▮▮▮▮▮ 9.2.2 虚拟机防火墙与安全组策略
▮▮▮▮▮▮▮ 9.3 nftables 与网络命名空间(Network Namespaces)
▮▮▮▮▮▮▮▮▮▮▮ 9.3.1 网络命名空间隔离与安全
▮▮▮▮▮▮▮▮▮▮▮ 9.3.2 在网络命名空间中使用 nftables
▮▮▮▮▮▮▮ 9.4 nftables 与 VRF(Virtual Routing and Forwarding)
▮▮▮▮▮▮▮▮▮▮▮ 9.4.1 VRF 的概念与应用场景
▮▮▮▮▮▮▮▮▮▮▮ 9.4.2 在 VRF 环境中配置 nftables
▮▮▮▮▮▮▮ 9.5 nftables 与自动化运维(Ansible、Puppet)
▮▮▮▮▮▮▮▮▮▮▮ 9.5.1 使用自动化工具管理 nftables 规则
▮▮▮▮▮▮▮▮▮▮▮ 9.5.2 nftables 配置的自动化部署与维护
▮▮▮▮ 10. chapter 10: nftables 进阶与未来展望
▮▮▮▮▮▮▮ 10.1 nftables 内核源码分析入门
▮▮▮▮▮▮▮▮▮▮▮ 10.1.1 Netfilter 框架源码结构
▮▮▮▮▮▮▮▮▮▮▮ 10.1.2 nftables 核心模块源码导读
▮▮▮▮▮▮▮ 10.2 nftables 开发与扩展
▮▮▮▮▮▮▮▮▮▮▮ 10.2.1 自定义 nftables 模块开发
▮▮▮▮▮▮▮▮▮▮▮ 10.2.2 贡献 nftables 社区
▮▮▮▮▮▮▮ 10.3 nftables 的未来发展趋势
▮▮▮▮▮▮▮▮▮▮▮ 10.3.1 eBPF 与 nftables 的结合展望
▮▮▮▮▮▮▮▮▮▮▮ 10.3.2 nftables 在下一代网络技术中的角色
▮▮▮▮▮▮▮ 10.4 nftables 学习资源与社区
▮▮▮▮▮▮▮▮▮▮▮ 10.4.1 官方文档、邮件列表、IRC 频道
▮▮▮▮▮▮▮▮▮▮▮ 10.4.2 优秀的 nftables 学习资料推荐


1. chapter 1: Netfilter & nftables 技术概览

1.1 Netfilter 的前世今生

1.1.1 Netfilter 的诞生与演进

在深入探索 nftables 的强大功能之前,理解其根基 Netfilter 项目的由来与发展历程至关重要。Netfilter 项目不仅仅是一个简单的防火墙工具,它代表了 Linux 内核网络子系统中的一个核心框架,为网络数据包过滤、网络地址转换(NAT)、连接跟踪和数据包处理提供了基础设施。

Netfilter 的诞生 (Birth of Netfilter)
Netfilter 项目起源于上世纪 90 年代末,由 Rusty Russell 主导开发。最初的目标是为 Linux 2.4 内核构建一个强大而灵活的数据包过滤框架,以替代当时略显笨拙且功能有限的 ipchains 工具。Netfilter 的设计理念是模块化和可扩展性,它在内核网络协议栈的关键路径上定义了一系列 Hook 点(Hook Points),允许不同的模块(例如,各种协议的过滤器、NAT 模块等)注册到这些 Hook 点,从而在数据包流经内核时对其进行检查和修改。

Netfilter 的早期发展 (Early Development of Netfilter)
随着 Linux 2.4 内核的发布,Netfilter 框架正式进入大众视野。早期的 Netfilter 主要通过 iptables 工具进行配置管理。iptables 实际上是一系列用户空间的命令行工具,包括 iptables (针对 IPv4)、ip6tables (针对 IPv6)、arptables (针对 ARP) 和 ebtables (针对以太网桥接)。这些工具分别对应于 Netfilter 框架在不同网络协议层面的应用。iptables 以其规则链的组织方式和丰富的匹配条件、动作,迅速成为 Linux 系统上事实标准的防火墙配置工具。

Netfilter 的成熟与壮大 (Maturity and Growth of Netfilter)
在 Linux 2.6 内核时代,Netfilter 框架日臻成熟,功能不断扩展。连接追踪(Connection Tracking, conntrack)机制的引入,使得 Netfilter 能够实现有状态防火墙,极大地提升了网络安全策略的灵活性和有效性。同时,NAT 模块的完善,使得 Linux 系统能够胜任网络地址转换、端口转发等复杂网络任务。Netfilter 不仅在服务器领域得到广泛应用,也逐渐渗透到嵌入式系统、路由器等各种网络设备中,成为 Linux 网络功能的核心基石。

面临的挑战与革新 (Challenges and Innovation)
尽管 iptables 及其背后的 Netfilter 框架非常成功,但随着网络技术的快速发展,以及用户对网络性能和灵活性的更高要求,iptables 的一些局限性也逐渐显现出来。例如,规则语法的冗余和复杂性,规则匹配性能的瓶颈,以及对新型网络协议和数据包处理方式的支持不足等问题。为了应对这些挑战,Netfilter 社区开始了新一代数据包过滤工具 nftables 的研发,旨在彻底革新 Linux 网络过滤体系,提供更强大、更高效、更灵活的网络安全解决方案。nftables 的出现,标志着 Netfilter 项目进入了一个新的发展阶段。

1.1.2 Netfilter 的核心组件:Hook 点、队列、连接追踪

Netfilter 框架之所以强大而灵活,很大程度上归功于其精心设计的核心组件。理解这些组件的工作原理,是深入学习 nftables 的基础。Netfilter 的三大核心组件包括:Hook 点(Hook Points)队列(Queue)连接追踪(Connection Tracking)

Hook 点(Hook Points)
Hook 点是 Netfilter 框架的核心架构。它们是预先定义在 Linux 内核网络协议栈关键路径上的五个位置,数据包在流经网络协议栈时,会依次经过这些 Hook 点。在每个 Hook 点,内核会检查是否有模块注册了相应的处理函数。如果注册了,内核就会调用这些函数,允许模块对数据包进行检查、修改、丢弃或放行等操作。Netfilter 定义了以下五个主要的 Hook 点:

NF_IP_PRE_ROUTING路由前 Hook 点。数据包进入网络接口后,在进行路由决策之前,首先会到达这个 Hook 点。通常用于目标地址转换(DNAT)数据包过滤等。
NF_IP_LOCAL_IN本地输入 Hook 点。经过路由决策后,如果数据包的目标地址是本机,则会到达这个 Hook 点,准备递交给上层协议栈(如 TCP/UDP)。通常用于入站数据包过滤
NF_IP_FORWARD转发 Hook 点。经过路由决策后,如果数据包的目标地址不是本机,且内核允许转发,则会到达这个 Hook 点,准备转发到下一个网络接口。通常用于转发数据包过滤
NF_IP_LOCAL_OUT本地输出 Hook 点。本机进程发出的数据包,在进行路由决策之前,会到达这个 Hook 点。通常用于出站数据包过滤源地址转换(SNAT)等。
NF_IP_POST_ROUTING路由后 Hook 点。数据包经过路由决策后,准备从网络接口发送出去之前,会到达这个 Hook 点。通常用于 源地址转换(SNAT)伪装(Masquerade)等。

理解 Hook 点的位置和作用至关重要,它决定了规则在数据包生命周期中的生效时机。

队列(Queue)
Netfilter 的队列机制允许将数据包从内核空间“排队”到用户空间进行处理。当规则的 Target(目标) 设置为 QUEUENFQUEUE 时,匹配的数据包会被放入队列中,等待用户空间的应用程序(如 libnetfilter_queue 库)进行处理。用户空间程序可以检查、修改数据包,并决定是将其放回内核网络栈继续处理,还是丢弃。队列机制为实现更复杂的数据包处理逻辑提供了可能,例如,入侵检测系统(IDS)入侵防御系统(IPS) 等高级网络安全应用。

连接追踪(Connection Tracking, conntrack)
连接追踪是 Netfilter 最重要的功能之一,它允许 Netfilter 跟踪网络连接的状态。对于每个经过 Netfilter 的连接(例如,TCP 连接、UDP 会话等),连接追踪模块会维护一个状态表,记录连接的源地址、目标地址、端口、协议、状态等信息。连接状态包括 NEW(新连接)、ESTABLISHED(已建立连接)、RELATED(相关连接)、INVALID(无效连接)等。

连接追踪机制使得 有状态防火墙(Stateful Firewall) 成为可能。基于连接状态,防火墙可以更智能地进行数据包过滤。例如,只允许已建立连接的回应数据包通过,而阻止新的、未知的入站连接,从而有效防御未经授权的访问。nftables 充分利用了连接追踪机制,并提供了更灵活的 ct 表达式,允许用户基于更精细的连接状态信息编写规则。

总结来说,Hook 点定义了数据包处理的关键位置,队列机制实现了内核空间与用户空间的协同处理,连接追踪提供了连接状态的上下文信息。这三大核心组件共同构成了 Netfilter 强大而灵活的基础架构,也为 nftables 的诞生奠定了坚实的技术基础。

1.2 为什么选择 nftables?

1.2.1 iptables 的局限性分析

尽管 iptables 在过去很长一段时间内都是 Linux 防火墙的标配,但随着网络环境的日益复杂和对性能要求的不断提高,iptables 的一些局限性逐渐显现出来,促使了新一代防火墙工具 nftables 的诞生。理解 iptables 的局限性,有助于我们更好地认识 nftables 的优势和价值。

语法冗余且复杂 (Redundant and Complex Syntax)
iptables 实际上是一系列独立的工具 (iptables, ip6tables, arptables, ebtables),分别处理不同的网络协议栈。这意味着,即使是相似的网络过滤规则,也需要在不同的工具中重复配置,语法结构也存在差异,导致配置管理繁琐且容易出错。例如,IPv4 和 IPv6 的规则需要分别使用 iptablesip6tables 进行配置,学习和维护成本较高。

规则匹配性能瓶颈 (Performance Bottleneck in Rule Matching)
iptables 的规则是线性存储和匹配的。当规则数量庞大时,数据包需要逐条规则进行匹配,效率较低。尤其是在大型网络环境中,大量的规则会显著降低数据包处理速度,成为性能瓶颈。iptables 的规则组织方式(链和表)在一定程度上可以优化匹配效率,但随着规则数量的增加,性能下降仍然难以避免。

扩展性不足 (Limited Extensibility)
iptables 的功能扩展主要依赖于内核模块。虽然 iptables 提供了丰富的扩展模块,但添加新的匹配条件或动作通常需要修改内核代码,开发周期长,部署复杂。对于快速变化的网络需求,iptables 的扩展性显得不足。

缺乏统一的数据结构 (Lack of Unified Data Structure)
iptables 使用多个独立的表(如 filter, nat, mangle 等)来组织规则,这些表之间缺乏统一的数据结构和管理方式。这导致规则管理不够灵活,难以实现跨表的复杂策略。例如,在 iptables 中,集合(sets)功能相对较弱,限制了其在处理大量 IP 地址、端口等场景下的应用。

对新型协议支持不足 (Insufficient Support for New Protocols)
iptables 最初是为 IPv4 设计的,虽然也支持 IPv6,但对一些新型网络协议和数据包处理方式的支持相对滞后。例如,对于 隧道协议(Tunneling Protocols)网络虚拟化技术(Network Virtualization) 等新兴技术,iptables 的支持能力有限,难以满足现代网络环境的需求。

事务性操作缺失 (Lack of Transactional Operations)
iptables 的规则更新是逐条进行的,缺乏事务性操作。这意味着,在批量更新规则时,如果操作中断,可能会导致规则配置处于不一致的状态,影响网络安全。

综上所述,iptables 虽然功能强大,但在语法复杂性、性能、扩展性、数据结构、协议支持和事务性操作等方面存在一些局限性。这些局限性促使了 nftables 的诞生,nftables 旨在解决 iptables 的不足,提供更现代、更高效、更灵活的网络过滤框架。

1.2.2 nftables 的优势:性能、灵活性、统一语法

nftables 作为 Netfilter 项目的继任者,吸取了 iptables 的经验教训,并进行了彻底的革新。nftables 不仅仅是 iptables 的简单替代品,而是一个全新的网络数据包分类框架,它在性能、灵活性和语法统一性等方面都具有显著的优势。

性能大幅提升 (Significant Performance Improvement)
nftables 在内核数据结构和规则匹配算法上进行了优化,显著提升了规则匹配性能。

优化的数据结构nftables 使用更高效的数据结构来存储规则,例如,使用 B-树(B-tree)R-树(R-tree) 等索引结构,加速规则查找和匹配过程。相比之下,iptables 的线性规则链在规则数量增加时,性能下降明显。
优化的匹配算法nftables 采用了更先进的规则匹配算法,例如,决策树(Decision Tree) 算法,可以根据数据包的特征快速定位到匹配的规则,减少不必要的规则遍历,提高匹配效率。
集合(Sets)和映射(Maps)nftables 引入了强大的集合和映射概念,可以将大量的 IP 地址、端口等元素组织成集合或映射,规则可以直接匹配集合或映射,避免了编写大量重复的规则,不仅简化了配置,也大幅提升了规则匹配效率。

高度灵活性 (High Flexibility)
nftables 提供了更灵活的规则配置和管理方式,可以满足各种复杂的网络策略需求。

统一的语法nftables 使用统一的命令行工具 nft 和统一的配置语法,不再区分 IPv4、IPv6、ARP、网桥等协议类型,所有类型的规则都可以在同一个框架下进行配置和管理,大大简化了配置复杂度。
灵活的规则组织nftables 的表(Tables)可以包含多个链(Chains),链可以自由组合,规则可以跳转到不同的链,构建更复杂的规则流程。用户可以根据实际需求灵活组织规则,实现更精细的网络策略。
丰富的表达式(Expressions)和语句(Statements)nftables 提供了丰富的表达式和语句,可以实现更复杂的匹配条件和动作。例如,payload 表达式可以深入解析数据包载荷,meta 表达式可以匹配元数据信息,meter 语句可以实现流量计量,quota 语句可以实现流量配额等。这些丰富的表达式和语句为实现高级网络功能提供了强大的工具。
可扩展性nftables 的架构设计更加模块化,易于扩展。用户可以自定义 nftables 模块,添加新的匹配条件、动作或协议支持,满足特定的需求。

统一的语法 (Unified Syntax)
nftables 最显著的改进之一是采用了统一的命令行工具 nft 和统一的配置语法。

nft 命令行工具nft 工具取代了 iptables, ip6tables, arptables, ebtables 等多个工具,成为配置和管理所有类型 nftables 规则的统一入口。用户只需要学习一套 nft 命令,就可以管理各种网络协议的规则。
声明式配置语法nftables 的配置语法更加声明式和结构化,使用类似 JSON 的语法格式,易于阅读和编写。用户可以使用 nft 命令直接输入规则,也可以将规则保存到配置文件中,批量加载和管理。
事务性操作nftables 支持事务性操作,可以保证规则更新的原子性。用户可以使用 nft batch 命令批量提交规则,要么所有规则都成功添加,要么都不添加,避免了规则配置不一致的问题。

更强大的集合(Sets)和映射(Maps)
nftables 引入了更强大、更灵活的集合和映射概念,极大地提升了处理大量数据和实现复杂策略的能力。

集合(Sets)nftables 的集合可以存储大量的元素(如 IP 地址、端口、MAC 地址等),规则可以直接匹配集合,高效处理大量数据。nftables 支持多种类型的集合,包括匿名集合、命名集合、动态集合、区间集合等,满足不同的应用场景。
映射(Maps)nftables 的映射可以将一个键(Key)映射到一个值(Value),规则可以根据键查找对应的值,实现更复杂的策略。例如,可以使用映射实现基于 IP 地址的流量控制、基于端口的策略路由等。集合和映射可以嵌套使用,构建更灵活、更高效的规则集。

更好的未来展望 (Better Future Prospects)
nftables 不仅解决了 iptables 的局限性,也为未来的网络技术发展预留了扩展空间。

与 eBPF 的结合nftables 可以与 eBPF(Extended Berkeley Packet Filter) 技术结合,利用 eBPF 的高性能和可编程性,实现更灵活、更高效的数据包处理。
适应下一代网络技术nftables 的灵活架构和可扩展性使其能够更好地适应下一代网络技术的发展,例如,软件定义网络(SDN)网络功能虚拟化(NFV) 等。

总而言之,nftables 相比 iptables,在性能、灵活性、语法统一性、数据处理能力和未来发展潜力等方面都具有显著的优势。选择 nftables,意味着选择更高效、更现代、更强大的 Linux 网络过滤解决方案。

1.3 nftables 的核心概念

1.3.1 表(Tables)、链(Chains)、规则(Rules)

nftables 的核心概念可以用三个关键词概括:表(Tables)链(Chains)规则(Rules)。这三个概念构成了 nftables 规则组织的基本框架,理解它们之间的关系和作用是掌握 nftables 的关键。

表(Tables)
表是 nftables 规则组织的最顶层容器。一个表用于存放具有相同功能和协议类型的链。表的主要属性包括:

族(Family):指定表所属的网络协议族,例如 inet (同时支持 IPv4 和 IPv6)、ip (仅 IPv4)、ip6 (仅 IPv6)、arpbridgenetdevroute 等。表的族决定了表中规则可以处理的数据包类型。
名称(Name):表的唯一标识符,用于在 nft 命令中引用表。

一个 nftables 配置可以包含多个表,每个表负责处理特定协议族的数据包。例如,可以创建一个 inet 族的表用于处理 IPv4 和 IPv6 的通用防火墙规则,再创建一个 bridge 族的表用于处理网桥流量的过滤。

链(Chains)
链是规则的容器,一个链包含一系列规则,规则按照在链中的顺序依次执行。链的主要属性包括:

类型(Type):指定链的类型,决定链的功能和默认行为。常见的链类型包括 filter (用于数据包过滤)、nat (用于网络地址转换)、route (用于路由策略) 等。不同类型的链具有不同的预定义行为和适用场景。
Hook 点(Hook):对于 基链(Base Chain),需要指定其关联的 Netfilter Hook 点,例如 ingressforwardinputoutputpostrouting。Hook 点决定了基链在网络协议栈中的执行位置。普通链(Regular Chain) 则不需要指定 Hook 点,它们通常被基链或其他链通过 jumpgoto 语句调用。
优先级(Priority):当多个基链注册到同一个 Hook 点时,优先级决定了它们的执行顺序。优先级数值越小,优先级越高,越先执行。
名称(Name):链的唯一标识符,用于在 nft 命令和规则中引用链。

链是 nftables 规则组织的核心单元。规则在链中按照顺序执行,用户可以通过创建和组织链,构建复杂的规则流程。

规则(Rules)
规则是 nftables 执行的最小单元,每条规则定义了对数据包的匹配条件和相应的动作。规则的基本结构包括:

匹配条件(Match Criteria):用于判断数据包是否符合规则的条件。匹配条件可以基于数据包的协议类型、源地址、目标地址、端口、接口、连接状态等各种属性。nftables 提供了丰富的 表达式(Expressions) 用于定义匹配条件。
动作(Action/Target):当数据包满足匹配条件时,规则执行的动作。动作可以是接受数据包 (accept)、丢弃数据包 (drop)、拒绝数据包 (reject)、记录日志 (log)、跳转到其他链 (jump, goto)、进行网络地址转换 (nat) 等。nftables 提供了丰富的 语句(Statements) 用于定义动作。

规则是 nftables 实现网络过滤和控制的具体指令。通过组合不同的匹配条件和动作,可以实现各种复杂的网络安全策略。

表、链、规则之间的关系

⚝ 表是链的容器,一个表可以包含多个链。
⚝ 链是规则的容器,一个链包含多条规则。
⚝ 规则定义了对数据包的匹配条件和动作,规则在链中按照顺序执行。
⚝ 数据包首先进入表,然后根据表的族和链的 Hook 点,进入相应的链进行规则匹配和处理。

理解表、链、规则之间的层次关系,有助于我们更好地组织和管理 nftables 规则,构建清晰、高效的网络安全策略。

1.3.2 集合(Sets)、映射(Maps)、元素(Elements)

nftables 引入了 集合(Sets)映射(Maps) 的概念,极大地增强了其处理大量数据和实现复杂策略的能力。元素(Elements) 则是构成集合和映射的基本单元。

集合(Sets)
集合是一个包含多个相同类型元素的容器。集合的主要特点和优势包括:

高效的数据存储:集合使用优化的数据结构存储元素,例如 哈希表(Hash Table)树(Tree),可以高效地进行元素查找和匹配。
简化规则配置:可以将大量的 IP 地址、端口、MAC 地址等元素添加到集合中,规则可以直接匹配集合,而无需编写大量重复的规则。例如,可以使用一个 IP 地址集合来表示允许访问 Web 服务器的所有客户端 IP 地址,只需一条规则即可匹配整个集合。
动态更新:集合的内容可以动态更新,例如,可以定期从外部文件或数据库加载 IP 地址列表到集合中,实现动态的访问控制策略。

nftables 支持多种类型的集合:

匿名集合(Anonymous Sets):在规则中直接定义的集合,没有名称,仅在当前规则中有效。
命名集合(Named Sets):预先创建的集合,具有名称,可以在多条规则中引用,方便复用和管理。
动态集合(Dynamic Sets):集合的内容可以根据规则的执行结果动态更新,例如,可以根据连接状态动态添加或删除集合元素,实现更智能的策略。
区间集合(Interval Sets):集合元素可以是数值区间,例如,端口范围、IP 地址范围等,方便表示连续的元素范围。

映射(Maps)
映射是一个键值对(Key-Value Pair)的容器,将一个键(Key)映射到一个值(Value)。映射的主要特点和优势包括:

实现键值查找:规则可以根据键查找映射中对应的值,并基于值进行策略决策。
构建复杂策略:可以使用映射实现更复杂的策略,例如,基于 IP 地址的流量控制、基于端口的策略路由、基于用户身份的访问控制等。
数据关联:映射可以将不同类型的数据关联起来,例如,可以将 IP 地址映射到地理位置信息、用户组信息等。

nftables 的映射功能非常强大,可以用于实现各种高级网络策略。

元素(Elements)
元素是构成集合和映射的基本单元。元素的类型取决于集合或映射的定义。常见的元素类型包括:

IP 地址:IPv4 地址或 IPv6 地址。
端口号:TCP 或 UDP 端口号。
MAC 地址:以太网 MAC 地址。
数值:整数或浮点数。
字符串:文本字符串。
复合元素:由多个基本元素组成的复合结构。

元素是集合和映射的组成部分,通过添加、删除、更新元素,可以动态管理集合和映射的内容。

集合、映射、元素之间的关系

⚝ 集合和映射都是容器,用于存储元素。
⚝ 集合存储相同类型的元素,映射存储键值对,键和值都是元素。
⚝ 元素是集合和映射的基本组成单元。
⚝ 规则可以匹配集合或映射,也可以操作集合和映射中的元素。

通过灵活运用集合和映射,可以构建更高效、更可维护、更强大的 nftables 规则集,应对各种复杂的网络安全和流量管理需求。

1.3.3 表达式(Expressions)与语句(Statements)

nftables 的规则中,表达式(Expressions)语句(Statements) 是两个核心概念。表达式 用于定义规则的匹配条件,语句 用于定义规则的动作。理解表达式和语句的类型和用法,是编写 nftables 规则的关键。

表达式(Expressions)
表达式用于描述数据包的属性,并进行匹配判断。nftables 提供了丰富的表达式,可以匹配数据包的各个层面和属性。常见的表达式类型包括:

payload 表达式:用于访问和匹配数据包载荷(Payload)的内容,例如,可以匹配 TCP 头部、UDP 头部、应用层协议数据等。payload 表达式允许深入解析数据包内容,实现更精细的协议分析和过滤。
meta 表达式:用于匹配数据包的元数据(Metadata),例如,网络接口名称、数据包长度、数据包类型、时间戳等。meta 表达式可以基于数据包的上下文信息进行匹配。
ct 表达式:用于匹配连接追踪(Connection Tracking)的状态信息,例如,连接状态、连接方向、连接协议等。ct 表达式是实现有状态防火墙的关键。
limit 表达式:用于实现速率限制和流量控制,例如,限制连接速率、数据包速率等。limit 表达式可以防止恶意攻击和滥用行为。
rt 表达式:用于匹配路由信息,例如,路由类型、路由策略等。rt 表达式可以基于路由决策进行策略控制。
immediate 表达式:用于在规则中直接指定数值或字符串常量。
lookup 表达式:用于在集合或映射中查找元素。

表达式可以单独使用,也可以组合使用,构建复杂的匹配条件。nftables 使用简洁的语法来表示表达式,例如:

ip protocol tcp:匹配 IP 协议为 TCP 的数据包。
tcp sport 80:匹配 TCP 源端口为 80 的数据包。
ct state established,related:匹配连接状态为已建立或相关的连接。

语句(Statements)
语句定义了当规则匹配成功时,nftables 执行的动作。nftables 提供了多种语句,可以实现各种网络控制功能。常见的语句类型包括:

accept:接受数据包,允许数据包继续在网络协议栈中处理。
drop:丢弃数据包,阻止数据包继续处理,且不发送任何通知。
reject:拒绝数据包,丢弃数据包并发送拒绝通知(例如,TCP RST 或 ICMP 错误消息)给发送方。
log:记录数据包日志,将数据包信息记录到系统日志中,用于审计和分析。
queue:将数据包排队到用户空间,等待用户空间应用程序处理。
goto :跳转到指定的链 <chain-name> 继续执行规则,跳转后不返回。
jump :跳转到指定的链 <chain-name> 执行规则,跳转后返回到当前链继续执行后续规则。
return:从当前链返回,如果当前链是被 jump 语句调用的,则返回到调用链;如果是基链,则结束规则处理。
counter:数据包计数器,统计匹配规则的数据包数量和字节数。
meter:流量计量器,用于流量计量和带宽控制。
quota:流量配额,限制规则匹配的数据包流量。
masquerade:伪装,实现动态源地址转换(SNAT)。
snat:源地址转换(SNAT),修改数据包的源地址。
dnat:目标地址转换(DNAT),修改数据包的目标地址。
redirect:端口重定向,将数据包重定向到本机或其他端口。

语句可以单独使用,也可以组合使用,实现复杂的动作序列。一条规则可以包含多个语句,语句按照在规则中定义的顺序依次执行。例如:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input tcp sport 22 counter log prefix "SSH Access: " accept

这条规则包含三个语句:counter (计数器)、log (日志记录) 和 accept (接受)。当匹配到 TCP 源端口为 22 的数据包时,会依次执行这三个语句:先计数,再记录日志,最后接受数据包。

表达式与语句的关系

⚝ 表达式定义规则的匹配条件,语句定义规则的动作。
⚝ 规则的基本结构是:if <expression> then <statement>
⚝ 一条规则可以包含一个或多个表达式,以及一个或多个语句。
⚝ 表达式和语句是构建 nftables 规则的核心组件,通过灵活组合表达式和语句,可以实现各种复杂的网络策略。

1.4 实验环境搭建与 nft 工具快速上手

1.4.1 Linux 环境准备:内核版本、nftables 工具安装

要开始 nftables 的学习和实践,首先需要搭建一个合适的实验环境。一个基本的 Linux 环境,并安装 nftables 工具即可满足学习需求。

Linux 发行版选择 (Linux Distribution Selection)
推荐使用主流的 Linux 发行版,例如:

Ubuntu:流行的桌面和服务器发行版,易于上手,社区支持活跃。
CentOS/RHEL:稳定可靠的企业级发行版,常用于服务器环境。
Debian:历史悠久的通用发行版,以稳定性和自由著称。
Fedora:Red Hat 赞助的社区发行版,技术更新较快,可以体验最新的软件包。

选择哪个发行版主要取决于个人偏好和使用习惯。对于初学者,Ubuntu 或 Fedora 可能更友好。对于追求稳定性的用户,CentOS/RHEL 或 Debian 是不错的选择。

内核版本要求 (Kernel Version Requirement)
nftables 需要 Linux 内核版本 3.13 或更高版本。建议使用较新的内核版本,以获得更好的功能和性能支持。可以使用以下命令查看内核版本:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 uname -r

如果内核版本低于 3.13,建议升级内核。不同发行版的内核升级方法有所不同,请参考相应的发行版文档。

nftables 工具安装 (nftables Tool Installation)
nftables 的用户空间管理工具是 nft 命令行工具。大多数主流 Linux 发行版都提供了 nftables 软件包,可以使用发行版的包管理器进行安装。

Ubuntu/Debian

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 sudo apt update
2 sudo apt install nftables

CentOS/RHEL/Fedora

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 sudo yum install nftables # CentOS/RHEL 7
2 sudo dnf install nftables # CentOS/RHEL 8/9, Fedora

Arch Linux

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 sudo pacman -S nftables

安装完成后,可以使用以下命令检查 nft 工具是否安装成功以及版本信息:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft --version

如果成功显示 nftables 版本信息,则说明安装成功。

启动 nftables 服务 (Start nftables Service)
安装 nftables 工具后,通常需要启动 nftables 服务才能使规则生效。不同发行版的启动方式可能略有不同。

使用 systemd 的发行版 (如 Ubuntu 16.04+, CentOS/RHEL 7+, Fedora, Debian 8+)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 sudo systemctl start nftables
2 sudo systemctl enable nftables # 设置开机自启
3 sudo systemctl status nftables # 查看服务状态

使用 SysVinit 或 Upstart 的发行版 (较旧版本)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 sudo service nftables start
2 sudo chkconfig nftables on # 设置开机自启 (SysVinit)
3 # 或
4 sudo update-rc.d nftables defaults # 设置开机自启 (Upstart)
5 sudo service nftables status # 查看服务状态

启动 nftables 服务后,就可以开始使用 nft 命令行工具配置和管理 nftables 规则了。

1.4.2 nft 命令行工具的基本操作:语法结构、常用命令

nftnftables 的命令行管理工具,用于创建、查看、修改和删除 nftables 对象(表、链、规则、集合、映射等)。掌握 nft 工具的基本操作是学习 nftables 的首要步骤。

nft 命令的基本语法结构 (Basic Syntax Structure of nft Command)
nft 命令的基本语法结构如下:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft [options] command [family] [object] [parameters]

nft: nft 命令本身。
[options]: 可选的命令行选项,例如 -f <file> (从文件加载配置)、-i (交互模式) 等。
command: 要执行的操作命令,例如 add, delete, list, flush 等。
[family]: 可选的网络协议族,例如 inet, ip, ip6, arp, bridge, netdev, route。如果命令操作的对象属于某个特定的族,则需要指定族。
[object]: 要操作的 nftables 对象类型,例如 table, chain, rule, set, map
[parameters]: 命令的具体参数,例如对象名称、属性、规则定义等。

常用 nft 命令 (Common nft Commands)

nft add table <family> <table>: 创建表。
▮▮▮▮⚝ 例如:nft add table inet filter 创建一个 inet 族的名为 filter 的表。
nft delete table <table>: 删除表。
▮▮▮▮⚝ 例如:nft delete table inet filter 删除 inet 族的 filter 表。
nft list tables: 列出所有表。
▮▮▮▮⚝ 例如:nft list tables 列出所有已创建的表。
nft add chain <family> <table> <chain> { type <type> hook <hook> priority <priority>; policy <policy>; }: 创建链。
▮▮▮▮⚝ 例如:nft add chain inet filter input { type filter hook input priority 0 ; policy accept; }inet 族的 filter 表中创建一个名为 input 的基链,类型为 filter,Hook 点为 input,优先级为 0,默认策略为 accept
nft delete chain <family> <table> <chain>: 删除链。
▮▮▮▮⚝ 例如:nft delete chain inet filter input 删除 inet 族的 filter 表中的 input 链。
nft list chains [family] [<table>]: 列出链。
▮▮▮▮⚝ 例如:nft list chains inet filter 列出 inet 族的 filter 表中的所有链。
nft add rule <family> <table> <chain> <rule-definition>: 添加规则。
▮▮▮▮⚝ 例如:nft add rule inet filter input tcp dport 22 acceptinet 族的 filter 表的 input 链中添加一条规则,允许 TCP 目标端口为 22 的数据包。
nft delete rule <family> <table> <chain> handle <handle>: 删除规则,需要指定规则的句柄(handle)。
▮▮▮▮⚝ 例如:nft list rule inet filter input 列出 input 链的规则,找到要删除的规则的句柄,然后使用 nft delete rule inet filter input handle <handle> 删除。
nft list rules [family] [<table> [ <chain>]]: 列出规则。
▮▮▮▮⚝ 例如:nft list rules inet filter input 列出 inet 族的 filter 表的 input 链中的所有规则。
nft flush table <family> <table>: 清空表中的所有链和规则。
▮▮▮▮⚝ 例如:nft flush table inet filter 清空 inet 族的 filter 表。
nft flush ruleset: 清空所有表、链和规则,恢复到初始状态。
▮▮▮▮⚝ 例如:nft flush ruleset 清空所有 nftables 配置。
nft save > <config-file>: 保存当前 nftables 配置到文件。
▮▮▮▮⚝ 例如:nft save > /etc/nftables.conf 将当前配置保存到 /etc/nftables.conf 文件。
nft -f <config-file>: 从文件加载 nftables 配置。
▮▮▮▮⚝ 例如:nft -f /etc/nftables.conf/etc/nftables.conf 文件加载配置。
nft monitor: 实时监控 nftables 事件,例如规则的添加、删除、数据包匹配等。

掌握这些基本命令,就可以进行 nftables 的基本配置和管理。可以通过 nft --helpman nft 命令查看更详细的 nft 工具使用说明。

1.4.3 第一个 nftables 规则:允许 SSH 访问

为了快速上手 nftables,我们来创建一个最简单的 nftables 规则:允许 SSH 访问。SSH 服务默认使用 TCP 端口 22。我们的目标是创建一个规则,允许来自任何源 IP 地址,目标端口为 22 的 TCP 连接进入本机。

创建表 (Create Table)
首先,创建一个 inet 族的名为 filter 的表,用于存放防火墙规则。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 sudo nft add table inet filter

创建链 (Create Chain)
filter 表中创建一个名为 input 的基链,类型为 filter,Hook 点为 input,优先级为 0,默认策略为 drop(拒绝所有未明确允许的流量)。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 sudo nft add chain inet filter input { type filter hook input priority 0 ; policy drop; }

这里将默认策略设置为 drop,意味着除非有明确的 accept 规则,否则所有入站流量都将被拒绝。这是一个良好的安全实践,即 默认拒绝策略(Default Deny Policy)

添加规则:允许 SSH 访问 (Add Rule: Allow SSH Access)
input 链中添加一条规则,允许 TCP 目标端口为 22 的连接。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 sudo nft add rule inet filter input tcp dport 22 accept

这条规则的含义是:

inet filter input: 将规则添加到 inet 族的 filter 表的 input 链中。
tcp dport 22: 匹配条件,匹配 TCP 协议且目标端口为 22 的数据包。
accept: 动作,如果匹配成功,则接受数据包。

查看规则 (List Rules)
使用 nft list rules 命令查看已添加的规则。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 sudo nft list rules inet filter input

应该看到类似如下的输出:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table inet filter {
2 chain input {
3 type filter hook input priority 0 policy drop;
4 tcp dport 22 accept comment "Allow SSH access"
5 }
6 }

可以看到,我们成功创建了 filter 表和 input 链,并在 input 链中添加了一条允许 SSH 访问的规则。

测试 SSH 访问 (Test SSH Access)
现在,可以从另一台机器尝试 SSH 连接到运行 nftables 的机器,测试规则是否生效。如果 SSH 连接成功,则说明规则配置正确。

保存配置 (Save Configuration)
为了使规则在系统重启后仍然生效,需要将当前的 nftables 配置保存到配置文件中。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 sudo nft save > /etc/nftables.conf

然后,设置 nftables 服务开机自启,确保系统启动时自动加载配置。

通过这个简单的例子,我们完成了第一个 nftables 规则的创建。这只是 nftables 功能的冰山一角,但它展示了 nftables 的基本配置流程和语法结构。在接下来的章节中,我们将深入学习 nftables 的更多高级特性和应用场景。

ENDOF_CHAPTER_

2. chapter 2: nftables 基础:表、链与规则详解

2.1 表的创建与管理

nftables 中,表(Tables) 是规则组织的最顶层结构,它如同一个容器,用于存放具有相同协议族(family)的 链(Chains)。在开始构建任何 nftables 规则之前,首先需要创建表。表的主要作用是定义规则集所应用的协议族,例如 IPv4IPv6ARP 等。

2.1.1 表的类型:inetipip6arpbridgenetdevroute

nftables 支持多种协议族,这意味着你可以使用 nftables 来管理不同类型的网络流量。以下是 nftables 中常见的表类型:

inet混合协议族表。这是最常用也是最灵活的表类型。inet 表可以同时处理 IPv4IPv6 流量。在一个 inet 表中,你可以创建同时适用于 IPv4IPv6 的链和规则,这大大简化了同时管理两种协议栈的配置。使用 inet 表时,规则会自动应用于 IPv4IPv6 协议,除非你显式指定了协议版本。

ipIPv4 协议族表。顾名思义,ip 表专门用于处理 IPv4 流量。在这个表中创建的链和规则只对 IPv4 数据包生效。如果你只需要管理 IPv4 流量,可以使用 ip 表。

ip6IPv6 协议族表。与 ip 表类似,ip6 表专门用于处理 IPv6 流量。在这个表中创建的链和规则只对 IPv6 数据包生效。用于专门管理 IPv6 网络环境。

arpARP 协议族表arp 表用于处理 地址解析协议(Address Resolution Protocol, ARP) 流量。ARP 用于将 IP 地址解析为 媒体访问控制(Media Access Control, MAC) 地址。arp 表允许你过滤和管理 ARP 请求和应答,这在网络安全和管理中非常有用,例如防止 ARP 欺骗。

bridge网桥协议族表bridge 表用于处理 网桥(bridge) 流量,即二层网络流量。当你需要在网桥设备上进行包过滤和管理时,可以使用 bridge 表。这对于虚拟化环境、网络交换机等场景非常有用,可以实现基于 MAC 地址、VLAN ID 等二层信息的过滤和策略。

netdev网络设备(network device)协议族表netdev 表是 nftables 中一个非常底层的表类型,它在网络设备级别工作,甚至在数据包进入网络协议栈之前就可以进行处理。netdev 表的 hook 点与传统的 Netfilter hook 点不同,它使用 ingress hook 点,允许在网络接口接收数据包的最早阶段进行处理。这对于需要高性能包过滤和处理的场景非常有用,例如 DDoS 防御、流量监控等。netdev 表通常与特定的网络接口绑定。

route路由协议族表route 表用于在路由决策过程中影响数据包的路由行为。你可以使用 route 表来创建规则,根据数据包的属性来修改路由选择。这对于实现复杂的策略路由、负载均衡等高级网络功能非常有用。

选择合适的表类型非常重要,它决定了你的规则集能够处理的网络流量类型。通常,inet 表由于其灵活性和对 IPv4/IPv6 双栈的支持,是大多数场景下的首选。而其他表类型则在特定的网络环境和需求下发挥作用。

2.1.2 创建、查看、删除表

掌握表的创建、查看和删除是使用 nftables 的基本操作。nft 命令行工具提供了简洁的语法来管理表。

创建表(Create Table)

使用 nft add table 命令创建表。你需要指定表类型和表名。表名可以是任意字符串。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建 inet 表,名为 my_inet_table
2 nft add table inet my_inet_table
3
4 # 创建 ip 表,名为 my_ip_table
5 nft add table ip my_ip_table
6
7 # 创建 bridge 表,名为 my_bridge_table
8 nft add table bridge my_bridge_table

查看表(View Table)

使用 nft list tables 命令列出所有已创建的表。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft list tables

输出示例:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table inet my_inet_table
2 table ip my_ip_table
3 table bridge my_bridge_table

要查看特定表的详细信息,可以使用 nft list table <family> <table> 命令。例如,查看 my_inet_table 表的详细信息:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft list table inet my_inet_table

如果表内有链或规则,也会一并显示出来。如果表是空的,则只显示表的基本信息。

删除表(Delete Table)

使用 nft delete table <family> <table> 命令删除表。注意,删除表会同时删除表内所有的链和规则,这是一个不可逆的操作,请务必谨慎。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 删除 my_inet_table 表
2 nft delete table inet my_inet_table
3
4 # 删除 my_ip_table 表
5 nft delete table ip my_ip_table

在删除表之前,最好先清空表内的所有链和规则,或者先备份当前的 nftables 配置。

示例:创建、查看和删除 inet 表

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 1. 创建 inet 表 my_test_table
2 nft add table inet my_test_table
3
4 # 2. 查看所有表
5 nft list tables
6
7 # 3. 查看 my_test_table 表的详细信息 (此时表是空的)
8 nft list table inet my_test_table
9
10 # 4. 删除 my_test_table 表
11 nft delete table inet my_test_table
12
13 # 5. 再次查看所有表,my_test_table 应该已经不存在了
14 nft list tables

通过这些基本操作,你可以开始管理 nftables 的表,为后续创建链和规则打下基础。记住,表是规则组织的第一步,选择合适的表类型对于构建有效的 nftables 配置至关重要。

2.2 链的深入解析

链(Chains)nftables 规则组织的核心结构。链存在于表中,用于容纳一系列的 规则(Rules)。数据包会按照链中规则的顺序依次进行匹配,直到找到匹配的规则或者遍历完整个链。链的设计使得规则管理更加模块化和高效。

2.2.1 链的类型:filternatroute

nftables 中的链可以根据其功能和用途进行分类。常见的链类型包括:

filter过滤链filter 链是最常用的链类型,用于实现数据包的过滤功能,即决定数据包是被接受(accept)还是丢弃(drop)。filter 链通常用于构建防火墙规则,控制网络流量的进出。

nat网络地址转换(Network Address Translation, NAT)链nat 链用于实现 NAT 功能,包括 源地址转换(Source NAT, SNAT)目标地址转换(Destination NAT, DNAT)伪装(Masquerade)nat 链允许你修改数据包的源 IP 地址、目标 IP 地址、源端口或目标端口,常用于实现网络共享、端口转发等功能。

route路由链route 链用于在数据包路由过程中影响路由决策。通过在 route 链中设置规则,可以根据数据包的属性来修改数据包的路由选择,实现策略路由等高级路由功能。

除了以上常见的链类型,nftables 还支持其他类型的链,例如:

mangle(在 iptables 中常见,但在 nftables 中不作为链类型,功能被更灵活的结构取代):在 iptables 中,mangle 表用于修改数据包的 服务类型(Type of Service, TOS) 字段、生存时间(Time To Live, TTL) 字段等。在 nftables 中,这些功能可以通过更灵活的表达式和语句来实现,不再需要特定的 mangle 链类型。

⑤ 用户自定义链:除了预定义的链类型,nftables 允许用户创建自定义的链,用于更灵活地组织和管理规则。自定义链可以提高规则的可读性和可维护性,并实现更复杂的规则逻辑。

nftables 中,链的类型更多的是一种逻辑上的分类,用于帮助用户更好地组织和管理规则。实际上,nftables 的链更加通用和灵活,可以通过不同的 hook 点和优先级来实现各种网络功能。

2.2.2 基链(Base Chain)与普通链(Regular Chain)

nftables 的链可以分为 基链(Base Chain)普通链(Regular Chain) 两种类型。理解这两种链类型的区别对于构建有效的 nftables 规则集至关重要。

基链(Base Chain)

入口点:基链是数据包进入 nftables 规则集的入口点。当数据包到达网络协议栈的特定 hook 点时,会首先进入相应的基链进行处理。
Hook 点绑定:基链必须与一个 hook 点(Hook Point) 关联。Hook 点定义了基链在网络协议栈中的位置,即在数据包处理的哪个阶段应用规则。常见的 hook 点包括 ingressforwardinputoutputpostrouting,后续会详细介绍。
类型定义:创建基链时需要指定链的类型(例如 filternatroute)和 hook 点。链类型有助于逻辑分类,hook 点则决定了链的实际作用位置。
唯一性:在一个表中,同一个 hook 点只能绑定一个基链。这意味着对于每个 hook 点,只有一个入口基链。
策略(Policy):基链可以设置默认策略(policy),例如 acceptdrop。当数据包遍历完基链中的所有规则后,如果没有匹配任何规则,则会应用默认策略。

普通链(Regular Chain)

非入口点:普通链不是数据包的入口点。数据包不会直接进入普通链,而是通过基链或其他链的 跳转(jump)goto 动作才能进入普通链。
无 Hook 点绑定:普通链不与任何 hook 点关联。它们是规则的容器,用于组织和模块化规则集。
类型可选:创建普通链时不需要指定链类型,或者可以指定为 filter 等类型以增强可读性。
可重用性:普通链可以在多个基链或其他链中被调用,实现规则的复用和模块化。
无默认策略:普通链不能设置默认策略。当数据包遍历完普通链中的所有规则后,如果没有被明确处理(例如 acceptdropreturn),则会返回到调用链的下一条规则继续执行。

总结基链与普通链的区别

特性基链(Base Chain)普通链(Regular Chain)
入口点是,数据包入口否,通过跳转或 goto 进入
Hook 点必须绑定 Hook 点不绑定 Hook 点
类型需要指定类型(filter, nat, route等)类型可选(filter等,或不指定)
默认策略可以设置默认策略(policy)无默认策略
调用方式数据包自动进入通过跳转或 goto 动作调用
主要用途定义数据包处理的入口和默认行为组织和复用规则,模块化规则集

应用场景示例

假设我们要创建一个防火墙,需要对入站(input)、转发(forward)和出站(output)流量进行过滤,并对出站流量进行 NAT。可以这样设计链的结构:

⚝ 创建一个 inet 表,例如 my_firewall
⚝ 创建三个基链,分别用于处理 inputforwardoutput hook 点,类型都设置为 filter
▮▮▮▮⚝ input_chain (hook input,type filter)
▮▮▮▮⚝ forward_chain (hook forward,type filter)
▮▮▮▮⚝ output_chain (hook output,type filter)
⚝ 创建一个基链用于处理 postrouting hook 点,类型设置为 nat,用于 SNAT。
▮▮▮▮⚝ nat_chain (hook postrouting,type nat)
⚝ 创建一些普通链,用于组织和复用规则,例如:
▮▮▮▮⚝ allowed_services (普通链,用于存放允许的服务规则)
▮▮▮▮⚝ block_malicious_ips (普通链,用于存放阻止恶意 IP 的规则)

在基链中,可以使用 jumpgoto 动作跳转到普通链,实现规则的模块化和复用。例如,在 input_chain 中,可以先跳转到 allowed_services 链检查是否是允许的服务,然后再跳转到 block_malicious_ips 链检查是否是恶意 IP。

理解基链和普通链的区别,以及如何合理地组织和使用它们,是构建清晰、高效和可维护的 nftables 规则集的关键。

2.2.3 链的 hook 点:ingressforwardinputoutputpostrouting

Hook 点(Hook Points)Netfilter 框架的核心概念之一,也是 nftables 的重要组成部分。Hook 点定义了规则在网络协议栈中被应用的位置。当网络数据包在协议栈中流动时,会经过不同的 hook 点,nftables 规则可以在这些 hook 点被触发和执行。

nftables 提供了五个主要的 hook 点,涵盖了数据包在网络协议栈中的关键路径:

ingress入口 hook 点ingress hook 点是数据包进入网络设备(网卡)后,最早 可以被 nftables 规则处理的位置,甚至在网络接口驱动程序接收数据包之后、协议栈处理之前。ingress hook 点属于 netdev 表类型,与特定的网络设备绑定。

位置:网络设备接收数据包后,协议栈处理之前。
用途
▮▮▮▮⚝ 早期过滤:在数据包进入协议栈之前进行过滤,可以有效减少不必要的数据包处理开销,提高性能。
▮▮▮▮⚝ DDoS 防御:在入口处进行恶意流量检测和过滤,可以有效防御 DDoS 攻击。
▮▮▮▮⚝ 流量整形:在入口处进行流量整形,限制入口流量速率。
表类型netdev 表。
链类型:基链必须是 type filtertype route

forward转发 hook 点forward hook 点位于数据包需要被 转发 时经过的位置。当 Linux 系统作为路由器或网关,接收到的数据包需要转发到其他网络时,会经过 forward hook 点。

位置:数据包路由决策确定需要转发后,但在发送到下一跳之前。
用途
▮▮▮▮⚝ 转发策略:控制哪些数据包可以被转发,哪些需要被阻止。
▮▮▮▮⚝ 防火墙:构建路由器或网关的转发防火墙,保护内部网络安全。
▮▮▮▮⚝ 流量监控:监控和记录转发流量。
表类型inetipip6 表。
链类型:基链必须是 type filter

input输入 hook 点input hook 点位于数据包的目的地是 本机 时经过的位置。当 Linux 系统接收到的数据包的目标 IP 地址是本机地址时,会经过 input hook 点。

位置:数据包路由决策确定目的地为本机后,但在交给上层协议(如 TCP、UDP)处理之前。
用途
▮▮▮▮⚝ 本机防火墙:保护 Linux 系统自身的安全,控制允许进入本机的流量。
▮▮▮▮⚝ 服务访问控制:限制对本机服务的访问,例如 SSH、HTTP 等。
▮▮▮▮⚝ 入侵检测:检测和阻止恶意入站连接。
表类型inetipip6 表。
链类型:基链必须是 type filter

output输出 hook 点output hook 点位于本机 发送 数据包时经过的位置。当 Linux 系统需要向外发送数据包时,会经过 output hook 点。

位置:本机进程发送数据包后,但在发送到网络接口之前。
用途
▮▮▮▮⚝ 出站流量控制:控制本机允许发出的流量,例如限制某些程序或用户的网络访问。
▮▮▮▮⚝ 安全审计:监控和记录本机发出的流量。
▮▮▮▮⚝ QoS:对出站流量进行 QoS 标记和策略应用。
表类型inetipip6 表。
链类型:基链必须是 type filtertype route

postrouting后路由 hook 点postrouting hook 点位于数据包即将离开网络设备(网卡)之前,并且在 路由决策之后输出 hook 点之后postrouting hook 点是进行 源地址转换(SNAT)伪装(Masquerade) 的常用位置。

位置:数据包路由决策和输出处理之后,即将发送到网络接口之前。
用途
▮▮▮▮⚝ 源地址转换(SNAT):修改数据包的源 IP 地址,实现网络共享、私有网络访问公网等功能。
▮▮▮▮⚝ 伪装(Masquerade):动态 IP 环境下的 SNAT,自动使用出口接口的 IP 地址作为源地址。
▮▮▮▮⚝ 修改数据包:在数据包离开前进行最后的修改,例如修改 TTL 值。
表类型inetipip6 表。
链类型:基链必须是 type nattype mangle(虽然 mangle 不作为链类型,但功能类似)。

Hook 点与数据包流向

数据包在网络协议栈中流动的过程中,会依次经过不同的 hook 点。对于一个需要转发的数据包,其流向通常是:

ingress (netdev 表) -> prerouting (iptables, nftables 不直接使用) -> forward (filter 表) -> postrouting (nat 表) -> egress (netdev 表)

对于目的地是本机的数据包:

ingress (netdev 表) -> prerouting (iptables, nftables 不直接使用) -> input (filter 表) -> ... (本机处理) ... -> output (filter 表) -> postrouting (nat 表) -> egress (netdev 表)

选择合适的 Hook 点

选择合适的 hook 点是构建有效 nftables 规则集的关键。你需要根据你的需求和要实现的功能,选择在哪个阶段应用规则。

入口过滤和早期处理:使用 ingress hook 点。
转发策略和路由器防火墙:使用 forward hook 点。
本机防火墙和入站访问控制:使用 input hook 点。
出站流量控制和审计:使用 output hook 点。
源地址转换和 NAT:使用 postrouting hook 点。

理解 hook 点的概念和作用,可以帮助你更精确地控制网络流量,构建更安全、更高效的网络策略。

2.2.4 链的优先级(Priority)

nftables 中,优先级(Priority) 用于确定 同一个 hook 点 上的 多个链 的执行顺序。当在同一个 hook 点上创建了多个基链时,优先级高的链会先被执行。优先级是一个整数值,数值越小,优先级越高

优先级的作用

确定链的执行顺序:在同一个 hook 点上,如果有多个基链,优先级决定了它们的执行顺序。优先级高的链先被执行,优先级低的链后被执行。
实现更精细的控制:通过优先级,可以在同一个 hook 点上实现多层次的规则处理。例如,可以先执行高优先级的安全规则,再执行低优先级的 QoS 规则。
与其他 Netfilter 组件集成:优先级可以用于与 Netfilter 的其他组件(例如连接追踪 conntrack)集成,确保规则在正确的时机执行。

默认优先级

如果创建链时没有显式指定优先级,nftables 会使用默认优先级。不同类型的链和 hook 点可能有不同的默认优先级。通常,filter 类型的链默认优先级为 0,nat 类型的链默认优先级也为 0。

设置优先级

在创建基链时,可以使用 priority <number> 参数来指定链的优先级。优先级值是一个整数,可以是负数、零或正数。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建一个 input 基链,优先级为 -100 (高优先级)
2 nft add chain inet filter input_chain { type filter hook input priority -100 ; }
3
4 # 创建一个 input 基链,优先级为 100 (低优先级)
5 nft add chain inet filter input_chain_low_priority { type filter hook input priority 100 ; }

优先级范围

nftables 的优先级范围通常在 -32768 到 32767 之间。负数表示高优先级,正数表示低优先级,零表示默认优先级。

优先级应用示例

假设我们需要在 input hook 点上同时应用防火墙规则和 QoS 规则。防火墙规则需要优先执行,确保安全策略先于 QoS 策略生效。可以这样设置优先级:

  1. 创建一个 input 基链 firewall_input,类型为 filter,优先级设置为 较低的值,例如 -50
  2. 在这个 firewall_input 链中,添加防火墙规则,例如允许已建立连接、阻止非法入站连接等。
  3. 创建一个 input 基链 qos_input,类型为 filter,优先级设置为 较高的值,例如 50
  4. 在这个 qos_input 链中,添加 QoS 规则,例如对特定类型的流量进行限速或优先级标记。

由于 firewall_input 链的优先级较低(-50),它会 先于 qos_input 链(优先级 50)被执行。这样就保证了防火墙规则先于 QoS 规则生效。

查看链的优先级

使用 nft list chain <family> <table> <chain> 命令可以查看链的详细信息,包括优先级。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft list chain inet filter firewall_input

输出示例:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table inet filter {
2 chain firewall_input { # handle 2
3 type filter hook input priority -50; policy accept;
4 }
5 }

在输出中,priority -50 表示该链的优先级为 -50。

优先级选择建议

安全策略优先:通常,防火墙等安全策略应该具有较高的优先级,确保安全规则先于其他规则生效。
QoS 策略次之:QoS 策略可以在安全策略之后执行,对符合特定条件的流量进行 QoS 处理。
默认优先级适用场景:对于大多数简单的规则集,使用默认优先级即可。只有在需要精细控制规则执行顺序,或者需要与其他 Netfilter 组件集成时,才需要显式设置优先级。
避免优先级冲突:在同一个 hook 点上创建多个链时,要仔细规划优先级,避免优先级冲突导致规则执行顺序混乱。

合理使用优先级,可以构建更复杂、更精细的 nftables 规则集,满足各种高级网络策略需求。

2.2.5 创建、查看、删除链

链的管理是 nftables 配置的核心操作。掌握链的创建、查看和删除,可以有效地组织和维护规则集。

创建链(Create Chain)

使用 nft add chain 命令创建链。你需要指定表族(family)、表名、链名和链的类型(对于基链还需要指定 hook 点和优先级)。

创建基链

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建一个 inet 表的 filter 基链 input_chain,hook 点为 input,优先级为 0 (默认)
2 nft add chain inet filter input_chain { type filter hook input priority 0 ; }
3
4 # 创建一个 inet 表的 nat 基链 postrouting_chain,hook 点为 postrouting,优先级为 100
5 nft add chain inet nat postrouting_chain { type nat hook postrouting priority 100 ; }
6
7 # 创建一个 inet 表的 filter 基链 forward_chain,hook 点为 forward,策略为 drop
8 nft add chain inet filter forward_chain { type filter hook forward priority 0 policy drop ; }

▮▮▮▮注意:基链必须指定 typehookprioritypolicy 是可选的。policy 只能在基链上设置,用于指定默认策略(acceptdrop)。

创建普通链

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建一个 inet 表的普通链 allowed_services
2 nft add chain inet filter allowed_services

▮▮▮▮注意:普通链不需要指定 typehookpriority

查看链(View Chain)

查看表中的所有链

▮▮▮▮使用 nft list table <family> <table> 命令可以列出指定表中的所有链。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft list table inet filter

▮▮▮▮输出示例:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table inet filter {
2 chain input_chain { # handle 2
3 type filter hook input priority 0; policy accept;
4 }
5
6 chain forward_chain { # handle 3
7 type filter hook forward priority 0; policy drop;
8 }
9
10 chain output_chain { # handle 4
11 type filter hook output priority 0; policy accept;
12 }
13
14 chain allowed_services { # handle 5
15 }
16 }

查看特定链的详细信息

▮▮▮▮使用 nft list chain <family> <table> <chain> 命令可以查看特定链的详细信息,包括链的类型、hook 点、优先级、策略以及链中包含的规则。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft list chain inet filter input_chain

▮▮▮▮输出示例:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table inet filter {
2 chain input_chain { # handle 2
3 type filter hook input priority 0; policy accept;
4 # 规则会在这里列出
5 }
6 }

删除链(Delete Chain)

使用 nft delete chain <family> <table> <chain> 命令删除链。注意,删除链会同时删除链内所有的规则,这是一个不可逆的操作,请务必谨慎。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 删除 inet 表 filter 族中的 input_chain 链
2 nft delete chain inet filter input_chain
3
4 # 删除 inet 表 filter 族中的 allowed_services 链
5 nft delete chain inet filter allowed_services

示例:创建、查看和删除链

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 1. 创建一个 inet 表 filter 族的基链 test_input_chain,hook 点为 input
2 nft add chain inet filter test_input_chain { type filter hook input priority 0 ; }
3
4 # 2. 创建一个 inet 表 filter 族的普通链 test_regular_chain
5 nft add chain inet filter test_regular_chain
6
7 # 3. 查看 inet 表 filter 族中的所有链
8 nft list table inet filter
9
10 # 4. 查看 test_input_chain 链的详细信息
11 nft list chain inet filter test_input_chain
12
13 # 5. 删除 test_input_chain 链
14 nft delete chain inet filter test_input_chain
15
16 # 6. 删除 test_regular_chain 链
17 nft delete chain inet filter test_regular_chain
18
19 # 7. 再次查看 inet 表 filter 族中的所有链,test_input_chain 和 test_regular_chain 应该已经不存在了
20 nft list table inet filter

通过这些链管理操作,你可以灵活地创建、查看和删除 nftables 的链,构建清晰和可维护的规则集。链是规则组织的关键,合理地使用链可以提高规则的管理效率和可读性。

2.3 规则的语法与结构

规则(Rules)nftables 配置中最基本的单元,用于定义对网络数据包的具体处理策略。规则由 匹配条件(Match Criteria)动作(Action/Target) 组成。当数据包满足规则的匹配条件时,nftables 会执行规则定义的动作。

2.3.1 规则的组成:匹配条件(Match Criteria)与动作(Action/Target)

一条 nftables 规则通常由以下两个主要部分组成:

匹配条件(Match Criteria)

定义:匹配条件用于指定规则要匹配的数据包的特征。只有当数据包满足所有指定的匹配条件时,规则才会被应用。
类型:匹配条件可以基于数据包的各种属性,例如:
▮▮▮▮⚝ 协议ip protocol tcp, ip protocol udp, ip protocol icmp 等。
▮▮▮▮⚝ 源地址和目标地址ip saddr 192.168.1.100, ip daddr 10.0.0.0/24, ip6 saddr ..., ip6 daddr ... 等。
▮▮▮▮⚝ 源端口和目标端口tcp sport 80, tcp dport { 22, 80, 443 }, udp sport ..., udp dport ... 等。
▮▮▮▮⚝ 网络接口iifname "eth0", oifname "wlan0", iif ..., oif ... 等。
▮▮▮▮⚝ 连接状态ct state established,related, ct state invalid 等。
▮▮▮▮⚝ 数据包载荷payload base 5 offset 12 layer l4 eq 80 (匹配 TCP 头部偏移 12 字节处的值是否为 80,即目标端口是否为 80) 等。
▮▮▮▮⚝ 元数据meta pkttype host, meta length > 1024 等。
组合:可以使用逻辑运算符(例如 && 表示 "与",, 也表示 "与",|| 表示 "或",! 表示 "非")将多个匹配条件组合起来,构建更复杂的匹配规则。

动作(Action/Target)

定义:动作定义了当数据包满足匹配条件时,nftables 要执行的操作。
类型:常见的动作包括:
▮▮▮▮⚝ accept接受 数据包,允许数据包继续在网络协议栈中流动。
▮▮▮▮⚝ drop丢弃 数据包,阻止数据包继续在网络协议栈中流动,且不给发送方任何通知。
▮▮▮▮⚝ reject拒绝 数据包,丢弃数据包并向发送方发送一个拒绝通知(例如 TCP RST 或 ICMP 错误消息)。
▮▮▮▮⚝ log日志记录 数据包的信息,用于审计和监控。
▮▮▮▮⚝ queue排队 数据包到用户空间,用于更高级的处理,例如入侵检测系统(IDS)。
▮▮▮▮⚝ goto <chain>跳转 到指定的链,继续在目标链中匹配规则。
▮▮▮▮⚝ jump <chain>跳转 到指定的链,执行完目标链后返回到当前链继续执行。
▮▮▮▮⚝ return返回 到调用链的下一条规则,或者如果当前链是基链,则应用基链的默认策略。
▮▮▮▮⚝ counter计数器,对匹配的数据包进行计数。
▮▮▮▮⚝ meter流量计量器,用于流量控制和速率限制。
▮▮▮▮⚝ quota流量配额,限制特定流量的使用量。
▮▮▮▮⚝ snatdnatmasqueradeNAT 相关动作,用于网络地址转换。
▮▮▮▮⚝ redirect端口重定向,将数据包重定向到本机或其他端口。

规则语法结构

nftables 规则的基本语法结构如下:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule

nft add rule:添加规则的命令。
<family>:表族,例如 inetipip6 等。
<table>:表名,例如 filternat 等。
<chain>:链名,例如 input_chainforward_chain 等。
<match-criteria>:匹配条件,可以是一个或多个匹配条件的组合。
<action>:动作,指定要执行的操作。

示例规则

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 允许来自任何地址,目标端口为 22 的 TCP 连接 (SSH)
2 nft add rule inet filter input_chain tcp dport 22 accept
3
4 # 阻止来自 192.168.1.100 的所有 IPv4 流量
5 nft add rule ip filter forward_chain ip saddr 192.168.1.100 drop
6
7 # 记录所有新的入站 TCP 连接尝试
8 nft add rule inet filter input_chain tcp flags syn ct state new log prefix "New TCP connection attempt: "
9
10 # 跳转到 allowed_services 链
11 nft add rule inet filter input_chain jump allowed_services

理解规则的组成部分和基本语法结构,是编写 nftables 规则的基础。通过灵活组合匹配条件和动作,可以实现各种复杂的网络策略。

2.3.2 规则的添加、插入、替换、删除

规则的管理包括添加、插入、替换和删除操作。nft 命令行工具提供了丰富的命令来管理规则。

添加规则(Add Rule)

使用 nft add rule 命令在链的 末尾 添加规则。这是最常用的添加规则的方式。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 在 inet 表 filter 族的 input_chain 链末尾添加规则:允许 TCP 端口 80
2 nft add rule inet filter input_chain tcp dport 80 accept

插入规则(Insert Rule)

使用 nft insert rule 命令在链的 指定位置 插入规则。插入规则会影响后续规则的索引。

在链的开头插入规则:可以使用 position 0index 0 参数,或者更简洁地使用 nft insert rule ... position 0 ...

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 在 inet 表 filter 族的 input_chain 链的开头插入规则:允许 TCP 端口 22
2 nft insert rule inet filter input_chain position 0 tcp dport 22 accept

在指定规则之后插入规则:可以使用 position after handle <handle> 参数,其中 <handle> 是现有规则的句柄(handle)。规则句柄是 nftables 为每条规则分配的唯一标识符,可以使用 nft list chain ... -n 命令查看规则句柄。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 假设 input_chain 链中有一条规则的句柄为 5,在这条规则之后插入新规则
2 nft insert rule inet filter input_chain position after handle 5 udp dport 53 accept

替换规则(Replace Rule)

使用 nft replace rule 命令替换链中 指定位置 的规则。替换规则会保留规则的位置和句柄,但会用新的规则内容替换旧的规则。

替换指定句柄的规则:可以使用 handle <handle> 参数指定要替换的规则句柄。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 假设 input_chain 链中句柄为 7 的规则需要被替换
2 nft replace rule inet filter input_chain handle 7 tcp dport 8080 reject with tcp reset

▮▮▮▮注意reject with tcp reset 是一个更具体的 reject 动作,用于 TCP 连接,会发送 TCP RST 包。

替换链中特定位置的规则(不常用,通常使用句柄更精确):可以使用 position <index> 参数,但索引可能会因为规则的插入和删除而变化,不如使用句柄稳定。

删除规则(Delete Rule)

使用 nft delete rule 命令删除链中 指定位置 的规则。删除规则会影响后续规则的索引和句柄。

删除指定句柄的规则:可以使用 handle <handle> 参数指定要删除的规则句柄。这是最推荐的删除规则方式,因为它最精确。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 删除 inet 表 filter 族的 input_chain 链中句柄为 7 的规则
2 nft delete rule inet filter input_chain handle 7

删除链中特定位置的规则(不常用,通常使用句柄更精确):可以使用 position <index> 参数,但索引可能会因为规则的插入和删除而变化,不如使用句柄稳定。

查看规则句柄

在管理规则时,规则句柄非常重要。可以使用 nft list chain <family> <table> <chain> -n 命令查看链中的规则,并显示规则句柄。-n 参数表示以数字形式显示句柄。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft list chain inet filter input_chain -n

输出示例(显示规则句柄):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table inet filter {
2 chain input_chain { # handle 2
3 type filter hook input priority 0; policy accept;
4 rule handle 3 tcp dport 22 accept comment "Allow SSH"
5 rule handle 4 tcp dport 80 accept comment "Allow HTTP"
6 rule handle 5 tcp dport 443 accept comment "Allow HTTPS"
7 rule handle 6 drop comment "Default drop"
8 }
9 }

在输出中,rule handle 3 ...rule handle 4 ... 等行显示了每条规则的句柄(3, 4, 5, 6)。在替换或删除规则时,可以使用这些句柄来精确操作。

规则管理最佳实践

使用规则句柄:在替换和删除规则时,优先使用规则句柄,确保操作的精确性,避免因规则位置变化导致误操作。
添加规则注释:使用 comment "<注释内容>" 为规则添加注释,提高规则的可读性和可维护性。
备份规则集:在进行大规模规则修改之前,务必备份当前的 nftables 规则集,以便在出现问题时可以快速恢复。
测试规则:在生产环境应用规则之前,务必在测试环境中充分测试规则的有效性和正确性,避免规则错误导致网络故障。

掌握规则的添加、插入、替换和删除操作,以及规则句柄的使用,可以有效地管理 nftables 规则集,并进行灵活的规则更新和维护。

2.3.3 规则的匹配顺序与执行流程

理解 nftables 规则的匹配顺序和执行流程,对于构建正确的规则集至关重要。nftables 规则的匹配是 顺序执行 的,并且遵循 “first-match” 原则。

规则的匹配顺序

链内顺序执行:在一个链中,规则按照它们在链中出现的 顺序 依次进行匹配。从链顶部的第一条规则开始,逐条向下匹配,直到找到匹配的规则或者遍历完整个链。
“First-match” 原则:一旦数据包匹配了链中的 第一条 规则,nftables 就会执行该规则定义的动作,并且 停止 在当前链中继续匹配后续规则。即使后续规则也可能匹配该数据包,也不会被执行。
基链默认策略:如果数据包遍历完基链中的所有规则,仍然没有找到匹配的规则,那么会应用基链的 默认策略(policy)。默认策略可以是 acceptdrop,在创建基链时指定。
普通链返回:如果数据包遍历完普通链中的所有规则,仍然没有被明确处理(例如 acceptdropreturn),那么会 返回 到调用链的下一条规则继续执行。普通链没有默认策略。

规则执行流程

  1. 数据包进入 Hook 点:当网络数据包到达网络协议栈的某个 hook 点时,例如 inputforwardoutput 等,会进入与该 hook 点关联的基链。
  2. 从链顶开始匹配nftables 从基链的 第一条规则 开始,依次检查数据包是否满足该规则的 匹配条件
  3. 规则匹配成功:如果数据包满足当前规则的 所有匹配条件,则认为规则匹配成功。
    ▮▮▮▮⚝ 执行规则动作nftables 会立即执行该规则定义的 动作,例如 acceptdroprejectlogjump 等。
    ▮▮▮▮⚝ 停止链内匹配:执行完规则动作后,nftables 停止 在当前链中继续匹配后续规则。数据包的处理流程取决于执行的动作。
    ▮▮▮▮▮▮▮▮⚝ 如果动作是 acceptdropreject,则数据包的处理结束,根据动作结果进行相应的处理(接受、丢弃或拒绝)。
    ▮▮▮▮▮▮▮▮⚝ 如果动作是 jump <chain>goto <chain>,则数据包会跳转到目标链继续匹配规则。
    ▮▮▮▮▮▮▮▮⚝ 如果动作是 return,则数据包会返回到调用链的下一条规则继续执行,或者如果当前链是基链,则应用基链的默认策略。
  4. 规则匹配失败:如果数据包 不满足 当前规则的任何一个匹配条件,则认为规则匹配失败。
    ▮▮▮▮⚝ 继续匹配下一条规则nftables 会继续匹配当前链中的 下一条规则,重复步骤 3 和 4。
  5. 遍历完整个链:如果数据包遍历完整个链中的所有规则,仍然没有找到匹配的规则。
    ▮▮▮▮⚝ 基链默认策略:如果当前链是 基链,则应用基链的 默认策略(policy)。例如,如果基链的策略是 accept,则接受数据包;如果是 drop,则丢弃数据包。
    ▮▮▮▮⚝ 普通链返回:如果当前链是 普通链,则数据包会 返回 到调用链的下一条规则继续执行。

流程图示

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 数据包进入 Hook -> 进入基链 -> 规则 1 匹配?
2 ├── -> 执行规则 1 动作 -> 处理结束或跳转/goto/return
3 └── -> 规则 2 匹配?
4 ├── -> 执行规则 2 动作 -> 处理结束或跳转/goto/return
5 └── -> ... -> 规则 N 匹配?
6 ├── -> 执行规则 N 动作 -> 处理结束或跳转/goto/return
7 └── -> 遍历完整个链 -> 基链?
8 ├── -> 应用基链默认策略
9 └── (普通链) -> 返回到调用链

规则顺序的重要性

由于 nftables 遵循 “first-match” 原则,规则在链中的顺序非常重要。规则的顺序直接影响了数据包的处理结果。

更具体的规则在前:通常,应该将 更具体 的规则放在 更通用 的规则之前。例如,允许特定 IP 地址的规则应该放在默认拒绝所有 IP 地址的规则之前。
例外规则在前:对于需要特殊处理的例外情况,应该将例外规则放在通用规则之前。例如,允许特定端口的规则应该放在默认阻止所有端口的规则之前。
默认拒绝策略:在防火墙配置中,通常采用 默认拒绝策略,即在链的末尾添加一条 drop 规则,作为默认的拒绝规则。所有没有被前面规则明确允许的流量都会被这条默认规则拒绝。

示例:规则顺序的影响

假设有以下两条规则,顺序不同,效果也不同:

顺序 1:

  1. nft add rule inet filter input_chain tcp dport 80 accept (允许 TCP 端口 80)
  2. nft add rule inet filter input_chain tcp accept (允许所有 TCP 流量)

在这种顺序下,所有 TCP 流量都会被 规则 1 匹配并接受,因为规则 1 比规则 2 更具体(只匹配端口 80)。规则 2 永远不会被执行,因为所有 TCP 流量已经被规则 1 处理了。

顺序 2:

  1. nft add rule inet filter input_chain tcp accept (允许所有 TCP 流量)
  2. nft add rule inet filter input_chain tcp dport 80 accept (允许 TCP 端口 80)

在这种顺序下,规则 1 会匹配所有 TCP 流量,并接受它们。规则 2 永远不会被执行,因为所有 TCP 流量已经被规则 1 处理了。

正确的顺序应该是:

  1. nft add rule inet filter input_chain tcp dport 80 accept (允许 TCP 端口 80)
  2. nft add rule inet filter input_chain tcp drop (默认拒绝所有 TCP 流量)

或者使用更通用的默认拒绝策略:

  1. nft add rule inet filter input_chain tcp dport 80 accept (允许 TCP 端口 80)
  2. nft add rule inet filter input_chain drop (默认拒绝所有流量)

在这种正确的顺序下,端口 80 的 TCP 流量会被规则 1 接受,而其他所有流量(包括非端口 80 的 TCP 流量)会因为没有匹配规则 1,而继续匹配到链末尾的默认 drop 规则,从而被拒绝。

理解规则的匹配顺序和执行流程,并根据 “first-match” 原则合理安排规则的顺序,是构建正确、高效的 nftables 规则集的关键。

2.4 常用匹配条件详解

匹配条件(Match Criteria)nftables 规则的核心组成部分,用于定义规则要匹配的数据包特征。nftables 提供了丰富的匹配条件,可以基于数据包的协议、地址、端口、接口、连接状态等多种属性进行匹配。

2.4.1 协议匹配:ip protocoltcpudpicmp

协议匹配 是最基本的匹配条件之一,用于根据数据包的 网络协议 类型进行匹配。nftables 支持多种协议匹配方式。

ip protocol <protocol>IP 协议匹配。用于匹配 IP 头部中的 协议字段<protocol> 可以是协议名称(例如 tcpudpicmp)或协议号(例如 TCP 的协议号是 6,UDP 的协议号是 17,ICMP 的协议号是 1)。

匹配 TCP 协议

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 匹配 TCP 协议的数据包
2 ip protocol tcp

匹配 UDP 协议

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 匹配 UDP 协议的数据包
2 ip protocol udp

匹配 ICMP 协议

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 匹配 ICMP 协议的数据包
2 ip protocol icmp

匹配协议号为 6 的协议 (TCP)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 使用协议号匹配 TCP
2 ip protocol 6

tcpudpicmp协议关键字匹配nftables 提供了更简洁的协议关键字,可以直接用于匹配 TCP、UDP 和 ICMP 协议。这些关键字实际上是 ip protocol 匹配的简写形式。

匹配 TCP 协议

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 匹配 TCP 协议的数据包 (与 ip protocol tcp 等效)
2 tcp

匹配 UDP 协议

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 匹配 UDP 协议的数据包 (与 ip protocol udp 等效)
2 udp

匹配 ICMP 协议

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 匹配 ICMP 协议的数据包 (与 ip protocol icmp 等效)
2 icmp

协议匹配应用示例

允许 SSH (TCP 端口 22)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 允许 TCP 协议,目标端口为 22 的连接
2 nft add rule inet filter input_chain tcp dport 22 accept

允许 DNS (UDP 端口 53)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 允许 UDP 协议,目标端口为 53 的连接
2 nft add rule inet filter input_chain udp dport 53 accept

阻止所有 ICMP 流量 (Ping)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 阻止所有 ICMP 协议的数据包
2 nft add rule inet filter forward_chain icmp drop

允许特定类型的 ICMP 消息 (例如 ICMP Echo Request)

▮▮▮▮可以使用更细粒度的 ICMP 消息类型匹配,例如 icmp type echo-request

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 允许 ICMP Echo Request (Ping 请求)
2 nft add rule inet filter input_chain icmp type echo-request accept

协议匹配的灵活性

nftables 的协议匹配非常灵活,可以根据协议名称或协议号进行匹配,也可以使用简洁的协议关键字。在 inet 表中,协议匹配可以同时应用于 IPv4 和 IPv6 流量。在 ip 表中,协议匹配只应用于 IPv4 流量;在 ip6 表中,协议匹配只应用于 IPv6 流量。

2.4.2 地址匹配:ip saddrip daddrip6 saddrip6 daddr

地址匹配 用于根据数据包的 源 IP 地址目标 IP 地址 进行匹配。nftables 区分 IPv4 和 IPv6 地址匹配。

ip saddr <address>IPv4 源地址匹配。用于匹配 IPv4 数据包的 源 IP 地址<address> 可以是单个 IPv4 地址、IPv4 地址范围(例如 192.168.1.100-192.168.1.200)或 IPv4 CIDR 网络(例如 192.168.1.0/24)。

匹配源 IP 地址为 192.168.1.100 的 IPv4 数据包

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ip saddr 192.168.1.100

匹配源 IP 地址在 192.168.1.100 到 192.168.1.200 范围内的 IPv4 数据包

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ip saddr 192.168.1.100-192.168.1.200

匹配源 IP 地址在 192.168.1.0/24 网络内的 IPv4 数据包

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ip saddr 192.168.1.0/24

ip daddr <address>IPv4 目标地址匹配。用于匹配 IPv4 数据包的 目标 IP 地址<address> 的格式与 ip saddr 相同。

匹配目标 IP 地址为 10.0.0.10 的 IPv4 数据包

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ip daddr 10.0.0.10

匹配目标 IP 地址在 10.0.0.0/24 网络内的 IPv4 数据包

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ip daddr 10.0.0.0/24

ip6 saddr <address>IPv6 源地址匹配。用于匹配 IPv6 数据包的 源 IPv6 地址<address> 可以是单个 IPv6 地址、IPv6 地址范围或 IPv6 CIDR 网络。

匹配源 IPv6 地址为 2001:db8::1 的 IPv6 数据包

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ip6 saddr 2001:db8::1

匹配源 IPv6 地址在 2001:db8::/32 网络内的 IPv6 数据包

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ip6 saddr 2001:db8::/32

ip6 daddr <address>IPv6 目标地址匹配。用于匹配 IPv6 数据包的 目标 IPv6 地址<address> 的格式与 ip6 saddr 相同。

匹配目标 IPv6 地址为 2001:db8:1::2 的 IPv6 数据包

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ip6 daddr 2001:db8:1::2

地址匹配应用示例

允许来自特定 IP 地址的 SSH 访问

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 允许来自 192.168.1.100 的 SSH 访问
2 nft add rule inet filter input_chain tcp saddr 192.168.1.100 dport 22 accept

阻止来自整个网络的访问

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 阻止来自 10.0.0.0/8 网络的所有 IPv4 流量
2 nft add rule ip filter forward_chain ip saddr 10.0.0.0/8 drop

只允许来自本地网络的访问

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 只允许来自 192.168.1.0/24 本地网络的入站 HTTP 和 HTTPS 访问
2 nft add rule inet filter input_chain ip saddr 192.168.1.0/24 tcp dport { 80, 443 } accept

阻止来自特定 IPv6 网络的访问

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 阻止来自 2001:db8:2::/48 IPv6 网络的所有流量
2 nft add rule ip6 filter forward_chain ip6 saddr 2001:db8:2::/48 drop

地址匹配的灵活性

nftables 的地址匹配非常灵活,支持单个地址、地址范围和 CIDR 网络匹配。可以根据源地址或目标地址进行匹配,区分 IPv4 和 IPv6 地址。地址匹配可以与其他匹配条件组合使用,构建更精细的规则。

2.4.3 端口匹配:tcp sporttcp dportudp sportudp dport

端口匹配 用于根据 TCP 或 UDP 协议的 源端口目标端口 进行匹配。端口匹配只适用于 TCP 和 UDP 协议。

tcp sport <port>TCP 源端口匹配。用于匹配 TCP 数据包的 源端口<port> 可以是单个端口号、端口范围(例如 1024-65535)或端口列表(例如 { 22, 80, 443 })。

匹配源端口为 1024 的 TCP 数据包

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 tcp sport 1024

匹配源端口在 1024 到 65535 范围内的 TCP 数据包 (动态端口范围)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 tcp sport 1024-65535

匹配源端口为 22、80 或 443 的 TCP 数据包

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 tcp sport { 22, 80, 443 }

tcp dport <port>TCP 目标端口匹配。用于匹配 TCP 数据包的 目标端口<port> 的格式与 tcp sport 相同。

匹配目标端口为 80 的 TCP 数据包 (HTTP)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 tcp dport 80

匹配目标端口在 1-1023 范围内的 TCP 数据包 (知名端口范围)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 tcp dport 1-1023

匹配目标端口为 21 (FTP 控制端口) 的 TCP 数据包

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 tcp dport 21

udp sport <port>UDP 源端口匹配。用于匹配 UDP 数据包的 源端口<port> 的格式与 tcp sport 相同。

匹配源端口为 53 的 UDP 数据包 (DNS 查询)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 udp sport 53

udp dport <port>UDP 目标端口匹配。用于匹配 UDP 数据包的 目标端口<port> 的格式与 udp sport 相同。

匹配目标端口为 53 的 UDP 数据包 (DNS 应答)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 udp dport 53

匹配目标端口在 67 和 68 范围内的 UDP 数据包 (DHCP)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 udp dport { 67, 68 }

端口匹配应用示例

允许入站 HTTP 和 HTTPS 访问

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 允许目标端口为 80 (HTTP) 或 443 (HTTPS) 的 TCP 连接
2 nft add rule inet filter input_chain tcp dport { 80, 443 } accept

允许出站 DNS 查询

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 允许源端口为 53 (DNS) 的 UDP 出站连接
2 nft add rule inet filter output_chain udp sport 53 accept

阻止所有入站 Telnet (TCP 端口 23) 访问

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 阻止目标端口为 23 (Telnet) 的 TCP 连接
2 nft add rule inet filter input_chain tcp dport 23 drop

允许来自特定源端口范围的连接

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 允许来自源端口范围 49152-65535 (私有端口范围) 的 TCP 连接
2 nft add rule inet filter input_chain tcp sport 49152-65535 accept

端口匹配的灵活性

nftables 的端口匹配非常灵活,支持单个端口、端口范围和端口列表匹配。可以根据源端口或目标端口进行匹配,区分 TCP 和 UDP 协议。端口匹配通常与协议匹配和地址匹配组合使用,构建更精细的规则。

2.4.4 接口匹配:iifnameoifnameiifoif

接口匹配 用于根据数据包的 网络接口 进行匹配。nftables 区分接口名称匹配和接口索引匹配,以及输入接口和输出接口匹配。

iifname <interface_name>输入接口名称匹配。用于匹配数据包 进入 的网络接口的 名称<interface_name> 是网络接口的名称,例如 eth0wlan0ppp0 等。

匹配从 eth0 接口进入的数据包

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 iifname "eth0"

匹配从 wlan0 或 eth1 接口进入的数据包

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 iifname { "wlan0", "eth1" }

oifname <interface_name>输出接口名称匹配。用于匹配数据包 离开 的网络接口的 名称<interface_name> 的格式与 iifname 相同。

匹配从 eth0 接口输出的数据包

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 oifname "eth0"

匹配从 ppp0 接口输出的数据包 (例如 PPPoE 连接)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 oifname "ppp0"

iif <interface_index>输入接口索引匹配。用于匹配数据包 进入 的网络接口的 索引<interface_index> 是网络接口的数字索引。接口索引通常在系统启动时分配,可以使用 ip link show 命令查看接口索引。

匹配从索引为 2 的接口进入的数据包

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 iif 2

oif <interface_index>输出接口索引匹配。用于匹配数据包 离开 的网络接口的 索引<interface_index> 的格式与 iif 相同。

匹配从索引为 3 的接口输出的数据包

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 oif 3

接口匹配应用示例

只允许从 eth0 接口进入的 SSH 访问

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 只允许从 eth0 接口进入的 SSH 连接
2 nft add rule inet filter input_chain iifname "eth0" tcp dport 22 accept

阻止从 wlan0 接口转发流量

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 阻止从 wlan0 接口转发的所有流量 (例如,阻止无线网络共享)
2 nft add rule inet filter forward_chain iifname "wlan0" drop

对从 ppp0 接口输出的流量进行 SNAT

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 对从 ppp0 接口输出的所有流量进行 SNAT (伪装)
2 nft add rule inet nat postrouting_chain oifname "ppp0" masquerade

基于接口索引匹配 (不常用,接口名称更直观):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 匹配从索引为 2 的接口进入的数据包
2 nft add rule inet filter input_chain iif 2 tcp dport 80 accept

接口匹配的灵活性

nftables 的接口匹配支持接口名称和接口索引两种方式,可以根据输入接口或输出接口进行匹配。接口名称匹配更直观易懂,接口索引匹配在某些底层场景下可能更高效。接口匹配常用于区分不同网络接口的流量,例如区分内网接口和外网接口、有线接口和无线接口等。

2.4.5 连接状态匹配:ct state

连接状态匹配(Connection Tracking State Match) 基于 Netfilter连接追踪(Connection Tracking, conntrack) 功能。连接追踪可以跟踪网络连接的状态,nftables 可以根据连接状态进行匹配,实现 有状态防火墙 的功能。

ct state 匹配条件用于匹配连接的当前状态。常见的连接状态包括:

new新的连接。表示连接的第一个数据包,通常是 TCP 连接的 SYN 包,或者是 UDP 或 ICMP 连接的第一个数据包。

established已建立的连接。表示连接已经成功建立,对于 TCP 连接,表示已经完成三次握手;对于 UDP 或 ICMP 连接,表示已经有双向的数据包交换。

related相关连接。表示与已建立连接相关的连接。例如,FTP 数据连接与 FTP 控制连接相关,ICMP 错误消息与原始连接相关。

invalid无效的连接。表示连接状态异常,例如 TCP 状态错误、数据包不符合协议规范等。

untracked未追踪的连接。表示连接没有被连接追踪模块跟踪。通常用于显式排除某些流量不进行连接追踪。

ct state 匹配语法

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ct state

<state1,state2,...> 是要匹配的连接状态列表,可以使用逗号分隔多个状态。

匹配新的连接

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ct state new

匹配已建立的连接

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ct state established

匹配已建立的连接和相关连接 (常用组合,允许已建立连接和相关连接的流量):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ct state established,related

匹配无效的连接

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ct state invalid

匹配新的或已建立的连接

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ct state { new, established }

连接状态匹配应用示例

允许已建立的和相关的连接 (构建有状态防火墙的基础):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 允许已建立的和相关的连接 (通常放在 input, forward, output 链的开头)
2 nft add rule inet filter input_chain ct state established,related accept
3 nft add rule inet filter forward_chain ct state established,related accept
4 nft add rule inet filter output_chain ct state established,related accept

只允许新的入站连接 (例如,只允许新的入站 TCP SYN 包):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 只允许新的入站 TCP 连接 (SYN 包)
2 nft add rule inet filter input_chain ct state new tcp flags syn accept

阻止无效的连接 (增强安全性):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 阻止无效的连接
2 nft add rule inet filter input_chain ct state invalid drop
3 nft add rule inet filter forward_chain ct state invalid drop
4 nft add rule inet filter output_chain ct state invalid drop

允许与已建立连接相关的 FTP 数据连接 (需要连接追踪模块正确识别 FTP 相关连接):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 允许与已建立连接相关的 FTP 数据连接
2 nft add rule inet filter forward_chain ct state related tcp dport 20:21 accept

连接状态匹配的优势

有状态防火墙:连接状态匹配是构建有状态防火墙的核心技术。有状态防火墙可以根据连接状态动态地允许或阻止流量,提供更精细的安全控制。
简化规则:使用连接状态匹配可以简化规则集。例如,只需要允许新的出站连接和已建立的入站连接,就可以实现基本的双向通信,而无需为每个方向都配置复杂的规则。
提高安全性:有状态防火墙可以有效防御基于连接状态的攻击,例如 SYN Flood 攻击、连接劫持等。

连接追踪的依赖

连接状态匹配依赖于 Netfilter 的连接追踪模块。要使用 ct state 匹配条件,需要确保系统内核启用了连接追踪功能,并且相关的连接追踪模块已经加载。通常,Linux 系统默认会启用连接追踪。

2.5 常用动作详解

动作(Actions/Targets) 定义了当数据包满足规则的匹配条件时,nftables 要执行的操作。nftables 提供了丰富的动作,可以实现数据包的接受、丢弃、拒绝、日志记录、排队、跳转等多种处理方式。

2.5.1 acceptdropreject

acceptdropreject 是最基本的也是最常用的动作,用于控制数据包的 命运

accept接受 动作。

作用:允许数据包通过,数据包会继续在网络协议栈中流动,最终到达目标。
效果
▮▮▮▮⚝ 对于 filter 链,accept 表示允许数据包通过防火墙。
▮▮▮▮⚝ 对于 nat 链,accept 通常不直接使用,NAT 链主要使用 snatdnatmasquerade 等 NAT 动作。
▮▮▮▮⚝ 对于 route 链,accept 表示接受当前的路由决策。
使用场景
▮▮▮▮⚝ 允许特定类型的流量通过防火墙。
▮▮▮▮⚝ 在 NAT 规则中,作为默认策略,允许已建立连接的返回流量。

示例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 允许 TCP 端口 80 的入站连接
2 nft add rule inet filter input_chain tcp dport 80 accept
3
4 # 允许已建立的连接
5 nft add rule inet filter input_chain ct state established accept

drop丢弃 动作。

作用:丢弃数据包,阻止数据包继续在网络协议栈中流动。数据包会被 静默丢弃,不会给发送方任何通知。
效果
▮▮▮▮⚝ 对于 filter 链,drop 表示阻止数据包通过防火墙。
▮▮▮▮⚝ 对于 nat 链,drop 表示丢弃数据包,阻止 NAT 转换。
▮▮▮▮⚝ 对于 route 链,drop 表示阻止数据包的路由。
使用场景
▮▮▮▮⚝ 阻止非法或不需要的流量通过防火墙。
▮▮▮▮⚝ 实现默认拒绝策略,丢弃所有未明确允许的流量。
▮▮▮▮⚝ 防御某些类型的网络攻击,例如 DDoS 攻击。

示例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 阻止来自特定 IP 地址的流量
2 nft add rule ip filter forward_chain ip saddr 192.168.1.100 drop
3
4 # 默认拒绝所有入站流量 (通常作为 input 链的最后一条规则)
5 nft add rule inet filter input_chain drop

reject拒绝 动作。

作用:丢弃数据包,并向发送方发送一个 拒绝通知。拒绝通知的类型取决于协议。
效果
▮▮▮▮⚝ 对于 TCP 协议,reject 会发送一个 TCP RST (Reset) 包,显式地拒绝连接。
▮▮▮▮⚝ 对于 UDP 协议,reject 会发送一个 ICMP port-unreachable 消息,通知目标端口不可达。
▮▮▮▮⚝ 对于其他协议,reject 可能会发送其他类型的 ICMP 错误消息。
▮▮▮▮⚝ 对于 filter 链,reject 表示拒绝数据包通过防火墙,并通知发送方。
▮▮▮▮⚝ 对于 nat 链,reject 表示拒绝数据包,并发送拒绝通知。
▮▮▮▮⚝ 对于 route 链,reject 表示拒绝数据包的路由,并发送拒绝通知。
使用场景
▮▮▮▮⚝ 显式拒绝某些类型的连接请求,并告知发送方拒绝原因。
▮▮▮▮⚝ 在某些情况下,rejectdrop 更友好,可以帮助发送方更快地知道连接被拒绝,而不是一直等待超时。
▮▮▮▮⚝ 但 reject 也可能暴露更多的网络信息,在某些安全敏感场景下,drop 可能更安全。

reject 的变体

▮▮▮▮⚝ reject with tcp reset:对于 TCP 协议,发送 TCP RST 包。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 拒绝 TCP 端口 23 (Telnet) 的入站连接,并发送 TCP RST
2 nft add rule inet filter input_chain tcp dport 23 reject with tcp reset

▮▮▮▮⚝ reject with icmp type port-unreachable:对于 UDP 和其他协议,发送 ICMP port-unreachable 消息 (默认的 reject 行为)。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 拒绝 UDP 端口 135 (RPC) 的入站连接,并发送 ICMP port-unreachable
2 nft add rule inet filter input_chain udp dport 135 reject with icmp type port-unreachable

▮▮▮▮⚝ reject with icmp type host-unreachable:发送 ICMP host-unreachable 消息。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 拒绝目标主机不可达
2 nft add rule inet filter output_chain ip daddr 192.0.2.1 reject with icmp type host-unreachable

acceptdropreject 的选择

accept:明确允许的流量。
drop:静默丢弃,不通知发送方,更隐蔽,安全性更高,但可能导致连接超时等待。
reject:拒绝并通知发送方,更友好,但可能暴露更多网络信息,安全性稍低。

在防火墙配置中,通常使用 accept 允许需要的流量,使用 drop 阻止不需要的流量,并在某些需要显式拒绝的场景下使用 reject。默认策略通常设置为 drop,实现最小权限原则。

2.5.2 log:日志记录

log 动作用于 记录 匹配规则的数据包信息。日志记录对于网络安全审计、故障排查和流量监控非常重要。

作用:将匹配规则的数据包信息记录到系统日志中。
效果:数据包在被记录日志后,会 继续 按照规则链的后续规则或默认策略进行处理。log 动作本身 不影响 数据包的转发或丢弃。
日志信息log 动作可以记录数据包的源地址、目标地址、协议、端口、接口等信息,以及规则的句柄、链名等信息。
日志级别log 动作可以使用不同的日志级别,例如 infowarndebug 等,控制日志的详细程度。
日志前缀:可以使用 prefix 参数为日志消息添加自定义前缀,方便日志过滤和分析。
日志选项log 动作还支持其他选项,例如 tcp-optionsip-optionsuidgroup 等,用于记录更详细的数据包信息。

log 动作语法

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 log [flags ] [level ] [prefix ""] [options ]

flags <flags>:日志标志,例如 tcp-optionsip-optionsuidgroup 等。
level <level>:日志级别,例如 emergalertcriterrorwarnnoticeinfodebugtrace。默认为 notice
prefix "<prefix_text>":日志消息前缀,自定义的字符串,方便日志过滤。
options <log_options>:其他日志选项,例如 queue-threshold <threshold>queue-limit <limit> 等 (不常用)。

log 动作应用示例

记录所有被拒绝的入站连接尝试

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 记录所有被 input_chain 链默认 drop 规则拒绝的连接尝试
2 nft add rule inet filter input_chain drop log prefix "Input Drop: " level info

▮▮▮▮这条规则会在系统日志中记录所有被 input_chain 链的 drop 规则匹配的数据包,日志消息会带有 "Input Drop: " 前缀,日志级别为 info

记录新的 TCP 连接尝试,并包含 TCP 选项和 IP 选项

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 记录新的 TCP 连接尝试,包含 TCP 选项和 IP 选项
2 nft add rule inet filter input_chain ct state new tcp flags syn log flags tcp-options,ip-options prefix "New TCP SYN: " level debug

▮▮▮▮这条规则会记录所有新的 TCP SYN 包,日志消息会包含 TCP 选项和 IP 选项,前缀为 "New TCP SYN: ",日志级别为 debug

记录特定源 IP 地址的流量

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 记录来自 192.168.1.100 的所有流量
2 nft add rule ip filter forward_chain ip saddr 192.168.1.100 log prefix "Source IP 192.168.1.100: " level warn

log 动作的注意事项

性能影响log 动作会增加系统开销,特别是对于高流量的网络环境。过多的日志记录可能会影响性能。应该只在必要的规则上添加 log 动作,并控制日志级别和日志量。
日志管理:日志文件会不断增长,需要定期进行日志轮转和清理,避免磁盘空间被日志占满。可以使用 logrotate 等工具进行日志管理。
安全风险:日志文件中可能包含敏感信息,例如 IP 地址、端口号、应用协议等。需要妥善保管日志文件,防止泄露。

log 动作是 nftables 中非常有用的功能,可以帮助用户监控网络流量、排查网络故障、进行安全审计。合理使用 log 动作,可以提高网络管理和安全运维的效率。

2.5.3 queue:数据包排队

queue 动作用于将匹配规则的数据包 排队用户空间 的应用程序进行处理。queue 动作是 Netfilter 框架与用户空间程序交互的重要机制,可以实现更高级的数据包处理功能,例如入侵检测系统(IDS)、流量分析、应用层过滤等。

作用:将匹配规则的数据包复制一份,并排队到用户空间的 NFQUEUENFLOG 队列。用户空间程序可以从队列中接收数据包,进行自定义处理,然后决定是否将数据包放回内核协议栈继续处理(例如 NFQUEUE),或者仅用于日志记录和分析(例如 NFLOG)。
效果:数据包会被排队到用户空间,等待用户空间程序处理。数据包在内核协议栈中的处理流程取决于用户空间程序的处理结果。
队列类型queue 动作可以指定不同的队列类型,例如 num <queue_number> (NFQUEUE 队列号)、to <nfnl_group> (NFLOG 组号) 等。
队列参数queue 动作还支持其他参数,例如 bypass (当用户空间程序没有响应时,是否绕过队列,让数据包继续处理)、queue-balance <cpu_range> (在多核 CPU 上进行队列负载均衡) 等。

queue 动作语法

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 queue [num <queue_number>] [to <nfnl_group>] [bypass] [queue-balance <cpu_range>]

num <queue_number>:指定 NFQUEUE 队列号,范围 0-65535。默认为 0。
to <nfnl_group>:指定 NFLOG 组号,范围 1-32。
bypass:当用户空间程序没有响应时,是否绕过队列,让数据包继续处理。默认为不绕过,即等待用户空间程序响应。
queue-balance <cpu_range>:在多核 CPU 上进行队列负载均衡,<cpu_range> 是 CPU 核心范围,例如 0-3 表示 CPU 0 到 CPU 3。

queue 动作应用示例

使用 NFQUEUE 将数据包排队到用户空间程序进行处理

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 将所有入站 TCP 端口 80 的数据包排队到 NFQUEUE 队列 0
2 nft add rule inet filter input_chain tcp dport 80 queue num 0

▮▮▮▮用户空间程序需要监听 NFQUEUE 队列 0,接收排队的数据包,进行处理,并决定是否将数据包放回内核协议栈。

使用 NFLOG 将数据包排队到用户空间程序进行日志记录和分析

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 将所有被拒绝的入站连接尝试排队到 NFLOG 组 1 进行日志记录
2 nft add rule inet filter input_chain drop log prefix "Input Drop: " level info queue to 1

▮▮▮▮用户空间程序需要监听 NFLOG 组 1,接收排队的数据包,进行日志记录和分析。NFLOG 通常用于被动监控,不影响数据包的内核处理流程。

使用 bypass 参数,当用户空间程序没有响应时,绕过队列

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 将入站 TCP 端口 80 的数据包排队到 NFQUEUE 队列 0,如果用户空间程序没有响应,则绕过队列,让数据包继续处理
2 nft add rule inet filter input_chain tcp dport 80 queue num 0 bypass

使用 queue-balance 参数,在多核 CPU 上进行队列负载均衡

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 将入站 TCP 端口 80 的数据包排队到 NFQUEUE 队列 0,并在 CPU 0-3 上进行负载均衡
2 nft add rule inet filter input_chain tcp dport 80 queue num 0 queue-balance 0-3

queue 动作的注意事项

用户空间程序queue 动作需要与用户空间程序配合使用。用户空间程序负责从队列中接收数据包,进行处理,并根据需要将数据包放回内核协议栈(对于 NFQUEUE)。
性能影响queue 动作会增加系统开销,特别是对于高流量的网络环境。数据包需要在内核空间和用户空间之间复制和传递,会消耗 CPU 和内存资源。
延迟:数据包排队到用户空间处理会引入延迟。对于实时性要求高的应用,应谨慎使用 queue 动作。
安全风险:用户空间程序需要谨慎编写,避免安全漏洞。用户空间程序可以修改数据包内容,甚至可以伪造数据包,需要进行严格的安全审计和测试。

queue 动作是 nftables 的高级功能,可以实现灵活的数据包处理和用户空间扩展。在构建高级网络安全设备、流量分析系统、应用层防火墙等场景下,queue 动作非常有用。

2.5.4 gotojumpreturn:链跳转与返回

gotojumpreturn 是用于 链跳转返回 的动作,可以实现规则链的模块化和流程控制。通过链跳转和返回,可以将复杂的规则集分解为多个小的、易于管理的链,提高规则的可读性和可维护性。

goto <chain>无条件跳转 到指定的链。

作用:立即跳转到指定的 普通链 <chain>,开始在目标链中匹配规则。
效果:数据包的处理流程会 立即转移 到目标链。当前链中 goto 动作之后的规则 不再执行。目标链执行完毕后,数据包 不会返回 到原始链。
目标链类型goto 动作只能跳转到 普通链,不能跳转到基链。
使用场景
▮▮▮▮⚝ 将数据包的处理流程完全转移到另一个链。
▮▮▮▮⚝ 实现规则的条件分支,根据匹配条件选择不同的处理链。
▮▮▮▮⚝ 构建规则处理流程的 “子程序”,但执行完子程序后不返回。

示例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 在 input_chain 链中,如果源 IP 地址是 192.168.1.100,则跳转到 special_rules 链处理
2 nft add rule inet filter input_chain ip saddr 192.168.1.100 goto special_rules
3
4 # 创建 special_rules 普通链,用于处理来自 192.168.1.100 的流量
5 nft add chain inet filter special_rules
6 # 在 special_rules 链中添加具体规则
7 nft add rule inet filter special_rules tcp dport 22 accept comment "Allow SSH from 192.168.1.100"
8 nft add rule inet filter special_rules log prefix "Special Rule Match: " level info
9 nft add rule inet filter special_rules return # 执行完 special_rules 链后返回

▮▮▮▮当数据包源 IP 地址为 192.168.1.100 时,会跳转到 special_rules 链处理。input_chain 链中 goto 规则之后的规则将不再执行。special_rules 链执行完毕后,通过 return 动作返回到 input_chain 链(实际上是返回到 input_chain 链的调用者的下一条规则,但由于 input_chain 是基链,所以相当于处理结束)。

jump <chain>子程序调用式跳转 到指定的链。

作用:跳转到指定的 普通链 <chain>,开始在目标链中匹配规则。
效果:数据包的处理流程会转移到目标链。当前链中 jump 动作之后的规则 仍然可能执行。目标链执行完毕后,数据包会 返回 到原始链,继续执行 jump 动作之后的规则。
目标链类型jump 动作只能跳转到 普通链,不能跳转到基链。
使用场景
▮▮▮▮⚝ 将一组通用的规则提取到单独的链中,并在多个链中复用。
▮▮▮▮⚝ 实现规则的模块化,将复杂的规则集分解为多个小的功能模块。
▮▮▮▮⚝ 构建规则处理流程的 “子程序”,执行完子程序后返回。

示例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建 common_rules 普通链,用于存放通用的规则
2 nft add chain inet filter common_rules
3 # 在 common_rules 链中添加通用规则,例如允许已建立连接
4 nft add rule inet filter common_rules ct state established,related accept
5 nft add rule inet filter common_rules return # 执行完 common_rules 链后返回
6
7 # 在 input_chain 链中,首先 jump 到 common_rules 链处理通用规则
8 nft add rule inet filter input_chain jump common_rules
9
10 # input_chain 链中继续添加其他规则,例如允许 SSH
11 nft add rule inet filter input_chain tcp dport 22 accept
12 nft add rule inet filter input_chain drop # 默认拒绝

▮▮▮▮数据包首先会 jumpcommon_rules 链处理通用规则(例如允许已建立连接)。common_rules 链执行完毕后,通过 return 动作返回到 input_chain 链,继续执行 jump 动作之后的规则(例如允许 SSH,默认拒绝)。

return返回 动作。

作用:从当前链 返回 到调用链的下一条规则,或者如果当前链是基链,则应用基链的默认策略。
效果
▮▮▮▮⚝ 如果在 普通链 中执行 return 动作,则数据包的处理流程会 返回调用链(即跳转到当前链的链)中 jumpgoto 动作之后的 下一条规则 继续执行。
▮▮▮▮⚝ 如果在 基链 中执行 return 动作,或者数据包遍历完基链中的所有规则后没有匹配任何规则,则会应用基链的 默认策略(policy)
使用场景
▮▮▮▮⚝ 在普通链中,表示当前链的处理结束,返回到调用链继续处理。
▮▮▮▮⚝ 在普通链中,作为链的默认动作,如果规则没有明确处理数据包,则返回到调用链。
▮▮▮▮⚝ 在基链中,显式应用基链的默认策略。

示例

▮▮▮▮⚝ 在普通链中使用 return 返回 (如上面的 common_rulesspecial_rules 示例)。
▮▮▮▮⚝ 在基链中使用 return 应用默认策略 (不常用,基链通常使用默认策略,不需要显式 return)。

gotojumpreturn 的区别与选择

动作目标链类型执行完目标链后是否返回当前链后续规则是否执行主要用途
goto普通链不返回不执行完全转移处理流程,条件分支,不返回的 “子程序”
jump普通链返回可能执行规则复用,模块化,子程序调用,返回的 “子程序”
return返回/应用默认策略取决于链类型普通链返回,基链应用默认策略

选择 goto 还是 jump
▮▮▮▮⚝ 如果需要将数据包的处理流程完全转移到另一个链,并且不需要返回,使用 goto
▮▮▮▮⚝ 如果需要调用另一个链处理一组规则,并在目标链处理完后返回到原始链继续处理,使用 jump
return 的作用
▮▮▮▮⚝ 在普通链中,return 用于返回到调用链,实现链的嵌套调用。
▮▮▮▮⚝ 在基链中,return 用于应用默认策略,但通常基链的默认策略会自动应用,不需要显式 return

合理使用 gotojumpreturn 动作,可以构建模块化、可复用、易于管理的 nftables 规则集,提高规则的组织性和效率。

ENDOF_CHAPTER_

3. chapter 3: nftables 核心概念:集合(Sets)与映射(Maps)

3.1 集合(Sets)详解

3.1.1 集合的优势与应用场景

集合(Sets)是 nftables 中最强大的功能之一,它允许将多个元素组合成一个逻辑单元,并在规则中引用这个单元。可以将集合视为一个容器,里面存放着一组具有相同类型的数据,例如 IP 地址、端口号、MAC 地址等。使用集合的主要优势在于规则的简化性能的提升

规则简化
当需要对多个目标(例如,多个 IP 地址或端口)应用相同的规则时,如果不使用集合,则需要为每个目标编写一条规则,这会导致规则集变得冗长且难以管理。而使用集合,只需创建一个包含所有目标的集合,然后在一条规则中引用这个集合即可。这大大减少了规则的数量,提高了规则集的可读性和可维护性。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 不使用集合需要多条规则
2 nft add rule inet filter input ip saddr 192.168.1.1 tcp dport 22 accept
3 nft add rule inet filter input ip saddr 192.168.1.2 tcp dport 22 accept
4 nft add rule inet filter input ip saddr 192.168.1.3 tcp dport 22 accept
5
6 # 使用集合只需要一条规则
7 nft add set inet filter allowed_ssh_hosts { type ipv4_addr; flags interval; }
8 nft add element inet filter allowed_ssh_hosts { 192.168.1.1, 192.168.1.2, 192.168.1.3 }
9 nft add rule inet filter input ip saddr @allowed_ssh_hosts tcp dport 22 accept

性能提升
nftables 在处理集合匹配时,使用了优化的数据结构和算法,例如哈希表和区间树等,这使得在大型规则集中进行集合匹配的效率非常高。相比于线性扫描多条独立规则,使用集合可以显著减少规则的匹配时间,从而提升整体的网络性能。尤其是在处理包含大量 IP 地址或端口的场景下,集合的性能优势更加明显。

动态更新
集合的内容可以动态更新,无需修改和重新加载规则。这意味着可以在运行时添加、删除或修改集合中的元素,规则会自动应用更新后的集合内容。这为动态策略管理和自动化运维提供了便利。例如,可以使用脚本定期更新包含恶意 IP 地址的集合,从而实现动态的黑名单功能。

应用场景

防火墙白名单/黑名单
▮▮▮▮使用 IP 地址集合或网络地址集合来定义允许或拒绝访问的 IP 列表。例如,创建一个白名单集合,只允许来自白名单 IP 的流量访问特定服务;或者创建一个黑名单集合,阻止来自黑名单 IP 的恶意流量。

端口范围管理
▮▮▮▮使用端口集合来管理允许或拒绝的服务端口范围。例如,创建一个端口集合,包含常用的 Web 服务端口(80, 443, 8080 等),然后使用一条规则允许或拒绝访问这些端口。

MAC 地址过滤
▮▮▮▮使用 MAC 地址集合来控制网络设备的访问权限。例如,创建一个 MAC 地址白名单集合,只允许来自白名单 MAC 地址的设备接入网络。

流量控制与 QoS
▮▮▮▮结合集合和 meter(流量计量器)、quota(流量配额)等语句,可以实现基于集合的流量控制和 QoS 策略。例如,为特定 IP 地址集合或用户组分配不同的带宽或流量配额。

地理位置访问控制
▮▮▮▮结合第三方工具(如 geoip 模块)和 IP 地址集合,可以实现基于地理位置的访问控制。例如,创建一个包含特定国家 IP 地址范围的集合,然后使用规则阻止或允许来自这些国家/地区的流量。

动态安全策略
▮▮▮▮结合动态集合和脚本,可以实现动态的安全策略。例如,当检测到异常行为时,自动将恶意 IP 地址添加到动态集合中,并实时生效,从而快速响应安全事件。

总而言之,集合是 nftables 中一个非常灵活和强大的工具,能够有效地简化规则集、提升性能,并支持动态策略管理,是构建高效、可扩展网络安全策略的关键组件。

3.1.2 集合的类型:匿名集合、命名集合、动态集合、区间集合等

nftables 提供了多种类型的集合,以满足不同的应用场景和需求。主要可以分为以下几种类型:

匿名集合(Anonymous Sets)
匿名集合是在规则中直接定义的集合,没有显式的名称。它们通常用于简单的、一次性的集合匹配,不需要在多条规则中共享或重复使用。匿名集合的定义方式是在规则中使用花括号 {} 直接列出集合元素。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 使用匿名集合允许来自特定 IP 的 SSH 访问
2 nft add rule inet filter input ip saddr { 192.168.1.1, 192.168.1.2, 192.168.1.3 } tcp dport 22 accept

优点:定义简单快捷,适用于简单的场景。
缺点:无法在多条规则中复用,不易于管理和维护。

命名集合(Named Sets)
命名集合是预先创建并赋予名称的集合。它们可以被多条规则引用,方便规则的复用和管理。命名集合需要先使用 nft add set 命令创建,然后再在规则中通过 @集合名称 的方式引用。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建命名集合 allowed_web_ports
2 nft add set inet filter allowed_web_ports { type inet_service; }
3 # 向集合中添加元素
4 nft add element inet filter allowed_web_ports { http, https, 8080 }
5
6 # 在规则中引用命名集合
7 nft add rule inet filter input tcp dport @allowed_web_ports accept

优点:可复用性高,易于管理和维护,规则结构清晰。
缺点:需要先创建集合,相比匿名集合稍显繁琐。

动态集合(Dynamic Sets)
动态集合是一种特殊的命名集合,其内容可以根据规则的执行结果动态地添加或删除元素。动态集合通常与 add @set-name { element }delete @set-name { element } 语句结合使用,实现基于规则的集合元素动态管理。动态集合需要使用 flags dynamic 标志创建。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建动态集合 blocked_ips
2 nft add set inet filter blocked_ips { type ipv4_addr; flags dynamic; }
3
4 # 规则当检测到来自某个 IP 的非法访问时将其添加到 blocked_ips 集合
5 nft add rule inet filter input ip protocol tcp flags syn tcp flags:0x00/0x02 counter log prefix "SYN-FLOOD: " drop add @blocked_ips { ip saddr }
6
7 # 规则阻止来自 blocked_ips 集合的流量
8 nft add rule inet filter input ip saddr @blocked_ips drop

优点:集合内容动态更新,实现自适应安全策略,灵活应对动态网络环境。
缺点:配置相对复杂,需要仔细设计规则逻辑。

区间集合(Interval Sets)
区间集合允许在集合中定义元素的范围,而不是单独列出每个元素。区间集合使用 interval 标志创建,并使用 .. 表示范围。区间集合可以用于 IP 地址范围、端口范围等场景,有效减少集合元素的数量,提高匹配效率。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建区间集合 allowed_ports包含端口 1-1024
2 nft add set inet filter allowed_ports { type inet_service; flags interval; }
3 nft add element inet filter allowed_ports { 1-1024 }
4
5 # 规则允许访问端口 1-1024 TCP 服务
6 nft add rule inet filter input tcp dport @allowed_ports accept

优点:简化范围元素的定义,减少集合大小,提高范围匹配效率。
缺点:仅适用于范围类型的元素,如数字、IP 地址等。

反向集合(Inverted Sets)
反向集合通过在集合名称前添加 ! 符号来表示,用于匹配不在集合中的元素。反向集合可以简化某些场景下的规则逻辑,例如,允许除了特定 IP 之外的所有 IP 访问。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建命名集合 allowed_ips
2 nft add set inet filter allowed_ips { type ipv4_addr; }
3 nft add element inet filter allowed_ips { 192.168.1.100 }
4
5 # 规则允许除了 192.168.1.100 之外的所有 IP 访问 Web 服务
6 nft add rule inet filter input ip saddr ! @allowed_ips tcp dport { 80, 443 } accept

优点:简化“排除”逻辑的规则,使规则更易读。
缺点:理解上可能稍有门槛,需要注意逻辑反转。

其他集合类型
除了上述常见的集合类型外,nftables 还支持其他一些集合类型,例如:

bitmap 集合:使用位图数据结构存储元素,适用于元素数量巨大且元素值范围集中的场景,例如端口号集合。
hash 集合:使用哈希表存储元素,适用于元素数量较大且元素值分布分散的场景,例如 IP 地址集合。
list 集合:使用链表存储元素,适用于元素数量较小且需要保持元素顺序的场景。

选择合适的集合类型取决于具体的应用场景和需求。一般来说,命名集合是使用最广泛的类型,动态集合适用于动态策略场景,区间集合适用于范围匹配场景,而匿名集合则适用于简单的临时性规则。理解不同集合类型的特点和适用场景,可以帮助我们更有效地使用 nftables 构建网络安全策略。

3.1.3 集合的创建、查看、修改与删除

掌握集合的创建、查看、修改和删除操作是使用 nftables 集合功能的基础。下面分别介绍这些操作的具体方法。

创建集合(Create Set)
使用 nft add set 命令创建集合。创建集合时需要指定集合所属的表(table)、集合名称、集合类型(type)以及可选的标志(flags)。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建一个名为 allowed_ssh_hosts 的 IPv4 地址集合,属于 inet 表的 filter 链
2 nft add set inet filter allowed_ssh_hosts { type ipv4_addr; }
3
4 # 创建一个名为 web_ports 的端口集合,属于 inet 表的 filter 链,并使用区间集合标志
5 nft add set inet filter web_ports { type inet_service; flags interval; }
6
7 # 创建一个动态集合 blocked_ips
8 nft add set inet filter blocked_ips { type ipv4_addr; flags dynamic; }

常用选项
table table_name:指定集合所属的表,例如 inet filterip nat 等。
set set_name:指定集合的名称,例如 allowed_ssh_hostsweb_ports 等。
{ type data_type; }:指定集合元素的数据类型,例如 ipv4_addr(IPv4 地址)、inet_service(端口号)、ether_addr(MAC 地址)等。常用的数据类型包括:
▮▮▮▮⚝ ipv4_addr:IPv4 地址
▮▮▮▮⚝ ipv6_addr:IPv6 地址
▮▮▮▮⚝ inet_proto:协议类型(如 tcp, udp, icmp)
▮▮▮▮⚝ inet_service:端口号(服务名或端口数字)
▮▮▮▮⚝ ether_addr:MAC 地址
▮▮▮▮⚝ mark:netfilter mark 值
▮▮▮▮⚝ ifname:接口名称
▮▮▮▮⚝ 更多数据类型请参考 nftables 手册。
flags flags:可选的标志,用于指定集合的特殊属性,例如:
▮▮▮▮⚝ dynamic:创建动态集合
▮▮▮▮⚝ interval:创建区间集合
▮▮▮▮⚝ timeout:为集合元素设置超时时间(动态集合常用)
▮▮▮▮⚝ gc:启用垃圾回收(动态集合常用)
▮▮▮▮⚝ 更多标志请参考 nftables 手册。

查看集合(Show Set)
使用 nft list set 命令查看集合的详细信息,包括集合的类型、标志、元素等。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 查看名为 allowed_ssh_hosts 的集合信息
2 nft list set inet filter allowed_ssh_hosts
3
4 # 查看指定表的所有集合
5 nft list table inet filter

nft list set 命令会输出集合的类型、标志以及当前包含的元素。例如:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table inet filter {
2 set allowed_ssh_hosts {
3 type ipv4_addr
4 flags interval
5 elements = { 192.168.1.1-192.168.1.3, 192.168.1.10 }
6 }
7 }

修改集合(Modify Set)
nftables 集合的修改操作主要包括添加元素、删除元素和更新元素。这些操作将在下一小节详细介绍。对于集合的类型和标志等基本属性,创建后通常不可直接修改。如果需要修改集合的类型或标志,通常需要先删除集合,然后重新创建。

删除集合(Delete Set)
使用 nft delete set 命令删除集合。删除集合时需要指定集合所属的表和集合名称。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 删除名为 allowed_ssh_hosts 的集合
2 nft delete set inet filter allowed_ssh_hosts
3
4 # 删除指定表的所有集合 (慎用!)
5 # nft delete table inet filter

注意:删除集合会同时删除所有引用该集合的规则,因此在删除集合前需要仔细评估影响。

清空集合(Flush Set)
如果只想清空集合中的所有元素,而保留集合本身,可以使用 nft flush set 命令。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 清空名为 allowed_ssh_hosts 的集合中的所有元素
2 nft flush set inet filter allowed_ssh_hosts

总结
nft add set table set_name { type data_type; flags flags; }:创建集合。
nft list set table set_name:查看集合信息。
nft delete set table set_name:删除集合。
nft flush set table set_name:清空集合元素。

掌握这些基本操作,就可以对 nftables 集合进行有效的管理。在实际应用中,通常会结合脚本和自动化工具来批量创建、管理和维护集合,提高运维效率。

3.1.4 集合的操作:添加元素、删除元素、更新元素

集合创建后,需要向集合中添加元素,并根据需要进行元素的删除和更新。nftables 提供了丰富的命令来操作集合元素。

添加元素(Add Element)
使用 nft add element 命令向集合中添加元素。可以一次添加一个或多个元素。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 向 allowed_ssh_hosts 集合添加单个 IP 地址
2 nft add element inet filter allowed_ssh_hosts { 192.168.1.20 }
3
4 # 向 allowed_ssh_hosts 集合添加多个 IP 地址
5 nft add element inet filter allowed_ssh_hosts { 192.168.1.21, 192.168.1.22, 192.168.1.23 }
6
7 # 向 web_ports 集合添加端口号和服务名
8 nft add element inet filter web_ports { 80, https, 8080 }
9
10 # 向区间集合添加区间范围
11 nft add element inet filter allowed_ports { 1025-65535 } # 使用 - 表示范围
12 nft add element inet filter allowed_ports { 1025..65535 } # 使用 .. 表示范围,效果相同

注意
⚝ 添加的元素类型必须与集合创建时指定的类型一致。
⚝ 对于区间集合,添加元素时可以使用 -.. 表示范围。
⚝ 可以使用逗号 , 分隔多个元素,一次添加多个元素。

删除元素(Delete Element)
使用 nft delete element 命令从集合中删除元素。可以一次删除一个或多个元素。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 从 allowed_ssh_hosts 集合删除单个 IP 地址
2 nft delete element inet filter allowed_ssh_hosts { 192.168.1.20 }
3
4 # 从 allowed_ssh_hosts 集合删除多个 IP 地址
5 nft delete element inet filter allowed_ssh_hosts { 192.168.1.21, 192.168.1.22 }
6
7 # 从 web_ports 集合删除端口号
8 nft delete element inet filter web_ports { 8080 }
9
10 # 从区间集合删除区间范围
11 nft delete element inet filter allowed_ports { 1025-65535 }

注意
⚝ 删除元素时,指定的元素必须与集合中已存在的元素完全匹配。
⚝ 可以使用逗号 , 分隔多个元素,一次删除多个元素。

更新元素(Update Element)
nftables 集合本身没有直接的“更新”操作。如果需要更新集合中的元素,通常需要先删除旧元素,然后再添加新元素。对于动态集合,可以使用 nft update element 命令,但这实际上是修改动态集合元素的属性,例如超时时间等,而不是替换元素本身。

对于普通命名集合,如果需要“更新”元素,可以结合 nft delete elementnft add element 命令来实现。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 假设需要将 allowed_ssh_hosts 集合中的 192.168.1.20 更新为 192.168.1.25
2
3 # 先删除旧元素
4 nft delete element inet filter allowed_ssh_hosts { 192.168.1.20 }
5
6 # 再添加新元素
7 nft add element inet filter allowed_ssh_hosts { 192.168.1.25 }

对于动态集合,nft update element 命令可以用于更新元素的属性,例如超时时间(timeout)。动态集合的元素可以设置超时时间,当元素在集合中存在的时间超过超时时间后,会被自动删除。可以使用 nft update element 命令修改已存在元素的超时时间。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建一个动态集合 dynamic_ips,元素超时时间为 300 秒 (5 分钟)
2 nft add set inet filter dynamic_ips { type ipv4_addr; flags dynamic,timeout; timeout 300s; }
3
4 # 添加元素到动态集合,并设置初始超时时间
5 nft add element inet filter dynamic_ips { 10.0.0.1 timeout 300s }
6
7 # 更新动态集合中已存在元素 10.0.0.1 的超时时间为 600 秒 (10 分钟)
8 nft update element inet filter dynamic_ips { 10.0.0.1 timeout 600s }

注意
nft update element 命令主要用于动态集合,更新元素的属性,例如超时时间。
⚝ 对于普通命名集合,元素的“更新”通常通过删除旧元素和添加新元素来实现。

批量操作
nftables 支持批量添加和删除集合元素,可以通过将元素列表写入文件,然后使用 nft --file 或管道输入的方式批量操作。这对于管理大量集合元素非常有用。

例如,创建一个名为 ip_list.txt 的文件,每行一个 IP 地址:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 192.168.1.100
2 192.168.1.101
3 192.168.1.102

然后可以使用以下命令批量添加元素:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add element inet filter allowed_ssh_hosts type ipv4_addr file ip_list.txt

或者使用管道输入:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 cat ip_list.txt | nft add element inet filter allowed_ssh_hosts type ipv4_addr -

批量删除元素的方法类似,只需将 add element 替换为 delete element 即可。

总结
nft add element table set_name { element1, element2, ... }:向集合添加元素。
nft delete element table set_name { element1, element2, ... }:从集合删除元素。
nft update element table dynamic_set_name { element timeout timeout_value }:更新动态集合元素的属性(如超时时间)。
⚝ 可以使用文件或管道批量操作集合元素。

熟练掌握集合元素的操作,可以灵活地管理 nftables 规则集,实现各种复杂的网络安全策略。

3.1.5 使用集合优化规则:IP 地址集合、端口集合、MAC 地址集合等

集合在 nftables 中最重要的应用之一就是优化规则,通过将多个重复的匹配条件合并到一个集合中,可以显著简化规则集,提高规则的执行效率和可维护性。本节将通过具体的例子,展示如何使用 IP 地址集合、端口集合和 MAC 地址集合来优化规则。

IP 地址集合优化
假设需要允许来自多个特定 IP 地址的 SSH 访问,如果不使用集合,需要为每个 IP 地址编写一条规则:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 不使用集合的规则
2 nft add rule inet filter input ip saddr 192.168.1.1 tcp dport 22 accept
3 nft add rule inet filter input ip saddr 192.168.1.2 tcp dport 22 accept
4 nft add rule inet filter input ip saddr 192.168.1.3 tcp dport 22 accept
5 # ... 更多规则 ...

当需要允许的 IP 地址数量很多时,规则会变得非常冗长。使用 IP 地址集合可以大大简化规则:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建 IP 地址集合 allowed_ssh_hosts
2 nft add set inet filter allowed_ssh_hosts { type ipv4_addr; }
3
4 # 向集合中添加允许的 IP 地址
5 nft add element inet filter allowed_ssh_hosts { 192.168.1.1, 192.168.1.2, 192.168.1.3, 192.168.1.0/24 }
6
7 # 使用集合优化后的规则
8 nft add rule inet filter input ip saddr @allowed_ssh_hosts tcp dport 22 accept

优势
⚝ 规则数量从多条减少到一条,规则集更简洁。
⚝ 修改允许的 IP 地址列表只需修改集合内容,无需修改规则。
⚝ 集合匹配性能更高,尤其是在 IP 地址数量较多时。

端口集合优化
假设需要允许访问多个 Web 服务端口(例如 80, 443, 8080, 8443),同样可以使用端口集合来优化规则:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 不使用集合的规则
2 nft add rule inet filter input tcp dport 80 accept
3 nft add rule inet filter input tcp dport 443 accept
4 nft add rule inet filter input tcp dport 8080 accept
5 nft add rule inet filter input tcp dport 8443 accept

使用端口集合优化后的规则:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建端口集合 web_ports
2 nft add set inet filter web_ports { type inet_service; }
3
4 # 向集合中添加 Web 服务端口
5 nft add element inet filter web_ports { http, https, 8080, 8443 } # 可以使用服务名或端口号
6
7 # 使用集合优化后的规则
8 nft add rule inet filter input tcp dport @web_ports accept

优势
⚝ 规则数量减少,更易于管理。
⚝ 修改允许的 Web 服务端口只需修改集合内容。
⚝ 端口集合可以使用服务名(如 http, https),提高可读性。

MAC 地址集合优化
在某些网络环境中,可能需要基于 MAC 地址进行访问控制。例如,只允许特定 MAC 地址的设备接入网络。可以使用 MAC 地址集合来实现:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建 MAC 地址集合 allowed_macs
2 nft add set bridge filter allowed_macs { type ether_addr; } # 注意 bridge
3
4 # 向集合中添加允许的 MAC 地址
5 nft add element bridge filter allowed_macs { 00:11:22:33:44:55, 00:AA:BB:CC:DD:EE }
6
7 # 使用集合优化后的规则只允许来自 allowed_macs 集合的流量通过 bridge forward
8 nft add rule bridge filter forward ether saddr @allowed_macs accept
9 nft add rule bridge filter forward drop # 默认拒绝其他所有 MAC 地址

优势
⚝ 集中管理允许的 MAC 地址列表。
⚝ 规则清晰,易于理解和维护。
⚝ 可以与其他 bridge 过滤规则结合使用,实现更精细的 MAC 地址控制。

组合使用多种集合
在复杂的网络策略中,可以组合使用多种类型的集合,例如同时使用 IP 地址集合、端口集合和协议集合,构建更灵活、更强大的规则。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建 IP 地址集合 trusted_networks
2 nft add set inet filter trusted_networks { type ipv4_addr; }
3 nft add element inet filter trusted_networks { 192.168.1.0/24, 10.0.0.0/24 }
4
5 # 创建端口集合 allowed_services
6 nft add set inet filter allowed_services { type inet_service; }
7 nft add element inet filter allowed_services { ssh, http, https }
8
9 # 规则允许来自 trusted_networks IP 访问 allowed_services 集合中的服务
10 nft add rule inet filter input ip saddr @trusted_networks tcp dport @allowed_services accept

总结
⚝ 使用集合可以将规则中的重复匹配条件抽象出来,简化规则集。
⚝ 集合提高了规则的可读性、可维护性和执行效率。
⚝ 可以根据不同的匹配条件类型选择合适的集合类型(IP 地址集合、端口集合、MAC 地址集合等)。
⚝ 可以组合使用多种集合,构建更复杂的网络策略。

在实际应用中,应充分利用集合的优势,将规则集模块化、结构化,提高 nftables 配置的效率和可管理性。

3.2 映射(Maps)详解

3.2.1 映射的优势与应用场景

映射(Maps)是 nftables 中另一个核心概念,它提供了一种键值对(key-value pairs)的存储和查找机制。可以将映射视为一个关联数组或字典,其中每个键(key)都关联着一个值(value)。在 nftables 规则中,可以使用映射根据键来查找对应的值,并基于查找结果执行不同的动作。

映射的主要优势在于实现更复杂的策略逻辑数据驱动的规则配置

实现复杂策略逻辑
映射允许根据不同的输入(键)执行不同的输出(值),从而实现更精细、更灵活的策略控制。例如,可以根据源 IP 地址或端口号,将流量路由到不同的出口网关;或者根据请求的 URL,将流量转发到不同的后端服务器。这种基于键值对的策略逻辑,可以应对更复杂的业务需求和网络场景。

数据驱动的规则配置
映射可以将策略配置数据与规则逻辑分离。策略数据存储在映射中,规则只负责根据映射内容进行查找和决策。这样可以更方便地管理和更新策略数据,而无需修改规则本身。例如,可以将用户 IP 地址与带宽限制值存储在映射中,然后使用规则根据映射动态地应用带宽限制。

状态ful 策略实现
结合连接追踪(connection tracking)和映射,可以实现基于连接状态的复杂策略。例如,可以根据连接的源 IP 地址、目的端口和协议类型,动态地分配不同的 QoS 优先级或应用不同的安全策略。

应用场景

基于 IP 的流量控制
▮▮▮▮使用 IP 地址作为键,带宽限制值作为值,存储在映射中。然后使用规则根据源 IP 地址查找映射,并应用相应的带宽限制。

基于端口的策略路由
▮▮▮▮使用目的端口号作为键,出口网关 IP 地址作为值,存储在映射中。然后使用规则根据目的端口号查找映射,并将流量路由到对应的出口网关。

基于 URL 的流量转发
▮▮▮▮使用请求 URL 或域名作为键,后端服务器 IP 地址作为值,存储在映射中。然后使用规则根据请求 URL 查找映射,并将流量转发到对应的后端服务器。

动态黑名单/白名单
▮▮▮▮使用 IP 地址作为键,标记(例如,blacklistwhitelist)作为值,存储在映射中。然后使用规则根据源 IP 地址查找映射,并根据标记执行相应的动作(例如,dropaccept)。

会话管理与状态保持
▮▮▮▮使用连接四元组(源 IP, 源端口, 目的 IP, 目的端口)或会话 ID 作为键,会话状态信息(例如,用户 ID, 登录时间, 权限级别)作为值,存储在映射中。然后使用规则根据会话信息进行访问控制或策略应用。

策略路由与负载均衡
▮▮▮▮结合映射和 fib(Forwarding Information Base)语句,可以实现复杂的策略路由和负载均衡策略。例如,根据源 IP 地址、目的端口或应用类型,将流量路由到不同的路径或后端服务器集群。

DDoS 防护与速率限制
▮▮▮▮使用源 IP 地址或连接数作为键,速率限制参数(例如,最大连接数, 最大包速率)作为值,存储在映射中。然后使用规则根据源 IP 地址或连接数查找映射,并应用相应的速率限制策略。

总而言之,映射是 nftables 中一个非常强大和灵活的工具,它扩展了 nftables 的策略表达能力,使其能够应对更复杂的网络场景和业务需求。通过合理地使用映射,可以构建更智能、更动态、更可扩展的网络安全策略。

3.2.2 映射的类型

nftables 的映射类型主要根据键的类型值的类型来区分。常见的映射类型包括:

基本映射类型
基本映射类型使用基本数据类型作为键和值,例如 IP 地址、端口号、整数、字符串等。

ipv4_addr : verdict:键为 IPv4 地址,值为 verdict(例如 accept, drop, goto)。
inet_service : ipv4_addr:键为端口号,值为 IPv4 地址。
integer : string:键为整数,值为字符串。
string : integer:键为字符串,值为整数。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建一个映射 ip_to_verdict,键为 IPv4 地址,值为 verdict
2 nft add map inet filter ip_to_verdict { type ipv4_addr : verdict; }
3
4 # 创建一个映射 port_to_gateway,键为端口号,值为 IPv4 地址
5 nft add map inet filter port_to_gateway { type inet_service : ipv4_addr; }

复合映射类型
复合映射类型使用复合数据类型作为键或值,例如元组(tuple)、集合(set)、映射(map)等。

ipv4_addr . inet_service : verdict:键为 IPv4 地址和端口号的元组,值为 verdict。
ipv4_addr : set of inet_service:键为 IPv4 地址,值为端口号集合。
ipv4_addr AlBeRt63EiNsTeIn verdict:键为 IPv4 地址,值为端口号到 verdict 的映射。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建一个映射 ip_port_to_verdict,键为 IPv4 地址和端口号的元组,值为 verdict
2 nft add map inet filter ip_port_to_verdict { type ipv4_addr . inet_service : verdict; }
3
4 # 创建一个映射 ip_to_ports,键为 IPv4 地址,值为端口号集合
5 nft add map inet filter ip_to_ports { type ipv4_addr : set of inet_service; }
6
7 # 创建一个映射 ip_to_port_verdict_map,键为 IPv4 地址,值为端口号到 verdict 的映射
8 nft add map inet filter ip_to_port_verdict_map { type ipv4_addr AlBeRt63EiNsTeIn verdict; }

匿名映射与命名映射
类似于集合,映射也分为匿名映射和命名映射。

匿名映射:在规则中直接定义的映射,没有显式的名称。适用于简单的、一次性的映射查找。
命名映射:预先创建并赋予名称的映射。可以被多条规则引用,方便规则的复用和管理。命名映射需要使用 nft add map 命令创建,然后在规则中通过 lookup @映射名称 的方式引用。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 使用匿名映射的规则
2 nft add rule inet filter input ip saddr vmap { { 192.168.1.1 AlBeRt63EiNsTeIn drop } }
3
4 # 创建命名映射 ip_verdict_map
5 nft add map inet filter ip_verdict_map { type ipv4_addr : verdict; }
6 nft add element inet filter ip_verdict_map { 192.168.1.1 AlBeRt63EiNsTeIn drop }
7
8 # 使用命名映射的规则
9 nft add rule inet filter input ip saddr lookup @ip_verdict_map

其他映射类型
除了上述常见的映射类型外,nftables 还支持其他一些特殊的映射类型,例如:

fib lookup 映射:用于策略路由,根据键查找路由表(FIB),并返回路由结果。
rt lookup 映射:用于路由策略,根据键查找路由策略数据库,并返回路由策略。
quota 映射:用于流量配额管理,根据键查找配额值,并进行流量计数和限制。
limit 映射:用于速率限制,根据键查找速率限制参数,并进行速率控制。

选择合适的映射类型取决于具体的应用场景和策略需求。一般来说,命名映射是使用最广泛的类型,复合映射适用于更复杂的数据结构,而匿名映射则适用于简单的临时性规则。理解不同映射类型的特点和适用场景,可以帮助我们更有效地使用 nftables 构建网络策略。

3.2.3 映射的创建、查看、修改与删除

映射的创建、查看、修改和删除操作与集合类似,但也有一些区别。下面分别介绍这些操作的具体方法。

创建映射(Create Map)
使用 nft add map 命令创建映射。创建映射时需要指定映射所属的表(table)、映射名称和映射类型(type)。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建一个名为 ip_to_verdict 的 IPv4 地址到 verdict 的映射,属于 inet 表的 filter 链
2 nft add map inet filter ip_to_verdict { type ipv4_addr : verdict; }
3
4 # 创建一个名为 port_to_gateway 的端口号到 IPv4 地址的映射
5 nft add map inet filter port_to_gateway { type inet_service : ipv4_addr; }
6
7 # 创建一个名为 ip_port_to_verdict 的 IPv4 地址和端口号元组到 verdict 的映射
8 nft add map inet filter ip_port_to_verdict { type ipv4_addr . inet_service : verdict; }

常用选项
table table_name:指定映射所属的表,例如 inet filterip nat 等。
map map_name:指定映射的名称,例如 ip_to_verdictport_to_gateway 等。
{ type key_type AlBeRt63EiNsTeIn verdictinet_service : ipv4_addr 等。

查看映射(Show Map)
使用 nft list map 命令查看映射的详细信息,包括映射的类型和键值对。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 查看名为 ip_to_verdict 的映射信息
2 nft list map inet filter ip_to_verdict
3
4 # 查看指定表的所有映射
5 nft list table inet filter

nft list map 命令会输出映射的类型以及当前包含的键值对。例如:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table inet filter {
2 map ip_to_verdict {
3 type ipv4_addr : verdict
4 elements = { 192.168.1.1 AlBeRt63EiNsTeIn drop }
5 }
6 }

修改映射(Modify Map)
nftables 映射的修改操作主要包括添加键值对、删除键值对和更新键值对。这些操作将在下一小节详细介绍。与集合类似,映射的类型在创建后通常不可直接修改

删除映射(Delete Map)
使用 nft delete map 命令删除映射。删除映射时需要指定映射所属的表和映射名称。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 删除名为 ip_to_verdict 的映射
2 nft delete map inet filter ip_to_verdict
3
4 # 删除指定表的所有映射 (慎用!)
5 # nft delete table inet filter

注意:删除映射会同时删除所有引用该映射的规则,因此在删除映射前需要仔细评估影响。

清空映射(Flush Map)
如果只想清空映射中的所有键值对,而保留映射本身,可以使用 nft flush map 命令。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 清空名为 ip_to_verdict 的映射中的所有键值对
2 nft flush map inet filter ip_to_verdict

总结
nft add map table map_name { type key_type : value_type; }:创建映射。
nft list map table map_name:查看映射信息。
nft delete map table map_name:删除映射。
nft flush map table map_name:清空映射键值对。

掌握这些基本操作,就可以对 nftables 映射进行有效的管理。在实际应用中,通常会结合脚本和自动化工具来批量创建、管理和维护映射,提高运维效率。

3.2.4 映射的操作:添加键值对、删除键值对、更新键值对、查找键值对

映射的核心操作是键值对的管理和查找。下面分别介绍这些操作的具体方法。

添加键值对(Add Element)
使用 nft add element 命令向映射中添加键值对。可以一次添加一个或多个键值对。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 向 ip_to_verdict 映射添加键值对
2 nft add element inet filter ip_to_verdict { 192.168.1.1 : accept }
3 nft add element inet filter ip_to_verdict { 192.168.1.2 : drop }
4
5 # 向 port_to_gateway 映射添加键值对
6 nft add element inet filter port_to_gateway { 80 : 10.0.0.1 }
7 nft add element inet filter port_to_gateway { 443 : 10.0.0.2 }
8
9 # 向 ip_port_to_verdict 映射添加键值对 (使用元组作为键)
10 nft add element inet filter ip_port_to_verdict { 192.168.1.1 . 80 : accept }
11 nft add element inet filter ip_port_to_verdict { 192.168.1.2 . 443 : drop }

注意
⚝ 添加的键和值类型必须与映射创建时指定的类型一致。
⚝ 使用冒号 : 分隔键和值。
⚝ 对于复合键类型(如元组),使用点号 . 分隔键的各个组成部分。
⚝ 可以使用逗号 , 分隔多个键值对,一次添加多个键值对。

删除键值对(Delete Element)
使用 nft delete element 命令从映射中删除键值对。可以一次删除一个或多个键值对。删除时只需指定键即可,无需指定值。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 从 ip_to_verdict 映射删除键为 192.168.1.1 的键值对
2 nft delete element inet filter ip_to_verdict { 192.168.1.1 }
3
4 # 从 port_to_gateway 映射删除键为 80 的键值对
5 nft delete element inet filter port_to_gateway { 80 }
6
7 # 从 ip_port_to_verdict 映射删除键为 192.168.1.1 . 80 的键值对
8 nft delete element inet filter ip_port_to_verdict { 192.168.1.1 . 80 }

注意
⚝ 删除键值对时,指定的键必须与映射中已存在的键完全匹配。
⚝ 可以使用逗号 , 分隔多个键,一次删除多个键值对。

更新键值对(Update Element)
与集合类似,nftables 映射本身没有直接的“更新”操作。如果需要更新映射中某个键的值,通常需要先删除旧的键值对,然后再添加新的键值对。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 假设需要将 ip_to_verdict 映射中键为 192.168.1.1 的值从 accept 更新为 reject
2
3 # 先删除旧的键值对
4 nft delete element inet filter ip_to_verdict { 192.168.1.1 }
5
6 # 再添加新的键值对,使用新的值
7 nft add element inet filter ip_to_verdict { 192.168.1.1 : reject }

查找键值对(Lookup)
映射的主要用途是在规则中进行查找操作。使用 lookup @映射名称 表达式可以在规则中根据键查找映射中对应的值。查找结果可以用于后续的规则匹配或动作。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建映射 ip_verdict_map
2 nft add map inet filter ip_verdict_map { type ipv4_addr : verdict; }
3 nft add element inet filter ip_verdict_map { 192.168.1.1 AlBeRt63EiNsTeIn drop }
4
5 # 规则根据源 IP 地址查找 ip_verdict_map 映射并执行查找到的 verdict 动作
6 nft add rule inet filter input ip saddr lookup @ip_verdict_map

在上述规则中,当数据包到达 input 链时,nftables 会根据数据包的源 IP 地址 (ip saddr) 在 ip_verdict_map 映射中查找对应的值。如果找到匹配的键(例如,源 IP 地址为 192.168.1.1),则规则会执行映射中对应的值(accept);如果找不到匹配的键(例如,源 IP 地址不是 192.168.1.1 或 192.168.1.2),则规则不会匹配,会继续执行下一条规则。

注意
lookup @映射名称 表达式返回的值类型必须与规则中后续的匹配条件或动作兼容。例如,如果映射的值类型是 verdict,则可以直接作为规则的动作。
⚝ 如果在映射中找不到匹配的键,lookup 表达式通常不会返回任何值,规则可能不会匹配,或者会根据默认行为执行。具体行为取决于规则的上下文和后续的匹配条件或动作。

批量操作
类似于集合,映射也支持批量添加和删除键值对,可以通过将键值对列表写入文件,然后使用 nft --file 或管道输入的方式批量操作。

例如,创建一个名为 ip_verdict_list.txt 的文件,每行一个键值对,键和值之间用冒号 : 分隔:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 192.168.1.100 : accept
2 192.168.1.101 : drop
3 192.168.1.102 : accept

然后可以使用以下命令批量添加键值对:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add element inet filter ip_to_verdict type ipv4_addr : verdict file ip_verdict_list.txt

或者使用管道输入:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 cat ip_verdict_list.txt | nft add element inet filter ip_to_verdict type ipv4_addr : verdict -

批量删除键值对的方法类似,只需将 add element 替换为 delete element,并指定要删除的键即可。

总结
nft add element table map_name { key1 AlBeRt63EiNsTeIn value2, ... }:向映射添加键值对。
nft delete element table map_name { key1, key2, ... }:从映射删除键值对。
⚝ 映射的“更新”通常通过删除旧键值对和添加新键值对来实现。
lookup @map_name 表达式用于在规则中查找映射值。
⚝ 可以使用文件或管道批量操作映射键值对。

熟练掌握映射的键值对操作和查找方法,可以充分利用映射的强大功能,构建更智能、更灵活的网络策略。

3.2.5 使用映射实现复杂策略:基于 IP 的流量控制、基于端口的策略路由等

映射的强大之处在于可以实现各种复杂的网络策略。本节将通过具体的例子,展示如何使用映射实现基于 IP 的流量控制和基于端口的策略路由等高级功能。

基于 IP 的流量控制
假设需要根据源 IP 地址对不同用户或用户组进行带宽限制。可以使用映射存储 IP 地址和对应的带宽限制值,然后使用 limit 表达式结合映射实现流量控制。

首先,创建一个映射 ip_bandwidth_limit,键为 IPv4 地址,值为带宽限制值(例如,每秒最大数据包数 packets/second)。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add map inet filter ip_bandwidth_limit { type ipv4_addr : limit rate packets/second; }
2
3 # 为不同 IP 地址设置不同的带宽限制
4 nft add element inet filter ip_bandwidth_limit { 192.168.1.100 : limit rate 100 packets/second } # IP 192.168.1.100 限制为 100pps
5 nft add element inet filter ip_bandwidth_limit { 192.168.1.101 : limit rate 50 packets/second } # IP 192.168.1.101 限制为 50pps
6 # ... 更多 IP 地址和限制 ...

然后,创建规则,使用 lookup 表达式查找映射,并使用 limit 表达式应用带宽限制。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input ip saddr lookup @ip_bandwidth_limit limit rate over { lookup @ip_bandwidth_limit } drop # 超过限制则丢弃
2 nft add rule inet filter input accept # 未超过限制则接受

工作原理
⚝ 当数据包到达 input 链时,规则首先使用 ip saddr lookup @ip_bandwidth_limit 查找源 IP 地址在 ip_bandwidth_limit 映射中对应的带宽限制值。
limit rate over { lookup @ip_bandwidth_limit } 表达式会根据查找到的带宽限制值进行速率检查。如果当前速率超过了限制值,则条件为真,执行 drop 动作;否则,条件为假,继续执行下一条规则。
⚝ 第二条规则 accept 用于处理未超过带宽限制的流量,以及在映射中没有找到对应 IP 地址的情况(此时 lookup 表达式可能不会返回有效的限制值,limit 表达式可能不会生效,默认允许通过)。

优势
⚝ 可以为不同的 IP 地址设置不同的带宽限制,实现精细化的流量控制。
⚝ 策略配置数据与规则逻辑分离,方便管理和更新带宽限制策略。
⚝ 可以动态地添加、删除或修改 IP 地址和带宽限制值,实现灵活的流量控制策略。

基于端口的策略路由
假设需要根据目的端口号将流量路由到不同的出口网关。可以使用映射存储目的端口号和对应的出口网关 IP 地址,然后使用 fib 语句结合映射实现策略路由。

首先,创建一个映射 port_gateway_map,键为端口号,值为出口网关 IP 地址。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add map inet filter port_gateway_map { type inet_service : ipv4_addr; }
2
3 # 为不同端口设置不同的出口网关
4 nft add element inet filter port_gateway_map { 80 : 10.0.0.1 } # 端口 80 路由到网关 10.0.0.1
5 nft add element inet filter port_gateway_map { 443 : 10.0.0.2 } # 端口 443 路由到网关 10.0.0.2
6 # ... 更多端口和网关 ...

然后,创建规则,使用 lookup 表达式查找映射,并使用 fib 语句设置路由。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter output ip daddr != 127.0.0.0/8 tcp dport lookup @port_gateway_map fib dnat to { lookup @port_gateway_map }

工作原理
⚝ 当数据包到达 output 链时,规则首先检查目的 IP 地址是否为本地回环地址(ip daddr != 127.0.0.0/8),并检查协议和目的端口是否为 TCP。
tcp dport lookup @port_gateway_map 表达式查找目的端口号在 port_gateway_map 映射中对应的出口网关 IP 地址。
fib dnat to { lookup @port_gateway_map } 语句使用 fib 语句进行策略路由,并将数据包的目标地址 NAT(DNAT)到查找到的出口网关 IP 地址。fib dnat 会根据目标地址查找路由表,并将数据包路由到对应的出口网关。

优势
⚝ 可以根据不同的目的端口号将流量路由到不同的出口网关,实现灵活的策略路由。
⚝ 策略配置数据与规则逻辑分离,方便管理和更新路由策略。
⚝ 可以动态地添加、删除或修改端口号和出口网关 IP 地址,实现动态路由策略。

更复杂的策略组合
映射可以与其他 nftables 功能(如集合、表达式、语句)组合使用,构建更复杂的网络策略。例如,可以将 IP 地址集合作为映射的键,将端口集合作为映射的值,实现基于 IP 地址组和端口组的策略控制。或者,可以将多个映射嵌套使用,实现多级策略查找和决策。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建 IP 地址集合 trusted_networks
2 nft add set inet filter trusted_networks { type ipv4_addr; }
3 nft add element inet filter trusted_networks { 192.168.1.0/24, 10.0.0.0/24 }
4
5 # 创建端口集合 allowed_services
6 nft add set inet filter allowed_services { type inet_service; }
7 nft add element inet filter allowed_services { ssh, http, https }
8
9 # 创建映射 ip_set_to_port_set_map键为 IP 地址集合值为端口集合
10 nft add map inet filter ip_set_to_port_set_map { type set of ipv4_addr : set of inet_service; }
11 nft add element inet filter ip_set_to_port_set_map { @trusted_networks : @allowed_services } # trusted_networks 集合映射到 allowed_services 集合
12
13 # 规则允许来自 trusted_networks 集合的 IP 访问 allowed_services 集合中的服务
14 nft add rule inet filter input ip saddr @trusted_networks tcp dport @allowed_services accept
15
16 # 或者使用映射查找的方式 (虽然这里略显冗余但演示了映射的用法)
17 # nft add rule inet filter input ip saddr vmap { lookup @ip_set_to_port_set_map : verdict accept }

总结
⚝ 映射是实现复杂网络策略的关键工具,可以用于流量控制、策略路由、访问控制等各种场景。
⚝ 映射可以与 limitfib 等语句结合使用,实现高级功能。
⚝ 映射可以与其他 nftables 功能组合使用,构建更灵活、更强大的网络策略。
⚝ 掌握映射的应用技巧,可以充分发挥 nftables 的潜力,应对各种复杂的网络需求。

3.3 集合与映射的组合应用

3.3.1 集合与映射的嵌套使用

集合和映射可以相互嵌套使用,从而构建更复杂、更灵活的数据结构和策略逻辑。嵌套使用主要体现在以下几个方面:

集合作为映射的值
可以将集合作为映射的值类型,实现一个键对应多个值的策略。例如,可以使用 IP 地址作为键,端口集合作为值,表示允许特定 IP 地址访问的端口列表。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建端口集合 web_ports
2 nft add set inet filter web_ports { type inet_service; }
3 nft add element inet filter web_ports { http, https, 8080 }
4
5 # 创建映射 ip_to_ports键为 IPv4 地址值为端口集合
6 nft add map inet filter ip_to_ports { type ipv4_addr : set of inet_service; }
7
8 # IP 地址 192.168.1.1 映射到 web_ports 集合
9 nft add element inet filter ip_to_ports { 192.168.1.1 : @web_ports }
10
11 # 规则允许来自 192.168.1.1 IP 访问 ip_to_ports 映射中对应的端口集合
12 nft add rule inet filter input ip saddr 192.168.1.1 tcp dport vmap { lookup @ip_to_ports : verdict accept }

在上述例子中,ip_to_ports 映射的值类型是 set of inet_service,表示端口集合。规则中使用 lookup @ip_to_ports 查找 IP 地址 192.168.1.1 对应的端口集合,然后使用 vmap 表达式将端口集合作为匹配条件,允许访问这些端口。

映射作为集合的元素
可以将映射作为集合的元素类型,实现一个集合包含多个映射的策略。例如,可以创建一个包含多个 IP 地址到端口映射的集合,表示一组复杂的访问控制规则。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建映射 ip_to_port_map_1
2 nft add map inet filter ip_to_port_map_1 { type ipv4_addr : inet_service; }
3 nft add element inet filter ip_to_port_map_1 { 192.168.1.1 : 80 }
4
5 # 创建映射 ip_to_port_map_2
6 nft add map inet filter ip_to_port_map_2 { type ipv4_addr : inet_service; }
7 nft add element inet filter ip_to_port_map_2 { 192.168.1.2 : 443 }
8
9 # 创建集合 access_rules元素类型为映射 (ipv4_addr : inet_service)
10 nft add set inet filter access_rules { type map of ipv4_addr : inet_service; }
11
12 # 将映射 ip_to_port_map_1 ip_to_port_map_2 添加到 access_rules 集合
13 nft add element inet filter access_rules { @ip_to_port_map_1, @ip_to_port_map_2 }
14
15 # 规则匹配 access_rules 集合中的映射规则
16 # (这里规则的实现比较复杂需要根据具体需求设计此处仅为示例)
17 # ... 规则逻辑 ...

将映射作为集合元素的使用场景相对较少,规则实现也可能比较复杂,需要根据具体需求进行设计。

映射的值为映射
映射的值类型也可以是另一个映射,实现多级映射或嵌套映射。例如,可以使用用户 ID 作为第一级键,服务类型作为第二级键,带宽限制值作为值,实现基于用户和服务类型的精细化流量控制。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建映射 user_service_bandwidth_limit键为用户 ID (integer)值为服务类型到带宽限制值的映射
2 nft add map inet filter user_service_bandwidth_limit { type integer AlBeRt63EiNsTeIn limit rate bytes/second; }
3
4 # 创建服务类型到带宽限制值的子映射 service_limit_map_1
5 nft add map inet filter service_limit_map_1 { type string : limit rate bytes/second; }
6 nft add element inet filter service_limit_map_1 { "http" : limit rate 100kbytes/second }
7 nft add element inet filter service_limit_map_1 { "ftp" : limit rate 50kbytes/second }
8
9 # 创建服务类型到带宽限制值的子映射 service_limit_map_2
10 nft add map inet filter service_limit_map_2 { type string : limit rate bytes/second; }
11 nft add element inet filter service_limit_map_2 { "http" : limit rate 200kbytes/second }
12 nft add element inet filter service_limit_map_2 { "ftp" : limit rate 100kbytes/second }
13
14 # 将用户 ID 1 映射到 service_limit_map_1用户 ID 2 映射到 service_limit_map_2
15 nft add element inet filter user_service_bandwidth_limit { 1 : @service_limit_map_1 }
16 nft add element inet filter user_service_bandwidth_limit { 2 : @service_limit_map_2 }
17
18 # 规则根据用户 ID 和服务类型查找带宽限制并应用流量控制
19 # (这里需要更复杂的规则逻辑例如从数据包中提取用户 ID 和服务类型然后进行双重映射查找)
20 # ... 规则逻辑 ...

多级映射可以实现更复杂的策略配置和查找逻辑,但规则实现也会相应增加复杂性。

集合与映射的组合表达式
在规则中,可以将集合和映射的查找表达式组合使用,实现更灵活的匹配条件和动作。例如,可以使用集合匹配源 IP 地址,然后使用映射根据目的端口查找对应的动作。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建 IP 地址集合 trusted_networks
2 nft add set inet filter trusted_networks { type ipv4_addr; }
3 nft add element inet filter trusted_networks { 192.168.1.0/24, 10.0.0.0/24 }
4
5 # 创建端口到 verdict 的映射 port_verdict_map
6 nft add map inet filter port_verdict_map { type inet_service : verdict; }
7 nft add element inet filter port_verdict_map { 80 AlBeRt63EiNsTeIn accept, 22 : drop }
8
9 # 规则如果源 IP 来自 trusted_networks 集合则根据目的端口查找 port_verdict_map 映射执行对应的 verdict 动作
10 nft add rule inet filter input ip saddr @trusted_networks tcp dport lookup @port_verdict_map

在上述规则中,首先使用集合 trusted_networks 匹配源 IP 地址,然后使用映射 port_verdict_map 根据目的端口查找 verdict 动作。只有当源 IP 地址在 trusted_networks 集合中时,才会执行映射查找和后续的 verdict 动作。

总结
⚝ 集合和映射可以相互嵌套使用,构建更复杂的数据结构和策略逻辑。
⚝ 集合可以作为映射的值类型,实现一对多的策略。
⚝ 映射的值可以是另一个映射,实现多级映射。
⚝ 集合和映射的查找表达式可以组合使用,实现更灵活的规则匹配和动作。
⚝ 嵌套使用集合和映射可以提高策略的灵活性和可扩展性,但也可能增加规则的复杂性,需要根据具体需求权衡使用。

3.3.2 使用集合和映射构建更灵活、更高效的规则集

集合和映射是构建灵活、高效 nftables 规则集的核心组件。合理地使用集合和映射,可以显著提高规则的可读性、可维护性和执行效率。本节将总结使用集合和映射构建规则集的最佳实践。

规则集模块化
将规则集按照功能模块化,例如防火墙规则、NAT 规则、流量控制规则等,分别放在不同的表或链中。在每个模块内部,使用集合和映射来组织和管理规则。

使用命名集合和命名映射:避免在规则中直接使用匿名集合和匿名映射,尽量使用命名集合和命名映射,提高规则的复用性和可管理性。
将策略数据与规则逻辑分离:将策略配置数据(例如,IP 地址列表、端口列表、带宽限制值等)存储在集合和映射中,规则只负责引用和使用这些数据,实现数据驱动的规则配置。
使用 include 文件组织规则:将集合、映射和规则分别放在不同的文件中,使用 include 语句将它们组织起来,方便模块化管理和维护。

规则优化与性能提升
使用集合和映射可以减少规则数量,提高规则匹配效率,从而提升整体性能。

使用集合合并重复规则:将多条相似的规则合并为一条规则,使用集合来匹配多个目标(例如,多个 IP 地址、端口号)。
使用区间集合优化范围匹配:对于 IP 地址范围、端口范围等连续的范围匹配,使用区间集合可以减少集合元素数量,提高匹配效率。
使用哈希集合和位图集合优化大型集合:对于包含大量元素的集合,根据元素类型和分布特点,选择合适的集合类型(例如,哈希集合、位图集合),提高集合查找效率。
优化规则顺序:将使用集合和映射的规则放在规则集的前面,优先进行集合和映射匹配,可以更快地过滤掉不匹配的流量,提高整体规则执行效率。

动态策略与自动化运维
集合和映射的动态更新特性,使其非常适合构建动态策略和自动化运维系统。

使用动态集合实现动态黑名单/白名单:结合脚本和监控系统,当检测到异常行为时,自动将恶意 IP 地址添加到动态集合中,实时生效,实现动态安全防护。
使用映射实现动态策略调整:根据实时网络状况或业务需求,动态地更新映射中的策略数据(例如,带宽限制值、路由策略),实现自适应策略调整。
结合自动化工具管理集合和映射:使用 Ansible、Puppet 等自动化工具批量创建、管理和维护集合和映射,提高运维效率,降低人工错误。
使用 API 或脚本操作集合和映射:nftables 提供了命令行工具和 libnftables 库,可以方便地通过 API 或脚本操作集合和映射,实现自动化策略管理和集成。

规则可读性与可维护性
合理地使用集合和映射,可以提高规则的可读性和可维护性。

使用描述性集合和映射名称:为集合和映射选择具有描述性的名称,例如 allowed_ssh_hostsweb_portsip_bandwidth_limit 等,提高规则的可读性。
添加规则注释:在规则中添加注释,解释规则的目的和作用,方便后续维护和理解。
保持规则集结构清晰:按照功能模块化组织规则集,使用缩进和空行等格式化方式,提高规则集的可读性。
定期审查和优化规则集:定期审查规则集,删除冗余规则,优化规则逻辑,保持规则集的简洁和高效。

总结
⚝ 使用集合和映射进行规则集模块化,提高可管理性。
⚝ 使用集合和映射优化规则,提高性能。
⚝ 利用集合和映射的动态特性,实现自动化运维。
⚝ 注重规则的可读性和可维护性,方便长期管理。

通过遵循上述最佳实践,可以充分发挥集合和映射的优势,构建灵活、高效、可维护的 nftables 规则集,应对各种复杂的网络安全和策略需求。

ENDOF_CHAPTER_

4. chapter 4: nftables 高级特性与扩展

4.1 表达式(Expressions)进阶

4.1.1 payload 表达式:深入解析数据包载荷

payload 表达式允许 nftables 规则检查数据包的载荷(payload),即数据包中实际携带的数据部分,而不仅仅是包头信息。这为实现更精细、更应用层的过滤和策略控制提供了强大的能力。

基本概念

载荷偏移(Payload Offset):指定从数据包的哪个字节开始读取载荷数据。偏移量通常相对于协议头的起始位置计算。
载荷长度(Payload Length):指定需要读取的载荷数据的长度。
数据类型(Data Type):指定载荷数据的类型,例如 u8(8 位无符号整数)、u16(16 位无符号整数)、u32(32 位无符号整数)等。这决定了如何解释读取的字节序列。
比较操作符(Comparison Operators):用于将读取的载荷数据与指定的值进行比较,例如 ==(等于)、!=(不等于)、<(小于)、>(大于)、&(按位与)等。

语法结构

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 payload offset <offset> length <length> <data_type> <comparison_operator> <value>

<offset>: 载荷偏移量,可以是十进制或十六进制数。
<length>: 载荷长度,可以是十进制或十六进制数。
<data_type>: 数据类型,例如 u8, u16, u32, u64
<comparison_operator>: 比较操作符,例如 ==, !=, <, >, &, ^, |
<value>: 要比较的值,可以是十进制或十六进制数。

应用示例

匹配 HTTP GET 请求:HTTP GET 请求通常以 "GET" 字符串开头。我们可以使用 payload 表达式来检测 HTTP GET 请求。假设 HTTP 流量基于 TCP 协议,且端口为 80。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input tcp dport 80 payload offset 0 length 3 bytes hex 474554 == 1 log prefix "HTTP GET Request: " accept

▮▮▮▮⚝ payload offset 0 length 3 bytes hex 474554: 从载荷的第 0 个字节开始,读取 3 个字节,并将其解释为十六进制数据 474554,对应 ASCII 码的 "GET"。
▮▮▮▮⚝ == 1: 将读取的载荷数据与 1 进行比较。这里实际上是将十六进制的 "GET" 转换为一个数值进行比较,更准确的做法是直接比较十六进制值,但为了演示 payload 的基本用法,这里简化处理。更严谨的 HTTP GET 匹配可能需要更复杂的规则和更长的 payload 检查。

检测 DNS 请求类型:DNS 请求类型(例如 A 记录查询、AAAA 记录查询)编码在 DNS 报文的特定偏移位置。假设我们需要检测 DNS A 记录查询(类型代码为 1)。DNS 请求通常使用 UDP 协议,端口为 53。DNS 查询类型字段通常位于 DNS 报文头的偏移量为 2 字节处,长度为 2 字节。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input udp dport 53 payload offset 2 length 2 bytes u16 0x0001 == 1 log prefix "DNS A Record Query: " accept

▮▮▮▮⚝ payload offset 2 length 2 bytes u16 0x0001: 从载荷的第 2 个字节开始,读取 2 个字节,并将其解释为 16 位无符号整数。0x0001 是 DNS A 记录查询的类型代码。
▮▮▮▮⚝ == 1: 将读取的 16 位无符号整数值与 1 进行比较,以匹配 DNS A 记录查询。

匹配特定 TCP 标志位:TCP 标志位位于 TCP 头部,可以使用 payload 表达式进行匹配。例如,匹配 SYN 包(SYN 标志位在 TCP 头部的偏移量为 13 字节,SYN 标志位的值为 0x02)。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input tcp flags syn payload offset 13 length 1 bytes u8 & 0x02 == 0x02 log prefix "SYN Packet Detected: " accept

▮▮▮▮⚝ payload offset 13 length 1 bytes u8 & 0x02 == 0x02: 从载荷的第 13 个字节开始,读取 1 个字节,并将其解释为 8 位无符号整数。& 0x02 执行按位与操作,检查 SYN 标志位是否被设置(值为 0x02)。

注意事项

性能影响:payload 表达式需要深度包检测(Deep Packet Inspection, DPI),相对于简单的头部匹配,会消耗更多的 CPU 资源。在高性能要求的场景中,应谨慎使用 payload 表达式,并尽量优化规则,例如结合其他更快速的匹配条件。
协议理解:要有效地使用 payload 表达式,需要深入理解网络协议的格式和数据包结构,包括各个字段的偏移量、长度和数据类型。
安全风险:过度依赖 payload 表达式进行安全策略控制可能存在被绕过的风险。攻击者可能通过构造畸形数据包或协议混淆等技术来逃避检测。应结合多层次的安全防护措施。

payload 表达式是 nftables 中一个非常强大的工具,它使得防火墙规则可以基于数据包的实际内容进行决策,从而实现更智能、更灵活的网络安全策略。然而,使用时需要权衡性能、复杂性和安全性等因素。

4.1.2 meta 表达式:元数据匹配,如接口名称、数据包长度等

meta 表达式允许 nftables 规则基于数据包的元数据(metadata)进行匹配。元数据是指与数据包相关的、但并非直接包含在数据包头部或载荷中的信息。这些信息通常由网络协议栈或内核在处理数据包的过程中生成和维护。meta 表达式为规则提供了更丰富的上下文信息,使得可以根据数据包的来源接口、目的接口、数据包长度、IP 协议版本等属性进行灵活的策略控制。

常见的 meta 表达式类型

接口相关
▮▮▮▮⚝ iifname(input interface name):输入接口名称,数据包进入网络堆栈的接口。
▮▮▮▮⚝ oifname(output interface name):输出接口名称,数据包离开网络堆栈的接口。
▮▮▮▮⚝ iif(input interface index):输入接口索引。
▮▮▮▮⚝ oif(output interface index):输出接口索引。
▮▮▮▮⚝ physdev(physical device name):物理设备名称,例如对于 VLAN 或 bridge 接口,physdev 指向底层的物理接口。
▮▮▮▮⚝ skdev (socket device index): 与数据包关联的套接字设备索引,通常用于本地生成的数据包。

数据包属性
▮▮▮▮⚝ pkttype(packet type):数据包类型,例如 unicast(单播)、broadcast(广播)、multicast(多播)。
▮▮▮▮⚝ len(packet length):数据包总长度(包括链路层头部)。
▮▮▮▮⚝ protocol(network protocol):网络协议类型,例如 ipip6arp
▮▮▮▮⚝ fib daddrtype (FIB destination address type): 通过 FIB (Forwarding Information Base) 查找确定的目标地址类型,例如 unicast, broadcast, local.
▮▮▮▮⚝ mark(packet mark):数据包标记,可以使用 mark 语句设置和匹配。
▮▮▮▮⚝ priority (packet priority): 数据包优先级 (例如,Linux traffic control 的 skb->priority)。
▮▮▮▮⚝ queue (packet queue): 与数据包关联的队列 ID。
▮▮▮▮⚝ rtclassid (routing class ID): 路由策略数据库 (RPDB) 返回的路由类 ID。
▮▮▮▮⚝ nfnlgroup (Netfilter netlink group): 与数据包关联的 Netfilter netlink 组。
▮▮▮▮⚝ ct zone (connection tracking zone): 连接追踪区域 (zone) ID。

语法结构

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 meta

<metadata_type>: 元数据类型,例如 iifname, oifname, len, pkttype 等。
<comparison_operator>: 比较操作符,例如 ==, !=, in, > 等。
<value>: 要比较的值,值的类型取决于元数据类型,例如接口名称是字符串,数据包长度是整数。

应用示例

基于输入接口允许 SSH 访问:只允许从特定接口(例如 eth0)进入的 SSH 连接。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input iifname "eth0" tcp dport 22 accept

▮▮▮▮⚝ iifname "eth0": 匹配输入接口名称为 "eth0" 的数据包。

阻止来自特定接口的广播流量:阻止从接口 wlan0 接收到的广播数据包。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input iifname "wlan0" meta pkttype broadcast drop

▮▮▮▮⚝ meta pkttype broadcast: 匹配数据包类型为广播的数据包。

基于数据包长度限制:限制特定类型数据包的最大长度,例如限制 ICMP 数据包的最大长度为 128 字节。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input ip protocol icmp meta len > 128 drop

▮▮▮▮⚝ meta len > 128: 匹配数据包长度大于 128 字节的数据包。

基于输出接口进行策略路由:将特定流量通过不同的输出接口发送,例如将目标地址为特定网段的流量通过 eth1 接口发送。这通常需要结合 route 表和链。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward ip daddr 192.168.2.0/24 meta oifname "eth1" accept

▮▮▮▮⚝ meta oifname "eth1": 匹配输出接口名称为 "eth1" 的数据包。注意,在 forward 链中使用 oifname 通常用于策略路由或基于接口的转发控制。

使用接口索引:使用接口索引进行匹配,例如匹配输入接口索引为 2 的数据包。接口索引可以使用 ip link show 命令查看。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input meta iif 2 tcp dport 80 accept

▮▮▮▮⚝ meta iif 2: 匹配输入接口索引为 2 的数据包。

注意事项

接口名称的动态性:接口名称可能会因为网络配置的改变而发生变化,例如 USB 网络接口的名称。使用接口索引可能更稳定,但可读性较差。建议在脚本中使用变量来管理接口名称,提高配置的灵活性和可维护性。
性能考虑:meta 表达式的匹配效率通常很高,因为元数据是内核已经解析和缓存的信息。相对于 payload 表达式,meta 表达式的性能开销较小。
适用场景:meta 表达式非常适合于基于网络拓扑结构、接口属性、数据包基本特征进行策略控制的场景,例如网络边界防火墙、路由器、网桥等。

meta 表达式是 nftables 中非常实用且高效的匹配工具,它扩展了规则的匹配维度,使得网络策略可以更加精细化和智能化。合理利用 meta 表达式可以提升网络安全性和管理效率。

4.1.3 ct 表达式:连接追踪状态的精细控制

ct 表达式(connection tracking expression)是 nftables 中用于访问和匹配连接追踪(connection tracking)信息的关键组件。连接追踪是 Netfilter 的核心功能之一,它能够跟踪网络连接的状态,使得防火墙可以实现有状态的包过滤。ct 表达式允许规则基于连接的状态、方向、协议、超时时间等属性进行灵活的策略控制。

连接追踪状态

连接追踪模块维护着一个连接状态表,记录着网络连接的各种信息。常见的连接状态包括:

NEW:新的连接,表示连接的第一个包。
ESTABLISHED:已建立的连接,表示连接已经成功建立,并且双向数据传输正常进行。
RELATED:关联连接,表示与已建立连接相关的连接,例如 FTP 数据连接与控制连接、NAT 场景下的反向连接等。
INVALID:无效连接,表示连接状态异常,例如不符合协议规范、乱序、或无法追踪的包。
UNTRACKED:未追踪的连接,表示显式地被配置为不进行连接追踪的连接。
SNAT:源地址转换连接。
DNAT:目标地址转换连接。

ct 表达式类型

状态匹配
▮▮▮▮⚝ ct state:匹配连接的总体状态,例如 ct state established,related 匹配已建立和关联的连接。
▮▮▮▮⚝ ct status:更细粒度的状态标志,例如 ct status dnat 匹配经过 DNAT 的连接。

方向匹配
▮▮▮▮⚝ ct dir original:匹配连接的原始方向(客户端到服务器)。
▮▮▮▮⚝ ct dir reply:匹配连接的回复方向(服务器到客户端)。

协议和地址信息
▮▮▮▮⚝ ct proto:匹配连接的协议,例如 ct proto tcp
▮▮▮▮⚝ ct src:匹配连接的源 IP 地址和端口。
▮▮▮▮⚝ ct dst:匹配连接的目标 IP 地址和端口。
▮▮▮▮⚝ ct original srcct original dstct reply srcct reply dst:分别匹配原始方向和回复方向的源/目标 IP 地址和端口。

超时时间
▮▮▮▮⚝ ct timeout:匹配连接的剩余超时时间(秒)。

标记和标签
▮▮▮▮⚝ ct mark:匹配连接的 conntrack mark,可以使用 ct mark set 语句设置。
▮▮▮▮⚝ ct mark mask:带掩码的 conntrack mark 匹配。
▮▮▮▮⚝ ct labels:匹配连接的 conntrack labels,可以使用 ct labels addct labels del 语句管理。
▮▮▮▮⚝ ct labels mask:带掩码的 conntrack labels 匹配。
▮▮▮▮⚝ ct helper (connection tracking helper): 匹配连接使用的 conntrack helper (例如, ftp, sip).
▮▮▮▮⚝ ct count (connection count): 匹配当前连接追踪表中的连接数量。

TCP 特有
▮▮▮▮⚝ ct tcp flags:匹配 TCP 连接的标志位状态。
▮▮▮▮⚝ ct tcp state:匹配 TCP 连接的更细致的状态,例如 SYN_SENT, SYN_RECV, ESTABLISHED, FIN_WAIT, CLOSE_WAIT 等。

语法结构

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ct

<ct_expression_type>: 连接追踪表达式类型,例如 state, status, dir, proto 等。
<comparison_operator>: 比较操作符,例如 ==, !=, in, > 等。
<value>: 要比较的值,值的类型取决于连接追踪表达式类型,例如状态是关键字,IP 地址是 IP 地址,端口是端口号。

应用示例

允许已建立和关联的连接:这是构建有状态防火墙的基础规则。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input ct state established,related accept

▮▮▮▮⚝ ct state established,related: 匹配连接状态为 establishedrelated 的连接。

阻止新的入站连接,除非是已建立连接的回复:更严格的入站策略,只允许已建立连接的回包进入。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input ct state { established, related } accept
2 nft add rule inet filter input ct state new drop

▮▮▮▮⚝ 第一条规则允许 establishedrelated 状态的连接。
▮▮▮▮⚝ 第二条规则丢弃所有 new 状态的连接,从而实现默认拒绝新连接。

基于连接方向进行策略控制:例如,只允许从内网到外网的 HTTP 请求,但不允许外网主动发起 HTTP 连接。假设内网接口为 eth0,外网接口为 eth1

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward iifname "eth0" oifname "eth1" ct dir original tcp dport 80 accept
2 nft add rule inet filter forward iifname "eth1" oifname "eth0" ct dir reply tcp sport 80 accept

▮▮▮▮⚝ 第一条规则允许从 eth0eth1 的原始方向的 HTTP 请求。
▮▮▮▮⚝ 第二条规则允许从 eth1eth0 的回复方向的 HTTP 响应。

基于连接追踪标记进行策略路由:先使用规则标记特定连接,然后在路由策略中使用连接标记。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward ip daddr 192.168.1.100 ct mark set 1
2 nft add rule inet filter forward ct mark 1 counter # 统计标记连接的流量

▮▮▮▮⚝ 第一条规则将目标地址为 192.168.1.100 的连接标记为 1。
▮▮▮▮⚝ 第二条规则匹配 conntrack mark 为 1 的连接,并进行计数。后续可以在路由策略中基于 conntrack mark 进行路由。

限制单个 IP 的并发连接数:使用 ct count 和集合 (sets) 实现。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add set inet filter src_limit { type ipv4_addr; flags dynamic,timeout 10m; }
2 nft add rule inet filter input ip protocol tcp ct state new ip saddr @src_limit limit rate over 10/minute drop
3 nft add rule inet filter input ip protocol tcp ct state new ip saddr @src_limit add @src_limit { ip saddr timeout 10m } accept

▮▮▮▮⚝ src_limit 集合用于存储源 IP 地址,并设置动态超时。
▮▮▮▮⚝ 第一条规则限制每分钟超过 10 个新连接的 IP 地址,超过则丢弃。
▮▮▮▮⚝ 第二条规则将源 IP 地址添加到 src_limit 集合,并允许连接。

注意事项

连接追踪开销:连接追踪会消耗系统资源,特别是 CPU 和内存。对于高并发连接的场景,需要合理配置连接追踪参数,例如调整连接追踪表大小、超时时间等,以优化性能。
状态同步:在集群环境中,需要考虑连接追踪状态的同步,以保证防火墙策略的一致性。可以使用 conntrackd 等工具进行连接追踪状态同步。
协议助手(Helpers):对于一些复杂的协议(例如 FTP、SIP),需要使用连接追踪助手(conntrack helpers)来正确追踪连接状态和关联连接。nftables 可以自动加载和使用协议助手。
notrack 规则:可以使用 notrack 动作来显式地禁用某些流量的连接追踪,以减少连接追踪开销。例如,对于不需要状态检测的流量,可以使用 notrack 动作。

ct 表达式是构建有状态防火墙和实现高级网络安全策略的核心工具。通过灵活运用 ct 表达式,可以实现基于连接状态、方向、协议等多种维度的精细化访问控制和安全防护。

4.1.4 limit 表达式:速率限制与流量控制

limit 表达式是 nftables 中用于实现速率限制和流量控制的重要工具。它允许规则基于数据包的速率或频率进行匹配,从而可以限制特定类型流量的带宽、连接速率等,有效地防止 DDoS 攻击、滥用资源等问题,并实现基本的 QoS (Quality of Service) 功能。

基本概念

速率(Rate):指单位时间内数据包或字节的数量,例如 "packets per second" (pps) 或 "bytes per second" (Bps)。
突发(Burst):允许在短时间内超过设定速率的量,通常以数据包或字节数表示。突发值越大,允许的短期峰值流量越高,但也会增加延迟。
平均速率(Average Rate):在一段时间内测量的平均速率。limit 表达式通常基于平均速率进行匹配。
令牌桶算法(Token Bucket Algorithm):limit 表达式通常基于令牌桶算法实现速率限制。令牌桶以设定的速率生成令牌,每个数据包消耗一个或多个令牌。当令牌桶中有足够的令牌时,数据包被允许通过;否则,数据包被限制或丢弃。

语法结构

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 limit rate { <rate> | <number> <unit>/<time_unit> } [burst <packets>] [bytes]

rate: 速率值,可以使用简写形式,例如 100pkt/sec, 10mbit/minute
<number> <unit>/<time_unit>: 速率的详细表示,例如 100 packets/second, 10 megabytes/minute
▮▮▮▮⚝ <unit>: 单位,可以是 pkt (packets), byte (bytes), kbyte, mbyte, gbyte, kbit, mbit, gbit.
▮▮▮▮⚝ <time_unit>: 时间单位,可以是 second, minute, hour, day.
burst <packets>: 突发值,以数据包数量表示。默认突发值为 5 个数据包。
bytes: 可选关键字,如果指定,则速率限制基于字节数,而不是数据包数。

应用示例

限制 ICMP 流量速率:限制每秒钟最多允许 10 个 ICMP 数据包通过,突发值为 20 个数据包。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input ip protocol icmp limit rate 10/second burst 20 packets log prefix "ICMP Rate Limited: " drop

▮▮▮▮⚝ limit rate 10/second burst 20 packets: 设置速率限制为每秒 10 个数据包,突发值为 20 个数据包。超过速率限制的 ICMP 数据包将被丢弃。

限制 SSH 连接速率:限制每分钟最多允许 5 个新的 SSH 连接。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input tcp dport 22 ct state new limit rate 5/minute log prefix "SSH Connection Rate Limited: " drop

▮▮▮▮⚝ limit rate 5/minute: 设置速率限制为每分钟 5 个连接。超过速率限制的新 SSH 连接将被丢弃。

限制 HTTP 流量带宽:限制 HTTP 流量的带宽为 1 Mbps。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward tcp dport 80 limit rate 1mbit/second bytes log prefix "HTTP Bandwidth Limited: " drop

▮▮▮▮⚝ limit rate 1mbit/second bytes: 设置速率限制为 1 Mbps,并基于字节数进行限制。超过带宽限制的 HTTP 流量将被丢弃。

允许一定速率的流量,超出速率则跳转到另一个链进行处理:例如,允许每秒 100 个数据包的正常流量通过,超出速率的流量跳转到 rate_limit_chain 进行更细致的处理(例如,更严格的限制或标记)。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add chain inet filter rate_limit_chain { policy accept; }
2 nft add rule inet filter input limit rate 100/second jump rate_limit_chain
3 nft add rule inet filter input drop # 默认丢弃超出速率的流量 (在 rate_limit_chain 处理后)

▮▮▮▮⚝ 第一条规则创建名为 rate_limit_chain 的链。
▮▮▮▮⚝ 第二条规则使用 limit rate 100/second jump rate_limit_chain。如果流量速率在限制范围内,则跳转到 rate_limit_chain 进行处理;如果超出速率,则继续执行下一条规则。
▮▮▮▮⚝ 第三条规则默认丢弃所有流量(实际上是超出速率限制的流量,因为正常速率的流量已经跳转到 rate_limit_chain 处理)。在 rate_limit_chain 中可以添加更复杂的速率限制或流量整形规则。

使用集合 (sets) 实现基于源 IP 的速率限制:对每个源 IP 地址进行独立的速率限制。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add set inet filter src_rate_limit { type ipv4_addr; flags dynamic,timeout 10m; }
2 nft add rule inet filter input ip protocol tcp ct state new ip saddr @src_rate_limit limit rate 10/minute burst 5 packets log prefix "Source IP Rate Limited: " drop
3 nft add rule inet filter input ip protocol tcp ct state new ip saddr @src_rate_limit add @src_rate_limit { ip saddr timeout 10m } accept

▮▮▮▮⚝ src_rate_limit 集合用于跟踪源 IP 地址。
▮▮▮▮⚝ 第一条规则限制来自集合中 IP 地址的新 TCP 连接速率为每分钟 10 个。
▮▮▮▮⚝ 第二条规则将源 IP 地址添加到集合,并允许连接。

注意事项

精度和延迟:limit 表达式的速率限制精度受到系统时钟分辨率和数据包处理延迟的影响。在非常高精度的速率限制场景中,可能需要结合更专业的流量整形工具(例如 tc)。
状态维护:limit 表达式需要维护每个规则的速率计数器和令牌桶状态,这会消耗一定的内存和 CPU 资源。规则数量过多时,可能会影响性能。
突发值设置:突发值设置过小可能导致正常突发流量被限制,设置过大则可能无法有效抑制恶意流量。需要根据实际应用场景合理设置突发值。
与 QoS 的结合:limit 表达式可以作为 QoS 策略的基础组件,但更复杂的 QoS 需求可能需要结合 Linux 的流量控制框架 (tc) 和队列规则 (qdisc) 来实现更精细的流量管理和优先级控制。

limit 表达式是 nftables 中实现基本速率限制和流量控制的有效手段。它可以用于保护网络资源、防止滥用和简单 QoS 场景。在实际应用中,需要根据具体需求和性能要求,合理配置速率、突发值等参数,并结合其他 nftables 功能和 Linux 流量控制工具,构建完善的网络流量管理策略。

4.1.5 rt 表达式:路由信息匹配

rt 表达式(routing expression)是 nftables 中用于匹配路由信息的表达式。它允许规则基于数据包的路由查找结果进行匹配,例如输出路由的类型、下一跳地址、路由表 ID 等。rt 表达式使得防火墙规则可以根据数据包的路由路径进行策略决策,从而实现更高级的策略路由、基于路由的过滤等功能。

常见的 rt 表达式类型

路由类型
▮▮▮▮⚝ rt type:匹配路由类型,例如 unicast(单播路由)、local(本地路由)、broadcast(广播路由)、multicast(多播路由)、unreachable(不可达路由)、prohibit(禁止路由)、blackhole(黑洞路由)、nat(NAT 路由)。

路由表 ID
▮▮▮▮⚝ rt table:匹配路由表 ID。Linux 系统中可以存在多个路由表,例如主路由表(ID 254)、本地路由表(ID 255)以及用户自定义的路由表。

下一跳信息
▮▮▮▮⚝ rt nexthop:匹配下一跳 IP 地址。
▮▮▮▮⚝ rt nexthop dev:匹配下一跳输出设备名称。
▮▮▮▮⚝ rt nexthop scope:匹配下一跳路由的作用域(scope),例如 host(主机)、link(链路)、global(全局)。
▮▮▮▮⚝ rt nexthop gateway:匹配下一跳网关地址。

路由策略数据库 (RPDB) 信息
▮▮▮▮⚝ rt classid:匹配路由策略规则的类 ID。路由策略数据库 (RPDB) 允许根据源/目标地址、TOS 等条件选择不同的路由表。
▮▮▮▮⚝ rt realm:匹配路由策略规则的 realm 值。Realm 是一种更高级的路由策略标记,可以用于更复杂的路由选择。

源路由信息
▮▮▮▮⚝ rt saddr:匹配源路由(source routing)指定的源地址。
▮▮▮▮⚝ rt daddr:匹配源路由指定的目标地址。

语法结构

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 rt

<rt_expression_type>: 路由表达式类型,例如 type, table, nexthop, classid 等。
<comparison_operator>: 比较操作符,例如 ==, !=, in, > 等。
<value>: 要比较的值,值的类型取决于路由表达式类型,例如路由类型是关键字,路由表 ID 是整数,IP 地址是 IP 地址。

应用示例

匹配本地路由流量:只允许目标地址为本地地址的流量通过。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter output rt type local accept

▮▮▮▮⚝ rt type local: 匹配路由类型为 local 的数据包,即目标地址为本机地址的数据包。

基于路由表 ID 进行过滤:只允许通过特定路由表(例如,路由表 ID 为 100)的流量通过。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward rt table 100 accept

▮▮▮▮⚝ rt table 100: 匹配路由表 ID 为 100 的数据包。这通常用于策略路由场景,不同的路由表对应不同的路由策略。

匹配下一跳地址:阻止所有下一跳地址为 192.168.1.1 的流量。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward rt nexthop 192.168.1.1 drop

▮▮▮▮⚝ rt nexthop 192.168.1.1: 匹配下一跳地址为 192.168.1.1 的数据包。

基于下一跳输出设备进行策略路由:将特定流量通过指定的输出设备发送。例如,将目标地址为 10.0.0.0/8 的流量通过 eth1 接口发送。这通常需要结合 route 表和链。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward ip daddr 10.0.0.0/8 rt nexthop dev "eth1" accept

▮▮▮▮⚝ rt nexthop dev "eth1": 匹配下一跳输出设备名称为 "eth1" 的数据包。

基于路由策略规则的类 ID 进行策略控制:假设路由策略规则中,类 ID 为 1 的规则用于标记需要特殊处理的流量。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward rt classid 1 log prefix "Policy Routed Traffic: " accept

▮▮▮▮⚝ rt classid 1: 匹配路由策略规则类 ID 为 1 的数据包。这需要预先配置路由策略规则 (使用 ip rule 命令)。

匹配不可达路由:记录所有由于路由不可达而被丢弃的数据包。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter output rt type unreachable log prefix "Unreachable Route: " drop

▮▮▮▮⚝ rt type unreachable: 匹配路由类型为 unreachable 的数据包。

注意事项

路由查找时机:rt 表达式的匹配发生在路由查找之后。对于 input 链,路由查找在 input hook 之前完成,因此 input 链规则无法使用 rt 表达式。rt 表达式主要用于 forwardoutput 链。
路由策略配置:要有效使用 rt 表达式,通常需要结合 Linux 的路由策略数据库 (RPDB) 进行配置。可以使用 ip rule 命令添加和管理路由策略规则。
性能开销:rt 表达式的匹配效率较高,因为路由信息通常在内核中已经计算和缓存。但过多的路由策略规则可能会增加路由查找的开销。
适用场景:rt 表达式适用于需要基于路由路径进行策略控制的场景,例如策略路由、多出口网络、VPN 网关等。它可以实现更灵活、更智能的流量转发和过滤策略。

rt 表达式是 nftables 中一个高级且强大的功能,它将防火墙规则与路由决策紧密结合,为网络策略控制提供了更丰富的维度和更精细的粒度。合理利用 rt 表达式可以构建复杂的策略路由和基于路由的网络安全体系。

4.2 语句(Statements)扩展

4.2.1 counter:数据包计数器

counter 语句是 nftables 中最基本的语句之一,用于对匹配规则的数据包和字节进行计数。它提供了一种简单而有效的方式来监控网络流量,统计规则的匹配次数和流量大小,为网络管理和性能分析提供数据支持。

基本功能

数据包计数:记录匹配规则的数据包数量。
字节计数:记录匹配规则的数据包的总字节数。
原子性操作:计数操作是原子性的,即使在高并发环境下也能保证计数的准确性。
可读性输出:使用 nft list ruleset 命令可以方便地查看计数器的值。

语法结构

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 counter [name ]

name <counter_name>: 可选参数,用于为计数器指定一个名称。如果未指定名称,nftables 会自动生成一个唯一的名称。使用名称可以更方便地引用和管理计数器。

应用示例

统计所有入站 HTTP 流量:创建一个规则,对所有入站的 HTTP 流量进行计数。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input tcp dport 80 counter name http_in_counter accept

▮▮▮▮⚝ counter name http_in_counter: 为该规则添加一个名为 http_in_counter 的计数器。所有匹配该规则的入站 HTTP 数据包都会被计数。

统计特定源 IP 地址的流量:统计来自 192.168.1.100 的所有流量。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input ip saddr 192.168.1.100 counter name src_ip_counter accept

▮▮▮▮⚝ counter name src_ip_counter: 为该规则添加一个名为 src_ip_counter 的计数器,统计来自 192.168.1.100 的流量。

统计被丢弃的 ICMP 流量:统计被防火墙丢弃的 ICMP 数据包数量。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input ip protocol icmp counter name dropped_icmp_counter drop

▮▮▮▮⚝ counter name dropped_icmp_counter: 为该规则添加一个名为 dropped_icmp_counter 的计数器,统计被丢弃的 ICMP 数据包。

查看计数器值:使用 nft list ruleset 命令查看规则集,计数器的值会显示在规则旁边。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft list ruleset

▮▮▮▮输出示例:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table inet filter {
2 chain input {
3 type filter hook input priority 0; policy accept;
4 tcp dport 80 counter name http_in_counter packets 1234 bytes 56789 accept comment "HTTP Inbound Traffic Counter"
5 ip saddr 192.168.1.100 counter name src_ip_counter packets 500 bytes 10000 accept comment "Source IP Traffic Counter"
6 ip protocol icmp counter name dropped_icmp_counter packets 100 bytes 2000 drop comment "Dropped ICMP Counter"
7 }
8 }

▮▮▮▮⚝ packets 1234 bytes 56789: 显示 http_in_counter 计数器已匹配 1234 个数据包,总字节数为 56789 字节。

重置计数器:可以使用 nft flush counter <counter_name> 命令重置计数器的值。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft flush counter http_in_counter

▮▮▮▮⚝ 执行此命令后,http_in_counter 的数据包计数和字节计数将被重置为 0。

注意事项

性能影响counter 语句的性能开销非常小,几乎可以忽略不计。在大多数场景下,可以放心地使用 counter 语句进行流量统计。
计数器持久性:nftables 计数器是运行时数据,不会持久化存储。当 nftables 服务重启或系统重启时,计数器值会被重置为 0。如果需要持久化存储计数器数据,需要定期将计数器值导出并保存到外部存储介质中。
命名规范:建议为计数器指定有意义的名称,以便于管理和识别。可以使用下划线或连字符分隔单词,例如 http_in_counter, dropped-icmp-counter
与其他语句的组合counter 语句可以与任何其他 nftables 语句组合使用,例如 accept, drop, log, queue 等。它可以作为规则的附加功能,在执行其他动作的同时进行流量统计。

counter 语句是 nftables 中一个简单但非常实用的工具,它为网络流量监控、规则性能评估、安全事件分析等提供了基础数据。合理使用 counter 语句可以提升网络管理的可见性和可控性。

4.2.2 meter:流量计量器

meter 语句是 nftables 中用于实现更高级流量控制和计量功能的语句。它基于令牌桶算法,可以对匹配规则的流量进行计量,并根据预设的阈值触发不同的动作。meter 语句比 limit 表达式更灵活,可以实现更复杂的流量整形、带宽控制、和基于流量的策略决策。

基本概念

计量器(Meter):一个命名的对象,用于跟踪和计量流量。每个计量器都有一个或多个带阈值的条目(entries)。
条目(Entry):计量器中的一个规则,定义了流量阈值和超出阈值时触发的动作。每个条目可以设置不同的速率和突发值。
速率(Rate):计量器条目定义的速率阈值,例如 "100kbps", "1000pps"。
突发(Burst):计量器条目定义的突发阈值,例如 "10kb", "100 packets"。
动作(Action):当流量超出计量器条目的阈值时触发的动作,例如 drop, reject, queue, mark 等。

语法结构

创建计量器

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 add meter inet filter { type }

▮▮▮▮⚝ <meter_name>: 计量器名称。
▮▮▮▮⚝ <flags>: 计量器标志,例如 flags { static } 表示静态计量器(默认),flags { dynamic } 表示动态计量器(不常用)。
▮▮▮▮⚝ <type>: 计量器类型,目前只有 type rate 可用,表示基于速率的计量器。

添加计量器条目

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 add rule inet filter meter name over { rate burst }

▮▮▮▮⚝ <chain_name>: 链名称。
▮▮▮▮⚝ <match_criteria>: 匹配条件,例如 tcp dport 80, ip saddr 192.168.1.0/24
▮▮▮▮⚝ meter name <meter_name> <entry_name>: 指定使用的计量器名称和条目名称。
▮▮▮▮⚝ over { rate <rate> burst <burst> }: 定义速率和突发阈值。
▮▮▮▮⚝ <action>: 超出阈值时触发的动作。

应用示例

限制 HTTP 流量带宽:创建一个计量器,限制 HTTP 流量的带宽为 1 Mbps。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add meter inet filter http_meter { type rate }
2 nft add rule inet filter forward tcp dport 80 meter name http_meter http_entry over { rate 1mbit/second burst 10kbyte } drop
3 nft add rule inet filter forward tcp dport 80 accept # 默认允许流量,除非超出计量器限制

▮▮▮▮⚝ 第一条规则创建名为 http_meter 的计量器。
▮▮▮▮⚝ 第二条规则添加计量器条目 http_entry,设置速率阈值为 1 Mbps,突发值为 10 KB。如果 HTTP 流量超出阈值,则执行 drop 动作。
▮▮▮▮⚝ 第三条规则默认允许 HTTP 流量,除非被计量器条目匹配并丢弃。

基于源 IP 地址的带宽限制:为每个源 IP 地址创建独立的计量器,限制每个源 IP 的带宽。这需要结合集合 (sets) 和动态计量器。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add set inet filter src_meter_set { type ipv4_addr; flags dynamic; }
2 nft add meter inet filter dynamic_meter { flags dynamic; type rate; }
3 nft add rule inet filter input ip saddr @src_meter_set meter name dynamic_meter @src_meter_set over { rate 100kbit/second burst 1kbyte } drop
4 nft add rule inet filter input ip saddr @src_meter_set add @src_meter_set { ip saddr } accept

▮▮▮▮⚝ src_meter_set 集合用于存储源 IP 地址。
▮▮▮▮⚝ dynamic_meter 是动态计量器,可以为集合中的每个元素(源 IP 地址)动态创建计量器实例。
▮▮▮▮⚝ 第一条规则限制来自 src_meter_set 集合中 IP 地址的流量,每个 IP 地址的带宽限制为 100 kbps,突发值为 1 KB。
▮▮▮▮⚝ 第二条规则将源 IP 地址添加到 src_meter_set 集合,并允许流量(除非超出计量器限制)。

多级流量控制:使用多个计量器条目实现多级流量控制策略。例如,当流量超出第一个阈值时进行标记,超出第二个阈值时进行丢弃。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add meter inet filter multi_level_meter { type rate }
2 nft add rule inet filter forward tcp dport 80 meter name multi_level_meter level1 over { rate 5mbit/second burst 50kbyte } mark set 1
3 nft add rule inet filter forward tcp dport 80 meter name multi_level_meter level2 over { rate 10mbit/second burst 100kbyte } drop
4 nft add rule inet filter forward tcp dport 80 accept

▮▮▮▮⚝ multi_level_meter 计量器包含两个条目 level1level2
▮▮▮▮⚝ 如果 HTTP 流量超出 5 Mbps,level1 条目被触发,数据包被标记为 1。
▮▮▮▮⚝ 如果 HTTP 流量超出 10 Mbps,level2 条目被触发,数据包被丢弃。
▮▮▮▮⚝ 默认情况下,HTTP 流量被允许。

注意事项

计量器管理:计量器是命名的对象,需要显式创建和管理。可以使用 nft list meters 查看已创建的计量器,使用 nft delete meter <meter_name> 删除计量器。
条目顺序:计量器条目的顺序很重要。nftables 会按照条目定义的顺序进行匹配。一旦匹配到某个条目,就会执行相应的动作,并停止匹配后续条目。
性能开销meter 语句的性能开销比 limit 表达式略高,但仍然相对高效。动态计量器会消耗更多的资源,因为需要为每个动态元素维护独立的计量器实例。
与 QoS 的结合meter 语句是实现高级 QoS 策略的重要组件。可以结合 mark 语句和 Linux 流量控制框架 (tc) 实现更精细的流量整形、优先级控制和带宽管理。

meter 语句是 nftables 中功能强大的流量计量和控制工具。它提供了比 limit 表达式更灵活、更可扩展的流量管理能力,可以用于实现各种复杂的流量整形、带宽限制、和基于流量的策略决策。

4.2.3 quota:流量配额

quota 语句是 nftables 中用于实现流量配额管理的语句。它允许规则基于预设的流量配额进行匹配,当流量使用量达到或超过配额时,可以触发相应的动作。quota 语句适用于需要限制用户或应用的流量使用量、实现按流量计费、或进行资源分配的场景。

基本概念

配额(Quota):预先设定的流量限制,通常以字节数表示,例如 "1GB", "100MB"。
已用流量(Used):计量器跟踪的已使用的流量量。
阈值(Threshold):配额值,当已用流量达到或超过阈值时,触发动作。
动作(Action):当流量配额达到或超过阈值时触发的动作,例如 drop, reject, queue, mark 等。
重置(Reset):可以将已用流量计数器重置为 0,重新开始计量。

语法结构

创建配额

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 add quota inet filter { type bytes }

▮▮▮▮⚝ <quota_name>: 配额名称。
▮▮▮▮⚝ <type>: 配额类型,目前只有 type limit 可用,表示限制流量配额。
▮▮▮▮⚝ <bytes>: 配额大小,以字节数表示,可以使用单位,例如 1G, 100M.

使用配额

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 add rule inet filter quota name over

▮▮▮▮⚝ <chain_name>: 链名称。
▮▮▮▮⚝ <match_criteria>: 匹配条件,例如 tcp dport 80, ip saddr 192.168.1.0/24
▮▮▮▮⚝ quota name <quota_name>: 指定使用的配额名称。
▮▮▮▮⚝ over: 关键字,表示当流量配额超过阈值时触发动作。
▮▮▮▮⚝ <action>: 超出配额时触发的动作。

应用示例

限制单个 IP 地址的下载流量:为 IP 地址 192.168.1.100 设置 1GB 的下载流量配额。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add quota inet filter download_quota { type limit bytes 1G }
2 nft add rule inet filter forward ip daddr 192.168.1.100 quota name download_quota over drop
3 nft add rule inet filter forward ip daddr 192.168.1.100 accept # 默认允许流量,除非超出配额

▮▮▮▮⚝ 第一条规则创建名为 download_quota 的配额,大小为 1GB。
▮▮▮▮⚝ 第二条规则使用 download_quota 配额,当目标地址为 192.168.1.100 的流量超出配额时,执行 drop 动作。
▮▮▮▮⚝ 第三条规则默认允许目标地址为 192.168.1.100 的流量,除非被配额限制。

限制特定用户的每月流量:假设通过某种方式(例如,基于用户认证)可以识别用户流量,并将其标记 (mark)。为标记为 1 的流量设置每月 10GB 的配额。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add quota inet filter user_quota { type limit bytes 10G }
2 nft add rule inet filter forward meta mark 1 quota name user_quota over reject # 超出配额拒绝连接
3 nft add rule inet filter forward meta mark 1 accept # 默认允许流量,除非超出配额

▮▮▮▮⚝ user_quota 配额大小为 10GB。
▮▮▮▮⚝ 第一条规则使用 user_quota 配额,当标记为 1 的流量超出配额时,执行 reject 动作,拒绝连接。
▮▮▮▮⚝ 第二条规则默认允许标记为 1 的流量,除非被配额限制。

查看配额使用情况:使用 nft list quota <quota_name> 命令查看配额的已用流量和剩余流量。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft list quota download_quota

▮▮▮▮输出示例:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 quota download_quota {
2 type limit bytes 1073741824
3 bytes 123456789 # 已用字节数
4 }

▮▮▮▮⚝ bytes 123456789: 显示 download_quota 配额已使用 123456789 字节。

重置配额:可以使用 nft reset quota <quota_name> 命令将配额的已用流量计数器重置为 0。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft reset quota download_quota

▮▮▮▮⚝ 执行此命令后,download_quota 的已用流量计数将被重置为 0,配额重新开始计算。

注意事项

配额管理:配额是命名的对象,需要显式创建和管理。可以使用 nft list quotas 查看已创建的配额,使用 nft delete quota <quota_name> 删除配额。
配额类型:目前 quota 语句只支持 limit 类型,即限制总流量配额。未来可能会扩展支持更多配额类型,例如时间配额、连接数配额等。
配额精度quota 语句的配额计量精度取决于数据包的大小和流量模式。在小数据包和高并发场景下,配额计量可能存在一定的误差。
与计费系统的集成quota 语句可以作为流量计费系统的基础组件。可以将配额使用情况导出到计费系统,实现按流量计费、流量预警、流量控制等功能。
重置策略:配额的重置策略需要根据实际应用场景进行设计。可以手动重置配额,也可以结合定时任务或外部脚本自动重置配额,例如每月初重置用户流量配额。

quota 语句是 nftables 中实现流量配额管理的关键工具。它可以用于限制用户或应用的流量使用量,实现资源分配和流量计费。合理使用 quota 语句可以有效地管理网络流量,优化资源利用率,并提供更灵活的网络服务。

4.2.4 masqueradesnatdnat:NAT 相关语句详解

masqueradesnatdnat 是 nftables 中用于实现网络地址转换 (NAT, Network Address Translation) 的关键语句。NAT 是一种将私有网络地址转换为公有网络地址的技术,广泛应用于家庭网络、企业内网等场景,用于解决 IPv4 地址短缺、隐藏内部网络拓扑、增强网络安全性等问题。nftables 提供了灵活且强大的 NAT 功能,支持多种 NAT 类型和配置方式。

NAT 类型

源地址转换 (SNAT, Source NAT):将数据包的源 IP 地址和/或源端口进行转换。SNAT 通常用于将私有网络内部的主机访问公网时,将其源地址转换为公网 IP 地址。
▮▮▮▮⚝ snat 语句:显式指定 SNAT 的转换地址和端口。
▮▮▮▮⚝ masquerade 语句:一种特殊的 SNAT,自动使用输出接口的 IP 地址作为转换地址,适用于动态 IP 地址环境。

目标地址转换 (DNAT, Destination NAT):将数据包的目标 IP 地址和/或目标端口进行转换。DNAT 通常用于将公网访问请求转发到私有网络内部的服务器,实现端口转发、负载均衡等功能。
▮▮▮▮⚝ dnat 语句:显式指定 DNAT 的转换地址和端口。

masquerade 语句

功能:实现伪装 (masquerade) 类型的 SNAT。masquerade 会自动获取数据包输出接口的 IP 地址,并将其作为 SNAT 的转换地址。当输出接口的 IP 地址动态变化时(例如,DHCP 获取的 IP 地址),masquerade 能够自动适应,无需手动更新规则。
适用场景:动态 IP 地址环境,例如家庭宽带路由器、移动热点等。
语法结构

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 masquerade [to <ipaddr>[:<port>-<port>]] [proto { tcp | udp | sctp | dccp }] [random] [persistent]

▮▮▮▮⚝ to <ipaddr>[:<port>-<port>]: 可选参数,指定伪装使用的源 IP 地址和端口范围。通常情况下,masquerade 会自动使用输出接口的 IP 地址。可以指定一个固定的 IP 地址,但通常不推荐,因为 masquerade 的主要优势在于自动适应动态 IP 地址。
▮▮▮▮⚝ proto { tcp | udp | sctp | dccp }: 可选参数,指定协议类型。默认情况下,masquerade 适用于所有协议。可以限制只对特定协议应用伪装。
▮▮▮▮⚝ random: 可选参数,使用随机端口进行源端口转换。默认行为。
▮▮▮▮⚝ persistent: 可选参数,尝试为同一连接保持相同的源端口映射。

应用示例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat postrouting oifname "eth0" masquerade

▮▮▮▮⚝ 此规则将所有通过 eth0 接口输出的数据包应用伪装 NAT。数据包的源 IP 地址将被转换为 eth0 接口的 IP 地址。

snat 语句

功能:实现显式的 SNAT。snat 语句需要明确指定转换后的源 IP 地址和/或端口范围。
适用场景:静态 IP 地址环境,需要精确控制 SNAT 转换地址和端口的场景。
语法结构

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 snat to <ipaddr>[:<port>-<port>] [proto { tcp | udp | sctp | dccp }] [random] [persistent]

▮▮▮▮⚝ to <ipaddr>[:<port>-<port>]: 必须参数,指定 SNAT 的转换地址和端口范围。可以指定单个 IP 地址或 IP 地址范围,以及端口范围。
▮▮▮▮⚝ proto { tcp | udp | sctp | dccp }: 可选参数,指定协议类型。
▮▮▮▮⚝ random: 可选参数,使用随机端口进行源端口转换。默认行为。
▮▮▮▮⚝ persistent: 可选参数,尝试为同一连接保持相同的源端口映射。

应用示例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat postrouting oifname "eth0" snat to 203.0.113.10

▮▮▮▮⚝ 此规则将所有通过 eth0 接口输出的数据包应用 SNAT,将其源 IP 地址转换为 203.0.113.10

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat postrouting oifname "eth0" snat to 203.0.113.10:10000-20000

▮▮▮▮⚝ 此规则将 SNAT 的转换地址设置为 203.0.113.10,并将源端口范围限制在 10000-20000。

dnat 语句

功能:实现 DNAT。dnat 语句需要明确指定转换后的目标 IP 地址和/或端口范围。
适用场景:端口转发、负载均衡、将公网请求转发到内网服务器等场景。
语法结构

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 dnat to <ipaddr>[:<port>-<port>] [proto { tcp | udp | sctp | dccp }] [random] [persistent]

▮▮▮▮⚝ to <ipaddr>[:<port>-<port>]: 必须参数,指定 DNAT 的转换地址和端口范围。可以指定单个 IP 地址或 IP 地址范围,以及端口范围。
▮▮▮▮⚝ proto { tcp | udp | sctp | dccp }: 可选参数,指定协议类型。
▮▮▮▮⚝ random: 可选参数,使用随机端口进行目标端口转换(通常不用于 DNAT)。
▮▮▮▮⚝ persistent: 可选参数,尝试为同一连接保持相同的目标端口映射。

应用示例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat prerouting tcp dport 80 dnat to 192.168.1.100:80

▮▮▮▮⚝ 此规则将所有目标端口为 80 的 TCP 数据包应用 DNAT,将其目标地址转换为 192.168.1.100,目标端口转换为 80。实现将公网 80 端口的请求转发到内网服务器 192.168.1.100:80

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat prerouting tcp dport 2222 dnat to 192.168.1.101:22

▮▮▮▮⚝ 此规则将公网 2222 端口的 TCP 请求转发到内网服务器 192.168.1.101 的 22 端口(SSH)。

NAT 链和 hook 点

nat:NAT 相关规则通常放在 nat 表中。
prerouting:DNAT 规则通常放在 nat 表的 prerouting 链中,在路由决策之前进行目标地址转换。
postrouting:SNAT 和 masquerade 规则通常放在 nat 表的 postrouting 链中,在路由决策之后、数据包即将发出之前进行源地址转换。
inputforward:在 filter 表的 inputforward 链中,可以对经过 NAT 转换后的数据包进行过滤。

注意事项

连接追踪:NAT 功能依赖于连接追踪。nftables 会自动为 NAT 连接创建连接追踪条目,跟踪 NAT 转换关系。
端口冲突:SNAT 和 masquerade 在进行端口转换时,可能会遇到端口冲突的问题。nftables 会尽量避免端口冲突,但在高并发场景下,仍有可能发生端口耗尽。
协议助手:对于一些复杂的协议(例如 FTP、SIP),需要使用连接追踪助手 (conntrack helpers) 来正确处理 NAT 场景下的连接和端口映射。nftables 可以自动加载和使用协议助手。
性能影响:NAT 功能会增加数据包处理的开销,特别是 DNAT 规则较多时,可能会影响性能。应尽量优化 NAT 规则,避免不必要的 NAT 转换。
安全风险:不当的 NAT 配置可能会引入安全风险。例如,开放过多的端口转发可能会暴露内网服务。应谨慎配置 DNAT 规则,并结合防火墙规则进行安全防护。

masqueradesnatdnat 语句是 nftables 中实现 NAT 功能的核心组件。它们提供了灵活的 NAT 配置选项,可以满足各种 NAT 应用场景的需求。合理配置 NAT 规则可以有效地实现网络地址转换、端口转发、负载均衡等功能,并增强网络安全性和管理效率。

4.2.5 redirect:端口重定向

redirect 语句是 nftables 中用于实现端口重定向(port redirection)的语句。它允许将数据包的目标端口重定向到另一个端口,通常用于将流量重定向到本地主机的不同端口,实现透明代理、端口映射、应用层负载均衡等功能。redirect 语句是 DNAT 的一种特殊形式,但它只能将目标地址重定向到本地主机。

基本功能

端口重定向:将数据包的目标端口修改为指定的端口。目标 IP 地址始终为本地主机地址 (127.0.0.1 或 ::1)。
协议支持:支持 TCP、UDP、SCTP 和 DCCP 协议。
本地重定向:只能将流量重定向到本地主机。不能将流量重定向到远程主机。
连接追踪redirect 语句依赖于连接追踪。nftables 会自动为重定向连接创建连接追踪条目。

语法结构

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 redirect to :- [proto { tcp | udp | sctp | dccp }]

to :<port>-<port>: 必须参数,指定重定向的目标端口范围。可以指定单个端口或端口范围。目标 IP 地址默认为本地主机地址。
proto { tcp | udp | sctp | dccp }: 可选参数,指定协议类型。默认情况下,redirect 适用于所有协议。可以限制只对特定协议应用重定向。

应用示例

将所有入站 HTTP 流量重定向到本地 8080 端口:实现一个简单的透明 HTTP 代理。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat prerouting tcp dport 80 redirect to :8080

▮▮▮▮⚝ 此规则将所有目标端口为 80 的 TCP 数据包重定向到本地主机的 8080 端口。例如,当访问本机的 80 端口时,流量会被重定向到本地运行在 8080 端口的 HTTP 代理服务。

将特定端口范围的 UDP 流量重定向到另一个端口范围:例如,将 UDP 端口 10000-10100 的流量重定向到本地的 20000-20100 端口范围。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat prerouting udp dport 10000-10100 redirect to :20000-20100

▮▮▮▮⚝ 此规则将目标端口在 10000-10100 范围内的 UDP 数据包重定向到本地主机的 20000-20100 端口范围。

将所有入站 TCP 流量重定向到本地的同一个端口:例如,将所有入站 TCP 流量都重定向到本地的 12345 端口。这在某些特殊场景下可能有用,例如,将所有入站 TCP 服务都统一到一个端口进行处理。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat prerouting tcp redirect to :12345

▮▮▮▮⚝ 此规则将所有入站 TCP 数据包重定向到本地主机的 12345 端口。

结合接口和协议进行端口重定向:例如,只将从 eth0 接口进入的 TCP 80 端口流量重定向到本地 8080 端口。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat prerouting iifname "eth0" tcp dport 80 redirect to :8080

▮▮▮▮⚝ 此规则只对从 eth0 接口进入的、目标端口为 80 的 TCP 数据包进行端口重定向。

redirect 与 DNAT 的区别

目标地址redirect 只能将目标地址重定向到本地主机 (127.0.0.1 或 ::1)。DNAT 可以将目标地址重定向到任何 IP 地址,包括本地主机和远程主机。
应用场景redirect 主要用于本地端口重定向,例如透明代理、本地服务端口映射。DNAT 应用场景更广泛,包括端口转发、负载均衡、将公网请求转发到内网服务器等。
语法redirect 语法更简洁,只需要指定目标端口。DNAT 语法需要指定目标 IP 地址和端口。

注意事项

本地服务监听:使用 redirect 语句进行端口重定向后,需要在本地主机上运行相应的服务来监听重定向后的端口。例如,如果将 80 端口重定向到 8080 端口,需要在本地主机上运行一个监听 8080 端口的 HTTP 服务。
环路风险:不当的 redirect 配置可能会导致环路。例如,如果将 80 端口重定向到 80 端口,可能会造成无限循环的重定向。应谨慎配置 redirect 规则,避免环路。
性能开销redirect 语句的性能开销与 DNAT 类似,会增加数据包处理的开销。但相对于复杂的 DNAT 规则,redirect 的性能影响通常较小。
安全风险:端口重定向可能会引入安全风险。例如,将不安全的端口重定向到本地服务可能会暴露本地服务。应谨慎配置 redirect 规则,并结合防火墙规则进行安全防护。

redirect 语句是 nftables 中实现本地端口重定向的便捷工具。它简化了 DNAT 的配置,特别适用于透明代理、本地服务端口映射等场景。合理使用 redirect 语句可以实现灵活的本地流量转发和端口管理。

4.3 连接追踪(Connection Tracking)与 conntrack-ng

4.3.1 连接追踪原理与作用

连接追踪(Connection Tracking,简称 conntrack)是 Netfilter 框架的核心组件之一,它负责跟踪网络连接的状态,为有状态防火墙、NAT (Network Address Translation)、QoS (Quality of Service) 等功能提供基础支持。连接追踪模块维护着一个连接状态表,记录着网络连接的各种信息,使得防火墙可以基于连接的状态、方向、协议等属性进行更精细的策略控制。

连接追踪原理

状态维护:连接追踪模块分析每个经过网络堆栈的数据包,根据数据包的协议类型、源/目标地址、端口等信息,判断数据包所属的连接,并维护连接的状态。
状态表:连接追踪信息存储在一个内核数据结构——连接状态表(conntrack table)中。每个连接在状态表中占用一个条目(conntrack entry)。
状态转换:连接状态会随着数据包的交互而发生转换。例如,对于 TCP 连接,状态会从 NEW 变为 ESTABLISHED,再到 CLOSE_WAITFIN_WAIT 等。
超时管理:每个连接状态条目都有一个超时时间(timeout)。如果在超时时间内没有收到属于该连接的数据包,连接状态条目会被自动删除,释放资源。不同协议和连接状态有不同的默认超时时间。
协议助手(Helpers):对于一些复杂的协议(例如 FTP、SIP),连接追踪模块需要协议助手(conntrack helpers)来辅助分析协议内容,正确识别连接和关联连接。协议助手负责解析应用层协议,提取连接信息,并更新连接状态。

连接追踪的作用

有状态防火墙:连接追踪是实现有状态防火墙的基础。防火墙可以基于连接状态(例如 NEW, ESTABLISHED, RELATED)来决定是否允许数据包通过。例如,通常只允许 ESTABLISHEDRELATED 状态的入站连接,而拒绝 NEW 状态的入站连接,从而实现更安全的访问控制。
NAT (网络地址转换):NAT 功能依赖于连接追踪来记录 NAT 转换关系。当进行 SNAT 或 DNAT 时,连接追踪模块会记录原始地址和转换后地址的映射关系,确保双向通信的正确性。
QoS (服务质量):连接追踪可以为 QoS 提供连接级别的流量识别和分类。可以基于连接状态、协议类型等信息,对不同连接应用不同的 QoS 策略,例如优先级调度、带宽限制等。
安全审计和日志:连接追踪信息可以用于安全审计和日志分析。可以记录连接的建立、状态变化、流量统计等信息,用于检测异常连接、分析网络攻击、排查网络故障等。
DDoS 防护:连接追踪可以用于 DDoS 防护。例如,可以限制单个源 IP 地址的新建连接速率,防止 SYN Flood 攻击。也可以基于连接状态进行流量清洗,过滤恶意连接。

连接状态类型

NEW:新的连接,表示连接的第一个包。对于 TCP 连接,通常是 SYN 包。
ESTABLISHED:已建立的连接,表示连接已经成功建立,并且双向数据传输正常进行。对于 TCP 连接,表示三次握手已完成。
RELATED:关联连接,表示与已建立连接相关的连接。例如,FTP 数据连接与控制连接、NAT 场景下的反向连接等。连接追踪模块通过协议助手识别关联连接。
INVALID:无效连接,表示连接状态异常,例如不符合协议规范、乱序、或无法追踪的包。
UNTRACKED:未追踪的连接,表示显式地被配置为不进行连接追踪的连接。可以使用 notrack 动作禁用连接追踪。
SNAT:源地址转换连接。
DNAT:目标地址转换连接。

conntrack-ng

下一代连接追踪:conntrack-ng 是下一代连接追踪模块,旨在替代传统的 conntrack 模块。conntrack-ng 在性能、可扩展性、功能性等方面进行了改进和增强。
主要改进
▮▮▮▮⚝ 性能优化:采用更高效的数据结构和算法,提升连接追踪性能,降低 CPU 消耗。
▮▮▮▮⚝ 多核支持:更好地利用多核 CPU 架构,提高并发处理能力。
▮▮▮▮⚝ 扩展性:更易于扩展和添加新的协议助手和功能。
▮▮▮▮⚝ 用户空间工具:提供更强大的用户空间工具 ctng-tools,用于管理和监控连接追踪。
nftables 集成:nftables 默认使用 conntrack-ng 作为连接追踪模块。可以使用 ct 表达式访问和控制 conntrack-ng 的连接追踪信息。

注意事项

资源消耗:连接追踪会消耗系统资源,特别是 CPU 和内存。连接状态表的大小受系统内存限制。在高并发连接场景下,需要合理配置连接追踪参数,例如调整连接状态表大小、超时时间等,以优化性能。
状态同步:在集群环境中,需要考虑连接追踪状态的同步,以保证防火墙策略的一致性。可以使用 conntrackd 或 conntrack-ng 的同步功能进行连接追踪状态同步。
协议助手更新:协议助手需要不断更新以支持新的协议和协议版本。及时更新协议助手可以保证连接追踪的准确性和可靠性。
禁用连接追踪:在某些特定场景下,可以禁用连接追踪以减少资源消耗。例如,对于不需要状态检测的流量,可以使用 notrack 动作禁用连接追踪。但禁用连接追踪会失去有状态防火墙和 NAT 等功能。

连接追踪是现代防火墙和网络安全体系的核心技术。理解连接追踪的原理和作用,合理配置和使用连接追踪功能,对于构建安全、高效、可控的网络环境至关重要。conntrack-ng 作为下一代连接追踪模块,为 nftables 提供了更强大、更高效的连接追踪能力。

4.3.2 nftables 与 conntrack-ng 的集成

nftables 与 conntrack-ng 紧密集成,使得 nftables 规则可以充分利用 conntrack-ng 提供的连接追踪信息,实现有状态防火墙、NAT 等功能。nftables 通过 ct 表达式访问和控制 conntrack-ng 的连接追踪信息,并使用 notrack 动作禁用连接追踪。

ct 表达式集成

访问连接状态:nftables 规则可以使用 ct state 表达式匹配连接的总体状态,例如 ct state established,related 匹配已建立和关联的连接。
访问连接属性:可以使用 ct proto, ct src, ct dst, ct dir, ct timeout, ct mark, ct labelsct 表达式访问连接的协议、源/目标地址、方向、超时时间、标记、标签等属性。
细粒度状态控制:对于 TCP 连接,可以使用 ct tcp state 表达式匹配更细致的 TCP 连接状态,例如 SYN_SENT, SYN_RECV, ESTABLISHED, FIN_WAIT, CLOSE_WAIT 等。
连接计数:可以使用 ct count 表达式匹配当前连接追踪表中的连接数量,实现基于连接数的策略控制。
协议助手匹配:可以使用 ct helper 表达式匹配连接使用的 conntrack helper,例如 ct helper ftp 匹配使用 FTP 协议助手的连接。

notrack 动作集成

禁用连接追踪:nftables 规则可以使用 notrack 动作显式地禁用某些流量的连接追踪。例如,对于不需要状态检测的流量,可以使用 notrack 动作,减少连接追踪开销。
规则优先级notrack 规则的优先级高于其他规则。如果一个数据包匹配了 notrack 规则,将不会进行连接追踪,并且不会继续匹配后续的需要连接追踪的规则。
适用场景
▮▮▮▮⚝ 高吞吐量场景:对于对延迟敏感、吞吐量要求高的流量,可以禁用连接追踪,减少处理开销。
▮▮▮▮⚝ 无状态协议:对于无状态协议(例如 UDP),如果不需要状态检测,可以禁用连接追踪。
▮▮▮▮⚝ 特定流量类型:对于某些特定类型的流量,例如监控流量、日志流量等,可以禁用连接追踪。

nftables NAT 语句与连接追踪

自动连接追踪:nftables 的 masquerade, snat, dnat, redirect 等 NAT 语句会自动为 NAT 连接创建连接追踪条目,并维护 NAT 转换关系。
连接状态更新:NAT 语句在执行 NAT 转换的同时,也会更新连接追踪状态。例如,当执行 DNAT 时,连接追踪模块会记录原始目标地址和转换后目标地址的映射关系,并将连接状态标记为 DNAT
连接追踪辅助 NAT:连接追踪模块为 NAT 功能提供必要的连接信息和状态维护,保证 NAT 转换的正确性和可靠性。

配置示例

允许已建立和关联的连接:使用 ct state 表达式实现有状态防火墙。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input ct state established,related accept
2 nft add rule inet filter input drop # 默认拒绝其他入站连接

禁用特定端口的连接追踪:使用 notrack 动作禁用 53 端口(DNS)的 UDP 流量的连接追踪。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet raw prerouting udp dport 53 notrack
2 nft add rule inet raw output udp sport 53 notrack

▮▮▮▮⚝ raw 表的 preroutingoutput 链在连接追踪之前处理数据包。

使用连接追踪标记进行策略路由:使用 ct mark set 语句标记连接,然后在路由策略中使用连接标记。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward ip daddr 192.168.1.100 ct mark set 1
2 nft add rule inet filter forward ct mark 1 counter # 统计标记连接的流量

实现端口转发 (DNAT):使用 dnat 语句实现端口转发,nftables 会自动处理连接追踪。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat prerouting tcp dport 80 dnat to 192.168.1.100:80

注意事项

规则顺序:包含 ct 表达式的规则,通常需要在不使用连接追踪的规则之后。例如,notrack 规则应放在 ct state 规则之前。
性能权衡:连接追踪虽然提供了强大的状态检测能力,但也会带来一定的性能开销。在性能敏感的场景中,需要权衡是否使用连接追踪,以及如何优化连接追踪配置。
连接追踪参数调优:可以调整 conntrack-ng 的内核参数,例如连接状态表大小、超时时间等,以优化连接追踪性能和资源利用率。可以使用 sysctl 命令或修改 /proc/sys/net/netfilter/ 目录下的文件进行调优。
监控连接追踪:可以使用 ctng-tools 工具(例如 ctng list, ctng count, ctng top) 监控 conntrack-ng 的连接追踪状态、连接数量、性能指标等。

nftables 与 conntrack-ng 的紧密集成,为构建高性能、高安全性的网络防火墙和 NAT 网关提供了强大的技术基础。通过灵活运用 ct 表达式和 notrack 动作,可以实现精细化的连接追踪控制和策略管理。

4.3.3 使用 ct 表达式进行连接追踪控制

ct 表达式是 nftables 中用于访问和控制连接追踪信息的关键工具。通过灵活运用 ct 表达式,可以实现各种基于连接状态、属性的策略控制,构建有状态防火墙、实现高级 NAT 功能、进行连接级别的 QoS 管理等。

基于连接状态的访问控制

允许已建立和关联的连接:这是有状态防火墙最基本的规则,只允许已建立连接的回包和关联连接进入,拒绝新的入站连接。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input ct state established,related accept
2 nft add rule inet filter input drop # 默认拒绝其他入站连接

只允许新的出站连接:限制只允许新的出站连接,已建立连接的回包和关联连接由第一条规则处理。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter output ct state new accept

拒绝无效连接:丢弃状态为 INVALID 的连接,通常表示连接状态异常或不符合协议规范。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward ct state invalid drop

基于 TCP 连接状态进行更细致的控制:例如,只允许 ESTABLISHED 状态的 TCP 连接,拒绝 SYN_RECV 等中间状态的连接。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter tcp ct state established accept
2 nft add rule inet filter tcp drop # 默认拒绝其他 TCP 连接

基于连接属性的策略控制

基于协议类型进行控制:例如,只允许 TCP 和 UDP 协议的已建立连接。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input ct state established,related ct proto { tcp, udp } accept

基于连接方向进行控制:例如,只允许从内网到外网的 HTTP 请求,但不允许外网主动发起 HTTP 连接。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward iifname "eth0" oifname "eth1" ct dir original tcp dport 80 accept
2 nft add rule inet filter forward iifname "eth1" oifname "eth0" ct dir reply tcp sport 80 accept

基于连接超时时间进行控制:例如,对于空闲时间过长的 TCP 连接,可以主动断开连接,释放资源。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward ct proto tcp ct timeout < 60s drop # 断开空闲时间超过 60 秒的 TCP 连接 (示例,实际应用需谨慎)

▮▮▮▮⚝ 注意:直接使用规则断开已建立连接可能导致连接中断,实际应用中应谨慎使用,并考虑使用更优雅的方式(例如 TCP keep-alive)。

基于连接标记 (mark) 和标签 (labels) 进行策略路由和 QoS:先使用规则标记或标签连接,然后在路由策略或 QoS 策略中使用连接标记或标签。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward ip daddr 192.168.1.100 ct mark set 1
2 nft add rule inet filter forward ct mark 1 counter # 统计标记连接的流量

基于连接计数 (count) 进行连接数限制:例如,限制单个源 IP 地址的并发连接数,防止连接耗尽攻击。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add set inet filter src_limit { type ipv4_addr; flags dynamic,timeout 10m; }
2 nft add rule inet filter input ip protocol tcp ct state new ip saddr @src_limit ct count over 10 limit rate 10/minute drop
3 nft add rule inet filter input ip protocol tcp ct state new ip saddr @src_limit add @src_limit { ip saddr timeout 10m } accept

▮▮▮▮⚝ 此示例规则限制单个源 IP 地址的新建 TCP 连接数不超过 10 个,并限制新建连接速率为每分钟 10 个。

结合 NAT 语句使用 ct 表达式

基于连接状态的 NAT 策略:例如,只对 NEW 状态的连接进行 DNAT。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat prerouting ct state new tcp dport 80 dnat to 192.168.1.100:80

基于连接方向的 NAT 策略:例如,只对原始方向的连接进行 SNAT。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat postrouting oifname "eth0" ct dir original masquerade

基于连接标记的 NAT 策略:例如,只对标记为 2 的连接进行 SNAT。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat postrouting ct mark 2 masquerade

注意事项

规则顺序ct 表达式的匹配顺序很重要。通常,应将更通用的连接状态匹配规则放在前面,例如 ct state established,related accept,然后是更具体的规则。
性能影响:过度依赖 ct 表达式进行复杂的状态检测可能会增加性能开销。应尽量优化规则,避免不必要的连接状态检查。
连接追踪表大小:连接追踪表的大小是有限的。在高并发连接场景下,需要合理配置连接追踪表大小,避免连接追踪表溢出。可以使用 sysctl 命令调整 net.netfilter.nf_conntrack_max 参数。
连接超时时间:连接超时时间会影响连接追踪表的资源占用和连接状态的准确性。应根据实际应用场景合理配置连接超时时间。可以使用 sysctl 命令调整 /proc/sys/net/netfilter/nf_conntrack_*_timeout_* 参数。
协议助手配置:对于一些复杂的协议,需要正确配置协议助手才能保证连接追踪的准确性。nftables 会自动加载和使用协议助手,但有时需要手动配置协议助手参数。

ct 表达式是 nftables 中进行连接追踪控制的核心工具。通过灵活运用 ct 表达式,可以构建各种复杂的有状态防火墙、NAT 网关、和连接级别的策略控制系统,实现更安全、更智能、更高效的网络管理。

4.4 Flowtables:硬件加速与 Offloading

4.4.1 Flowtables 的概念与优势

Flowtables 是 nftables 框架中用于实现硬件加速和 Offloading 的关键组件。它允许将部分或全部 nftables 规则卸载 (offload) 到网络设备的硬件层面执行,例如网卡 (NIC) 或交换芯片,从而显著提升数据包处理性能,降低 CPU 负载,特别是在高吞吐量和低延迟要求的网络环境中。

Flowtables 的概念

硬件 Offloading:Flowtables 的核心思想是将数据包处理从软件层面(内核)转移到硬件层面(网卡或交换芯片)。硬件设备通常具有更高的并行处理能力和更低的延迟,可以更高效地处理网络流量。
流表 (Flow Table):Flowtables 基于流表 (flow table) 的概念。流表是一个硬件数据结构,用于存储数据包处理规则。每个流表条目 (flow entry) 定义了匹配条件和对应的动作。当数据包到达硬件设备时,硬件设备会根据流表进行快速匹配和处理。
规则卸载:nftables Flowtables 允许将部分或全部 nftables 规则转换为硬件流表条目,并将其卸载到硬件设备。卸载后的规则由硬件设备直接执行,无需经过内核网络堆栈,从而实现硬件加速。
软件 Fallback:对于无法卸载到硬件的规则或数据包,仍然会回退 (fallback) 到软件层面(内核)进行处理,保证规则的完整性和兼容性。

Flowtables 的优势

性能提升:硬件加速显著提升数据包处理性能,特别是在高吞吐量、高包速率、低延迟要求的场景下。可以达到线速转发性能。
降低 CPU 负载:将数据包处理卸载到硬件,可以大幅降低 CPU 负载,释放 CPU 资源用于其他任务,提升系统整体性能和资源利用率。
低延迟:硬件处理路径通常比软件处理路径更短,延迟更低。Flowtables 可以降低网络延迟,提升应用响应速度。
节能:降低 CPU 负载可以减少系统功耗,实现节能效果。
可扩展性:Flowtables 可以与 nftables 软件规则灵活组合,实现软件定义网络 (SDN) 的灵活性和硬件加速的性能优势。
透明集成:nftables Flowtables 与 nftables 规则框架无缝集成。用户可以使用熟悉的 nftables 语法和工具配置 Flowtables,无需学习新的 API 或工具。

Flowtables 的适用场景

高性能防火墙:构建线速防火墙,满足高吞吐量、低延迟的安全防护需求。
网络加速:加速数据包转发,提升网络吞吐量和降低延迟。
数据中心网络:在数据中心网络中,利用 Flowtables 提升虚拟交换机 (vSwitch) 和网络虚拟化 (NVF) 的性能。
SDN (软件定义网络):结合 SDN 控制器,实现基于 Flowtables 的灵活、可编程的网络控制。
资源受限环境:在嵌入式设备、边缘计算等资源受限环境中,利用 Flowtables 降低 CPU 负载,提升性能和节能。

Flowtables 的局限性

硬件支持:Flowtables 依赖于网络设备的硬件支持。并非所有网卡或交换芯片都支持 Flowtables 功能。需要选择支持 Flowtables 的硬件设备。
规则限制:并非所有 nftables 规则都可以卸载到硬件。Flowtables 通常只支持部分规则类型和匹配条件。复杂的规则可能无法卸载,仍然需要在软件层面处理。
功能限制:硬件流表的功能通常比软件 nftables 规则集的功能更有限。一些高级的 nftables 功能可能无法在硬件层面实现。
配置复杂性:Flowtables 的配置和管理可能比纯软件 nftables 规则更复杂,需要考虑硬件设备的特性和限制。
调试难度:硬件加速的数据包处理路径更难调试和排错。需要使用专门的硬件调试工具和技术。

Flowtables 的关键组件

Flow Offload 驱动:网卡或交换芯片的驱动程序需要支持 Flowtables 功能,并提供相应的 API 接口。
nftables Flowtables 模块:nftables 框架中的 Flowtables 模块负责将 nftables 规则转换为硬件流表条目,并与硬件驱动程序交互。
硬件流表:网络设备硬件中的流表,用于存储卸载的规则,并进行硬件加速的数据包处理。

Flowtables 是 nftables 框架中实现硬件加速和 Offloading 的重要技术。它为构建高性能、低延迟的网络应用提供了新的选择。在选择使用 Flowtables 时,需要充分考虑硬件支持、规则限制、功能需求和配置复杂性等因素,并根据实际应用场景进行权衡和选择。

4.4.2 配置和使用 Flowtables

配置和使用 nftables Flowtables 涉及到硬件设备支持、内核配置、nftables 规则配置等多个方面。以下是配置和使用 Flowtables 的基本步骤和示例。

检查硬件和驱动程序支持

网卡支持:首先需要确认网卡 (NIC) 或交换芯片是否支持 Flowtables 功能。可以查阅硬件设备的规格说明书或厂商文档。
驱动程序支持:网卡驱动程序需要支持 Flowtables 功能。通常需要使用较新版本的驱动程序。可以查看驱动程序的文档或更新日志,确认 Flowtables 支持情况。
内核模块:确保内核加载了 Flowtables 相关的模块,例如 nft_flow_offload 模块。可以使用 lsmod | grep nft_flow_offload 命令检查模块是否加载。

配置内核和 nftables

启用 Flowtables 功能:在 nftables 配置文件中(例如 /etc/nftables.conf 或单独的 Flowtables 配置文件),需要启用 Flowtables 功能。可以使用 flowtable inet <flowtable_name> flags offload; 语句创建 Flowtables。
指定 Offload 标志:在创建表 (table) 或链 (chain) 时,需要指定 offload 标志,表示该表或链中的规则可以被卸载到 Flowtables。例如,table inet filter_offload { flags offload; ... }
编写可卸载的规则:编写 nftables 规则时,需要注意规则是否可以被卸载到硬件。Flowtables 通常只支持部分规则类型和匹配条件。可以参考 nftables 文档或硬件厂商文档,了解 Flowtables 支持的规则限制。

配置 Flowtables 规则示例

创建 Flowtables 和 Offload 表

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 flowtable inet fw_flowtable {
2 flags offload;
3 }
4
5 table inet filter_offload {
6 flags offload;
7 flowtable fw_flowtable;
8
9 chain forward {
10 type filter hook forward priority 0; policy accept;
11 # 可卸载的规则
12 }
13 }

▮▮▮▮⚝ flowtable inet fw_flowtable { flags offload; }: 创建名为 fw_flowtable 的 Flowtables,并启用 offload 标志。
▮▮▮▮⚝ table inet filter_offload { flags offload; flowtable fw_flowtable; ... }: 创建名为 filter_offload 的表,启用 offload 标志,并关联到 fw_flowtable
▮▮▮▮⚝ flowtable fw_flowtable;: 将 filter_offload 表关联到 fw_flowtable,表示该表中的规则可以使用 fw_flowtable 进行硬件加速。

添加可卸载的规则:例如,添加一个简单的转发规则,允许特定网段的流量通过。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter_offload forward ip saddr 192.168.1.0/24 ip daddr 10.0.0.0/8 accept

▮▮▮▮⚝ 此规则是一个简单的转发规则,可以被卸载到 Flowtables。

添加不可卸载的规则:例如,添加一个使用 log 语句的规则,log 语句通常无法卸载到硬件。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter_offload forward tcp dport 80 log prefix "HTTP Traffic: " accept

▮▮▮▮⚝ 此规则包含 log 语句,可能无法被卸载到 Flowtables,仍然会在软件层面执行。

验证 Flowtables 是否生效

查看 Flowtables 状态:可以使用 nft list flowtable inet fw_flowtable 命令查看 Flowtables 的状态,包括已卸载的规则数量、流表条目使用情况等。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft list flowtable inet fw_flowtable

▮▮▮▮输出示例:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 flowtable inet fw_flowtable {
2 flags offload
3 hook forward priority 0 device eth0
4 entries 1
5 memory 4096 bytes
6 }

▮▮▮▮⚝ entries 1: 表示 Flowtables 中已卸载了 1 条规则。
▮▮▮▮⚝ hook forward priority 0 device eth0: 表示 Flowtables 关联到 forward 链,并绑定到 eth0 设备。

监控流量:可以使用 tcpdump 或其他抓包工具监控网络流量,验证 Flowtables 是否生效。例如,在高负载情况下,观察 CPU 负载是否明显降低,网络吞吐量是否提升。
性能测试:进行性能测试,例如使用 iperf3 等工具测试网络吞吐量、延迟等指标,对比使用 Flowtables 和不使用 Flowtables 的性能差异。

注意事项

规则兼容性:在配置 Flowtables 规则时,需要仔细阅读硬件厂商和 nftables 文档,了解 Flowtables 支持的规则类型、匹配条件、动作等限制。避免使用 Flowtables 不支持的规则,导致规则无法卸载或行为异常。
规则优先级:Flowtables 规则的优先级可能与软件 nftables 规则不同。需要仔细测试和验证规则的执行顺序和效果。
调试和排错:Flowtables 的调试和排错可能比纯软件 nftables 规则更复杂。可以使用硬件厂商提供的调试工具或技术,以及 nftables 提供的 Flowtables 状态查看命令,辅助排错。
动态更新:Flowtables 的规则更新可能比软件 nftables 规则更新更慢。在高动态规则更新场景中,需要考虑 Flowtables 的更新性能和延迟。
硬件资源限制:硬件流表的容量是有限的。Flowtables 可以卸载的规则数量受到硬件流表容量的限制。需要监控 Flowtables 的流表条目使用情况,避免流表溢出。

配置和使用 nftables Flowtables 需要深入理解硬件设备特性、nftables 规则框架和 Flowtables 的工作原理。在实际应用中,建议从小规模测试开始,逐步验证 Flowtables 的功能和性能,并根据实际需求进行优化和调整。

4.5 模块化与规则组织

4.5.1 使用 include 文件组织规则

随着 nftables 规则集的规模不断增大,将所有规则都放在一个配置文件中会变得难以管理和维护。nftables 提供了 include 语句,允许将规则分散到多个文件中,并通过 include 语句将这些文件包含到主配置文件中,实现规则的模块化和组织化。使用 include 文件可以提高规则的可读性、可维护性、和重用性。

include 语句语法

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 include "<file_path>"

include: 关键字,表示包含外部文件。
"<file_path>": 要包含的文件的路径。文件路径可以是绝对路径或相对路径。相对路径相对于主配置文件的位置。

使用 include 文件组织规则的优势

模块化:将规则按功能模块或业务模块拆分到不同的文件中,例如防火墙规则、NAT 规则、QoS 规则、特定应用的规则等。每个文件负责一个模块的规则,提高规则的组织性和结构性。
可读性:将大型规则集拆分成多个小文件,每个文件只包含一部分规则,降低了单个文件的复杂度,提高了规则的可读性。
可维护性:模块化的规则更易于维护和修改。当需要修改某个模块的规则时,只需要修改对应的文件,而不需要修改整个配置文件,降低了维护成本和风险。
重用性:可以将通用的规则模块(例如,定义常用集合、变量、函数等)放在单独的文件中,并在多个配置文件中重用,提高了规则的重用性和一致性。
版本控制:将规则分散到多个文件中,更方便使用版本控制系统(例如 Git)进行管理。可以更精细地跟踪规则的修改历史,进行版本回滚和协作开发。

组织规则文件的示例

假设需要组织一个包含防火墙、NAT 和 QoS 规则的 nftables 规则集。可以创建以下文件结构:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 /etc/nftables.conf # 主配置文件
2 /etc/nftables.d/
3 ├── firewall.nft # 防火墙规则文件
4 ├── nat.nft # NAT 规则文件
5 ├── qos.nft # QoS 规则文件
6 └── common.nft # 通用规则定义文件 (集合、变量、函数等)

/etc/nftables.conf (主配置文件)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #!/usr/sbin/nft -f
2
3 include "/etc/nftables.d/common.nft"
4 include "/etc/nftables.d/firewall.nft"
5 include "/etc/nftables.d/nat.nft"
6 include "/etc/nftables.d/qos.nft"

▮▮▮▮⚝ 主配置文件只包含 include 语句,将规则加载任务委托给子文件。

/etc/nftables.d/common.nft (通用规则定义文件)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 定义常用集合
2 define trusted_networks = { 192.168.1.0/24, 10.0.0.0/8 }
3 define web_servers = { 192.168.1.100, 192.168.1.101 }
4
5 # 定义常用端口集合
6 set tcp_services { type inet_service; flags interval; }
7 add @tcp_services { ssh, http, https }

▮▮▮▮⚝ 定义了常用的集合和变量,可以在其他规则文件中重用。

/etc/nftables.d/firewall.nft (防火墙规则文件)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table inet filter {
2 chain input {
3 type filter hook input priority 0; policy drop;
4
5 # 允许已建立和关联的连接
6 ct state established,related accept
7
8 # 允许来自信任网络的 SSH 访问
9 ip saddr $trusted_networks tcp dport ssh accept
10
11 # 允许来自信任网络的 HTTP/HTTPS 访问
12 ip saddr $trusted_networks tcp dport { http, https } accept
13
14 # 记录并丢弃其他入站流量
15 log prefix "Firewall Drop: " drop
16 }
17
18 chain forward {
19 type filter hook forward priority 0; policy drop;
20
21 # 允许已建立和关联的连接
22 ct state established,related accept
23
24 # 允许内网访问外网 HTTP/HTTPS
25 ip saddr $trusted_networks tcp dport { http, https } accept
26
27 # 记录并丢弃其他转发流量
28 log prefix "Forward Drop: " drop
29 }
30 }

▮▮▮▮⚝ 包含了防火墙的 filter 表和 input, forward 链的规则。使用了 common.nft 中定义的 $trusted_networks 变量和 tcp_services 集合。

/etc/nftables.d/nat.nft (NAT 规则文件)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table nat nat {
2 chain prerouting {
3 type nat hook prerouting priority 0; policy accept;
4
5 # 端口转发:将公网 80 端口转发到内网 Web 服务器
6 tcp dport 80 dnat to $web_servers:80
7 }
8
9 chain postrouting {
10 type nat hook postrouting priority 0; policy accept;
11
12 # SNAT:内网主机通过 eth0 接口访问公网
13 oifname "eth0" masquerade
14 }
15 }

▮▮▮▮⚝ 包含了 NAT 的 nat 表和 prerouting, postrouting 链的规则。使用了 common.nft 中定义的 $web_servers 变量。

/etc/nftables.d/qos.nft (QoS 规则文件)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # QoS 规则示例 (需要结合 tc 流量控制)
2 table mangle qos {
3 chain forward {
4 type mangle hook forward priority 0; policy accept;
5
6 # 标记 HTTP 流量为高优先级 (示例,需要结合 tc qdisc 配置)
7 tcp dport { http, https } meta mark set 10
8 }
9 }

▮▮▮▮⚝ 包含了 QoS 相关的 mangle 表和 forward 链的规则。

加载和管理模块化规则

加载规则:使用 nft -f /etc/nftables.conf 命令加载主配置文件,nftables 会自动加载所有 include 的子文件。
查看规则集:使用 nft list ruleset 命令查看完整的规则集,包括所有 include 文件的规则。
修改规则:修改对应的子文件,然后重新加载主配置文件,即可更新规则。
版本控制:可以使用 Git 等版本控制系统管理 /etc/nftables.d/ 目录下的所有规则文件。

注意事项

文件路径include 语句中的文件路径需要正确指定。可以使用绝对路径或相对路径。相对路径相对于主配置文件的位置。
文件顺序include 语句的顺序决定了规则的加载顺序。在主配置文件中,先 include 的文件中的规则会先被加载。
循环包含:避免循环包含,例如 A 文件 include B 文件,B 文件又 include A 文件,会导致错误。
权限管理:确保规则文件的权限设置正确,只有授权用户才能修改规则文件。

使用 include 文件组织 nftables 规则是一种良好的实践,可以提高规则的可管理性、可读性和可维护性。在大型和复杂的 nftables 规则集中,强烈建议使用 include 文件进行模块化组织。

4.5.2 规则集的模块化设计与管理

规则集的模块化设计与管理是构建可维护、可扩展、高效 nftables 规则集的关键。模块化设计将大型复杂的规则集分解为多个独立的、功能明确的模块,每个模块负责一部分特定的网络策略。模块化管理则关注如何有效地组织、维护、更新和部署这些模块化的规则。

模块化设计原则

功能模块化:将规则按功能模块划分,例如:
▮▮▮▮⚝ 防火墙模块:负责基本的包过滤、状态检测、访问控制等。
▮▮▮▮⚝ NAT 模块:负责网络地址转换,包括 SNAT、DNAT、端口转发等。
▮▮▮▮⚝ QoS 模块:负责流量整形、带宽限制、优先级控制等。
▮▮▮▮⚝ 安全模块:负责入侵检测、DDoS 防护、恶意流量过滤等。
▮▮▮▮⚝ 应用模块:针对特定应用的规则,例如 Web 服务、邮件服务、数据库服务等。
层次化模块化:对于大型规则集,可以进一步进行层次化模块化。例如,防火墙模块可以再细分为入站防火墙、出站防火墙、转发防火墙等子模块。
接口模块化:按网络接口划分模块,例如:
▮▮▮▮⚝ WAN 接口模块:处理来自公网接口的流量。
▮▮▮▮⚝ LAN 接口模块:处理来自内网接口的流量。
▮▮▮▮⚝ DMZ 接口模块:处理来自 DMZ 区域接口的流量。
区域模块化:按网络区域划分模块,例如:
▮▮▮▮⚝ DMZ 区域模块:管理 DMZ 区域的网络策略。
▮▮▮▮⚝ 办公区模块:管理办公区域的网络策略。
▮▮▮▮⚝ 服务器区模块:管理服务器区域的网络策略。
策略模块化:按安全策略或业务策略划分模块,例如:
▮▮▮▮⚝ 默认拒绝策略模块:实现默认拒绝所有流量,只允许明确允许的流量。
▮▮▮▮⚝ 最小权限原则模块:只开放必要的服务和端口,限制不必要的访问。
▮▮▮▮⚝ 合规性策略模块:满足特定合规性要求的策略,例如 PCI DSS、HIPAA 等。

模块化管理方法

使用 include 文件:如 4.5.1 节所述,使用 include 文件将不同模块的规则分散到不同的文件中,提高规则的组织性和可维护性。
命名规范:为模块、文件、表、链、集合、变量、计数器等命名时,采用统一的命名规范,提高规则的可读性和可理解性。例如,使用模块名称作为前缀,例如 fw_input_chain, nat_dnat_rule, qos_bandwidth_limit_meter
注释:在规则文件中添加详细的注释,解释规则的功能、目的、匹配条件、动作等。方便其他人员理解和维护规则。
版本控制:使用版本控制系统(例如 Git)管理规则文件,跟踪规则的修改历史,进行版本回滚和协作开发。
自动化部署:使用自动化工具(例如 Ansible, Puppet, Chef)自动化部署和更新 nftables 规则。提高部署效率和一致性,减少人为错误。
集中化管理:对于大规模网络环境,可以使用集中化的管理平台或工具,统一管理和监控所有 nftables 规则集。
文档化:编写规则集文档,描述规则集的整体架构、模块划分、功能说明、配置方法、维护流程等。方便用户理解和使用规则集。
测试和验证:在部署规则集之前,进行充分的测试和验证,确保规则的正确性和有效性。可以使用自动化测试工具或脚本进行测试。
监控和日志:部署规则集后,进行持续的监控和日志分析,及时发现和解决问题,优化规则性能和安全性。

模块化设计示例

假设需要为一个企业网络设计 nftables 规则集,可以采用以下模块化设计:

主配置文件 (/etc/nftables.conf)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #!/usr/sbin/nft -f
2
3 include "/etc/nftables.d/common.nft" # 通用定义
4 include "/etc/nftables.d/firewall.nft" # 防火墙模块
5 include "/etc/nftables.d/nat.nft" # NAT 模块
6 include "/etc/nftables.d/qos.nft" # QoS 模块
7 include "/etc/nftables.d/dmz.nft" # DMZ 区域策略
8 include "/etc/nftables.d/office.nft" # 办公区策略
9 include "/etc/nftables.d/server.nft" # 服务器区策略

通用定义模块 (/etc/nftables.d/common.nft):定义常用集合、变量、函数等,例如信任网络、Web 服务器、常用端口、日志函数等。
防火墙模块 (/etc/nftables.d/firewall.nft):实现基本的包过滤、状态检测、默认拒绝策略等。包含 filter 表和 input, forward, output 链的通用规则。
NAT 模块 (/etc/nftables.d/nat.nft):实现 SNAT、DNAT、端口转发等 NAT 功能。包含 nat 表和 prerouting, postrouting 链的规则。
QoS 模块 (/etc/nftables.d/qos.nft):实现流量整形、带宽限制、优先级控制等 QoS 功能。包含 mangle 表和 forward 链的规则,以及 meter, quota, limit 等语句。
DMZ 区域策略模块 (/etc/nftables.d/dmz.nft):定义 DMZ 区域的网络策略,例如允许从公网访问 DMZ 区域的 Web 服务器,限制 DMZ 区域访问内网等。
办公区策略模块 (/etc/nftables.d/office.nft):定义办公区域的网络策略,例如允许办公区访问互联网,限制办公区访问服务器区等。
服务器区策略模块 (/etc/nftables.d/server.nft):定义服务器区域的网络策略,例如只允许特定来源访问服务器,限制服务器访问互联网等。

模块化管理的优势

降低复杂性:将大型规则集分解为多个小模块,降低了整体复杂性,更易于理解和管理。
提高可维护性:模块化的规则更易于维护和修改。当需要修改某个功能或区域的策略时,只需要修改对应的模块,而不需要修改整个规则集。
增强可扩展性:模块化的设计更易于扩展和添加新的功能或策略。可以方便地添加新的模块,而不会影响现有模块。
提高团队协作效率:模块化的规则更易于团队协作开发和维护。不同团队成员可以负责不同的模块,并行开发和维护规则集。
提升规则重用性:可以将通用的模块(例如通用定义模块、防火墙模块、NAT 模块)在不同的环境中重用,提高规则的重用性和一致性。

规则集的模块化设计与管理是构建高效、可维护、可扩展 nftables 规则集的关键。通过合理的模块划分、规范化的管理方法、和自动化工具的应用,可以有效地管理大型复杂的 nftables 规则集,提升网络安全性和管理效率。

4.6 事务(Transactions)与原子操作

4.6.1 nftables 事务机制

nftables 事务(transactions)机制提供了一种原子性操作的方式来批量修改规则集。事务机制保证了在执行一系列规则修改操作时,要么所有操作都成功执行,要么所有操作都不执行,从而避免了规则集在修改过程中处于不一致或中间状态,提高了规则更新的可靠性和安全性。

事务的基本概念

原子性 (Atomicity):事务的核心特性。原子性保证事务中的所有操作要么全部成功执行,要么全部失败回滚。不存在部分执行的情况。
一致性 (Consistency):事务执行前后,规则集始终保持一致性状态。不会出现规则集在修改过程中处于不完整或不一致的状态。
隔离性 (Isolation):多个事务并发执行时,每个事务都感觉不到其他事务的存在,仿佛是独立执行的。保证了事务之间的互不干扰。
持久性 (Durability):事务一旦提交成功,对规则集的修改就会永久保存,即使系统发生故障也不会丢失。

nftables 事务的实现方式

nftables 事务通过以下机制实现:

规则集快照 (Snapshot):在开始事务之前,nftables 会创建一个当前规则集的快照。快照记录了规则集的完整状态。
内存修改:事务中的所有规则修改操作(添加、删除、替换等)都只在内存中的规则集副本上进行,不会立即应用到内核运行的规则集。
提交 (Commit):当事务中的所有操作都成功执行后,可以提交事务。提交操作会将内存中的规则集副本替换为内核运行的规则集,使修改生效。
回滚 (Abort/Rollback):如果在事务执行过程中发生错误,或者用户主动中止事务,可以回滚事务。回滚操作会将规则集恢复到事务开始之前的快照状态,撤销所有已做的修改。

事务的生命周期

一个 nftables 事务的生命周期通常包括以下步骤:

  1. 开始事务 (Begin Transaction):使用 nft begin 命令开始一个新的事务。
  2. 执行规则修改操作:在事务中执行一系列规则修改操作,例如 add rule, delete rule, replace rule, add set, delete set 等。
  3. 检查操作结果:检查每个规则修改操作是否成功执行。如果发生错误,可以选择回滚事务。
  4. 提交事务 (Commit Transaction):如果所有操作都成功执行,使用 nft commit 命令提交事务,使修改生效。
  5. 回滚事务 (Abort Transaction):如果在事务执行过程中发生错误,或者用户主动中止事务,使用 nft abort 命令回滚事务,撤销所有修改。

事务操作命令

nft begin: 开始一个新的事务。
nft commit: 提交当前事务,使修改生效。
nft abort: 回滚当前事务,撤销所有修改。

事务应用示例

批量添加规则并提交

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft begin
2 nft add rule inet filter input tcp dport 80 accept comment "Allow HTTP"
3 nft add rule inet filter input tcp dport 443 accept comment "Allow HTTPS"
4 nft add rule inet filter input tcp dport 22 accept comment "Allow SSH"
5 nft commit

▮▮▮▮⚝ 以上命令在一个事务中批量添加了三条规则,并最终提交事务,使所有规则同时生效。如果在添加规则过程中发生错误,可以使用 nft abort 命令回滚事务,撤销所有已添加的规则。

批量删除规则并提交

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft begin
2 nft delete rule inet filter input handle 123
3 nft delete rule inet filter input handle 456
4 nft delete rule inet filter input handle 789
5 nft commit

▮▮▮▮⚝ 以上命令在一个事务中批量删除了三条规则,并提交事务。

事务回滚示例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft begin
2 nft add rule inet filter input tcp dport 80 accept comment "Allow HTTP"
3 nft add rule inet filter input tcp dport 443 accept comment "Allow HTTPS"
4 nft add rule inet filter input tcp dport 22 accept comment "Allow SSH"
5 nft abort # 发生错误或需要撤销修改,回滚事务

▮▮▮▮⚝ 以上命令开始一个事务,添加了三条规则,然后使用 nft abort 命令回滚事务。回滚后,之前添加的规则不会生效。

注意事项

事务嵌套:nftables 不支持事务嵌套。在一个事务中不能再开始另一个事务。
事务范围:一个事务只能包含 nftables 规则修改操作。不能包含其他系统操作或外部命令。
错误处理:在事务执行过程中,需要检查每个规则修改操作的返回结果,判断是否成功。如果发生错误,应及时回滚事务,避免规则集处于不一致状态。
性能影响:事务机制会带来一定的性能开销,因为需要创建规则集快照、在内存中修改规则集副本等。在高频率规则更新场景中,需要权衡事务的可靠性和性能开销。
原子性保证:nftables 事务机制保证了规则更新的原子性,提高了规则更新的可靠性和安全性。在需要批量修改规则集、或者需要保证规则更新原子性的场景中,应优先使用事务机制。

nftables 事务机制为规则集的批量修改提供了原子性保证,是构建可靠、安全 nftables 规则管理系统的关键技术。在进行规则集更新操作时,建议始终使用事务机制,提高规则更新的可靠性和安全性。

4.6.2 批量操作与原子性规则更新

批量操作与原子性规则更新是 nftables 事务机制的核心应用场景。通过事务机制,可以将一系列规则修改操作组合成一个原子操作,保证规则更新的原子性、一致性和可靠性。批量操作可以提高规则更新效率,原子性规则更新可以避免规则集在更新过程中处于不一致状态,提高网络安全性和稳定性。

批量操作的优势

提高效率:批量操作可以将多个规则修改命令组合成一个事务,减少了与 nftables 内核模块的交互次数,提高了规则更新效率。特别是在需要添加、删除大量规则时,批量操作的效率优势更加明显。
简化脚本:使用事务机制可以将多个规则修改命令放在一个脚本中,简化了脚本的编写和管理。
原子性保证:批量操作结合事务机制,可以保证规则更新的原子性。要么所有规则修改操作都成功执行,要么所有操作都不执行,避免了规则集在更新过程中处于不一致状态。

原子性规则更新的重要性

避免规则集不一致:在没有事务机制的情况下,如果批量修改规则过程中发生错误,可能导致部分规则生效,部分规则未生效,规则集处于不一致状态。不一致的规则集可能导致网络策略混乱、安全漏洞、服务中断等问题。
保证网络策略完整性:原子性规则更新保证了网络策略的完整性。例如,在更新防火墙规则时,需要同时添加多条规则才能实现完整的安全策略。原子性更新保证了这些规则要么同时生效,要么同时不生效,避免了策略不完整导致的风险。
提高系统稳定性:原子性规则更新提高了系统的稳定性。避免了规则集在更新过程中处于不确定状态,减少了因规则不一致导致的网络故障和系统异常。
简化回滚操作:使用事务机制进行原子性规则更新,可以方便地进行回滚操作。如果规则更新后发现问题,可以使用 nft abort 命令快速回滚到之前的规则集状态,减少故障恢复时间。

批量操作与原子性更新的应用场景

初始化规则集:在系统启动或服务初始化时,需要批量添加大量的初始规则。使用事务机制可以保证初始规则集的一次性、完整性加载。
更新规则集版本:在需要升级或替换整个规则集版本时,可以使用事务机制批量删除旧版本规则,并批量添加新版本规则,保证规则集版本更新的原子性。
动态调整规则集:在需要根据网络流量、安全事件、业务需求等动态调整规则集时,可以使用事务机制批量添加、删除、修改规则,保证规则动态调整的原子性和实时性。
自动化规则管理:在自动化规则管理系统中,使用事务机制进行规则更新,可以提高系统的可靠性和稳定性。例如,在 SDN 控制器、自动化配置管理工具中,可以使用事务机制批量更新 nftables 规则。

批量操作示例

使用管道批量添加规则

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft begin
2 echo "add rule inet filter input tcp dport 80 accept comment 'Allow HTTP'" | nft -f -
3 echo "add rule inet filter input tcp dport 443 accept comment 'Allow HTTPS'" | nft -f -
4 echo "add rule inet filter input tcp dport 22 accept comment 'Allow SSH'" | nft -f -
5 nft commit

▮▮▮▮⚝ 使用 echo 命令和管道 | 将多个 add rule 命令传递给 nft -f - 命令,实现批量添加规则。

使用脚本批量添加规则

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #!/bin/bash
2 nft begin
3 nft add rule inet filter input tcp dport 80 accept comment "Allow HTTP"
4 nft add rule inet filter input tcp dport 443 accept comment "Allow HTTPS"
5 nft add rule inet filter input tcp dport 22 accept comment "Allow SSH"
6 nft commit

▮▮▮▮⚝ 将多个 nft add rule 命令放在一个脚本文件中,然后执行脚本,实现批量添加规则。

使用循环批量添加规则

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft begin
2 for port in 80 443 22; do
3 nft add rule inet filter input tcp dport $port accept comment "Allow TCP port $port"
4 done
5 nft commit

▮▮▮▮⚝ 使用 for 循环批量添加规则,例如批量开放多个 TCP 端口。

最佳实践

始终使用事务:在进行任何规则集修改操作时,都应该使用事务机制,保证规则更新的原子性和可靠性。
批量处理规则:尽量将多个相关的规则修改操作放在一个事务中批量处理,提高规则更新效率。
错误处理:在脚本中添加错误处理机制,检查每个规则修改操作的返回结果,如果发生错误,及时回滚事务。
自动化测试:在自动化规则管理系统中,添加自动化测试环节,验证规则更新后的规则集是否正确生效,保证规则更新的质量。
监控和日志:对规则更新操作进行监控和日志记录,方便审计和排错。

批量操作与原子性规则更新是 nftables 事务机制的核心价值所在。通过合理利用事务机制和批量操作,可以构建高效、可靠、安全的 nftables 规则管理系统,提高网络安全性和管理效率。

ENDOF_CHAPTER_

5. chapter 5: nftables 实战:构建防火墙

5.1 基础防火墙策略设计原则

防火墙是网络安全的第一道防线,其策略设计至关重要。一个优秀的防火墙策略,不仅能有效地保护系统安全,还能在保障安全的同时,最大限度地减少对正常网络通信的影响。本节将深入探讨构建防火墙时必须遵循的几个核心设计原则,为后续的实战操作奠定坚实的基础。

5.1.1 最小权限原则

最小权限原则(Principle of Least Privilege, PoLP)是信息安全领域的一项基本原则,指的是只授予用户或进程完成其工作所需的最小权限。在防火墙策略设计中,这意味着我们应该仅允许必要的网络流量通过,而默认阻止所有其他流量

核心思想: 限制访问,降低风险。
应用场景
▮▮▮▮ⓒ 服务端口限制:仅开放对外提供服务的端口,例如 Web 服务器的 80 和 443 端口,邮件服务器的 25、110、143、465、993、995 端口等。
▮▮▮▮ⓓ 源地址限制:对于某些内部服务,可以限制只允许特定来源的 IP 地址或网段访问。例如,数据库服务只允许应用服务器访问。
▮▮▮▮ⓔ 协议限制:仅允许必要的网络协议通过。例如,如果不需要 FTP 服务,则可以阻止 TCP 协议的 20 和 21 端口。
优势
▮▮▮▮ⓖ 减少攻击面:通过限制不必要的网络访问,可以显著减少潜在的攻击入口。即使系统存在漏洞,攻击者也可能因为防火墙的限制而无法利用。
▮▮▮▮ⓗ 提高安全性:最小权限原则有助于构建更安全的系统环境,降低因配置错误或权限滥用导致的安全风险。
▮▮▮▮ⓘ 简化管理:清晰的权限划分和限制,有助于简化安全管理和审计工作。

案例分析
假设一个 Web 服务器只需要对外提供 HTTP 和 HTTPS 服务,那么根据最小权限原则,防火墙策略应该只允许 TCP 协议的 80 和 443 端口入站,并阻止所有其他入站流量。对于出站流量,可以根据实际需求进行更细粒度的控制,但通常情况下,Web 服务器需要访问 DNS 服务器(UDP 53 端口)和一些外部资源,因此需要允许相关的出站连接。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建 inet 表,用于 IPv4 和 IPv6
2 nft add table inet filter
3
4 # 创建 input 链,hook 点为 input,优先级为 0
5 nft add chain inet filter input { type filter hook input priority 0 ; policy drop; }
6
7 # 允许 loopback 接口流量
8 nft add rule inet filter input iifname lo accept
9
10 # 允许已建立的和相关的连接
11 nft add rule inet filter input ct state established,related accept
12
13 # 允许 SSH 入站连接 (TCP 22 端口)
14 nft add rule inet filter input tcp dport 22 accept
15
16 # 允许 HTTP 入站连接 (TCP 80 端口)
17 nft add rule inet filter input tcp dport 80 accept
18
19 # 允许 HTTPS 入站连接 (TCP 443 端口)
20 nft add rule inet filter input tcp dport 443 accept
21
22 # 默认策略为 drop,拒绝所有未明确允许的入站流量
23 # (在链创建时已设置 policy drop)

在这个例子中,我们只允许了 loopback 流量、已建立和相关的连接,以及 SSH、HTTP、HTTPS 服务的入站连接,其余所有入站流量都被默认拒绝,这体现了最小权限原则的应用。

5.1.2 默认拒绝策略

默认拒绝策略(Default Deny Policy)是防火墙策略设计中最核心的原则之一。它指的是在没有明确允许的情况下,默认拒绝所有网络流量。与默认允许策略(Default Allow Policy)相反,默认拒绝策略被认为是更安全的选择。

核心思想: 显式允许,隐式拒绝。
实现方式
▮▮▮▮ⓒ 设置链的默认策略为 dropreject:在 nftables 中,可以在创建链时通过 policy droppolicy reject 来设置默认策略。
▮▮▮▮ⓓ 只添加允许规则:防火墙规则集中只包含明确允许通过的流量规则,而没有任何默认允许所有流量的规则。
优势
▮▮▮▮ⓕ 增强安全性:默认拒绝策略可以有效地阻止未授权的访问和潜在的攻击。即使出现新的漏洞或未知的攻击方式,默认拒绝策略也能提供一层额外的保护。
▮▮▮▮ⓖ 降低配置风险:相比于默认允许策略,默认拒绝策略更不容易因为配置疏忽而导致安全漏洞。即使忘记配置某些允许规则,也只是会影响部分正常功能,而不会直接暴露安全风险。
▮▮▮▮ⓗ 符合最小权限原则:默认拒绝策略是最小权限原则的具体体现,它强制用户显式地声明哪些流量是允许的,从而确保只开放必要的网络访问。

案例对比

默认允许策略(不推荐):假设防火墙默认允许所有流量,然后只添加规则来阻止已知的恶意流量。这种策略的风险在于,一旦出现新的未知恶意流量,或者配置规则出现遗漏,就可能导致安全漏洞。
默认拒绝策略(推荐):防火墙默认拒绝所有流量,然后只添加规则来允许必要的正常流量。这种策略更加安全可靠,即使出现配置遗漏,也只是会影响部分正常功能,而不会直接暴露安全风险。

nftables 配置示例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建 input 链,默认策略为 drop
2 nft add chain inet filter input { type filter hook input priority 0 ; policy drop; }
3
4 # 只添加允许规则,例如允许 SSH 和 HTTP
5 nft add rule inet filter input tcp dport 22 accept
6 nft add rule inet filter input tcp dport 80 accept
7
8 # 所有未明确允许的流量都将被默认策略 drop 拒绝

在这个例子中,policy drop 确保了所有未被明确允许的流量都会被拒绝,从而实现了默认拒绝策略。

5.1.3 分层防御

分层防御(Defense in Depth)是一种综合性的安全策略,指的是在系统的不同层面部署多重安全控制措施,以形成多层次的保护。即使某一层次的安全措施失效,其他层次的安全措施仍然可以提供保护,从而提高整体的安全性。在防火墙策略设计中,分层防御也同样重要。

核心思想: 多层保护,纵深防御。
应用层面
▮▮▮▮ⓒ 网络层防火墙:这是最基础的一层防御,通过 nftables 或其他防火墙软件实现,用于控制网络流量的进出。
▮▮▮▮ⓓ 主机层防火墙:在每台主机上部署防火墙软件,例如 firewalldiptables,进一步加强主机的安全防护。
▮▮▮▮ⓔ 应用层防火墙:例如 Web 应用防火墙(WAF),用于检测和防御针对 Web 应用的攻击,例如 SQL 注入、跨站脚本攻击(XSS)等。
▮▮▮▮ⓕ 入侵检测系统(IDS)/入侵防御系统(IPS):用于监控网络流量和系统日志,检测潜在的入侵行为,并进行告警或阻断。
▮▮▮▮ⓖ 安全审计:定期进行安全审计,检查安全策略的有效性,及时发现和修复安全漏洞。
▮▮▮▮ⓗ 物理安全:例如机房门禁、监控系统等,防止物理入侵。
优势
▮▮▮▮ⓙ 提高整体安全性:多层次的安全措施可以有效地提高系统的整体安全性,降低单一安全措施失效带来的风险。
▮▮▮▮ⓚ 增强防御能力:分层防御可以应对各种类型的攻击,包括网络层攻击、应用层攻击、物理入侵等。
▮▮▮▮ⓛ 降低风险扩散:即使某一层次的安全措施被突破,其他层次的安全措施仍然可以阻止攻击的进一步扩散。

案例场景
一个典型的企业网络安全架构可能包括以下分层防御措施:

  1. 边界防火墙:部署在企业网络的边界,用于控制内外网之间的流量,实现网络层防火墙的功能。
  2. 内部防火墙:在企业内部网络的不同区域之间部署防火墙,例如 DMZ 区、办公区、数据中心区等,实现网络隔离和访问控制。
  3. 主机防火墙:在重要的服务器和终端设备上部署主机防火墙,例如数据库服务器、Web 服务器、开发人员的电脑等,加强主机自身的安全防护。
  4. Web 应用防火墙(WAF):部署在 Web 服务器前端,用于保护 Web 应用免受攻击。
  5. 入侵检测系统(IDS)/入侵防御系统(IPS):部署在网络关键节点,用于监控网络流量和系统日志,检测和防御入侵行为。
  6. 安全审计:定期进行安全审计,检查安全策略的有效性,及时发现和修复安全漏洞。

nftables 在分层防御中的角色
nftables 主要用于实现网络层防火墙的功能,可以作为分层防御体系中的重要组成部分。通过合理配置 nftables 规则,可以有效地控制网络流量,实现网络隔离和访问控制,为其他安全措施提供基础保障。

5.2 构建基本的有状态防火墙

有状态防火墙(Stateful Firewall)是一种能够跟踪连接状态的防火墙。与传统的无状态防火墙(Stateless Firewall)相比,有状态防火墙能够根据连接状态来决定是否允许数据包通过,从而提供更精细、更安全的访问控制。本节将介绍如何使用 nftables 构建一个基本的有状态防火墙。

5.2.1 允许已建立连接和相关连接

有状态防火墙的核心功能之一是连接追踪(Connection Tracking)。通过连接追踪,防火墙可以记录网络连接的状态,例如 NEW(新连接)、ESTABLISHED(已建立连接)、RELATED(相关连接)等。基于连接状态,我们可以制定更灵活的防火墙规则。

连接状态类型
▮▮▮▮ⓑ NEW:表示一个新的连接请求,通常是连接的第一个数据包。
▮▮▮▮ⓒ ESTABLISHED:表示连接已经建立,数据可以双向传输。
▮▮▮▮ⓓ RELATED:表示与已建立连接相关的连接,例如 FTP 数据连接、NAT 后的连接等。
▮▮▮▮ⓔ INVALID:表示无效的连接,例如不符合协议规范的数据包、乱序的数据包等。
允许已建立连接和相关连接的必要性
▮▮▮▮ⓖ 安全性:只允许已建立连接和相关连接的入站流量,可以有效地阻止未经请求的入站连接,降低被攻击的风险。
▮▮▮▮ⓗ 功能性:许多网络应用都需要双向通信,例如 Web 浏览、SSH 远程登录等。允许已建立连接和相关连接可以确保这些应用正常工作。
▮▮▮▮ⓘ 性能:对于已建立连接的数据包,防火墙可以直接放行,无需进行复杂的规则匹配,提高数据包处理效率。

nftables 规则配置

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 允许已建立的和相关的连接
2 nft add rule inet filter input ct state established,related accept
3 nft add rule inet filter forward ct state established,related accept
4 nft add rule inet filter output ct state established,related accept

ct state established,related: 这是一个连接状态匹配表达式,用于匹配连接状态为 establishedrelated 的数据包。
accept: 动作,表示接受匹配的数据包。

规则解释
这些规则添加到 inputforwardoutput 链中,表示允许所有接口上已建立的和相关的连接。这意味着,如果一个连接是由本机发起的(出站连接),那么该连接的后续入站流量将被允许通过。

案例场景
假设用户通过 SSH 客户端连接到远程服务器。

  1. 客户端发起连接:客户端发送 SYN 包到服务器,这是一个 NEW 状态的连接。
  2. 服务器响应连接:服务器回复 SYN-ACK 包,连接状态变为 ESTABLISHED
  3. 连接建立:客户端发送 ACK 包,连接正式建立,状态保持为 ESTABLISHED
  4. 数据传输:客户端和服务器之间可以双向传输数据,所有数据包都属于 ESTABLISHED 状态的连接。

在上述过程中,只有当连接状态为 ESTABLISHEDRELATED 时,防火墙才会允许入站流量通过。对于未经请求的入站 SYN 包(NEW 状态),如果没有任何允许 NEW 状态连接的规则,则会被默认策略拒绝,从而提高了安全性。

5.2.2 开放常用服务端口:SSH、HTTP、HTTPS

在构建基本的有状态防火墙之后,我们需要根据实际需求开放一些常用的服务端口,例如 SSH(Secure Shell)、HTTP(Hypertext Transfer Protocol)、HTTPS(HTTP Secure)等。

常用服务端口
▮▮▮▮ⓑ SSH (TCP 22 端口):用于远程安全登录和管理 Linux 服务器。
▮▮▮▮ⓒ HTTP (TCP 80 端口):用于提供 Web 服务,明文传输。
▮▮▮▮ⓓ HTTPS (TCP 443 端口):用于提供安全的 Web 服务,加密传输。
开放服务端口的原则
▮▮▮▮ⓕ 按需开放:只开放对外提供服务的端口,避免开放不必要的端口,减少攻击面。
▮▮▮▮ⓖ 最小权限:可以进一步限制允许访问这些端口的源 IP 地址或网段,提高安全性。
▮▮▮▮ⓗ 安全加固:对于开放的服务端口,需要进行安全加固,例如 SSH 服务可以禁用密码登录,使用密钥认证;Web 服务可以配置 HTTPS 证书,启用安全协议等。

nftables 规则配置

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 允许 SSH 入站连接 (TCP 22 端口)
2 nft add rule inet filter input tcp dport 22 ct state new accept
3
4 # 允许 HTTP 入站连接 (TCP 80 端口)
5 nft add rule inet filter input tcp dport 80 ct state new accept
6
7 # 允许 HTTPS 入站连接 (TCP 443 端口)
8 nft add rule inet filter input tcp dport 443 ct state new accept

tcp dport 22, tcp dport 80, tcp dport 443: 分别匹配目标端口为 22、80、443 的 TCP 协议数据包。
ct state new: 匹配连接状态为 new 的数据包,即新的连接请求。
accept: 动作,表示接受匹配的数据包。

规则解释
这些规则添加到 input 链中,表示允许来自任何源 IP 地址,目标端口为 22、80、443 的 TCP 新连接请求。这意味着外部用户可以通过 SSH、HTTP 或 HTTPS 协议访问本机提供的服务。

更安全的配置
为了提高安全性,可以进一步限制允许访问这些端口的源 IP 地址或网段。例如,只允许特定 IP 地址或网段的 SSH 访问:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 只允许来自 192.168.1.0/24 网段的 SSH 入站连接
2 nft add rule inet filter input ip saddr 192.168.1.0/24 tcp dport 22 ct state new accept

在这个例子中,ip saddr 192.168.1.0/24 限制了源 IP 地址必须属于 192.168.1.0/24 网段,才能允许 SSH 连接。

5.2.3 阻止非法入站连接

在允许了必要的入站连接之后,我们需要确保阻止所有非法的、未经授权的入站连接。由于我们在创建 input 链时已经设置了默认策略为 drop,因此所有未被明确允许的入站流量都会被默认拒绝。

默认拒绝策略的作用
▮▮▮▮ⓑ 阻止未知攻击:默认拒绝策略可以有效地阻止未知的、新型的网络攻击。即使攻击者使用新的攻击手段,只要没有被明确允许,就无法进入系统。
▮▮▮▮ⓒ 防止配置错误:即使防火墙规则配置出现遗漏或错误,默认拒绝策略也能提供一层额外的保护,避免安全漏洞。
▮▮▮▮ⓓ 简化管理:默认拒绝策略使得防火墙规则集更加清晰和易于管理。只需要关注需要允许的流量,而无需考虑如何阻止所有可能的恶意流量。

nftables 配置检查
为了确保默认拒绝策略生效,我们需要检查 input 链的策略是否设置为 dropreject

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft list chain inet filter input

输出结果应该包含 policy drop;policy reject; 类似的信息,例如:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table inet filter {
2 chain input {
3 type filter hook input priority 0; policy drop;
4 ... (其他规则) ...
5 }
6 ...
7 }

如果 policy 设置为 accept 或其他值,则需要修改为 dropreject

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft chain modify inet filter input policy drop

进一步的安全加固
除了默认拒绝策略,还可以添加一些额外的规则来阻止常见的非法入站连接,例如:

阻止 ICMP flood 攻击:限制 ICMP 请求的速率,防止 ICMP flood 攻击。
阻止 SYN flood 攻击:使用 limit 表达式限制新连接的速率,防止 SYN flood 攻击(更专业的 SYN flood 防御通常需要结合 SYN cookies 等技术)。
阻止端口扫描:检测和阻止端口扫描行为,例如使用 recent 模块(iptables)或 set 结合 meter 实现(nftables,更复杂)。

简单的 SYN flood 防御示例 (仅为演示,实际应用中可能需要更精细的配置):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 限制每秒最多接受 10 个新的 TCP 连接请求到 80 端口
2 nft add rule inet filter input tcp dport 80 ct state new limit rate 10/second accept

总结
通过设置默认拒绝策略,并结合允许已建立连接、开放必要服务端口等规则,我们构建了一个基本的有状态防火墙。这个防火墙能够有效地保护系统安全,同时保证常用网络服务的正常运行。在实际应用中,还需要根据具体的安全需求和网络环境,进一步完善和优化防火墙策略。

5.3 高级防火墙功能实现

在掌握了基本的防火墙构建方法之后,我们可以进一步探索 nftables 的高级功能,实现更复杂的防火墙策略,例如端口转发、DMZ 设置、基于 IP 地址和地理位置的访问控制、DDoS 防护等。

5.3.1 端口转发与 DMZ 设置

端口转发(Port Forwarding)和 DMZ(Demilitarized Zone,隔离区)是构建安全网络架构中常用的技术,可以有效地保护内部网络的安全,并对外提供安全可控的服务。

端口转发
▮▮▮▮ⓑ 概念:端口转发是指将发送到防火墙公网 IP 地址特定端口的流量,转发到内网服务器的指定 IP 地址和端口。
▮▮▮▮ⓒ 应用场景
▮▮▮▮▮▮▮▮❹ 内网 Web 服务器对外提供服务:将发送到防火墙公网 IP 地址 80 或 443 端口的流量,转发到内网 Web 服务器的 IP 地址和 80 或 443 端口。
▮▮▮▮▮▮▮▮❺ 远程访问内网服务器:将发送到防火墙公网 IP 地址特定端口(例如非 22 端口)的流量,转发到内网 SSH 服务器的 IP 地址和 22 端口。
▮▮▮▮ⓕ nftables 实现:可以使用 dnat (destination NAT) 语句实现端口转发。

nftables 端口转发配置示例
假设内网 Web 服务器 IP 地址为 192.168.1.100,需要将公网 IP 地址的 80 端口转发到内网服务器的 80 端口。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 在 nat 表的 prerouting 链中添加规则
2 nft add rule nat prerouting iifname eth0 tcp dport 80 dnat to 192.168.1.100
3
4 # 允许转发的流量通过 forward 链
5 nft add rule inet filter forward iifname eth0 oifname eth1 tcp dport 80 daddr 192.168.1.100 ct state new,established,related accept

table nat prerouting: 端口转发通常在 nat 表的 prerouting 链中进行,因为需要在路由决策之前修改目标地址。
iifname eth0: 假设 eth0 是公网接口。
tcp dport 80: 匹配目标端口为 80 的 TCP 流量。
dnat to 192.168.1.100: 将目标地址修改为 192.168.1.100,目标端口保持不变(默认为原始目标端口 80)。
table inet filter forward: 需要允许转发的流量通过 filter 表的 forward 链。
oifname eth1: 假设 eth1 是内网接口。
daddr 192.168.1.100: 匹配目标地址为 192.168.1.100 的流量。
ct state new,established,related: 允许新的、已建立的和相关的连接。

DMZ (隔离区)
▮▮▮▮ⓑ 概念:DMZ 是指位于内部网络和外部网络之间的一个隔离网络区域。通常用于部署对外提供服务的服务器,例如 Web 服务器、邮件服务器等。
▮▮▮▮ⓒ 作用
▮▮▮▮▮▮▮▮❹ 隔离风险:将对外服务器部署在 DMZ 区,即使这些服务器被攻击攻陷,也不会直接威胁到内部网络的安全。
▮▮▮▮▮▮▮▮❺ 增强安全性:DMZ 区通常会配置更严格的安全策略,例如更严格的防火墙规则、入侵检测系统等。
▮▮▮▮ⓕ 网络架构:典型的 DMZ 网络架构通常包括三个防火墙:
▮▮▮▮▮▮▮▮❼ 边界防火墙 (外部防火墙):位于外部网络和 DMZ 区之间,用于控制外部网络访问 DMZ 区的流量,以及 DMZ 区访问外部网络的流量。
▮▮▮▮▮▮▮▮❽ 内部防火墙:位于 DMZ 区和内部网络之间,用于控制 DMZ 区访问内部网络的流量,以及内部网络访问 DMZ 区的流量。
▮▮▮▮ⓘ nftables 实现:可以使用 nftables 配置边界防火墙和内部防火墙的规则,实现 DMZ 的隔离和访问控制。

DMZ 网络架构示意图

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 [Internet] -- (边界防火墙) -- [DMZ 区] -- (内部防火墙) -- [内部网络]

nftables DMZ 防火墙配置思路 (简化示例):

边界防火墙 (外部防火墙)
▮▮▮▮⚝ 允许外部网络访问 DMZ 区的 Web 服务器 (TCP 80, 443 端口)。
▮▮▮▮⚝ 阻止外部网络访问 DMZ 区的其他服务。
▮▮▮▮⚝ 允许 DMZ 区访问外部网络的必要服务 (例如 DNS, HTTP/HTTPS 更新)。
▮▮▮▮⚝ 阻止 DMZ 区访问内部网络。

内部防火墙
▮▮▮▮⚝ 允许内部网络访问 DMZ 区的 Web 服务器 (TCP 80, 443 端口)。
▮▮▮▮⚝ 阻止内部网络访问 DMZ 区的其他服务。
▮▮▮▮⚝ 阻止 DMZ 区访问内部网络 (除非有特殊需求,例如数据库访问)。

注意:DMZ 的具体配置需要根据实际的网络架构和安全需求进行详细设计。nftables 只是实现 DMZ 防火墙策略的工具之一。

5.3.2 基于 IP 地址和地理位置的访问控制

基于 IP 地址和地理位置的访问控制是一种更精细的访问控制方式,可以根据请求来源的 IP 地址或地理位置来决定是否允许访问。

基于 IP 地址的访问控制
▮▮▮▮ⓑ 应用场景
▮▮▮▮▮▮▮▮❸ 限制特定 IP 地址或网段的访问:例如,只允许公司总部或分支机构的 IP 地址访问内部应用。
▮▮▮▮▮▮▮▮❹ 阻止恶意 IP 地址的访问:例如,根据入侵检测系统或安全情报,阻止已知的恶意 IP 地址访问。
▮▮▮▮ⓔ nftables 实现:可以使用 ip saddr (源 IP 地址) 或 ip daddr (目标 IP 地址) 匹配表达式,结合 set (集合) 功能,实现高效的 IP 地址访问控制。

nftables 基于 IP 地址的访问控制示例
假设只允许来自 192.168.1.0/2410.0.0.0/24 网段的 IP 地址访问 SSH 服务。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建一个 IP 地址集合包含允许访问 SSH 的网段
2 nft add set inet filter allowed_ssh_ips { type ipv4_addr; flags interval; }
3 nft add element inet filter allowed_ssh_ips { 192.168.1.0/24, 10.0.0.0/24 }
4
5 # 允许来自集合中 IP 地址的 SSH 入站连接
6 nft add rule inet filter input tcp dport 22 ip saddr @allowed_ssh_ips ct state new accept
7
8 # 拒绝其他来源的 SSH 入站连接 (默认策略已设置为 drop)

nft add set inet filter allowed_ssh_ips ...: 创建一个名为 allowed_ssh_ips 的 IP 地址集合,类型为 ipv4_addrflags interval 表示支持网段范围。
nft add element inet filter allowed_ssh_ips ...: 向集合中添加允许的 IP 地址或网段。
ip saddr @allowed_ssh_ips: 匹配源 IP 地址是否属于 allowed_ssh_ips 集合。

基于地理位置的访问控制
▮▮▮▮ⓑ 应用场景
▮▮▮▮▮▮▮▮❸ 限制特定国家或地区的访问:例如,只允许国内用户访问网站,阻止国外用户的访问。
▮▮▮▮▮▮▮▮❹ 根据地理位置进行内容分发:例如,根据用户所在地区,将用户引导到最近的 CDN 节点。
▮▮▮▮ⓔ 实现方式
▮▮▮▮▮▮▮▮❻ GeoIP 数据库:需要使用 GeoIP 数据库,例如 MaxMind GeoIP 数据库,将 IP 地址映射到地理位置信息。
▮▮▮▮▮▮▮▮❼ nftables 扩展模块:需要使用 nftables 的 GeoIP 扩展模块 (例如 nft-geoip),或者结合外部工具 (例如 ipset + GeoIP) 实现地理位置匹配。

nftables 基于地理位置的访问控制思路 (需要安装和配置 GeoIP 扩展模块):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 假设已安装和配置 nft-geoip 模块
2
3 # 允许来自中国的 HTTP 访问
4 nft add rule inet filter input tcp dport 80 geoip country destination { CN } accept
5
6 # 拒绝来自其他国家或地区的 HTTP 访问 (默认策略已设置为 drop)

geoip country destination { CN }: 使用 geoip 表达式,匹配目标 IP 地址的地理位置国家代码是否为 CN (中国)。

注意:基于地理位置的访问控制并非 100% 准确,因为 IP 地址地理位置信息可能存在误差,并且用户可以使用 VPN 或代理服务器绕过地理位置限制。因此,地理位置访问控制通常作为一种辅助的安全措施,而不是唯一的安全手段。

5.3.3 DDoS 防护基础:SYN Flood 防御、连接数限制

DDoS (Distributed Denial of Service,分布式拒绝服务) 攻击是一种常见的网络攻击方式,通过大量恶意请求占用服务器资源,导致正常用户无法访问服务。nftables 可以用于实现一些基础的 DDoS 防护功能,例如 SYN Flood 防御和连接数限制。

SYN Flood 防御
▮▮▮▮ⓑ 原理:SYN Flood 攻击利用 TCP 握手协议的缺陷,发送大量 SYN 包,但不完成后续的握手过程,导致服务器资源被大量半连接占用,无法响应正常的连接请求。
▮▮▮▮ⓒ nftables 防御方法
▮▮▮▮▮▮▮▮❹ 限制新连接速率:使用 limit 表达式限制每秒钟接受的新连接请求数量,防止恶意 SYN 包淹没服务器。
▮▮▮▮▮▮▮▮❺ SYN Cookie:更专业的 SYN Flood 防御技术,需要在内核层面启用 SYN Cookie 功能,nftables 可以配合 SYN Cookie 使用。

nftables SYN Flood 防御示例 (限制新连接速率):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 限制每秒最多接受 20 个新的 TCP 连接请求到 80 端口
2 nft add rule inet filter input tcp dport 80 ct state new limit rate 20/second accept
3
4 # 超过速率限制的连接请求将被默认策略 drop 拒绝

limit rate 20/second: 限制速率为每秒 20 个数据包。超过速率限制的数据包将不会执行 accept 动作,而是继续匹配后续规则或执行默认策略 (drop)。

更专业的 SYN Flood 防御 (需要内核支持 SYN Cookie):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 启用 SYN Cookie (内核参数,需要修改 sysctl 配置)
2 # net.ipv4.tcp_syncookies = 1
3
4 # nftables 规则可以配合 SYN Cookie 使用,但 nftables 本身不直接实现 SYN Cookie 功能
5 # 以下规则仅为示例,实际效果取决于内核 SYN Cookie 的配置和工作方式
6
7 # 允许新的 TCP 连接请求到 80 端口 (依赖内核 SYN Cookie 防御)
8 nft add rule inet filter input tcp dport 80 ct state new accept

注意:SYN Cookie 是一种更专业的 SYN Flood 防御技术,需要在内核层面启用。nftables 可以配合 SYN Cookie 使用,但 nftables 本身不直接实现 SYN Cookie 功能。上述 nftables 规则只是一个简单的示例,实际效果取决于内核 SYN Cookie 的配置和工作方式。更完善的 SYN Flood 防御方案可能需要结合其他技术,例如防火墙硬件、DDoS 防护服务等。

连接数限制
▮▮▮▮ⓑ 原理:某些 DDoS 攻击会建立大量连接,占用服务器连接资源,导致服务器无法响应正常的连接请求。
▮▮▮▮ⓒ nftables 防御方法
▮▮▮▮▮▮▮▮❹ 限制单个 IP 地址的连接数:使用 connlimit 模块 (iptables) 或 set 结合 counter 实现 (nftables),限制单个 IP 地址同时建立的连接数量。

nftables 连接数限制示例 (使用 set 结合 counter):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建一个 map用于记录每个源 IP 地址的连接数
2 nft add map inet filter ip_conn_count { type ipv4_addr : counter }
3
4 # 限制单个 IP 地址最多同时建立 50 个连接到 80 端口
5 nft add rule inet filter input tcp dport 80 ct state new update @ip_conn_count { ip saddr : counter inc } counter less-equal 50 accept
6
7 # 超过连接数限制的连接请求将被默认策略 drop 拒绝

nft add map inet filter ip_conn_count ...: 创建一个名为 ip_conn_count 的 map,键类型为 ipv4_addr,值类型为 counter (计数器)。
⚝ **update @ip_conn_count { ip saddr AlBeRt63EiNsTeIn 对于每个新的连接请求,更新 map 中对应源 IP 地址的计数器,如果不存在则创建并初始化为 1,如果存在则加 1。 ⚝ **counter less-equal 50**: 判断计数器的值是否小于等于 50,如果是则执行accept` 动作,否则继续匹配后续规则或执行默认策略 (drop)。

注意:连接数限制可以有效地防御某些类型的 DDoS 攻击,但过度的连接数限制可能会影响正常用户的访问。因此,需要根据实际情况合理设置连接数限制阈值。此外,更复杂的 DDoS 防护可能需要结合流量清洗、负载均衡、CDN 等技术。

5.4 防火墙日志记录与分析

防火墙日志记录(Firewall Logging)是安全管理的重要组成部分。通过记录防火墙的运行日志,可以了解网络流量情况、安全事件、攻击行为等,为安全分析、故障排查、性能优化提供重要依据。本节将介绍如何配置 nftables 日志,并使用 ulogd 或其他工具进行日志管理与分析。

5.4.1 配置 nftables 日志

nftables 提供了灵活的日志记录功能,可以使用 log 语句将匹配的数据包信息记录到系统日志中。

log 语句的基本用法

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 记录所有被拒绝的入站 TCP 连接
2 nft add rule inet filter input tcp log prefix "nftables-drop-input-tcp: " drop

log: 日志记录语句。
prefix "nftables-drop-input-tcp: ": 可选参数,用于设置日志消息的前缀,方便日志分析和过滤。
drop: 动作,表示拒绝匹配的数据包,并记录日志。

log 语句的常用选项
▮▮▮▮ⓑ prefix "string": 设置日志消息的前缀字符串。
▮▮▮▮ⓒ flags option: 设置日志标志,控制记录哪些信息,常用选项包括:
▮▮▮▮▮▮▮▮❹ tcp-options: 记录 TCP 选项。
▮▮▮▮▮▮▮▮❺ tcp-sequence: 记录 TCP 序列号。
▮▮▮▮▮▮▮▮❻ ip-options: 记录 IP 选项。
▮▮▮▮▮▮▮▮❼ skuid: 记录发起连接的进程 UID。
▮▮▮▮ⓗ group group_id: 将日志消息发送到指定的 ulogd 组 (需要配合 ulogd 使用)。

nftables 日志配置示例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 记录所有被拒绝的入站流量,并添加前缀和日志标志
2 nft add rule inet filter input log prefix "nftables-drop-input: " flags tcp-options,ip-options drop
3
4 # 记录所有被接受的 SSH 连接,并添加前缀
5 nft add rule inet filter input tcp dport 22 log prefix "nftables-accept-ssh: " accept

日志级别
nftables 的 log 语句默认使用内核日志级别 KERN_WARNING (4)。可以通过修改内核日志级别配置,或者使用 ulogd 等工具,将日志消息发送到不同的日志目标,例如不同的日志文件、远程日志服务器等。

日志查看
nftables 的日志消息默认会记录到系统日志中,可以使用 dmesg 命令查看内核日志,或者查看系统日志文件 (例如 /var/log/messages/var/log/syslog,具体路径取决于 Linux 发行版和日志配置)。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 dmesg | grep nftables-drop-input

5.4.2 使用 ulogd 或其他工具进行日志管理与分析

系统日志 (例如 dmesg/var/log/messages) 适用于简单的日志查看,但对于大规模的防火墙日志管理和分析,效率较低。为了更有效地管理和分析防火墙日志,可以使用专门的日志管理工具,例如 ulogd (userspace logging daemon)、rsyslogElasticsearch + Logstash + Kibana (ELK) 等。

ulogd (userspace logging daemon)
▮▮▮▮ⓑ 简介ulogd 是一个用户空间的日志守护进程,可以接收来自内核的日志消息 (例如 Netfilter/nftables 日志),并将日志消息转发到不同的目标,例如文件、数据库、远程日志服务器等。
▮▮▮▮ⓒ 优势
▮▮▮▮▮▮▮▮❹ 高性能ulogd 在用户空间处理日志,避免了内核日志处理的性能瓶颈。
▮▮▮▮▮▮▮▮❺ 灵活配置ulogd 支持多种日志输出目标和格式,可以根据需求灵活配置。
▮▮▮▮▮▮▮▮❻ 插件化架构ulogd 采用插件化架构,可以通过插件扩展功能,例如支持不同的日志输出格式、日志分析功能等。
▮▮▮▮ⓖ nftables 与 ulogd 集成
▮▮▮▮▮▮▮▮❽ group 选项:在 nftables log 语句中使用 group 选项,将日志消息发送到指定的 ulogd 组。
▮▮▮▮▮▮▮▮❾ ulogd 配置:配置 ulogd 监听指定的组 ID,并将接收到的日志消息输出到指定的目标。

nftables 与 ulogd 集成配置示例

  1. 安装 ulogd
1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # Debian/Ubuntu
2 sudo apt-get install ulogd2 ulogd2-sqlite3 # 安装 ulogd2 和 sqlite3 插件
3
4 # CentOS/RHEL
5 sudo yum install ulogd ulogd-sqlite3 # 安装 ulogd 和 sqlite3 插件
  1. 配置 ulogd
    ▮▮▮▮编辑 ulogd 配置文件 (例如 /etc/ulogd.conf/etc/ulogd2.conf),配置日志输出目标和格式。例如,将日志输出到 sqlite3 数据库:
1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 [global]
2 plugin="/usr/lib/ulogd/ulogd_inppkt_NFLOG.so" # NFLOG 输入插件 (nftables 日志)
3 plugin="/usr/lib/ulogd/ulogd_output_SQLITE3.so" # SQLite3 输出插件
4 plugin="/usr/lib/ulogd/ulogd_filter_IFINDEX.so" # 接口索引过滤插件
5
6 [input]
7 plugin=inppkt_NFLOG
8 group=1 # 监听组 ID 1
9
10 [output]
11 plugin=output_SQLITE3
12 file="/var/log/ulogd.db" # SQLite3 数据库文件路径
13 sync=1
14 table="ulog" # 表名
  1. nftables 规则配置
    ▮▮▮▮在 nftables log 语句中使用 group 1,将日志消息发送到 ulogd 监听的组 ID 1。
1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 记录所有被拒绝的入站 TCP 连接,并发送到 ulogd group 1
2 nft add rule inet filter input tcp log group 1 prefix "nftables-drop-input-tcp: " drop
  1. 启动 ulogd
1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 sudo systemctl start ulogd # 或 ulogd2,取决于发行版
  1. 日志分析
    ▮▮▮▮可以使用 sqlite3 客户端或其他工具,查询 ulogd 输出的 sqlite3 数据库,进行日志分析。
1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 sqlite3 /var/log/ulogd.db
2 sqlite> SELECT * FROM ulog WHERE message LIKE '%nftables-drop-input-tcp%';

其他日志管理工具
除了 ulogd,还可以使用其他日志管理工具,例如 rsyslogsyslog-ngFluentdLogstash 等。这些工具通常支持更丰富的功能,例如日志集中管理、实时分析、告警等。选择合适的日志管理工具,需要根据实际需求和技术栈进行评估。

日志分析内容
通过分析防火墙日志,可以获取以下信息:

网络流量趋势:了解网络流量的整体趋势,例如流量峰值、流量分布等。
安全事件:检测潜在的安全事件,例如端口扫描、非法访问、DDoS 攻击等。
攻击来源:分析攻击来源 IP 地址、地理位置等信息,为溯源和反制提供依据。
规则优化:根据日志分析结果,优化防火墙规则,提高安全性和性能。
故障排查:在网络故障排查过程中,防火墙日志可以提供重要的线索。

5.5 防火墙规则的测试与维护

防火墙规则的测试与维护是确保防火墙有效性和稳定性的重要环节。在部署防火墙规则之后,需要进行充分的测试,验证规则是否符合预期,并定期进行维护和优化,以适应不断变化的网络环境和安全需求.

5.5.1 使用 nft monitor 监控规则执行

nft monitor 是 nftables 工具提供的一个非常有用的命令,可以实时监控 nftables 规则的执行过程,包括规则匹配、动作执行、错误信息等。通过 nft monitor,可以直观地了解防火墙规则的工作状态,帮助进行规则调试和性能分析。

nft monitor 基本用法

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 sudo nft monitor

运行 nft monitor 命令后,终端会进入监控模式,实时输出 nftables 事件信息。当有数据包通过防火墙时,nft monitor 会显示匹配的规则、执行的动作等信息。

nft monitor 输出信息
nft monitor 输出的信息包括:

时间戳:事件发生的时间。
事件类型:例如 rule add (规则添加)、rule delete (规则删除)、packet (数据包匹配) 等。
表名、链名、规则句柄:标识触发事件的规则。
数据包信息:例如协议、源 IP 地址、目标 IP 地址、端口等。
动作信息:例如 acceptdroplog 等。

nft monitor 监控示例

  1. 启动 nft monitor
    ▮▮▮▮在一个终端窗口中运行 sudo nft monitor

  2. 测试网络连接
    ▮▮▮▮在另一个终端窗口中,尝试访问被防火墙保护的服务,例如 SSH、HTTP 等。

  3. 查看 nft monitor 输出
    ▮▮▮▮观察 nft monitor 终端窗口的输出信息,可以看到数据包匹配的规则、执行的动作等。

▮▮▮▮例如,如果访问 HTTP 服务,可能会看到类似以下的输出:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table inet filter, chain input, rule 3 packet: iifname "eth0" tcp dport 80 ct state new accept (verdict accept)

▮▮▮▮这表示数据包匹配了 inet filter input 链的第 3 条规则,规则内容为 iifname "eth0" tcp dport 80 ct state new accept,执行的动作是 accept (接受)。

nft monitor 选项
nft monitor 命令还支持一些选项,用于过滤和定制输出信息,例如:

-f <file>: 将监控输出写入到指定文件。
-v: 显示更详细的输出信息 (verbose)。
-q: 静默模式,只输出错误信息 (quiet)。
-t <table>: 只监控指定表的事件。
-c <chain>: 只监控指定链的事件。

nft monitor 应用场景

规则调试:验证新添加的规则是否生效,是否按照预期工作。
性能分析:监控规则执行时间,分析性能瓶颈。
安全审计:实时监控防火墙的运行状态,检测异常流量和攻击行为。
学习 nftables:通过观察 nft monitor 输出,更深入地理解 nftables 规则的执行流程。

5.5.2 规则备份与恢复

防火墙规则的备份与恢复是重要的安全管理措施,可以防止因误操作、系统故障等原因导致规则丢失或损坏,并快速恢复防火墙配置。

规则备份方法
▮▮▮▮ⓑ nft list ruleset 命令:使用 nft list ruleset 命令可以将当前 nftables 规则集导出为文本格式。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 sudo nft list ruleset > /path/to/firewall_rules.nft

▮▮▮▮⚝ nft list ruleset: 输出当前 nftables 规则集。
▮▮▮▮⚝ >: 重定向输出到文件。
▮▮▮▮⚝ /path/to/firewall_rules.nft: 备份文件路径,可以自定义文件名和路径。

▮▮▮▮ⓑ 定期备份:建议定期备份防火墙规则,例如每天或每周备份一次,并将备份文件存储在安全可靠的位置。可以使用 cron 任务或其他自动化工具实现定期备份。

规则恢复方法
▮▮▮▮ⓑ nft -f <file> 命令:使用 nft -f <file> 命令可以从备份文件中加载 nftables 规则。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 sudo nft -f /path/to/firewall_rules.nft

▮▮▮▮⚝ nft -f: 从文件中加载规则。
▮▮▮▮⚝ /path/to/firewall_rules.nft: 备份文件路径。

▮▮▮▮ⓑ 恢复前的准备:在恢复规则之前,建议先备份当前的规则集 (如果可能),以防止恢复过程中出现意外情况。

规则版本控制
对于复杂的防火墙规则集,可以使用版本控制系统 (例如 Git) 管理规则文件,方便规则的版本管理、修改历史追溯、多人协作等。

规则备份与恢复的最佳实践

定期备份:建立定期备份防火墙规则的机制,例如每天或每周备份一次。
自动化备份:使用 cron 任务或其他自动化工具实现自动备份,减少人工操作的错误和遗漏。
异地备份:将备份文件存储在异地,防止本地存储介质损坏导致备份丢失。
版本控制:使用版本控制系统管理规则文件,方便规则的版本管理和协作。
恢复测试:定期进行规则恢复测试,验证备份文件的有效性和恢复流程的正确性。
安全存储:确保备份文件的安全存储,防止泄露或被篡改。

5.5.3 防火墙规则优化与性能调优

随着网络环境和安全需求的变化,防火墙规则也需要不断优化和调整,以提高安全性和性能。规则优化与性能调优是一个持续的过程,需要定期进行评估和改进。

规则优化策略
▮▮▮▮ⓑ 减少规则数量
▮▮▮▮▮▮▮▮❸ 使用集合 (Sets) 和映射 (Maps):使用集合和映射可以有效地减少规则数量,提高规则匹配效率。例如,将多个 IP 地址或端口号放入集合中,使用一条规则匹配整个集合,而不是为每个 IP 地址或端口号编写一条规则。
▮▮▮▮ⓓ 优化规则顺序
▮▮▮▮▮▮▮▮❺ 将常用规则放在前面:将匹配频率较高的规则放在链的前面,可以减少不必要的规则匹配,提高整体性能。
▮▮▮▮▮▮▮▮❻ 将更具体的规则放在前面:对于有重叠匹配条件的规则,将更具体的规则放在前面,避免被更通用的规则误匹配。
▮▮▮▮ⓖ 避免冗余规则和重复匹配
▮▮▮▮▮▮▮▮❽ 删除冗余规则:定期检查规则集,删除不再需要的规则,例如过时的允许规则、重复的拒绝规则等。
▮▮▮▮▮▮▮▮❾ 合并重复匹配条件:如果多条规则具有相同的匹配条件,可以尝试合并成一条规则,减少重复匹配。
▮▮▮▮ⓙ 使用更高效的匹配表达式
▮▮▮▮▮▮▮▮❶ 选择合适的匹配表达式:根据实际需求选择最合适的匹配表达式,例如使用 ip saddr 匹配 IP 地址,使用 tcp dport 匹配 TCP 目标端口等。
▮▮▮▮▮▮▮▮❷ 避免复杂的正则表达式匹配:正则表达式匹配通常性能较低,应尽量避免在防火墙规则中使用复杂的正则表达式。

性能调优方法
▮▮▮▮ⓑ 使用 nft monitor 进行性能分析:使用 nft monitor 监控规则执行时间,分析性能瓶颈,找出耗时较长的规则。
▮▮▮▮ⓒ 优化内核参数:调整 Linux 内核网络参数,例如 TCP 连接参数、网络缓冲区大小等,可以提高整体网络性能,间接提升防火墙性能。
▮▮▮▮ⓓ 硬件加速:如果硬件设备支持,可以启用硬件加速功能 (例如 Flowtables),将部分防火墙处理任务卸载到硬件,提高性能。
▮▮▮▮ⓔ 定期性能测试:定期进行防火墙性能测试,例如吞吐量测试、延迟测试、压力测试等,评估防火墙性能是否满足需求,并根据测试结果进行调优。

规则优化与性能调优的工具

nft monitor: 用于实时监控规则执行,分析性能瓶颈。
nft list ruleset: 用于查看和分析规则集,找出冗余规则和重复匹配。
pingtracerouteiperf 等网络工具: 用于进行网络性能测试,评估防火墙性能。
系统性能监控工具 (例如 topvmstatsar): 用于监控系统资源使用情况,分析性能瓶颈。

总结
防火墙规则的测试与维护是确保防火墙有效性和稳定性的重要环节。通过使用 nft monitor 监控规则执行、进行规则备份与恢复、以及定期进行规则优化与性能调优,可以构建一个安全、高效、可靠的 nftables 防火墙系统,有效地保护网络安全。

ENDOF_CHAPTER_

6. chapter 6: nftables 实战:网络地址转换(NAT)

6.1 NAT 原理与类型:SNAT、DNAT、Masquerade

网络地址转换(Network Address Translation,NAT)是现代网络中至关重要的技术,它允许多个私有网络内的设备通过一个或少量公网 IP 地址访问互联网。NAT 的出现有效地缓解了 IPv4 地址枯竭的问题,并增强了网络安全性。在 nftables 中,NAT 的实现同样强大而灵活,本节将深入探讨 NAT 的原理、类型以及在 nftables 中的基本概念。

6.1.1 源地址转换(SNAT)

源地址转换(Source NAT,SNAT)是最常见的 NAT 类型之一。其核心思想是修改数据包的源 IP 地址。当私有网络内的设备向公网发送数据包时,SNAT 会将数据包的源 IP 地址替换为 NAT 网关的公网 IP 地址。这样,公网服务器接收到的数据包源地址就变成了 NAT 网关的公网 IP,而非私有网络的 IP 地址。

工作原理
当内部网络主机(例如,IP 地址为 192.168.1.100)尝试访问外部网络(例如,8.8.8.8)时,数据包首先到达 NAT 网关。
▮▮▮▮ⓐ NAT 网关上的 nftables 规则会识别出需要进行 SNAT 的数据包。
▮▮▮▮ⓑ nftables 将数据包的源 IP 地址 192.168.1.100 替换为网关的公网 IP 地址,例如 203.0.113.45
▮▮▮▮ⓒ 同时,nftables 会记录这个连接的转换关系(源 IP、源端口、目标 IP、目标端口等),以便后续响应数据包能够正确地反向转换。
▮▮▮▮ⓓ 修改后的数据包以网关的公网 IP 地址作为源地址发送到互联网。
▮▮▮▮ⓔ 当外部服务器响应数据包时,数据包的目标地址是 NAT 网关的公网 IP 地址。
▮▮▮▮ⓕ NAT 网关根据之前记录的连接追踪信息,将数据包的目标 IP 地址 203.0.113.45 还原为内部主机的私有 IP 地址 192.168.1.100,并将数据包转发给内部主机。

应用场景
共享公网 IP:最典型的应用场景是家庭路由器和企业网关,允许多台内部主机共享一个或少量公网 IP 地址访问互联网。
隐藏内部网络结构:SNAT 有效地隐藏了内部网络的真实 IP 地址和拓扑结构,增强了网络安全性。外部网络只能看到 NAT 网关的公网 IP 地址,无法直接访问内部网络主机。

nftables 实现 SNAT 的关键
在 nftables 中,SNAT 主要通过 snat 语句来实现。snat 语句可以指定要替换的源 IP 地址,通常设置为 NAT 网关的公网接口 IP 地址。

6.1.2 目标地址转换(DNAT)

目标地址转换(Destination NAT,DNAT),也称为端口转发(Port Forwarding),其核心思想是修改数据包的目标 IP 地址和/或目标端口。DNAT 常用于将外部网络对公网 IP 地址特定端口的访问请求,转发到内部网络中特定主机的特定端口上。这样,外部用户可以通过访问 NAT 网关的公网 IP 地址和端口,间接访问到内部网络的服务。

工作原理
当外部网络主机(例如,IP 地址为 8.8.8.8)尝试访问内部网络服务器(例如,IP 地址为 192.168.1.100,提供 HTTP 服务端口 80)时,它会向 NAT 网关的公网 IP 地址(例如 203.0.113.45)的特定端口(例如 8080)发送请求。
▮▮▮▮ⓐ NAT 网关上的 nftables 规则会捕获目标地址为 203.0.113.45,目标端口为 8080 的数据包。
▮▮▮▮ⓑ nftables 将数据包的目标 IP 地址 203.0.113.45 替换为内部服务器的私有 IP 地址 192.168.1.100,并将目标端口 8080 替换为内部服务器的 HTTP 服务端口 80(如果需要端口转换)。
▮▮▮▮ⓒ 同样,nftables 会记录这个连接的转换关系,以便后续响应数据包能够正确地反向转换。
▮▮▮▮ⓓ 修改后的数据包以内部服务器的私有 IP 地址和端口作为目标地址发送到内部网络。
▮▮▮▮ⓔ 内部服务器处理请求并返回响应数据包,数据包的源地址是内部服务器的私有 IP 地址和端口,目标地址是外部主机的 IP 地址和端口。
▮▮▮▮ⓕ 当响应数据包返回到 NAT 网关时,NAT 网关根据连接追踪信息,将数据包的源 IP 地址和端口还原为 NAT 网关的公网 IP 地址和端口,并将数据包发送回外部主机。

应用场景
端口转发:允许外部网络访问内部网络提供的服务,例如 Web 服务器、邮件服务器、游戏服务器等。通过将公网 IP 地址的特定端口映射到内部服务器的相应端口,实现服务的发布。
DMZ (Demilitarized Zone,隔离区) 设置:可以将部分服务器放置在 DMZ 区域,通过 DNAT 将外部访问请求转发到 DMZ 区域的服务器,同时通过防火墙规则限制 DMZ 区域与内部网络的访问,提高安全性。
负载均衡:DNAT 可以作为负载均衡的基础,将外部请求分发到后端的多台服务器上,实现简单的负载均衡。

nftables 实现 DNAT 的关键
在 nftables 中,DNAT 主要通过 dnat 语句来实现。dnat 语句可以指定要替换的目标 IP 地址和/或目标端口,通常设置为内部服务器的私有 IP 地址和端口。

6.1.3 伪装(Masquerade)

伪装(Masquerade)是一种特殊的 SNAT 形式,它自动使用网卡接口的 IP 地址作为 SNAT 的源 IP 地址。与 snat 需要显式指定 IP 地址不同,masquerade 更加灵活,尤其适用于 NAT 网关的公网 IP 地址不固定的场景,例如通过 DHCP 动态获取 IP 地址的场景。

工作原理
masquerade 的工作原理与 SNAT 类似,都是修改数据包的源 IP 地址。但 masquerade 的关键在于自动获取出口网卡的 IP 地址
▮▮▮▮ⓐ 当配置了 masquerade 规则时,nftables 会自动检测指定出口网卡的 IP 地址。
▮▮▮▮ⓑ 当需要进行 NAT 转换时,nftables 会使用检测到的网卡 IP 地址作为 SNAT 的源 IP 地址。
▮▮▮▮ⓒ 其余的数据包处理流程与 SNAT 相同,包括连接追踪和反向转换。

应用场景
动态 IP 环境:最典型的应用场景是家庭宽带路由器,其公网 IP 地址通常由 ISP 通过 DHCP 动态分配。masquerade 可以自动适应 IP 地址的变化,无需手动更新 NAT 规则。
简化配置:在公网 IP 地址不固定的情况下,使用 masquerade 可以简化 NAT 配置,避免手动指定 IP 地址的麻烦。

nftables 实现 Masquerade 的关键
在 nftables 中,伪装通过 masquerade 语句来实现。masquerade 语句通常需要指定出口网卡接口,以便 nftables 能够确定使用哪个接口的 IP 地址进行伪装。

masqueradesnat 的选择
snat:适用于公网 IP 地址固定的场景。配置 snat 需要显式指定要使用的公网 IP 地址。优点是配置明确,性能略优于 masquerade
masquerade:适用于公网 IP 地址动态变化的场景。配置 masquerade 无需指定 IP 地址,会自动获取出口网卡 IP。优点是配置灵活,适应性强。缺点是性能略低于 snat,因为需要动态获取 IP 地址。

6.2 使用 nftables 实现 SNAT

源地址转换(SNAT)是 NAT 中最基础且常用的类型。本节将详细介绍如何使用 nftables 实现 SNAT,包括基本配置和高级应用。

6.2.1 配置基本的 SNAT 规则

要配置基本的 SNAT 规则,我们需要创建一个 NAT 表,并在 postrouting 链中添加规则。postrouting 链是数据包在路由决策之后、即将离开网卡时经过的 hook 点,非常适合进行源地址转换。

创建 NAT 表
首先,创建一个类型为 nat 的表。NAT 表专门用于处理 NAT 相关的操作。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add table nat nat

创建 postrouting 链
在 NAT 表中,创建一个名为 postrouting 的基链(base chain),并将其 hook 点设置为 postrouting,优先级设置为 0(默认优先级)。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add chain nat postrouting { type nat hook postrouting priority 0 \; }

添加 SNAT 规则
假设我们的内部网络为 192.168.1.0/24,公网接口为 eth0,公网 IP 地址为 203.0.113.45。我们需要添加一条规则,将源地址为 192.168.1.0/24,且出口接口为 eth0 的数据包进行 SNAT,将源 IP 地址替换为 203.0.113.45

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat postrouting ip saddr 192.168.1.0/24 oifname "eth0" snat to 203.0.113.45

规则解释
ip saddr 192.168.1.0/24: 匹配源 IP 地址为 192.168.1.0/24 网段的数据包。
oifname "eth0": 匹配出口接口为 eth0 的数据包。
snat to 203.0.113.45: 对匹配的数据包执行 SNAT 动作,将源 IP 地址替换为 203.0.113.45

完整配置示例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #!/bin/bash
2 # 清空已有的 nftables 规则 (谨慎操作)
3 nft flush ruleset
4
5 # 创建 nat 表
6 nft add table nat nat
7
8 # 创建 postrouting 链
9 nft add chain nat postrouting { type nat hook postrouting priority 0 \; }
10
11 # 添加 SNAT 规则
12 nft add rule nat postrouting ip saddr 192.168.1.0/24 oifname "eth0" snat to 203.0.113.45
13
14 # 允许转发 (如果需要)
15 echo 1 > /proc/sys/net/ipv4/ip_forward

配置验证
在内部网络主机 192.168.1.100 上执行 curl ifconfig.me 命令,如果返回的 IP 地址是 203.0.113.45,则说明 SNAT 配置成功。

6.2.2 SNAT 的高级应用:多出口 IP 地址

在某些场景下,NAT 网关可能配置了多个公网 IP 地址,例如,为了提高可靠性或实现负载均衡。nftables 允许配置 SNAT 规则,从多个公网 IP 地址中选择一个作为 SNAT 的源 IP 地址。

使用 IP 地址范围
snat 语句可以使用 IP 地址范围,让 nftables 从指定的 IP 地址范围内自动选择一个可用的 IP 地址。

假设 NAT 网关有公网 IP 地址范围 203.0.113.45-203.0.113.50

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat postrouting ip saddr 192.168.1.0/24 oifname "eth0" snat to 203.0.113.45-203.0.113.50

nftables 会自动从 203.0.113.45203.0.113.50 之间选择一个 IP 地址作为 SNAT 的源 IP 地址。选择策略通常是轮询或者根据连接数等因素动态选择。

使用 IP 地址列表
snat 语句也可以使用 IP 地址列表,指定多个可用的公网 IP 地址。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat postrouting ip saddr 192.168.1.0/24 oifname "eth0" snat to { 203.0.113.45, 203.0.113.46, 203.0.113.47 }

nftables 会从列表 203.0.113.45, 203.0.113.46, 203.0.113.47 中选择一个 IP 地址进行 SNAT。

使用网卡接口 IP 地址
如果 NAT 网关的公网 IP 地址是通过网卡接口配置的,可以使用网卡接口名称来指定 SNAT 的源 IP 地址。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat postrouting ip saddr 192.168.1.0/24 oifname "eth0" snat to :eth0

snat to :eth0 表示使用 eth0 接口的 IP 地址作为 SNAT 的源 IP 地址。这种方式更加灵活,当接口 IP 地址发生变化时,SNAT 规则会自动适应。

端口范围指定
snat 还可以指定端口范围,用于 SNAT 后的源端口转换。默认情况下,SNAT 会尽量保持源端口不变,但如果端口冲突,或者需要进行端口映射,可以指定端口范围。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat postrouting ip saddr 192.168.1.0/24 oifname "eth0" snat to 203.0.113.45:1024-65535

:1024-65535 表示 SNAT 后的源端口将从 102465535 范围内选择。

6.3 使用 nftables 实现 DNAT

目标地址转换(DNAT)常用于端口转发,允许外部网络访问内部网络的服务。本节将介绍如何使用 nftables 实现 DNAT,包括端口转发和负载均衡基础配置。

6.3.1 端口转发配置

端口转发是最常见的 DNAT 应用场景。假设我们需要将外部网络对 NAT 网关公网 IP 地址 203.0.113.458080 端口的访问请求,转发到内部网络服务器 192.168.1.10080 端口(HTTP 服务)。

创建 NAT 表和 prerouting 链
DNAT 操作通常在 prerouting 链中进行。prerouting 链是数据包进入路由决策之前经过的 hook 点,非常适合进行目标地址转换。

如果 NAT 表已经创建,则无需重复创建。创建 prerouting 链:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add chain nat prerouting { type nat hook prerouting priority 0 \; }

添加 DNAT 规则
添加 DNAT 规则,将目标地址为 203.0.113.45,目标端口为 8080,协议为 tcp 的数据包,DNAT 到 192.168.1.100:80

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat prerouting tcp dport 8080 ip daddr 203.0.113.45 dnat to 192.168.1.100:80

规则解释
tcp dport 8080: 匹配 TCP 协议,且目标端口为 8080 的数据包。
ip daddr 203.0.113.45: 匹配目标 IP 地址为 203.0.113.45 的数据包。
dnat to 192.168.1.100:80: 对匹配的数据包执行 DNAT 动作,将目标 IP 地址替换为 192.168.1.100,目标端口替换为 80

完整配置示例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #!/bin/bash
2 # 清空已有的 nftables 规则 (谨慎操作)
3 nft flush ruleset
4
5 # 创建 nat 表
6 nft add table nat nat
7
8 # 创建 prerouting 链
9 nft add chain nat prerouting { type nat hook prerouting priority 0 \; }
10
11 # 添加 DNAT 规则 (端口转发)
12 nft add rule nat prerouting tcp dport 8080 ip daddr 203.0.113.45 dnat to 192.168.1.100:80
13
14 # 添加 SNAT 规则 (确保内部服务器响应可以正确返回)
15 nft add rule nat postrouting ip daddr 192.168.1.100 tcp dport 80 snat to 203.0.113.45
16
17 # 允许转发 (如果需要)
18 echo 1 > /proc/sys/net/ipv4/ip_forward

注意
除了 DNAT 规则,通常还需要配置 SNAT 规则,以确保内部服务器响应外部请求时,源地址能够正确转换为 NAT 网关的公网 IP 地址,否则外部主机可能无法正确接收响应。在上面的例子中,我们添加了一条 SNAT 规则,针对目标地址为 192.168.1.100,目标端口为 80 的 TCP 数据包进行 SNAT。

配置验证
从外部网络主机访问 http://203.0.113.45:8080,如果能够访问到内部服务器 192.168.1.100 的 HTTP 服务,则说明端口转发配置成功。

6.3.2 负载均衡基础:DNAT 轮询

DNAT 可以作为简单的负载均衡器使用,将外部请求轮询地转发到后端的多台服务器上。

使用 DNAT 轮询
dnat 语句可以使用 to 关键字后跟多个 IP 地址和端口,实现简单的轮询负载均衡。

假设后端有两台 Web 服务器:192.168.1.101:80192.168.1.102:80

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat prerouting tcp dport 80 ip daddr 203.0.113.45 dnat to 192.168.1.101:80, 192.168.1.102:80

当外部请求访问 203.0.113.45:80 时,nftables 会轮流将请求转发到 192.168.1.101:80192.168.1.102:80

完整配置示例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #!/bin/bash
2 # 清空已有的 nftables 规则 (谨慎操作)
3 nft flush ruleset
4
5 # 创建 nat 表
6 nft add table nat nat
7
8 # 创建 prerouting 链
9 nft add chain nat prerouting { type nat hook prerouting priority 0 \; }
10
11 # 添加 DNAT 规则 (轮询负载均衡)
12 nft add rule nat prerouting tcp dport 80 ip daddr 203.0.113.45 dnat to 192.168.1.101:80, 192.168.1.102:80
13
14 # 添加 SNAT 规则 (确保后端服务器响应可以正确返回)
15 nft add rule nat postrouting ip daddr { 192.168.1.101, 192.168.1.102 } tcp dport 80 snat to 203.0.113.45
16
17 # 允许转发 (如果需要)
18 echo 1 > /proc/sys/net/ipv4/ip_forward

注意
这种轮询 DNAT 方式是一种非常基础的负载均衡方法,它没有考虑后端服务器的健康状态、负载情况等因素。在生产环境中,通常需要使用更专业的负载均衡器,例如 HAProxy、Nginx 等。但对于简单的应用场景或测试环境,DNAT 轮询可以提供快速的负载均衡解决方案。

6.4 Masquerade 的应用场景与配置

伪装(Masquerade)是 SNAT 的一种特殊形式,尤其适用于动态 IP 地址环境。本节将介绍 Masquerade 的应用场景和配置方法。

6.4.1 动态 IP 环境下的网络共享

在家庭宽带或移动网络环境中,公网 IP 地址通常由 ISP 通过 DHCP 动态分配。在这种情况下,使用固定的 SNAT IP 地址是不合适的,因为 IP 地址可能会经常变化。masquerade 可以自动获取出口网卡的 IP 地址,并用作 SNAT 的源 IP 地址,非常适合动态 IP 环境下的网络共享。

配置 Masquerade 规则
假设公网接口为 eth0,内部网络为 192.168.1.0/24。配置 Masquerade 规则非常简单:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule nat postrouting oifname "eth0" masquerade

规则解释
oifname "eth0": 匹配出口接口为 eth0 的数据包。
masquerade: 对匹配的数据包执行 Masquerade 动作。nftables 会自动获取 eth0 接口的 IP 地址作为 SNAT 的源 IP 地址。

完整配置示例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #!/bin/bash
2 # 清空已有的 nftables 规则 (谨慎操作)
3 nft flush ruleset
4
5 # 创建 nat 表
6 nft add table nat nat
7
8 # 创建 postrouting 链
9 nft add chain nat postrouting { type nat hook postrouting priority 0 \; }
10
11 # 添加 Masquerade 规则
12 nft add rule nat postrouting oifname "eth0" masquerade
13
14 # 允许转发 (如果需要)
15 echo 1 > /proc/sys/net/ipv4/ip_forward

配置验证
在内部网络主机上执行 curl ifconfig.me 命令,如果返回的 IP 地址是 eth0 接口的公网 IP 地址,则说明 Masquerade 配置成功。即使 eth0 接口的 IP 地址发生变化,Masquerade 规则仍然有效,无需手动更新。

6.4.2 简化 NAT 配置

即使在公网 IP 地址固定的场景下,使用 masquerade 也可以简化 NAT 配置。与 snat 需要显式指定 IP 地址不同,masquerade 无需指定 IP 地址,只需要指定出口网卡接口即可。这在某些情况下可以减少配置的复杂性。

例如,如果 NAT 网关只有一个公网 IP 地址,且配置在 eth0 接口上,可以使用 masquerade 替代 snat

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 使用 masquerade
2 nft add rule nat postrouting oifname "eth0" masquerade
3
4 # 等价于使用 snat (假设 eth0 的 IP 地址是 203.0.113.45)
5 nft add rule nat postrouting oifname "eth0" snat to 203.0.113.45

在功能上,这两种配置方式在单 IP 地址场景下是等价的。但 masquerade 的配置更简洁。

6.5 NAT 与连接追踪的交互

连接追踪(Connection Tracking)是 Netfilter 和 nftables 的核心功能之一,NAT 的实现也高度依赖于连接追踪。理解 NAT 与连接追踪的交互对于深入理解 NAT 的工作原理和排查 NAT 相关问题至关重要。

6.5.1 NAT 对连接追踪的影响

NAT 操作(SNAT 和 DNAT)会修改数据包的源 IP 地址、目标 IP 地址、源端口或目标端口。这些修改会直接影响连接追踪的行为。

连接追踪表的更新
当数据包经过 NAT 规则时,nftables 会根据 NAT 操作修改连接追踪表中的信息。
▮▮▮▮ⓐ SNAT:当进行 SNAT 时,连接追踪表会记录原始的源 IP 地址和端口,以及转换后的源 IP 地址和端口。这样,当响应数据包返回时,NAT 网关可以根据连接追踪信息将目标地址还原为原始的内部 IP 地址和端口。
▮▮▮▮ⓑ DNAT:当进行 DNAT 时,连接追踪表会记录原始的目标 IP 地址和端口,以及转换后的目标 IP 地址和端口。同样,当响应数据包返回时,NAT 网关可以根据连接追踪信息将源地址还原为原始的外部 IP 地址和端口。

连接状态的维护
连接追踪不仅记录 IP 地址和端口的转换关系,还维护连接的状态,例如 NEW(新连接)、ESTABLISHED(已建立连接)、RELATED(关联连接)等。NAT 操作不会改变连接状态的维护,连接状态仍然按照正常的 TCP/IP 协议流程进行跟踪。

NAT 类型与连接追踪
不同的 NAT 类型(SNAT、DNAT、Masquerade)对连接追踪的影响方式略有不同,但核心都是通过连接追踪表记录转换关系,实现双向通信。

6.5.2 NAT 场景下的连接状态管理

在 NAT 环境中,连接状态管理对于确保 NAT 的正确工作至关重要。例如,在配置防火墙规则时,通常会允许 ESTABLISHEDRELATED 状态的连接通过,以确保 NAT 后的连接能够正常建立和通信。

允许已建立连接和相关连接
在 NAT 防火墙中,通常需要添加规则,允许 ESTABLISHEDRELATED 状态的连接通过。这样可以确保已经建立的连接(例如,SNAT 后的内部主机发起的连接)以及与这些连接相关的连接(例如,FTP 数据连接)能够正常工作。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input ct state { established, related } accept
2 nft add rule inet filter forward ct state { established, related } accept

连接追踪超时设置
连接追踪表中的连接记录会占用系统资源。为了防止连接追踪表无限增长,连接追踪模块会为每种连接状态设置超时时间。当连接在一段时间内没有数据包交互时,连接记录会被自动删除。

在 NAT 环境中,连接追踪超时设置尤为重要。合理的超时设置可以有效地释放连接追踪表资源,提高 NAT 网关的性能。可以使用 sysctl 命令调整连接追踪超时参数,例如:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=3600 # TCP 已建立连接超时时间 (秒)
2 sysctl -w net.netfilter.nf_conntrack_udp_timeout=30 # UDP 连接超时时间 (秒)

具体的超时时间需要根据实际应用场景和网络环境进行调整。

6.6 NAT 故障排除与常见问题

NAT 配置虽然强大,但在实际应用中也可能遇到各种问题。本节将介绍一些常见的 NAT 故障排除方法和常见问题。

无法访问外部网络(SNAT/Masquerade 故障)
检查 SNAT/Masquerade 规则:确认 SNAT 或 Masquerade 规则是否正确配置,包括源地址范围、出口接口等。
检查路由配置:确认 NAT 网关的路由配置是否正确,内部网络流量是否正确路由到 NAT 网关,NAT 网关是否能够路由到外部网络。
检查出口接口 IP 地址:如果使用 masquerade,确认出口接口是否配置了公网 IP 地址,且 IP 地址是否正确。
检查防火墙规则:确认防火墙规则是否阻止了内部网络到外部网络的流量。

端口转发不生效(DNAT 故障)
检查 DNAT 规则:确认 DNAT 规则是否正确配置,包括目标端口、目标 IP 地址、内部服务器 IP 地址和端口等。
检查防火墙规则:确认防火墙规则是否允许外部网络访问 NAT 网关的端口,以及是否允许 NAT 网关转发流量到内部服务器。
检查内部服务器监听端口:确认内部服务器是否在监听正确的端口,且服务是否正常运行。
检查 SNAT 回流规则:确认是否配置了 SNAT 回流规则,确保内部服务器响应能够正确返回给外部主机。
连接追踪状态检查:使用 nft monitorconntrack -L 命令监控连接追踪状态,查看是否有连接记录生成,以及连接状态是否正常。

NAT 性能问题
规则优化:优化 nftables 规则集,减少规则数量,提高规则匹配效率。
Flowtables 加速:如果硬件支持,可以考虑使用 Flowtables 加速 NAT 性能。
连接追踪参数调优:根据实际负载情况,调整连接追踪超时参数,避免连接追踪表过大。
硬件升级:如果软件优化效果不明显,可能需要考虑升级 NAT 网关的硬件性能。

常见问题
端口冲突:在配置 DNAT 时,需要注意端口冲突问题。如果 NAT 网关的公网 IP 地址的某个端口已经被其他服务占用,则无法将该端口用于端口转发。
应用层协议兼容性:某些应用层协议(例如,FTP、SIP)在 NAT 环境下可能存在兼容性问题,需要进行特殊的 NAT 穿越配置(例如,ALG - Application Layer Gateway)。
连接追踪表溢出:在高并发连接场景下,连接追踪表可能会溢出,导致新的连接无法建立。需要合理配置连接追踪表大小和超时参数,或者考虑使用无状态 NAT 技术。

通过理解 NAT 的原理、类型、配置方法以及与连接追踪的交互,并掌握常见的故障排除方法,可以有效地应用 nftables 实现各种 NAT 功能,并解决实际网络环境中的 NAT 相关问题。

ENDOF_CHAPTER_

7. chapter 7: nftables 实战:流量整形与 QoS

7.1 流量整形与 QoS 基础概念

在深入探讨 nftables 如何实现流量整形(Traffic Shaping)与服务质量(Quality of Service, QoS)之前,我们首先需要理解这两个关键概念及其背后的基本原理。流量整形和 QoS 是网络管理中至关重要的技术,它们帮助我们优化网络资源利用率,提升用户体验,并确保关键业务应用的性能。

7.1.1 流量整形(Traffic Shaping)与流量监管(Traffic Policing)

流量整形(Traffic Shaping)和流量监管(Traffic Policing)都是控制网络流量的技术,但它们在实现方式和目标上存在显著差异,理解这些差异对于有效地应用 QoS 策略至关重要。

流量整形(Traffic Shaping)

流量整形,也称为流量平滑(Traffic Smoothing),其主要目标是平滑网络流量,使其传输速率符合预定的策略。当流量速率超过预设的限制时,整形机制会将超出部分的流量延迟发送,通常会将这些数据包放入缓冲区(Buffer)或队列中,然后以一个更加平稳的速率发送出去。

核心特点
▮▮▮▮▮▮▮▮⚝ 延迟:流量整形会延迟超出速率限制的流量,而不是直接丢弃。
▮▮▮▮▮▮▮▮⚝ 平滑:通过延迟发送,流量整形可以有效地平滑突发流量,减少网络拥塞。
▮▮▮▮▮▮▮▮⚝ 缓冲区:通常需要缓冲区来存储被延迟的数据包。
▮▮▮▮▮▮▮▮⚝ 适用场景:适用于需要保证带宽,但不允许突发流量影响网络稳定性的场景,例如,视频流媒体服务、VoIP 等。

流量监管(Traffic Policing)

流量监管的目标是限制网络流量的速率,当流量速率超过预设的阈值时,监管机制会采取丢弃标记超出部分流量的措施。与流量整形不同,流量监管不会延迟流量,而是直接对超出部分进行处理。

核心特点
▮▮▮▮▮▮▮▮⚝ 丢弃或标记:流量监管主要通过丢弃或标记超出速率限制的流量来实现速率控制。标记通常用于后续的 QoS 处理,例如,降低优先级。
▮▮▮▮▮▮▮▮⚝ 立即生效:流量监管对超出速率的流量立即采取行动,不会产生延迟。
▮▮▮▮▮▮▮▮⚝ 无缓冲区:流量监管通常不需要缓冲区。
▮▮▮▮▮▮▮▮⚝ 适用场景:适用于需要严格限制带宽使用,并对超出流量进行惩罚的场景,例如,限制用户上传下载速度、防止 DDoS 攻击等。

对比总结

特性流量整形(Traffic Shaping)流量监管(Traffic Policing)
处理方式延迟发送丢弃或标记
缓冲区需要缓冲区无需缓冲区
流量平滑平滑突发流量不平滑,直接限制速率
延迟引入延迟无延迟
网络拥塞缓解有效缓解网络拥塞缓解拥塞能力相对较弱
适用场景保带宽、平滑流量限带宽、惩罚超速流量

理解流量整形和流量监管的区别,有助于我们在实际应用中选择合适的技术。例如,对于需要保证服务质量的应用,如在线会议,我们可能更倾向于使用流量整形,以平滑流量并减少延迟抖动;而对于需要严格控制带宽的应用,如文件共享服务,流量监管可能更合适,以防止个别用户过度占用带宽。

7.1.2 QoS 的目标与策略

服务质量(Quality of Service, QoS)是一系列网络技术的集合,旨在保证网络应用获得可预测的网络性能,尤其是在网络资源受限或拥塞的情况下。QoS 的目标是根据不同应用的需求,为其分配不同的网络资源,从而优化整体网络体验。

QoS 的主要目标

带宽保证(Bandwidth Guarantee):为关键应用预留足够的带宽,确保其正常运行所需的最低带宽需求得到满足。
延迟控制(Latency Control):降低网络延迟,特别是对于实时性要求高的应用,如 VoIP 和在线游戏,延迟控制至关重要。
抖动控制(Jitter Control):减少数据包到达时间间隔的变化,即抖动,抖动会严重影响实时音视频通信的质量。
丢包率降低(Packet Loss Reduction):降低数据包在传输过程中丢失的概率,提高数据传输的可靠性。
优先级区分(Priority Differentiation):为不同类型的流量设置不同的优先级,确保高优先级流量优先获得网络资源。

QoS 的基本策略

为了实现上述 QoS 目标,通常需要采用以下策略:

分类与标记(Classification and Marking):
▮▮▮▮ⓐ 分类:识别不同类型的网络流量,例如,根据源地址、目标地址、端口号、协议类型、应用类型等进行分类。
▮▮▮▮ⓑ 标记:对分类后的流量进行标记,例如,使用 IP 报头中的 DSCP(Differentiated Services Code Point)字段或 VLAN 标签中的 CoS(Class of Service)字段进行标记。标记信息将在后续的 QoS 处理中被使用。

队列管理(Queue Management):
▮▮▮▮ⓐ 优先级队列(Priority Queuing, PQ):根据流量的优先级,将数据包放入不同的队列中,高优先级队列的数据包优先被发送。
▮▮▮▮ⓑ 加权公平队列(Weighted Fair Queuing, WFQ):为每个队列分配不同的权重,根据权重比例分配带宽资源,确保公平性。
▮▮▮▮ⓒ 随机早期检测(Random Early Detection, RED):在队列拥塞之前,随机丢弃一部分数据包,以提前预警拥塞,避免全局同步现象。

拥塞避免(Congestion Avoidance):
▮▮▮▮ⓐ 流量整形(Traffic Shaping):如前所述,通过延迟发送超出速率限制的流量,平滑突发流量,减少网络拥塞。
▮▮▮▮ⓑ 流量监管(Traffic Policing):限制流量速率,防止过度占用网络资源,减轻拥塞。

资源预留(Resource Reservation):
▮▮▮▮ⓐ RSVP(Resource Reservation Protocol):一种信令协议,允许应用在网络中预留资源,例如,带宽。虽然 RSVP 在现代网络中应用较少,但其思想仍然重要。

QoS 策略的应用层面

QoS 策略可以应用在不同的网络层面,包括:

链路层 QoS:例如,IEEE 802.1p 协议定义的 CoS 字段,用于在 VLAN 环境中标记数据帧的优先级。
网络层 QoS:例如,IP 报头中的 DSCP 字段,用于标记 IP 数据包的优先级,DiffServ(Differentiated Services)模型就是基于 DSCP 实现 QoS 的典型架构。
应用层 QoS:一些应用协议本身也支持 QoS,例如,RTP(Real-time Transport Protocol)协议可以携带 QoS 相关的信息。

nftables 中,我们可以利用其强大的匹配和动作能力,结合 Linux 内核的 QoS 功能,实现精细化的流量整形和 QoS 策略。接下来的章节将详细介绍如何使用 nftables 的各种表达式和语句,构建有效的 QoS 解决方案。

7.2 使用 limit 表达式进行速率限制

nftables 提供了 limit 表达式,用于实现基本的速率限制功能。limit 表达式可以基于连接数或数据包速率对流量进行限制,是实现简单 QoS 策略的有效工具。

7.2.1 基于连接数限制

基于连接数限制是指限制在一定时间内允许建立的新连接数量。这种方法常用于防止突发的连接请求,例如,限制 Web 服务器在单位时间内接受的新连接数,以防止 SYN Flood 攻击或过载。

limit 表达式语法

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 limit rate {数量}/{时间单位} burst {突发数量}

rate {数量}/{时间单位}:定义允许的最大速率。{数量} 是指在 {时间单位} 内允许通过的最大数量,可以是数据包数或连接数。{时间单位} 可以是 secondminutehourday 或其缩写 secondminutehourday
burst {突发数量}:定义允许的突发数量。突发数量是指在速率限制允许的情况下,额外允许通过的最大数量。突发机制允许在短时间内超过平均速率,以应对突发流量。

示例:限制 SSH 连接速率

假设我们需要限制每分钟最多允许 5 个新的 SSH 连接,并允许最多 10 个连接的突发。可以使用以下 nftables 规则:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input tcp dport 22 limit rate 5/minute burst 10 packets counter accept

规则解释
▮▮▮▮ⓐ inet filter input:规则添加到 inet 表的 filter 链的 input 链上,用于处理进入主机的流量。
▮▮▮▮ⓑ tcp dport 22:匹配目标端口为 22 的 TCP 流量,即 SSH 流量。
▮▮▮▮ⓒ limit rate 5/minute burst 10 packets:应用 limit 表达式,限制速率为每分钟 5 个数据包,突发数量为 10 个数据包。这里虽然写的是 packets,但实际上 limit 表达式会跟踪连接建立的速率,因此可以理解为限制每分钟 5 个新连接。
▮▮▮▮ⓓ counter accept:如果流量符合速率限制,则执行 accept 动作,并增加计数器。

测试连接数限制

可以使用 netcatssh 等工具快速建立多个连接进行测试。在短时间内尝试建立超过 5 个 SSH 连接,观察是否只有前 5 个连接成功,后续连接被延迟或拒绝。可以使用 nft monitor 命令实时监控规则的执行情况。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft monitor

在另一个终端窗口,尝试快速建立多个 SSH 连接:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 for i in {1..10}; do ssh user@your_server & done

观察 nft monitor 的输出,以及 SSH 连接的建立情况,验证速率限制是否生效。

7.2.2 基于数据包速率限制

基于数据包速率限制是指限制在一定时间内允许通过的数据包数量。这种方法可以更精细地控制流量速率,例如,限制特定协议或特定端口的数据包速率,防止带宽被过度占用。

示例:限制 ICMP 数据包速率

假设我们需要限制每秒钟最多允许 10 个 ICMP 数据包通过,并允许最多 20 个数据包的突发。可以使用以下 nftables 规则:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input ip protocol icmp limit rate 10/second burst 20 packets counter accept

规则解释
▮▮▮▮ⓐ inet filter input:规则添加到 inet 表的 filter 链的 input 链上。
▮▮▮▮ⓑ ip protocol icmp:匹配协议为 ICMP 的流量,即 ping 命令使用的协议。
▮▮▮▮ⓒ limit rate 10/second burst 20 packets:应用 limit 表达式,限制速率为每秒钟 10 个数据包,突发数量为 20 个数据包。
▮▮▮▮ⓓ counter accept:如果流量符合速率限制,则执行 accept 动作,并增加计数器。

测试数据包速率限制

可以使用 ping 命令发送大量 ICMP 数据包进行测试。在发送 ping 命令时,可以使用 -f 参数进行 flood ping,快速发送大量数据包。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ping -f -c 100 your_server

观察 ping 命令的输出,以及使用 nft monitor 监控规则的执行情况。如果速率限制生效,应该只有一部分 ping 数据包被允许通过,超出速率限制的数据包会被丢弃(默认动作是 drop,如果没有明确指定 accept)。

结合 reject 动作

在实际应用中,除了 accept 动作外,我们还可以结合 reject 动作,对超出速率限制的流量进行明确拒绝,并返回 ICMP 错误信息。例如,对于超出 ICMP 速率限制的流量,可以返回 icmp-admin-prohibited 错误:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input ip protocol icmp limit rate 10/second burst 20 packets reject icmp-admin-prohibited

这样,当 ping 命令发送的数据包超过速率限制时,会收到 icmp-admin-prohibited 错误回复,更明确地告知发送方流量被限制。

limit 表达式是 nftables 中实现简单速率限制的有效手段,适用于对连接数或数据包速率进行基本控制的场景。然而,对于更复杂的流量控制需求,例如,基于带宽的精确控制、流量整形、优先级队列等,limit 表达式的功能就显得不足。在后续章节中,我们将介绍 meterquota 语句,以及如何与 Linux 高级队列技术 tc 集成,实现更强大的流量整形和 QoS 功能。

7.3 使用 meterquota 进行流量控制

nftables 提供了 meter(计量器)和 quota(配额)语句,用于实现更高级的流量控制功能,包括基于带宽的速率限制和基于流量配额的资源管理。与 limit 表达式相比,meterquota 提供了更灵活、更强大的流量控制机制。

7.3.1 基于流量计量器的带宽控制

meter(计量器)语句允许我们基于带宽对流量进行计量和控制。计量器可以跟踪流量的速率,并根据预设的速率限制,对超出部分的流量执行相应的动作,例如,丢弃或跳转到其他链进行处理。

meter 语句语法

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add meter inet filter {meter_name} {type} {properties}

meter_name:计量器的名称,用于在规则中引用。
type:计量器的类型,常用的类型包括:
▮▮▮▮ⓐ rate:基于速率的计量器,用于限制带宽。
▮▮▮▮ⓑ packet:基于数据包计数的计量器,用于限制数据包数量。
properties:计量器的属性,根据类型不同,属性也不同。对于 rate 类型,常用的属性包括:
▮▮▮▮ⓐ rate {带宽}/{时间单位}:定义允许的最大带宽速率。例如,rate 10mbit/second 表示限制为 10 Mbps。
▮▮▮▮ⓑ burst {字节数}:定义允许的突发流量大小,以字节为单位。例如,burst 10kbyte 表示允许 10 KB 的突发流量。
▮▮▮▮ⓒ overhead {字节数}:定义每个数据包的开销字节数,用于更精确地计算带宽。例如,以太网帧头和帧尾的开销。

示例:限制 HTTP 下载带宽

假设我们需要限制 HTTP 下载的带宽为 1 Mbps,并允许 10 KB 的突发流量。可以使用以下 nftables 规则:

首先,创建计量器:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add meter inet filter http_download_meter rate { rate 1mbit/second burst 10kbyte }

然后,创建规则使用计量器:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward tcp dport 80 meter http_download_meter drop

规则解释
▮▮▮▮ⓐ nft add meter inet filter http_download_meter ...:创建名为 http_download_meter 的计量器,类型为 rate,速率限制为 1 Mbps,突发大小为 10 KB。
▮▮▮▮ⓑ nft add rule inet filter forward tcp dport 80 meter http_download_meter drop:规则添加到 inet 表的 filter 链的 forward 链上,用于处理转发流量。匹配目标端口为 80 的 TCP 流量(HTTP 流量)。使用 meter http_download_meter 语句,将流量与计量器关联。如果流量超出速率限制,则执行 drop 动作。

测试带宽控制

可以使用 wgetcurl 等工具下载大文件进行测试。在下载过程中,观察下载速度是否被限制在 1 Mbps 左右。可以使用 iftopbmon 等工具实时监控网络带宽使用情况。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 wget http://example.com/large_file

同时,使用 iftop 监控网络接口的带宽使用情况:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 iftop -i eth0

观察 iftop 的输出,验证下载速度是否被限制在 1 Mbps 左右。

7.3.2 基于流量配额的资源管理

quota(配额)语句允许我们基于流量配额对资源进行管理。配额可以限制在一定时间内允许通过的总流量大小。当流量超过配额时,可以执行相应的动作,例如,丢弃或跳转到其他链进行处理。

quota 语句语法

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add quota inet filter {quota_name} {type} {properties}

quota_name:配额的名称,用于在规则中引用。
type:配额的类型,常用的类型包括:
▮▮▮▮ⓐ bytes:基于字节数的配额,用于限制总流量大小。
▮▮▮▮ⓑ packets:基于数据包计数的配额,用于限制总数据包数量。
properties:配额的属性,根据类型不同,属性也不同。对于 bytes 类型,常用的属性包括:
▮▮▮▮ⓐ quota {总字节数}:定义允许的总流量大小,以字节为单位。例如,quota 1gbyte 表示限制为 1 GB。
▮▮▮▮ⓑ used {已用字节数}(可选):定义已使用的流量大小,用于初始化配额。默认值为 0。

示例:限制每日下载总流量

假设我们需要限制每天每个用户下载的总流量为 1 GB。可以使用 map 结合 quota 实现基于用户 IP 的流量配额管理。

首先,创建一个 map 用于存储用户 IP 和已用流量:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add map inet filter user_quota_map { type ipv4_addr : counter }

然后,创建配额:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add quota inet filter daily_download_quota bytes quota 1gbyte

创建规则,使用 mapquota

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward ip saddr @user_quota_map counter name user_quota_map verdict continue quota daily_download_quota drop

规则解释
▮▮▮▮ⓐ nft add map inet filter user_quota_map ...:创建名为 user_quota_mapmap,键类型为 IPv4 地址,值类型为计数器,用于记录每个用户的已用流量。
▮▮▮▮ⓑ nft add quota inet filter daily_download_quota ...:创建名为 daily_download_quota 的配额,类型为 bytes,总配额为 1 GB。
▮▮▮▮ⓒ nft add rule inet filter forward ip saddr @user_quota_map ...:规则添加到 inet 表的 filter 链的 forward 链上。
▮▮▮▮▮▮▮▮❹ ip saddr @user_quota_map:匹配源 IP 地址,并使用 map 更新计数器。如果 IP 地址不存在于 map 中,则会自动创建新的条目,并初始化计数器为 0。
▮▮▮▮▮▮▮▮❺ counter name user_quota_map:更新 map 中对应 IP 地址的计数器,记录已用流量。
▮▮▮▮▮▮▮▮❻ verdict continue quota daily_download_quota drop:使用 quota daily_download_quota 语句,将流量与配额关联。如果流量超出配额,则执行 drop 动作。verdict continue 表示即使配额未超出,也继续执行后续规则(如果有)。

配额重置

上述规则实现了基于用户 IP 的每日下载总流量限制。为了实现每日重置配额,需要定期清空 user_quota_map 和重置 daily_download_quota 的已用流量计数器。可以使用 nft flush quota 命令重置配额:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft flush quota inet filter daily_download_quota

可以结合 cron 任务,每天定时执行配额重置操作,实现每日流量配额管理。

meterquota 语句为 nftables 提供了强大的流量控制能力,可以实现基于带宽的速率限制和基于流量配额的资源管理。结合 map 等高级特性,可以构建更灵活、更精细化的 QoS 策略。在实际应用中,可以根据具体需求选择合适的流量控制方法,优化网络资源利用率,提升用户体验。

7.4 高级队列技术与 nftables 集成

虽然 nftables 自身提供了 limitmeterquota 等基本的流量控制功能,但对于更高级的 QoS 需求,例如,优先级队列、加权公平队列、复杂的流量整形算法等,还需要借助 Linux 内核的高级队列技术(Advanced Queueing, AQ)。Linux 的 tc(traffic control)命令是配置和管理高级队列的主要工具。nftables 可以与 tc 协同工作,通过 nftables 强大的数据包匹配和标记能力,结合 tc 丰富的队列管理功能,实现更精细、更强大的 QoS 解决方案。

7.4.1 Linux 流量控制(tc)框架简介

Linux tc 命令是 Linux 内核提供的流量控制工具,用于配置和管理网络接口的队列规则(qdisc, queueing discipline)。tc 框架的核心概念包括:

队列规则(qdisc, queueing discipline)

队列规则是 tc 框架的核心,它定义了数据包在网络接口上的排队和调度策略。每个网络接口可以配置一个根队列规则(root qdisc),根队列规则下可以包含多个子队列规则,形成一个树状结构。

常用的队列规则类型包括:

pfifo_fast:默认的队列规则,基于数据包的 TOS(Type of Service)或 CoS 优先级进行简单优先级排队。
prio:优先级队列规则,允许创建多个优先级队列,高优先级队列的数据包优先被发送。
htb(Hierarchical Token Bucket):分层令牌桶队列规则,功能强大的队列规则,支持分层结构、带宽保证、流量整形等功能,常用于构建复杂的 QoS 策略。
cbq(Class Based Queueing):基于类的队列规则,也支持分层结构和带宽管理,但配置相对复杂,已被 htb 逐渐取代。
fq_codel(Fair Queueing with Controlled Delay):公平队列规则,旨在减少网络延迟和抖动,适用于交互式应用和实时应用。
sfq(Stochastic Fairness Queueing):随机公平队列规则,旨在提供公平的带宽分配,防止个别流量过度占用带宽。

类(class)

类是队列规则的子单元,用于对流量进行分类和管理。在支持分层结构的队列规则(如 htbcbq)中,可以在队列规则下创建多个类,每个类可以配置不同的队列规则、过滤器和流量控制参数。

过滤器(filter)

过滤器用于将数据包分类到不同的类或队列。过滤器可以基于数据包的各种属性进行匹配,例如,源地址、目标地址、端口号、协议类型、IP 报头中的 DSCP 字段等。tc 过滤器可以与 nftables 标记的数据包协同工作,实现更灵活的流量分类。

动作(action)

动作定义了对匹配到的数据包执行的操作。常用的动作包括:

police:流量监管动作,用于限制流量速率,可以丢弃或标记超出速率限制的流量。
mirred:镜像动作,用于将数据包复制一份发送到另一个网络接口。
pedit:数据包编辑动作,用于修改数据包的某些字段,例如,修改 DSCP 字段。
mark:标记动作,用于给数据包打上内核标记,供后续的 tc 过滤器或 nftables 规则使用。

7.4.2 nftables 与 tc 的协同工作

nftablestc 可以通过以下方式协同工作,实现更强大的 QoS 功能:

nftables 标记数据包,tc 基于标记进行队列管理

这是 nftablestc 协同工作最常用的方式。nftables 规则可以使用 mark 语句给符合特定条件的数据包打上内核标记(fwmark)。然后,tc 过滤器可以基于数据包的内核标记,将数据包分类到不同的队列或类中,应用不同的队列规则和流量控制策略。

nftables 使用 queue 动作,将数据包排队到用户空间

nftables 提供了 queue 动作,可以将数据包排队到用户空间,由用户空间程序进行处理。用户空间程序可以实现更复杂的流量处理逻辑,例如,应用层 QoS、深度包检测(DPI)等。虽然 queue 动作提供了很大的灵活性,但用户空间处理会引入额外的性能开销,通常只在特殊场景下使用。

tc 使用 u32 过滤器,匹配 nftables 设置的 conntrack 标记

tcu32 过滤器可以匹配数据包的 conntrack 标记(ctmark)。nftables 规则可以使用 ct mark set 语句设置 conntrack 标记。通过这种方式,tc 可以基于连接状态或更复杂的 nftables 规则进行流量分类。

7.4.3 使用 nftables 标记数据包,tc 进行队列管理

下面以一个示例,演示如何使用 nftables 标记数据包,然后使用 tc 基于标记进行优先级队列管理。

配置 tc 优先级队列

首先,使用 tc 命令在网络接口 eth0 上配置 prio 优先级队列规则。prio 队列规则默认创建 3 个优先级队列,队列 0 优先级最高,队列 2 优先级最低。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 tc qdisc add dev eth0 root handle 1: prio

然后,为每个优先级队列创建过滤器,将不同标记的数据包分类到不同的队列。假设我们使用内核标记值 1、2、3 分别代表高、中、低优先级流量。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 tc filter add dev eth0 parent 1: protocol ip u32 match mark 1 0xff flowid 1:1
2 tc filter add dev eth0 parent 1: protocol ip u32 match mark 2 0xff flowid 1:2
3 tc filter add dev eth0 parent 1: protocol ip u32 match mark 3 0xff flowid 1:3

命令解释
▮▮▮▮ⓐ tc qdisc add dev eth0 root handle 1: prio:在 eth0 接口上添加根队列规则 prio,句柄为 1:
▮▮▮▮ⓑ tc filter add dev eth0 parent 1: protocol ip u32 match mark ...:为根队列规则 1: 添加过滤器,协议为 IP,使用 u32 过滤器匹配数据包的内核标记。
▮▮▮▮▮▮▮▮❸ match mark 1 0xff flowid 1:1:匹配内核标记值为 1 的数据包,将其分类到队列 1:1(优先级队列 0)。
▮▮▮▮▮▮▮▮❹ match mark 2 0xff flowid 1:2:匹配内核标记值为 2 的数据包,将其分类到队列 1:2(优先级队列 1)。
▮▮▮▮▮▮▮▮❺ match mark 3 0xff flowid 1:3:匹配内核标记值为 3 的数据包,将其分类到队列 1:3(优先级队列 2)。

配置 nftables 规则标记数据包

接下来,配置 nftables 规则,根据流量类型给数据包打上相应的内核标记。例如,将 SSH 流量标记为高优先级(标记值 1),HTTP 流量标记为中优先级(标记值 2),其他流量标记为低优先级(标记值 3)。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add table inet filter
2 nft add chain inet filter forward
3 nft add rule inet filter forward tcp dport 22 counter mark set 1
4 nft add rule inet filter forward tcp dport 80 counter mark set 2
5 nft add rule inet filter forward counter mark set 3

规则解释
▮▮▮▮ⓐ nft add table inet filter:创建 inetfilter
▮▮▮▮ⓑ nft add chain inet filter forward:在 filter 表中创建 forward 链。
▮▮▮▮ⓒ nft add rule inet filter forward tcp dport 22 counter mark set 1:匹配目标端口为 22 的 TCP 流量(SSH 流量),打上内核标记 1。
▮▮▮▮ⓓ nft add rule inet filter forward tcp dport 80 counter mark set 2:匹配目标端口为 80 的 TCP 流量(HTTP 流量),打上内核标记 2。
▮▮▮▮ⓔ nft add rule inet filter forward counter mark set 3:匹配所有其他流量,打上内核标记 3。

测试优先级队列

配置完成后,可以使用 pingsshwget 等工具产生不同类型的流量进行测试。观察不同类型流量的延迟和带宽分配情况,验证优先级队列是否生效。可以使用 tc qdisc show dev eth0tc class show dev eth0 命令查看队列规则和类的配置信息。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 tc qdisc show dev eth0
2 tc class show dev eth0

通过 nftables 标记数据包,结合 tc 高级队列技术,我们可以实现更精细、更强大的 QoS 策略,满足各种复杂的网络流量管理需求。例如,可以使用 htb 队列规则实现分层带宽管理、流量整形和带宽保证,为不同类型的应用提供差异化的服务质量。

7.5 基于 nftables 的应用层 QoS

虽然 nftables 主要工作在网络层和传输层,但通过结合一些扩展模块和技巧,也可以实现一定程度的应用层 QoS。应用层 QoS 的目标是基于应用协议或应用类型进行流量控制和优先级管理。例如,优先保障 VoIP 语音流量的质量,限制 P2P 下载流量的带宽。

7.5.1 识别应用层协议

要实现应用层 QoS,首先需要识别应用层协议nftables 本身不具备深度包检测(DPI)能力,无法直接解析应用层协议内容。但是,可以通过以下方法在一定程度上识别应用层协议:

基于端口号识别

最简单的方法是基于端口号识别应用层协议。许多应用协议使用固定的或常用的端口号,例如,HTTP 使用 80 端口,HTTPS 使用 443 端口,DNS 使用 53 端口,SSH 使用 22 端口等。nftables 可以根据 TCP/UDP 端口号匹配流量,从而初步识别应用层协议。

例如,识别 HTTP 流量:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward tcp dport 80 counter

识别 HTTPS 流量:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward tcp dport 443 counter

基于连接追踪辅助识别

连接追踪模块可以记录连接的应用层协议信息。例如,对于 HTTP 协议,连接追踪模块可以记录连接是否为 HTTP 连接。nftables 可以使用 ct helper 表达式,匹配连接追踪模块识别的应用层协议。

例如,识别 HTTP 协议(需要连接追踪模块支持 HTTP 协议识别):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward ct helper http counter

使用 payload 表达式进行浅层协议识别

nftablespayload 表达式可以访问数据包的载荷部分,进行浅层协议识别。例如,可以检查 HTTP 请求的 Host 头部,或 DNS 查询的域名信息。但 payload 表达式的匹配能力有限,且性能开销较大,不适合进行复杂的 DPI。

例如,检查 HTTP Host 头部是否包含特定域名:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward tcp dport 80 payload base 52 offset 0 length 20 match "example.com" counter

这种方法只能进行简单的字符串匹配,且偏移量和长度需要根据协议格式进行调整,不够灵活和可靠。

结合用户空间程序进行深度协议识别

更可靠的应用层协议识别方法是结合用户空间程序进行深度包检测(DPI)。可以使用 nftablesqueue 动作将数据包排队到用户空间,由用户空间程序进行 DPI 分析,识别应用层协议,并根据识别结果,通过 Netlink 接口动态修改 nftables 规则或设置 conntrack 标记,再由 nftablestc 进行后续的 QoS 处理。

这种方法灵活性高,可以实现复杂的应用层协议识别和 QoS 策略,但性能开销较大,实现也较为复杂。

7.5.2 基于应用类型进行 QoS 策略配置

在识别应用层协议的基础上,可以根据应用类型配置相应的 QoS 策略。例如:

优先保障 VoIP 语音流量

对于 VoIP 语音流量(例如,基于 SIP 协议或 RTP 协议的流量),可以设置更高的优先级,保证低延迟和低抖动,提升语音通话质量。可以使用基于端口号或连接追踪辅助识别 VoIP 流量,并使用 nftables 标记数据包,结合 tc 优先级队列进行 QoS 保障。

例如,将 UDP 端口范围 16384-32767 的流量标记为高优先级(假设 VoIP 应用使用此端口范围):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter forward udp dport range 16384-32767 counter mark set 1

然后,结合 tc 优先级队列,将标记为 1 的流量放入高优先级队列。

限制 P2P 下载流量带宽

对于 P2P 下载流量(例如,BitTorrent 协议),可以限制其带宽,防止 P2P 流量过度占用网络资源,影响其他应用的性能。可以使用基于端口号或 DPI 方法识别 P2P 流量,并使用 nftablesmeter 语句或结合 tchtb 队列规则进行带宽限制。

例如,限制 TCP 端口范围 6881-6889 的流量带宽为 1 Mbps(假设 BitTorrent 协议常用此端口范围):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add meter inet filter p2p_meter rate { rate 1mbit/second burst 10kbyte }
2 nft add rule inet filter forward tcp dport range 6881-6889 meter p2p_meter drop

区分在线视频和网页浏览流量

对于在线视频流量(例如,YouTube、Netflix 等),可以给予一定的带宽保证,但优先级低于 VoIP 流量。对于网页浏览流量,可以设置为中等优先级。可以使用基于端口号、域名或 DPI 方法区分不同类型的流量,并使用 nftables 标记数据包,结合 tc 分层队列规则进行 QoS 管理。

例如,将访问特定视频网站域名的 HTTP/HTTPS 流量标记为中优先级,普通网页浏览流量标记为低优先级(需要结合域名解析和连接追踪辅助识别):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 假设已通过某种方式识别出访问视频网站的流量,并设置了 conntrack 标记 ct mark 10
2 nft add rule inet filter forward ct mark 10 counter mark set 2 # 视频流量标记为 2
3 nft add rule inet filter forward tcp dport {80, 443} counter mark set 3 # 普通网页浏览流量标记为 3

然后,结合 tc 分层队列规则,将不同标记的流量放入不同的优先级队列或类中,实现差异化的 QoS 策略。

应用层 QoS 的实现相对复杂,需要根据具体的应用场景和需求,选择合适的协议识别方法和 QoS 策略。nftables 提供了灵活的规则配置和扩展能力,可以与 Linux 内核的 QoS 功能协同工作,构建强大的应用层 QoS 解决方案。

ENDOF_CHAPTER_

8. chapter 8: nftables 性能优化与最佳实践

8.1 nftables 性能优势深度剖析

nftables 作为 iptables 的继任者,在设计之初就充分考虑了性能问题。它不仅仅是语法的革新,更在内核层面进行了深度的优化,从而在处理网络数据包时展现出更高效的性能。本节将深入剖析 nftables 在内核数据结构和规则匹配算法上的优化,并通过性能测试对比,量化展示 nftables 相对于 iptables 的性能优势。

8.1.1 内核数据结构优化

nftables 在内核中使用了更为高效的数据结构来存储和管理规则集,这是其性能提升的关键因素之一。相较于 iptables 线性遍历规则链的方式,nftables 采用了更加灵活和高效的数据结构,例如:

链式哈希表(Chained Hash Tables):nftables 使用链式哈希表来组织表(tables)、链(chains)和规则(rules)。哈希表能够实现接近常数时间的查找效率,显著减少了规则查找的时间复杂度。
▮▮▮▮ⓑ 表和链的快速查找:通过哈希表,nftables 可以快速定位到指定的表和链,而无需像 iptables 那样遍历链表。
▮▮▮▮ⓒ 规则的快速定位:在链内部,规则也通过哈希表进行组织,加速了规则的匹配过程。

灵活的表达式树(Expression Trees):nftables 将规则的匹配条件和动作表示为表达式树。这种结构允许内核更高效地解析和执行规则,并为未来的优化提供了更大的空间。
▮▮▮▮ⓑ 优化的规则解析:表达式树使得规则的解析过程更加结构化和高效,减少了不必要的计算开销。
▮▮▮▮ⓒ 更易于优化:表达式树的结构使得内核可以更容易地进行规则优化,例如规则重排、公共子表达式消除等。

共享规则集(Shared Rule Sets):在某些情况下,nftables 允许在不同的表或链之间共享规则集。这不仅减少了内存占用,也提高了规则的加载和执行效率。
▮▮▮▮ⓑ 减少内存占用:共享规则集避免了规则的重复存储,节省了宝贵的内存资源。
▮▮▮▮ⓒ 提高效率:规则共享意味着内核可以更有效地利用缓存,减少了规则加载和执行的开销。

总而言之,nftables 通过采用链式哈希表、表达式树和共享规则集等先进的数据结构,从根本上提升了规则的存储和查找效率,为性能的提升奠定了坚实的基础。

8.1.2 规则匹配算法优化

除了数据结构的优化,nftables 在规则匹配算法上也进行了改进,进一步提升了数据包处理的速度。

字节码引擎(Bytecode Engine):nftables 引入了字节码引擎来执行规则匹配。规则被编译成字节码,由虚拟机执行,这比 iptables 的解释执行方式更加高效。
▮▮▮▮ⓑ 编译执行:将规则编译成字节码,避免了每次数据包到达时都进行规则解析的开销。
▮▮▮▮ⓒ 虚拟机优化:字节码虚拟机可以针对特定的硬件平台进行优化,进一步提升执行效率。

JIT (Just-In-Time) 编译:在某些架构上,nftables 甚至可以进行 JIT 编译,将字节码动态编译成本地机器码执行,实现极致的性能。
▮▮▮▮ⓑ 动态编译:将热点规则动态编译成本地机器码,充分利用硬件性能。
▮▮▮▮ⓒ 极致性能:JIT 编译能够最大限度地减少规则执行的开销,实现接近硬件级别的性能。

规则集预编译和加载:nftables 允许将规则集预编译成二进制格式,并快速加载到内核中。这大大缩短了防火墙启动和规则更新的时间。
▮▮▮▮ⓑ 快速启动:预编译规则集可以显著缩短防火墙启动时间,尤其是在规则集非常庞大的情况下。
▮▮▮▮ⓒ 快速更新:规则更新也可以通过预编译的方式进行,减少了规则生效的延迟。

优化的集合(Sets)和映射(Maps)查找:nftables 对集合和映射的查找进行了优化,使用了高效的查找算法,例如哈希查找、树查找等,使得基于集合和映射的规则匹配更加快速。
▮▮▮▮ⓑ 高效查找算法:根据集合和映射的类型,选择合适的查找算法,例如哈希查找适用于无序集合,树查找适用于有序集合。
▮▮▮▮ⓒ 加速集合和映射操作:优化的查找算法显著提升了集合和映射操作的性能,使得使用集合和映射的规则更加高效。

通过字节码引擎、JIT 编译、规则集预编译和加载,以及优化的集合和映射查找等技术,nftables 在规则匹配算法上实现了质的飞跃,大幅提升了数据包处理的效率。

8.1.3 性能测试对比:nftables vs iptables

理论分析之外,实际的性能测试更能直观地展示 nftables 的优势。大量的性能测试表明,在各种场景下,nftables 的性能都优于 iptables。以下是一些典型的性能测试结果和分析:

规则匹配速度:在相同的规则集下,nftables 的规则匹配速度通常比 iptables 快数倍甚至数十倍。尤其是在规则数量庞大、规则逻辑复杂的情况下,nftables 的优势更加明显。
▮▮▮▮ⓑ 线性规则链 vs 哈希表:iptables 线性遍历规则链,时间复杂度为 O(n),而 nftables 使用哈希表,时间复杂度接近 O(1)。
▮▮▮▮ⓒ 字节码引擎 vs 解释执行:nftables 的字节码引擎比 iptables 的解释执行效率更高。

吞吐量(Throughput):在高负载的网络环境下,nftables 的吞吐量通常高于 iptables。这意味着在相同的硬件条件下,使用 nftables 的系统能够处理更多的网络流量。
▮▮▮▮ⓑ 更低的 CPU 占用:nftables 更高效的规则处理,意味着更低的 CPU 占用,从而释放更多的 CPU 资源用于处理网络流量。
▮▮▮▮ⓒ 更高的网络性能:更高的吞吐量直接转化为更高的网络性能,提升了系统的整体网络处理能力。

延迟(Latency):在对延迟敏感的应用场景中,nftables 通常能够提供更低的延迟。这对于实时性要求高的应用,例如在线游戏、音视频通话等至关重要。
▮▮▮▮ⓑ 更快的规则处理:nftables 更快的规则处理速度,直接降低了数据包在防火墙上的处理延迟。
▮▮▮▮ⓒ 更好的用户体验:更低的延迟能够提升用户体验,尤其是在对延迟敏感的应用中。

CPU 占用率:在相同的负载下,nftables 的 CPU 占用率通常低于 iptables。这意味着使用 nftables 的系统可以节省更多的 CPU 资源,用于运行其他应用或服务。
▮▮▮▮ⓑ 高效的内核实现:nftables 在内核数据结构和算法上的优化,降低了 CPU 的消耗。
▮▮▮▮ⓒ 更低的资源消耗:更低的 CPU 占用率意味着更低的资源消耗,提高了系统的资源利用率。

性能测试案例

简单防火墙规则集:在简单的防火墙规则集下,nftables 的性能提升可能不那么明显,但仍然优于 iptables。
复杂防火墙规则集:当规则集变得复杂,例如包含大量的规则、复杂的匹配条件、集合和映射时,nftables 的性能优势会显著放大。
高并发连接场景:在高并发连接的场景下,nftables 的连接追踪(connection tracking)机制更加高效,能够更好地应对高负载。
DDoS 防御场景:在 DDoS 防御场景中,nftables 的性能优势尤为突出,能够更有效地过滤恶意流量,保护系统安全。

总结

通过内核数据结构优化、规则匹配算法优化以及大量的性能测试验证,nftables 展现出了相对于 iptables 的显著性能优势。选择 nftables 不仅是拥抱新技术,更是提升网络性能、降低资源消耗、提高系统安全性的明智之举。在对性能有较高要求的场景下,nftables 无疑是更佳的选择。

8.2 规则集优化策略

即使 nftables 本身具有优秀的性能,但如果规则集设计不合理,仍然可能导致性能下降。因此,掌握规则集优化策略至关重要。本节将介绍如何通过减少规则数量、优化规则顺序以及避免冗余规则等方法,提升 nftables 规则集的性能。

8.2.1 减少规则数量:集合与映射的应用

规则数量的增加通常会直接导致性能下降。因此,减少规则数量是规则集优化的首要任务。nftables 提供的集合(sets)和映射(maps)功能,正是减少规则数量、提升规则集效率的利器。

使用集合(Sets)合并相似规则:当需要对多个 IP 地址、端口或协议应用相同的策略时,可以使用集合将这些元素组织起来,然后使用一条规则引用该集合,代替多条重复的规则。
▮▮▮▮ⓑ 场景示例:例如,要阻止来自多个恶意 IP 地址的访问,可以使用一个 IP 地址集合,然后使用一条规则 ip saddr @blacklist drop 即可,而无需为每个 IP 地址编写一条 ip saddr <IP 地址> drop 规则。
▮▮▮▮ⓒ 优势
▮▮▮▮▮▮▮▮❹ 减少规则数量:将多个相似规则合并为一条,显著减少规则集的规模。
▮▮▮▮▮▮▮▮❺ 提高效率:减少了规则匹配的次数,提升了规则执行效率。
▮▮▮▮▮▮▮▮❻ 易于维护:修改策略时,只需要更新集合中的元素,无需修改多条规则。

使用映射(Maps)实现策略的精细化控制:映射可以将一个键(例如 IP 地址、端口)映射到一个值(例如策略动作、流量控制参数)。通过映射,可以根据不同的键值应用不同的策略,实现更精细化的控制,同时减少规则数量。
▮▮▮▮ⓑ 场景示例:例如,要根据不同的源 IP 地址应用不同的流量限制策略,可以使用一个 IP 地址到流量限制参数的映射,然后使用一条规则根据源 IP 地址查找映射表,并应用相应的流量限制策略。
▮▮▮▮ⓒ 优势
▮▮▮▮▮▮▮▮❹ 精细化控制:可以根据不同的键值应用不同的策略,实现更灵活的控制。
▮▮▮▮▮▮▮▮❺ 减少规则数量:使用一条规则和映射表代替多条规则,减少规则集的规模。
▮▮▮▮▮▮▮▮❻ 提高灵活性:策略调整更加灵活,只需要修改映射表即可。

动态集合(Dynamic Sets):对于需要动态更新的集合,例如黑名单、白名单等,可以使用动态集合。动态集合可以根据规则的执行结果自动添加或删除元素,无需手动维护,简化了管理,也提高了效率。
▮▮▮▮ⓑ 场景示例:例如,可以使用动态集合实现自动化的 DDoS 防御。当检测到来自某个 IP 地址的恶意流量时,自动将其添加到动态黑名单集合中,并阻止其后续访问。
▮▮▮▮ⓒ 优势
▮▮▮▮▮▮▮▮❹ 自动化管理:动态集合自动维护,无需人工干预,降低了管理成本。
▮▮▮▮▮▮▮▮❺ 实时更新:集合内容可以实时更新,及时反映网络状况变化。
▮▮▮▮▮▮▮▮❻ 提高效率:动态集合的自动更新机制,保证了规则集的实时性和有效性。

最佳实践

⚝ 尽可能使用集合和映射来合并相似规则,减少规则数量。
⚝ 充分利用动态集合的自动化管理功能,简化规则维护。
⚝ 在设计规则集时,优先考虑使用集合和映射来组织规则逻辑。

8.2.2 优化规则顺序:提高匹配效率

规则的匹配是按照规则在链中的顺序进行的。因此,合理的规则顺序可以显著提高规则匹配的效率。优化规则顺序的基本原则是:将更常用、更可能匹配的规则放在前面,将不常用、不太可能匹配的规则放在后面

将常用规则放在前面:将处理常见流量的规则放在链的前面,可以减少不必要的规则匹配,提高整体效率。
▮▮▮▮ⓑ 场景示例:例如,对于 Web 服务器,允许 HTTP/HTTPS 流量的规则应该放在前面,而阻止其他不常用端口的规则可以放在后面。
▮▮▮▮ⓒ 优势
▮▮▮▮▮▮▮▮❹ 减少匹配次数:常用规则优先匹配,减少了后续规则的匹配次数。
▮▮▮▮▮▮▮▮❺ 提高效率:整体规则匹配速度加快,提升了数据包处理效率。

将更具体的规则放在前面:更具体的规则通常具有更高的优先级。例如,针对特定 IP 地址或端口的规则应该放在更通用的规则前面。
▮▮▮▮ⓑ 场景示例:例如,允许特定 IP 地址访问 SSH 服务的规则,应该放在允许所有 IP 地址访问 HTTP 服务的规则前面。
▮▮▮▮ⓒ 优势
▮▮▮▮▮▮▮▮❹ 精确匹配:更具体的规则优先匹配,保证了策略的精确性。
▮▮▮▮▮▮▮▮❺ 避免误判:避免通用规则误判,确保策略的正确执行。

accept 规则放在前面accept 规则通常是处理正常流量的规则,应该放在前面,快速放行正常流量,减少后续规则的处理。
▮▮▮▮ⓑ 场景示例:例如,允许已建立连接的规则 ct state established,related accept 应该放在链的最前面。
▮▮▮▮ⓒ 优势
▮▮▮▮▮▮▮▮❹ 快速放行accept 规则优先匹配,快速放行正常流量。
▮▮▮▮▮▮▮▮❺ 减少处理开销:减少了后续规则对正常流量的处理开销。

使用 gotojump 语句优化流程:对于复杂的规则集,可以使用 gotojump 语句将规则链分成多个子链,并根据不同的条件跳转到不同的子链进行处理。这可以优化规则匹配流程,提高效率。
▮▮▮▮ⓑ 场景示例:例如,可以根据协议类型将规则链分成 TCP 子链、UDP 子链和 ICMP 子链,然后根据数据包的协议类型跳转到相应的子链进行处理。
▮▮▮▮ⓒ 优势
▮▮▮▮▮▮▮▮❹ 流程优化:将规则链分成子链,优化了规则匹配流程。
▮▮▮▮▮▮▮▮❺ 提高效率:减少了不必要的规则匹配,提升了整体效率。
▮▮▮▮▮▮▮▮❻ 结构清晰:子链结构使得规则集更加模块化,结构更清晰,易于维护。

最佳实践

⚝ 分析网络流量特征,将常用规则、更具体的规则和 accept 规则放在前面。
⚝ 对于复杂的规则集,使用 gotojump 语句优化规则匹配流程。
⚝ 定期评估规则顺序,根据实际流量情况进行调整。

8.2.3 避免冗余规则和重复匹配

冗余规则和重复匹配不仅浪费资源,也会降低规则集的性能。因此,避免冗余规则和重复匹配是规则集优化的重要方面。

删除冗余规则:检查规则集,删除功能重复或永远不会被匹配到的规则。
▮▮▮▮ⓑ 场景示例:例如,如果已经有一条规则 ip saddr 192.168.1.0/24 drop,那么规则 ip saddr 192.168.1.100 drop 就是冗余的,应该删除。
▮▮▮▮ⓒ 方法
▮▮▮▮▮▮▮▮❹ 规则审查:定期审查规则集,识别和删除冗余规则。
▮▮▮▮▮▮▮▮❺ 工具辅助:可以使用工具辅助规则审查,例如规则集分析工具。

合并重复匹配条件:如果多条规则使用了相同的匹配条件,可以考虑将这些规则合并,减少重复匹配。
▮▮▮▮ⓑ 场景示例:例如,如果有多条规则都使用了 ip protocol tcptcp dport 80 这两个匹配条件,可以考虑将这些规则合并成一条,或者使用集合来优化。
▮▮▮▮ⓒ 方法
▮▮▮▮▮▮▮▮❹ 条件分析:分析规则集中的匹配条件,识别重复条件。
▮▮▮▮▮▮▮▮❺ 规则合并:将使用重复条件的规则合并,或者使用集合和映射来优化。

使用最有效的匹配条件:选择最有效的匹配条件,避免使用低效的匹配条件。例如,使用 IP 地址匹配通常比使用域名匹配更高效。
▮▮▮▮ⓑ 场景示例:例如,如果需要阻止访问某个网站,优先使用网站的 IP 地址,而不是域名。
▮▮▮▮ⓒ 原则
▮▮▮▮▮▮▮▮❹ 精确匹配优先:优先使用精确匹配条件,例如 IP 地址、端口号。
▮▮▮▮▮▮▮▮❺ 避免复杂匹配:尽量避免使用复杂的匹配条件,例如正则表达式匹配。

利用连接追踪(Connection Tracking):充分利用连接追踪机制,避免对已建立连接的数据包进行重复匹配。例如,使用 ct state established,related accept 规则快速放行已建立连接和相关连接的数据包。
▮▮▮▮ⓑ 优势
▮▮▮▮▮▮▮▮❸ 减少重复匹配:连接追踪机制可以识别已建立连接的数据包,避免重复匹配。
▮▮▮▮▮▮▮▮❹ 提高效率:显著提升了处理已建立连接的数据包的效率。

最佳实践

⚝ 定期审查规则集,删除冗余规则。
⚝ 分析规则集中的匹配条件,合并重复条件。
⚝ 选择最有效的匹配条件,避免使用低效的匹配条件。
⚝ 充分利用连接追踪机制,避免重复匹配。

8.3 利用 Flowtables 提升性能

Flowtables 是 nftables 提供的一种硬件加速机制,可以将部分规则卸载到硬件层面进行处理,从而大幅提升网络数据包的处理速度。本节将介绍 Flowtables 的概念、适用场景以及如何配置和使用 Flowtables 来加速网络处理。

8.3.1 Flowtables 的适用场景

Flowtables 并非适用于所有场景,它主要针对流(flow)类型的网络流量进行加速。流是指具有相同五元组(源 IP 地址、目标 IP 地址、源端口、目标端口、协议)的数据包序列。Flowtables 的优势在于:

硬件加速:Flowtables 将流的规则卸载到网卡硬件或交换芯片上进行处理,利用硬件的并行处理能力,大幅提升数据包处理速度。
▮▮▮▮ⓑ 卸载到硬件:将规则卸载到硬件,减轻了 CPU 的负担。
▮▮▮▮ⓒ 并行处理:硬件可以并行处理多个数据包,提高了处理效率。

低延迟:由于硬件处理速度快,Flowtables 可以显著降低数据包的处理延迟。
▮▮▮▮ⓑ 硬件速度:硬件处理速度远高于软件处理速度。
▮▮▮▮ⓒ 降低延迟:降低延迟对于实时性要求高的应用非常重要。

高吞吐量:Flowtables 可以处理大量的网络流量,提高网络吞吐量。
▮▮▮▮ⓑ 高负载能力:硬件可以承受更高的网络负载。
▮▮▮▮ⓒ 提升吞吐量:提升吞吐量意味着可以处理更多的网络流量。

适用场景

高流量网络环境:例如数据中心、骨干网络等,需要处理大量网络流量的场景。
需要硬件加速的场景:例如防火墙、路由器、交换机等,需要硬件加速来提升性能的场景。
流类型流量为主的场景:例如 TCP 长连接、视频流等,流类型流量占比较高的场景。

不适用场景

低流量网络环境:在低流量网络环境下,Flowtables 的性能提升可能不明显。
非流类型流量为主的场景:例如 UDP 短连接、控制信令等,非流类型流量占比较高的场景。
硬件不支持 Flowtables 的环境:如果网卡硬件或交换芯片不支持 Flowtables,则无法使用硬件加速功能。

注意事项

⚝ Flowtables 主要加速的是转发(forward)链上的流量,对于 inputoutput 链上的流量加速效果有限。
⚝ Flowtables 的规则功能相对简单,只支持基本的五元组匹配和 accept 动作,不支持复杂的规则逻辑。
⚝ Flowtables 的配置和管理相对复杂,需要对硬件和网络协议有深入的了解。

8.3.2 合理配置 Flowtables 加速网络处理

要利用 Flowtables 加速网络处理,需要进行合理的配置。配置 Flowtables 的基本步骤如下:

检查硬件支持:首先需要检查网卡硬件或交换芯片是否支持 Flowtables 功能。通常可以在网卡驱动或硬件文档中找到相关信息。
▮▮▮▮ⓑ 网卡驱动:查看网卡驱动是否支持 Flowtables 特性。
▮▮▮▮ⓒ 硬件文档:查阅网卡硬件或交换芯片的文档,确认是否支持 Flowtables。

启用 Flowtables 功能:在 nftables 中,需要显式地启用 Flowtables 功能。可以通过在 table 语句中添加 use flowtables 参数来启用。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table inet filter use flowtables {
2 # ...
3 }

创建 Flowtables 链:在启用了 Flowtables 功能的表中,可以创建 Flowtables 链。Flowtables 链的类型为 filternat,hook 点通常为 forward

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table inet filter use flowtables {
2 chain forward flowtable {
3 type filter hook forward priority 0; policy accept;
4 # ... Flowtables 规则 ...
5 }
6 }

添加 Flowtables 规则:在 Flowtables 链中添加规则。Flowtables 规则的语法与普通规则类似,但功能和限制有所不同。Flowtables 规则通常只包含基本的五元组匹配和 accept 动作。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table inet filter use flowtables {
2 chain forward flowtable {
3 type filter hook forward priority 0; policy accept;
4 ip protocol tcp tcp dport { 80, 443 } flow add @flowtable
5 }
6 chain forward filter {
7 type filter hook forward priority 1; policy accept;
8 # ... 普通规则 ...
9 }
10 }

▮▮▮▮ⓐ flow add @flowtable 动作:使用 flow add @flowtable 动作将匹配的流添加到 Flowtables 中。
▮▮▮▮ⓑ 普通规则链:Flowtables 链通常与普通规则链配合使用,Flowtables 链处理可以硬件加速的流,普通规则链处理其他流量。

监控 Flowtables 状态:可以使用 nft monitor 命令监控 Flowtables 的状态,例如已卸载的流数量、命中次数等。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft monitor flowtable inet filter forward-flowtable

配置示例

以下示例配置了一个简单的 Flowtables 规则,将 TCP 端口 80 和 443 的流量卸载到硬件加速:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 table inet filter use flowtables {
2 chain forward flowtable {
3 type filter hook forward priority 0; policy accept;
4 ip protocol tcp tcp dport { 80, 443 } flow add @flowtable
5 }
6
7 chain forward filter {
8 type filter hook forward priority 1; policy accept;
9 ct state established,related accept
10 iifname "eth0" tcp dport 22 accept
11 iifname "eth0" drop
12 }
13 }

最佳实践

⚝ 仅在硬件支持 Flowtables 的情况下使用 Flowtables 功能。
⚝ 仅将流类型流量的规则卸载到 Flowtables,例如 TCP 长连接、视频流等。
⚝ Flowtables 规则应尽可能简单,只包含基本的五元组匹配和 accept 动作。
⚝ Flowtables 链应与普通规则链配合使用,Flowtables 链处理可以硬件加速的流,普通规则链处理其他流量。
⚝ 定期监控 Flowtables 状态,评估性能提升效果。

8.4 nftables 配置的监控与调优

有效的监控和调优是保证 nftables 配置高性能运行的关键。本节将介绍如何使用 nft monitor 进行实时监控,如何进行性能瓶颈分析和定位,以及如何进行系统资源监控和调整,从而实现 nftables 配置的最佳性能。

8.4.1 使用 nft monitor 进行实时监控

nft monitor 是 nftables 提供的一个强大的实时监控工具,可以实时显示规则的执行情况、数据包的匹配信息、错误信息等。通过 nft monitor,可以深入了解 nftables 的运行状态,及时发现和解决问题。

基本用法

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft monitor

该命令会实时输出 nftables 的事件信息,包括规则的添加、删除、修改,数据包的匹配,错误信息等。

常用选项

-nn: 以数字形式显示 IP 地址和端口号,避免 DNS 反向解析,提高效率。
-t: 显示时间戳,方便分析事件发生的时间顺序。
-e: 仅显示错误信息,方便快速定位错误。
-f <file>: 将监控输出保存到文件中。
--table <table_name>: 仅监控指定表的事件。
--chain <chain_name>: 仅监控指定链的事件。
--rule <rule_handle>: 仅监控指定规则的事件。

监控示例

监控所有事件,并显示时间戳和数字地址

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft monitor -nt

仅监控错误信息

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft monitor -e

监控指定表 inet filter 的事件

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft monitor --table inet filter

监控指定链 inet filter input 的事件

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft monitor --table inet filter --chain input

监控指定规则句柄为 123 的规则的事件

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft monitor --rule 123

应用场景

规则调试:使用 nft monitor 可以实时查看规则的匹配情况,帮助调试规则逻辑是否正确。
性能分析:通过监控规则的执行次数、数据包的匹配信息,可以分析规则集的性能瓶颈。
安全监控:监控错误信息和异常事件,及时发现安全问题。
实时日志:将监控输出保存到文件中,作为实时日志使用。

最佳实践

⚝ 在规则调试阶段,使用 nft monitor 实时监控规则执行情况,确保规则逻辑正确。
⚝ 在性能分析阶段,使用 nft monitor 结合其他性能分析工具,定位性能瓶颈。
⚝ 在安全监控场景中,可以使用 nft monitor -e 仅监控错误信息,及时发现异常情况。
⚝ 根据实际需求选择合适的监控选项,避免输出过多信息影响性能。

8.4.2 性能瓶颈分析与定位

当 nftables 配置性能不佳时,需要进行性能瓶颈分析和定位。常见的性能瓶颈包括:

规则集过于庞大:规则数量过多,导致规则匹配时间过长。
▮▮▮▮ⓑ 症状:CPU 占用率高,吞吐量下降,延迟增加。
▮▮▮▮ⓒ 定位:使用 nft list ruleset 查看规则集大小,分析规则数量是否过多。
▮▮▮▮ⓓ 优化:使用集合和映射减少规则数量,优化规则集结构。

规则逻辑复杂:规则的匹配条件过于复杂,例如使用了大量的正则表达式、深度包检测等,导致规则匹配时间过长。
▮▮▮▮ⓑ 症状:CPU 占用率高,吞吐量下降,延迟增加。
▮▮▮▮ⓒ 定位:分析规则集,识别复杂的匹配条件,评估其性能影响。
▮▮▮▮ⓓ 优化:简化规则逻辑,避免使用过于复杂的匹配条件,使用更高效的匹配方法。

规则顺序不合理:常用规则放在后面,导致不必要的规则匹配,降低效率。
▮▮▮▮ⓑ 症状:CPU 占用率略高,吞吐量略有下降。
▮▮▮▮ⓒ 定位:分析规则顺序,评估规则顺序是否合理。
▮▮▮▮ⓓ 优化:优化规则顺序,将常用规则、更具体的规则和 accept 规则放在前面。

连接追踪开销过大:连接追踪机制在高并发连接场景下可能会带来一定的性能开销。
▮▮▮▮ⓑ 症状:CPU 占用率高,内存占用高,高并发连接场景下性能下降。
▮▮▮▮ⓒ 定位:使用 conntrack -C 命令查看连接追踪表大小,评估连接追踪开销。
▮▮▮▮ⓓ 优化:优化连接追踪配置,例如调整连接追踪表大小、超时时间等,或者在不需要连接追踪的场景下禁用连接追踪。

硬件资源不足:CPU、内存、网卡等硬件资源不足,导致 nftables 无法充分发挥性能。
▮▮▮▮ⓑ 症状:CPU 满载,内存耗尽,网卡瓶颈,系统整体性能下降。
▮▮▮▮ⓒ 定位:使用 topfreesar 等系统监控工具,查看硬件资源使用情况。
▮▮▮▮ⓓ 优化:升级硬件资源,例如更换更快的 CPU、增加内存、更换更高性能的网卡。

性能分析工具

nft monitor: 实时监控规则执行情况,辅助规则调试和性能分析。
perf: Linux 性能分析工具,可以深入分析内核函数调用,定位性能瓶颈。
火焰图(Flame Graph): 可视化性能分析结果,直观展示 CPU 占用情况。
conntrack -C: 查看连接追踪表大小,评估连接追踪开销。
tophtop: 实时监控系统资源使用情况。
vmstatiostatsar: 系统性能统计工具,提供更全面的性能数据。

性能瓶颈定位流程

  1. 观察系统性能:使用 tophtop 等工具观察 CPU、内存、网络等资源使用情况,初步判断性能瓶颈。
  2. 使用 nft monitor 监控:使用 nft monitor 实时监控规则执行情况,分析规则匹配是否耗时过长。
  3. 使用 perf 和火焰图分析:使用 perf 采集性能数据,生成火焰图,深入分析内核函数调用,定位性能瓶颈。
  4. 分析规则集:分析规则集大小、规则逻辑、规则顺序等,评估规则集对性能的影响。
  5. 评估连接追踪开销:使用 conntrack -C 查看连接追踪表大小,评估连接追踪开销。
  6. 检查硬件资源:使用 vmstatiostatsar 等工具检查硬件资源使用情况,判断是否硬件资源不足。

8.4.3 系统资源监控与调整

系统资源监控和调整是保证 nftables 配置高性能运行的重要环节。需要实时监控 CPU、内存、网络等资源使用情况,并根据监控结果进行相应的调整。

监控指标

CPU 占用率:反映 CPU 的繁忙程度,过高的 CPU 占用率可能导致性能下降。
内存使用率:反映内存的使用情况,内存不足可能导致系统崩溃或性能急剧下降。
网络吞吐量:反映网络的传输能力,吞吐量过低可能影响网络应用性能。
数据包丢包率:反映网络数据包丢失的情况,丢包率过高可能导致网络连接不稳定或性能下降。
延迟:反映网络延迟的大小,延迟过高可能影响实时性应用的用户体验。
连接追踪表大小:反映连接追踪机制的开销,连接追踪表过大可能导致内存占用过高。

监控工具

命令行工具tophtopvmstatiostatsarfreenetstatssconntrack 等。
图形化工具GrafanaPrometheusZabbixCacti 等。

资源调整策略

CPU 优化
▮▮▮▮⚝ 优化规则集:减少规则数量、简化规则逻辑、优化规则顺序。
▮▮▮▮⚝ 使用 Flowtables:将部分规则卸载到硬件加速。
▮▮▮▮⚝ 调整 CPU 调度策略:例如使用实时调度策略,提高 nftables 进程的优先级。
▮▮▮▮⚝ 升级 CPU 硬件:更换更快的 CPU。

内存优化
▮▮▮▮⚝ 优化规则集:减少规则数量,减少内存占用。
▮▮▮▮⚝ 调整连接追踪表大小:根据实际连接数调整连接追踪表大小,避免内存浪费。
▮▮▮▮⚝ 释放不必要的内存:关闭不必要的服务和应用,释放内存资源。
▮▮▮▮⚝ 升级内存硬件:增加内存容量。

网络优化
▮▮▮▮⚝ 优化规则集:减少规则数量,提高网络处理速度。
▮▮▮▮⚝ 使用 Flowtables:将部分规则卸载到硬件加速,提高网络吞吐量。
▮▮▮▮⚝ 调整网络参数:例如调整 TCP 窗口大小、拥塞控制算法等,优化网络传输性能。
▮▮▮▮⚝ 升级网卡硬件:更换更高性能的网卡。

连接追踪优化
▮▮▮▮⚝ 调整连接追踪表大小:根据实际连接数调整连接追踪表大小,避免内存浪费。
▮▮▮▮⚝ 调整连接追踪超时时间:缩短不必要的连接追踪超时时间,减少连接追踪表大小。
▮▮▮▮⚝ 禁用不必要的连接追踪:在不需要连接追踪的场景下禁用连接追踪,例如只进行 stateless 防火墙过滤。

自动化监控与调优

使用脚本自动化监控:编写脚本定期采集系统资源数据,并进行分析和告警。
集成监控系统:将 nftables 监控集成到现有的监控系统中,例如 Grafana、Prometheus、Zabbix 等,实现集中监控和管理。
自动化调优:根据监控数据,自动化调整 nftables 配置和系统资源,例如动态调整连接追踪表大小、规则顺序等。

最佳实践

⚝ 建立完善的系统资源监控体系,实时监控 CPU、内存、网络等资源使用情况。
⚝ 根据监控数据,定期进行性能分析和瓶颈定位。
⚝ 根据性能瓶颈,采取相应的资源调整策略,优化 nftables 配置和系统资源。
⚝ 尽可能实现自动化监控和调优,提高运维效率和系统稳定性。

ENDOF_CHAPTER_

9. chapter 9: nftables 与现代网络技术融合

9.1 nftables 与容器技术(Docker、Kubernetes)

9.1.1 容器网络模型与 nftables

容器技术,如 Docker 和 Kubernetes,已经成为现代应用部署的主流方式。容器的轻量级、可移植性和快速部署的特性,极大地提升了应用开发的效率和灵活性。在容器化环境中,网络是至关重要的基础设施,而 nftables 作为 Linux 系统强大的防火墙和网络过滤工具,在容器网络中扮演着重要的角色。

容器网络模型多种多样,常见的包括:

桥接网络(Bridge Network)
▮▮▮▮这是 Docker 默认的网络模式。
▮▮▮▮ⓐ 容器连接到宿主机上的一个虚拟网桥(docker0 或自定义桥接网络)。
▮▮▮▮ⓑ 容器通过网桥与宿主机以及其他容器通信。
▮▮▮▮ⓒ nftables 可以部署在宿主机上,对进出容器的网络流量进行统一管理和控制。
主机网络(Host Network)
▮▮▮▮容器直接共享宿主机的网络命名空间。
▮▮▮▮ⓐ 容器与宿主机共用一个网络接口和 IP 地址。
▮▮▮▮ⓑ 网络性能高,但隔离性较差。
▮▮▮▮ⓒ nftables 规则直接作用于宿主机网络接口,也适用于主机网络模式下的容器。
Overlay 网络
▮▮▮▮常用于多主机容器集群,如 Kubernetes。
▮▮▮▮ⓐ 通过隧道技术(如 VXLAN、Geneve)构建跨主机的虚拟网络。
▮▮▮▮ⓑ 实现容器跨主机通信,并保持网络隔离。
▮▮▮▮ⓒ nftables 可以部署在宿主机上,对 Overlay 网络的流量进行过滤和安全策略实施。同时,容器编排系统(如 Kubernetes)也可能使用 nftables 或其底层机制来实现网络策略。
Macvlan 网络
▮▮▮▮允许为容器分配宿主机物理网卡上的 MAC 地址和 VLAN。
▮▮▮▮ⓐ 容器如同直接连接到物理网络,网络性能接近物理网络。
▮▮▮▮ⓑ 需要网络设备支持 Macvlan。
▮▮▮▮ⓒ nftables 可以像管理物理网络一样管理 Macvlan 网络中的容器流量。

在这些网络模型中,nftables 都可以有效地集成和应用。无论是简单的桥接网络,还是复杂的 Overlay 网络,nftables 都能提供灵活、高效的网络安全和流量管理能力。例如,在桥接网络中,可以使用 nftables 规则限制容器之间的网络访问,或者对暴露给外部网络的容器服务进行安全防护。在 Kubernetes 环境中,nftables 可以作为 Kubernetes 网络策略的底层实现,提供细粒度的网络隔离和访问控制。

9.1.2 在 Docker 中使用 nftables

在 Docker 环境中使用 nftables,可以增强容器网络的安全性,实现更精细化的网络管理。以下是一些在 Docker 中应用 nftables 的常见场景和方法:

宿主机防火墙规则
▮▮▮▮在宿主机上配置 nftables 规则,可以作为 Docker 容器的第一道安全防线。
▮▮▮▮⚝ 限制容器访问外部网络:默认情况下,Docker 容器可以自由访问外部网络。可以使用 nftables 规则限制容器的出站流量,只允许访问特定的外部服务或地址。
▮▮▮▮⚝ 保护宿主机服务:即使容器使用了主机网络模式,也可以通过 nftables 规则保护宿主机上的服务,防止容器内的恶意程序影响宿主机。
▮▮▮▮⚝ 端口转发安全:当使用 Docker 的端口映射功能(-p--publish)将容器端口暴露到宿主机时,nftables 可以用来控制哪些外部 IP 地址可以访问这些暴露的端口。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 示例:只允许特定 IP 访问宿主机 8080 端口,该端口映射到容器的 80 端口
2 nft add rule inet filter input tcp dport 8080 ip saddr != 192.168.1.100 counter drop

容器内部署 nftables
▮▮▮▮在某些高级场景下,可能需要在 Docker 容器内部署 nftables
▮▮▮▮⚝ 增强容器隔离:虽然容器本身具有一定的隔离性,但在某些安全敏感的应用中,可能需要在容器内部进一步加强网络隔离。在容器内部署 nftables 可以实现更细粒度的容器网络策略。
▮▮▮▮⚝ 模拟复杂的网络环境:在开发和测试阶段,可能需要在容器内部模拟复杂的网络拓扑和安全策略。容器内 nftables 可以帮助实现这些场景。

▮▮▮▮在 Docker 容器内部署 nftables 的步骤
▮▮▮▮▮▮▮▮❶ 基础镜像准备:确保 Docker 镜像包含 nftables 工具。通常基于 Debian 或 Ubuntu 的镜像默认包含,或者可以通过 apt-get install nftables 安装。对于 Alpine Linux 等镜像,可能需要使用 apk add nftables 安装。
▮▮▮▮▮▮▮▮❷ 特权模式或 capabilities:运行容器时,需要赋予容器操作 nftables 的权限。可以使用 --privileged 选项以特权模式运行容器,或者更安全的方式是使用 --cap-add=NET_ADMIN 添加 NET_ADMIN capability。
▮▮▮▮▮▮▮▮❸ 容器内配置 nftables:进入容器内部,使用 nft 命令配置规则。规则的配置方式与在宿主机上相同。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 示例:运行一个特权模式的容器,并在容器内配置 nftables
2 docker run --privileged --name nftables-container -it ubuntu:latest bash
3 # 在容器内部执行
4 apt-get update && apt-get install -y nftables
5 nft add table inet filter
6 nft add chain inet filter input hook input priority 0 policy accept
7 nft add rule inet filter input tcp dport 22 counter accept # 允许 SSH
8 nft list rules inet filter input

Docker 网络策略与 nftables 的关系
▮▮▮▮Docker 自身也提供了网络策略功能,可以限制容器之间的网络通信。Docker 的网络策略后端实现,在某些情况下,会使用 iptablesnftables
▮▮▮▮⚝ Docker 网络策略:通过 docker network create 命令创建网络时,可以使用 --ingress 选项启用入口网络策略。然后可以使用 docker network connect 命令将容器连接到网络,并定义网络策略。
▮▮▮▮⚝ 后端实现:Docker 的网络策略具体实现可能依赖于底层的网络驱动和 Linux 内核版本。在较新的 Docker 版本和 Linux 内核上,Docker 更有可能使用 nftables 作为网络策略的后端。

▮▮▮▮理解 Docker 网络策略与 nftables 的关系,有助于更有效地管理容器网络安全。可以直接使用 Docker 网络策略进行简单的容器间隔离,也可以结合宿主机 nftables 规则,实现更复杂的安全策略。

9.1.3 Kubernetes 网络策略与 nftables

Kubernetes 作为容器编排领域的领导者,其网络策略(Network Policy)是保障集群网络安全的重要机制。Kubernetes 网络策略允许用户定义 Pod 之间的网络访问规则,实现细粒度的网络隔离。而 nftables 在 Kubernetes 网络策略的实现中扮演着关键角色。

Kubernetes 网络策略概念
▮▮▮▮Kubernetes 网络策略是一种声明式的 API 对象,用于指定 Pod 的入站(ingress)和出站(egress)流量规则。
▮▮▮▮⚝ 基于命名空间:网络策略通常在命名空间(Namespace)级别生效,可以控制同一命名空间或跨命名空间 Pod 之间的访问。
▮▮▮▮⚝ 基于标签选择器:网络策略使用标签选择器(Label Selector)来选择策略应用的 Pod 和允许访问的源/目标 Pod。
▮▮▮▮⚝ 支持多种协议和端口:网络策略可以基于协议(TCP、UDP、SCTP)和端口号定义规则。

网络插件与网络策略控制器
▮▮▮▮Kubernetes 网络策略的实现依赖于网络插件(Network Plugin)和网络策略控制器(Network Policy Controller)。
▮▮▮▮⚝ 网络插件:负责 Kubernetes 集群的网络连通性,例如 Flannel、Calico、Cilium、Weave Net 等。不同的网络插件可能采用不同的技术实现网络策略。
▮▮▮▮⚝ 网络策略控制器:监听 Kubernetes API Server 中网络策略对象的创建、更新和删除事件,并将策略转换为底层网络配置。
▮▮▮▮⚝ nftables 作为后端:许多 Kubernetes 网络插件,如 Calico 和 Cilium,以及 Kubernetes 官方推荐的 kube-router,都使用 nftables 或其底层机制来实现网络策略。这些插件会将 Kubernetes 网络策略转换为 nftables 规则,从而实现 Pod 之间的网络隔离和访问控制。

nftables 在 Kubernetes 网络策略中的作用
▮▮▮▮nftables 由于其高性能、灵活性和可扩展性,成为 Kubernetes 网络策略实现的理想选择。
▮▮▮▮⚝ 高效的规则匹配nftables 的集合(Sets)和映射(Maps)功能,可以高效地处理大量的网络策略规则,满足 Kubernetes 集群中大规模 Pod 部署的需求。
▮▮▮▮⚝ 灵活的策略表达nftables 丰富的匹配条件和动作,可以实现复杂的网络策略,例如基于 IP 地址、端口、协议、连接状态等的访问控制。
▮▮▮▮⚝ 与 conntrack 集成nftables 与连接追踪(conntrack)的良好集成,使得 Kubernetes 网络策略可以实现有状态防火墙的功能,例如允许已建立连接的流量。
▮▮▮▮⚝ 可编程性nftables 提供了用户空间 API(libnftnl),方便网络插件控制器将其集成到 Kubernetes 网络策略实现中。

查看 Kubernetes 网络策略的 nftables 规则
▮▮▮▮如果 Kubernetes 集群的网络插件使用 nftables 作为后端,可以通过在 Kubernetes 节点上使用 nft list rules 命令来查看由网络策略生成的 nftables 规则。
▮▮▮▮⚝ 定位规则:Kubernetes 网络策略生成的 nftables 规则通常会放在特定的 tablechain 中,例如,Calico 使用 cali-fw- 前缀的表和链。
▮▮▮▮⚝ 理解规则:分析这些 nftables 规则,可以深入理解 Kubernetes 网络策略是如何被转换为底层的网络配置,以及网络策略的具体生效方式。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 示例:查看 Calico 生成的 nftables 规则 (假设节点上安装了 nftables 工具)
2 kubectl run -it --rm --restart=Never debug-node --image=docker.io/library/alpine --overrides='{"spec":{"nodeName": "<your_node_name>", "hostNetwork": true}}' -- sh
3 # 在 debug-node 容器内执行 (由于 hostNetwork=true,容器共享宿主机网络命名空间)
4 apk add nftables
5 nft list rules table cali-fw4-filter

▮▮▮▮将 <your_node_name> 替换为 Kubernetes 节点的名字。这个命令会在指定的节点上启动一个 Alpine Linux 容器,并进入容器的 shell 环境。由于使用了 hostNetwork: true,容器共享宿主机的网络命名空间,因此可以在容器内部使用 nft 命令查看宿主机的 nftables 规则。

通过理解 nftables 在 Kubernetes 网络策略中的作用,可以更好地设计和管理 Kubernetes 集群的网络安全策略,并对网络策略的实现原理有更深入的认识。

9.2 nftables 与虚拟化技术(VMware、KVM)

9.2.1 虚拟网络环境下的 nftables 应用

虚拟化技术,如 VMware vSphere、KVM (Kernel-based Virtual Machine) 和 Xen,是构建现代数据中心和云计算平台的基础。在虚拟化环境中,网络环境变得更加复杂,需要考虑虚拟机(VM)之间的隔离、VM 与物理网络之间的连接,以及整体网络的安全性和性能。nftables 在虚拟网络环境中同样可以发挥重要作用。

虚拟交换机(vSwitch)与 nftables
▮▮▮▮虚拟交换机是虚拟网络的核心组件,负责在虚拟机之间以及虚拟机与外部网络之间转发数据包。常见的虚拟交换机包括 VMware vSphere 的 vSwitch 和 Linux Bridge、Open vSwitch (OVS) 等。
▮▮▮▮⚝ Linux Bridge:Linux Bridge 是 Linux 内核自带的虚拟交换机,常用于 KVM 环境。Linux Bridge 本身的网络过滤功能相对简单,通常与 iptablesnftables 结合使用,实现更复杂的网络策略。
▮▮▮▮⚝ Open vSwitch (OVS):OVS 是一种高性能、可编程的虚拟交换机,支持 OpenFlow 协议。OVS 可以与 nftables 集成,利用 nftables 的强大过滤能力,增强 OVS 的安全性和灵活性。
▮▮▮▮⚝ VMware vSwitch:VMware vSphere vSwitch 提供了丰富的网络功能,包括安全策略。虽然 VMware vSwitch 本身不直接使用 nftables,但理解 nftables 的原理和功能,有助于更好地理解和配置 VMware vSwitch 的安全策略,例如端口组防火墙、网络隔离等。

虚拟机防火墙
▮▮▮▮在虚拟化环境中,为每个虚拟机配置独立的防火墙是一种常见的安全实践。
▮▮▮▮⚝ 基于主机的防火墙:可以在每个虚拟机内部署 nftables 防火墙。这种方式与物理机部署防火墙类似,可以提供对虚拟机最直接的保护。虚拟机内部的 nftables 可以控制虚拟机的入站和出站流量,限制虚拟机可以访问的网络资源。
▮▮▮▮⚝ 虚拟化平台防火墙:一些虚拟化平台(如 VMware NSX-T、OpenStack Neutron Security Groups)提供了集中式的虚拟防火墙功能。这些平台级的防火墙通常在虚拟交换机层面实现,可以对虚拟机之间的流量进行统一管理和控制。虽然这些平台不一定直接使用 nftables,但其功能和原理与 nftables 有相似之处。

网络隔离与安全组
▮▮▮▮在虚拟化环境中,网络隔离是保障安全性的重要手段。
▮▮▮▮⚝ VLAN 隔离:可以使用 VLAN 技术将虚拟机划分到不同的虚拟网络中,实现网络隔离。nftables 可以部署在 VLAN 网关上,对不同 VLAN 之间的流量进行控制。
▮▮▮▮⚝ 安全组(Security Groups):安全组是一种虚拟防火墙技术,常用于云计算环境(如 AWS EC2 Security Groups、OpenStack Security Groups)。安全组可以定义虚拟机实例的入站和出站规则,实现虚拟机之间的安全隔离。在 OpenStack Neutron 中,安全组的实现可以基于 iptablesnftables

Overlay 网络与虚拟化
▮▮▮▮Overlay 网络技术(如 VXLAN、Geneve)不仅用于容器网络,也常用于虚拟化环境,构建跨物理网络的虚拟数据中心。
▮▮▮▮⚝ VMware NSX-T:VMware NSX-T 是一种软件定义网络(SDN)平台,使用 VXLAN 等 Overlay 网络技术构建虚拟网络。NSX-T 提供了分布式防火墙、微隔离等安全功能,可以对 Overlay 网络中的虚拟机流量进行精细化控制。
▮▮▮▮⚝ OpenStack Neutron:OpenStack Neutron 是 OpenStack 云平台的网络组件,也支持 VXLAN 等 Overlay 网络。Neutron Security Groups 可以基于 nftables 实现,对 Overlay 网络中的虚拟机提供安全组功能。

在虚拟化环境中应用 nftables,需要根据具体的虚拟化平台和网络架构选择合适的部署方式。无论是虚拟机内部署 nftables,还是在虚拟交换机或虚拟化平台层面集成 nftables,都可以有效地提升虚拟网络的安全性和管理效率。

9.2.2 虚拟机防火墙与安全组策略

虚拟机防火墙和安全组策略是虚拟化环境中保障虚拟机安全的关键措施。它们都旨在控制虚拟机的网络访问,但实现方式和应用场景略有不同。

虚拟机防火墙(VM Firewall)
▮▮▮▮虚拟机防火墙通常是指部署在虚拟机操作系统内部的防火墙软件,例如 nftablesiptablesfirewalld (基于 nftablesiptables 的前端管理工具) 等。
▮▮▮▮⚝ 精细化控制:虚拟机防火墙可以提供最精细的网络访问控制,因为规则直接作用于虚拟机内部的网络接口。可以根据虚拟机上运行的应用和服务,定制特定的防火墙规则。
▮▮▮▮⚝ 操作系统集成:虚拟机防火墙与虚拟机操作系统紧密集成,可以利用操作系统的网络功能和安全特性。
▮▮▮▮⚝ 独立管理:每个虚拟机都需要独立配置和管理防火墙规则,管理成本相对较高,尤其是在虚拟机数量较多的情况下。
▮▮▮▮⚝ 适用场景:适用于对安全要求高、需要精细化控制的虚拟机,例如数据库服务器、Web 服务器等。

▮▮▮▮虚拟机内部署 nftables 防火墙的策略示例
▮▮▮▮▮▮▮▮❶ 默认拒绝入站流量

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input policy drop

▮▮▮▮▮▮▮▮❷ 允许已建立和相关的连接

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input ct state related,established counter accept

▮▮▮▮▮▮▮▮❸ 允许 SSH 访问(仅限特定 IP 或网段)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input tcp dport 22 ip saddr 192.168.1.0/24 counter accept

▮▮▮▮▮▮▮▮❹ 允许 HTTP 和 HTTPS 访问

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter input tcp dport { 80, 443 } counter accept

▮▮▮▮▮▮▮▮❺ 允许出站流量(根据需要限制出站流量):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 nft add rule inet filter output policy accept

安全组策略(Security Group Policy)
▮▮▮▮安全组策略通常是在虚拟化平台层面实现的防火墙功能,例如 VMware vSphere Security Groups、OpenStack Security Groups、AWS EC2 Security Groups 等。
▮▮▮▮⚝ 平台级管理:安全组策略由虚拟化平台统一管理,可以对一组虚拟机应用相同的安全规则。管理成本较低,尤其适用于大规模虚拟机环境。
▮▮▮▮⚝ 粗粒度控制:安全组策略通常提供较为粗粒度的网络访问控制,例如基于协议、端口范围和源/目标 IP 地址或安全组的规则。
▮▮▮▮⚝ 虚拟机外部生效:安全组策略在虚拟机外部的网络层面生效,通常在虚拟交换机或虚拟网络边缘执行。
▮▮▮▮⚝ 适用场景:适用于大规模虚拟机环境,需要快速部署和统一管理安全策略的场景,例如云计算环境、大规模 Web 应用等。

▮▮▮▮OpenStack Security Groups 基于 nftables 的策略示例(简化示例,实际实现可能更复杂):
▮▮▮▮假设有一个名为 web-servers 的安全组,需要允许入站 HTTP 和 HTTPS 流量,以及出站所有流量。
▮▮▮▮▮▮▮▮❶ 创建安全组(OpenStack Neutron API 操作):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 openstack security group create web-servers

▮▮▮▮▮▮▮▮❷ 添加安全组规则(OpenStack Neutron API 操作):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 openstack security group rule create --protocol tcp --port-range 80:80 --direction ingress web-servers
2 openstack security group rule create --protocol tcp --port-range 443:443 --direction ingress web-servers
3 openstack security group rule create --protocol any --direction egress web-servers

▮▮▮▮▮▮▮▮❸ 将安全组应用到虚拟机(OpenStack Nova API 操作):
▮▮▮▮▮▮▮▮创建虚拟机时,指定安全组 web-servers

▮▮▮▮底层 nftables 规则示例(由 OpenStack Neutron Security Groups Controller 生成,仅为示意):

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 表:neutron-security-groups
2 table inet neutron-security-groups {
3 # 链:sg-web-servers-ingress (入站规则)
4 chain sg-web-servers-ingress {
5 type filter hook input priority 0 policy accept;
6 # 规则:允许 TCP 端口 80 入站
7 tcp dport 80 counter accept
8 # 规则:允许 TCP 端口 443 入站
9 tcp dport 443 counter accept
10 # 默认拒绝其他入站流量 (隐含或显式规则)
11 drop
12 }
13 # 链:sg-web-servers-egress (出站规则)
14 chain sg-web-servers-egress {
15 type filter hook output priority 0 policy accept;
16 # 规则:允许所有出站流量
17 counter accept
18 }
19 }

▮▮▮▮当虚拟机 web-servers 启动时,OpenStack Neutron Security Groups Controller 会将上述 nftables 规则应用到虚拟机所在的计算节点上,从而实现安全组策略。

选择虚拟机防火墙还是安全组策略,取决于具体的安全需求、管理规模和虚拟化环境。通常情况下,可以结合使用虚拟机防火墙和安全组策略,实现多层次的安全防护。安全组策略提供基础的、平台级的安全隔离,而虚拟机防火墙提供更精细的、虚拟机级别的安全控制。

9.3 nftables 与网络命名空间(Network Namespaces)

9.3.1 网络命名空间隔离与安全

网络命名空间(Network Namespaces)是 Linux 内核提供的一种强大的网络隔离机制。它允许在单个 Linux 系统上创建多个独立的网络环境。每个网络命名空间拥有独立的网络设备、路由表、防火墙规则等网络资源,彼此之间相互隔离,就像运行在不同的物理机器上一样。

网络命名空间的核心概念
▮▮▮▮⚝ 隔离性:网络命名空间实现了网络资源的完全隔离。在一个网络命名空间中创建的网络设备、IP 地址、路由表、防火墙规则等,对其他网络命名空间是不可见的。
▮▮▮▮⚝ 独立性:每个网络命名空间可以独立配置网络参数,例如 IP 地址、路由、DNS 等。
▮▮▮▮⚝ 轻量级:网络命名空间是内核级别的隔离,资源开销小,创建和切换速度快,非常适合构建轻量级的虚拟化环境。

网络命名空间的应用场景
▮▮▮▮⚝ 容器技术:Docker 和 Kubernetes 等容器技术广泛使用网络命名空间来实现容器的网络隔离。每个 Docker 容器或 Kubernetes Pod 通常运行在独立的网络命名空间中。
▮▮▮▮⚝ 虚拟化:网络命名空间可以作为一种轻量级的虚拟化技术,用于隔离不同的应用或用户。例如,可以在一个物理服务器上创建多个网络命名空间,每个命名空间运行不同的服务,彼此之间互不干扰。
▮▮▮▮⚝ 网络测试与开发:网络命名空间可以方便地创建隔离的网络环境,用于网络测试、开发和调试。可以在不同的命名空间中模拟不同的网络拓扑和条件,进行网络功能验证和性能测试。
▮▮▮▮⚝ 安全隔离:网络命名空间可以增强系统的安全性。将不同的服务或应用运行在不同的网络命名空间中,可以降低安全风险,防止安全漏洞扩散。

网络命名空间与安全
▮▮▮▮网络命名空间本身就提供了一层网络隔离的安全屏障。
▮▮▮▮⚝ 流量隔离:不同网络命名空间之间的网络流量默认是隔离的。一个命名空间内的进程无法直接访问另一个命名空间内的网络资源,除非显式配置网络连接。
▮▮▮▮⚝ 权限隔离:在网络命名空间中,网络管理操作(如配置 IP 地址、路由、防火墙)通常只在当前命名空间内有效,不会影响其他命名空间。这有助于限制网络管理权限的范围,提高安全性。
▮▮▮▮⚝ 攻击面缩小:将服务隔离在不同的网络命名空间中,可以缩小攻击面。即使一个命名空间内的服务受到攻击,攻击者也难以跨越命名空间边界,影响其他服务。

创建和管理网络命名空间
▮▮▮▮Linux 提供了 ip netns 命令用于管理网络命名空间。
▮▮▮▮⚝ 创建命名空间

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ip netns add ns1
2 ip netns add ns2

▮▮▮▮⚝ 列出命名空间

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ip netns list

▮▮▮▮⚝ 进入命名空间

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ip netns exec ns1 bash # 在命名空间 ns1 中执行 bash

▮▮▮▮⚝ 删除命名空间

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ip netns delete ns1

▮▮▮▮在网络命名空间中配置网络
▮▮▮▮在进入网络命名空间后,可以使用 ip 命令(如 ip addr, ip link, ip route)配置当前命名空间的网络设备、IP 地址、路由等。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 创建 veth pair 连接 ns1 和 ns2
2 ip link add veth0 type veth peer name veth1
3 # 将 veth0 移动到 ns1,veth1 移动到 ns2
4 ip link set veth0 netns ns1
5 ip link set veth1 netns ns2
6 # 在 ns1 中配置 veth0
7 ip netns exec ns1 ip addr add 10.1.1.1/24 dev veth0
8 ip netns exec ns1 ip link set dev veth0 up
9 # 在 ns2 中配置 veth1
10 ip netns exec ns2 ip addr add 10.1.1.2/24 dev veth1
11 ip netns exec ns2 ip link set dev veth1 up
12 # 在 ns1 和 ns2 中分别配置路由
13 ip netns exec ns1 ip route add default via 10.1.1.2 dev veth0
14 ip netns exec ns2 ip route add default via 10.1.1.1 dev veth1

▮▮▮▮这样就在 ns1ns2 两个网络命名空间之间创建了一个直连的网络。

9.3.2 在网络命名空间中使用 nftables

nftables 可以很好地与网络命名空间集成,为每个网络命名空间提供独立的防火墙功能。在网络命名空间中使用 nftables,可以进一步增强网络隔离和安全性。

每个命名空间独立的 nftables 实例
▮▮▮▮每个网络命名空间都拥有独立的 nftables 实例和规则集。在一个命名空间中配置的 nftables 规则,不会影响其他命名空间。这意味着可以在不同的命名空间中应用不同的防火墙策略。

在命名空间中配置 nftables
▮▮▮▮在网络命名空间中配置 nftables 的方法与在默认命名空间中相同。只需要先进入目标网络命名空间,然后使用 nft 命令进行配置。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 进入网络命名空间 ns1
2 ip netns exec ns1 bash
3 # 在 ns1 中配置 nftables 规则
4 nft add table inet filter
5 nft add chain inet filter input hook input priority 0 policy drop
6 nft add rule inet filter input tcp dport 22 counter accept # 允许 SSH
7 nft add rule inet filter input ct state related,established counter accept # 允许已建立连接
8 nft add rule inet filter output policy accept # 允许所有出站流量
9 nft list rules inet filter input # 查看规则
10 exit # 退出 ns1 命名空间

▮▮▮▮上述命令在网络命名空间 ns1 中配置了一个基本的 nftables 防火墙,只允许 SSH 入站连接和已建立连接,默认拒绝其他入站流量,允许所有出站流量。

命名空间间的流量控制
▮▮▮▮如果需要控制不同网络命名空间之间的流量,可以在连接命名空间的网络设备上配置 nftables 规则。例如,在前面创建的 veth pair 连接 ns1ns2 的例子中,可以在宿主机命名空间(默认命名空间)中,对 veth0veth1 设备之间的流量进行控制。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 在默认命名空间中配置 nftables 规则,控制 ns1 和 ns2 之间的流量
2 nft add table inet filter
3 nft add chain inet filter forward hook forward priority 0 policy drop
4 # 允许 ns1 (10.1.1.1/24) 访问 ns2 (10.1.1.2/24) 的 HTTP 服务
5 nft add rule inet filter forward iifname veth0 oifname veth1 ip saddr 10.1.1.0/24 ip daddr 10.1.1.0/24 tcp dport 80 counter accept
6 # 允许 ns2 (10.1.1.2/24) 访问 ns1 (10.1.1.1/24) 的 HTTPS 服务
7 nft add rule inet filter forward iifname veth1 oifname veth0 ip saddr 10.1.1.0/24 ip daddr 10.1.1.0/24 tcp dport 443 counter accept
8 nft list rules inet filter forward # 查看规则

▮▮▮▮这些规则在默认命名空间的 filter 表的 forward 链上生效,控制了 veth0veth1 设备之间的转发流量,从而实现了对 ns1ns2 命名空间之间流量的控制。

结合 nft monitor 监控命名空间规则
▮▮▮▮可以使用 nft monitor 命令监控特定网络命名空间中的 nftables 规则变化和数据包匹配情况。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 监控命名空间 ns1 中的 nftables 规则变化
2 ip netns exec ns1 nft monitor
3 # 在另一个终端,在 ns1 中修改 nftables 规则
4 ip netns exec ns1 nft add rule inet filter input tcp dport 8080 counter accept
5 # 监控输出会显示规则的添加事件

▮▮▮▮通过 nft monitor,可以实时了解网络命名空间中 nftables 规则的动态变化,方便进行调试和监控。

在网络命名空间中使用 nftables,可以构建更加安全、隔离性更强的网络环境,尤其是在容器化、虚拟化和网络测试等场景中,能够发挥重要作用。

9.4 nftables 与 VRF(Virtual Routing and Forwarding)

9.4.1 VRF 的概念与应用场景

VRF(Virtual Routing and Forwarding,虚拟路由转发)是一种在单个物理路由器或 Linux 系统上创建多个独立的路由实例的技术。每个 VRF 实例拥有独立的路由表、转发表和路由协议进程,彼此之间逻辑隔离。VRF 技术类似于网络命名空间,但主要关注路由隔离,而网络命名空间则提供更全面的网络资源隔离。

VRF 的核心概念
▮▮▮▮⚝ 路由隔离:VRF 的核心功能是路由隔离。每个 VRF 实例维护独立的路由表,不同 VRF 实例之间的路由信息互不干扰。
▮▮▮▮⚝ 逻辑路由器:可以将每个 VRF 实例看作一个逻辑路由器。在同一个物理设备上,可以运行多个逻辑路由器,每个逻辑路由器负责处理特定用户的流量或特定业务的流量。
▮▮▮▮⚝ 共享物理资源:VRF 实例共享物理路由器的硬件资源,例如 CPU、内存、接口等。但逻辑上是隔离的。

VRF 的应用场景
▮▮▮▮⚝ 多租户环境:在多租户数据中心或云环境中,可以使用 VRF 实现租户之间的路由隔离。每个租户分配一个 VRF 实例,租户的网络流量在各自的 VRF 实例中路由,保证租户之间的数据隔离和安全。
▮▮▮▮⚝ 服务隔离:在大型企业网络中,可以使用 VRF 隔离不同的业务部门或服务。例如,可以将生产网络、开发网络、测试网络分别放在不同的 VRF 实例中,实现业务隔离和安全控制。
▮▮▮▮⚝ VPN 服务:VRF 常用于构建 VPN 服务。每个 VPN 连接可以关联到一个 VRF 实例,VPN 用户的流量在特定的 VRF 实例中路由,与其他 VPN 用户或公共网络的流量隔离。
▮▮▮▮⚝ MPLS VPN:VRF 是 MPLS VPN (Multiprotocol Label Switching Virtual Private Network) 的核心组件。在 MPLS VPN 中,PE (Provider Edge) 路由器使用 VRF 实例来隔离不同的 VPN 客户的路由信息。

Linux VRF 实现
▮▮▮▮Linux 内核从 3.9 版本开始支持 VRF 功能。可以使用 ip route vrf 命令管理 VRF 实例。
▮▮▮▮⚝ 创建 VRF 实例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ip link add vrf-blue type vrf table 100
2 ip link add vrf-red type vrf table 200

▮▮▮▮▮▮▮▮table 参数指定 VRF 实例使用的路由表 ID。每个 VRF 实例需要分配一个唯一的路由表 ID。
▮▮▮▮⚝ 启动 VRF 实例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ip link set vrf-blue up
2 ip link set vrf-red up

▮▮▮▮⚝ 将网络接口关联到 VRF 实例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ip link set eth1 master vrf-blue
2 ip link set eth2 master vrf-red

▮▮▮▮▮▮▮▮将物理接口或虚拟接口关联到 VRF 实例后,该接口的网络流量将会在关联的 VRF 实例中路由。
▮▮▮▮⚝ 配置 VRF 实例的路由
▮▮▮▮▮▮▮▮在 VRF 实例中配置路由,需要使用 vrf 参数指定 VRF 实例名。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ip route add 192.168.1.0/24 dev eth1 table 100 vrf vrf-blue
2 ip route add default via 192.168.1.1 dev eth1 table 100 vrf vrf-blue

▮▮▮▮▮▮▮▮上述命令在 vrf-blue VRF 实例的路由表(ID 100)中添加路由。

VRF 与网络命名空间的区别与联系
▮▮▮▮⚝ 隔离范围:网络命名空间提供更全面的网络资源隔离,包括网络设备、IP 地址、路由表、防火墙规则等。VRF 主要关注路由隔离,网络设备和防火墙规则等仍然在全局命名空间中管理。
▮▮▮▮⚝ 应用场景:网络命名空间适用于需要完全隔离网络环境的场景,例如容器、轻量级虚拟化。VRF 适用于需要路由隔离的场景,例如多租户、VPN 服务、MPLS VPN。
▮▮▮▮⚝ 结合使用:VRF 和网络命名空间可以结合使用。例如,可以在网络命名空间内部署 VRF 实例,实现更细粒度的隔离。

9.4.2 在 VRF 环境中配置 nftables

nftables 可以与 VRF 技术很好地协同工作,为 VRF 环境提供安全策略和流量控制。在 VRF 环境中配置 nftables,需要注意规则的作用范围和 VRF 实例的关联。

全局 nftables 规则与 VRF
▮▮▮▮默认情况下,nftables 规则作用于全局网络命名空间。这些全局规则会影响所有 VRF 实例的流量,除非显式指定规则的作用范围。

基于接口的规则
▮▮▮▮nftables 规则可以使用接口名称(iifname, oifname, iif, oif)作为匹配条件。可以将规则应用于特定的接口,从而实现对特定 VRF 实例流量的控制。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 示例:在全局 nftables 中,只允许 vrf-blue 实例的 eth1 接口入站 SSH 流量
2 nft add rule inet filter input iifname eth1 tcp dport 22 counter accept
3 nft add rule inet filter input iifname != eth1 tcp dport 22 counter drop # 默认拒绝其他接口的 SSH

▮▮▮▮上述规则使用了 iifname eth1 匹配条件,只对入接口为 eth1 的流量生效。由于 eth1 接口关联到 vrf-blue VRF 实例,因此这些规则实际上只对 vrf-blue 实例的入站流量生效。

基于 VRF 实例的规则(增强功能,可能需要较新版本的 nftables 和内核):
▮▮▮▮在较新版本的 nftables 和 Linux 内核中,可能支持直接基于 VRF 实例名称或 ID 进行规则匹配。例如,可以使用类似 vrfname vrf-bluevrfid 100 的匹配条件。
▮▮▮▮(请查阅具体版本的 nftables 文档,确认是否支持此功能以及语法。)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # 示例(假设 nftables 支持 vrfname 匹配):
2 nft add rule inet filter input vrfname vrf-blue tcp dport 22 counter accept
3 nft add rule inet filter input vrfname != vrf-blue tcp dport 22 counter drop # 默认拒绝其他 VRF 的 SSH

▮▮▮▮如果 nftables 支持 VRF 实例匹配,可以使用更清晰、更直接的方式来定义 VRF 实例的安全策略。

VRF 实例内部署 nftables(高级用法):
▮▮▮▮虽然 VRF 主要关注路由隔离,但理论上也可以在 VRF 实例内部署独立的 nftables 实例。这需要更复杂的技术手段,例如结合网络命名空间和 VRF。
▮▮▮▮⚝ 创建网络命名空间:为每个 VRF 实例创建一个对应的网络命名空间。
▮▮▮▮⚝ 将 VRF 接口移动到命名空间:将关联到 VRF 实例的接口移动到对应的网络命名空间中。
▮▮▮▮⚝ 在命名空间内部署 nftables:在每个网络命名空间中,配置独立的 nftables 规则。

▮▮▮▮这种方式可以实现更彻底的 VRF 实例隔离,包括路由、网络设备和防火墙规则的完全隔离。但配置和管理复杂度也更高,通常只在非常特殊的场景下使用。

VRF 环境下的 NAT
▮▮▮▮在 VRF 环境中,NAT (Network Address Translation,网络地址转换) 的配置也需要考虑 VRF 实例的隔离性。可以使用 nftables 的 NAT 功能(masquerade, snat, dnat)在 VRF 边界进行地址转换。
▮▮▮▮⚝ VRF-aware NAT:配置 NAT 规则时,需要确保 NAT 操作只在特定的 VRF 实例中生效,不会影响其他 VRF 实例的流量。可以使用接口匹配或 VRF 实例匹配条件来限定 NAT 规则的作用范围。

在 VRF 环境中配置 nftables,需要深入理解 VRF 的路由隔离机制和 nftables 的规则匹配原理。根据具体的 VRF 应用场景和安全需求,选择合适的 nftables 规则配置方式,才能有效地保障 VRF 环境的网络安全和流量控制。

9.5 nftables 与自动化运维(Ansible、Puppet)

9.5.1 使用自动化工具管理 nftables 规则

自动化运维工具,如 Ansible、Puppet、Chef 和 SaltStack,在现代 IT 基础设施管理中扮演着至关重要的角色。它们可以帮助管理员高效、一致地管理大量的服务器和网络设备配置。nftables 规则的配置和管理也可以通过自动化工具来实现,提高运维效率,降低人为错误。

Ansible 与 nftables
▮▮▮▮Ansible 是一种流行的自动化运维工具,使用 YAML 语言描述配置,通过 SSH 协议与目标主机通信。Ansible 提供了 nftables 模块,可以方便地管理 nftables 规则。
▮▮▮▮⚝ nftables 模块:Ansible 的 nftables 模块允许用户以声明式的方式定义 nftables 规则。可以使用 YAML 文件描述 table, chain, rule, setnftables 对象,Ansible 会自动将配置应用到目标主机。
▮▮▮▮⚝ 幂等性:Ansible 的 nftables 模块操作是幂等的。这意味着多次运行同一个 Ansible playbook,最终的 nftables 配置结果是一致的。Ansible 会检查目标主机的当前配置,只应用必要的更改。
▮▮▮▮⚝ 示例 Ansible playbook

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 ---
2 - hosts: firewalls
3 become: true
4 tasks:
5 - name: Ensure nftables is installed
6 package:
7 name: nftables
8 state: present
9
10 - name: Flush existing rules
11 nftables:
12 state: flushed
13
14 - name: Create inet filter table
15 nftables:
16 table: inet filter
17 state: present
18
19 - name: Create input chain
20 nftables:
21 chain: input
22 table: inet filter
23 hook: input
24 policy: drop
25 type: filter
26 state: present
27
28 - name: Allow established and related connections
29 nftables:
30 rule: 'ct state related,established counter accept'
31 chain: input
32 table: inet filter
33 state: present
34
35 - name: Allow SSH access from specific network
36 nftables:
37 rule: 'tcp dport 22 ip saddr 192.168.1.0/24 counter accept'
38 chain: input
39 table: inet filter
40 state: present
41
42 - name: Allow HTTP and HTTPS access
43 nftables:
44 rule: 'tcp dport { 80, 443 } counter accept'
45 chain: input
46 table: inet filter
47 state: present
48
49 - name: Allow outgoing traffic
50 nftables:
51 chain: output
52 table: inet filter
53 hook: output
54 policy: accept
55 type: filter
56 state: present
57
58 - name: Enable nftables service
59 service:
60 name: nftables
61 state: started
62 enabled: yes

▮▮▮▮这个 Ansible playbook 定义了一个基本的 nftables 防火墙配置,包括创建表、链、规则,并启动 nftables 服务。

Puppet 与 nftables
▮▮▮▮Puppet 是一种基于模型的配置管理工具,使用 Puppet DSL (Domain Specific Language) 描述配置。Puppet 社区提供了 puppet-nftables 模块,用于管理 nftables 规则。
▮▮▮▮⚝ puppet-nftables 模块puppet-nftables 模块允许用户使用 Puppet DSL 定义 nftables 资源,例如 nftables::table, nftables::chain, nftables::rule, nftables::set 等。
▮▮▮▮⚝ 资源抽象:Puppet 将 nftables 配置抽象为资源,用户只需要关注资源的期望状态,Puppet 会自动计算并应用必要的更改。
▮▮▮▮⚝ 示例 Puppet manifest

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 class { 'nftables':
2 default_input_policy => 'drop',
3 default_output_policy => 'accept',
4 default_forward_policy => 'drop',
5 }
6
7 nftables::chain { 'input':
8 table => 'filter',
9 type => 'filter',
10 hook => 'input',
11 policy => 'drop',
12 }
13
14 nftables::rule { 'allow-established':
15 table => 'filter',
16 chain => 'input',
17 rule => 'ct state related,established counter accept',
18 }
19
20 nftables::rule { 'allow-ssh':
21 table => 'filter',
22 chain => 'input',
23 rule => 'tcp dport 22 ip saddr 192.168.1.0/24 counter accept',
24 }
25
26 nftables::rule { 'allow-http-https':
27 table => 'filter',
28 chain => 'input',
29 rule => 'tcp dport { 80, 443 } counter accept',
30 }
31
32 nftables::chain { 'output':
33 table => 'filter',
34 type => 'filter',
35 hook => 'output',
36 policy => 'accept',
37 }

▮▮▮▮这个 Puppet manifest 定义了与前面 Ansible playbook 类似的 nftables 防火墙配置。

其他自动化工具
▮▮▮▮除了 Ansible 和 Puppet,其他自动化工具,如 Chef 和 SaltStack,也提供了 nftables 管理模块或功能。
▮▮▮▮⚝ Chef:Chef 提供了 nftables cookbook,可以使用 Ruby DSL 定义 nftables 配置。
▮▮▮▮⚝ SaltStack:SaltStack 提供了 nftables state module,可以使用 YAML 或 Salt DSL 定义 nftables 配置。

使用自动化工具管理 nftables 规则,可以实现配置的标准化、版本控制和快速部署。可以将 nftables 配置代码纳入版本控制系统(如 Git)管理,方便追踪配置变更和回滚。

9.5.2 nftables 配置的自动化部署与维护

自动化部署和维护 nftables 配置,是实现高效运维的关键环节。自动化工具不仅可以用于初始配置,还可以用于日常维护、更新和审计。

配置模板化
▮▮▮▮使用自动化工具时,可以将 nftables 配置参数化和模板化。例如,可以使用变量定义允许访问的 IP 网段、开放的端口号等。这样可以根据不同的环境或需求,灵活地生成 nftables 配置文件。
▮▮▮▮⚝ Ansible Jinja2 模板:Ansible 使用 Jinja2 模板引擎。可以在 Ansible playbook 中使用 Jinja2 语法,定义变量和模板,动态生成 nftables 配置文件。
▮▮▮▮⚝ Puppet Hiera 数据:Puppet 可以使用 Hiera 数据管理配置参数。可以将 nftables 配置参数定义在 Hiera 数据文件中,Puppet manifest 可以从 Hiera 中读取参数。

配置版本控制
▮▮▮▮将 nftables 配置文件和自动化脚本纳入版本控制系统(如 Git)管理。
▮▮▮▮⚝ 追踪配置变更:版本控制系统可以记录每次配置变更的详细信息,包括修改人、修改时间、修改内容等。方便追踪配置历史,审计配置变更。
▮▮▮▮⚝ 配置回滚:如果配置更新出现问题,可以快速回滚到之前的版本。
▮▮▮▮⚝ 协作开发:版本控制系统支持多人协作开发和管理 nftables 配置。

自动化测试与验证
▮▮▮▮在自动化部署 nftables 配置后,需要进行自动化测试和验证,确保配置的正确性和有效性。
▮▮▮▮⚝ 语法检查:自动化工具可以在部署前进行 nftables 语法检查,防止配置错误。
▮▮▮▮⚝ 连通性测试:可以使用自动化测试工具(如 nc, curl, ping)测试网络连通性,验证 nftables 规则是否生效。
▮▮▮▮⚝ 安全扫描:可以使用安全扫描工具(如 Nmap)扫描目标主机,验证 nftables 防火墙是否按预期工作。

持续集成/持续部署(CI/CD)
▮▮▮▮将 nftables 配置自动化部署纳入 CI/CD 流程。
▮▮▮▮⚝ 自动化构建:当 nftables 配置代码发生变更时,CI 系统自动构建和测试配置。
▮▮▮▮⚝ 自动化部署:CI 系统在测试通过后,自动将 nftables 配置部署到目标主机。
▮▮▮▮⚝ 持续监控:部署后,持续监控 nftables 运行状态和网络安全状况,及时发现和解决问题。

配置审计与合规性
▮▮▮▮自动化工具可以帮助进行 nftables 配置审计和合规性检查。
▮▮▮▮⚝ 配置审计:定期审计 nftables 配置,检查是否存在不合理的规则或安全漏洞。
▮▮▮▮⚝ 合规性检查:根据安全策略和合规性要求,编写自动化脚本检查 nftables 配置是否符合规范。例如,检查是否启用了默认拒绝策略、是否限制了不必要的端口开放等。

通过自动化部署和维护 nftables 配置,可以显著提高运维效率,降低人为错误,增强网络安全,并实现配置的标准化和合规性。在现代网络环境中,自动化运维已经成为 nftables 管理的必然趋势。

ENDOF_CHAPTER_

10. chapter 10: nftables 进阶与未来展望

10.1 nftables 内核源码分析入门

10.1.1 Netfilter 框架源码结构

Netfilter 和 nftables 并非独立的实体,nftables 是构建在 Netfilter 框架之上的新一代防火墙解决方案。要深入理解 nftables 的运作机制,探究其高性能和灵活性的根源,就不可避免地需要涉足 Linux 内核源码,特别是 Netfilter 框架的相关部分。本节将引导读者初步了解 Netfilter 框架的源码结构,为后续深入源码分析打下基础。

Netfilter 框架的源码主要分布在 Linux 内核源码树的 net/netfilter/ 目录下。该目录结构清晰地反映了 Netfilter 框架的核心组成部分和功能模块。以下是 net/netfilter/ 目录下的关键子目录和文件,以及它们所代表的含义:

core/: Netfilter 框架的核心代码,包含了 hook 点注册、数据包遍历 hook 点链表、连接跟踪(conntrack)框架的基础代码等。这是 Netfilter 的基石,定义了数据包过滤和操作的基本流程。
x_tables/: iptables 的实现代码,虽然本书重点是 nftables,但 iptables 作为 Netfilter 的重要组成部分,其源码对于理解 Netfilter 框架仍然具有参考价值。x_tables 目录下的代码实现了 iptables 的表(tables)、链(chains)、规则(rules)等核心概念。
nftables/: nftables 的核心实现代码,这是我们源码分析的重点。nftables 目录下的代码实现了 nftables 的表、链、规则、集合、映射等新特性,以及表达式(expressions)和语句(statements)的处理逻辑。
nf_conntrack/: 连接跟踪(Connection Tracking, conntrack)的实现代码。连接跟踪是状态防火墙的核心技术,nf_conntrack 目录下的代码实现了连接状态的跟踪、管理和超时处理等功能。
nf_queue/: 数据包队列(packet queueing)的实现代码。Netfilter 允许将数据包排队到用户空间进行处理,nf_queue 目录下的代码实现了数据包排队和用户空间程序与内核空间 Netfilter 模块的交互。
nf_tables.h: nftables 相关的头文件,定义了 nftables 核心数据结构、API 接口和常量等。
KconfigMakefile: 内核配置和编译相关的文件,用于配置和编译 Netfilter 框架和各个模块。

为了更好地理解 Netfilter 框架的源码结构,我们可以从数据包在 Netfilter 中的流转路径入手。当网络数据包到达 Linux 系统时,会经过以下关键路径,并触发 Netfilter 框架的相应处理流程:

Hook 点注册: Netfilter 框架预定义了五个核心的 hook 点(NF_INET_PRE_ROUTINGNF_INET_LOCAL_INNF_INET_FORWARDNF_INET_LOCAL_OUTNF_INET_POST_ROUTING),分别对应数据包处理的不同阶段。内核模块(例如 nftables 模块)可以向 Netfilter 框架注册 hook 函数,以便在数据包到达 hook 点时被调用。注册 hook 点的代码可以在 net/netfilter/core/core.c 文件中找到,例如 nf_register_net_hook() 函数。

数据包遍历 hook 点链表: 当数据包到达某个 hook 点时,Netfilter 框架会遍历该 hook 点上注册的所有 hook 函数,并依次调用它们。这个过程的核心代码也在 net/netfilter/core/core.c 文件中,例如 nf_hook_slow() 函数。

规则匹配与动作执行: nftables 模块注册的 hook 函数会在数据包遍历 hook 点链表的过程中被调用。nftables 模块的核心功能是根据用户配置的规则集,对数据包进行匹配,并执行相应的动作(例如 acceptdropqueue 等)。规则匹配和动作执行的代码主要在 net/netfilter/nftables/ 目录下,例如 nft_do_chain() 函数负责链的遍历和规则的匹配。

连接跟踪: 如果启用了连接跟踪功能,Netfilter 框架会在数据包处理过程中维护连接状态信息。连接跟踪的代码主要在 net/netfilter/nf_conntrack/ 目录下。nftables 可以利用连接跟踪信息进行状态防火墙的实现,例如使用 ct state 匹配条件。

数据包队列: 如果规则的动作是 queue,Netfilter 框架会将数据包排队到用户空间。数据包队列的代码主要在 net/netfilter/nf_queue/ 目录下。用户空间程序可以通过 libnetfilter_queue 库与内核空间 Netfilter 模块进行交互,接收和处理排队的数据包。

通过对 net/netfilter/ 目录结构的初步了解,以及对数据包在 Netfilter 框架中流转路径的分析,我们可以对 Netfilter 框架的源码结构建立一个宏观的认识。后续深入源码分析时,可以根据具体的模块和功能,进一步探索相关的源码文件和函数,逐步揭开 Netfilter 和 nftables 的神秘面纱。

10.1.2 nftables 核心模块源码导读

在对 Netfilter 框架源码结构有了初步了解之后,本节将聚焦于 nftables 核心模块的源码导读,帮助读者深入理解 nftables 的关键实现细节。nftables 模块的源码主要集中在 net/netfilter/nftables/ 目录下。以下是一些关键的源码文件和它们所负责的核心功能:

nft_core.c: nftables 模块的核心代码,包含了模块初始化、表(tables)、链(chains)、规则(rules)的创建、管理和遍历等核心功能。例如,nft_table_create() 函数负责创建表,nft_chain_create() 函数负责创建链,nft_rule_add() 函数负责添加规则,nft_do_chain() 函数负责链的遍历和规则匹配。

nft_set.c: 集合(sets)的实现代码。nftables 的集合功能是其高性能和灵活性的重要组成部分。nft_set.c 文件实现了集合的创建、管理、元素添加、删除和查找等功能。例如,nft_set_create() 函数负责创建集合,nft_set_elem_add() 函数负责向集合添加元素,nft_set_lookup() 函数负责在集合中查找元素。

nft_map.c: 映射(maps)的实现代码。映射是 nftables 中用于实现更复杂策略的高级功能。nft_map.c 文件实现了映射的创建、管理、键值对添加、删除和查找等功能。例如,nft_map_create() 函数负责创建映射,nft_map_elem_add() 函数负责向映射添加键值对,nft_map_lookup() 函数负责在映射中查找键值对。

nft_expr.c: 表达式(expressions)的框架代码。nftables 的表达式机制允许用户灵活地定义匹配条件和执行动作。nft_expr.c 文件定义了表达式的通用框架和接口,以及一些基础表达式的实现。

nft_stmt.c: 语句(statements)的框架代码。语句定义了规则匹配成功后执行的具体动作。nft_stmt.c 文件定义了语句的通用框架和接口,以及一些基础语句的实现,例如 acceptdropqueue 等。

nft_ verdict.c: 规则判决(verdict)处理代码。规则的最终动作被称为判决,例如 acceptdropgotojumpreturn 等。nft_verdict.c 文件负责处理规则的判决结果,并根据判决类型执行相应的操作。

nft_trans.c: 事务(transactions)的实现代码。nftables 的事务机制保证了规则更新的原子性。nft_trans.c 文件实现了事务的开始、提交和回滚等功能。

nft_flowtable.c: Flowtables 的实现代码。Flowtables 是 nftables 中用于硬件加速和 offloading 的重要特性。nft_flowtable.c 文件实现了 Flowtables 的创建、管理和规则 offloading 等功能。

为了更好地理解 nftables 核心模块的源码,我们可以选择一个具体的 nftables 功能,例如规则的添加和匹配过程,进行深入的源码分析。以下是一个简单的源码导读示例,以规则添加为例:

nft_rule_add() 函数: 规则添加的入口函数是 nft_rule_add(),定义在 net/netfilter/nftables/nft_core.c 文件中。该函数的主要流程如下:
▮▮▮▮ⓐ 参数解析和校验: nft_rule_add() 函数首先解析用户传递的规则参数,例如所属的表、链、匹配条件、动作等,并进行参数校验,确保参数的合法性。
▮▮▮▮ⓑ 规则结构体创建: 根据解析后的参数,nft_rule_add() 函数创建一个 nft_rule 结构体,用于存储规则的各种属性,例如匹配条件、动作、计数器等。nft_rule 结构体的定义可以在 net/netfilter/nftables/nft.h 头文件中找到。
▮▮▮▮ⓒ 规则插入链表: 将新创建的 nft_rule 结构体插入到所属链的规则链表中。链的结构体 nft_chain 中维护了一个规则链表 rules,用于存储该链上的所有规则。
▮▮▮▮ⓓ 规则计数器初始化: 初始化规则的计数器,例如数据包计数器和字节计数器,用于统计规则的匹配次数和流量。
▮▮▮▮ⓔ 事务处理: 将规则添加操作纳入事务管理,确保规则更新的原子性。

nft_do_chain() 函数: 规则匹配的核心函数是 nft_do_chain(),定义在 net/netfilter/nftables/nft_core.c 文件中。该函数负责遍历链上的规则,并对数据包进行匹配。其主要流程如下:
▮▮▮▮ⓐ 遍历规则链表: nft_do_chain() 函数遍历指定链的规则链表 rules,依次取出链表中的每条规则。
▮▮▮▮ⓑ 规则匹配: 对于每条规则,nft_do_chain() 函数调用 nft_rule_match() 函数进行规则匹配。nft_rule_match() 函数会根据规则的匹配条件,检查数据包是否满足条件。匹配条件可以是协议、源地址、目标地址、端口、接口等。
▮▮▮▮ⓒ 动作执行: 如果规则匹配成功,nft_do_chain() 函数会执行规则定义的动作。动作可以是 acceptdropqueuegotojumpreturn 等。动作的执行逻辑由相应的语句处理函数负责,例如 nft_do_accept()nft_do_drop() 等。
▮▮▮▮ⓓ 计数器更新: 如果规则匹配成功,nft_do_chain() 函数会更新规则的计数器,例如数据包计数器和字节计数器。
▮▮▮▮ⓔ 判决处理: 根据规则的动作,nft_do_chain() 函数会返回相应的判决结果,例如 NF_ACCEPTNF_DROPNF_QUEUE 等。Netfilter 框架会根据判决结果,决定如何处理数据包。

通过对 nft_rule_add()nft_do_chain() 函数的源码导读,我们可以初步了解 nftables 规则添加和匹配的基本流程。读者可以参考这种方法,选择其他感兴趣的 nftables 功能,例如集合操作、映射操作、表达式处理、语句处理等,深入阅读相关的源码文件和函数,逐步掌握 nftables 核心模块的实现细节。

10.2 nftables 开发与扩展

10.2.1 自定义 nftables 模块开发

nftables 的强大之处不仅在于其自身的功能,还在于其高度的可扩展性。nftables 允许开发者根据自身需求,开发自定义的模块,扩展 nftables 的功能,例如添加新的匹配条件、新的动作、新的数据包处理逻辑等。本节将介绍如何进行自定义 nftables 模块的开发。

自定义 nftables 模块开发主要涉及以下几个方面:

选择模块类型: nftables 模块可以扩展多种功能,例如:
▮▮▮▮⚝ 表达式模块 (Expression Module): 用于添加新的匹配条件或数据操作功能。例如,可以开发一个基于正则表达式的字符串匹配表达式,或者一个用于解析应用层协议的表达式。
▮▮▮▮⚝ 语句模块 (Statement Module): 用于添加新的动作或数据包处理逻辑。例如,可以开发一个将数据包重定向到特定用户空间程序的语句,或者一个用于实现自定义流量控制策略的语句。
▮▮▮▮⚝ 对象模块 (Object Module): 用于添加新的 nftables 对象类型,例如新的集合类型或映射类型。

编写模块代码: 根据选择的模块类型,编写相应的 C 代码。nftables 模块开发需要遵循一定的 API 接口和编程规范。以下是一些关键的 API 接口和注意事项:

▮▮▮▮⚝ 模块注册: 每个 nftables 模块都需要定义一个模块注册结构体,例如 nft_expr_ops (表达式模块)、nft_stmt_ops (语句模块) 等,并使用 nft_register_expr()nft_register_stmt() 等函数将模块注册到 nftables 框架。注册结构体中需要指定模块的名称、类型、版本、以及模块提供的功能函数(例如表达式的评估函数、语句的执行函数等)。

▮▮▮▮⚝ 数据结构定义: 根据模块的功能需求,定义模块需要使用的数据结构。例如,表达式模块可能需要定义用于存储表达式参数的数据结构,语句模块可能需要定义用于存储语句配置信息的数据结构。

▮▮▮▮⚝ 功能函数实现: 实现模块的核心功能函数。例如,表达式模块需要实现表达式的评估函数,该函数接收数据包和表达式参数作为输入,返回表达式的匹配结果。语句模块需要实现语句的执行函数,该函数接收数据包和语句配置信息作为输入,执行相应的动作。

▮▮▮▮⚝ 错误处理: 在模块代码中进行必要的错误处理,例如参数校验失败、资源分配失败等。错误处理应该返回合适的错误码,并提供详细的错误信息,方便用户排查问题。

▮▮▮▮⚝ 内存管理: 注意模块代码中的内存管理,避免内存泄漏和野指针等问题。模块分配的内存需要在模块卸载时正确释放。

编译模块: 将模块代码编译成内核模块。nftables 模块通常以内核模块的形式加载到 Linux 内核中。模块的编译需要编写 Makefile 文件,并使用内核编译系统进行编译。

加载模块: 使用 insmod 命令将编译好的内核模块加载到 Linux 内核中。加载模块后,nftables 框架会自动识别并加载模块提供的功能。

测试模块: 编写测试用例,对自定义模块的功能进行测试。测试用例应该覆盖模块的各种功能场景和边界条件,确保模块的正确性和稳定性。

以下是一个简单的自定义 nftables 表达式模块的示例代码框架,用于实现一个简单的 "大于" 比较表达式:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #include <linux/module.h>
2 #include <net/netfilter/nf_tables.h>
3
4 static const struct nft_expr_ops nft_expr_ops_gt;
5
6 struct nft_expr_gt {
7 u32 value;
8 };
9
10 static int nft_expr_gt_init(const struct nft_ctx *ctx,
11 const struct nft_expr *expr,
12 const struct nlattr * const *attrs)
13 {
14 struct nft_expr_gt *priv = nft_expr_priv(expr);
15
16 if (!attrs[NFTA_EXPR_NAME])
17 return -EINVAL;
18
19 priv->value = ntohl(nla_get_u32(attrs[NFTA_EXPR_NAME]));
20 return 0;
21 }
22
23 static void nft_expr_gt_eval(struct nft_regs *regs,
24 const struct nft_expr *expr)
25 {
26 struct nft_expr_gt *priv = nft_expr_priv(expr);
27 u32 reg = nft_reg_load32(nft_expr_reg(expr, regs));
28
29 if (reg > priv->value)
30 regs->verdict.code = NFT_CONTINUE; // 匹配成功,继续执行后续规则
31 else
32 regs->verdict.code = NFT_BREAK; // 匹配失败,跳过后续规则
33 }
34
35 static const struct nft_expr_ops nft_expr_ops_gt = {
36 .type = NFT_EXPR_TYPE_CMP,
37 .name = "gt",
38 .ops_flags = NFT_EXPR_F_STATELESS,
39 .flags = 0,
40 .priv_size = sizeof(struct nft_expr_gt),
41 .init = nft_expr_gt_init,
42 .eval = nft_expr_gt_eval,
43 .owner = THIS_MODULE,
44 };
45
46 static int __init nft_gt_module_init(void)
47 {
48 return nft_register_expr(&nft_expr_ops_gt);
49 }
50
51 static void __exit nft_gt_module_exit(void)
52 {
53 nft_unregister_expr(&nft_expr_ops_gt);
54 }
55
56 module_init(nft_gt_module_init);
57 module_exit(nft_gt_module_exit);
58
59 MODULE_LICENSE("GPL");
60 MODULE_AUTHOR("Your Name");
61 MODULE_DESCRIPTION("nftables 'greater than' expression module");

上述代码框架只是一个简单的示例,实际的自定义 nftables 模块开发可能涉及更复杂的功能和逻辑。开发者需要深入理解 nftables 的 API 接口和内核编程规范,才能开发出高效、稳定、可靠的自定义模块,满足特定的网络安全和数据包处理需求。

10.2.2 贡献 nftables 社区

nftables 是一个开源项目,由 Netfilter 社区维护和开发。参与开源社区,贡献代码、文档、测试用例等,是提升自身技术能力、促进项目发展的重要途径。对于 nftables 爱好者和开发者来说,积极参与 nftables 社区贡献,不仅可以帮助完善 nftables 项目,也能从中学习到宝贵的经验和知识。

以下是一些参与 nftables 社区贡献的方式:

学习和使用 nftables: 深入学习 nftables 的各种功能和特性,并在实际环境中应用 nftables。在使用过程中,发现问题、总结经验,为社区贡献提供素材。

提交 Bug 报告: 在使用 nftables 过程中,如果遇到 Bug 或问题,及时向社区提交 Bug 报告。Bug 报告应该包含详细的问题描述、复现步骤、环境信息等,方便开发者定位和修复问题。提交 Bug 报告可以通过 Netfilter 的 Bugzilla 跟踪系统或者邮件列表进行。

提交补丁 (Patch): 如果具备一定的 C 语言和内核开发能力,可以尝试修复 Bug 或实现新功能,并向社区提交补丁。提交补丁需要遵循一定的代码规范和提交流程。补丁应该经过充分的测试,并附带详细的补丁说明。提交补丁可以通过邮件列表或者 Git 代码仓库的 Pull Request 方式进行。

参与代码 review: 参与社区的代码 review 工作,帮助审核其他开发者提交的补丁。代码 review 可以提高代码质量,促进知识共享。参与代码 review 需要认真阅读代码,并提出建设性的意见和建议。

完善文档: nftables 的文档是用户学习和使用 nftables 的重要资源。如果发现文档存在不足或错误,可以向社区提交文档补丁,完善文档内容,提高文档质量。文档贡献可以包括修复文档错误、补充文档内容、改进文档结构、翻译文档等。

贡献测试用例: 完善 nftables 的测试用例,提高测试覆盖率,确保 nftables 的稳定性和可靠性。可以根据 nftables 的功能和特性,编写新的测试用例,并提交到社区。

参与社区讨论: 积极参与 nftables 社区的邮件列表、IRC 频道等讨论,解答其他用户的问题,分享自己的经验和知识,参与功能设计和技术方案的讨论。

推广 nftables: 在技术博客、社区论坛、技术会议等场合,分享 nftables 的使用经验和技术心得,推广 nftables 的应用,扩大 nftables 的影响力。

参与 nftables 社区贡献,需要保持积极、开放、合作的态度,尊重社区的规则和文化,与其他社区成员友好交流,共同推动 nftables 项目的发展。Netfilter 社区是一个活跃、友好的社区,欢迎各种形式的贡献。通过参与社区贡献,不仅可以提升自身的技术能力,还能结识更多志同道合的朋友,共同构建更美好的开源世界。

10.3 nftables 的未来发展趋势

10.3.1 eBPF 与 nftables 的结合展望

eBPF (Extended Berkeley Packet Filter) 是一种革命性的内核技术,它允许用户在内核空间安全、高效地运行自定义程序,而无需修改内核源码或加载内核模块。eBPF 具有高性能、低开销、高灵活性的特点,在网络观测、安全分析、性能调优等领域有着广泛的应用前景。nftables 与 eBPF 的结合,被认为是未来网络安全和数据包处理领域的重要发展趋势。

eBPFnftables 的结合可以从以下几个方面展开:

增强 nftables 的表达式和语句: eBPF 程序可以作为 nftables 的表达式或语句,扩展 nftables 的匹配条件和动作。例如,可以使用 eBPF 程序实现更复杂的协议解析、应用层检测、DDoS 防御等功能。eBPF 程序的灵活性和可编程性,可以弥补 nftables 内置表达式和语句的不足,为用户提供更强大的自定义能力。

实现更高效的数据包处理: eBPF 程序可以直接在内核空间运行,避免了数据包在内核空间和用户空间之间的频繁切换,从而提高了数据包处理的效率。nftables 可以将部分规则处理逻辑 offload 到 eBPF 程序中,利用 eBPF 的高性能特性,加速数据包过滤和转发。

实现更灵活的网络策略: eBPF 程序可以访问内核数据结构和函数,获取更丰富的网络信息,例如进程信息、socket 信息、路由信息等。nftables 可以结合 eBPF 程序获取的网络信息,实现更精细化的网络策略,例如基于进程的网络访问控制、基于应用层协议的 QoS 策略等。

实现实时的网络观测和安全分析: eBPF 程序可以实时监控网络事件和数据包流量,并进行统计分析。nftables 可以与 eBPF 程序协同工作,将网络事件和数据包信息传递给 eBPF 程序进行分析,实现实时的网络观测和安全分析。例如,可以使用 eBPF 程序监控异常网络流量、检测恶意攻击行为、分析网络性能瓶颈等。

目前,nftableseBPF 的结合还处于发展初期,但已经有一些初步的探索和实践。例如,nftables 已经支持使用 meta nfproto 表达式匹配协议族,可以用于区分 IPv4 和 IPv6 数据包。未来,可以进一步扩展 nftables 的表达式和语句,支持更丰富的 eBPF 功能,例如:

eBPF 表达式: 允许用户在 nftables 规则中使用 eBPF 程序作为匹配条件。例如,可以使用 eBPF 程序检测数据包是否包含特定的应用层协议特征,或者根据数据包的 payload 内容进行匹配。

eBPF 语句: 允许用户在 nftables 规则中使用 eBPF 程序作为动作。例如,可以使用 eBPF 程序对数据包进行修改、重定向、或者将数据包信息发送到用户空间程序进行处理。

eBPF 集合和映射: 允许用户在 nftables 中使用 eBPF 程序创建和管理集合和映射。例如,可以使用 eBPF 程序动态维护 IP 地址黑名单或白名单,或者根据网络流量动态调整 QoS 策略。

eBPFnftables 的结合,将为网络安全和数据包处理领域带来新的变革。eBPF 的高性能和灵活性,与 nftables 的强大功能和易用性相结合,将为用户提供更强大、更高效、更灵活的网络安全解决方案。

10.3.2 nftables 在下一代网络技术中的角色

随着云计算、容器化、SDN (Software-Defined Networking)、NFV (Network Functions Virtualization) 等下一代网络技术的快速发展,网络环境变得越来越复杂和动态。传统的防火墙技术在应对这些新的挑战时,面临着诸多局限性。nftables 作为新一代的防火墙解决方案,在下一代网络技术中将扮演越来越重要的角色。

nftables 在下一代网络技术中的角色主要体现在以下几个方面:

云环境下的网络安全: 云计算环境具有弹性伸缩、资源共享、多租户隔离等特点,对网络安全提出了更高的要求。nftables 的高性能、灵活性、和可扩展性,使其成为云环境下理想的网络安全解决方案。nftables 可以用于构建云防火墙、虚拟私有云 (VPC) 安全组、容器网络安全策略等,保护云环境中的虚拟机、容器和应用的安全。

容器网络安全: 容器技术 (例如 Docker、Kubernetes) 的普及,带来了新的网络安全挑战。容器网络环境具有动态性、微服务化、网络策略复杂等特点。nftables 可以与容器网络插件 (例如 Calico、Flannel) 集成,实现容器网络的安全策略管理。nftables 可以基于容器的标签、命名空间、网络策略等信息,实现精细化的容器网络访问控制和安全隔离。

SDN/NFV 环境下的网络功能: SDN 和 NFV 技术将网络控制平面和数据平面分离,实现了网络功能的虚拟化和软件化。nftables 可以作为 SDN 控制器或 NFV 基础设施的一部分,提供灵活的网络功能,例如防火墙、NAT、负载均衡、流量整形等。nftables 可以通过 SDN 控制器动态配置规则,实现网络功能的自动化部署和管理。

边缘计算网络安全: 边缘计算将计算和存储资源推向网络边缘,更接近数据源和用户。边缘计算网络具有分布式、低延迟、高带宽等特点,对网络安全提出了新的挑战。nftables 可以部署在边缘计算节点上,提供边缘网络的安全防护。nftables 可以根据边缘计算的应用场景和安全需求,配置灵活的安全策略,保护边缘数据和应用的安全。

物联网 (IoT) 网络安全: 物联网设备数量庞大、类型多样、安全能力参差不齐,物联网网络面临着严峻的安全威胁。nftables 可以部署在物联网网关或边缘节点上,作为物联网网络的安全入口,提供物联网设备的安全接入控制、流量过滤、入侵检测等功能。nftables 可以根据物联网设备的特点和安全需求,定制化的安全策略,保护物联网网络的安全。

总而言之,nftables 以其高性能、灵活性、可扩展性等优势,在下一代网络技术中扮演着越来越重要的角色。随着网络技术的不断发展,nftables 将继续演进和完善,为构建安全、可靠、高效的下一代网络基础设施提供强有力的支撑。

10.4 nftables 学习资源与社区

10.4.1 官方文档、邮件列表、IRC 频道

学习和掌握 nftables 技术,离不开丰富的学习资源和活跃的社区支持。nftables 社区提供了完善的官方文档、邮件列表、IRC 频道等资源,方便用户学习、交流和获取帮助。

官方文档 (Official Documentation): Netfilter 官方网站提供了详细的 nftables 文档,包括用户手册、wiki 页面、man 手册等。官方文档是学习 nftables 最权威、最全面的资源。

▮▮▮▮⚝ Netfilter Wiki: Netfilter Wiki (https://wiki.netfilter.org/ ) 包含了大量的 nftables 相关文档,包括快速入门指南、教程、示例、FAQ 等。Netfilter Wiki 是学习 nftables 的首选资源。

▮▮▮▮⚝ nftables man pages: Linux 系统自带的 nftables man pages 提供了 nft 命令行工具的详细使用说明,以及 nftables 语法的详细解释。可以通过 man nft 命令查看 nftables man pages。

▮▮▮▮⚝ nftables 官方网站: Netfilter 官方网站 (https://www.netfilter.org/projects/nftables/ ) 提供了 nftables 项目的最新信息、下载链接、文档链接等。

邮件列表 (Mailing Lists): Netfilter 社区维护了多个邮件列表,用于用户交流、问题解答、Bug 报告、功能讨论等。参与邮件列表是与 nftables 开发者和用户交流的重要途径。

▮▮▮▮⚝ netfilter@vger.kernel.org: Netfilter 核心邮件列表,用于讨论 Netfilter 和 nftables 的技术问题、开发进展、Bug 报告等。订阅该邮件列表可以及时了解 nftables 的最新动态。

▮▮▮▮⚝ netfilter-devel@vger.kernel.org: Netfilter 开发邮件列表,主要用于开发者之间的技术交流和代码讨论。

▮▮▮▮⚝ netfilter-announce@vger.kernel.org: Netfilter 公告邮件列表,用于发布 Netfilter 和 nftables 的版本发布、安全公告等重要信息。

▮▮▮▮订阅 Netfilter 邮件列表可以通过 Netfilter 官方网站 (https://www.netfilter.org/community/lists/ ) 进行。

IRC 频道 (Internet Relay Chat): Netfilter 社区在 OFTC 网络上提供了一个 IRC 频道 #netfilter,用于实时的在线交流。IRC 频道是快速获取帮助、与其他用户交流、参与社区讨论的便捷方式。

▮▮▮▮⚝ IRC 服务器: irc.oftc.net
▮▮▮▮⚝ 频道名称: #netfilter

▮▮▮▮可以使用任何 IRC 客户端连接到 irc.oftc.net 服务器,并加入 #netfilter 频道参与交流。

社区论坛和博客: 除了官方资源外,还有一些社区论坛和技术博客也提供了丰富的 nftables 学习资源和经验分享。例如:

▮▮▮▮⚝ Stack Overflow: Stack Overflow 网站上有很多关于 nftables 的问题和解答,可以通过搜索关键词 "nftables" 找到相关内容。

▮▮▮▮⚝ 个人技术博客: 很多技术博客作者分享了 nftables 的学习心得、实践经验、案例分析等,可以通过搜索引擎找到这些博客文章。

通过充分利用官方文档、邮件列表、IRC 频道、社区论坛和博客等资源,可以系统地学习 nftables 技术,及时获取帮助,并与社区保持互动,不断提升自身的技术水平。

10.4.2 优秀的 nftables 学习资料推荐

除了官方文档和社区资源外,还有一些优秀的 nftables 学习资料值得推荐,可以帮助读者更深入、更系统地学习 nftables

书籍:

▮▮▮▮⚝ 《Linux iptables firewall》 (英文版): 虽然书名是 iptables,但书中也包含了对 Netfilter 框架和 nftables 的介绍,可以作为 Netfilter 框架的入门读物。

▮▮▮▮⚝ 《Network Security with Netfilter/iptables》 (英文版): 这本书深入讲解了 Netfilter/iptables 的原理和应用,虽然侧重于 iptables,但对于理解 Netfilter 框架和网络安全原理仍然很有帮助。

▮▮▮▮⚝ 《nftables in 10 minutes》 (在线文档): 这是一个非常简洁、快速的 nftables 入门教程,可以在短时间内了解 nftables 的基本概念和操作。

在线教程和文章:

▮▮▮▮⚝ DigitalOcean 上的 nftables 教程: DigitalOcean 网站上提供了一系列关于 nftables 的教程,从入门到进阶,内容丰富,示例清晰。

▮▮▮▮⚝ Red Hat 官方文档中的 nftables 部分: Red Hat 官方文档中关于防火墙的部分,详细介绍了 nftables 的配置和使用,可以作为 RHEL/CentOS 系统上 nftables 的学习参考。

▮▮▮▮⚝ Arch Linux Wiki 上的 nftables 页面: Arch Linux Wiki 上关于 nftables 的页面,内容详尽,涵盖了 nftables 的各个方面,是学习 nftables 的优秀资源。

▮▮▮▮⚝ 个人博客文章: 很多技术博客作者撰写了关于 nftables 的文章,分享了学习心得、实践经验、案例分析等,可以通过搜索引擎找到这些文章,例如搜索 "nftables tutorial"、"nftables examples" 等关键词。

视频教程:

▮▮▮▮⚝ YouTube 上的 nftables 教程: YouTube 上有很多关于 nftables 的视频教程,可以通过搜索关键词 "nftables tutorial" 找到相关视频。视频教程可以更直观地展示 nftables 的操作和配置过程。

▮▮▮▮⚝ 在线教育平台上的 nftables 课程: 一些在线教育平台 (例如 Udemy、Coursera) 上也可能提供关于 nftables 的课程,可以根据自身需求选择合适的课程进行学习。

选择合适的学习资料,结合官方文档和社区资源,循序渐进地学习和实践,相信读者一定能够掌握 nftables 这项强大的网络安全技术,并在实际工作中灵活应用。

ENDOF_CHAPTER_