Iptables DNAT实现broadcast与unicast之间相互映射

shixudong@163.com

疫情期间,因工作需要远程唤醒办公电脑(已通过wireguard组网),以前通过在家里树莓派上运行wolf(Wake on Lan Forwarder)实现网络唤醒包的接收和转广播来唤醒家里电脑。现在则需要将唤醒包转发到异地后广播以唤醒办公电脑,顺便试一下新方法,看看能否不借助转发软件(如专用wolf或通用socat)而直接通过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

几点注意事项:
(1)    命令中eth0对应DNAT前数据包的入口设备(cisco是在广播包的出口接口设置ip directed-broadcast),必须是三层设备(在网桥情况下必须是桥设备br0,而不能是桥端口设备eth0)
(2)    以上两条命令缺一不可
(3)    由于linux自身的IP路由机制,DNAT转换后的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同样的效果。

上述两种情况的区别在于,前者是真正的二层和三层广播,不仅能用于远程网络唤醒,还可用于广播UDP数据;而后者在三层上不是广播,一般只能用于远程网络唤醒(网卡硬件层面处理)。

顺便提一下,如仅在内部网络上使用远程唤醒,实际上并不需要借助iptables,只需在远端linux作上述配置,便可直接针对远程广播地址或特定的单播IP发送唤醒包。

二、DNAT实现broadcast到unicast映射

网上很难搜到DNAT成功实现broadcast到unicast映射的相关资料,但我在树莓派上却能一次性成功,这种感觉很怪异,难道我的树莓派有特殊配置。于是在虚拟机上测试了一下broadcast到unicast的DNAT映射,确实和网上说的一样,无法成功。经对比分析,树莓派启用了br_netfilter模块,试着在树莓派上卸载该模块(sudo rmmod br_netfilter),再次测试,果然无法成功。
根据Linux网络相关源码分析,Linux网卡接收数据包时,网卡驱动调用eth_type_trans对数据包进行预处理,该函数通过比较目标MAC地址判断二层包类型并进行标记:PACKET_BROADCAST(二层广播地址)、PACKET_MULTICAST(二层多播地址)、PACKET_OTHERHOST(目标MAC非本网卡MAC)、PACKET_HOST(目标MAC为本网卡MAC)。ip_forward在包类型不是PACKET_HOST时,一律DROP,而iptables并不能修改二层包类型,在不启用br_netfilter的情形下,iptables对broadcast做DNAT时,由于broadcast包类型不为PACKET_HOST无法被三层转发,导致DNAT最终无法成功。
启用br_netfilter后,在二层调用iptables对broadcast做DNAT时,br_netfilter会做一些善后处理,如判断DNAT后数据包目的地和进入包在同一网桥可通过二层直接转发出去;如两者不在同一网桥,br_netfilter会将DNAT后数据包的二层目标地址修改为桥MAC,并将原broadcast包类型修改为PACKET_HOST,后续交由三层处理并顺利通过ip_forward完成转发。所以DNAT实现broadcast到unicast映射的最简单办法就是启用br_netfilter模块。
但上述方法存在一个不足,由于桥转发本身的内在机制,当DNAT后数据包目的地和初始进入包都位于网桥同一物理端口时,无法顺利二层转发,当然也无法实现broadcast到unicast的DNAT映射了。为避免这种情况,仍需设法回到三层来处理DNAT,或者说在不启用br_netfilter模块的前提下,实现broadcast到unicast的DNAT映射。
根据上文介绍和相关源码分析,可通过ebtables将二层广播地址修改为桥MAC,并将broadcast包类型修改为PACKET_HOST,然后强制移交三层处理DNAT映射,这样既绕开了网桥同一端口无法转发的机制,也解决了ip_forward DROP包的限制。经验证,ebtables BROUTING使用-j redirect --redirect-target DROP可对需要DNAT的broadcast包进行redirect后移交三层iptables实现broadcast到unicast的DNAT映射。

三、特别提醒
1、第一部分用DNAT实现unicast到broadcast映射,通常都在远程网络实现,因而不会涉及桥接。但如需在本地网络实现,正好相反,通常仅在桥接时才有意义,譬如将DHCP Offer包从单播改成广播,此时必须考虑桥接的影响,除了按第一部分操作外,还得参照第二部分进行桥接处理(一般启用br_netfilter即可),否则unicast包在二层就转发出去了,压根没有机会经由三层DNAT转换成broadcast包。
2、第二部分用DNAT实现broadcast到unicast映射,因本地广播不能跨网,定向广播跨网后实质上不再被视为广播,所以仅针对本地网络有效,跨网情况毫无意义。因转换方向不同,故无需进行第一部分操作,而且broadcast包既可以是定向广播也可以是本地广播。
3、要使DNAT成功实现broadcast到unicast的映射,上文提到的br_netfilter模块和ebtables工具都必须在bridge环境下方能起作用。如Linux没有采用bridge,就无法通过DNAT实现broadcast到unicast的映射,此时可通过iptables的TEE变通实现broadcast到unicast的转换(详见iptables TEE使用注意事项)。

四、网络唤醒包的分流

让我们言归正传,重新聚焦到远程唤醒包的异地转发实现上,原先网络唤醒包只要发往一处,现在则希望同时发往异地,也就是说需要对唤醒包进行复制和转发。貌似可通过TEE目标实现多路转发,然而由于TEE包不能改变复制包的三层地址,而且TEE包本身不使用conntrack,直接通过ip_local_out发出,很难对其进行必要的NAT处理,故原始包和复制包使用相同的目标IP(对于远程唤醒包来说,一般多为iptables所在机器IP),导致根本不可能送达异地。可行的办法是通过nat表PREROUTING链采用string匹配不同唤醒电脑的MAC地址加以分流。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值