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

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

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

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

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

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


person Tarnay Kálmán    schedule 15.01.2009    source источник
comment
Итак, вы хотите разбудить DHCP-сервер от клиента, который зависит именно от этого сервера, чтобы получить IP-адрес? Я не думаю, что это будет возможно.   -  person Arnout    schedule 15.01.2009
comment
Вы правы - я думал, что это своего рода ситуация с курицей и яйцом, но в основном это то же самое, что DHCP-клиент ищет сервер (как вы сказали). Хорошо, что у SO нет голосования по комментариям :-)   -  person Arnout    schedule 15.01.2009


Ответы (4)


Кажется, я нашел решение. Можно использовать 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();
    }
}
person Tarnay Kálmán    schedule 15.01.2009
comment
Есть две проблемы с этим комментарием. Во-первых, чтобы передать пакет всем компьютерам в сети, вам необходимо включить широковещательную рассылку IP (255.255.255.255) на маршрутизаторе, что обычно считается плохой идеей с точки зрения безопасности (из-за дополнительного потенциала для внутренних сетевых атак, таких как ping-флуд). , вы используете версию SharpPcap, которая устарела на несколько лет. Если вы загрузите последнюю версию, она уже содержит класс для создания/анализа пакетов WOL. Я знаю, потому что я написал это еще в ноябре/декабре по запросу пользователя. . - person Evan Plaice; 15.02.2011
comment
Вот ссылка на проект SharpPcap. sourceforge.net/projects/sharppcap - person Evan Plaice; 15.02.2011
comment
re: DestinationHwAddress -- 12 Fs — это MAC-эквивалент широковещательного IP-адреса 255.255.255.255. На самом деле у вас есть 13 Fs. :) - person Jesse Chisholm; 18.12.2014
comment
Извините за двусмысленный комментарий там. Я знаю, что это должно быть 12, но это не сработало с 12. Сработало с 13. Это/была ошибка где-то на каком-то нижнем уровне, или кто знает... - person Tarnay Kálmán; 18.12.2014

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

Самые распространенные:

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

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

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

  • MAC-адрес назначения: FF:FF:FF:FF:FF:FF (широковещательный)
  • Волшебная полезная нагрузка пакета

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

  • MAC-адрес назначения: FF:FF:FF:FF:FF:FF (широковещательный)
  • UDP-порт: 9
  • Волшебная полезная нагрузка пакета

Magic Payload состоит из:

  • Поток синхронизации: 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, построенное на примере Example09, который можно найти в исходном коде SharpPcap.

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

using PacketDotNet;

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

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

using SharpPcap;

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

person Evan Plaice    schedule 10.11.2010

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

person ctacke    schedule 15.01.2009
comment
Я знаю, что WOL выполняется по MAC-адресу ... Моя проблема в том, что Windows отправляет широковещательные передачи UDP только на сетевой адаптер, который Windows считает основным сетевым адаптером. И я не могу найти способ привязать сокет к интерфейсу, у которого нет IP-адреса. (как это делают DHCP-клиенты) - person Tarnay Kálmán; 26.03.2009

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

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

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

person Rob Williams    schedule 15.01.2009
comment
Я нашел один :) (Мы разместили в то же время) - person Tarnay Kálmán; 15.01.2009