Netfilter/iptables的一些新进展

简介:

关注了一下Netfilter的最新进展,新东西还真不少哇!但是最让人心动的有两个。

一.新的bpf模块

基于Linux kernel 3.9版本的patch是xt_bpf的支持,对应的iptables模块是libxt_bpf,这个在iptables-1.4.19版本中已经支持,顾名思义,bpf其实就是伯克利包过滤的缩写,对于它的描述,参见《 BPF(BSD Packet Filter)--应用和理念扩展 》。从名称上看,BPF理应就是iptables包过滤的首选技术,但是不知道什么原因,xt_tables一直维护着自己的数据结构保存rule的match和target,现在有了BPF的支持,我想内核协议栈在处理iptables规则时的效率会高很多,以往的一系列的多个match,现在封装进一个match,该match可以通过bytecode参数来指示,它是已经编译好的字节码,内核直接去执行,速度非常快。以往的match匹配基本就是遍历,现在基于bpf的不再依赖遍历了,而是去“执行”那段bytecode!
        tcpdump工具一直以来都是基于BPF的,虽然它的match在语法上和iptables的极其类似,其匹配效率却比iptales高很多,类似
-i eth2 tcp port 1234 and host 1.2.3.4
这一串匹配在iptables中需要建立4个entry,然而使用BPF的话,就可以编译成一段以下顺序执行的代码:
1.加载dev字段
2.判断dev字段,如果不是eth2则跳到x
3.加载协议字段
4.判断协议字段,如果不是tcp则跳到x
...
x.返回

这段代码类似汇编代码,被内核解释执行。不过,我在kernel 2.6.32上开始没有编译成功,因为这个版本太老了,很多接口和新的内核都不兼容,改了好久才勉强能运行,但是不能插入复杂的bytecode,否则就panic!
       不管怎样,采用这个BPF的架构,内核空间的代码执行效率会提高很多,并且代码量也会减少很多,像ipt_do_table这个巨无霸函数也能瘦身了。

二.最新的nftables项目

说到iptables内核代码的瘦身,Netfilter网站上开辟了另外一条路,那就是 nftables项目 ,它旨在完全替换掉既有的iptables/ebtables/arptables以及对应的v6版本。
    nftables最主要的革新在于两点,其一就是命令语法的完全改变,第二就是内核代码的优化。它采取了类似BPF的过滤方式,其matches的匹配过程就是一个状态机转换的过程,最终的终止节点就是target。在代码层面,它彻底改变了iptables对match存储的混乱场面,以下是匹配的核心代码:
//更加合理的数据结构,比iptables的平坦化的数据结构布局好多了 struct nft_expr {     const struct nft_expr_ops    *ops;     unsigned char            data[]; }; struct nft_rule {     struct list_head        list;     struct list_head        dirty_list;     struct rcu_head            rcu_head;     u64                handle:46,                     genmask:2,                     dlen:16;     unsigned char            data[]         __attribute__((aligned(__alignof__(struct nft_expr)))); };  //net/netfilter/nf_tables_core.c  unsigned int nft_do_chain_pktinfo(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) {     const struct nft_chain *chain = ops->priv;     const struct nft_rule *rule;     const struct nft_expr *expr, *last;     struct nft_data data[NFT_REG_MAX + 1];     unsigned int stackptr = 0;     struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE];     int rulenum = 0;     /*      * Cache cursor to avoid problems in case that the cursor is updated      * while traversing the ruleset.      */     unsigned int gencursor = chain->net->nft.gencursor;  do_chain:     rule = list_entry(&chain->rules, struct nft_rule, list); next_rule:     data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;     list_for_each_entry_continue_rcu(rule, &chain->rules, list) {          /* This rule is not active, skip. */         if (unlikely(rule->genmask & (1 << gencursor)))             continue;          rulenum++;                         nft_rule_for_each_expr(expr, last, rule) {             if (expr->ops == &nft_cmp_fast_ops)                 nft_cmp_fast_eval(expr, data);             else if (expr->ops != &nft_payload_fast_ops ||                  !nft_payload_fast_eval(expr, data, pkt))                 expr->ops->eval(expr, data, pkt);              if (data[NFT_REG_VERDICT].verdict != NFT_CONTINUE)                 break;         }          switch (data[NFT_REG_VERDICT].verdict) {         case NFT_BREAK:             data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;             /* fall through */         case NFT_CONTINUE:             continue;         }         break;     }      switch (data[NFT_REG_VERDICT].verdict) {        //结果判定         case NF_ACCEPT:     case NF_DROP:     case NF_QUEUE:         nft_chain_stats(chain, pkt, jumpstack, stackptr);          if (unlikely(pkt->skb->nf_trace))             nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);          return data[NFT_REG_VERDICT].verdict;     case NFT_JUMP:         //stack结构更好地组织了rule                 if (unlikely(pkt->skb->nf_trace))             nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);          BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE);         jumpstack[stackptr].chain = chain;         jumpstack[stackptr].rule  = rule;         jumpstack[stackptr].rulenum = rulenum;         stackptr++;         /* fall through */     case NFT_GOTO:         chain = data[NFT_REG_VERDICT].chain;         goto do_chain;     case NFT_RETURN:         if (unlikely(pkt->skb->nf_trace))             nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN);          /* fall through */     case NFT_CONTINUE:         break;     default:         WARN_ON(1);     }      if (stackptr > 0) {         if (unlikely(pkt->skb->nf_trace))             nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_RETURN);          stackptr--;         chain = jumpstack[stackptr].chain;         rule  = jumpstack[stackptr].rule;         rulenum = jumpstack[stackptr].rulenum;         goto next_rule;     }     nft_chain_stats(chain, pkt, jumpstack, stackptr);      if (unlikely(pkt->skb->nf_trace))         nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_POLICY);      return nft_base_chain(chain)->policy; }

