基于ARP协议获取局域网内主机MAC地址

简介:

ARP帧数据结构

复制代码
#define BROADMAC        {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF} //广播MAC
#define EH_TYPE            0x0806                            //ARP类型
#define ARP_HRD            0X0001                            //硬件类型:以太网接口类型为        
#define ARP_PRO            0x0800                            //协议类型:IP协议类型为X0800
#define ARP_HLN            0x06                            //硬件地址长度:MAC地址长度为B
#define ARP_PLN            0x04                            //协议地址长度:IP地址长度为B
#define ARP_REQUEST        0x0001                            //操作:ARP请求为
#define ARP_REPLY        0x0002                            //操作:ARP应答为
#define ARP_THA            {0,0,0,0,0,0}                    //目的MAC地址:ARP请求中该字段没有意义,设为;ARP响应中为接收方的MAC地址
#define ARP_PAD            {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} //18字节的填充数据
#define SPECIAL            0x70707070                        //定义获得自己MAC地址的特殊源IP,.112.112.112
#define ETH_HRD_DEFAULT    {BROADMAC, {0,0,0,0,0,0}, htons(EH_TYPE)} //广播ARP包帧头
#define ARP_HRD_DEFAULT    {htons(ARP_HRD), htons(ARP_PRO), ARP_HLN, ARP_PLN, htons(ARP_REQUEST), {0,0,0,0,0,0}, 0, ARP_THA, 0, ARP_PAD}
#define IPTOSBUFFERS 12
#define WM_PACKET    WM_USER + 105    //用户自定义消息

struct ethernet_head
{// 物理帧帧头结构
    unsigned char dest_mac[6];                                    //目标主机MAC地址(6字节)
    unsigned char source_mac[6];                                //源端MAC地址(6字节)
    unsigned short eh_type;                                        //以太网类型(2字节)
};
struct arp_head
{//ARP数据帧
    unsigned short hardware_type;                                //硬件类型:以太网接口类型为
    unsigned short protocol_type;                                //协议类型:IP协议类型为X0800
    unsigned char add_len;                                        //硬件地址长度:MAC地址长度为B
    unsigned char pro_len;                                        //协议地址长度:IP地址长度为B
    unsigned short option;                                        //操作:ARP请求为,ARP应答为

    unsigned char sour_addr[6];                                    //源MAC地址:发送方的MAC地址
    unsigned long sour_ip;                                        //源IP地址:发送方的IP地址
    unsigned char dest_addr[6];                                    //目的MAC地址:ARP请求中该字段没有意义;ARP响应中为接收方的MAC地址
    unsigned long dest_ip;                                        //目的IP地址:ARP请求中为请求解析的IP地址;ARP响应中为接收方的IP地址
    unsigned char padding[18];
};

struct arp_packet                                        //最终arp包结构
{//物理帧结构
    ethernet_head eth;                                    //以太网头部
    arp_head arp;                                        //arp数据包头部
};
复制代码
获取本机的网络适配器

复制代码
    int i = 1;
    string strDev = "";
    m_Dev.AddString("经分析,本系统网络适配器列表如下:");
    pcap_if_t* alldevs = 0; 
    pcap_if_t* pDev = 0;
    pcap_addr_t* pAdr = 0;
    char errbuf[PCAP_ERRBUF_SIZE+1]; 
    if (pcap_findalldevs(&alldevs, errbuf) == -1)
    {// 获得设备列表
        MessageBox(errbuf, NULL, MB_OK | MB_ICONINFORMATION);// 若没有设备则弹出警告
        exit(1);
    } 
    for(pDev = alldevs; pDev; pDev = pDev->next)
    {// 遍历所有成员
        if (pDev->description)
        {
            strDev = char(i + 48);
            strDev += ". ";
            strDev += DelSpace(pDev->description);//去掉网卡描述过多的空格
            pAdr = pDev->addresses;//IP地址
            if (pAdr!=NULL)
            {        
                if (pAdr->addr->sa_family == AF_INET)
                {//pAdr->addr是否IP地址类型
                    strDev += " -> ";
                    strDev += IpToStr(((struct sockaddr_in *)pAdr->addr)->sin_addr.s_addr);
                    if(IpToStr(((struct sockaddr_in *)pAdr->addr)->sin_addr.s_addr)[0] != '0')
                    {
                        m_Dev_No = i;
                        UpdateData(FALSE);//传递变量值去界面
                    }
                    strDev += " & [";
                    strDev += IpToStr(((struct sockaddr_in *)pAdr->netmask)->sin_addr.s_addr);//子网掩码
                    strDev += "]";
                    GetDlgItem(IDC_GET_MAC)->EnableWindow(TRUE);//若网卡有IP地址,则使抓包按钮可用
                }
            }
            m_Dev.InsertString(i++, strDev.c_str());
        }
    }
    pcap_freealldevs(alldevs);//不再需要网络适配器列表, 释放
