Linux系统中使用ebtables技术
ebtables就是以太网桥防火墙,以太网桥工作在数据链路层(MAC层),ebtables主要过滤数据链路层数据包,ebtables能过滤桥接流量。ebtables每个阶段的过滤时机都比iptables早。
ebtables的配置分为表、链和规则三级。
表:内置固定的,共三种:filter,nat,broute,用-t选项指定。filter最常用,不设置-t默认就是这个表。filter过滤本机流入流出的数据包,是默认使用的表,nat用于地址转换-mac地址,broute用于以太网桥-产生一个桥路由器。
ebtables中的broute表功能:
用于控制进来的数据包是需要进行bridge转发还是进行route转发,即2层转发和3层转发。
BROUTING的ACCEPT/DROP和FORWARD中的区别:
当在BROUTING中执行DROP时,它会在下图的broute/brouting点中直接将包转入iptables;
brouter:是(基于链路层信息)通过网桥转发一部分数据帧并能够(基于网络层信息)通过路由转发其他数据帧的设备。数据帧是被网桥转发还是被路由转发,取决于决策的配置信息。
例如,可以使用 brouter 充当 2 个网络之间 IP 流量互通的普通路由器,同时通过网桥转发这些网络之间的特定流量(NetBEUI,ARP 等)。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 地址(MAC-DNAT)。如果数据帧通过了 PREROUTING 链,则网桥通过查看数据帧的目的 MAC 地址(它不关心网络层信息)来决定将数据帧的发送到哪。
因此,一个被路由转发的 IP 数据包在逻辑上将会经过 ebtables 的 INPUT 链,而不会经过 ebtables 的 FORWARD 链。
在 Linux bridge 上 ebtables 与 iptables 如何进行交互 [译] - 知乎
broute表
用于产生一个桥路器(brouter),包含一个内建chain:
BROUTING 在最早的地方遍历,只能在帧以forwarding状态进入到bridge port的时候才会被遍历。
target DROP和ACCEPT在broute表中有特殊的含义。DROP表示帧已经被route;ACCEPT表示帧已经被bridge
当被绑定到网桥上的网卡接收到数据帧时,数据帧会首先通过 BROUTING 链。在这个特殊的链,你可以选择通过路由转发此数据帧或通过网桥转发此数据帧,这时候网桥将成为一个 brouter。
brouter:是(基于链路层信息)通过网桥转发一部分数据帧并能够(基于网络层信息)通过路由转发其他数据帧的设备。数据帧是被网桥转发还是被路由转发,取决于决策的配置信息。
brouteis used to make a brouter, it has one built-in chain: BROUTING.The targets DROP and ACCEPThave a special meaning in the broute table (these names are used instead ofmore descriptive names to keep the implementation generic). DROPactually means the frame has to be routed, while ACCEPTmeans the frame has to be bridged. The BROUTINGchain is traversed very early. However, it is only traversed by frames entering ona bridge port that is in forwarding state. Normally those frameswould be bridged, but you can decide otherwise here. The redirecttarget is very handy here.
Ebtables使用手册_mac address don't match_Jasonfang0118的博客-CSDN博客
NAT表
nat 经常用于改变MAC地址,包含三个内建的chains:
PREROUTING(为了改变帧当它们已进入)
OUTPUT(为了改变局部产生的或(b)routed 帧 ,在它们被bridge之前)
POSTROUTING(为了改变帧,在它们出去的时候)
filter表
filter 是默认的表,包含三个内建的chains:
INPUT(对于已经决定的帧,在MAC目的地址层)
OUTPUT(对于局部产生的或(b)routed 帧)
FORWARD(对于由bridge传输的帧)
ebtables 之 BROUTING 和 PREROUTING 的 redirect 的区别
ebtable的broute表的BROUTING链的redirect和nat表的PREROUTING的redirect的区别。
很多人不明白 ebtales 的 broute 表的 redirect 和 nat 表 PREROUTING 的 redirect 的区别,其实只要记住两点即可,那就是对于相同点,它们都将数据包导向了本地的 IP 层;对于不同点,broute 表的 redirect 将数据包的接收设备设置成了实际接收数据的物理网卡,而 nat 表将数据包的接收设备设置成了桥设备,这个可以在 Linux 协议栈的源代码中看个究竟。对于 broute 表的 redirect,可以在 br_handle_frame 这个 handle_bridge 调用的回调函数中看到以下的语句:
我们看一下 br_should_route_hook 这个回调函数 ebt_broute:
它进入了我们都熟悉 xxx_do_table 函数,这也就是常规的 Netfilter 规则查找操作,最终在找到匹配规则时,进入 redirect 这个 target。如果没有 broute 表的规则,则会进入 NF_HOOK 这个 HOOK,其间将会遍 NF_BR_BROUTING 所有的规则,如果有 target 为 redirect 的规则命中,则也会进入 redirect 这个 target,这个 target 是什么呢?是 ebt_redirect_tg 这个函数:
从 br_handle_frame 可以看出,一旦 broute 表的匹配规则返回了 DROP,则 handle_bridge 直接返回这个 skb,不再向下执行,这意味着 skb 将在 handle_bridge 返回后沿着 netif_receive_skb 继续走下去,而如果没有匹配的 broute 表规则,则可能在 nat 表的 PREROUTING 链中命中,然后在执行了 ebt_redirect_tg 之后会调用 br_handle_frame_finish 继续下去,在 br_handle_frame_finish 中,由于目的 MAC 地址已经改成了本机网卡的 MAC 地址,因此会调用 br_pass_frame_up 将数据包向协议栈的上层发送:
注意,在 broute 表中的 redirect 之后,数据包的接收设备是实际的物理网卡 ethX,目的 MAC 成了物理网卡 ethX 的 MAC 地址,而在 nat 的 PREROUTING 的 redirect 之后,数据包的接收设备是网桥设备,目的 MAC 地址成了网桥设备的 MAC 地址,知道了这个之后,我们再看一下一个和 iptables 的 nat 表的 redirect 的问题。
设想一个配置,本机 S 的 eth0 的 IP 地址为 1.1.1.254/24,其上开启 tcp 的 88 端口,和本机直连的一台主机 H 的 IP 地址为 1.1.1.2/24,在 S 上配置:
brctl addbr br0 brctl addif eth0 ifconfig br0 1.1.1.254/24 ifcongig eth0 0.0.0.0 #为了防止路由乱掉,因此删除eth0的IP地址 iptables -t nat -A PREROUTING -d 2.2.2.2 -p tcp --dport 1234 -j REDIRECT --to-ports 88
在 H 上执行
route add -host 2.2.2.2 gw 1.1.1.254 telnet 2.2.2.2 1234
结果呢?不通!连 syn-ack 都没有收到,然而在 S 上删除 REDIRECT 规则而执行以下规则则是可以的:
iptables -t nat -A PREROUTING -d 2.2.2.2 -p tcp --dport 1234 -j DNAT --to-destination 1.1.1.254:88
难道 DNAT 和 REDIRECT 有什么区别吗?如果你不明白这两者有什么区别,那么如果你知道 SNAT 和 MASQUERADE 的区别也不错,起码能帮助你理解。DNAT 和 SNAT 能指定任意的源地址一样,可以指定任意的目的地址,那么 REDIRECT 则和 MASQUERADE 也类似,它只是内核根据自己的策略而选择出的一个目的地址,正如 MASQUERADE 也是内核根据 RFC 的建议以及自己的策略选择出的一个源地址一样。那么如何来选择 REDIRECT 的目的地址呢?看一下 iptables 的 man 手册就知道了:
REDIRECT
This target is only valid in the nat table, in the PREROUTING and OUTPUT chains, and user-defined chains which are only called from those chains. It redirects the packet to the machine itself by changing the destination IP to the primary address of the incoming interface (locally-generated packets are mapped to the 127.0.0.1 address).
特别要注意的是 “to the primary address of the incoming interface” 这一句。内核中的 REDIRECT 规则是如何做到这点的呢?这还要看一下代码才知道:
这下我们就一切都明白了,既然 broute 表的 redirect 将接收设备设置为实际的物理网卡,而此网卡的 IP 地址已经被删除,那么上述函数的 newdst 当然不存在了,因此数据包就被 DROP 掉了,到此为止,问题就很清晰了。可见 ebtables 的 redirect 方式直接影响到了 iptables 的 redirect,为了让 iptables 的 redirect 在使用 bridge 时仍然随时可行,则必须为使能 broute redirect 的网卡上设置 IP 地址,为了不使路由冲突,考虑 127.0.0.2。
注:broute 表的意义
为何会有这样的问题?broute 是原因。所谓的 broute 则是 bridge or router,类似早先安装宽带时运营商送的那种猫,能作为桥设备也能作为路由器。如果作为路由器,根本不存在桥设备这一说,因此将接收设备设置为实际的物理网卡也是理所当然的啦。
linux netfilter--broute流程_osnet的博客-CSDN博客
\net\bridge
br_input.c
br_handle_frame
如果一个以太网接口eth1,它并没有桥接到br-lan0中,此时,从eth1进来的数据包不会走到ebtables中。它会在下图中的bridge check点,检查数据包进入的接口是否属于某个桥,如果是则走ebtables,否则直接走iptables。
在/net/bridge/br_if.c中的br_add_if中注册了桥口的处理函数:
所以tap0口必须加入到桥中。桥口的处理函数就是br_handle_frame。
NFTABLES和iptables
之前一直耳闻 nftables 是下一代 iptables 。前段时间配了一台主机,折腾成家里的软路由。就一并来尝鲜一系列新东西,其中就包括 nftables 。nftables 和 iptables 、ebtables 等一样,都是对底层 xtables 的封装,目前看来 nftables 比 iptables 更简洁易用,更易读,更容易理解,扩展性和也更好。但是目前各个发行版中对 nftables 的支持还比较参差不齐,导致 nftables 很多功能比 iptables 还是有所缺失,所以个人感觉短期内还是替代不了 iptables。 nftables 所支持的功能列表及所以来的内核版本和内核模块可以在这里找到 Supported features compared to xtables - nftables wiki 。
openwrt 桥模式下ebtables转发所有流量到三层,导致DHCP无法获取IP解决方案 | 码农家园
配置如下记录Log规则:
iptables -t nat -I POSTROUTING -s 10.99.0.0/24 -d 192.168.0.100 -j LOG --log-prefix "Iptables-NAT-POSTROUTING: " --log-level 4
iptables -t nat -I PREROUTING -s 10.99.0.0/24 -d 192.168.0.100 -j LOG --log-prefix "Iptables-NAT-PREROUTING: " --log-level 4
iptables -I INPUT -s 10.99.0.0/24 -d 192.168.0.100 -j LOG --log-prefix "Iptables-FILTER" --log-level 4
ebtables -A INPUT --log-level info --log-ip --log-ip6 --log-arp --log-prefix BRIDGE_LOG
发现报文从br0口出来又走了一次报文发送。此时关键是ebtable中没有配置任何规则。
而在PLC上抓包,发现源MAC不是网关的MAC,而是远程运维PC上的tap0口的MAC地址,而源IP地址又是网关br0口的IP地址。确定是走了Iptable的NAT表的PREROUTING和POSTROUTING链了。
从可以到不可以,只修改了如下几个内核选项:
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_LOG_COMMON=y
+CONFIG_NFT_LOG=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_NAT=y
+CONFIG_NETFILTER_XT_TARGET_NETMAP=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_REDIRECT=y
+CONFIG_NF_LOG_ARP=y
+CONFIG_NF_LOG_IPV4=y
可能相关的选项为:CONFIG_NF_CONNTRACK=y和CONFIG_NETFILTER_XT_NAT=y,先将这两个选项去掉,看看能不能走到iptable的NAT链表。经测试发现和这两个宏无关。
但是打开CONFIG_BRIDGE_NETFILTER=y宏,可以让二层转发的报文走入iptable的NAT转换表。可以实现我们的目的。查看源码,打开该宏后会编译br_netfilter.c文件,该文件中有br_nf_post_routing()函数,该函数实现的功能是:
#define NF_HOOK(pf, hook, sk, skb, indev, outdev, okfn) (okfn)(sk, skb)
调用钩子函数的代码:
nf_hooks[pf][hook]
struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
NFPROTO_NUMPROTO变量定义如下:
调用钩子时是根据pf(协议类型)和hooknum来调用的。
在net/bridge/br_device.c文件中的br_dev_xmit函数中,如果根据转发表找到了出端口,则调用br_deliver()函数。
在br_nf_post_routing()函数中,将pf类型由NFPROTO_BRIDGE修改为NFPROTO_IPV4或NFPROTO_IPV6,然后再走一遍
这样就可以进入到IPV4转IP地址流程,但是源和目的MAC地址又不变。
netfilter日志打印
sysctl net.netfilter.nf_log.2=nf_log_ipv4
sysctl net.netfilter.nf_log.3=nf_log_arp
sysctl net.netfilter.nf_log.7=nf_log_bridge
sysctl net.netfilter.nf_log.10=nf_log_ipv6
iptables -t nat -I POSTROUTING -s 10.99.0.0/24 -d 192.168.0.100 -j LOG --log-prefix "Iptables-NAT-POSTROUTING: " --log-level 4
iptables -t nat -I PREROUTING -s 10.99.0.0/24 -d 192.168.0.100 -j LOG --log-prefix "Iptables-NAT-PREROUTING: " --log-level 4
iptables -I INPUT -s 10.99.0.0/24 -d 192.168.0.100 -j LOG --log-prefix "Iptables-FILTER" --log-level 4
ebtables -A INPUT --log-level info --log-ip --log-ip6 --log-arp --log-prefix BRIDGE_LOG
iptables -t nat -A POSTROUTING -o br0 -j MASQUERADE