熟悉ebtables和iptables的都知道,后者提供的选项所能实现的功能要远远多于前者,但这并不是说IP层的功能要比数据链路层的更丰富,因为只要数据包进入网卡,协议栈代码就能“看到”整个数据包,剩下的问题就是如何来解析和过滤的问题了,只要愿意,实际上协议栈完全可以在数据链路层提供和IP层同样的过滤功能,比如ip_conntrack。
         然而,协议栈并没有这么实现,因为那样会造成严重的代码冗余,维护成本将会很高。Linux的bridge filter提供了bridge-nf-call-iptables机制来使bridge的Netfilter可以复用IP层的Netfilter代码。Netfilter提供了强大的过滤match,流识别机制,使每一个数据包都可以和一个五元组标示的流关联起来,这样就可以对整个流而不是单独的数据包进行更加人性化的操作,而对流的识别以及之后的过滤作用最大的就是mark机制,注意这个mark并不是数据包本身的,它只在本机协议栈内有效。Netfilter代码可以识别一个流的头包,然后会将一个mark打入该流,接下来的数据包可以直接从流中取出该mark来进行过滤而不必再遍历整个规则链了,类似下面的规则是常用的:
iptables -t mangle -I PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -m mark ! --mark 0 -j ACCEPT
iptables -t mangle -A PREROUTING -m state --state ESTABLISHED -j ACCEPT
iptables -t mangle -N mark_Policy"
iptables -t mangle -A mark_Policy $matches1 -j MARK --set-mark 100
iptables -t mangle -A mark_Policy $matches2 -j MARK --set-mark 100
iptables -t mangle -A mark_Policy -m mark ! --mark 0 -j CONNMARK --save-mark

类似一种cache机制,只有一个流的第一个数据包才要遍历整个规则链,其余的就可以直接restore出来mark了,接下来协议栈可以根据该mark来进行过滤或者进行Policy Routing。
        如果使用bridge-nf-call-iptables的话,能否使bridge层利用上述优势呢?比如抉择哪些数据包需要被本地捕获,哪些数据包需要丢弃,答案当然是模棱两可的,并不绝对。对于上面第二个问题,抉择哪些数据包需要丢弃是可以做到的,因为bridge-nf-call-iptables作用于bridge Netfilter的PREROUTING上,完全可以在FORWARD上做Drop or not的抉择,这没有任何问题,然而对于第一个问题,哪些数据包需要被本地IP层捕获,当前的实现就无能为力,然而只需要修改不多的两行bridge模块的代码,问题便迎刃而解,然而能做如此小的手术解决如此大的问题,确实需要积累很多的常识,我不是自夸,这是实话。
        在给出解决办法之前,我首先给出将本应该bridge出去的数据帧捕获到本地IP层会在哪里用到,如果没有实际的需求而去修改代码,那未免太学院派了。一个典型的需求就是透明网桥模式的×××,×××的加密和封装需要在IP层进行,因此需要把感兴趣流捕获到IP层,不感兴趣流直接bridge出去,这是一个实际的需求,然而现有的bridge模块的代码却是解决不了,why?听我娓娓道来。
        Linux的bridge代码中,bridge-nf-call-iptables体现在br_nf_pre_routing函数中,该函数也是一个Netfilter HOOK函数:

static struct nf_hook_ops br_nf_ops[] __read_mostly = {     {         .hook = br_nf_pre_routing,         .owner = THIS_MODULE,         .pf = PF_BRIDGE,         .hooknum = NF_BR_PRE_ROUTING,         .priority = NF_BR_PRI_BRNF,     },     ... }

在该函数的最后:

NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,         br_nf_pre_routing_finish);

调用了IP层的Netfilter PREROUTING代码,我希望先调用IP层的Netfilter,在其mangle表中设置好感兴趣流的mark,然后在bridge的nat表中将打上mark的数据帧redirect到本地的IP层,遗憾的是,这是无法做到的,因为优先级的关系,br_nf_pre_routing的优先级是NF_BR_PRI_BRNF,它位于nat的优先级之后:

enum nf_br_hook_priorities {     NF_BR_PRI_FIRST = INT_MIN,     NF_BR_PRI_NAT_DST_BRIDGED = -300, //NAT的优先级     NF_BR_PRI_FILTER_BRIDGED = -200,     NF_BR_PRI_BRNF = 0,        //br_nf_pre_routing的优先级     NF_BR_PRI_NAT_DST_OTHER = 100,     NF_BR_PRI_FILTER_OTHER = 200,     NF_BR_PRI_NAT_SRC = 300,     NF_BR_PRI_LAST = INT_MAX, };

因此即使IP层的Netfilter为数据帧打上了mark,该mark也不可能为NAT所用,因此此时已经执行过NAT了...如果此时你说还可以在BROUTING上将数据帧热direct到local IP layer,那你的设备就完全成了一个IP层的设备,虽说还能保持bridge的语义(比如放过arp数据帧),然而这种设计会让你的产品文档很令人费解,你的心理预期也将和最终所想的谬之千里。
        最后,我们来看看应该怎么修改代码来解决这个问题。最本质的,那就是修改br_nf_pre_routing这个HOOK函数的优先级,使之执行于bridge的NAT之后,这比较好办,修改br_netfilter.c代码:

static struct nf_hook_ops br_nf_ops[] __read_mostly = {         {                 .hook = br_nf_pre_routing,                 .owner = THIS_MODULE,                 .pf = PF_BRIDGE,                 .hooknum = NF_BR_PRE_ROUTING, #ifdef IP_FILTER_BEFORE_NAT         /**          * 2013/03/06 by 赵亚          * 使iptables的PREROUTING在ebtables的DNAT之前进行,          * 因为网桥的DNAT要使用iptables设置的mark          */                 .priority = NF_BR_PRI_NAT_DST_BRIDGED-1, #else                 .priority = NF_BR_PRI_BRNF, #endif ...

另一处修改是br_nf_pre_routing_finish,问题涉及到执行完IP Netfilter之后,需要从哪里继续的问题,修改该函数的最后:

#ifdef IP_FILTER_BEFORE_NAT         /**          * 2013/03/06 by 赵亚          * 重新开始NF_BR_PRI_BRNF          */         NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,                        br_handle_frame_finish, NF_BR_PRI_NAT_DST_BRIDGED); #else         NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,                        br_handle_frame_finish, 1); #endif

NF_BR_PRI_BRNF被定义成了0,如果按照标准的现有2.6.32内核的实现,应该从优先级1开始执行,然而我们的修改版上,由于此时还没有执行NAT,因此需要从NAT开始执行,而我们的br_nf_pre_routing优先级被设置成了NAT的优先级减去1,那么接下来应该从NAT开始。
        这个修改也不是说没有副作用的,它使得标准的实现,即NAT位于IP Netfilter之前这个假设所带来的收益完全失效,记住此点即可。

转载于:https://blog.51cto.com/dog250/1268895

关于bridge-nf-call-iptables的设计问题相关推荐

  1. K8S专题-基础组件的部署1

    文章目录 前言 1.最好是手动 2.Docker安装 3.K8S **在`kubeadm init` 之前kubelet会不断重启** 总结 前言 1.最好是手动 2.Docker安装 # 安装依赖软 ...

  2. 【Kubernetes快速实战】

    K8S官网文档:https://kubernetes.io/zh/docs/home/ 文章目录 前言 一.K8S核心特性 二.K8S集群安装 1.安装K8S集群 1.关闭防火墙 2.关闭 selin ...

  3. 3、kubeadm部署Kubernetes 网络插件flannel、Calico、weave 并设置集群角色

    Kubernetes(k8s)是自动化容器操作的开源平台,这些操作包括部署,调度和节点集群间扩展. Kubernetes不仅支持Docker,还支持Rocket,这是另一种容器技术. 使用Kubern ...

  4. 关系数据库设计五大范式学习记录——<五>

    一.前言 设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式, 各种范式呈递次规范,`越高的范式数据库冗余越小`. 二.范式简介 范式来自英文Norma ...

  5. 伤脑筋的bridge模式-我不明白。。

