
shixudong163.com在《WSL2和VPN》一文后話中簡單提了一下WSL2mirrored在支持multicast方面的不足當(dāng)時并沒有開展進(jìn)一步的深入研究。近日在github上看到多篇issues10735、12344在討論WSL2的組播問題特別是WSL2mirrored和Windows主機(jī)之間無法進(jìn)行組播通信遂靜下心來做了一番功課得以形成此文。一、WSL2的組播支持WSL2新增mirrored模式號稱支持multicast但無論是mirrored、bridged還是nat三者其實(shí)都使用同一個Linux內(nèi)核對組播的支持在內(nèi)核層面是無差別的。只是由于網(wǎng)絡(luò)層面的不同導(dǎo)致了三種模式對組播的支持程度有所差異而已。在外部設(shè)備看來nat模式下組播包無法被轉(zhuǎn)發(fā)出去可認(rèn)為WSL2nat不支持multicastMirrored和Bridged模式對組播的支持程度基本上是一樣的只是WSL2一直想要廢棄bridged模式所以才有mirrored模式號稱支持組播一說。WSL2向外部設(shè)備發(fā)送組播數(shù)據(jù)包沒有問題但WSL2官方內(nèi)核不支持CONFIG_IP_MULTICAST因此WSL2在接收組播包時無法發(fā)送組播加入信息。當(dāng)網(wǎng)絡(luò)上啟用了IGMP snooping后因?yàn)闆]有收到WSL2的組播加入信息交換機(jī)壓根不會將WSL2希望接收的組播包發(fā)送到Windows主機(jī)導(dǎo)致WSL2無法接收外部設(shè)備發(fā)來的組播包。對于這一情形有兩種解決方法可以讓W(xué)SL2能夠正常接收外部設(shè)備發(fā)來的組播包。1、由Windows主機(jī)代為發(fā)送WSL2需要的組播加入信息。2、使用CONFIG_IP_MULTICASTy重新編譯WSL2內(nèi)核支持WSL2發(fā)送組播加入信息。二、WSL2bridged的組播優(yōu)勢和不足WSL2bridged使用與主機(jī)不同的IP和MACWSL2和Windows主機(jī)之間的組播通信與WSL2和外部設(shè)備之間的組播通信沒有區(qū)別因此WSL2可以順利向Windows主機(jī)發(fā)送組播數(shù)據(jù)包。而且由于WSL2和Windows主機(jī)之間沒有外部網(wǎng)絡(luò)故即使WSL2使用不支持CONFIG_IP_MULTICAST官方內(nèi)核也能順利接收Windows主機(jī)發(fā)來的組播包。針對WSL2橋接到主機(jī)有線網(wǎng)卡的情形考慮到大多數(shù)網(wǎng)絡(luò)已默認(rèn)啟用IGMP snooping功能如前所述WSL2bridged必須使用CONFIG_IP_MULTICASTy的定制內(nèi)核才能順利接收外部設(shè)備發(fā)來的組播包。針對WSL2橋接到主機(jī)無線網(wǎng)卡的情形即使外部網(wǎng)絡(luò)沒有啟用IGMP snooping功能依然有兩種例外情況會導(dǎo)致WSL2無法接收外部設(shè)備發(fā)來的組播包1、如WSL2使用CONFIG_IP_MULTICASTy的定制內(nèi)核WSL2在接收組播包時能夠發(fā)送組播加入信息但有些無線AP在識別到該組播加入信息后將自動啟用multicast_to_unicast功能發(fā)往Windows主機(jī)的組播包被轉(zhuǎn)換為以主機(jī)無線網(wǎng)卡MAC為目標(biāo)的單播包由于Windows網(wǎng)橋驅(qū)動功能太爛不能依據(jù)三層組播IP對multicast_to_unicast進(jìn)行逆轉(zhuǎn)換將單播目標(biāo)MAC恢復(fù)成組播目標(biāo)MAC導(dǎo)致WSL2因使用與主機(jī)不同的MAC反而無法接收組播包Vmware橋接主機(jī)無線網(wǎng)卡時也有同樣的問題VirtualBox橋接可根據(jù)三層組播IP對multicast_to_unicast進(jìn)行逆轉(zhuǎn)換不存在類似缺陷。2、如WSL2橋接的主機(jī)無線網(wǎng)卡固件具有multicast filter特性由于WSL2在接收組播包時無法向主機(jī)無線網(wǎng)卡添加多址過濾條件主機(jī)無線網(wǎng)卡也會主動攔截外部發(fā)給WSL2的組播包。針對例外情形1優(yōu)先使用官方內(nèi)核不讓W(xué)SL2發(fā)出組播加入信息或者通過防火墻攔截WSL2發(fā)出的組播加入信息。此時無線AP一般不會啟用multicast_to_unicast功能外部設(shè)備發(fā)來的組播包能順利被WSL2接收。針對例外情形2理論上的解決思路是讓W(xué)indows主機(jī)也加入到WSL2接收組播包所需要的同一個組播組此時將由Windows主機(jī)向自身無線網(wǎng)卡添加多址過濾條件放行WSL2需要的組播包。該思路看起來很美妙然而卻和例外情形1相沖突因?yàn)橹灰猈indows主機(jī)加入到同一個組播組必然會發(fā)送組播加入信息觸發(fā)無線AP自動啟用multicast_to_unicast功能導(dǎo)致WSL2無法接收組播包。因此還需要同時通過防火墻攔截Windows主機(jī)或WSL2發(fā)出的組播加入信息方能保證WSL2順利接收外部設(shè)備發(fā)來的組播包。如外部網(wǎng)絡(luò)啟用了IGMP snooping功能情形稍為復(fù)雜這是因?yàn)榇蟛糠譄o線AP在檢測到網(wǎng)絡(luò)上啟用IGMP snooping功能后也能自動啟用multicast_to_unicast功能。根據(jù)前面分析此時WSL2將進(jìn)入無解狀態(tài)無論內(nèi)核是否啟用CONFIG_IP_MULTICAST都無法接收外部設(shè)備發(fā)來的組播包。該情形下可以改用WSL2mirrored解決。三、WSL2mirrored的組播優(yōu)勢和不足對于WSL2mirrored來說在和主機(jī)無線網(wǎng)卡配合使用時由于使用了和主機(jī)無線網(wǎng)卡相同的MAC依然可以順利接收外部設(shè)備通過無線AP發(fā)來的multicast_to_unicast組播包不存在類似WSL2bridged的瑕疵。也就是說WSL2無需考慮Win11主機(jī)使用有線網(wǎng)卡還是無線網(wǎng)卡只要使用CONFIG_IP_MULTICASTy的定制內(nèi)核就能順利接收外部設(shè)備發(fā)來的組播包。在不考慮WSL2和Windows主機(jī)之間相互組播通信時顯然WSL2mirrored對組播的支持更勝一籌。然而正是由于WSL2鏡像機(jī)制的特殊性導(dǎo)致無論內(nèi)核是否啟用CONFIG_IP_MULTICASTWSL2mirrored和Windows主機(jī)之間均無法進(jìn)行組播通信。下面分析具體原因并給出解決方案。四、解決WSL2mirrored的組播不足在《也談tcpdump抓包》之五“tcpdump和lo”提到Linux在進(jìn)行本機(jī)組播通信時根據(jù)默認(rèn)路由選擇對應(yīng)的網(wǎng)卡并直接在三層調(diào)用dev_loopback_xmit發(fā)送組播包在該函數(shù)中又直接調(diào)用netif_rx接收組播包因此本機(jī)組播通信全程不使用lo網(wǎng)卡。對于Windows來說根據(jù)抓包結(jié)果判斷本機(jī)組播通信和單播通信一樣全程必須使用loopback設(shè)備。除了這個區(qū)別外兩者相同點(diǎn)是如果要發(fā)送的組播IP未在本機(jī)任何網(wǎng)卡完成組播注冊工作則不向本機(jī)發(fā)送組播包。WSL2mirrored鏡像了主機(jī)所有網(wǎng)卡包括IP和MAC針對主機(jī)loopback設(shè)備還準(zhǔn)備了半鏡像網(wǎng)卡loopback0。對于WSL2來說loopback0可不是什么邏輯網(wǎng)卡而是實(shí)實(shí)在在的物理網(wǎng)卡可用ethtool -i loopback0驗(yàn)證。Windows實(shí)時監(jiān)控WSL2內(nèi)部系統(tǒng)調(diào)用如監(jiān)控到WSL2內(nèi)部應(yīng)用通過系統(tǒng)調(diào)用打開了相應(yīng)端口Windows就將外部設(shè)備發(fā)往該端口的數(shù)據(jù)包鏡像到WSL2對應(yīng)網(wǎng)卡的接收方向。Windows自發(fā)自收單播通信發(fā)生在主機(jī)loopback設(shè)備上當(dāng)WSL2內(nèi)部有相應(yīng)偵聽端口時主機(jī)發(fā)往loopback設(shè)備的數(shù)據(jù)包也會根據(jù)主機(jī)不同的發(fā)送網(wǎng)卡鏡像到WSL2內(nèi)部對應(yīng)網(wǎng)卡的接收方向當(dāng)數(shù)據(jù)包源IP為主機(jī)127.0.0.1時則鏡像到loopback0網(wǎng)卡。當(dāng)我們希望從Windows主機(jī)向WSL2mirrored發(fā)送組播包時如果主機(jī)沒有同時加入該組播組如前所述主機(jī)并不會向loopback設(shè)備發(fā)送組播包只會向主機(jī)網(wǎng)卡發(fā)送組播包而主機(jī)發(fā)送方向的組播包顯然不可能鏡像到WSL2對應(yīng)網(wǎng)卡的接收方向因而WSL2接收不到組播包。針對該情形解決辦法是讓W(xué)indows主機(jī)也加入到WSL2接收組播包所需要的同一個組播組實(shí)現(xiàn)該組播IP在主機(jī)發(fā)送網(wǎng)卡的注冊。此后Windows主機(jī)發(fā)送組播包時也會向loopback設(shè)備發(fā)送一份并根據(jù)主機(jī)組播發(fā)送網(wǎng)卡將組播包鏡像到WSL2對應(yīng)網(wǎng)卡的接收方向使得WSL2能夠順利接收Windows主機(jī)發(fā)出的組播包。在《也談tcpdump抓包》一文還提到Linux無法抓取自發(fā)自收組播包而Windows則可在loopback設(shè)備上抓取自發(fā)自收組播包。而且如同Linux一樣Windows在loopback設(shè)備抓包時也過濾了一半的數(shù)據(jù)包僅在接收環(huán)節(jié)顯示抓包結(jié)果抓包程序的這一設(shè)計(jì)思路本意是為了消除loopback設(shè)備上不必要的顯示冗余。然而當(dāng)Windows主機(jī)將發(fā)往loopback設(shè)備的數(shù)據(jù)包鏡像到WSL2內(nèi)部網(wǎng)卡時由于主機(jī)在發(fā)送鏈路上缺失接收環(huán)節(jié)導(dǎo)致在loopback設(shè)備抓包時根本抓不到從主機(jī)發(fā)到WSL2的包只能抓到從WSL2回到主機(jī)的包可用TCP單播通信驗(yàn)證。因此在前述情形下如Windows主機(jī)加入組播組后在另外一個端口偵聽那么Windows主機(jī)發(fā)給WSL2的組播包雖然必須通過loopback設(shè)備但由于組播是單向通信并且主機(jī)沒有接收環(huán)節(jié)導(dǎo)致出現(xiàn)主機(jī)loopback設(shè)備上抓不到組播包、而WSL2對應(yīng)網(wǎng)卡上卻能抓到組播包的現(xiàn)象。如果不是對loopback設(shè)備抓包機(jī)制和數(shù)據(jù)包方向有清醒的認(rèn)識詳見《也談tcpdump抓包》之六“tcpdump和數(shù)據(jù)包方向”Windows下雖無法抓取數(shù)據(jù)包方向但數(shù)據(jù)包方向原理雷同就會被搞得一頭霧水彷佛主機(jī)壓根沒往loopback設(shè)備發(fā)送過組播包。當(dāng)Windows主機(jī)加入組播組并且偵聽和WSL2一樣的端口時兩者都需要啟用SO_REUSEADDR并且綁定組播地址而非INADDR_ANY主機(jī)在loopback設(shè)備的發(fā)送鏈路上具備了接收環(huán)節(jié)就能在loopback設(shè)備上正常抓取組播包了。采用上述方案解決WSL2mirrored接收Windows主機(jī)發(fā)來的組播包顯然該過程在WSL2內(nèi)部是可抓包的在WSL2看來這就是外來組播包而非自發(fā)自收組播包。在分析WSL2mirrored無法向Windows主機(jī)發(fā)送組播包的原因時有必要復(fù)習(xí)一下WSL2mirrored的鏡像原理Windows實(shí)時監(jiān)控WSL2內(nèi)部系統(tǒng)調(diào)用如監(jiān)控到WSL2內(nèi)部應(yīng)用通過系統(tǒng)調(diào)用打開了相應(yīng)端口Windows就將外部設(shè)備發(fā)往該端口的數(shù)據(jù)包鏡像到WSL2對應(yīng)網(wǎng)卡的接收方向Windows監(jiān)控到WSL2向外發(fā)送數(shù)據(jù)包時就將數(shù)據(jù)包鏡像到Windows主機(jī)對應(yīng)網(wǎng)卡的發(fā)送方向。至于WSL2的物理網(wǎng)卡loopback0被稱之為半鏡像網(wǎng)卡是因?yàn)橹鳈C(jī)發(fā)往loopback設(shè)備的數(shù)據(jù)包也會根據(jù)主機(jī)的不同發(fā)送網(wǎng)卡鏡像到WSL2對應(yīng)網(wǎng)卡的接收方向當(dāng)數(shù)據(jù)包源IP為主機(jī)127.0.0.1時則鏡像到WSL2的loopback0網(wǎng)卡然而反之卻不成立。當(dāng)WSL2向外發(fā)送數(shù)據(jù)包時如果不加以特殊處理不可能被Windows鏡像到主機(jī)loopback設(shè)備的接收方向。當(dāng)我們希望從WSL2mirrored向Windows主機(jī)發(fā)送組播包時WSL2根據(jù)默認(rèn)路由選擇對應(yīng)的網(wǎng)卡發(fā)出組播包Windows將其鏡像到主機(jī)對應(yīng)網(wǎng)卡的發(fā)送方向顯然該組播包不可能進(jìn)入到Windows主機(jī)的接收環(huán)節(jié)。根據(jù)這一事實(shí)要想WSL2向Windows主機(jī)發(fā)送組播包只有在路由選擇上動手腳設(shè)法讓W(xué)indows將WSL2發(fā)出的組播包鏡像到主機(jī)loopback設(shè)備的接收方向從而被Windows主機(jī)接收。前文所謂的特殊處理就是用來干這事的其實(shí)質(zhì)就是WSL2mirrored專用的hostAddressLoopback處理機(jī)制該機(jī)制通過策略路由實(shí)現(xiàn)了WSL2內(nèi)部網(wǎng)卡包括loopback0網(wǎng)卡到主機(jī)loopback設(shè)備的反向鏡像。因此完全可以通過設(shè)置hostAddressLoopbacktrue并借用其處理機(jī)制改變WSL2內(nèi)部組播包的走向?qū)⑵溏R像到主機(jī)loopback設(shè)備的接收方向。對于沒有采用connect方式(《TPROXY與Wireguard》文末小插曲也有提到)或者沒有調(diào)用bind綁定源IP的組播發(fā)送程序執(zhí)行sudo ip route add 組播IP via 169.254.73.152 dev eth0 onlink后此處eth0表示默認(rèn)路由所在網(wǎng)卡Windows主機(jī)就能順利接收WSL2mirrored發(fā)出的組播包。但該方法有兩個不足一是改變了組播的走向?qū)е陆M播包發(fā)不到外部設(shè)備二是由于Linux的路由查找機(jī)制如果組播發(fā)送程序采用connect方式或者調(diào)用bind綁定了源IP就無法改變組播包的走向。另一種解決方法更為完美完全可以克服以上兩個不足那就是同時借用hostAddressLoopback機(jī)制和《iptables TEE使用技巧》一文提到的iptables TEE。遺憾的是WSL2官方內(nèi)核CONFIG_NETFILTER_XT_TARGET_TEE is not set也需要使用CONFIG_NETFILTER_XT_TARGET_TEEy重新編譯內(nèi)核然后執(zhí)行如下三條命令即可后兩條執(zhí)行順序不能顛倒。sudo iptables -A OUTPUT -p udp -d 組播IP -j TEE --gateway WSL2的網(wǎng)卡IP該IP表示默認(rèn)路由所在網(wǎng)卡對應(yīng)的IPsudo ip rule add from all ipproto icmp lookup localsudo ip rule add from all lookup 128第一條命令通過TEE克隆組播包并且只改變克隆組播包的走向因此不影響原始組播包繼續(xù)發(fā)往外部設(shè)備。TEE采取了類似unconnect方式的路由尋址機(jī)制故不受組播發(fā)送程序使用connect方式或者調(diào)用bind綁定源IP的限制。由于TEE在路由尋址時尋址條件相對簡陋沒有protocol字段而WSLmirrored的hostAddressLoopback機(jī)制僅適用于tcp/udp所以還需要第三條命令去除hostAddressLoopback機(jī)制對protocol的限制。第二條命令用于保護(hù)從WSL2內(nèi)部ping自身網(wǎng)卡IP不受影響。采用上述兩種方法后建議后一種Windows主機(jī)能夠順利接收WSL2mirrored發(fā)出的組播包。而且在主機(jī)看來由于組播包是從loopback設(shè)備接收的這就是自發(fā)自收組播包而非外來組播包。很顯然如同WSL2bridged一樣WSL2mirrored和Windows主機(jī)之間的組播通信無需經(jīng)過外部switch/bridge不涉及IGMP snooping所以WSL2內(nèi)核也無需啟用CONFIG_IP_MULTICASTy。五、Linux組播路由選擇Linux發(fā)送組播包時組播發(fā)送程序應(yīng)使用IP_MULTICAST_IF選項(xiàng)指定組播發(fā)送網(wǎng)卡否則將由Linux路由選擇相應(yīng)的組播發(fā)送網(wǎng)卡。在IP_MULTICAST_IF指定INADDR_ANY作為組播發(fā)送網(wǎng)卡或者組播發(fā)送程序干脆沒有使用IP_MULTICAST_IF選項(xiàng)時內(nèi)核將選擇默認(rèn)路由對應(yīng)的網(wǎng)卡發(fā)送組播包如需要通過其他網(wǎng)卡發(fā)送組播包則需要添加靜態(tài)路由指定組播出口網(wǎng)卡無需指定gateway。一旦確定了發(fā)送網(wǎng)卡就在該網(wǎng)卡上進(jìn)行組播發(fā)送。通過路由選擇組播發(fā)送網(wǎng)卡時如靜態(tài)路由指定了gateway如果組播發(fā)送程序沒有使用connect方式或者沒有調(diào)用bind綁定源IP或者靜態(tài)路由關(guān)聯(lián)的出口網(wǎng)卡和IP_MULTICAST_IF選項(xiàng)指定的組播發(fā)送網(wǎng)卡一致時組播包將通過單播方式發(fā)送到gateway本文第四部分解決WSL2mirrored向Windows主機(jī)發(fā)送組播包的第一種方法就是使用了這一思路。即使靜態(tài)路由指定了gateway由于Linux的路由查找機(jī)制如果組播發(fā)送程序使用了connect方式或者調(diào)用bind綁定了源IP則組播包發(fā)送時將忽略該靜態(tài)路由指定的gateway但仍在該靜態(tài)路由關(guān)聯(lián)的出口網(wǎng)卡上進(jìn)行組播發(fā)送。在該情形下如繼續(xù)希望能將組播包通過單播方式發(fā)送到指定的gateway可使用本文第四部分第二種方法利用iptables TEE類似unconnect方式的路由尋址機(jī)制將組播包通過單播方式發(fā)送到TEE指定的gateway。Linux接收組播包時同單播接收偵聽一樣既可以在組播地址上偵聽也可以在INADDR_ANY地址上偵聽。同時組播接收程序還必須使用IP_ADD_MEMBERSHIP選項(xiàng)指定需注冊的組播IP以及組播接收網(wǎng)卡否則同樣由Linux路由選擇相應(yīng)的組播接收網(wǎng)卡。在IP_ADD_MEMBERSHIP選項(xiàng)指定INADDR_ANY作為組播接收網(wǎng)卡時內(nèi)核將選擇默認(rèn)路由對應(yīng)的網(wǎng)卡接收組播包。當(dāng)外來組播包達(dá)到本機(jī)時IP層需要校驗(yàn)組播包到達(dá)網(wǎng)卡是否已注冊該組播IP如組播IP未在該網(wǎng)卡注冊IP層將丟棄該組播包這也是即便交換機(jī)沒有啟用IGMP snooping單播接收程序能接收廣播包、卻不能接收組播包的真實(shí)原因。組播包通過IP層校驗(yàn)并到達(dá)本機(jī)UDP協(xié)議棧時如組播接收程序已關(guān)閉IP_MULTICAST_ALL選項(xiàng)默認(rèn)開啟先前IP層已放行的從非指定組播接收網(wǎng)卡收到的組播包仍會被UDP丟棄此外即使組播接收程序在INADDR_ANY地址上偵聽先前IP層已放行的非指定組播IP對應(yīng)的組播包也會被UDP丟棄。Linux組播接收的上述特點(diǎn)導(dǎo)致和單播接收的行為不完全一致容易引起誤解。由于內(nèi)核只是在IP/UDP層針對組播IP進(jìn)行了一些額外校驗(yàn)最終仍然要調(diào)用單播接收所使用的UDP接收處理函數(shù)因此組播接收程序在使用INADDR_ANY偵聽時一方面仍可以象單播接收那樣接收所有網(wǎng)卡上到達(dá)的單播包另一方面卻并不能接收所有網(wǎng)卡上到達(dá)的組播包。如前所述組播包必須在IP層被強(qiáng)行攔截一道攔截掉那些組播IP未在到達(dá)網(wǎng)卡注冊的組播包。到了UDP層如組播接收程序沒有改變IP_MULTICAST_ALL選項(xiàng)默認(rèn)開啟此時組播接收行為如同單播IP層能放行的組播包都能被接收包括從非指定組播接收網(wǎng)卡收到的組播包組播IP須事先在到達(dá)網(wǎng)卡注冊以及已注冊的其他組播IP對應(yīng)的組播包。六、多網(wǎng)卡Windows和WSL2mirrored前面提到Windows和Linux本機(jī)組播通信有一個共同點(diǎn)即如果要發(fā)送的組播IP未在本機(jī)任何網(wǎng)卡完成組播注冊工作則不向本機(jī)發(fā)送組播包。換句話說對于那些已在Windows相關(guān)網(wǎng)卡自動注冊的組播IP224.0.0.1/224.0.0.251/224.0.0.252/239.255.255.250在單網(wǎng)卡環(huán)境下Windows主機(jī)向這些組播IP發(fā)送組播包時主機(jī)無需另行開啟組播接收程序也會向loopback設(shè)備發(fā)送組播包并被WSL2mirrored上的組播接收程序順利接收。在多網(wǎng)卡Windows環(huán)境下特別是包含了VPN網(wǎng)卡對于那些已在Windows相關(guān)網(wǎng)卡自動注冊的組播IPWindows組播發(fā)送程序并不按照已有路由選擇組播發(fā)送網(wǎng)卡雖然這些組播包仍然會被發(fā)送到loopback設(shè)備但往往被鏡像到WSL2另一塊網(wǎng)卡的接收方向。對于WSL2mirrored來說如主機(jī)發(fā)來的這些組播IP224.0.0.252/239.255.255.250未在WSL2的另一塊網(wǎng)卡自動注冊或者WSL2組播接收程序關(guān)閉了IP_MULTICAST_ALL選項(xiàng)WSL2就無法接收這些來自主機(jī)loopback設(shè)備的組播包除非在WSL2上添加靜態(tài)路由指定了正確的組播接收網(wǎng)卡。本文第四部分通過hostAddressLoopback處理機(jī)制路由指定gateway雙管齊下解決了WSL2mirrored向Windows主機(jī)發(fā)送組播包的問題。然而在多網(wǎng)卡Windows環(huán)境下從WSL2mirrored向Windows主機(jī)發(fā)送那些已在Windows相關(guān)網(wǎng)卡自動注冊的組播IP時同樣也會面臨Windows組播接收程序并不按照已有路由選擇組播接收網(wǎng)卡的問題。即使WSL2已通過指定gateway將組播包發(fā)到了主機(jī)loopback設(shè)備但由于Windows組播接收網(wǎng)卡和WSL2組播發(fā)送網(wǎng)卡的不匹配也會導(dǎo)致Windows主機(jī)無法接收這些組播包。此時可在WSL2上調(diào)整靜態(tài)路由所需的網(wǎng)卡或TEE所需的gateway使得WSL2組播發(fā)送網(wǎng)卡和Windows組播接收網(wǎng)卡相匹配以便Windows主機(jī)能夠順利接收這些WSL2已發(fā)送到主機(jī)loopback設(shè)備、并已在Windows相關(guān)網(wǎng)卡自動注冊了組播IP的組播包。本文第五部分闡述的Linux組播路由選擇機(jī)制同樣也適用于那些已在Linux相關(guān)網(wǎng)卡自動注冊的組播IP224.0.0.1/224.0.0.251。鑒于Linux組播路由選擇相對Windows更為簡潔明了因此針對上述多網(wǎng)卡環(huán)境下Windows和WSL2mirrored之間組播通信的特殊情形解決方案一律繞開了Windows不可捉摸的組播路由選擇機(jī)制而是采用了在WSL2mirrored側(cè)調(diào)整組播靜態(tài)路由的方法加以實(shí)現(xiàn)。多網(wǎng)卡Windows環(huán)境下非自動注冊組播IP的路由選擇取決于組播路由224.0.0.0/4對應(yīng)網(wǎng)卡的躍點(diǎn)數(shù)。常規(guī)情況下VPN網(wǎng)卡不會添加該路由而Windows本身的物理網(wǎng)卡以及各種虛擬機(jī)平臺生成的虛擬網(wǎng)卡將各自添加一條組播路由224.0.0.0/4指向?qū)?yīng)網(wǎng)卡。鑒于虛擬機(jī)平臺生成的虛擬網(wǎng)卡不能被WSL2正常鏡像無法和WSL2通信因此最簡單的做法就是降低Windows主機(jī)默認(rèn)路由對應(yīng)網(wǎng)卡的躍點(diǎn)數(shù)確保Windows始終在主機(jī)默認(rèn)路由對應(yīng)的網(wǎng)卡上進(jìn)行非自動注冊組播IP的發(fā)送和接收。七、Windows和Vmware在分析Windows和WSL2之間組播互通問題的過程中意外發(fā)現(xiàn)Vmware虛擬機(jī)橋接到Windows無線網(wǎng)卡時Windows主機(jī)也無法接收到Vmware虛擬機(jī)發(fā)送的組播包反之則沒有問題。這是由于Vmware采用了簡單粗暴的橋接方式將主機(jī)橋接網(wǎng)卡發(fā)送方向的數(shù)據(jù)包同時注入到該網(wǎng)卡的接收方向。在虛擬機(jī)橋接到主機(jī)無線網(wǎng)卡的情形下接收方向被橋接注入的數(shù)據(jù)包也使用二層nat轉(zhuǎn)換后的主機(jī)無線網(wǎng)卡MAC作為源MAC。Vmware虛擬機(jī)發(fā)出的組播包被橋接網(wǎng)卡分為兩路一路向外發(fā)送另一路向主機(jī)發(fā)送Windows內(nèi)核檢測到以自身無線網(wǎng)卡MAC名義發(fā)出的組播包同時出現(xiàn)在發(fā)送和接收方向誤以為產(chǎn)生了二層環(huán)路主動丟棄了接收方向的組播包導(dǎo)致Windows無法接收Vmware虛擬機(jī)發(fā)來的組播包。Windows主機(jī)發(fā)出的組播包同樣被橋接網(wǎng)卡分為兩路接收方向的組播包也一樣被Windows丟棄但并不影響Vmware虛擬機(jī)接收該組播包。顯然Windows主機(jī)無法接收Vmware虛擬機(jī)發(fā)送的組播包與WSL2mirrored和Windows主機(jī)之間無法組播通信有著本質(zhì)的區(qū)別前者是組播包已到主機(jī)無線網(wǎng)卡接收方向并能被主機(jī)抓包但后續(xù)被Windows內(nèi)核丟包后者純粹是路由問題組播包無法發(fā)送到接收方接收方也壓根抓不到包。因此也就無法用后者改變組播包路由的思路解決前者面臨的問題??赏ㄟ^引入Windows無線網(wǎng)橋來解決這一問題讓Vmware虛擬機(jī)橋接到Windows無線網(wǎng)橋?qū)τ赩mware來說無線橋接變成了有線橋接由無線網(wǎng)橋履行二層nat轉(zhuǎn)換功能。Vmware虛擬機(jī)發(fā)出的組播包被注入到無線網(wǎng)橋接收方向時其源MAC仍是虛擬機(jī)網(wǎng)卡MAC而非主機(jī)無線網(wǎng)卡MAC因而能被Windows主機(jī)順利接收。當(dāng)Vmware虛擬機(jī)為Linux并且網(wǎng)絡(luò)上有IGMP查詢器、switch啟用了IGMP snooping還有一種更巧秒的辦法可以解決前述問題。在Linux虛擬機(jī)上執(zhí)行如下命令后Windows主機(jī)也能順利接收Vmware虛擬機(jī)發(fā)送的組播包。sudo bash -c echo 1 /sys/class/net/br0/bridge/multicast_queriersudo bash -c echo 1 /sys/class/net/eth0/brport/multicast_to_unicastsudo ebtables -A OUTPUT -p ipv4 --ip-proto igmp --ip-dst 224.0.0.1 -j DROP該解決思路來自于本人疫情期間關(guān)于組播學(xué)習(xí)的一些心得前兩條命令用于啟用Linux網(wǎng)橋假設(shè)為br0物理端口假設(shè)為eth0的multicast_to_unicast功能同樣可適用于有線網(wǎng)絡(luò)Linux虛擬機(jī)發(fā)送的組播包目標(biāo)MAC被轉(zhuǎn)換為單播MAC主機(jī)無線網(wǎng)卡MAC能被Windows主機(jī)接收。第三條命令用于防止Vmware虛擬機(jī)linux網(wǎng)橋自帶的IGMP查詢器干涉網(wǎng)絡(luò)上已存在的IGMP查詢器。前提條件是網(wǎng)絡(luò)上有IGMP查詢器、switch啟用了IGMP snoopingWindows主機(jī)得以將組播IP加入信息定期向Linux虛擬機(jī)報(bào)告確保虛擬機(jī)能長期保存主機(jī)發(fā)來的組播IP信息持續(xù)為multicast_to_unicast功能提供有效的單播MAC。此處關(guān)鍵仍在于Windows主機(jī)無法接收虛擬機(jī)網(wǎng)橋IGMP查詢器發(fā)出的組播查詢包因此也就無法主動向Linux虛擬機(jī)進(jìn)行定期報(bào)告而網(wǎng)絡(luò)上的IGMP查詢器可使Windows主機(jī)順便向Linux虛擬機(jī)進(jìn)行定期報(bào)告。本文第二部分提到WSL2橋接到主機(jī)無線網(wǎng)卡和無線AP的multicast_to_unicast功能之間的沖突導(dǎo)致WSL2bridged無法接收外部設(shè)備發(fā)來的組播包。Vmware虛擬機(jī)Linux橋接主機(jī)無線網(wǎng)卡時也有同樣的問題WSL2可以采用mirrored方式解決Vmware虛擬機(jī)Linux的類似問題又該如何解決呢先透露一下答案組合使用Windows無線網(wǎng)橋和Linux的ebtables命令。為何一定需要Windows無線網(wǎng)橋呢這和Vmware的二層nat轉(zhuǎn)換機(jī)制有關(guān)在《Virtualbox配置Linux guest橋和修改網(wǎng)卡MAC》一文中提到在橋接無線網(wǎng)卡時VirtualBox的二層nat轉(zhuǎn)換機(jī)制依賴虛擬機(jī)網(wǎng)卡MAC導(dǎo)致虛擬機(jī)里無法隨意更改虛擬機(jī)網(wǎng)卡MAC。Vmware的二層nat轉(zhuǎn)換不存在類似問題但也有自己的特色即只有看到了虛擬機(jī)外出數(shù)據(jù)包的源IP才允許同樣的IP作為目標(biāo)IP從外部進(jìn)入虛擬機(jī)。當(dāng)外部設(shè)備發(fā)來的數(shù)據(jù)包目標(biāo)IP為未知IP時Vmware的二層nat轉(zhuǎn)換壓根就不將該數(shù)據(jù)包傳給虛擬機(jī)平時感覺不到這個特色是因?yàn)锳RP在默默起作用驗(yàn)證方法手工修改虛擬機(jī)IP主機(jī)通過靜態(tài)ARP映射指向該IP除非虛擬機(jī)先ping外部設(shè)備否則主機(jī)永遠(yuǎn)無法ping通虛擬機(jī)。Vmware虛擬機(jī)橋接到Windows無線網(wǎng)橋后無線橋接變成了有線橋接由無線網(wǎng)橋而非Vmware履行二層nat轉(zhuǎn)換功能。即使外部設(shè)備發(fā)來的數(shù)據(jù)包目標(biāo)IP為Vmware未知的IP也會被VMware如數(shù)傳給虛擬機(jī)。一旦數(shù)據(jù)包到達(dá)了虛擬機(jī)就可以使用etables對其上下其手在Vmware虛擬機(jī)Linux上執(zhí)行如下命令后便不受無線AP的multicast_to_unicast功能影響可以施施然接收外部設(shè)備發(fā)來的組播包了。sudo ebtables -t nat -A PREROUTING -p ipv4 --ip-proto igmp --ip-dst 224.0.0.1 -j redirectsudo ebtables -t nat -A PREROUTING -p ipv4 --ip-proto udp --ip-dst 224.0.0.0/4 -j redirect在執(zhí)行上述命令前雖然外部設(shè)備發(fā)來的組播包也能到達(dá)虛擬機(jī)但在經(jīng)過無線AP的multicast_to_unicast轉(zhuǎn)換后組播包目標(biāo)MAC被改為主機(jī)無線網(wǎng)卡MAC。到達(dá)虛擬機(jī)時包類型被標(biāo)記為PACKET_OTHERHOST后續(xù)被虛擬機(jī)三層DROP導(dǎo)致虛擬機(jī)無法接收外部設(shè)備發(fā)來的組播包。這兩條命令的作用都是將滿足條件的組播包目標(biāo)MAC從主機(jī)無線網(wǎng)卡MAC修改為Linux網(wǎng)橋MAC同時修改包類型為PACKET_HOST使之能到達(dá)虛擬機(jī)三層并能被三層進(jìn)行常規(guī)處理詳見《Linux二層包類型對網(wǎng)絡(luò)功能的影響分析》之二“包類型對橋的影響”。第一條命令允許Linux接收IGMP查詢器發(fā)來的組播查詢包并向外部IGMP查詢器報(bào)告自己的組播加入信息使得外部設(shè)備能向Vmware虛擬機(jī)Linux發(fā)送組播包。第二條命令允許Linux接收外部設(shè)備發(fā)來的組播數(shù)據(jù)包并將其轉(zhuǎn)交給上層組播接收程序。這一解決方案無法適用于WSL2bridged這是由于WSL2橋接所依賴的Hyper-v使用了Switch技術(shù)而VMware采用的是Hub技術(shù)所以當(dāng)組播包目標(biāo)MAC被無線AP改成主機(jī)無線網(wǎng)卡MAC后根本到不了WSL2bridged。測試中發(fā)現(xiàn)Vmware虛擬機(jī)橋接到主機(jī)無線網(wǎng)卡后除了不支持multicast_to_unicast逆轉(zhuǎn)換居然能向Windows主機(jī)無線網(wǎng)卡添加多址過濾條件解除了主機(jī)無線網(wǎng)卡攔截外部組播包的隱患。改為橋接Windows無線網(wǎng)橋后這一隱性福利消失了。如遇到主機(jī)無線網(wǎng)卡固件具有multicast filter特性還需要讓W(xué)indows主機(jī)也加入到Vmware虛擬機(jī)接收組播包所需要的同一個組播組由Windows主機(jī)向自身無線網(wǎng)卡添加多址過濾條件放行Vmware虛擬機(jī)所需要的外來組播包。