TCP/IP researching之ARP协议浅析

以太网协议 | ARP协议详解-ARP报文结构解析 笔者在 FPGA 上用到以太网,记录以下知识点,同时分享给你,希望对你有帮助,文中有什么错误的地方,请批评指正。 目录 一、ARP协议在以太网中传输的帧结构如下图所示: 二、 数据包每个部分介绍: 三、ARP 请求抓包截图 一、ARP协议在以太网中传输的帧结构如下图所示: 二、 数据包每个部分介绍: 以太网目的地址(6Byte):当发送 ARP 请求时此处全... 阅读详情
 

在大学就一直想写一个局域网IP查看工具,用来查询一个局域网的以使用的IP地址。毕业一年多了,这个网络小工具也没能有时间写。当时由于水平有限未能完成,8月底正好有这个时间,于是花了一个星期的时间来做这件事,最后终于完成了。其间的一些体会写出来和大家分享。此文适合于对TCP/IP协议有所了解和具有一定编程基础的朋友。

 

非技术篇(关心技术的朋友直接跳过)

一、为什么要写这个东西?

大三下学期时宿舍楼通校园网了,大家是无比的兴奋,但是很快问题就来了。我所在的宿舍楼里,有6层,计算机多达400多台(可能还要多一些),而只分配了一个C类IP段,254个IP地址,网关占一个,所以IP争夺是无法避免了。大家的苦恼都来源于此,而故事就此开始了。

笔者看过一些网络方面的书,所以知道一些做法。第一个办法是很早起来占住一个IP(晚上熄灯)。那么之后的人要面对的问题是:你可以改动IP设置,但是你并不知道那些IP没有被其他机器使用。Window2000可以动态该IP地址,无需重启,WinXP更强,修复一下可以恢复过来。当然要手工操作,有时候你突然死机在重启,IP就不再属于你了!哈哈,你就晕吧!

当然可以通过别的方式来查看这个情况Ping命令是一个,还有一些类似的工具。Ping命令不太可靠,一个一个的Ping,很浪费时间,没有时效性。而且后来天网防火墙等软件可以设置不响应。所以这个办法行不通了,看着别人上网,自己设置一个IP冲突一个,真是郁闷。要是有个东西可以准确的查看局域网的IP使用情况该多好啊!当时在网上搜索了很久,发现了一个基于UDP协议的查看IP的程序,还有源代码。效果改观了很多,它使用一个独立的线程发送,利用socket接受,缺憾是天网可以屏蔽它。当时开始思考这个问题,每台机器的唯一不变的是网卡的物理地址即Mac地址,局域网到底是用什么机制来实现IP地址到Mac的映射了,这可是通信的基本的问题!因为对网络协议感兴趣的原因,后来查阅很多种资料,包括RFC的英文文档,用代理在国外的找的,该文档介绍各种于网络相关的标准,有各种协议的规范。我知道了一些ARP(Address Resolution Protocol,地址解析协议)的知识,后面介绍这个协议。

不多久,真的出现了这么一个小软件。据说是这栋楼的一个VC高手写的,看到这个东西的只需要输入一个查询范围如202.4.151.1-202.4.151.254它就会快速的查询IP地址的使用情况。当时看不到源代码,佩服了半天。有一点可以肯定,它使用的是ARP协议,用到了多线程。当时仅仅是知道一些网络协议,没有编过Winsock方面的程序,多线程也很弱。所以写不出来,但当时就想,以后有机会要写一个类似的小工具。

 

二、作手准备

时光飞逝,之后考程序员,做毕业设计,工作,再换工作…从机械设计回到软件开发。加班,学习,学习,加班…日子过得真快。后来终于又休息了。《深入浅出MFC》《Windows核心编程》《Windows网络编程技术》看了很长时间了,渐渐的领悟了一些东西,多线程也熟悉了不少。特别是有个项目涉及到了UDP多点传输,当时把Socket深入的看了一些,调试了几个这个示例程序,对这个Socket模型熟悉起来。感觉有足够的知识来写这个东西了。

但我还没有想到具体的思路,于是到网上搜索(在前人的基础上有所超越,而不是作重复的事情),找到了几篇关于ARP的文章,下面的引用到的两篇是其中的。同时也开始接触row socket(原始套接字),研究sniffer(嗅探器)。当时考虑到,Ping的时候,如果不知道相应的IP地址的MAC地址该如何处理,只能回到ARP协议,对了上层协议必须建立在下层协议的基础上工作! Row socket虽然原始,却只能到网络层,而ARP协议在链路层工作,因为在网线或设备识别的只能是MAC地址,同时它不是物理层。此时正好在看Winpcap包帮助文档,它里面已经封装了对设备的操作,它可以直接发送链路层的包。用它可以发送所有的上层的包,而网络协议本身最后传送的包,最后都会包装层底层包。说白了,只要你了解了各种包格式,你就可以实现ISO/OSI的各个协议层的功能!OK,这个东西能够满足要求,Winpcap也了解不少了,可以动手了。

 

