ebtables和iptables与linux bridge的交互

本文为翻译文,不一定是逐字逐句的翻译,而且中间会加上自己的一点见解,如有理解错误的地方,还请大家指出,我定虚心学习。原文见链接

其中斜体字是自己的理解,建议和ebtables手册和iptables手册一起看。

1.介绍

本文档描述了iptables和 ebtables过滤表如何在基于Linux的网桥上进行交互。
在2.4.x内核上获取桥接防火墙包括修补内核源代码。2.6内核包含ebtables和br-nf代码,所以不需要修补。由于需求很高,2.4版内核的补丁仍然可以在ebtables主页上找到。该BR-NF代码使桥接IP帧/数据包通过iptables的链。该BR-NF代码使桥接IP帧/数据包通过iptables的链。ebtables在以太网层进行过滤,而iptables只对IP数据包进行过滤。

1.弄清楚br-nf代码都做了什么,就明白iptables的规则为什么在bridge上也能够起作用了。
2.这里既然说道iptables只对ip数据包进行过滤,那么,可以这么理解,与ip协议同层的包括arp,802.1q等协议(见linux中/etc/ethertypes列出的),那么这些协议的数据包是不会被iptables过滤的。

应该指出的是,br-nf代码有时会违反TCP/IP网络模型。例如在链路层内执行IP DNAT。要注意的是,我们完全清楚,帧是用于链路层的,而分组是用于网络层的。但是,当我们谈论链路层内的IP数据包时,我们将这些数据称为帧/数据包或数据包/帧。

2.帧如何遍历ebtables链

本节只考虑ebtables,而不是iptables。
首先我们要记住我们在说的是以太网层,也就是tcp/ip模型的1层和2层。
以网桥(工作在以太网层)为目的地的数据包的ip目的地址不一定是网桥所在的计算机。这就是路由器的工作原理(mac目的地址是路由器,ip目的地址才是你想交互的实际的box)。

1.明确一个概念:工作在2层的设备,如网桥,交换机,意味着他们只和数据包的二层的头交互,并不意味着它一定有mac地址(以前我是这么认为的)。
2.一个帧中的目的mac地址,只是数据帧下一跳的目的地,并不一定是它的最终目的地,最终目的地由目的ip决定。3.box我没有翻译,就把它理解为可以接受ip数据包的黑匣子就可以

Figure2a.数据帧穿越网桥的方案

在linux的桥代码中有6个hook点,BROUTING是专门为ebtables新增的。

Figure2b.以太网桥接的hook点

hook是网络代码中的特定位置,其它代码可以将自己绑定到该位置,从而处理通过该位置的分组/帧。例如,内核模块负责将ebtables的FORWARD链绑定掉桥的FORWARD点。这是模块被加载到内核或者启动时完成的。
请注意,ebtables的BROUTING和PREOUTING链在桥接决定之前被遍历,因此这些链设置会看到桥会忽略的帧。使用此链时应考虑到这一点。另外要注意的是,这些链不会看到进入非转发网桥端口的帧。

如何理解最后一句的non-forwarding bridge port,应该是有一个开关负责打开bridge的forwarding功能,就像ip_forward。然而我并没有找到此配置。仅仅找到了/proc/sys/net/bridge/bridge-nf-call-iptables和CONFIG_BRIDGE_NETFILTER,但是感觉应该不是这里的non-frowarding。

桥对一个帧的决策可能是以下情况之一:

  • 桥接,条件是:目的Mac地址在桥的另一端端口
  • 从桥的所有端口广播此帧,条件是:桥不知道拥有此目的Mac地址的box
  • 将此帧传递至更高协议栈,条件是:帧的目的Mac是桥的Mac或者是桥某个端口的Mac
  • 忽略此帧,条件是:帧的目的Mac地址在桥的同侧,和帧入口在同侧

图2b中,有几点问题,
1. 图中第一个Routing做了什么,之后呢?
2. FORWARD是依据什么作为判决条件的?
3. BRIDGING为什么是一个判断框,而又没有N(否定情况)?
4. 这里的BRIDGING是通过桥口将数据帧发出去的意思吗?

