Как получить список MAC-адресов в ЛВС на C#?

439
23 марта 2017, 18:17

Мне нужно получить список MAC-адресов всех компьютеров в ЛВС. Как я могу это сделать? Думаю, что можно получить этот список у DHCP-сервера, но не могу понять, как это сделать.

Answer 1

Источник codeproject

Для получения используем код:

// Получить мой IP-адрес компьютера
Console.WriteLine("My IP : {0}", GetIPAddress());
// Получить мой MAC-адрес компьютера
Console.WriteLine("My MAC: {0}", GetMacAddress());
// Получить все устройства в сети
Dictionary<IPAddress, PhysicalAddress> all = GetAllDevicesOnLAN();
foreach (KeyValuePair<IPAddress, PhysicalAddress> kvp in all)
{
    Console.WriteLine("IP : {0}\n MAC {1}", kvp.Key, kvp.Value);
}

Для его работы следующие структуру и методы:

/// <summary>
/// MIB_IPNETROW cтруктура возвращаемая GetIpNetTable
/// НЕ ИЗМЕНЯЙТЕ ЭТУ СТРУКТУРУ.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
struct MIB_IPNETROW
{
    [MarshalAs(UnmanagedType.U4)]
    public int dwIndex;
    [MarshalAs(UnmanagedType.U4)]
    public int dwPhysAddrLen;
    [MarshalAs(UnmanagedType.U1)]
    public byte mac0;
    [MarshalAs(UnmanagedType.U1)]
    public byte mac1;
    [MarshalAs(UnmanagedType.U1)]
    public byte mac2;
    [MarshalAs(UnmanagedType.U1)]
    public byte mac3;
    [MarshalAs(UnmanagedType.U1)]
    public byte mac4;
    [MarshalAs(UnmanagedType.U1)]
    public byte mac5;
    [MarshalAs(UnmanagedType.U1)]
    public byte mac6;
    [MarshalAs(UnmanagedType.U1)]
    public byte mac7;
    [MarshalAs(UnmanagedType.U4)]
    public int dwAddr;
    [MarshalAs(UnmanagedType.U4)]
    public int dwType;
}
/// <summary>
/// GetIpNetTable Внешний метод
/// </summary>
/// <param name="pIpNetTable"></param>
/// <param name="pdwSize"></param>
/// <param name="bOrder"></param>
/// <returns></returns>
[DllImport("IpHlpApi.dll")]
[return: MarshalAs(UnmanagedType.U4)]
static extern int GetIpNetTable(IntPtr pIpNetTable,
      [MarshalAs(UnmanagedType.U4)] ref int pdwSize, bool bOrder);