三、编码

Winpcap的使用请参考帮助文档,Web格式的,没有索引(MSDN有)。内容不多,知识却不少。笔者也没有彻底研究,涉及到的代码,有较为详细的注释。首先参考了《手把手教你玩转ARP包》,作者提供了详细的代码,讲的也很详细,于是没有花多少时间就看明白了。但是作者的工程是用VS2003写的,但没有说在哪个Window版本上通过,估计上Win2000,转换到VC6的工程后,在WinXP上却没有出现提到的arp缓冲条目增加的情况。这个问题困扰了两天,最后发现之前下载的文章《详谈调用winpcap驱动写arp多功能工具》有收发arp包的功能。离我的需要很近了。该代码是console工程,必须改造成MFC App。这倒不是很难。简单的设计了界面,具体实现的时候有些问题费了些时间。前后用了一个星期,没有自己的电脑进度慢了很多。

以上算是心得,具体程序的实现在技术篇细细道来。好吧,技术篇!!

言归正传,书回正题!

 

技术篇

一 ARP协议介绍

原理方面的内容整理出自《手把手教你玩转ARP包》

工作原理

以太网设备比如网卡都有自己全球唯一的MAC地址,它们是以MAC地址来传输以太网数据包的,它们不可能识别IP包中的IP地址,实际上网卡把受到的包提交到协议栈的缓冲,成为链路层包,再分离出IP层的包,再分离出TCP或UDP…。就像剥开竹笋,发送包则是相反的过程。

我们在以太网中进行IP通信的时候需要一个协议来建立IP地址与MAC地址的对应关系,以使IP数据包能发到一个确定的地方去。这就是ARP(Address Resolution Protocol,地址解析协议)。

讲到此处,我们可以在命令行窗口中,输入

     arp –a

来看一下效果,类似于这样的条目

210.118.45.100    00-0b -5f -e6-c5-d7    dynamic

就是我们电脑里存储的关于IP地址与MAC地址的对应关系,dynamic表示是临时存储在ARP缓存中的条目,过一段时间就会超时被删除(具体时间不同操作系统不同)。

这样一来,比如我们的电脑要和一台机器比如210.118.45.1通信的时候,它会首先去检查arp缓存,查找是否有对应的arp条目,如果没有,它就会给这个以太网络发ARP请求包广播询问210.118.45.1的对应MAC地址,当然,网络中每台电脑都会收到这个请求包,但是它们发现210.118.45.1并非自己,就不会做出相应,而210.118.45.1就会给我们的电脑回复一个ARP应答包,告诉我们它的MAC地址是xx-xx-xx-xx-xx-xx,于是我们电脑的ARP缓存就会相应刷新,多了这么一条:

210.118.45.1   xx-xx-xx-xx-xx-xx   dynamic

为什么要有这么一个ARP缓存呢,试想一下如果没有缓存,我们每发一个IP包都要发个广播查询地址,岂不是又浪费带宽又浪费资源?

      我们的网络设备无法识别ARP包的真伪,而且也不能识别,基本的约定都是假的,会带来灾难。如果我们按照ARP的格式来发送数据包,只要信息有效计算机就会根据包中的内容做相应的反应。

       这也是以太网可靠通信的基础,但是如果我能操纵网卡设备发送数据和掌握包的格式,我可以做一些欺骗和捣乱。当然,笔者只是理论分析,并不提倡读者这么做。

 

ARP包的格式

一个ARP包是分为两个部分的,前面一个是物理帧头或EtherHeader,后面一个才是ARP帧或Arp-Frame。

       首先,物理帧头,它将存在于任何一个协议数据包的前面,我们称之为DLC Header,因为这个帧头是在数据链路层构造的,并且其主要内容为收发双方的物理地址,以便硬件设备识别。

DLC Header

字段

长度(Byte)

默认值

备注

接收方MAC

6

 

广播时,为 ff-ff-ff-ff-ff-ff

发送方MAC

6

 

 

Ethertype

2

0x0806

0x0806是ARP帧的类型值

 

图1 物理帧头格式

 

     图1是需要我们填充的物理帧头的格式,我们可以看到需要我们填充的仅仅是发送端和接收端的物理地址罢了,是不是很简单呢?

       接下来我们看一下ARP帧的格式.

ARP Frame

字段

长度(Byte)

默认值

备注

硬件类型

2

0x1

以太网类型值

上层协议类型

2

0x0800

上层协议为IP协议

MAC地址长度

1

0x6

以太网MAC地址长度为6

IP地址长度

1

0x4

IP地址长度为4

操作码

2

 

0x1表示ARP请求包,0x2表示应答包

