惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cisco Talos Blog
Cisco Talos Blog
Cyberwarzone
Cyberwarzone
T
Tenable Blog
Security Latest
Security Latest
NISL@THU
NISL@THU
V
Vulnerabilities – Threatpost
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
W
WeLiveSecurity
罗磊的独立博客
Stack Overflow Blog
Stack Overflow Blog
云风的 BLOG
云风的 BLOG
Martin Fowler
Martin Fowler
Engineering at Meta
Engineering at Meta
T
Tor Project blog
H
Heimdal Security Blog
Microsoft Security Blog
Microsoft Security Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
雷峰网
雷峰网
L
LINUX DO - 热门话题
The GitHub Blog
The GitHub Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Recorded Future
Recorded Future
Hugging Face - Blog
Hugging Face - Blog
P
Privacy & Cybersecurity Law Blog
F
Full Disclosure
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
PCI Perspectives
PCI Perspectives
MyScale Blog
MyScale Blog
B
Blog RSS Feed
www.infosecurity-magazine.com
www.infosecurity-magazine.com
K
Kaspersky official blog
Attack and Defense Labs
Attack and Defense Labs
H
Hackread – Cybersecurity News, Data Breaches, AI and More
有赞技术团队
有赞技术团队
Know Your Adversary
Know Your Adversary
Hacker News - Newest:
Hacker News - Newest: "LLM"
Scott Helme
Scott Helme
The Last Watchdog
The Last Watchdog
博客园 - 【当耐特】
S
Security Affairs
The Cloudflare Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
人人都是产品经理
人人都是产品经理
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
N
News and Events Feed by Topic
AI
AI
H
Help Net Security
美团技术团队
T
Threatpost
Project Zero
Project Zero

I'm OWenT

