/*

程序功能:

1、构造arp包,并发送。程序参数顺序:源IP、目的IP、mac地址、flag

2、获取网络中的ARP数据包,解析数据包的内容。程序参数:日志文件名

winpacp中文技术文档(基本是英文的):http://www.ferrisxu.com/WinPcap/html/index.html

*/

一、构造arp包

在构造之前先了解一下arp包的结构,先从网上找了张图

从图中可以看出以太网首部占14字节,以太网ARP字段占28字节。其中op字段为操作类型,1表示ARP请求、2表示ARP应答

再介绍几个要用到的pcap函数

  1. int pcap_findalldevs ( pcap_if_t ** alldevsp,  char * errbuf)

函数功能:列出当前所有可用的网络设备(网卡),将设备信息存入pcap_if_t结构列表中

参数:1、alldevsp    指向pcap_if_t结构列表的指针的地址(注意这里是pcap_if_t指针的地址,而不是pcap_if_t结构的地址)

    有些地方这里可能会写pcap_if结构,其实pcap_if和pcap_if_t就是同一个东西,我们来看看在pcap.h中是怎么定义的

   pcap_if结构体成员:

Struct pcap_if {

struct pcap_if  *next;  //指向下一个链表成员

char *name; //网卡名称

chat *description; //网卡描述信息

struct pcap_addr address;

u_int flags; //接口标志

}

    2、errbuf   错误缓冲区,要求长度至少为PCAP_ERRBUF_SIZE 字节,那么PCAP_ERRBUF_SIZE是多大呢

          这在pcap.h中宏定义的,如下图

     这个错误缓冲区用来做什么呢?在函数错误返回时(返回值为-1)会向错误缓冲中填充错误信息,错误信息为可打印ASCII码

     函数正确时返回0

  2、pcap_t * pcap_open_live ( char * device, int snaplen, int promisc,int to_ms, char * errbuf )

函数功能:在网络中打开一个活动的捕获<这是winpcap技术文档给出的说明,也就是指定从一个网络设备捕获数据包,我是这么理解的>

    函数的返回值为一个结构体指针pcap_t即为struct pcap。pcap_t结构体有点长就不做说明了,里面就是捕获句柄的一些信息

参数: <文档是英文的不知道有没有翻译对>

    device 设备名

    snaplen 单包最大捕捉字节数(若数据包大于snaplen,只有前面snaplen字节大小的数据被捕获)  

    promisc 混杂模式(即使该参数是false,也可能由其他原因导致网络接口为混杂模式)

    to_ms 指定毫秒级读超时(当一个数据包被发现时,并不一定立即返回数据包,它会等待一段时间,允许一个操作从系统内核读取多个数据  包。不是所有的平台都支持读超时,在不支持的平台上读超时会被忽略。)<在支持读超时的平台上若读超时为0,将导致永不超时>

    errbuf 用于返回错误或警告信息

  3、void pcap_close ( pcap_t  *p )

    关闭pcap_open_live()获取的包捕获句柄,释放相关资源

