首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 系统运维 >

关于bridge-nf-call-iptables的设计有关问题

2013-03-12 
关于bridge-nf-call-iptables的设计问题熟悉ebtables和iptables的都知道,后者提供的选项所能实现的功能要

关于bridge-nf-call-iptables的设计问题
熟悉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层会在哪里用到,如果没有实际的需求而去修改代码,那未免太学院派了。一个典型的需求就是透明网桥模式的VPN,VPN的加密和封装需要在IP层进行,因此需要把感兴趣流捕获到IP层,不感兴趣流直接bridge出去,这是一个实际的需求,然而现有的bridge模块的代码却是解决不了,why?听我娓娓道来。
        Linux的bridge代码中,bridge-nf-call-iptables体现在br_nf_pre_routing函数中,该函数也是一个Netfilter HOOK函数:

#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之前这个假设所带来的收益完全失效,记住此点即可。

热点排行