复制代码
  获取本机MAC地址

复制代码
unsigned char* BuildArpRequestPacket(unsigned char* source_mac, unsigned char* arp_sha, unsigned long chLocalIP, unsigned long arp_tpa, int PackSize)
{//封装ARP请求包
    static arp_packet arpPackStru;
    static const arp_packet arpDefaultPack= {ETH_HRD_DEFAULT,ARP_HRD_DEFAULT};
    memcpy(&arpPackStru,&arpDefaultPack,sizeof(arpDefaultPack));
    //填充源MAC地址
    memcpy(arpPackStru.eth.source_mac,source_mac,6);//源MAC
    memcpy(arpPackStru.arp.sour_addr,arp_sha,6);//源MAC
    arpPackStru.arp.sour_ip=chLocalIP;//源IP地址    
    arpPackStru.arp.dest_ip=arp_tpa;//目的IP地址
    return (unsigned char *)&arpPackStru;
}
unsigned char* GetSelfMac(char* pDevName, unsigned long chLocalIP)
{//获得本机MAC地址,pDevName为网卡名称,chLocalIP为本机IP地址
    pcap_t* pAdaptHandle;                                                
    char errbuf[PCAP_ERRBUF_SIZE + 1]; 
    //打开网卡适配器
    if((pAdaptHandle = pcap_open_live(pDevName, 60, 1, 100, errbuf)) == NULL)
    {    
        MessageBox(NULL, "无法打开适配器,可能与之不兼容!", "Note", MB_OK);
        return NULL;
    }
    struct pcap_pkthdr *header;//包头部
    const u_char *pkt_data;//包数据部
    int res;
    unsigned short arp_op;
    static unsigned char arp_sha[6];
    unsigned long arp_spa = 0;
    unsigned long arp_tpa = 0;
    unsigned char source_mac[6] = {0,0,0,0,0,0};
    unsigned char* arp_packet_for_self;
    arp_packet_for_self = BuildArpRequestPacket(source_mac, source_mac, SPECIAL, chLocalIP, 60);//把自己作为目的,构建一个广播ARP请求包,伪造请求来自.112.112.112
    while(!GetMacSignal)
    {
        pcap_sendpacket(pAdaptHandle, arp_packet_for_self, 60);//发送ARP请求包
        Sleep(10);                                        
        res = pcap_next_ex(pAdaptHandle, &header, &pkt_data);
        if(res == 0)
        {
            continue;
        }
        //物理帧头部占字节,然后是硬件类型,上层协议类型,硬件地址长度,IP地址长度,这四个占去字节,具体参看ARP帧的数据结构
        memcpy(&arp_op, pkt_data + 20, 2);//操作类型(请求或应答)
        memcpy(arp_sha, pkt_data + 22, 6);//源MAC
        memcpy(&arp_spa, pkt_data + 28, 4);//源IP    
        memcpy(&arp_tpa, pkt_data + 38, 4);//目标IP    
        
        if(arp_op == htons(ARP_REPLY) && arp_spa == chLocalIP && arp_tpa == SPECIAL)
        {//是本机
            GetMacSignal = 1;
            pcap_close(pAdaptHandle);
            return arp_sha;
        }
        Sleep(100);//若不成功再等ms再发,让网卡歇歇
    }
    pcap_close(pAdaptHandle);
    return arp_sha; 
}
复制代码
发送ARP请求线程