发送方MAC

6

 

 

发送方IP

4

 

 

接受方MAC

6

 

 

接受方IP

4

 

 

填充数据

18

 

因为物理帧最小长度为64字节,前面的42字节再加上4个CRC校验字节,还差18个字节

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

我们可以看到需要我们填充的同样也只是MAC, IP, 再加上一个1或2的操作码而已。

 

ARP包的填充

1) 请求包的填充:

    比如我们的电脑MAC地址为 aa-aa-aa-aa-aa-aa,IP为 192.168.0.1

我们想要查询 192.168.0.99的MAC地址,应该怎么来做呢?

首先填充DLC Header,通过前面的学习我们知道,想要知道某个计算机对应的MAC地址是要给全网发送广播的,所以接收方MAC肯定是 ffffffffffff,发送方MAC当然是自己啦,于是我们的DLC Header就填充完成了,如图,加粗的是我们要手动输入的值(当然我编的程序比较智能,会根据你选择的ARP包类型帮你自动填入一些字段,你一用便知^_^)。

DLC Header

字段

长度(Byte)

填充值

接收方MAC

6

Ffffffffffff

发送方MAC

6

Aaaaaaaaaaaa

Ethertype

2

0x0806

 

 

 

 

 

 

 

 

图3 ARP请求包中 DLC Header内容

 

接下来是ARP帧,请求包的操作码当然是 1,发送方的MAC以及IP当然填入我们自己的。然后要注意一下,这里的接收方IP填入我们要查询的那个IP地址,就是192.168.0.99了,而收方MAC填入任意值就行,不起作用,于是,如图,

ARP Frame

字段

长度(Byte)

填充值

硬件类型

2

1

上层协议类型

2

0x0800

MAC地址长度

1

6

IP地址长度

1

4

操作码

2

1

发送方MAC

6

Aaaaaaaaaaaa

发送方IP

4

192.168.0.1

接收方MAC

6

任意值 xxxxxxxxxxxx

接收方IP

4

192.168.0.99

填充数据

18

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

图4 ARP请求包中 ARP帧的内容

如果我们构造一个这样的包发送出去,如果 192.168.0.99存在且是活动的,我们马上就会收到一个192.168.0.99发来的一个响应包,我们可以查看一下我们的ARP缓存列表,是不是多了一项类似这样的条目:

192.168.0.99                  bb-bb-bb-bb-bb-bb

是不是很神奇呢?我们再来看一下ARP响应包的构造:

 

响应包的填充

     有了前面详细的解说,你肯定就能自己说出响应包的填充方法来了吧,所以我就不细说了,列两个表就好了

     比如说给 192.168.0.99(MAC为 bb-bb-bb-bb-bb-bb)发一个ARP响应包,告诉它我们的MAC地址为 aa-aa-aa-aa-aa-aa,就是如此来填充各个字段

 

DLC Header

字段

长度(Byte)

填充值

接收方MAC

6

Bbbbbbbbbbbb

发送方MAC

6

Aaaaaaaaaaaa

Ethertype

2

0x0806

 

图5 ARP响应包中 DLC Header内容

 

ARP Frame

字段

长度(Byte)

填充值

硬件类型

2

1

上层协议类型

2

0800

MAC地址长度

1

6

IP地址长度

1

4

操作码

2

2

发送方MAC

6

Aaaaaaaaaaaa

发送方IP

4

192.168.0.1

接收方MAC

6

Bbbbbbbbbbbb

接收方IP

4

192.168.0.99

填充数据

18

0

          图6 ARP响应包中 ARP帧的内容

这样192.168.0.99的ARP缓存中就会多了一条关于我们192.168.0.1的地址映射。

好接下来是编程实现了:

 

二、编程的具体实现

通过分析发现以下几条是必须实现的,然后每一个功能近可能的封装在一个函数里面。

1 网卡的枚举,设置和缓冲区分配;

2 填充和发送一个ARP包;

3 监听线程(Sniffer);

4 解析ARP包;

5 获得本机IP MAC地址;

6 发送线程和接受线程的协调;

至于如何显示IP和MAC信息,比较简单请参考源码。

 

为了更方便的调用winpcap库函数,笔者封装了一个CWinPcap类。代码的几个关键之处说明一下,请参考所附源代码:

1网卡的枚举,设置和缓冲区分配

// success return 0

int CWinPcap::OpenPcap()