国产大模型(GLM 5.1、Kimi K2.6)真实场景效果和 Coding Plan 额度测试 新版本libatapp的连接管理——从etcd服务发现到拓扑驱动的自动重连 新版本libatbus的设计变更——从树形路由到拓扑驱动 Protobuf又一坑 - C++标准和ABI兼容性 AI真好用-给Blog主题统一加mermaid,chart.js,excalidraw,draw.io的多种引入方式支持 给内网部署Squid-通用HTTP下载缓存 UE使用CodeChecker和clang-tidy生成静态分析报告 找出UE的循环依赖 C++小协程栈和临时变量及作用域的栈溢出问题分析 游戏服务的可观测性能力建设(C++生态) 指标上报的多线程优化和多拉取源点优化 协程(libcopp)的Channel功能和CPU命中率优化 通用RPC代码生成器 实现strong_rc_ptr(比shared_ptr更快的引用计数智能指针) 手夯一个STL allocator和对象内存分析组件 std::condition_variable 的信号丢失问题 踩坑一处(GCC)STL std::async 实现BUG导致的crash问题 GCC 14的一个warning to error BUG 给xresloader(Excel导表工具)增强UE读表支持(包含蓝图,Blueprint) Opentelemetry社区在gRPC的几个链接问题(静态库和动态库混用,musl工具链,符号裁剪) Excel转表工具(xresloader)的新验证器(验证外部Excel和文本数据,唯一性和自定义规则) protobuf v22和gRPC v1.55版本升级的依赖变化和upb适配 关于protobuf近期版本(v20/v3.20+)和 gRPC v1.54版本在某些编译环境下的一些链接和编译问题 xresloader-Excel导表工具链的近期变更汇总 打通游戏服务端框架的C++20协程改造的最后一环 Opentelemetry-cpp的Logs模块标准更新(涉及近期版本:1.8-1.9的BREAK CHANGES) 给cmake-toolset和工具链(curl等)加HTTP/2和HTTP/3支持 又开新坑之 coredns 插件: nftables和filter 关于opentelemetry-cpp社区对于C++ Head Only组件单例和符号可见性的讨论小记 填个转表工具 xresloader 去年的坑(数组尾部裁剪) 集成 upb 和 lua binding 的踩坑小记 libcopp对C++20协程的接入和接口设计 再度优化GCC、LLVM、Clang、libc++、libc++abi等套件的构建脚本 游戏服务的分布式事务优化(二)- 事务管理 游戏服务的分布式事务优化(一)- Write Ahead Log(WAL) 模块 记录一些bazel适配用编译选项 测试现代化硬件C++浮点数性能和一致性 适配Boringssl和OpenSSL 3.0 近期cmake-toolset的一些适配问题 C++20 Text Formatting/fmtlib 适配问题小记 再次重构LLVM+Clang+libcxx+libc++abi+其他相关工具的构建流程 重构基于CMake的构建工具链 新版GCC和LLVM+Clang终于Release啦 折腾一下nftables下的双拨 [C++20] Module partitions和符号交叉引用(声明和实现分离) [Rust] 实现一个线程安全且迭代器可以保存的链表 基于protobuf的代码生成 几个使用protobuf中C++接口的Arena的坑 Amazon Aurora DB存储引擎论文阅读小记 近期对libatapp的一些优化调整(增加服务发现和连接管理,支持yaml等) xresloader转表工具链增加了一些新功能(map,oneof支持,输出矩阵,基于模板引擎的加载代码生成等) 在游戏服务器中使用分布式事务 libcopp接入C++20 Coroutine和一些过渡期的设计 libatbus 的大幅优化 容器配置开发环境小计 PALM Tree - 适合多核并发架构的B+树 - 论文阅读小记 跨平台协程库 - libcopp 简介 C++20 Coroutine 性能测试 (附带和libcopp/libco/libgo/goroutine/linux ucontext对比) 尝鲜Github Action 一些xresloader(转表工具)的改进 protobuf、flatbuffer、msgpack 针对小数据包的简单对比 协程框架(libcopp) 小幅优化 Excel转表工具(xresloader) 增加protobuf插件功能和集成 UnrealEngine 支持 Anna(支持任意扩展和超高性能的KV数据库系统)阅读笔记 C++20 Coroutine libcopp merge boost.context 1.69.0 Google去中心化分布式系统论文三件套(Percolator、Spanner、F1)读后感 Rust玩具-企业微信机器人通用服务 使用ELK辅助监控开发测试环境服务质量和问题定位 2018年的新通用伪随机数算法(xoshiro / xoroshiro)的C++(head only)实现 Webpack+vue+boostrap+ejs构建Web版GM工具 Rust的第二次接触-写个小服务器程序 理解和适配AEAD加密套件 atsf4g-co的进化:协程框架v2、对象路由系统和一些其他细节优化 协程框架(libcopp)v2优化、自适应栈池和同类库的Benchmark对比 可执行文件压缩 初识Rust 使用restructedtext编写xresloader文档 atframework的etcd模块化重构 C++的backtrace ECDH椭圆双曲线(比DH快10倍的密钥交换)算法简介和封装 protobuf-net的动态Message实现 pbc的proto3接入 atgateway内置协议流程优化-加密、算法协商和ECDH 整理一波软件源镜像同步工具+DevOps工具 Blog切换到Hugo libcopp v2的第一波优化完成 libcopp(v2) vs goroutine性能测试 libcopp的线程安全、栈池和merge boost.context 1.64.0 GCC 7和LLVM+Clang+libc++abi 4.0的构建脚本 libatbus的几个藏得很深的bug 用cmake交叉编译到iOS和Android 开源项目得一些小维护 atapp的c binding和c#适配 对象路由系统设计 2016年总结 近期的一个协程流程BUG 重写了llvm+clang+libc++和libc++abi的构建脚本 atsf4g完整游戏工程示例|I'm OWenT atframework基本框架已经完成|I'm OWenT
nftables初体验
owent · 2020-02-11 · via I'm OWenT

blog-website

前言

