shixudong@163.com
疫情期间,因工作需要远程唤醒办公电脑(已通过wireguard组网),以前通过在家里树莓派上编译运行wolf(Wake on Lan Forwarder)实现网络唤醒包的接收和转广播来唤醒家里电脑,现在则需要将唤醒包转发到异地后广播以唤醒办公电脑,成熟的做法当然是设法在异地设备上继续运行wolf转发广播。既然是设法,当然存在“设法”不成功的可能,于是想顺便研究一下能否不借助wolf而直接通过iptables DNAT解决。经过网上搜索资料,反复验证测试,发现iptables确实能通过DNAT实现unicast与broadcast之间相互映射,从而轻易解决远程唤醒异地广播问题,现把问题解决过程分享如下。
一、DNAT实现unicast到broadcast映射
关于DNAT实现unicast到broadcast的映射,网上资料较多,已有成熟解决方案,本人在这里主要起到收集整理资料的作用,没花多少脑子。解决方案根据kernel版本不同分两种情况:
1、sysctl支持bc_forwarding参数的linux较新内核,同时通过如下两条命令即可允许iptables将unicast DNAT到broadcast。
sudo sysctl -w net.ipv4.conf.eth0.bc_forwarding=1
sudo sysctl -w net.ipv4.conf.all.bc_forwarding=1
两点注意事项:
- 命令中eth0为DNAT前数据包的入口设备,必须是三层设备(在网桥情况下必须是桥设备,而不能是桥端口设备)
- 由于linux内核限制,此处broadcast只能是定向广播,而不能是本地广播(255.255.255.255)
2、不支持bc_forwarding参数的linux老内核,利用一个从不使用的单播IP,在Linux上为这个IP设置一个静态ARP表项(ff:ff:ff:ff:ff:ff),然后通过iptables将unicast DNAT到该单播IP,即可将三层unicast IP转换成二层以太网广播地址,可达到和1同样的效果。
二、DNAT实现broadcast到unicast映射
网上基本搜不到DNAT成功实现broadcast到unicast映射的相关资料,但我在树莓派上却能一次性成功,这种感觉很怪异,难道我的树莓派有特殊配置。于是在虚拟机上测试了一下broadcast到unicast的DNAT映射,确实和网上说的一样,无法成功。经对比分析,树莓派启用了br_netfilter模块,试着在树莓派上卸载该模块(sudo rmmod br_netfilter),再次测试,果然无法成功。再次分析br_netfilter和ip_forward源码,发现ip_forward在包类型不是PACKET_HOST时,一律DROP。由于包类型在二层赋值,如仅在三层调用iptables对broadcast做DNAT,iptables代码并不对二层包类型进行修改,而broadcast因包类型不为PACKET_HOST从而无法被三层转发,导致DNAT无法成功。而启用br_netfilter模块后,在二层调用iptables对broadcast做DNAT,此时同一网桥可在二层直接转发iptables的DNAT包;如DNAT前后数据包不在同一网桥,仍需交由三层来转发,由于br_netfilter相关代码会根据DNAT目标自动将broadcast的包类型修改为PACKET_HOST,后续也能顺利通过三层转发。所以DNAT实现broadcast到unicast映射的最简单办法就是启用br_netfilter模块。
但上述方法存在一个不足,当DNAT前后数据包都位于网桥同一端口时,无法顺利二层转发,当然也无法实现broadcast到unicast的DNAT映射了,这是桥转发本身的安全机制。为避免这种情况,仍需要回到三层来设法处理DNAT,或者说在不启用br_netfilter模块的前提下,实现broadcast到unicast的DNAT映射。根据上文介绍和ebtables源码分析,可以通过ebtables在二层将broadcast包类型修改为PACKET_HOST,然后交由三层处理DNAT并转发,这样既解决了ip_forward DROP包的限制,也绕开了网桥同一端口无法转发的机制。经验证,ebtables BROUTING和PREROUTING的redirect都能实现自动将broadcast包类型修改为PACKET_HOST,从而保证后续iptables实现broadcast到unicast的DNAT时能被ip_forward顺利转发。
在某些特定情形下,必须要启用br_netfilter模块,为绕开网桥同一端口无法转发DNAT的机制,可使用带--redirect-target DROP参数的ebtables BROUTING对需要DNAT的broadcast包进行redirect后强行移交三层处理,仍然可以完美克服上述不足。
综上,要使DNAT能成功实现broadcast到unicast映射,都必须借助bridge来完成,如无bridge存在,就无法操作ebtables和br_netfilter。
三、网络唤醒包的分流
原先网络唤醒包只要发往一处,现在则需要同时发往异地,也就是说最好能实现唤醒包的复制和转发,然而通过TEE模块实现较为复杂。因为TEE包没有使用conntrack,直接通过ip_local_out发出,很难对其进行必要的NAT处理。可在PREROUTING中通过string匹配唤醒电脑的MAC地址加以分流。