{

       WCHAR buf[1024];

       ULONG bufsize;

       int res, i = 0;

 

       memset ((void*)adapterlist, 0, sizeof(adapterlist));

       res = PacketGetAdapterNames ((char*)buf, &bufsize); // 枚举网卡

       if (res == 0)

       {

              return -1;

       }

       WCHAR *p1, *p2;

       p1 = p2 = buf;

 

       while ((*p1 != '/0') || (*(p1 - 1) != '/0'))

       {

              if (*p1 == '/0')

              {

                     memcpy (adapterlist[i], p2, 2 * (p1 - p2));

                     p2 = p1 + 1;

                     i++;

              }

              p1++;

       }

 

       m_iAdapterNum = i;

       m_iSelAdapter = i - 1;

 

       // 打开最后一个网卡,PC机一般是一个网卡

       m_lpAdapter = PacketOpenAdapter( ((char *)adapterlist + m_iSelAdapter * 1024) );

       if (m_lpAdapter == NULL || (m_lpAdapter->hFile == INVALID_HANDLE_VALUE))

       {

              return -1;

       }

 

       // 分配sender包空间

       m_lpPacketSender = PacketAllocatePacket();

       if (m_lpPacketSender == NULL)

              return -1;

 

       return 0;

}

 

2 如何填充和发送一个ARP包

首先是包的分组格式定义

// Ether(DLC) header

typedef struct ethdr

{

    unsigned char   eh_dst[6];   // 以太网目的MAC地址

    unsigned char   eh_src[6];  // 以太网源MAC地址

    unsigned short  eh_type;      // 帧类型

}ETHDR,*PETHDR;

 

// ARP分组格式

typedef struct arphdr

{

    unsigned short  arp_hdr;      // 硬件类型

    unsigned short  arp_pro;      // 协议类型

    unsigned char   arp_hln;      // 硬件地址长度

    unsigned char   arp_pln;      // 协议地址长度

    unsigned short  arp_opt;      // ARP/RARP

    unsigned char   arp_sha[6]; // 发送者地址

    unsigned long   arp_spa;     // 发送者IP地址

    unsigned char   arp_tha[6]; // 接受者地址

    unsigned long   arp_tpa;      // 接受者IP地址

}ARPHDR,*PARPHDR;

接着是填充和发送一个ARP请求包

/********************************************************************

功能       供发送线程调用,发送一个arp请求包

 

参数

       ipCur      目标IP地址

       ipMine     本机IP地址

       mac[]      网卡MAC地址                                                     

********************************************************************/

int CWinPcap::Sender(ULONG ipCur, ULONG ipMine, BYTE mac[])

{

       char pBufSend[1024];

       ETHDR   eth;

       ARPHDR arp;

 

       // Fill the ARP request packets.

       int i;

       for (i = 0; i < 6; i++)

       {

              eth.eh_dst[i] = 0xff;

              arp.arp_tha[i] = 0x00;

       }

 

       // {填充DLC头和ARP头

       eth.eh_type     = htons(ETH_ARP);

       memcpy(eth.eh_src, mac, 6);

      

       arp.arp_hdr     = htons(ARP_HARDWARE);

       arp.arp_pro     = htons(ETH_IP);

       arp.arp_hln     = 6;

       arp.arp_pln     = 4;

       arp.arp_opt     = htons(ARP_REQUEST);

      

       memcpy(arp.arp_sha, mac, 6);

       arp.arp_spa     = htonl(ipMine);

       arp.arp_tpa = htonl(ipCur);

       // }

      

       memset(pBufSend, 0, sizeof(pBufSend));

       memcpy(pBufSend, ð, sizeof(eth));

       // 装配完整arp包

       memcpy(pBufSend + sizeof(eth), &arp, sizeof(arp));

      

       PacketInitPacket(m_lpPacketSender, pBufSend, sizeof(eth) + sizeof(arp));

       if(PacketSendPacket(m_lpAdapter, m_lpPacketSender,TRUE)==FALSE)

       {

              return -1;

       }

 

       return 0;

}

 

3监听线程(Sniffer);

线程函数体实际执行的函数:

int CWinPcap::Sniff()

{

       static CIPFluxDlg *pdlg = (CIPFluxDlg *)AfxGetMainWnd();

    char recvbuf[1024*250];

       DWORD res = 0;

      

       // {初始化网卡,设置为混合模式NDIS_PACKET_TYPE_PROMISCUOUS

    if(PacketSetHwFilter(m_lpAdapter, NDIS_PACKET_TYPE_PROMISCUOUS)==FALSE)

    {

        //printf("Warning: Unable to set the adapter to promiscuous mode/n");

    }

      

    if(PacketSetBuff(m_lpAdapter, 500*1024)==FALSE)

    {

        //printf("PacketSetBuff Error: %d/n",GetLastError());

        return -1;

    }

      

    if(PacketSetReadTimeout(m_lpAdapter, 1)==FALSE)

    {

        //printf("Warning: Unable to set the timeout/n");

    }

      

    if((m_lpPacketReceiver=PacketAllocatePacket())==FALSE)

    {

        //printf("PacketAllocatePacket receive Error: %d/n",GetLastError());

        return -1;

    }

      

    PacketInitPacket(m_lpPacketReceiver, (char *)recvbuf, sizeof(recvbuf));

       // }

 

       // {接受包

       do

       {

              if(PacketReceivePacket(m_lpAdapter, m_lpPacketReceiver, TRUE) == FALSE)

              {

                     if(GetLastError() == 6)

                            return 0;

                     return -1;

              }

              GetData (m_lpPacketReceiver); // 解析包的内容

              if (pdlg->m_bStop == TRUE)

                     break;

       }while (1);

       // }

       ResetEvent(pdlg->m_hEvent); // 辅助函数

 

       return 0;

}

 

