ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ebtables与iptables之间的交互技巧

ebtables与iptables之间的交互技巧 shixudong163.com疫情期间在研究《iptables DNAT实现broadcast与unicast之间相互映射》关系时对ebtables与iptables之间的交互进行了深入学习。网上ebtables的中文资料大多是关于man ebtables的翻译性文献而ebtables官网的《ebtables/iptables interaction on a Linux-based bridge》一文也基本是概念性的内容缺乏深入的分析。通过查阅源码本文对ebtables与iptables之间的交互操作进行了稍许分析原本一些模糊的概念和原理均得以厘清。特此记录以备今后随时查询如能有益于他人善莫大焉。一、桥接模式使用iptables默认情况下只经过网桥的流量不会被iptables处理。为了让网桥上的流量经过iptables处理粗暴的做法是使用如下命令规则要匹配双向流量或双向分别使用各自规则sudo ebtables -t broute -A BROUTING -p IPv4 --ip-proto tcp -j redirect --redirect-target DROP其作用是强制桥上所有tcp包走路由而非桥不足是broute表的redirect将数据包的接收设备设置成了桥物理端口而非桥设备自己导致后续iptables nat表PREROUTING链只能使用DNAT取代REDIRECT。优雅的做法是使用如下命令sudo modprobe br_netfilter其作用是让桥直接在二层调用iptables然后继续进行二层转发。可以通过抓包工具验证前者ttl比后者ttl小1那是因为前者走了路由必须启用ip_forward否则无效而后者直接通过br_forward转发无需启用ip_forward。如果同时启用上述两种方式由于broute的优先级最高对于同一个数据包如符合broute规则就强制走路由直接在三层调用iptables如不符合broute规则才通过br_netfilter在二层调用iptables。更新常规情况下桥接模式使用iptables无需同时启用上述两种方法并且优先推荐br_netfilter。然而如果还需要使用iptables/TPROXY由于TPROXY和br_netfilter天然存在冲突此时就只能通过broute把需要TPROXY处理的数据包强制交给三层iptables处理其他流量则继续由br_netfilter在二层调用iptables。顺便提一下在二层调用iptables后如二层数据包的最终目标MAC为多播MAC或网桥MAC或者网桥处于promisc模式该数据包仍将移交三层处理。通过br_netfilter注册的ip_sabotage_in钩子函数可以避免同一数据包再次遍历三层PREROUTING链同一数据包不可能同时经过二层和三层的FORWARD或POSTROUTING链。二、桥接模式使用iptables后何时需要ebtables如前所说一般情况下桥接模式使用iptables后只需启用br_netfilter模块即可引导桥流量遍历iptables规则无需额外使用ebtables工具。但若需要在iptables nat表PREROUTING链中做DNAT且DNAT后数据包目的地与初始进入包都位于网桥同一物理端口时由于两个原因该DNAT最终是无法成功的。一个原因是由于桥转发本身的内在机制网桥收到的包不允许从同一端口再次转发出去第二个原因是如DNAT映射后期望的响应包后续返回时没有经过桥就无法对该响应包结合原DNAT映射进行反向处理导致原发送设备会因为收到响应包的源IP和期望的IP不一致而丢弃会话。针对上述问题无线网络和有线网络分别有着不同的解决思路下面展开分析一下无线网络下首先启用桥对应无线物理端口的hairpin_mode参数允许网桥收到的包从同一端口转发出去其次启用hostapd的ap_isolate功能使得DNAT后期望的响应包必须经过桥或者针对DNAT规则增加相应的SNAT规则引导响应包经过桥。也就是说无线网络解决该问题无需另行引入ebtables工具。有线网络也可以采用上述思路启用桥对应有线网卡的hairpin_mode参数并针对DNAT规则增加相应的SNAT规则引导响应包经过桥。但只增加SNAT规则又会引发新的问题br_netfilter在二层调用iptables新增的SNAT规则时只能修改源IP为桥IP以引导响应包返回桥却无法同步修改源MAC为桥MAC。如果发送设备和DNAT目标都位于网桥上联的同一个物理交换机上该交换机先是在原发送设备对应的端口学习到该源MAC又在网桥对应的交换机端口学习到同一个源MAC产生MAC漂移。后续来自DNAT目标的响应包使用网桥MAC作为目标MAC返回网桥并经NAT转换后仍需通过交换机继续发往原发送设备NAT转换后的响应包到达交换机时交换机因MAC漂移发现目标MAC对应的端口为最后学习到的网桥也即该响应包进来的端口同样不允许从同一端口再次转发出去而主动丢包。为避免交换机MAC漂移还需针对该SNAT规则iptables规则配套使用ebtables snat规则修改源MAC为桥MAC来回两个方向都要修改以消除MAC漂移。如果网桥上联的是另一个linux网桥也可关闭上联linux网桥的地址学习功能来消除MAC漂移实际上该响应包此时通过上联网桥的br_flood功能自然能成功发送到原发送设备对应的端口。针对有线网络除采用上述思路hairpin_modeiptables SNATebtables snat外还可采用前面强制路由的思路即仅针对需要DNAT的包采用ebtables/broute强制移交三层路由此时必须启用ip_forward同样可以绕开网桥同一端口无法二层转发的机制然后增加相应的SNAT规则引导响应包经过桥。当数据包在三层做DNAT后不用再经过br_forward而是通过ip_forward转发同时SNAT在三层修改源IP为桥IP后数据包最终发送出去时自动将二层源MAC修改为桥MAC无需额外使用ebtables单独修改。需要注意的是桥接模式下通过br_netfilter直接在二层调用iptables仍然能保证iptables的连接跟踪机制。但ebtables工具不支持连接跟踪特性在使用ebtables/broute规则针对需要DNAT的包强制走路由时要分别考虑进出两个方向的包而不像iptables下返程包可以通过连接跟踪自动匹配。三、ebtables主动对MAC地址做snat/dnat在一些数据中心网络设施采用了SDN架构能限制接入设备的MAC地址。在日常环境中很容易模拟这一现象在只有无线网卡的笔记本上使用VirtualBox并使用Bridged Networking连网时需要对虚拟机的MAC做“nat”转换为主机无线网卡的MAC以便连到外部网络此时Bridged Networking也能限制虚拟机的MAC地址。对于VirtualBox这种情况在多个虚拟机利用linux桥和“内部网络”连接方式组网测试网络功能时Bridged Networking只能识别到采用“桥接网卡”虚拟机的MAC无法识别采用“内部网络”虚拟机的MAC此时可在“桥接网卡”虚拟机上使用ebtables的snat规则将其他虚拟机的MAC地址转换为Bridged Networking能识别的MAC地址使得其他虚拟机最终也能通过Bridged Networking连到外部网络。下面两条命令是必不可少的sudo ebtables -t nat -A POSTROUTING -o eth0 -j snat --to-src cat /sys/class/net/br0/address --snat-arpsudo ebtables -t nat -A PREROUTING -p arp -i eth0 --arp-op Reply -j dnat --to-dst ff:ff:ff:ff:ff:ff第一条命令将其他虚拟机的源MAC通过snat转换为“桥接网卡”虚拟机的桥MAC此桥MAC可被Bridged Networking识别后续就能被Bridged Networking再次“nat”转换为主机无线网卡的MAC。该条命令同时将其他虚拟机arp请求包里的Sender MAC也转换为桥MAC同样以便通过后续的再次“nat”。第二条命令将外部回来的单播arp响应包的目标MAC通过dnat转换为二层广播地址后向其他虚拟机广播。前面提到过ebtables没有连接跟踪机制对于外部回来的响应包还需针对每个内部IP添加一条相应的dnat规则同时也适用于外部进来的初始包。sudo ebtables -t nat -A PREROUTING -p IPv4 -i eth0 --ip-dst $IP -j dnat --to-dst $MAC以上三条命令均是利用二层机制对数据包的MAC进行nat转换如嫌最后一类命令繁琐需要对每个内部IP添加一条可采用三层机制优化。考虑执行第一条命令后外部设备看到的其他虚拟机MAC地址全部是“桥接网卡”虚拟机的桥MAC如不执行最后一类命令外来响应包或初始包都会自然移交到“桥接网卡”虚拟机的三层处理此时只需启用“桥接网卡”虚拟机的路由功能启用ip_forward无需上述第三类命令即可将外来数据包路由到相应的其他虚拟机。采用路由处理后其他虚拟机向外部发出的包走二层出去外来响应包或初始包通过三层进来此时“桥接网卡”虚拟机如发现外来数据包的源IP、目标IP即其他虚拟机IP和自身IP都属于同一网段会向同网段外部设备不停发送Redirect Host包可在“桥接网卡”虚拟机上关掉send_redirects功能或者增加如下命令防止路由功能发送Redirect Host包。sudo ebtables -t broute -A BROUTING -p ! arp -i eth0 -d cat /sys/class/net/br0/address -j redirect --redirect-target DROP使用该命令后将数据包的接收设备设置为桥物理端口一般情况下桥物理端口不配置IP所以不满足外来数据包的源IP、目标IP和接口自身IP都属于同一网段这一规则故路由功能也不会发送Redirect Host包又不影响其他情形下的send_redirects功能。上述命令的其他注意事项一是使用-p ! arp参数参见上述第二条命令不对arp包强制路由。二是注意不能使用-j DROP取代-j redirect --redirect-target DROP做强制路由当桥MAC和桥物理端口MAC不一致时-j DROP实际上起不到强制路由作用详见后文分析。四、broute之DROP简要分析broute的DROP和ebtables/iptables的其他DROP意义完全不同其他DROP就是字面意思-丢弃数据包而broute的DROP表示将包移交三层去路由。broute的DROP有多种用法虽然都是移交三层但其行为各不相同最稳妥的用法就是前述例子中的BROUTING -j redirect --redirect-target DROP如直接使用-j DROP有很大可能起不到强制路由作用变成名副其实的DROP被三层DROP。下面结合源码分析阐述一下两者实质性差异。Linux网桥由多个物理端口组成网桥和物理端口都有各自MAC大多数情况下桥MAC和物理端口MAC并不一致。当两者不一致时由于桥物理端口不参与ARP响应导致该物理端口收包的目标MAC要么是桥MAC要么是其他机器MAC该情形下网桥物理网卡永远收不到目标MAC与自身MAC一致的包因此在调用eth_type_trans时总是将包类型设置为PACKET_OTHERHOST该PACKET_OTHERHOST包后续到达br_handle_frame时br_handle_frame在调用BROUTING之后、调用PREROUTING之前将目标MAC和桥MAC一致的包修改为PACKET_HOST。。BROUTING -j DROP虽然被br_handle_frame调用但调用完毕后直接退出br_handle_frame并不修改包类型在桥物理端口MAC和桥MAC不一致时该物理端口收到的包类型全是PACKET_OTHERHOST三层针对PACKET_OTHERHOST一律DROP导致事实上起不到强制路由作用。而BROUTING -j redirect --redirect-target DROP调用和退出虽然和BROUTING -j DROP相同但在进行redirect处理时将数据包的目标MAC替换为桥物理端口的MAC同时修改包类型为PACKET_HOST可被三层处理或路由。还有很少用到的BROUTING -j dnat -to-dst xx:xx:xx:xx:xx:xx --dnat-target DROP仅当xx:xx:xx:xx:xx:xx设置为桥物理端口MAC时方修改包类型为PACKET_HOST其实质完全等价于前述redirect如xx:xx:xx:xx:xx:xx和桥物理端口MAC不一致包类型一律修改为PACKET_OTHERHOST其实质完全等价于前述-j DROP。较老的内核bridge在处理dnat时压根不修改包类型当收包的桥物理端口MAC和桥MAC不一致时收包总是PACKET_OTHERHOST如同-j DROP一样起不到强制路由作用。如前所述启用br_netfilter后排除一些特例一般情况下确实无需使用ebtables以及broute表但如网桥所在linux主要网络流量不是用于二层转发时建议考虑使用如下命令sudo ebtables -t broute -A BROUTING -p ipv4 -d cat /sys/class/net/br0/address -j redirect --redirect-target DROP该命令的作用是将发往Linux本身的包目标MAC为网桥MAC包括需要linux路由的包强制交给三层避免了不必要的桥代码处理节省了CPU资源。唯一的不足前面也已提及即后续iptables匹配nat表PREROUTING链时只能使用DNAT取代REDIRECT。
返回列表