复制代码
void SendArpRequest(pcap_if_t* pDev, unsigned char* bLocalMac)
{//发送ARP请求
    pcap_addr_t* pAdr = 0;
    unsigned long chLocalIp = 0;//存放本地ip地址
    unsigned long arp_tpa = 0;
    unsigned long snd_tpa = 0;
    unsigned long nlNetMask = 0;
    int netsize = 0;
    const char* pDevName = strSelDeviceName.c_str();
    pcap_t* pAdaptHandle;
    char errbuf[PCAP_ERRBUF_SIZE + 1];
    //打开网卡适配器
    if((pAdaptHandle = pcap_open_live(pDev->name, 60, 0, 100, errbuf)) == NULL)
    {    
        MessageBox(NULL, "无法打开适配器,可能与之不兼容!", "Send", MB_OK);
        return;
    }
    unsigned char* arp_packet_for_req;
    arp_packet_for_req = BuildArpRequestPacket(bLocalMac, bLocalMac, chLocalIp, chLocalIp, 60);    //构造包
    unsigned long ulOldMask=0;
    for (pAdr = pDev->addresses; pAdr; pAdr = pAdr->next)
    {
        if (!nThreadSignal)
        {//判断线程是否应该中止
            break;
        }
        chLocalIp = ((struct sockaddr_in *)pAdr->addr)->sin_addr.s_addr;//得到本地ip
        if (!chLocalIp) 
        {
            continue;
        }
        nlNetMask = ((struct sockaddr_in *)(pAdr->netmask))->sin_addr.S_un.S_addr;//得到子网掩码
        if(ulOldMask==nlNetMask)
        {
            continue;
        }
        ulOldMask=nlNetMask;
        netsize = ~ntohl(nlNetMask);//子网大小
        arp_tpa = ntohl(chLocalIp & nlNetMask);//IP地址
        for (int i=0; i < netsize; i++)
        {
            if (!nThreadSignal) 
            {
                break;
            }
            arp_tpa++;
            snd_tpa = htonl(arp_tpa);
            memcpy(arp_packet_for_req + 38, &snd_tpa, 4);//目的IP在子网范围内按序增长    
            pcap_sendpacket(pAdaptHandle, arp_packet_for_req, 60);//发送ARP请求包
            Sleep(5);//休息一下再发ARP请求包
        }
    }
}
UINT StartArpScan(LPVOID mainClass)
{//发送ARP请求线程
    AfxGetApp()->m_pMainWnd->SendMessage(WM_PACKET, 0, 1);//开始发送ARP请求包
    SendArpRequest(pDevGlobalHandle, bLocalMac);                                    //对选中设备的所有绑定的IP网段进行ARP请求
    AfxGetApp()->m_pMainWnd->SendMessage(WM_PACKET, 0, 2);//全部ARP请求包发送完毕
    return 0;
}
复制代码
接收ARP响应线程