之前耳闻 nftables 是下一代 iptables 。前段时间配了一台主机,折腾成家里的软路由。就一并来尝鲜一系列新东西,其中就包括 nftablesnftablesiptablesebtables 等一样,都是对底层 xtables 的封装,目前看来 nftablesiptables 更简洁易用,更易读,更容易理解,扩展性和也更好。但是目前各个发行版中对 nftables 的支持还比较参差不齐,导致 nftables 很多功能比 iptables 还是有所缺失,所以个人感觉短期内还是替代不了 iptables (比如 tproxy 功能需要 linux kernel 4.19+, 而即便是 CentOS 8 的内核版本也只是 4.18 ,所以都不支持 )。 nftables 所支持的功能列表及所以来的内核版本和内核模块可以在这里找到 https://wiki.nftables.org/wiki-nftables/index.php/Supported_features_compared_to_xtables 。

nftables 的功能分两块,一块是内核支持,这个受限于内核版本。另一部分是用户空间的库和工具。有些发行版会滚动更新内核,但是 nftables 版本比较低,这时候如果要用就得自己编译。nftables 依赖库及命令行工具的代码仓库如下:

  • libmnl: http://git.netfilter.org/libmnl/
  • libnftnl: http://git.netfilter.org/libnftnl/
  • nftables: http://git.netfilter.org/nftables/

podman 一样, nftables 的高版本对依赖库的版本也有一定要求,系统自带的不一定符合要求,就得一个一个编译。我写了一个构建脚本: https://github.com/owent-utils/docker-setup/blob/master/build-nftables.sh , 并且实测如果使用 podman 或者 docker 的话,可以宿主机编译,然后mount共享给子机也是可以的。

官方Wiki: https://wiki.nftables.org 官方文档: https://www.netfilter.org/projects/nftables/manpage.html 官方文档不是很全,这个文档更完整一些: https://www.mankier.com/8/nft

nftables与iptables

先贴一张 iptables 的流程图。

2002-nf-packet-flow.svg