4 解析ARP响应包

/********************************************************************

功能      从接受到的包中提取和解析出ARP包个字段

 

参数     

       lp    网卡接受到的包的缓冲区指针

********************************************************************/

void CWinPcap::GetData(LPPACKET lp)

{

       ULONG ulOffset = 0, ulBytesReceived;

       char *buf = NULL;

       char *pChar, *pBase;

       struct bpf_hdr *phdr = NULL;

       struct sockaddr_in sin;

       ETHDR   *pEther;

       ARPHDR *pArp;

       //IPHDR  *pIphdr;

       CString strIP, strMAC;

 

       static CIPFluxDlg *pdlg = (CIPFluxDlg *)AfxGetMainWnd();

      

       buf = (char*)lp->Buffer;

       ulBytesReceived = lp->ulBytesReceived;

 

       while (ulOffset < ulBytesReceived)

       {

              phdr = (struct bpf_hdr *)(buf + ulOffset);

              ulOffset += phdr->bh_hdrlen;

 

              pChar = (char *)(buf + ulOffset);

        pBase = pChar;

        ulOffset = Packet_WORDALIGN(ulOffset + phdr->bh_caplen);

             

        pEther     = (PETHDR)pChar;               

        pArp       = (PARPHDR)(pChar + sizeof(ETHDR));

             

              // receive ARP reply packets which contain IP address and relative MAC address

              // 受到arp响应包,包含IP地址和相关的MAC地址

              if (pEther->eh_type == htons(ETH_ARP) && pArp->arp_opt == htons(ARP_REPLY))

              {

                     sin.sin_addr.s_addr = pArp->arp_spa;

                     strIP.Format("%-16s", inet_ntoa(sin.sin_addr));

                     CString str;

 

                     str.Format("%02X", pEther->eh_src[0]);

                     strMAC = str;

                     for (int i = 1; i < 6; i++)

                     {

                            str.Format ("-%02X", pEther->eh_src[i]);

                            strMAC += str;

                     }

                     pdlg->ShowSearch(strIP, strMAC);

                     SetEvent(pdlg->m_hEvent);

              }

       }

}

 

5 获得本机IP地址和MAC地址

工程中没有采取Winpcap函数来获得MAC地址,而是采用非常有用的iphelp库函数DWORD

WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen);

/************************************************************************

功能       获得本机网卡的IP地址,物理地址,涉及到

 

参数      

       sin          IP地址

       strMAC   MAC地址16进制表达

       mac[]      MAC地址字节表达

************************************************************************/

void CWinPcap::GetNetInfo(sockaddr_in &sin, CString &strMAC, BYTE mac[])

{

       PIP_ADAPTER_INFO pAdapterInfo = NULL;

       char ch;

       long sizeinfo;

       ULONG size = 0;

       int res = 0;

 

       sizeinfo = sizeof(m_netinfo);

       if (m_lpAdapter)

       {

              // 先获得ip地址

              res = PacketGetNetInfoEx (adapterlist[m_iSelAdapter], &m_netinfo, &sizeinfo);

              if (res)

              {

                     sin = *(struct sockaddr_in *)&m_netinfo.IPAddress;

              }

              else

              {

                     strMAC = "FF-FF-FF-FF-FF-FF";

              }

              // 试图获得AdapterInfo,size返回需要的缓冲区的大小

              res = GetAdaptersInfo ((PIP_ADAPTER_INFO)&ch, &size);

              if (res == ERROR_BUFFER_OVERFLOW)

              {

                     pAdapterInfo = (PIP_ADAPTER_INFO)malloc (sizeof(IP_ADAPTER_INFO));

                     res = GetAdaptersInfo(pAdapterInfo, &size);

                     if (res == 0)

                     {

                            CString str;

                            BYTE *pch = pAdapterInfo->Address; // 导出mac地址16进制表达

                            memcpy (mac, pch, 6);

                            for (int i = 0; i < 6; i++)

                            {

                                   if (i)

                                          strMAC += "-";

                                   str.Format("%02X", *(pch + i));

                                   strMAC += str;

                            }

                     }

                     free (pAdapterInfo);

              }

       }

}

 

6 发送线程和接受线程的协调

只是简单的多个发送线程,一个监听线程。还没有涉及同步问题。

