7
最近在学习Linux下网络包的封取,通过搜索获得很多好的文章,我不得不转.这篇文章有点不全,我尽量联系作者,尽量补全这篇文章,但是这篇文章前面的信息还是不错.
http://blog.csdn.net/zhzhwu/archive/2006/11/17/1393153.aspx 原文地址


一、     概要说明
1.1    目的要求
掌握ARP协议原理,熟悉Winpcap使用方法;使用Winpcap,手动封装ARP数据包,并实现ARP响应数据包的接收和解析,实现基于ARP协议获取本局域网内全部活动主机MAC地址与IP地址对应关系列表。
1.2    开发平台
1.2.1操作系统:Windows XP (sp2)
1.2.2开发语言:C语言
1.2.3开发工具:VC 6.0 和 Winpcap
二、     相关知识介绍
2.1 winpcap驱动简介
   winpcap(windows packet capture)是windows平台下一个免费,公共的网络访问系统。开发winpcap这个项目的目的在于为win32应用程序提供访问网络底层的能力。它提供了以下的各项功能:
1>    捕获原始数据报,包括在共享网络上各主机发送/接收的以及相互之间交换的数据报;
2>      在数据报发往应用程序之前,按照自定义的规则将某些特殊的数据报过滤掉;
3>      在网络上发送原始的数据报;
4>      收集网络通信过程中的统计信息。
winpcap的主要功能在于独立于主机协议(如TCP-IP)而发送和接收原始数据报。也就是说,winpcap不能阻塞,过滤或控制其他应用程序数据报的发收,它仅仅只是监听共享网络上传送的数据报。因此,它不能用于QoS调度程序或个人防火墙。
2.2 Packet32.h修改
     老师提供的Packet32.h文件确实如下结构体:
struct sockaddr_storage {
   u_char sa_len;
   u_char sa_family;
   u_char padding[128];
};
在写程序过程中自行将此程序加入。
三、     程序设计思路
3.1 总体思路
   程序设计的总体思路是:首先获得本地主机网络适配器信息;若有多个网络适配器时,打开指定的网络适配器,获得该网络适配器的相关信息,如本地主机IP等;再创建线程接收所有流过的数据报;创建线程向本局域网内所有主机发送arp数据报。
3.2 打开网络适配器,接收所有流过的数据报
   首先打开指定的网络适配器,获得本地主机网络适配器信息后,创建线程,将网络适配器设置为混杂模式,接收所有流过的数据报。接受数据报成功时候调用dealData函数处理解析数据报。
3.3 发送ARP请求数据报,获得指定IP的MAC地址
   首先初始化ethernet_head、arp_head结构,然后将本地主机IP与子网掩码进行“与”运算,得到网关地址,然后依次对本局域网内所有IP发送ARP数据报。发送不成功时提示错误返回。

下面是代码:

/******************************************
*文件名称:arpHomeWork.c
*作    者:武执正
*摘    要:使用Winpcap,手动封装ARP数据包,
*          实现ARP响应数据报的接收和解析,
*          获取本局域网内全部活动主机MAC地址
*          与IP地址对应列表
*完成时间:2006-10-25
*/

#include <packet32.h>
#include <ntddndis.h>
#include <stdio.h>
#include <conio.h>

#pragma comment(lib,"ws2_32")
#pragma comment(lib,"packet")

#define ETH_IP       0x0800
#define ETH_ARP      0x0806
#define ARP_REQUEST  0x0001
#define ARP_REPLY    0x0002
#define ARP_HARDWARE 0x0001
#define MAX_NUM_ADAPTER  10

#pragma pack(push,1)

//最终发送的数据报结构
typedef struct    ethernet_head
{
   unsigned char    dest_mac[6];      //目标主机mac  
   unsigned char    source_mac[6];      //本地主机mac
   unsigned short    eh_type;          //类型
}ethernet_head, *pEthernetHead;

//ARP数据报头结构
typedef struct    arpHead
{
   unsigned short  hardware_type;        //硬件类型
   unsigned short  protocol_type;        //协议类型
   unsigned char   add_len;            //硬件地址长度
   unsigned char   pro_len;            //协议地址长度
   unsigned short  option;                //操作号
   unsigned char   sour_addr[6];        //发送者硬件地址
   unsigned long   sour_ip;            //发送者协议地址
   unsigned char   dest_addr[6];        //目的站硬件地址
   unsigned long   dest_ip;            //目的站协议地址
   unsigned char    padding[18];
}arpHead, *pArpHead;