复制代码
UINT WaitForArpRepeatPacket(LPVOID mainClass)
{        
    pcap_t* pAdaptHandle;                                                        
    const char* pDevName = strSelDeviceName.c_str();
    char errbuf[PCAP_ERRBUF_SIZE + 1]; 
    //打开网卡适配器
    if((pAdaptHandle = pcap_open_live(pDevName, 60, 0, 100, errbuf)) == NULL)
    {    
        MessageBox(NULL, "无法打开适配器,可能与之不兼容!", "wait", MB_OK);
        return -1;
    }
    string ipWithMac;
    char* filter = "ether proto\\arp";
    bpf_program fcode;
    int res;
    unsigned short arp_op = 0;
    unsigned char arp_sha [6];
    unsigned long arp_spa = 0;
    struct pcap_pkthdr *header;
    const u_char *pkt_data;
    if (pcap_compile(pAdaptHandle, &fcode, filter, 1, (unsigned long)(0xFFFF0000)) < 0)
    {
        MessageBox(NULL,"过滤条件语法错误!", "wait", MB_OK);
        return -1;
    }
    //set the filter
    if (pcap_setfilter(pAdaptHandle, &fcode) < 0)
    {
        MessageBox(NULL,"适配器与过滤条件不兼容!", "wait", MB_OK);
        return -1;
    }
    while(1)
    {
        if (!nThreadSignal) 
        {
            break;
        }
        int i = 0;
        ipWithMac = "";
        res = pcap_next_ex(pAdaptHandle, &header, &pkt_data);
        if (!res)
        {
            continue;
        }
        memcpy(&arp_op, pkt_data + 20, 2);//包的操作类型
        memcpy(arp_sha, pkt_data + 22, 6);//源MAC地址
        memcpy(&arp_spa, pkt_data + 28, 4);//源IP地址
        ipWithMac += IpToStr(arp_spa);
        for (int j = strlen(IpToStr(arp_spa)); j < 16; j++)
        {
            ipWithMac += " ";
        }
        ipWithMac += "  --*->   ";
        ipWithMac += MacToStr(arp_sha);
        for (i = 6; i > 0; i--)
        {                                                
            if (arp_sha[i - 1] != bLocalMac[i - 1])
            {
                break;
            }
        }
        if(arp_op == htons(ARP_REPLY) && i)
        {
            AfxGetApp()->m_pMainWnd->SendMessage(WM_PACKET, WPARAM(&ipWithMac), 0);//通知主线程更新界面
        }
    }                        
    return 0;
}
复制代码
  主线程消息处理

复制代码
LRESULT CArpByWinpcapDlg::OnPacket(WPARAM wParam, LPARAM lParam)
{
    string* transPack = (string*)wParam;
    //处理捕获到的数据包
    if (lParam == 0)
    {
        m_Mac_list.AddString(transPack->c_str());
        m_count = "发现 ";
        char buffer[5];
        itoa(m_Mac_list.GetCount(), buffer, 10);    //将数量转化为进制字符串;
        m_count += buffer;
        m_count += "  台活动主机";
    }
    else if (lParam == 1)
    {
        m_sending = "正在发送ARP请求包!";
    }
    else if (lParam == 2)
    {
        if (nThreadSignal)
        {
            m_sending = "全部ARP请求包发送完毕!";    //判断是自行发送完毕还是用户终止的?
        };
    }
    UpdateData(FALSE);
    return 0;
}
复制代码


本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2009/01/04/1368466.html,如需转载请自行联系原作者
目录
相关文章
|
3月前
|
缓存 网络协议 安全
【网络工程师】<软考中级>解析协议ARP&路由协议RIP/OSPF/BGP
【1月更文挑战第27天】【网络工程师】<软考中级>解析协议ARP&路由协议RIP/OSPF/BGP
|
3月前
|
存储 缓存 网络协议
ARP协议:地址解析协议
ARP协议:地址解析协议
40 0
|
1月前
|
网络协议 数据格式
|
2月前
|
存储 缓存 网络协议
计算机网络:思科实验【2-MAC地址、IP地址、ARP协议及总线型以太网的特性】
计算机网络:思科实验【2-MAC地址、IP地址、ARP协议及总线型以太网的特性】
|
2月前
|
存储 缓存 网络协议
|
2月前
|
存储 缓存 网络协议
【网安 | 网络协议】ARP协议(地址解析协议)
【网安 | 网络协议】ARP协议(地址解析协议)
194 1
|
4月前
|
存储 缓存 网络协议
dpdk课程学习之练习笔记二(arp, udp协议api测试)
dpdk课程学习之练习笔记二(arp, udp协议api测试)
63 0
|
6月前
|
缓存 网络协议 网络架构
【计算机网络】第三章 数据链路层(MAC地址 IP地址 ARP协议)
【计算机网络】第三章 数据链路层(MAC地址 IP地址 ARP协议)
|
7月前
|
缓存 网络协议 Windows
网络协议与攻击模拟-03-ARP协议
网络协议与攻击模拟-03-ARP协议
78 0
|
3月前
|
网络协议 API 网络安全
用户态协议栈设计实现udp,arp与icmp协议
用户态协议栈设计实现udp,arp与icmp协议
61 1