首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

Windows 網路編程:透過 SendARP 取得遠端主機 MAC 位址

     編輯:VC 教學

前言

在區域網路中,IP 位址屬於網路層 (Layer 3),MAC 位址屬於資料鏈路層 (Layer 2)。當我們只知道目標 IP,需取得其 MAC 位址時(如網路掃描、ARP 綁定、Wake-on-LAN),可利用 Windows IP Helper API 中的 SendARP 函式,發送 ARP 請求封包並解析回應。

核心 API:SendARP


#include 
#pragma comment(lib, "Iphlpapi.lib")

ULONG SendARP(
    IPAddr DestIP,      // 目標 IP 位址 (網路位元組序)
    IPAddr SrcIP,       // 來源 IP (通常為 0,由系統自動選擇)
    PULONG pMacAddr,    // 接收 MAC 位址的緩衝區 (至少 6 bytes)
    PULONG PhyAddrLen   // 輸入/輸出:緩衝區大小 / 實際 MAC 長度
);

回傳 NO_ERROR (0) 表示成功,否則為 Windows 錯誤碼。

完整範例程式:命令列掃描工具

支援掃描單一 IP 或連續 IP 範圍 (指定數量),輸出 IP、主機名、MAC 位址。


#include 
#include 
#include 
#include 

#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "Iphlpapi.lib")

void PrintUsage()
{
    printf("RmtMac v1.0 - Get remote MAC address via ARP\n");
    printf("Usage: RmtMac.exe  [Count]\n");
    printf("Example: RmtMac.exe 192.168.1.100\n");
    printf("         RmtMac.exe 192.168.1.1 10  (scan 10 consecutive IPs)\n");
}

int main(int argc, char* argv[])
{
    if (argc < 2 || argc > 3)
    {
        PrintUsage();
        return 1;
    }

    // 初始化 Winsock
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        fprintf(stderr, "WSAStartup failed: %d\n", GetLastError());
        return 1;
    }

    // 解析目標 IP
    ULONG targetIP = inet_addr(argv[1]);
    if (targetIP == INADDR_NONE)
    {
        fprintf(stderr, "Invalid IP address: %s\n", argv[1]);
        WSACleanup();
        return 1;
    }

    int count = (argc == 3) ? atoi(argv[2]) : 1;
    if (count <= 0) count = 1;

    // 逐一掃描
    for (int i = 0; i < count; ++i)
    {
        ULONG currentIP = htonl(ntohl(targetIP) + i); // 處理位元組序與遞增
        struct in_addr addr;
        addr.s_addr = currentIP;

        printf("IP: %-15s ", inet_ntoa(addr));

        // 1. 嘗試反向解析主機名
        struct hostent* host = gethostbyaddr((char*)¤tIP, 4, AF_INET);
        if (host)
            printf("Host: %-30s ", host->h_name);
        else
            printf("Host: (unknown) ");

        // 2. 發送 ARP 取得 MAC
        BYTE macAddr[6] = {0};
        ULONG macLen = 6;
        DWORD ret = SendARP(currentIP, 0, (PULONG)macAddr, &macLen);

        if (ret == NO_ERROR && macLen == 6)
        {
            printf("MAC: %02X-%02X-%02X-%02X-%02X-%02X\n",
                macAddr[0], macAddr[1], macAddr[2],
                macAddr[3], macAddr[4], macAddr[5]);
        }
        else
        {
            printf("MAC: (failed, error=%lu)\n", ret);
        }
    }

    WSACleanup();
    return 0;
}

關鍵技術細節解析

1. IP 位址位元組序處理

  • inet_addr 回傳「網路位元組序」(Big Endian) 的 ULONG。
  • IP 遞增需轉為「主機位元組序」(ntohl)、加 1 後再轉回 (htonl)。

2. ARP 快取機制與限制

  • SendARP 實際上會先查詢本機 ARP 快取,若無則發送 ARP Request 廣播。
  • 僅限同一子網路:跨路由器/閘道器無法直接取得 MAC,會得到閘道器的 MAC。
  • 目標主機必須開機且回應 ARP,防火牆可能封鎖 ICMP/ARP 導致失敗。

3. 錯誤碼常見對照

進階應用:掃描整個子網路

結合 GetAdaptersInfo 取得本機 IP/子網路遮罩,計算網段範圍,多執行緒並行呼叫 SendARP,可構建高效的網路掃描器。注意:大量 ARP 廣播可能觸發交換器安全機制 (如 Port Security),建議加入隨機延遲或限制併發數。

結語

SendARP 是 Windows 取得遠端 MAC 位址最直接的 API,無需手造原始封包。掌握其參數準備、位元組序轉換、錯誤處理,即可快速開發網路發現、資產管理、喚醒上電等實用工具。完整專案碼可依此範例擴充 GUI 介面、匯出 CSV、整合資料庫等功能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
錯誤碼常數名稱說明
0NO_ERROR成功
1168ERROR_NOT_FOUNDARP 快取無此 IP,且廣播無回應
87ERROR_INVALID_PARAMETER參數錯誤 (如緩衝區太小)
1753ERROR_NO_MORE_ITEMS無更多項目