//IP数据报头结构
typedef struct ipHead
{
   unsigned char    h_lenver;
   unsigned char    tos;
   unsigned short    total_len;
   unsigned short    ident;
   unsigned short    frag_and_flags;
   unsigned char    ttl;
   unsigned char    proto;
   unsigned short    checksum;            //校验和
   unsigned int    sourceip;            //本地主机IP
   unsigned int    destip;                //目标主机IP
}ipHead, *PipHead;

#pragma pack(push)

LPADAPTER    lpadapter = 0;
LPPACKET    lppacketr, lppackets;
unsigned long    myip;        //本地主机IP
unsigned char    myMac[6] = {0};            //本地主机mac初始化
char    adapterlist[MAX_NUM_ADAPTER][1024];        //本地主机网络适配器列表数组
int        num = 0;            //用于发送ARP包时候递增

/******************
*处理接收到的数据报
*******************/
void dealData(LPPACKET lp)
{
   unsigned long    ulbytesreceived, off;
   unsigned long    k;
   char    *buf, *pChar, *base;
   PipHead    ip;
   struct bpf_hdr    *hdr;
   struct sockaddr_in    sin;
   ethernet_head    *eth;
   arpHead    *arp;

   ulbytesreceived = lp->ulBytesReceived;
   buf = (char *)lp->Buffer;

   off = 0;

   //解析数据报
   while (off < ulbytesreceived)
   {
       hdr = (struct bpf_hdr *)(buf+off);
       off += hdr->bh_hdrlen;            //修改off

       pChar = (char *)(buf+off);
       base = pChar;
       off = Packet_WORDALIGN(off + hdr->bh_caplen);

       eth = (pEthernetHead)pChar;                
       arp = (pArpHead)(pChar + sizeof(ethernet_head));

       if (eth->eh_type == htons(ETH_IP))
       {
           ip = (PipHead)(pChar+sizeof(ethernet_head));
       }//if
       else if((eth->eh_type==htons(ETH_ARP)) && (arp->option==htons(ARP_REPLY)))  
       {
           sin.sin_addr.s_addr = arp->sour_ip;

           if (sin.sin_addr.s_addr == htonl(myip))
           {
               memcpy(myMac, eth->source_mac, 6);
           }//if

           //输出ip地址
           printf("  %.16s <-> ", inet_ntoa(sin.sin_addr));

           //输出mac地址
           for(k=0;k<5;k++)
           {
               printf("%.2x-",eth->source_mac[k]);
           }//if
           printf("%.2x",eth->source_mac[5]);
       }//else
   }//while
   return ;
}

/************************************************
*将网络适配器设置为混杂模式,接收所有流过的数据报,
*然后解析该数据报
************************************************/
DWORD WINAPI sniff()
{

   char    recvbuf[1024*250];

   //将网络适配器设置为混杂模式失败
   if (!PacketSetHwFilter(lpadapter, NDIS_PACKET_TYPE_PROMISCUOUS))
   {
       printf("Warning:不能设置网络适配器为混杂模式 ");
   }//if

   //自定义网络适配器的内核缓冲的大小为 500*1024失败
   if (!PacketSetBuff(lpadapter, 500*1024))
   {
       printf("PacketSetBuff Error! ");
       return    -1;
   }//if

   //设置接收一个数据报后等待的时间为1毫秒失败
   if (!PacketSetReadTimeout(lpadapter, 1))
   {
       printf("Warning: 不能设置超时时间 ");
   }//if

   if (!(lppacketr=PacketAllocatePacket()))
   {
       printf("PacketAllocatePacket receive Error! ");
       return    -1;
   }//if

   //初始化一个packet结构
   PacketInitPacket(lppacketr, (char *)recvbuf, sizeof(recvbuf));

   //没有按键按下时候
   while (!kbhit())
   {
       //接收数据报,不成功时退出;成功时解析数据报
       if (!PacketReceivePacket(lpadapter, lppacketr, TRUE))
       {
           printf("PacketReceivePacket Error!");
           return    -1;
       }//if

       dealData(lppacketr);
   }//while

   return 0;
}

