WinPcap编程(二)
0.
这一次具体讲抓包的两种方法。
(建议)清除ARP表,最好自己写个批处理命令。快一点。
1.0 抓包步骤
步骤很简单:先打开适配器列表 --> 选择适配器 --> 通过遍历链表的方式到达你选择的适配器位置 --> 打开设备 --> 开始抓包。
每一个步骤都是一个函数。了解步骤,后面就好办。
首先,了解一个数据类型pcap/pcap_t。它代表一个打开的设备,理解成它就是适配器就行(实际上是这个适配器的描述符)。这个结构体对用户来说是不透明的,它通过wpcap.dll提供的函数,维护了它的内容。
然后,跳转至你的设备在WinPcap编程(一)中存在,就不多说。
之后,打开设备的函数:
pcap_t* pcap_open ( const char * source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth * auth, char * errbuf )
备注:
第一个参数:source是我们所要打开的设备。当我们获取所有的设备之后,这个source就是d->name。不能为NULL。
第二个参数:snaplen是我们抓取的数据包的大小,100就是抓取整个数据包的前100B,65536最大,把整个包都包括了。
第三个参数:flags设置为混杂模式(PCAP_OPENFLAG_PROMISCUOUS ),即不管数据包是否给我,我都去捕获。这样可以捕捉局域网内所有的包。
第四个参数: read_timeout设置超时时间,以毫秒计(1s=1000ms)。在适配器上进行读取数据操作的时候,不管网络上有没有包,都会在 read_timeout这个时间内响应。
设置为0意味着没有超时。没有数据包到达,读操作将永远不会返回。
设置成-1,无论有没有数据包到达,读操作都会立即返回。
第五个参数:auth远程机登录信息,若本地则为NULL;
第六个参数:errbuf 出错信息。
1.1抓包的两种方式:
1.1.1 回调函数的方法进行抓包
每次抓到包就用回调函数进行处理。处理完接着抓包(如果设置了num的话)。
抓包函数:
int pcap_loop ( pcap_t * p, int cnt, pcap_handler callback, u_char * user )
备注0:
第一个参数:P即是打开的设备。
第二个参数:cnt表示捕捉个数。
第三个参数:回调函数指针。对捕捉的数据包进行操作 。
第四个参数:用户信息,一般为NULL。
函数返回值:
返回值为0,捕捉了cnt次,正常返回。
返回值为-1,发生错误。
返回值为-2,使用pcap_breakloop()结束循环。
回调函数抓包还有一种方法, pcap_dispatch() 。
区别是: pcap_ dispatch() 当超时时间到了(timeout expires)就返回 (尽管不能保证) ,而 pcap_loop() 不会因此而返回,只有当 cnt 数据包被捕获。
所以,pcap_loop()会在一小段时间内,阻塞网络的利用。pcap_dispatch() 函数一般用于比较复杂的程序中。
1.1.2 不利用回调函数
回调函数比较好,但是有时候需要不用回调函数的方法,特别在多线程里面。
我用C# + WPF写的,用回调函数的话一直出现错误。仔细考虑,应该是托管与非托管的问题。看了SharpPcap的源码,貌似也没有好的解决方案。
【有好的方案的看见了希望能够提供一下,感谢。】
不利用回调函数抓包的话,方法比较简单,每次只能抓一个包,加个while()循环就OK了。
int pcap_next_ex (
pcap_t * p,
struct pcap_pkthdr ** pkt_header,
const u_char ** pkt_data
)
备注:
第一个参数:打开的设备。
第二个参数:WinPcap添加的一些信息。(时间戳,捕捉到包的长度,实际包的长度)。
第三个参数:实际数据包。
函数返回值:
返回值为1,正常返回;
返回值为0,超时后返回一个无效的包;
返回值为-1,发生错误;
返回值为-2,读到EOF。
源码:
#define WIN32
#include "pcap.h"
#include "winsock.h"
#include "time.h" /* packet handler 函数原型 */
void packet_handler(
u_char *param,
const struct pcap_pkthdr *header,
const u_char *pkt_data
); int main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i = ;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE]; /* 获取本机设备列表 */
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &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("\nNo interfaces found! Make sure WinPcap is installed.\n");
return -;
} printf("Enter the interface number (1-%d):", i);
scanf_s("%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(d->name, // 设备名
, // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容
PCAP_OPENFLAG_PROMISCUOUS, // 混杂模式
, // 读取超时时间
NULL, // 远程机器验证
errbuf // 错误缓冲池
)) == NULL)
{
fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
/* 释放设备列表 */
pcap_freealldevs(alldevs);
return -;
} printf("\nlistening on %s...\n", d->description); /* 释放设备列表 */
pcap_freealldevs(alldevs); /* 开始捕获 */
pcap_loop(adhandle, , packet_handler, NULL); system("pause");
return ;
} /* 每次捕获到数据包时,libpcap都会自动调用这个回调函数 */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
struct tm ltime = {};
char timestr[];
time_t local_tv_sec; /* 将时间戳转换成可识别的格式 */
local_tv_sec = header->ts.tv_sec;
localtime_s(<ime, &local_tv_sec);
strftime(timestr, sizeof timestr, "%H:%M:%S", <ime); printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
}
回调函数
#define WIN32
#include "pcap.h" int main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i = ;
pcap_t *adhandle;
int res;
char errbuf[PCAP_ERRBUF_SIZE];
struct tm ltime;
char timestr[];
struct pcap_pkthdr *header;
const u_char *pkt_data;
time_t local_tv_sec; int j = ;//限制只抓10个包 /* 获取本机设备列表 */
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &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("\nNo interfaces found! Make sure WinPcap is installed.\n");
return -;
} printf("Enter the interface number (1-%d):", i);
scanf_s("%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(d->name, // 设备名
, // 要捕捉的数据包的部分
// 65535保证能捕获到不同数据链路层上的每个数据包的全部内容
PCAP_OPENFLAG_PROMISCUOUS, // 混杂模式
, // 读取超时时间
NULL, // 远程机器验证
errbuf // 错误缓冲池
)) == NULL)
{
fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
/* 释放设列表 */
pcap_freealldevs(alldevs);
return -;
} printf("\nlistening on %s...\n", d->description); /* 释放设备列表 */
pcap_freealldevs(alldevs); /* 获取数据包 */
while ((res = pcap_next_ex(adhandle, &header, &pkt_data)) >= &&j>){ if (res == )
/* 超时时间到 */
continue; /* 将时间戳转换成可识别的格式 */
local_tv_sec = header->ts.tv_sec;
localtime_s(<ime,&local_tv_sec);
strftime(timestr, sizeof timestr, "%H:%M:%S", <ime);
j--; printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
} if (res == -){
printf("Error reading the packets: %s\n", pcap_geterr(adhandle));
return -;
}
system("pause");
return ;
}
非回调函数
WinPcap编程(二)的更多相关文章
- Linux shell脚本编程(二)
Linux shell脚本编程(二) 练习:求100以内所有偶数之和; 使用至少三种方法实现; 示例1: #!/bin/bash # declare -i sum=0 #声明一个变量求和,初始值为0 ...
- 【原创】高性能网络编程(二):上一个10年,著名的C10K并发连接问题
1.前言 对于高性能即时通讯技术(或者说互联网编程)比较关注的开发者,对C10K问题(即单机1万个并发连接问题)应该都有所了解."C10K"概念最早由Dan Kegel发布于其个人 ...
- Java并发编程二三事
Java并发编程二三事 转自我的Github 近日重新翻了一下<Java Concurrency in Practice>故以此文记之. 我觉得Java的并发可以从下面三个点去理解: * ...
- WinPcap编程入门实践
转自:http://www.cnblogs.com/blacksword/archive/2012/03/19/2406098.html WinPcap可能对大多数人都很陌生,我在这里就先简单介绍一下 ...
- Python进阶之面向对象编程(二)
Python面向对象编程(二) .note-content {font-family: "Helvetica Neue",Arial,"Hiragino Sans GB& ...
- Linux网络编程(二)
Linux网络编程(二) 使用多进程实现服务器并发访问. 采用多进程的方式实现服务器的并发访问的经典范例. 程序实现功能: 1.客户端从标准输入读入一行文字,发送到服务器. 2.服务器接收到客户端发来 ...
- java GUI编程二
java基础学习总结--GUI编程(二) 一.事件监听 测试代码一: 1 package cn.javastudy.summary; 2 3 import java.awt.*; 4 import j ...
- Java Socket聊天室编程(二)之利用socket实现单聊聊天室
这篇文章主要介绍了Java Socket聊天室编程(二)之利用socket实现单聊聊天室的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下 在上篇文章Java Socket聊天室编程(一)之 ...
- s3c2440裸机-时钟编程(二、配置时钟寄存器)
s3c2440裸机编程-时钟编程(二.配置时钟寄存器) 1.2440时钟时序 下图是2440时钟配置时序: 1.上电后,nRESET复位信号拉低,此时cpu还无法取指令工作. 2.nRESET复位信号 ...
随机推荐
- PHP面试题(二)
前言 从网上找了一套号称是百度的php面试题目,这里记录一下 PHP的gc机制 php的垃圾回收机制注意以下几点即可: 引用计数refcount和is_ref,也就是php不会随意的malloc内存空 ...
- Linux 和 Windows 下对long long的输出
以前一直用__int64来识别windows还是Linux,可是发现HDU好像不认 看到wzy用的UNIX可以. UNIX是Linux下定义的,具体是什么可以去百度. 那么就可以 #ifdef UNI ...
- View获取焦点
<EditText android:id="@+id/et_phoneNum" android:layout_width="match_parent" a ...
- 《Android开发艺术探索》读书笔记 (9) 第9章 四大组件的工作过程
第9章 四大组件的工作过程 9.1 四大组件的运行状态 (1)四大组件中只有BroadcastReceiver既可以在AndroidManifest文件中注册,也可以在代码中注册,其他三个组件都必须在 ...
- redis 自启动脚本
看到网上许多手写的亦或复制的redis开机自启动脚本, 版本好多, 其实最简单的可以从下载的redis文件里找得到 我下载的redis是 3.0.3 版本的, 对于其他版本, 没有详细查看, 有需要 ...
- HDU 5119 Happy Matt Friends(dp+位运算)
题意:给定n个数,从中分别取出0个,1个,2个...n个,并把他们异或起来,求大于m个总的取法. 思路:dp,背包思想,考虑第i个数,取或者不取,dp[i][j]表示在第i个数时,异或值为j的所有取法 ...
- EventBus 事件总线 原理
原理 一句话描述:register会把当前类中匹配的方法,存入一个map,而post会根据实参去map查找进行反射调用 撇开专业术语,其实EventBus就是在内部[存储]了一堆onEvent开头的方 ...
- 突然想写点东西,关于web新人的。采用问答方式
我自己是会计专业,转行自学web的,学习有一两年了,也还是新人一个,只不过不是那种超级“新”的,所以有什么话说得不对,请轻喷.欢迎大家来和我交流. 1.我能不能转行学web? 能不能学web这个不是别 ...
- [转载]使用兼容ie6 ie7 ie8 FF的text-overflow:ellips
使用兼容ie6 ie7 ie8 FF的text-overflow:ellipsis超出文本显示省略号来代替截取函数更有利于seo,如果使用截取函数,源代码中的标题是显示不完整的,即便是在title属性 ...
- java中对象的转型
1.对象的向上转型——将子类的对象赋值给父类的引用 Student s=new Student(); Person p=s; 一个引用能够调哪些成员(变量和函数),取决于这个引用的类型 也就是Pe ...