新的nftables瘦身的原因在于大量采用了回调函数,使判定逻辑独立出来,核心的do_tables变成了一个单纯的状态机!这个抽取动作带来了的效果就是rule更加灵活了,类似BPF的思想,数据包可以根据每一步的结果在不同的rule或者不同的match之间任意跳转了。相比iptables在匹配过程中的大量判断,结果硬编码,nftables确实有一个质的飞跃,期待nftables早日出炉!



 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1268859


相关文章
|
存储 缓存 物联网
uboot 启动流程详细分析参考
uboot 启动流程详细分析参考
1620 1
|
Kubernetes Cloud Native 关系型数据库
提升数据安全与性能,掌握Helm一键部署MySQL 8.0主从技巧
【4月更文挑战第9天】提升数据安全与性能,掌握Helm一键部署MySQL 8.0主从技巧
894 0
|
9月前
|
人工智能 自然语言处理 搜索推荐
小米实测:Deepseek——你的私人旅游攻略定制专家!
大家好,我是小米,一个31岁的技术爱好者。今天分享如何用Deepseek规划完美旅行。Deepseek能快速整合信息、提供个性化推荐,省时省力,并支持实时问答。从目的地选择到行程规划,再到预订机票住宿和旅行中的实时帮助,它都能提供强大支持。希望今天的分享能帮到你,期待你用Deepseek规划出属于自己的精彩旅程!如果你觉得有用,欢迎点赞、转发并关注我的微信公众号“软件求生”,获取更多技术干货。
769 8
|
编解码 数据可视化 数据挖掘
空间单细胞|Slide-seq分析、可视化与整合(1)
空间单细胞|Slide-seq分析、可视化与整合(1)
|
前端开发 JavaScript vr&ar
前端新技术探索:WebAssembly、Web Components与WebVR/AR
【4月更文挑战第12天】WebAssembly、Web Components和WebVR/AR正重塑Web应用的未来。WebAssembly允许C/C++等语言在Web上高效运行,提供接近原生的性能,如游戏引擎。Web Components通过Custom Elements和Shadow DOM实现可复用的自定义UI组件,提升模块化开发。WebVR/AR(现WebXR)则让VR/AR体验无需额外应用,直接在浏览器中实现。掌握这些技术对前端开发者至关重要。
332 3
|
数据中心 机器学习/深度学习 大数据
|
图形学 开发者 存储
超越基础教程:深度拆解Unity地形编辑器的每一个隐藏角落,让你的游戏世界既浩瀚无垠又细节满满——从新手到高手的全面技巧升级秘籍
【8月更文挑战第31天】Unity地形编辑器是游戏开发中的重要工具,可快速创建复杂多变的游戏环境。本文通过比较不同地形编辑技术,详细介绍如何利用其功能构建广阔且精细的游戏世界,并提供具体示例代码,展示从基础地形绘制到植被与纹理添加的全过程。通过学习这些技巧,开发者能显著提升游戏画面质量和玩家体验。
868 3
|
安全 API
Vue3 proxy 解决跨域
jsonp 这种方式在之前很常见,他实现的基本原理是利用了HTML里script元素标签没有跨域限制 动态创建script标签,将src作为服务器地址,服务器返回一个callback接受返回的参数
664 0
Vue3 proxy 解决跨域
|
数据采集 存储 JavaScript
使用Python截取网页内容的综合指南
使用Python截取网页内容的综合指南
564 1
|
并行计算 开发者 Python
Python多线程和多进程在Web开发中的应用与挑战
Python多线程和多进程在Web开发中的应用与挑战
260 0