Как отправить пакет WOL (или что-нибудь вообще) через сетевой адаптер, у которого нет IP-адреса?

StackOverflow https://stackoverflow.com/questions/445411

Вопрос

Я пытаюсь отправить пакет WOL на все интерфейсы, чтобы разбудить шлюз (который является DHCP-сервером, поэтому у машины еще не будет IP-адреса).

И похоже, что я могу привязывать сокеты только к парам IP и портов...

Итак, вопрос:Как создать сокет (или что-то еще), привязанный к сетевой карте, у которой нет IP-адреса?(Любой язык в порядке.C# предпочтительнее)

@ctacke:Я знаю, что WOL выполняется по MAC-адресу...Моя проблема в том, что Windows отправляет широковещательные сообщения UDP только на тот сетевой адаптер, который Windows считает основным сетевым адаптером (который даже не является сетевым адаптером с маршрутом по умолчанию на моем компьютере с Vista).И я не могу найти способ привязать сокет к интерфейсу, у которого нет IP-адреса.(как это делают DHCP-клиенты)

@Арноут:Почему нет?Клиенты знают MAC-адрес шлюза.Я просто хочу отправить пакет WOL, как это делает DHCP-клиент изначально... (DHCP обнаруживает, что пакеты приходят из 0.0.0.0). Я не возражаю, если мне придется создавать весь пакет побайтно...

Это было полезно?

Решение

Кажется, я нашел решение. Можно использовать 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();
    }
}

Другие советы

WOL выполняется MAC, а не IP. Вот пример .

WOL — очень гибкий протокол, который можно реализовать разными способами.

Наиболее распространенными являются:

  • Отправка WOL в качестве полезной нагрузки Ethernet-пакета.
  • Отправка WOL в качестве полезной нагрузки пакета UDP (для маршрутизации по сети).

Как только он попадает в локальную сеть, он передается всем хостам в сети, используя широковещательный MAC-адрес.

Для пакета Ethernet структура следующая:

  • MAC-адрес назначения:ФФ:ФФ:ФФ:ФФ:ФФ:ФФ (трансляция)
  • Полезная нагрузка волшебного пакета

Для пакета UDP структура следующая:

  • MAC-адрес назначения:ФФ:ФФ:ФФ:ФФ:ФФ:ФФ (трансляция)
  • UDP-порт:9
  • Полезная нагрузка волшебного пакета

Магическая полезная нагрузка состоит из:

  • Поток синхронизации:FFFFFFFFFFFF (это 6 пар или 6 байт FF)
  • 16 копий MAC-адреса компьютера, с которого вы передаете сигнал WOL.
  • Необязательная парольная фраза длиной 0, 4 или 6 байт.

Чтобы получать пакеты WOL из Интернета (через брандмауэр/маршрутизатор):

  • Настройте порт маршрутизатора 9 для переадресации на IP 255.255.255.255 (широковещательный IP-адрес).
  • Установите IP-адрес назначения:Внешний IP роутера

Примечание:Этого можно достичь только на примере UDP, поскольку в пакетах Ethernet отсутствует уровень IP, необходимый для маршрутизации пакета через Интернет.IE, пакеты Ethernet являются опцией только для локальной сети.Проблема с отправкой пакетов WOL через UDP связана с безопасностью, поскольку вам необходимо настроить маршрутизатор на включение IP-вещания (255.255.255.255).Включение широковещательной передачи по IP обычно считается плохой идеей из-за дополнительного риска внутренней атаки внутри сети (затопление Ping, подмена кэша и т. д.).

Дополнительную информацию о протоколе, включая взятие образца, см. этот сайт.

Если вам нужен простой и быстрый инструмент командной строки, который генерирует пакеты WOL (и вы работаете в Debian, Linux Mint или Ubuntu), вы можете установить инструмент, который уже делает это.

Просто установите с помощью командной строки:

sudo apt-get install wakeonlan

Обновлять:

Вот рабочий пример, который генерирует пакет WakeOnLan с использованием текущей версии SharpPcap.

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();
        }
    }
}

Примечание:Это полнофункциональное консольное приложение для отправки пакетов Wake-On-Lan, созданное на основе примера 09, который можно найти в исходном коде SharpPcap.

В этом примере используются следующие библиотеки, которых нет в .NET Framework:

using PacketDotNet;

Эта библиотека (.dll) поставляется в комплекте с SharpPcap.Он отвечает за создание и анализ всех пакетов в SharpPcap.Здесь находится класс WakeOnLan.

Примечание:Код построения/анализа пакетов изначально был включен в SharpPcap.dll.Он был перенесен в отдельную библиотеку, поскольку SharpPcap должен быть оболочкой для winpcap.Многие из его пользователей занимаются разработкой протоколов и/или обработкой необработанных сетевых пакетов.

using SharpPcap;

SharpPcap содержит весь код оболочки winpcap(windows)/libpcap(*nix).Необходимо выбрать интерфейс и отправить пакеты по сети.

.NET работает как виртуальная машина (CLR), поэтому абстрагируется от большей части реальной машины. Например, он предоставляет только интерфейсы для сетей TCP и UDP, которые в стеке сетевых протоколов намного выше того, что вы обсуждаете. Возможно, вам удастся найти сторонний компонент, обеспечивающий доступ к низкоуровневому интерфейсу, но я бы на это не рассчитывал (в прошлом я смотрел на .NET и Java).

Для доступа к этому минимуму в стеке сетевых протоколов вам, вероятно, потребуется кодировать на C соответствующие системные вызовы ОС. Вы можете найти это проще всего в Python, и вы можете обнаружить, что эта функциональность уже реализована в библиотеках Python или сторонних. Например, я предлагаю взглянуть на сетевые библиотеки Twisted. Это было одной из причин, по которой я переключился на Python для большей части моей работы.

С наилучшими пожеланиями.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top