下面我会对这几个问题作答。

Figure2c 桥接表ebtables遍历过程

Ebtables有三个表:filter,nat和broute,如图2c,每个表有各自的链。
注:filter和nat表的OUTPUT链是分离的,并有不同的用法。
图2b和2c给出了清晰地ebtables的链是如何附加到桥的hook点的。
当被绑定到桥上的网卡接收到帧时,帧会首先经过BROUTING链。在这个特殊的链,你可以选择路由或者桥接此帧,使你成为一个brouter(桥路器)。与在互联网上找到的关于brouter是什么的定义有些不同。下一个定义很好地描述了使用BROUTING链的brouting能力:
“brouter是桥接一些帧/分组(即基于链路层信息的转发)并路由其他帧/分组(即基于网络层信息的转发)的设备。桥/路径决策基于配置信息。”

我觉得这里体现出了文章介绍部分说明的情况“br-nf代码有时会违反TCP/IP网络模型”,本身bridge和ebtables都处于第二层,然而这里竟然会去根据三层的信息决定是路由还是桥接。

例如,可以使用brouter作为2个网络之间IP流量的普通路由器,同时桥接这些网络之间的特定流量(NetBEUI,ARP,无论什么)。IP路由表不使用网桥逻辑设备,而是将IP地址分配给物理网络设备,这些设备也恰好是网桥端口(网桥受限网卡)。

这里说的IP路由表不使用网桥逻辑设备,box将ip地址分配给物理网络设备,也正好是网桥接口。不太理解,为什么说IP路由表不使用网桥逻辑设备,其次,当网卡被桥接后,其ip地址是访问不到的,我做过试验,同时也有理论证明。见链接

BROUTING链中的默认决定是桥接。

默认是ACCEPT,在BROUTE表中,ACCEPT的含义略有不同,就是桥接的意思,这个可以从ebtables的用法中找到。而DROP的含义是让帧被路由。还有一个决策时redirect,它相当于做了目的Mac地址转换,并将桥口的Mac地址作为目的Mac。这个redict的作用和DROP的作用效果一样,都会让帧走到三层,去做路由抉择,区别在于,DROP并没有进行目的Mac地址转换。
redirect可以用在broute表的BROUTING链和nat的PREROUNTING链,只是它们更换的Mac不一样,nat中使用的桥的的Mac地址(linux中桥设备默认有一个Mac地址,是桥口的某一个设备Mac地址)

接下来,帧通过PREROUTING链。在此链中,你可以更改帧的目标MAC地址(DNAT)。如果该帧通过该链,则桥接代码将决定帧的发送位置。网桥通过查看目的MAC地址来实现这一点,它不关心网络层地址(例如IP地址)。

在此回答刚才的问题1,2,3,4:
1. 到了三层,根据路由表查看数据包下一跳应该发送到哪里(如果有iptables相关策略,就会去遍历iptables的链点)
2. 依据目的Mac地址是否是自己或者是广播包(应该说是不是bridge的Mac地址,应该不是bridge.port地址,这里也是个疑问。)
3. 否定时通过路由
4. 数据包的出口还是桥的接口,判断框里应该写BRIDGING/ROUTING,但是经过routing后的帧还是有可能会经过ebtables的OUTPUT和POSTROUTING。

如果网桥决定这个帧的目的地是本机,这个帧就会经过INPUT链。在这个链你可以过滤目的是bridge box的帧。遍历过INPUT链后,这个帧将会被传送上网络层(IP相关的代码中)。因此,一个被路由的IP数据包会经过ebtables的INPUT链,而不会经过ebtables的FORWARD链。这是符合逻辑的。

Figure2d 传入帧遍历的链

Figure2e 转发帧遍历的链

桥接决定后,本地始发的帧将遍历nat OUTPUT,过滤器OUTPUT和nat POSTROUTING链。nat OUTPUT链允许改变目的地MAC地址,并且过滤器OUTPUT链允许过滤来自桥接盒的帧。请注意,在桥接决策后,nat OUTPUT链会被遍历,所以这实际上太晚了。我们应该改变这一点。nat POSTROUTING链与上面描述的一样。