源码:

 /*
构造并发送ARP包
2015年6月24日15:44:21
blog:http://www.cnblogs.com/wd1001/
*/
#include <stdlib.h>
#include <stdio.h>
#include <pcap.h> #pragma comment(lib, "wpcap.lib")
#pragma comment(lib, "wsock32.lib")
#pragma comment(lib, "ws2_32.lib") main(int argc, char **argv)
{
u_char packet[];
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=,j,k,temp[];
pcap_t * adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
/* 获取设备列表 */ if (argc != )//argc==5,及程序后面有四个参数
{
printf("usage: %s inerface", argv[]);
return -;
} if (pcap_findalldevs(&alldevs, errbuf) == -)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit();
}
/* 数据列表 */
for(d=alldevs; d; d=d->next)
{
printf("%d. %s", ++i, d->name);
if (d->description)
printf(" (%s)\n", d->description);
else
printf(" (No description available)\n");
}
if(i==)
{
printf("\n找不到网卡! 检查是否安装WinPcap.\n");
return -;
}
printf("Enter the interface number (1-%d):",i);
scanf("%d", &inum);
if(inum < || inum > i)
{
printf("\nInterface number out of range.\n");
/* 释放设备列表 */
pcap_freealldevs(alldevs);
return -;
}
/* 转到选择的设备 */
for(d=alldevs, i=; i< inum-;d=d->next, i++);
/* 打开设备 */
if ( (adhandle= pcap_open_live(d->name, //设备名
, // 最大捕捉字节数
, // 混杂模式
, // 读入超时
errbuf // 错误缓冲
) ) == NULL)
{
/*打开失败*/
fprintf(stderr,"\n打开失败. %s 不被winpcap支持\n",d->name);
/* 释放列表 */
pcap_freealldevs(alldevs);
return -;
}
/* 释放设备列表 */
pcap_freealldevs(alldevs); /* 填充数据段 */ //flag为1表示ARP请求
if(''==argv[][])
{
//源MAC地址
k=;
for(i=;i<;i=i+)
{
temp[]=(int)argv[][i];
temp[]=(int)argv[][i+];
if(temp[]>) //当输入mac为小写字母时字符转换为16进制
temp[]=temp[]-;
else if(temp[]>)
temp[]=temp[]-;//当输入mac为大写字母时字符转换为16进制
else
temp[]=temp[]-;//当输入mac为数字时字符转换为16进制
if(temp[]>)
temp[]=temp[]-;
else if(temp[]>)
temp[]=temp[]-;
else
temp[]=temp[]-;
packet[+k]=packet[+k]=temp[]*+temp[];
k++;
} //发送ARP请求时目的MAC全置为ff
for(i=;i<;i++)
{
packet[i]=packet[+i]=0xff;
}
} //flag=2:ARP应答
else
{
//目的MAC地址
k=;
for(i=;i<;i=i+)
{
temp[]=(int)argv[][i];
temp[]=(int)argv[][i+];
if(temp[]>)
temp[]=temp[]-;
else if(temp[]>)
temp[]=temp[]-;
else
temp[]=temp[]-;
if(temp[]>)
temp[]=temp[]-;
else if(temp[]>)
temp[]=temp[]-;
else
temp[]=temp[]-;
packet[k]=packet[+k]=temp[]*+temp[];
k++;
}
//应答ARP请求时把源MAC置为0
for(i=;i<;i++)
{
packet[+i]=packet[+i]=0x00;
}
} //源IP地址
k=;
temp[]=; //指向每个字节初始位置
for(i=;i<;i++)
{
temp[]=;
temp[]=;
for(j=;j<;j++)
{
if(argv[][j+temp[]]>=''&&argv[][j+temp[]]<='')
{
temp[]=(int)argv[][j+temp[]]-;
temp[]=temp[]*+temp[];
//printf("%d %d\n",temp[0],temp[1]);
}
else
{
//当遇到点时j自加1目的是让temp[2]+j指向下一字节的第一位
j++;
break;
}
}
packet[+k]=temp[];
k++;
temp[]+=j;
}
//目标IP地址
k=;
temp[]=;
for(i=;i<;i++)
{
temp[]=;
temp[]=;
for(j=;j<;j++)
{
if(argv[][j+temp[]]>=''&&argv[][j+temp[]]<='')
{
temp[]=(int)argv[][j+temp[]]-;
temp[]=temp[]*+temp[];
//printf("%d %d\n",temp[0],temp[1]);
}
else
{
j++;
break;
}
}
packet[+k]=temp[];
k++;
temp[]+=j;
}
//ARP首部
packet[]=0x08;//12、13位为帧类型
packet[]=0x06;
packet[]=0x00;//14、15位为硬件类型
packet[]=0x01;
packet[]=0x08;//16、17位为协议类型
packet[]=0x00;
packet[]=0x06;//硬件地址长度
packet[]=0x04;//协议地址长度
packet[]=0x00;//op
packet[]=(int)argv[][]-;//op(1为请求2为应答) /* 填充发送包的剩余部分 */
for(i=;i<;i++)
{
packet[+i]=;
}
//这里后四个字节本应该是校验位,这里就不算了,写个日期纪念一下
packet[]=0x20;
packet[]=0x15;
packet[]=0x6;
packet[]=0x24;
/* 发送包 */
pcap_sendpacket(adhandle, packet, );
printf("Success!\n"); return ;
}