void CIPFluxDlg::OnBtnStart()

{

       int nTotal = 0;

       ULONG ipFirst, ipLast;

       ULONG ulStartIP = 0;

       m_bStop = FALSE;

       static BOOL bInit = FALSE;

 

       m_IPFirst.GetAddress(ipFirst);

       m_IPLast.GetAddress(ipLast);

       nTotal = ipLast - ipFirst + 1;

       m_lstIP.DeleteAllItems();

 

       GetDlgItem (IDC_BTN_START)->EnableWindow (FALSE);

      

       // 生成一次监听线程

       if (bInit == FALSE)

       {

              m_hSniffer = AfxBeginThread(_tFuncReceiver, (void*)this);

              bInit = TRUE;

       }

       Sleep (300);

 

       m_IPFirst.GetAddress(ulStartIP);

 

       for (int i = 0; i < nTotal; i++)

       {

              m_ipCur = ulStartIP + i;

              m_hSender = AfxBeginThread(_tFuncSender, (void*)this);

 

              // 等待上一个线程结束

              WaitForSingleObject (m_hSender, INFINITE);

       }

       m_bStop = TRUE;

       GetDlgItem (IDC_BTN_START)->EnableWindow (TRUE);

}

 

四、总结

以上代码思路清晰,代码注释较为详细,列出的代码已过六成,工程也并不大。编程水平高的读者甚至可以很快实现类似的程序!当然还有些不足如:不能严格的发送一个请求ARP包收到后立刻解析显示出来,再发送下一个,而是差不多全部发送完毕后,才显示出来。而是release模式有未处理异常,多线程的异常处理还需要深入了解。

WinXP/VC6.0编译通过,WinXP和Win2000下正常运行。

附加说明:

ARP原理说明引用了《手把手教你玩转ARP包》的部分是为了阅读的方便,本文与另外两篇文章侧重不同,读者可自行比较。关于ARP的问题欢迎读者来讨论。

关于Winpcap如何使用,和编译的问题就不再讨论了。请仔细查看Winpcap开发包帮助,引用的两篇文章。

 

后记:

从协议原理到代码实现,从Row socket到Winpcap…只要你理解了其中的规律你就可以写出一些类似的实用工具来。希望读者能有所收获!

 

参考文章、资料:

《手把手教你玩转ARP包》

http://blog.youkuaiyun.com/PiggyXP/- PiggyXP- 5/31/2004 11:40:00 AM系列文章

 

《TCP-IP详解卷1:协议ARP章节,卷2:021.pdf》

 

《详谈调用winpcap驱动写arp多功能工具》

{

Author: TOo2y[原创]

E-mail: TOo2y@safechina.net

Homepage: http://www.safechina.net/

Date: 11-9-2002

}

IPv6头部 一、IPv6数据包的结构 IPv6报文 分为三个部分:头部、扩展头、上层协议数据单元。 IPv4报文:头部、上层协议数据单元 IPv6头部始终存在,大小固定40字节。 扩展头可能有0个或多个,且长度不固定。 二、IPv6头部 1.结构 2.域 Payload Length负载长度:最长65535字节,包含扩展头和上层协议PDU。 Next Header: 三、IPv6扩展头 排序: Hop-by-Hop Options header逐跳选项头 Destination Options head 阅读详情

相关推荐

网络帧格式,ARP,IP,TCP,UDP帧格式

三速以太网,网络帧格式,ARP,IP,TCP,UDP帧格式

TCP,UDP完整数据包校验和通用计算

ICMP,IP,UDP,TCP报头部分都有checksum(检验和)字段。ICMP和IP报头校验和的计算都很简单,使用RFC1071中给出的方法即可完成(如下)。 //计算校验和USHORT checksum(USHORT *buffer,int size){ unsigned long cksum=0; while(size>1) {  cksum+=*buffer++;  size-=

lgb571的专栏 3818

通达信短周期指标盘中实时监控与预警选股实战

本文详细介绍了通达信短周期指标在盘中实时监控与预警选股中的实战应用。通过分时指标改造、多股同列监控技巧及预警策略优化,帮助短线交易者捕捉转瞬即逝的交易机会,提升选股效率与准确性。重点解析了如何避免假信号干扰及系统卡顿问题,并探讨了从预警到自动交易的进阶应用。

weixin_29230805的博客 889

交换机开发(四)—— ARP 基础知识解析

一、ARP协议简介       Internet是由各种各样的物理网络通过使用诸如路由器之类的设备连接在一起组成的。当主机发送一个数据包到另一台主机的过程中 可能要经过多种不同的物理网络。主机和路由器都是在网络层通过IP地址来识别的,这个地址是在全世界内唯一的。 然而,数据包是通过物理网络传递的。在物理网络中,主机和路由器通过其MAC地址来识别的,其范围限于本地网络中。 MAC地址和IP地址是两