1.还是不理解这个桥接决定到底是什么意思呢。难不成就是数据包出去是否要通过这个桥。先简单这么理解吧。
2.为什么说,桥接决策后,nat表的OUTPUT链会被遍历,这实际上太晚了。因为nat OUTPUT链允许进行DNAT,但是此时桥接决策已做,意味着数据包从哪个网卡出去已经确定了,此时再做DNAT的有可能变换后的目的地址其实不应该从这个口出去的,但是已经晚了。

Figure2f 传出帧遍历的链

当目标设备是逻辑桥设备时,需要被路由帧也可能通过这三条链。
这个容易理解,目的MAC为逻辑桥设备,被路由决策后,封装后的帧的源MAC地址为桥的Mac。

 

3.一个用做桥梁和路由器的设备(而不是桥路器)

Figure3a IP代码hooks

下面是iptables数据包遍历方案

Figure3b 路由表(iptables)遍历过程

请注意,iptables nat OUTPUT链位于路由决策之后。正如前一节所述(讨论ebtables时),这对于DNAT来说已经太晚了。这是通过重新路由IP数据包,如果它已被DNAT解决,在继续之前。为了清楚起见:这是Linux内核的标准行为,不是由我们的代码引起的。

在nat OUTPUT链上既可以做snat也可以做dnat,为什么说dnat在这里做太晚了呢,因为,此时路由决策已经做了,数据包其实已经却从哪个口出到达下一跳了,但是转换后的目的地址并不一定可以从此口可以到达的。

图3a和3b给出了iptables链连接到IP hook的清晰视图 。在内核中启用bridge代码和netfilter时,iptables链也会连接到桥接代码的钩子上。但是,这并不意味着它们不再附加到他们的标准IP代码钩子上。对于与桥接代码接触的IP数据包,br-nf代码将决定iptables 链将在网络代码的哪个位置被遍历。很明显,这就确保没有链被同一个数据包遍历两次。所有不与网桥代码接触的数据包都会以标准方式遍历iptables的链,如图3b所示。

除了别的之外,以下各节还将尝试解释br-nf代码的功能以及它为什么执行此操作。
可以看到一个IP数据包/帧可能会遍历 nat PREROUTING,filter NPUT,nat OUTPUT,filter OUTPUT和nat POSTROUTING ebtables链。
这是在当网桥也用作路由器时,可能会发生这种情况。包含该IP数据包的以太网帧将具有网桥的目标MAC地址,而目标IP地址不是网桥。包括 iptables链,这是IP数据包如何通过网桥/路由器。


Figure3c 桥梁/路由器 路由数据包到一个桥接口(简单视图)

这里是假设路由决定发送帧到桥接口。如果路由决定发送数据包到非桥接口,是下面这种情况:


Figure3d 桥梁/路由器 路由数据包到一个桥接口(简单视图)

这两幅图如何理解呢:比如一条linux服务器,三个网卡,eth0,eth1,eth2,eth0和eth1被桥接为br0,接受到的数据包从br0的某一个端口进来,经过路由判定后,该数据包需要从eth2口送出(例如数据包的目的地址和网桥地址不一个子网,或者网桥没有地址,而恰巧和eth2在一个子网,或者默认路由是通过eth2才能到达的)。

图3c和3d假定IP数据包到达桥端口。这里显然是“不协调”的是 在ebtables INPUT链之前遍历iptables PREROUTING 链,但是这不能在不牺牲功能的情况下得到帮助。请参阅下一节。

4.对被桥接的数据包进行目的地址转换。

取一个桥接收到的IP数据包。我们假设我们想在它上面做一些IP DNAT。更改数据包的目标地址(IP地址和MAC地址)必须发生在网桥代码决定如何处理帧/数据包之前。

因为等网桥代码处理完成后,帧已经不是远来的帧了,黄花菜都凉了,如果要在网桥代码里做DNAT的话,那么,这必须是同一个人写的代码,但是即使这样也违背了linux模块分离的特性)