运行结果:

输入参数:随意设置源IP,目的IP和mac地址

选择网卡并发送,抓包结果如下


二、获取网络中的ARP数据包,解析数据包的内容

在上面的基础上再解析ARP数据包就简单了

同样在解析前先介绍几个要用到的函数

  1、int pcap_compile ( pcap_t * p, struct bpf_program * fp, char * str,int optimize , bpf_u_int32 netmask )

函数功能:将字符串str编译进一个过滤程序,将程序中高级的过滤表达式,转换成能被内核级的过滤引擎所处理的东西

参数:1、p为pcap_open_live返回的一个捕获句柄

   2、fp为一个指向bpf_program结构的指针,由pcap_compile()函数填写

bpf_program结构为:

struct bpf_program {
u_int bf_len;
struct bpf_insn *bf_insns;
};

bpf_insn结构为:

struct bpf_insn {
u_short code;
u_char jt;
u_char jf;
bpf_int32 k;
};

    3、str 过滤串表达式

    4、optimize 优化控制,是否执行结果代码优化(optimize controls whether optimization on the resulting code is performed)

    5、netmask 子网掩码

  2、int pcap_setfilter (pcap_t *p, struct bpf_program *fp)

函数功能:在捕获过程中绑定一个过滤器

源码:

 /*
获取网络中的ARP数据包,解析数据包的内容
2015年6月24日19:36:36
blog:http://www.cnblogs.com/wd1001/
*/
#include <stdlib.h>
#include <stdio.h>
#include <pcap.h>
#pragma comment(lib, "wpcap.lib")
#pragma comment(lib, "wsock32.lib")
#pragma comment(lib, "ws2_32.lib")
//定义ARP包数据
typedef struct arppkt
{
unsigned short hdtyp;//硬件类型
unsigned short protyp;//协议类型
unsigned char hdsize;//硬件地址长度
unsigned char prosize;//协议地址长度
unsigned short op;//(操作类型)操作值:ARP/RARP
u_char smac[];//源MAC地址
u_char sip[];//源IP地址
u_char dmac[];//目的MAC地址
u_char dip[];//目的IP地址
}arpp;
int main(int argc,char * argv[] )
{
struct tm * timeinfo;
struct tm *ltime;
time_t rawtime;
FILE * fp=NULL;
int result;
int i=,inum;
pcap_if_t * alldevs;//指向pcap_if_t结构列表指针
pcap_if_t * d;
pcap_t * adhandle;//定义包捕捉句柄
char errbuf[PCAP_ERRBUF_SIZE];//错误缓冲最小为256
u_int netmask; //定义子网掩码
char packet_filter[]="ether proto \\arp";
struct bpf_program fcode;
struct pcap_pkthdr * header;
const u_char * pkt_data;
//打开日志文件
if((fp=fopen(argv[],"a"))==NULL)
{
printf("打开文件失败!\n");
exit();
}
if (argc != )//argc==2,及程序后面有1个参数
{
printf("程序%s需要一个日志文件名参数!\n", argv[]);
return -;
}
//当前所有可用的网络设备
if (pcap_findalldevs(&alldevs, errbuf) == -)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit();
}
//列出网络设备
for(d=alldevs; d; d=d->next)
{
printf("%d. %s", ++i, d->name);
if (d->description)
printf(" (%s)\n", d->description);
else
printf(" (没有描述可用)\n");
}
if(i==)
{
printf("\n找不到网卡! 检查是否安装WinPcap.\n");
return -;
}
printf("选择对应网卡编号 (1-%d):",i);
scanf("%d", &inum);
if(inum < || inum > i)
{
printf("\n输入的编号超出范围!\n");
/* 释放设备列表 */
pcap_freealldevs(alldevs);
return -;
}
/* 转到选择的设备 */
i=;
d=alldevs;
while(i<inum-)
{
d=d->next;
i++;
}
if ( (adhandle= pcap_open_live(d->name,, ,,errbuf) ) == NULL)
{
/*打开失败*/
fprintf(stderr,"\n打开失败. %s 不被winpcap支持\n",d->name);
/* 释放设备列表 */
pcap_freealldevs(alldevs);
return -;
}
/* 释放设备列表 */
pcap_freealldevs(alldevs); //获得子网掩码
netmask=((sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
//编译过滤器,只捕获ARP包
if(pcap_compile(adhandle,&fcode,packet_filter,,netmask)<)
{
printf("\nUnable to compile the packet filter.Check the syntax.\n");
pcap_freealldevs(alldevs);
return -;
}
//设置过滤器
if(pcap_setfilter(adhandle,&fcode)<)
{
printf("\nError setting the filter.\n");
pcap_freealldevs(alldevs);
return -;
}
//输出每次修改文件时间
time ( &rawtime );
timeinfo = localtime ( &rawtime );
printf("--------------修改时间:%s",asctime (timeinfo));
fprintf(fp,"-----------修改时间:%s",asctime (timeinfo));
fflush(fp);//刷新缓冲流
while((result=pcap_next_ex(adhandle,&header,&pkt_data))>=)
{
//循环解析ARP数据包
if(result==)
continue;
//解析ARP包,结果输出到屏幕与文件
arppkt* arph = (arppkt *)(pkt_data +);
//输出操作时间
ltime=localtime(&header->ts.tv_sec);
printf("时间:%s",asctime (ltime));
fprintf(fp,"时间:%s",asctime (ltime));
//输出源IP
printf("源IP:");
fprintf(fp,"源IP:");
for(i=;i<;i++)
{
printf("%d.",arph->sip[i]);
fprintf(fp,"%d.",arph->sip[i]);
}
printf("%d\t",arph->sip[]);
fprintf(fp,"%d.\t",arph->sip[]);
//输出目的IP
printf("目的IP:");
fprintf(fp,"目的IP:");
for(i=;i<;i++)
{
printf("%d.",arph->dip[i]);
fprintf(fp,"%d.",arph->dip[i]);
}
printf("%d\t",arph->dip[]);
fprintf(fp,"%d\t",arph->dip[]);
//输出源mac
printf("源mac:");
fprintf(fp,"源mac:");
for(i=;i<;i++)
{
printf("%x-",arph->smac[i]);
fprintf(fp,"%x-",arph->smac[i]);
}
printf("%x\t",arph->smac[]);
fprintf(fp,"%x\t",arph->smac[]);
//输出目的mac
printf("目的mac:");
fprintf(fp,"目的mac:");
for(i=;i<;i++)
{
printf("%x-",*(pkt_data+i));
fprintf(fp,"%x-",*(pkt_data+i));
}
printf("%x\t",*(pkt_data+));
fprintf(fp,"%x\t",*(pkt_data+));
//输出操作类型
printf("操作类型(ARP/RARP):");
fprintf(fp,"操作类型(ARP/RARP):");
if(arph->op==)
{
printf("ARP\t");
fprintf(fp,"ARP\t");
}
else
{
printf("RARP\t");
fprintf(fp,"RARP\t");
}
printf("\n");
fprintf(fp,"\n");
printf("--------------------------------------\n");
fprintf(fp,"--------------------------------------\n");
fflush(fp);
}
fclose(fp);
return ;
}

c语言Winpcap编程构造并接收解析arp包的更多相关文章

  1. 11. Go 语言网络编程

    Go 语言网络编程 Go语言在编写 web 应用方面非常得力.因为目前它还没有 GUI(Graphic User Interface 图形化用户界面)的框架,通过文本或者模板展现的 html 界面是目 ...

  2. Go语言备忘录(3):net/http包的使用模式和源码解析

    本文是晚辈对net/http包的一点浅显的理解,文中如有错误的地方请前辈们指出,以免误导! 转摘本文也请注明出处:Go语言备忘录(3):net/http包的使用模式和源码解析,多谢!  目录: 一.h ...

  3. Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...

  4. (转)Java并发编程:volatile关键字解析

    转:http://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或 ...

  5. WinPcap编程(前言&&学习)

    计算机网络课设要求用WinPcap写对ARP包的接收与发送. 所以学了一下WinPcap的内容. 参考的博客: http://blog.csdn.net/htttw/article/details/7 ...

  6. Mysql C语言API编程入门讲解

    原文:Mysql C语言API编程入门讲解 软件开发中我们经常要访问数据库,存取数据,之前已经有网友提出让鸡啄米讲讲数据库编程的知识,本文就详细讲解如何使用Mysql的C语言API进行数据库编程.   ...

  7. Java并发编程:volatile关键字解析(转载)

    转自https://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析   Java并发编程:volatile关键字解析 ...

  8. Go语言 并发编程

    Go语言 并发编程 作者:Eric 微信:loveoracle11g 1.创建goroutine // 并行 是两个队列同时使用两台咖啡机 // 并发 是两个队列交替使用一台咖啡机 package m ...

  9. C语言socket编程

    建议先去看一下思路 真的写的很不错呦~ 思路参考博客:https://www.cnblogs.com/renfanzi/p/5713054.html linux c语言socket编程代码(单一服务端 ...

随机推荐

  1. Cleaning Shifts(区间覆盖)

    /* http://acm.hdu.edu.cn/webcontest/contest_showproblem.php?pid=1019&ojid=1&cid=10 题目: 给定一个时 ...

  2. SRM 597

    我果然是题短了就能做得好- -.Div 2的三道题都短,于是迅速的过掉了250和500,rating涨了150^ ^. Div 2 250pt 题意:给一个vector<int> A,对其 ...

  3. 金牌分析师助力 鲁泰A图谋再造一个“鲁泰”?_财经_中国网

    金牌分析师助力 鲁泰A图谋再造一个"鲁泰"?_财经_中国网 金牌分析师助力 鲁泰A图谋再造一个"鲁泰"?

  4. tcp dump 截取http

    监听命令 sudo tcpdump -w mm.txt -s 0 -A -v  tcp dst port 8080 -w mm.txt :把记录下来的数据已二进制格式存储在mm.txt文件内  -w ...

  5. 另一个有趣的Captcha 网站

    今天在一个网站注册时又发现了一个有趣的Captcha形式.给你一个翻转的图片,然后让你拽下面的slide bar让它回到正常的位置,很有趣.下面是提供这个Captcha的网站. minteye – s ...

  6. [PWA] 8.Unobtrusive update: Delete old cache and only keep one, hard refresh to let new SW to take control

    So once you modify the code, service worker will auto create a new one and it won't take control ove ...

  7. 合肥三洋股份,惠而浦家电携四大品牌-Take ,所有的市场

        大家都知道,数家电企业的日子并不好过.一方面,产品同质化竞争越发激烈.家电市场已进入了恶性价格战时代.还有一方面,消费者对家电产品的需求越发多元化.个性化.这意味着无法满足消费者需求的产品非常 ...

  8. CreateProcess函数具体解释

    CreateProcess说明:WIN32API函数CreateProcess用来创建一个新的进程和它的主线程,这个新进程执行指定的可执行文件. 函数原型:BOOL CreateProcess(    ...

  9. 转载:C#实现接口回调

    通常情况下,我们创建一个对象,并马上直接去使用它的方法.然而,在有些情况下,希望能在某个场景出现后或条件满足时才调用此对象的方法.回调就可以解决这个“延迟调用对象方法”的问题.这个被调用方法的对象称为 ...

  10. 开始学习编程了…… 2015年九月七日 …… 31岁的Me.

    给自己下的命令:做今天开始认认真真地开始学习编程,一年后的今天一定要找到一份编程的工作. 为什么要学编程?:因为不想回以前的圈子,“创业”快三年什么都给“创”没了,咳……,不过呢,倒是领略到编程能带来 ...