/**********************************************
*发送ARP Request数据报,请求获得指定ip的mac地址
***********************************************/
DWORD WINAPI sendArp()
{
   int        k;
   char    sendbuf[1024];
   ethernet_head    eth;
   arpHead    arp;

   //初始化目的主机mac和IP
   for (k=0; k<6; k++)
   {
       eth.dest_mac[k] = 0xff;
       arp.dest_addr[k] = 0x00;
   }//for

   memcpy(eth.source_mac,myMac,6);
   eth.eh_type = htons(ETH_ARP);

   arp.hardware_type = htons(ARP_HARDWARE);
   arp.protocol_type = htons(ETH_IP);
   arp.add_len = 6;
   arp.pro_len = 4;
   arp.option = htons(ARP_REQUEST);
   arp.sour_ip = htonl(myip);
   memcpy(arp.sour_addr, myMac,6);

   //本地主机IP与子网掩码“与”运算得到网关IP
   arp.dest_ip = htonl((myip&0xffffff00)+1+(num++));      

   memset(sendbuf, 0, sizeof(sendbuf));          //初始化发送缓存
   memcpy(sendbuf, &eth, sizeof(eth));            //把eth放入发送缓存
   memcpy(sendbuf+sizeof(eth), &arp, sizeof(arp));    //把arp放入发送缓存

   //初始化一个_PACKET结构
   PacketInitPacket(lppackets, sendbuf, sizeof(eth)+sizeof(arp));
   //发送数据报,不成功时退出
   if (!PacketSendPacket(lpadapter, lppackets, TRUE))
   {
       printf("PacketSendPacket in sendArp Error! ");

       return    -1;
   }//if

   return    0;
}

/****************************************
*主函数:首先获得本地主机网络适配器数量,
*再打开特定的网络适配器,然后调用函数发送
*解析ARP数据报
*****************************************/
int main(int argc,char *argv[])
{
   HANDLE   sthread,rthread;
   unsigned char    adaptername[8192];
   unsigned char    *temp1, *temp2;
   unsigned long    adapterlength;
   unsigned long    threadsid, threadrid;        //线程ID
   struct  bpf_stat     stat;
   struct  sockaddr_in  sin;
   struct  npf_if_addr  ipbuff;
   int        adapternum = 0;            //网络适配器数量,初始化为0
   int        open;                    //标识打开第几个网络适配器
   int        i;
   long    npflen;

   adapterlength = sizeof(adaptername);

   //不能得到网络适配器信息时退出
   if (!PacketGetAdapterNames((char *)adaptername, &adapterlength))
   {
       printf("PacketGetAdapterNames Error! ");
       return -1;
   }//if
   temp1 = adaptername;
   temp2 = adaptername;
   i = 0;
   
   //分离出网络适配器信息,并计算网络适配器个数
   // while ((*temp1!= '
   //////////////////////////////////////////////////////////////剩下的代码不全

Tags: , , , , | 引用(0)
2008/09/06 16:35
我的pc是双网卡想知道哪个网卡连接了一个指定ip和mac的机器,我就 用winPcap库发送ARP询问帧,分别通过2张网卡发送ARP包,收到回应的网卡就是我想得到的。但winpcap库我在网上找了很多安装包,都没有packet32.lib之类得。。可以发一个给我吗?  我邮箱:tortisenow@163.com
似的
2008/04/07 08:30
后面的代码有没有?我找自己搞不定啊husan_3@sohu.com
似的
2008/04/03 11:19
完整的代码有没有啊,我是初学的
借来的温柔 Email
2008/03/18 10:16
楼主大哥能否发分完整的说明书和源码给我参考下?我就要答辩了!我做的就是这个毕业设计吖  4月10号答辩 ,急用!先谢谢了!我的邮箱
ace_man@163.com
huzhangyou2002 回复于 2008/03/18 10:32
毕业设计也不认真做?就想着交差?哎 抱歉我做不到
wzz_boy
2008/03/11 21:44
我也等着急用呀,可不可以把源码发给我呢?  

wzz_boy@yahoo.com.cn
huzhangyou2002 回复于 2008/03/12 09:44
上面的这些代码就可以直接使用啊
分页: 1/2 第一页 1 2 下页 最后页
发表评论
表情
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
打开HTML
打开UBB
打开表情
隐藏
记住我
昵称   密码   游客无需密码
网址   电邮   [注册]