    看了看 看了看..看不明白. 还是那图,还是那人. 伤脑筋. 不过看到了几句话: oo的原则 之一就是 相比使用继承 使用 对象组合更好 . 另外: GoF 在说明Bridge 模式时,在意图中指出B ...

  6. QT教程:如何实现将图稿从PS等设计工具中导出

    Qt是目前最先进.最完整的跨平台C++开发工具.它不仅完全实现了一次编写,所有平台无差别运行,更提供了几乎所有开发过程中需要用到的工具.如今,Qt已被运用于超过70个行业.数千家企业,支持数百万设备及 ...

  7. 数据库理论 —— 数据库设计六大范式

    前言 笔者遇到范式是在数据仓库建模时,以前对范式的理解比较浅显,且只了解前三范式,对后面三个范式并不了解,趁此机会和大家一起把其他范式学习下. 1. 基础概念 在了解范式之前我们需要对其中的一些基本概 ...

  8. 小红书自研小程序:电商体验与效果优化的运行时体系设计

    小程序在其诞生后的几年内,凭借其简单.轻量.流畅.无需安装等特点,引来了爆发式的增长.伴随小红书电商业务的发展,我们洞察到越来越多的商家和品牌大客户有自己定制化需求场景,传统的电商和薯店存在下面三大问 ...

  9. Neutron的SDN化

    对于SDN大家估计都耳熟能详,这里首先讲讲虚拟化网络技术故事,当VM技术出现的时候,存储通过本地存储或远端挂载的形式基本没有太大变化,但是网络技术呈现形式一直不断翻新. OVS可以说是一个网络虚拟化里 ...

  10. 2021-7-19-OpenStack基础知识学习

    OpenStack基础知识学习 参考文献:Wolf_Coder,百度百科 1,云计算 1.1,出现原因 由亚马逊公司提出.1.随着业务增加公司内部的服务器不够使用,进行虚拟化技术->2.随着公司 ...

最新文章

  1. jsp java 登陆_jsp+java servlet实现简单用户登录
  2. 云计算风起云涌,超融合恰逢其时!
  3. 技巧:在Silverlight中如何访问外部xap文件中UserControl
  4. 功能机也不放过,谷歌或为 Chrome 提供非触控模式
  5. 刷paper利器!不想打开PDF,这个插件自动帮你转到介绍页
  6. Qt之Threads和QObjects
  7. 计算机二级java邓伦单_2010年3月计算机等级考试二级Java笔试试题(文字版)
  8. 简单操作去除PDF文件
  9. 哪个NBA球队会夺冠?用深度学习预测最有潜力的球员!
  10. 游戏检测到计算机性能过低,windows检测到您的计算机性能缓慢
  11. SVN中clean up的含义
  12. 【问题解决】seckill-秒杀项目 -- 服务端异常
  13. 使用myEclipse开发Hibernate项目的步骤
  14. Tivoli Storage Manager[转]
  15. Micheal Nielsen's神经网络学习之三:过拟合与规范化
  16. 《那些年啊,那些事——一个程序员的奋斗史》——123
  17. laravel model 模型详细基本用法
  18. text-davinci-002与 text-davinci-003 有什么不同?
  19. Android AbsoluteLayout布局(绝对布局)
  20. 如何在Power BI中实现主页显示一个月,Tools显示前N个月的数据?

热门文章

  1. Linux 内核C -- 第02课:驱动中的指定初始化
  2. excel正在等待某个应用程序以完成对象链接与嵌入操作_ES32 嵌入式开发从这里开始...
  3. 古希腊之争(一)详解(C++)
  4. 用户环境变量_linux 初级3 环境变量命令env、set、export、declare的区别
  5. python 类 内置方法_类相关内置方法
  6. matlab标签背景透明,ROI透明背景(matlab)
  7. java listbook,java,_Java泛型问题,在编译时,提示警告: 需要: ListT 找到: ListBookDetails,java - phpStudy...
  8. 架构 DNS原理及其解析过程
  9. 运维 xshell 学习
  10. php 命令显示扩展信息