前文提到計劃將辦公室的電腦改為下班休眠,需VPN連線時再透過網路喚醒,但遇到一點困難:WOL封包必須透過廣播方式送到休眠主機,最簡便的做法是在同一網段內(Subnet)發送IP末碼為255(例如:192.168.1.255)的封包,電腦會以MAC地址ff-ff-ff-ff-ff-ff發送,所有網卡都會收到。而問題出在使用VPN連線時,家中電腦取得的公司IP與休眠主機分屬不同網段,無法透過IP 255廣播,前文提過一種在Switch/NAT設定靜態IP對應MAC ff-ff-ff-ff-ff-ff的解法,但公司網路設備非掌控範圍,無法在上面動手腳,想到最直覺的做法-在同網段內找一台機器跑一個內應程式,接受來自跨網段要求,對網段內廣播WOL封包。

前文提到的WOL Magic Packer Sender軟體,需透過操作介面手動傳送,但Magic封包的構造很簡單,六個Byte 0xff,配上目標MAC地址(也是六個Byte)重複16次,共102 Bytes,用C#組byte[]再用UdpClient送出就能搞定,所以:

using System;
using System.Net;
using System.Net.Sockets;
using System.Linq;
 
public class MagicPacket
{
 
    public static void Send( string ipAddress, string macAddress)
    {
        //UDP Port 9
        IPEndPoint pEndPoint = new IPEndPoint(IPAddress.Parse(ipAddress), 9 );
        byte[] macAddrBytes =
            //將aa:bb:cc:dd:ee:ff或aa-bb-cc-dd-ee-ff MAC地址轉成byte[]
            macAddress.Split('-' , ':')
            .Select(o => Convert.ToByte(o, 16)).ToArray();
        //送出UPD封包
        using (UdpClient udpClient = new UdpClient ())
        {
            byte[] data = new byte[102 ];
            //最前方六個0xff
            for (var i = 0 ; i < 6; i ++ )
                data[i] = 0xff ;
            //重複16次MAC地址
            for (int j = 1 ; j <= 16; j ++ )
            {
                macAddrBytes.CopyTo(data, j * 6);
            }
            udpClient.Send(data, (int)data.Length, pEndPoint);
            udpClient.Close();
        }
    }
}

就這樣,呼叫MagicPacket.Send("192.168.1.255", "aa-bb-cc-dd-ee-ff"); 即可正確送出Magic封包喚醒電腦,這段程式可以放進同網段其他主機的ASP.NET,改用瀏覽器叫電腦起床,也可以寫成服務接收從簡訊、Skype、HipChat傳來訊息代替Morning Call,運用上很有彈性。

補上這一小塊拼圖,我的跨網段網路喚醒計劃終於完成了~


Comments

# by Overing

Jeffrey 大 請問 ... CreateMagicPacket 是要給 Send 呼叫的嗎?

# by Jeffrey

to Overing,是我昏頭了,原本組封包邏輯寫在CreateMagicPacket函式,後來為求簡化直接搬進Send(),卻忘了把原函式移除,已修改,感謝提醒。

Post a comment