在这张图表示的流程里 nftablesiptables 最大的一个区别就是, nftables 可以自由创建多个 table, 然后去hook图里的不同阶段( https://www.mankier.com/8/nft#Chains )。而 iptables 仅有默认的 raw , mangle , nat , filter 等table, hook了名字一样的阶段。nftables 可以建立多个 table, 多个table的执行顺序是按优先级来的( https://www.mankier.com/8/nft#Chains 下面的 Table 6.Table 7. 里有文档)。 其他的规则和流程 nftablesiptables 是一样的。只是 nftables 更简单易读一些。

nftables 的基本命令表达式为 nft create/add/delete/list/flush table/chain/rule [ip/ip6/inet/arp/bridge/netdev] [表达式] 。其中 inet 相当于 ip+ip6

表达式主要有两大类,一类是匹配表达式,还有一类是行为表达式,每一类都分很多种而且是多层级的和 iptables 也差不多。但是 nftables 有个比较方便的地方是表达式的最后一个参数如果要多个的话,可以用 { VALUE1, VAULE2 } 来一次写多个。比如我要同时匹配 tcp和udp 协议,可以写成 meta l4proto { tcp, udp } ; 如果我要匹配所有的 ipv6 的源地址是私有地址和回环地址的话可以写成 ip6 saddr {::1/128, fc00::/7, fe80::/10, fd00::/8, ff00::/8}

以下是一些常用命令:

iptables nftables 说明
iptables -t mangle -L nft list table mangle 显示指定table(mangle)的所有chains
- nft list ruleset 显示所有table的所有chains
iptables -t mangle -A V2RAY -j TRACE nft add rule inet mangle V2RAY meta nftrace set 1 跟踪调试包
iptables -t mangle -A V2RAY -j LOG --log-level debug --log-prefix "###LOG PREFIX:" nft add rule inet mangle V2RAY log prefix '"###LOG PREFIX:"' level debug flags all 输出内核日志

上面跟踪调试包流程的时候 nftables 可以用 ` nft monitor trace` 来查看包的状态流转。具体可参见 Wiki: https://wiki.nftables.org/wiki-nftables/index.php/Ruleset_debug/tracing

nftables 里有个工具 iptables-nft (iptables-translate [iptables参数列表]) 可以用来转换 iptables 表达式到 nftables表达式。但是我自己实测的不是很全有些地方也有些谬误。

nftables与ebtables

上面的流程图显示来自于桥接的走了另一套状态流转的流程。要控制桥接的流程,传统的做法可以使用 ebtables 。按文档的说法 ( https://www.mankier.com/8/ebtables-legacy#Description-Tables ), 在 BROUTE 链DROP掉包,能阻止桥接来的包走转发规则,从而转走路由规则。 但是在 nftables 的文档里仅有 https://www.mankier.com/8/nft#Statements-Payload_Statement 里写了个例子改路由。然而我尝试了几次并没有成功。不管我怎么设置,最终还是走了桥接的包转发,并没有走我指定的流转路径(比如转换成tproxy)。另外还看到个文档 ( https://www.mankier.com/8/ebtables-nft ) nftables 目前还不支持对 BROUTE 的HOOK。所以我自己这里目前还是走的用 ebtables

个人感觉 ebtables 使用起来比 iptables 麻烦一些,很多插件功能不支持,有些规则也有些限制,比如不支持 ipset 。但是凑合着还算能用吧。

使用 ebtables 需要开启内核模块: br_netfilter

另外如果要使用网桥包转路由,然后走比如tproxy需要增加如下配置:

echo "
net.ipv4.ip_forward=1
net.ipv4.ip_forward_use_pmtu=1
net.ipv4.conf.all.forwarding=1
net.ipv4.conf.default.forwarding=1
net.ipv6.conf.all.forwarding=1
net.ipv6.conf.default.forwarding=1
# Configures below are used to support tproxy for bridge
net.bridge.bridge-nf-call-arptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.conf.all.rp_filter=0
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.all.route_localnet=1
net.ipv4.conf.default.route_localnet=1
" > /etc/sysctl.d/91-forwarding.conf ;
sysctl -p ;

nftables与ipset

我看了一圈文档,没有找到 nftables 直接访问 ipset 的方式。按Wiki的说法( https://wiki.nftables.org/wiki-nftables/index.php/Moving_from_ipset_to_nftables ) 是可以用 nftables 内置的set和map功能来代替。不过现有的一些工具之集成了对 ipset 的支持没有支持 nftables 的set和map的话,就得另想办法了。

总体上 ipsetnftables 的map和set功能差不太多,有一个区别是 nftables 的map和set都是绑在 nftables 的table里的,而 ipset 没有table的概念。个人觉得 nftables 的更好用一些。

部分参考对比如下:

ipset nftables
ipset create V2RAY_BLACKLIST_IPV4 hash:ip family inet nft add set ip v2ray BLACKLIST { type ipv4_addr\; }
ipset flush V2RAY_BLACKLIST_IPV4 nft flush set ip v2ray BLACKLIST
ipset add V2RAY_BLACKLIST_IPV4 $PPP_OUTER_IP nft add element ip v2ray BLACKLIST { $PPP_OUTER_IP } ;
iptables -t mangle -A V2RAY -p tcp -m set --match-set V2RAY_BLACKLIST_IPV4 dst -j RETURN nft add rule ip v2ray PREROUTING meta l4proto tcp ip daddr @BLACKLIST return
ipset create myset hash:ip,port,ip family inet nft add set inet filter myset { type type ipv4_addr . inet_service . ipv4_addr : verdict \; }
ipset add myset 172.16.0.1,tcp:80,10.0.0.1 nft add element inet filter myset { 172.16.0.1 . 80 . 10.0.0.1 : accept } ;
iptables -t filter -A INPUT -m set --match-set myset src,dst,dst -j ACCEPT nft add rule inet filter INPUT meta nfproto ipv4 ip saddr . tcp dport . ip daddr vmap @myset

nftables与iptables与NAT

按 Wiki 里的说法 ( https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)#Incompatibilities ) 。要使用 nftables 来做 NAT 就要关闭 iptables 的NAT。即不能载入 iptable_natip6table_nat 。但是我自己这边使用的时候,这两个模块被其他的模块拉起了,也是能正常NAT的。不过我并没有用 iptables 配置任何NAT规则。要彻底屏蔽这两个内核模块并且禁止其他模块拉起可以运行如下脚本:

echo "## Do not load the iptable_nat,ip_tables,ip6table_nat,ip6_tables module on boot.
blacklist iptable_nat
blacklist ip6table_nat

# Upper script will disable auto load , or using scripts below to force disable modules
# install iptable_nat /bin/true
# install ip6table_nat /bin/true
" | tee /etc/modprobe.d/disable-iptables.conf

另外我本地为了支持NAT和一些辅助功能开启的模块如下:

echo "
xt_nat
nf_reject_ipv4
nf_reject_ipv6
nf_tables_set
nf_log_ipv6
nf_log_ipv4
nf_log_common
nf_tables
nfnetlink
nf_nat
nf_conntrack
nf_defrag_ipv6
nf_defrag_ipv4
nft_log
nft_masq
nft_ct
nft_meta_bridge
nft_counter
nft_reject
nft_reject_inet
nft_reject_bridge
nft_chain_nat
nft_nat
" | tee /etc/modules-load.d/nftables-nat.conf

nftables与firewalld

我之前一直有用 firewalld 来操作防火墙。但是当把 firewalld 的后端设为 nftables 以后。我发现我自己加的规则老被它刷掉。所以最后我关掉了 firewalld 并且抄了一份它的默认配置如下:

nft list table inet security_firewall > /dev/null 2>&1 ;
if [ $? -eq 0 ]; then
    nft delete table inet security_firewall ;
fi
nft add table inet security_firewall ;

nft add table inet security_firewall ;

nft add chain inet security_firewall PREROUTING { type filter hook prerouting priority raw + 10\; policy accept\; }
nft add rule inet security_firewall PREROUTING icmpv6 type { nd-router-advert, nd-neighbor-solicit } accept ;
nft add rule inet security_firewall PREROUTING meta nfproto ipv6 fib saddr . iif oif missing drop ;

nft add chain inet security_firewall INPUT { type filter hook input priority filter + 10\; policy accept\; }
nft add rule inet security_firewall INPUT ct state { established, related } accept
nft add rule inet security_firewall INPUT ct status dnat accept
# 这里 br0是我自己建的用于内网通信的桥接,添加了enp1s0f0和enp1s0f1 。 enp5s0是我用来调试的接口, WAN口的出口留了两个用于拨号, enp1s0f2 和 enp1s0f3
nft add rule inet security_firewall INPUT iifname { lo, br0, enp1s0f0, enp1s0f1, enp5s0 } accept
# Internal services -- begin
nft add rule inet security_firewall INPUT ip saddr {127.0.0.1/32, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8} tcp dport 22 ct state { new, untracked } accept
nft add rule inet security_firewall INPUT ip6 saddr {::1/128, fc00::/7, fe80::/10, fd00::/8, ff00::/8} tcp dport 22 ct state { new, untracked } accept
nft add rule inet security_firewall INPUT ip6 daddr fe80::/64 udp dport 546 ct state { new, untracked } accept
nft add rule inet security_firewall INPUT tcp dport 53 ct state { new, untracked } accept
nft add rule inet security_firewall INPUT udp dport 53 ct state { new, untracked } accept
nft add rule inet security_firewall INPUT udp dport 67 ct state { new, untracked } accept
nft add rule inet security_firewall INPUT udp dport 547 ct state { new, untracked } accept
nft add rule inet security_firewall INPUT tcp dport 853 ct state { new, untracked } accept
# 其他自定义要放过的服务端口和协议
# Internal services -- end
nft add rule inet security_firewall INPUT meta l4proto { icmp, ipv6-icmp } accept
nft add rule inet security_firewall INPUT ct state { invalid } drop
nft add rule inet security_firewall INPUT reject with icmpx type admin-prohibited

nft add chain inet security_firewall OUTPUT { type filter hook output priority filter + 10\; policy accept\; }
nft add rule inet security_firewall OUTPUT  oifname "lo" accept
nft add rule inet security_firewall OUTPUT  ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 type addr-unreachable

nft add chain inet security_firewall FORWARD { type filter hook forward priority filter + 10\; policy accept\; }
nft add rule inet security_firewall FORWARD  ct state { established, related } accept
nft add rule inet security_firewall FORWARD  ct status dnat accept
# 这里 br0是我自己建的用于内网通信的桥接,添加了enp1s0f0和enp1s0f1 。 enp5s0是我用来调试的接口, WAN口的出口留了两个用于拨号, enp1s0f2 和 enp1s0f3
nft add rule inet security_firewall FORWARD  iifname { lo, br0, enp1s0f0, enp1s0f1, enp5s0 } accept
nft add rule inet security_firewall FORWARD  ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 type addr-unreachable
#
nft add rule inet security_firewall FORWARD  meta l4proto { icmp, ipv6-icmp } accept
nft add rule inet security_firewall FORWARD  ct state { new, untracked } accept
#
nft add rule inet security_firewall FORWARD  ct state { invalid } drop
nft add rule inet security_firewall FORWARD  reject with icmpx type admin-prohibited

备注小记

以下纪录一下我折腾 nftables 的过程中留下的一些可以复用的脚本和趟的坑。

  • NAT的设置脚本: https://github.com/owent-utils/docker-setup/blob/master/setup-router/ppp-nat/setup-nat-ssh.sh
  • 防火墙设置脚本: https://github.com/owent-utils/docker-setup/blob/master/setup-router/ppp-nat/setup-nft-security.sh
  • pppoe自动加入ipsetnftables的set的设置脚本: https://github.com/owent-utils/docker-setup/blob/master/setup-router/ppp-nat/setup-ppp-route-ipv4.sh
  • 要使用 tproxy (透明代理) 和打 SO_MARK 的设置脚本: https://github.com/owent-utils/docker-setup/blob/master/setup-router/v2ray/setup-tproxy.nft.sh
  • docker/podman 里如果要使用 tproxy (透明代理) 和打 SO_MARK,需要基于 CAP_NET_ADMIN 权限
  • 要使用 tproxy (透明代理) 需要开启的内核模块: (其中 nft_tproxy 要求 linux kernel 4.19+)
    echo "
    nf_tproxy_ipv4
    nf_tproxy_ipv6
    nf_socket_ipv4
    nf_socket_ipv6
    xt_TPROXY
    nft_socket
    nft_tproxy
    " | tee /etc/modules-load.d/nftables-tproxy.conf
    
  • 要管理 ebtablesbroute 链要开启内核模块: br_netfilter

nftables Hook

Type Families Hooks Description
filter all all Standard chain type to use in doubt.
nat ip, ip6, inet prerouting, input, output, postrouting Chains of this type perform Native Address Translation based on conntrack entries. Only the first packet of a connection actually traverses this chain - its rules usually define details of the created conntrack entry (NAT statements for instance).
route ip, ip6 output If a packet has traversed a chain of this type and is about to be accepted, a new route lookup is performed if relevant parts of the IP header have changed. This allows to e.g. implement policy routing selectors in nftables.

Standard priority names, family and hook compatibility matrix

The priority parameter accepts a signed integer value or a standard priority name which specifies the order in which chains with same hook value are traversed. The ordering is ascending, i.e. lower priority values have precedence over higher ones.

Name Value Families Hooks
raw -300 ip, ip6, inet all
mangle -150 ip, ip6, inet all
dstnat -100 ip, ip6, inet prerouting
filter 0 ip, ip6, inet, arp, netdev all
security 50 ip, ip6, inet all
srcnat 100 ip, ip6, inet postrouting

Standard priority names and hook compatibility for the bridge family

Name Value Hooks
dstnat -300 prerouting
filter -200 all
out 100 output
srcnat 300 postrouting