知秋一叶 8426

openvpn 安装 (Alibaba Cloud Linux release 3 (Soaring Falcon))

1.错误:configure: error: libnl-genl-3.0 package not found or too old. Is the development package and pkg-config (/usr/bin/pkg-config) installed?# ta.key在/etc/openvpn/server/目录下可以如下配置,否则需要写完整路径。# 配置账号密码登录客户端需要ca证书(可选)# 证书校验算法 配置上面生成的完整路径。# ca证书 配置上面生成的完整路径。

dubhe_zhao的博客 2148

使用LogisticRegression和LightGBM模型对信贷违约进行预测----基于kaggle比赛数据

3.分离数值型变量与类别型变量,发现有些数值型变量因为输入不规范,比如数值中含有字符(28_,_10000_等)被划分为类别型变量 ,比如 'Age','Annual_Income','Num_of_Loan', 'Num_of_Delayed_Payment', 'Changed_Credit_Limit','Credit_Mix','Monthly_Balance', 'Outstanding_Debt' ,'Amount_invested_monthly'等。三、分箱,woe编码,计算IV值。

I_am_a_big_tiger的博客 1682

2014计算机三级网络,2014计算机三级网络技术综合题解题思路

第三小题DHCP报文解析1.DHCP获取IP地址的过程:2.DLC:-----DLC Header-------DLC:Destination =001234567890 目的地址的MACDLC:Source = 001122334455 源地址的MACIP:D=1192.168.0.100 ,S=192.168.0.1 D目的地址S源地址UDP:D=68,S=67 采用UDP协议3.IP:——I...

weixin_42314448的博客 690

【侯俊霞全网最全收集--PLC1200/200SMART(88+93课时) 第1章】

第1章:零基础快速入门西门子S7-1200

问就ycy的博客 2033

手把手教你玩转ARP包(二)【数据包的游戏系列之一】

  作者:   优快云  VC/MFC 网络编程 PiggyXP  ^_^   目录:     一.    关于ARP协议的基础知识     3. ARP包的填充二。发送数据包的编程实现   1.填充数据包 .........................紧接上文............................ 3.ARP包的填充1) 请

小猪的网络编程 1万+

IEDA激活码失效?教你5分钟快速续期的方法

本文针对IEDA激活码失效问题,提供了一套从快速应急到深度排查的完整解决方案。文章不仅详解了5分钟快速续期与清理缓存等应急方法,更深入剖析了授权机制、离线激活流程,并指导如何构建可持续的授权管理策略,帮助开发者彻底解决激活困扰,确保开发环境稳定。

a0b1c2d3的专栏 273

OpenSpec 从入门到精通:AI 时代的最佳 SDD 范式

