7

我正在尝试在所有接口上发送 WOL 包以唤醒网关(这是 DHCP 服务器,因此机器还没有 IP)。

而且似乎我只能将套接字绑定到 IP 和端口对......

所以问题是:如何创建一个绑定到没有 IP 的 NIC 的套接字(或其他东西)?(任何语言都可以。首选c#)

@ctacke:我知道 WOL 是由 MAC 地址完成的......我的问题是 Windows 只在 Windows 认为是主 NIC 的 NIC 上发送 UDP 广播(它甚至不是我的 Vista 机器上具有默认路由的 NIC )。而且我似乎找不到将套接字绑定到没有 IP 地址的接口的方法。(就像 DHCP 客户端一样)

@Arnout:为什么不呢?客户端知道网关的 MAC 地址。我只想像 DHCP 客户端最初那样发送一个 WOL 数据包......(DHCP 发现数据包声称来自 0.0.0.0)我不介意我是否必须逐字节构造整个数据包......

4

4 回答 4

8

看来我找到了解决办法。可以使用 winpcap 将数据包注入任何接口。.net 有很好的包装:http ://www.tamirgal.com/home/dev.aspx?Item=SharpPcap

(我更喜欢不需要安装额外库的解决方案......)

更新:这是我在所有接口上发送 WOL 数据包的方法:

//You need SharpPcap for this to work

private void WakeFunction(string MAC_ADDRESS)
{
    /* Retrieve the device list */
    Tamir.IPLib.PcapDeviceList devices = Tamir.IPLib.SharpPcap.GetAllDevices();

    /*If no device exists, print error */
    if (devices.Count < 1)
    {
        Console.WriteLine("No device found on this machine");
        return;
    }

    foreach (NetworkDevice device in devices)
    {
        //Open the device
        device.PcapOpen();

        //A magic packet is a broadcast frame containing anywhere within its payload: 6 bytes of ones
        //(resulting in hexadecimal FF FF FF FF FF FF), followed by sixteen repetitions 

        byte[] bytes = new byte[120];
        int counter = 0;
        for (int y = 0; y < 6; y++)
            bytes[counter++] = 0xFF;
        //now repeat MAC 16 times
        for (int y = 0; y < 16; y++)
        {
            int i = 0;
            for (int z = 0; z < 6; z++)
            {
                bytes[counter++] =
                    byte.Parse(MAC_ADDRESS.Substring(i, 2),
                    NumberStyles.HexNumber);
                i += 2;
            }
        }

        byte[] etherheader = new byte[54];//If you say so...
        var myPacket = new Tamir.IPLib.Packets.UDPPacket(EthernetFields_Fields.ETH_HEADER_LEN, etherheader);

        //Ethernet
        myPacket.DestinationHwAddress = "FFFFFFFFFFFFF";//it's buggy if you don't have lots of "F"s... (I don't really understand it...)
        try { myPacket.SourceHwAddress = device.MacAddress; }
        catch { myPacket.SourceHwAddress = "0ABCDEF"; }//whatever
        myPacket.EthernetProtocol = EthernetProtocols_Fields.IP;

        //IP
        myPacket.DestinationAddress = "255.255.255.255";
        try { myPacket.SourceAddress = device.IpAddress; }
        catch { myPacket.SourceAddress = "0.0.0.0"; }
        myPacket.IPProtocol = IPProtocols_Fields.UDP;
        myPacket.TimeToLive = 50;
        myPacket.Id = 100;
        myPacket.Version = 4;
        myPacket.IPTotalLength = bytes.Length - EthernetFields_Fields.ETH_HEADER_LEN;           //Set the correct IP length
        myPacket.IPHeaderLength = IPFields_Fields.IP_HEADER_LEN;

        //UDP
        myPacket.SourcePort = 9;                
        myPacket.DestinationPort = 9;           
        myPacket.UDPLength = UDPFields_Fields.UDP_HEADER_LEN;


        myPacket.UDPData = bytes;
        myPacket.ComputeIPChecksum();
        myPacket.ComputeUDPChecksum();

        try
        {
            //Send the packet out the network device
            device.PcapSendPacket(myPacket);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }

        device.PcapClose();
    }
}
于 2009-01-15T16:24:51.437 回答
4

WOL 是一种非常灵活的协议,可以以多种不同的方式实现。

最常见的是:

  • 发送 WOL 作为以太网数据包的有效负载。
  • 发送 WOL 作为 UDP 数据包的有效负载(用于通过网络路由)。

一旦它登陆本地网络,它就会使用广播 MAC 地址传递给网络上的所有主机。

对于以太网数据包,其结构为:

  • 目标 MAC:FF:FF:FF:FF:FF:FF(广播)
  • 魔术包有效负载

对于 UDP 数据包,结构为:

  • 目标 MAC:FF:FF:FF:FF:FF:FF(广播)
  • UDP 端口:9
  • 魔术包有效负载

魔术有效载荷包括:

  • 同步流:FFFFFFFFFFFF(即 6 对或 6 个字节的 FF)
  • 您向 WOL 发送信号的计算机 MAC 的 16 个副本
  • 0、4 或 6 个字节的可选密码。

从互联网接收 WOL 数据包(通过防火墙/路由器):

  • 配置路由器端口9转发到IP 255.255.255.255(广播IP)
  • 设置目的IP:路由器的外网IP

注意:这只能使用 UDP 示例来实现,因为以太网数据包缺少通过 Internet 路由数据包所需的 IP 层。IE,以太网数据包是本地网络唯一选项。通过 UDP 发送 WOL 数据包的问题是安全性,因为您必须将路由器设置为启用 IP 广播 (255.255.255.255)。启用 IP 广播通常被认为是一个坏主意,因为会增加网络内部攻击的风险(Ping 泛洪、缓存欺骗等)。

有关协议的更多信息,包括样本捕获,请参阅此站点

如果您想要一个生成 WOL 数据包的快速而简单的命令行工具(并且您在 debian、linux mint 或 Ubuntu 上运行),您可以安装一个已经执行此操作的工具。

只需使用命令行安装:

sudo apt-get install wakeonlan

更新:

这是一个使用当前版本的 SharpPcap 生成 WakeOnLan 数据包的工作示例。

using System;
using System.Collections.Generic;
using System.Net.NetworkInformation;
using PacketDotNet;
using SharpPcap;

namespace SharpPcap.Test.Example9
{
    public class DumpTCP
    {
        public static void Main(string[] args)
        {
            // Print SharpPcap version
            string ver = SharpPcap.Version.VersionString;
            Console.WriteLine("SharpPcap {0}, Example9.SendPacket.cs\n", ver);

            // Retrieve the device list
            var devices = CaptureDeviceList.Instance;

            // If no devices were found print an error
            if(devices.Count < 1)
            {
                Console.WriteLine("No devices were found on this machine");
                return;
            }

            Console.WriteLine("The following devices are available on this machine:");
            Console.WriteLine("----------------------------------------------------");
            Console.WriteLine();

            int i = 0;

            // Print out the available devices
            foreach(var dev in devices)
            {
                Console.WriteLine("{0}) {1}",i,dev.Description);
                i++;
            }

            Console.WriteLine();
            Console.Write("-- Please choose a device to send a packet on: ");
            i = int.Parse( Console.ReadLine() );

            var device = devices[i];

            Console.Write("What MAC address are you sending the WOL packet to: ");
            string response = Console.ReadLine().ToLower().Replace(":", "-");

            //Open the device
            device.Open();

            EthernetPacket ethernet = new EthernetPacket(PhysicalAddress.Parse(
                "ff-ff-ff-ff-ff-ff"), PhysicalAddress.Parse("ff-ff-ff-ff-ff-ff"),
                EthernetPacketType.WakeOnLan);
            ethernet.PayloadPacket = new WakeOnLanPacket(
                PhysicalAddress.Parse(response));
            byte[] bytes = ethernet.BytesHighPerformance.Bytes;

            try
            {
                //Send the packet out the network device
                device.SendPacket(bytes);
                Console.WriteLine("-- Packet sent successfuly.");
            }
            catch(Exception e)
            {
                Console.WriteLine("-- "+ e.Message );
            }

            //Close the pcap device
            device.Close();
            Console.WriteLine("-- Device closed.");
            Console.Write("Hit 'Enter' to exit...");
            Console.ReadLine();
        }
    }
}

注意:这是基于 Example09 构建的全功能 Wake-On-Lan 数据包发送控制台应用程序,可在 SharpPcap 源代码中找到。

此示例中使用的在 .NET 框架中找不到的库是:

using PacketDotNet;

该库 (.dll) 与 SharpPcap 一起打包。它负责 SharpPcap 中的所有数据包构造和解析。这是 WakeOnLan 类所在的位置。

注意:数据包构造/解析代码最初捆绑在 SharpPcap.dll 中。它被迁移到了自己的库,因为 SharpPcap 旨在成为 winpcap 的包装器。它的许多用户处理设计协议和/或处理原始网络数据包。

using SharpPcap;

SharpPcap 包含所有 winpcap(windows)/libpcap(*nix) 包装器代码。需要选择接口并通过线路发送实际数据包。

于 2010-11-10T09:11:30.863 回答
2

WOL 由 MAC 完成,而不是 IP。 这是一个例子

于 2009-01-15T02:19:57.680 回答
0

.NET 作为虚拟机 (CLR) 运行,因此它抽象出大部分底层真实机器。例如,它只为 TCP 和 UDP 网络提供接口,这在网络协议栈中比您正在讨论的要高得多。您可能能够找到提供对较低级别接口的访问的第三方组件,但我不会指望它(我过去曾研究过 .NET 和 Java)。

为了访问网络协议栈的底层,您可能需要用 C 编写相关的 OS 系统调用。您可能会发现这在 Python 中最简单,并且您可能会发现此功能已经在 Python 或第三方库中实现。例如,我建议看一下 Twisted 网络库。这也是我在大部分工作中转向 Python 的原因之一。

最良好的祝愿。

于 2009-01-15T16:22:57.153 回答