关于bridge-nf-call-iptables的设计问题
然而,协议栈并没有这么实现,因为那样会造成严重的代码冗余,维护成本将会很高。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的设计问题相关推荐
- K8S专题-基础组件的部署1
文章目录 前言 1.最好是手动 2.Docker安装 3.K8S **在`kubeadm init` 之前kubelet会不断重启** 总结 前言 1.最好是手动 2.Docker安装 # 安装依赖软 ...
- 【Kubernetes快速实战】
K8S官网文档:https://kubernetes.io/zh/docs/home/ 文章目录 前言 一.K8S核心特性 二.K8S集群安装 1.安装K8S集群 1.关闭防火墙 2.关闭 selin ...
- 3、kubeadm部署Kubernetes 网络插件flannel、Calico、weave 并设置集群角色
Kubernetes(k8s)是自动化容器操作的开源平台,这些操作包括部署,调度和节点集群间扩展. Kubernetes不仅支持Docker,还支持Rocket,这是另一种容器技术. 使用Kubern ...
- 关系数据库设计五大范式学习记录——<五>
一.前言 设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式, 各种范式呈递次规范,`越高的范式数据库冗余越小`. 二.范式简介 范式来自英文Norma ...
- 伤脑筋的bridge模式-我不明白。。
看了看 看了看..看不明白. 还是那图,还是那人. 伤脑筋. 不过看到了几句话: oo的原则 之一就是 相比使用继承 使用 对象组合更好 . 另外: GoF 在说明Bridge 模式时,在意图中指出B ...
- QT教程:如何实现将图稿从PS等设计工具中导出
Qt是目前最先进.最完整的跨平台C++开发工具.它不仅完全实现了一次编写,所有平台无差别运行,更提供了几乎所有开发过程中需要用到的工具.如今,Qt已被运用于超过70个行业.数千家企业,支持数百万设备及 ...
- 数据库理论 —— 数据库设计六大范式
前言 笔者遇到范式是在数据仓库建模时,以前对范式的理解比较浅显,且只了解前三范式,对后面三个范式并不了解,趁此机会和大家一起把其他范式学习下. 1. 基础概念 在了解范式之前我们需要对其中的一些基本概 ...
- 小红书自研小程序:电商体验与效果优化的运行时体系设计
小程序在其诞生后的几年内,凭借其简单.轻量.流畅.无需安装等特点,引来了爆发式的增长.伴随小红书电商业务的发展,我们洞察到越来越多的商家和品牌大客户有自己定制化需求场景,传统的电商和薯店存在下面三大问 ...
- Neutron的SDN化
对于SDN大家估计都耳熟能详,这里首先讲讲虚拟化网络技术故事,当VM技术出现的时候,存储通过本地存储或远端挂载的形式基本没有太大变化,但是网络技术呈现形式一直不断翻新. OVS可以说是一个网络虚拟化里 ...
- 2021-7-19-OpenStack基础知识学习
OpenStack基础知识学习 参考文献:Wolf_Coder,百度百科 1,云计算 1.1,出现原因 由亚马逊公司提出.1.随着业务增加公司内部的服务器不够使用,进行虚拟化技术->2.随着公司 ...
最新文章
- jsp java 登陆_jsp+java servlet实现简单用户登录
- 云计算风起云涌,超融合恰逢其时!
- 技巧:在Silverlight中如何访问外部xap文件中UserControl
- 功能机也不放过,谷歌或为 Chrome 提供非触控模式
- 刷paper利器!不想打开PDF,这个插件自动帮你转到介绍页
- Qt之Threads和QObjects
- 计算机二级java邓伦单_2010年3月计算机等级考试二级Java笔试试题(文字版)
- 简单操作去除PDF文件
- 哪个NBA球队会夺冠?用深度学习预测最有潜力的球员!
- 游戏检测到计算机性能过低,windows检测到您的计算机性能缓慢
- SVN中clean up的含义
- 【问题解决】seckill-秒杀项目 -- 服务端异常
- 使用myEclipse开发Hibernate项目的步骤
- Tivoli Storage Manager[转]
- Micheal Nielsen's神经网络学习之三:过拟合与规范化
- 《那些年啊,那些事——一个程序员的奋斗史》——123
- laravel model 模型详细基本用法
- text-davinci-002与 text-davinci-003 有什么不同?
- Android AbsoluteLayout布局(绝对布局)
- 如何在Power BI中实现主页显示一个月,Tools显示前N个月的数据?
热门文章
- Linux 内核C -- 第02课:驱动中的指定初始化
- excel正在等待某个应用程序以完成对象链接与嵌入操作_ES32 嵌入式开发从这里开始...
- 古希腊之争(一)详解(C++)
- 用户环境变量_linux 初级3 环境变量命令env、set、export、declare的区别
- python 类 内置方法_类相关内置方法
- matlab标签背景透明,ROI透明背景(matlab)
- java listbook,java,_Java泛型问题,在编译时,提示警告: 需要: ListT 找到: ListBookDetails,java - phpStudy...
- 架构 DNS原理及其解析过程
- 运维 xshell 学习
- php 命令显示扩展信息