同样都是「先写规范再写代码」的开源 SDD 框架,OpenSpec(https://github.com/fission-ai/openspec) 展现出了极高的工程性价比,无论是使用 Claude Code、Cursor 还是 Aider,都可以无缝接入 OpenSpec 的规格管理层。这些问题需要人来做判断,AI 做不了这个主。整个流程跑下来,OpenSpec 产出的效果还是令人满意的,一些前期没有考虑到的细节 AI 都补上了,生成的相关文档也有利于开发人员的知识对齐,可以尝试在团队内部推广。

qq_39093474的博客 925

ARP数据包

一.             关于ARP协议的基础知识 1.ARP的工作原理             我们都知道以太网设备比如网卡都有自己全球唯一的MAC地址,它们是以MAC地址来传输以太网数据包的,但是它们却识别不了我们IP包中的IP地址,所以我们在以太网中进行IP通信的时候就需要一个协议来建立IP地址与MAC地址的对应关系,以使IP数据包能发到一个确定的地方去。这就是ARP(Addre

Skylar 2443

ABB变频器使用PROFINET IO通信模块时的激活方法

ABB变频器使用PROFINET IO通信模块时的激活方法

Robot_PLC_HMI_Automation 2732

学习笔记——C++实现ARP欺骗

以下代码大体上是没有问题的,可以根据自己的一些需求进行修改! 谢谢指正错误 在课设期间,从网上学习了简单的实现ARP欺骗 ARP欺骗的原理很简单:通过不断的向目标发送ARP包,致使目标主机的ARP缓存表中正确的IP映射的是错误的MAC地址 在书上的介绍中,采用了WinPcap的开发包,这样很方便的对网卡进行操作 所以,首先需要安装winpacp,并下载开发者包https://www......

Think88666的博客 2975

(持续更新中!)详解【计算机类&面试真题】军队文职考试 ——第二期(真题+解析)| 网络协议的三个核心要素;交互式系统中的非剥夺策略;中断和陷入的区别;可变分区管理中的硬件机制;数据库系统的优点

本篇博客将讨论军队文职面试(计算机类)的几个关键问题。我们将介绍网络协议的核心要素(帮助你理解网络通信的基本原理)、交互式系统中的非剥夺策略(解释为何这是一个优秀的策略以及其对用户体验、系统稳定性和可预测性的影响)、中断和陷入的区别(从引起原因、处理机制、权限级别和应用等方面进行阐述)、可变分区管理的硬件机制以及数据库系统与文件系统的优点比较。通过阅读本文,您将深入了解这些话题,为面试准备和实际应用提供有价值的知识。

追光者♂:记录、分享、总结、提升,现象级专栏《Python从入门到人工智能》作者,无惧黑暗,坚信曙光 1705

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

手把手教你玩转ARP包

前   言          首先要感谢网络安全资深专家卢湖川博士以及VC网络版的limin朋友提供的资料以及帮助^_^经常看到论坛有人问起关于数据包的截获、分析等问题,幸好本人也对此略有所知,所以就想写一系列的文章来详细深入的探讨关于数据包的知识,,我希望通过这一系列的文章,能使得关于数据包的知识得以普及,所以这系列的每一篇文章我都会有由浅入深的解释、详细的分析、以及编码步骤,另外附上带

江湖·郎中·路 2339

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

tcp

<br /><br />解析一(TCP-1.1) <br /><br />这个包是发送方向服务器发送的SOCKET请求包。也就是请求连接。 <br /><br />---DLC HEADER--- <br />00-11-D8-76-8D-A3 目标主机的MAC地址 <br />00-11-D8-54-5B-5C 发送机MAC地址 <br />---SNAP HEADER--- <br />08-00 表示以太网类型使用的是IP协议 <br />---IP HEADER--- <br />45 4代表IP版

laolei1986的专栏 800

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

ARP详解

ARP简介 IP地址只是一个逻辑地址,要想在链路层上传播数据,需要知道MAC物理地址。而IP数据包中只有IP地址,所以就需要一个协议来通过IP地址来获取对应的MAC地址,这个协议就是ARP协议。 ARP原理 ARP报文解析 1、 ARP是工作在链路层的,ARP请求发送一个帧。 帧分为两部分:帧头部、ARP请求数据。 上图是帧的结构: 1、 帧的头部的目的MAC地址为FFFFFFFFFFFF,表示这是一个广播帧,会转发给网络中的所有主机。 2、 帧的头部的帧类型有以下选择: 1、 0800:运载的是IP数

qq_40276626的博客 8688

ARP协议简介

ARP,全称Address Resolution Protocol,中文名为地址解析协议,它工作在数据链路层,在本层和硬件接口联系,同时对上层提供服务。 数据链路如以太网或令牌环网都有自己的寻址机制,这是使用数据链路的任何网络层都必须遵守的,IP数据包常通过以太网发送,以太网设备并不识别32位IP地址,它们是以48位以太网地址(MAC地址)传输以太网数据包,设备驱动程序从不检查IP数据报中的

oyanghaizhi的专栏 1483

计算机网络中这些高频考题,你还在死记硬背吗?(三)

路由器DHCP功能概述及其工作原理

IT学长 823

常用网络数据帧格式

本文主要介绍ARP、ICMP、UDP、TCP等常用网络数据帧格式。

斌赋的博客 7332

DHCP报文分析

在三级网络技术中,有一道考察DHCP服务器报文的综合题,考查的题目看似相同,考点比较固定,可是均有侧重,有必要挑出来分析一下。 基本工作原理: DHCP客户端申请IP租约的4个阶段 续约: 如果采用动态地址分配策略,则DHCP服务器分配给客户端的IP地址有一定的租借期限(默认8天),当租借期满后服务器会收回该IP地址。如果DHCP客户端希望继续使用该地址,需要更新IP地址租约。

贵宝的博客 3万+

@RequestHeader #RequestHeader注解 @FDDLC

@RequestHeader和@RequestParam作用类似。 @RequestParam(name="requestParamName")的作用是从请求中获取名为requestParamName的参数, 在默认情况下(即required=true)缺少该参数会出错。 而@RequestHeader(name="headerParamName")的作用是从请求头中获取名为headerParamName的参数,在默认情况下(即required=true)缺少该参数会出错。 上面表示从请求头中获

LiuXingchang的博客 1179

php header详解

header (PHP 3, PHP 4, PHP 5) header -- 发送一个原始 HTTP 标头 说明 void header ( string string [, bool replace [, int http_response_code]] ) header() 函数用来发送一个原始 HTTP 标头。有关 HTTP 标头的更多内容见 HTTP/1.1 规范 。 可选...

翅膀同学的优快云 Blog 286
上一篇: 轻松实现一个操作ini文件的类
下一篇: 杀毒软件的奥秘
xmlscript
博客等级 码龄25年 1粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值