Чтение ARP таблицы с использованием WinAPI

      Данный пример реализует программное получение ARP таблицы через вызов «Internet Protocol Helper (IP Helper) API». Данный протокол позволяет разработчику программного обеспечения получать и изменять конфигурацию сети для локального компьютера. В Microsoft Windows функционал данного протокола заключен в библиотеку «Iphlpapi.dll» которая взаимодействует со множеством других библиотек.
Для получения ARP таблицы в библиотеке присутствуют приведенные ниже методы.
  • GetIpNetTable();
  • CreateIpNetEntry();
  • DeleteIpNetEntry();
  • FlushIpNetTable();
  • CreateProxyArpEntry();
  • DeleteProxyArpEntry();
  • SendARP().
      Более подробную информацию по данным методам вы можете получить по следующему адресу http://msdn.microsoft.com.
Полный листинг получения ARP таблицы представлен ниже.
private void Form1_Load(object sender, EventArgs e)
{
    GetIpNetARPTable();
    dataGridView1.DataSource = dt;
}

//Объявляем таблицу
DataTable dt = null;      

//Определяем структуру MIB_IPNETROW.
[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;
}

//Объявляем функцию GetIpNetTable.
[DllImport("IpHlpApi.dll")]
[return: MarshalAs(UnmanagedType.U4)]
static extern int GetIpNetTable(
   IntPtr pIpNetTable,
   [MarshalAs(UnmanagedType.U4)]
 ref int pdwSize,
   bool bOrder);

[DllImport("IpHlpApi.dll", SetLastError = true,
                           CharSet = CharSet.Auto)]
internal static extern int FreeMibTable(IntPtr plpNetTable);

//Код ошибки если недостаточно места в буфере обмена.
const int ERROR_INSUFFICIENT_BUFFER = 122;

private void  GetIpNetARPTable()
{
    //Инициализируем новую таблицу
    dt = new DataTable();

    //Добавляем новые колонки
    dt.Columns.Add("Адрес в интернете");
    dt.Columns.Add("Физический адрес");           

    // The number of bytes needed.
    int bytesNeeded = 0;

    //Результат вызова API.
    int result = GetIpNetTable(IntPtr.Zero, ref bytesNeeded, false);
                
    if (result != ERROR_INSUFFICIENT_BUFFER)
    {
        //Создаем исключение
        throw new Win32Exception(result);
    }
                
    IntPtr buffer = IntPtr.Zero;
   
    try
    {
        //Выделение памяти
        buffer = Marshal.AllocCoTaskMem(bytesNeeded);

        // Make the call again. If it did not succeed, then
        // raise an error.
        result = GetIpNetTable(buffer, ref bytesNeeded, false);

        // If the result is not 0 (no error), then throw an exception.
        if (result != 0)
        {
            //Создаем исключение
            throw new Win32Exception(result);
        }

        // Now we have the buffer, we have to marshal it. We can read
        // the first 4 bytes to get the length of the buffer.
        int entries = Marshal.ReadInt32(buffer);

        // Increment the memory pointer by the size of the int.
        IntPtr currentBuffer = new IntPtr(buffer.ToInt64() +
           Marshal.SizeOf(typeof(int)));

        // Allocate an array of entries.
        MIB_IPNETROW[] table = new MIB_IPNETROW[entries];

        // Cycle through the entries.
        for (int index = 0; index < entries; index++)
        {
            // Call PtrToStructure, getting the structure information.
            table[index] = (MIB_IPNETROW)Marshal.PtrToStructure(new
             IntPtr(currentBuffer.ToInt64() + (index *
             Marshal.SizeOf(typeof(MIB_IPNETROW)))), typeof(MIB_IPNETROW));
        }


        for (int index = 0; index < entries; index++)
        {
            MIB_IPNETROW row = table[index];    

            //Получение IP адреса
            System.Net.IPAddress ip =
             new System.Net.IPAddress(BitConverter.GetBytes(table[index].dwAddr));                    

            //Собираем MAC адрес по кусочкам
            string MAC = row.mac0.ToString("X2") + '-' + row.mac1.ToString("X2") + '-' +
                row.mac2.ToString("X2") + '-' + row.mac3.ToString("X2") + '-' +
                row.mac4.ToString("X2") + '-' + row.mac5.ToString("X2");

            //Добавляем новую строку в таблицу
            dt.Rows.Add(new object[] { ip.ToString(), MAC}); 
        }
    }
    finally
    {
        // Release the memory.
        FreeMibTable(buffer);
    }            
}
Ниже приведен пример работы тестового проекта.

Ссылка для скачивания примера: Яндекс.Диск


2 комментария:

  1. А что делать с буфером обмена ? ведь он даст вставить

    ОтветитьУдалить
  2. Здравствуйте, посмотрите вот эту инструкцию: http://www.csharpcoderr.com/2014/06/digittextbox2.html

    ОтветитьУдалить

Большая просьба, не писать в комментариях всякую ерунду не по теме!