/// <summary>
/// Коды ошибок GetIpNetTable возвращает, что мы распознаем
/// </summary>
const int ERROR_INSUFFICIENT_BUFFER = 122;
/// <summary>
/// Получить IP-адреса и MAC-адреса всех известных устройств в локальной сети.
/// </summary>
/// <remarks>
/// 1) Эта таблица не обновляется часто - выбор из неё ​​может занять некоторое время 
///    , чтобы выявить, что устройство пропало из сети или новое устройство было подключено. 
/// 2) Фильтрует не локальные устройства, если они найдены - это многоадресная рассылка
///    и могут быть исключены по диапазону IP-адресов.        
/// </remarks>
/// <returns></returns>
private static Dictionary<IPAddress, PhysicalAddress> GetAllDevicesOnLAN()
{
    Dictionary<IPAddress, PhysicalAddress> all = new Dictionary<IPAddress, PhysicalAddress>();
    // Добавляем этот компьютер в список ... 
    all.Add(GetIPAddress(), GetMacAddress());
    int spaceForNetTable = 0;
    // Получаем необходимое пространство     
    // Мы делаем это, запрашивая таблицу, но не указывая никакого пространства вообще.
    // Возвращаемое значение скажет нам, сколько нам действительно нужно.
    GetIpNetTable(IntPtr.Zero, ref spaceForNetTable, false);
    // Распределяем пространство     
    // Мы используем блок try-finally для обеспечения выполнения.
    IntPtr rawTable = IntPtr.Zero;
    try
    {
        rawTable = Marshal.AllocCoTaskMem(spaceForNetTable);
        // Получаем фактические данные
        int errorCode = GetIpNetTable(rawTable, ref spaceForNetTable, false);
        if (errorCode != 0)
        {
            // Сбой по какой-то причине - здесь больше ничего нельзя сделать.
            throw new Exception(string.Format(
              "Unable to retrieve network table. Error code {0}", errorCode));
        }
        // Получаем количество строк
        int rowsCount = Marshal.ReadInt32(rawTable);
        IntPtr currentBuffer = new IntPtr(rawTable.ToInt64() + Marshal.SizeOf(typeof(Int32)));
        // Конвертируем необработанную таблицу в отдельные записи
        MIB_IPNETROW[] rows = new MIB_IPNETROW[rowsCount];
        for (int index = 0; index < rowsCount; index++)
        {
            rows[index] = (MIB_IPNETROW)Marshal.PtrToStructure(new IntPtr(currentBuffer.ToInt64() +
                                        (index * Marshal.SizeOf(typeof(MIB_IPNETROW)))
                                       ),
                                        typeof(MIB_IPNETROW));
        }
        // Определяем список фиктивных записей (мы можем их отбросить)
        PhysicalAddress virtualMAC = new PhysicalAddress(new byte[] { 0, 0, 0, 0, 0, 0 });
        PhysicalAddress broadcastMAC = new PhysicalAddress(new byte[] { 255, 255, 255, 255, 255, 255 });
        foreach (MIB_IPNETROW row in rows)
        {
            IPAddress ip = new IPAddress(BitConverter.GetBytes(row.dwAddr));
            byte[] rawMAC = new byte[] { row.mac0, row.mac1, row.mac2, row.mac3, row.mac4, row.mac5 };
            PhysicalAddress pa = new PhysicalAddress(rawMAC);
            if (!pa.Equals(virtualMAC) && !pa.Equals(broadcastMAC) && !IsMulticast(ip))
            {
                //Console.WriteLine("IP: {0}\t\tMAC: {1}", ip.ToString(), pa.ToString());
                if (!all.ContainsKey(ip))
                {
                    all.Add(ip, pa);
                }
            }
        }
    }
    finally
    {
        // Освобождаем память
        Marshal.FreeCoTaskMem(rawTable);
    }
    return all;
}
/// <summary>
/// Получает IP-адрес текущего ПК
/// </summary>
/// <returns></returns>
private static IPAddress GetIPAddress()
{
    String strHostName = Dns.GetHostName();
    IPHostEntry ipEntry = Dns.GetHostEntry(strHostName);
    IPAddress[] addr = ipEntry.AddressList;
    foreach (IPAddress ip in addr)
    {
        if (!ip.IsIPv6LinkLocal)
        {
            return (ip);
        }
    }
    return addr.Length > 0 ? addr[0] : null;
}
/// <summary>
/// Получает MAC-адрес текущего ПК.
/// </summary>
/// <returns></returns>
private static PhysicalAddress GetMacAddress()
{
    foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
    {
        // Учитывть только сетевые интерфейсы Ethernet
        if (nic.NetworkInterfaceType == NetworkInterfaceType.Ethernet &&
            nic.OperationalStatus == OperationalStatus.Up)
        {
            return nic.GetPhysicalAddress();
        }
    }
    return null;
}
/// <summary>
/// Метод возвращает "истина", если указанный IP-адрес является адресом многоадресной рассылки
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
private static bool IsMulticast(IPAddress ip)
{
    bool result = true;
    if (!ip.IsIPv6Multicast)
    {
        byte highIP = ip.GetAddressBytes()[0];
        if (highIP < 224 || highIP > 239)
        {
            result = false;
        }
    }
    return result;
}
READ ALSO
&ldquo;Множественное наследование&rdquo; c#

“Множественное наследование” c#

Есть иерархия классов, появилась ситуация в которой не могу придумать нормального решения(стрелками показано наследование, красным цветом...

217
Логика взаимодействия окон и контекста MVVM

Логика взаимодействия окон и контекста MVVM

Допустим у меня есть унифицированное окошкоBasicDialogUI

236
Почему MemberInfo.GetCustomAttributes игнорирует наследование

Почему MemberInfo.GetCustomAttributes игнорирует наследование

Метод MemberInfoGetCustomAttributes получает список атрибутов члена типа

217
System.Data.SqlClient.SqlException не обработано

System.Data.SqlClient.SqlException не обработано

Есть программкаПри выполнении записи в базу данных вылетает ошибка:

533