所以,这个IP DNAT必须在网桥代码之前发生。即在桥代码实际上做任何事情之前。这与ebtables nat PREROUTING链将被遍历的地方是一样的(出于同样的原因)。这应该解释图3c和3d中遇到的不协调。
我们也应该注意到,桥接决策的帧成为上述列表中的第四项(例如忽略帧)将在ebtables和iptables的PREROUTING链中看到 。

前面三个是指broute的BROUTING,mangle的PREROUTING和nat的PREROUTING。

5.被桥接的数据包遍历链的过程

桥接数据包永远不会到第1层(链路层)之上的任何网络代码。所以,桥接的IP数据包/帧将永远不会输入IP代码。因此,所有iptables链将被遍历是因为IP数据包会经过网桥的代码。链遍历看起来像这样:

这里图中没有画mangle表,包括mangle PREROUTING、mangle FORWARD和mangle POSTROUTING。

6.在iptables中 使用桥口

希望能够在iptables规则中使用属于网桥(网桥端口)的物理设备是可以且有效的。了解输入的网桥端口对防止欺骗攻击是必要的。假设br0有端口eth0和eth1。如果 iptables规则只能使用br0,那么除了查看MAC源地址(然后仍然...)之外,无法知道eth0端的一个box何时将其源IP地址更改为eth1端子box的源IP地址。 使用iptables physdev模块,您可以在iptables规则中使用eth0和eth1 ,因此可以捕获这些尝试。 
试想一个场景,网桥两端各有一个pc终端,ip分别为192.168.1.11和192.168.1.12,他们的默认网关是桥,现在需要限制1.12地址访问外网,那么如果没有网桥端口参数(--physdev-in)的话,1.12很容易通过伪装ip(手动修改或者snat)来逃脱此限制。

6.1 iptables想要使用网桥目的端口

为了使这成为可能,必须在网桥代码决定帧需要发送的位置(eth0,eth1或两者)之后,才能遍历iptables链。这对第3部分提出的方案有一定影响(所以我们在这里查看路由过程,从桥某一端口进入box)。它实际上看起来像这样(在图3c的情况下)
Figure6a 路由时遍历链的过程(桥和netfilter代码已经编译到了内核中)

注意此图和图3c的区别,iptables的NAT POSTROUTING被移动到了最后面,晚于ebtables的各个链。
所有的链是在bridge代码中被遍历的。这都是br-nf代码做的工作。显然这并不意味着被路由的IP数据包不会进入IP代码。而是他们在IP代码中时不会经过iptables的链而已。

这个做法是如何实现的呢,有待看内核源码分析。

6.2 IP DNAT作用于本地生成的数据包(因此在 iptables nat OUTPUT链中)
本地生成的数据包的通常将通过的链是这样的:
Figure6c

这里iptables的nat POSTROUTING之所又在前面了,原因应该不考虑br-nf代码

从6.1中我们知道实际情况应该是这样的(因为br-nf代码)
Figure6d:

请注意,当数据包在IP代码中时,iptables nat OUTPUT链被遍历,并且当数据包通过桥接决定时,iptables的filter OUTPUT链被遍历。这使得可以对另外的设备在nat OUTPUT链执行DNAT,并让我们在filter OUTPUT链中使用网桥端口作为现在。

这一句“This makes it possible to do DNAT to another device in the nat OUTPUT chain”,应意思是说在nat OUTPUT链执行完DNAT后,数据包可能会用另一个设备(网口)将此帧发送出去。不知道这么理解是不是对的:)

7.帧/数据包通过iptables PREROUTING,FORWARD和POSTROUTING链的 两种可能方式

由于br-nf代码的存在,帧/数据包可以通过给定的3个iptables链来传递2种方式。第一种方式是帧被桥接时,所以 iptables链被bridge代码调用。第二种方式是当数据包被路由时。因此必须特别注意区分这两者,特别是在iptables FORWARD链中。这有一个需要注意的奇怪的例子:
Figure7a. 非常基本的配置 
172.16.1.2和172.16.1.4的默认网关是172.16.1.1。172.16.1.1是端口为eth1和eth2的网桥接口br0。
更多细节:
这个想法是172.16.1.4和172.16.1.2之间的通信被桥接,而其余的通过伪装被路由。
Figure7b: 示意设置的数据流情况 
以下是在启动桥/路由器时使用的可能方案:
iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -d 172.16.1.0/24 -j ACCEPT
iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -j MASQUERADE
 
brctl addbr br0
brctl stp br0 off
brctl addif br0 eth1
brctl addif br0 eth2
 
ifconfig eth1 0 0.0.0.0
ifconfig eth2 0 0.0.0.0
ifconfig br0 172.16.1.1网络掩码255.255.255.0起
 
echo'1'> / proc / sys / net / ipv4 / ip_forward 
注意第一行。因为 iptables对于桥接数据包和路由数据包都执行代码,我们需要区分这两者。我们并不希望桥接帧/数据包被伪装。如果我们省略第一行,那么一切都会起作用,但事情会以不同的方式发生。比如172.16.1.2 ping 172.16.1.4。网桥接收到ping请求,并在首先伪装IP地址后通过它的eth1端口发送。所以数据包的源IP地址现在是172.16.1.1,而172.16.1.4将响应这个桥。伪装会将此响应的IP目标从172.16.1.1更改为172.16.1.4。一切正常。但最好不要有这种行为。因此,我们使用第一行来避免这种情况。

8.iptables PREROUTING链中的IP DNAT作用在进入桥端口的帧/数据包上

通过一些常规播放,可以确保(参见/net/bridge/br_netfilter.c)DNAT'ed数据包在DNAT之后具有与它们所来的输入设备相同的输出设备(我们想要调用的逻辑桥设备br0)将通过ebtables FORWARD链,而不是通过ebtables INPUT / OUTPUT链。所有其他的DNAT'ed数据包将被纯粹路由,所以不会通过ebtables FORWARD链,将通过ebtables INPUT链并可能通过ebtables OUTPUT链。
如果在iptables的nat PREROUTING链执行DNAT的话,那么次数据帧可能出现两种情况,1.目的MAC地址不是桥地址,如果判定数据包从br0进入而且还是从br0出去的话,那么它将进过ebtables的 FORWARD链而不是ebtables INPUT/OUTPUT链。2.目的MAC地址是桥地址,将会被路由,所以不会走ebtables的FORWARD链。

9.使用iptables的MAC模块扩展

这里解释的副作用发生在内核中启用了netfilter代码时,IP数据包被路由并且该数据包的输出设备是逻辑桥设备。在iptables FORWARD链中过滤MAC源时会遇到副作用。从前面部分应该清楚,iptables FORWARD链的遍历被推迟到数据包经过桥代码时。这样做是为了我们可以在网桥端口输出设备上进行过滤。这对MAC源地址有副作用,因为IP代码已将MAC源地址更改为桥接设备的MAC地址。因此在iptables的 FORWARD链中过滤源Mac是有问题的且目的Mac是网桥/路由器的计算机的MAC的数据包。如果你真的需要过滤这个MAC源地址,你应该在nat PREROUTING链中进行。是的,这非常丑陋,但是如果将可以过滤真正的MAC源地址的功能加在FORWARD链中,将涉及非常肮脏的黑客攻击,这是不值得。这当然会使第6部分的反欺骗言论变得有趣。
还没来得及细想为什么会涉及黑客攻击。

10.使用iptables的physdev模块

2.6标准内核包含一个名为physdev的iptables匹配模块,该模块必须用于匹配网桥的物理输入输出端口。它的基本用法很简单(请参阅iptables手册页以获取更多详细信息):
iptables -m physdev --physdev -in <bridge-port>
iptables -m physdev --physdev-out <bridge-port> 
 
最后是两幅图片,比较清晰的指出了IP数据包在Linux bridging firewall上的流转。图1图2
 

总结:

为什么在br-nf代码中遍历iptables的链

  1. 在进入bridge前就用进行dnat
  2. 为了能将bridge port作为过滤条件
 
 

 

posted @ 2018-04-03 21:49  攻城狮dreamer  阅读(15649)  评论(1编辑  收藏  举报