winpcap 获取数据包源码——可直接编译可用
作者:互联网
源码
winpcap 获取数据包
定义了TCP头部,IPv4地址,ip头结构体。此外还有一些和pcap相关的结构体和函数。
结构体:pcap_if_t,pcap_t,bpf_program
函数:pcap_findalldevs,pcap_freealldevs,pcap_open_live,pcap_datalink,pcap_compile,pcap_setfilter,pcap_loop,packet_handler
pcap_findalldevs这个函数同pcap_findalldevs_ex,返回系统选中可用的接口。组建一个网络设备表,该表可被pcap_open_live()打开。(注意可能有些网络设备不能被pcap_open_live()通过调用pcap_findalldevs()打开,因为,例如进程不具有打开它们的特权;出现这种情况,这些设备将不会在列表中出现)alldevsp指向列表的第一项,列表的每一项都是一个pcap_if_t结构。
pcap_if_t*
pcap_if* next 如果不是为null,则指向列表的下一个元素;如果是空,则代表当前元素是最后一个元素。
char* name 指向字符串的指针 字符串用来向pcap_open_live()传递设备的名称
char* description 如果不为null,它指向的字符串是对设备的一个简单的描述。
pcap_addr* addresses 指向设备列表中第一个元素的地址;
u_int flags PCAP_IF_接口标志,当前只有PCAP_IDF_LOOPBACK,考察接口是不是一个自环接口。
pcap_freealldevs(pcap_if_t* alldevsp)
释放由pcap_findalldevs()返回的接口列表。
pcap_t* pcap_open_live(char* device, intsnaplen, int promisc,int to_ms, char* ebuf)
Deprecated: usethe pcap_open() instead. 打开一个物理接口进行捕获。
pcap_open_live() 用来获得一个观察网络数据包的包捕获描述符。Device是一个标识要打开的设备的字符串,on Linux systems with 2.2 or later kernels, a device argument of "any"or NULL can be used to capture packets from all interfaces. Snaplen定义要捕获的最大字节数。promisc定义是否将接口设置为混杂模式 (promiscuousmode.)。(注意:即使这个参数为false,接口也有可能因为其他原因而处于混杂模式下) For now, this doesn't work on the "any" device; if anargument of "any" or NULL is supplied, the promisc flag is ignored.to_ms用毫秒定义读取超时。读取超时用以解决没有必要捕获数据包就开始读取,而是等待一段时间,有较多数据包到达,然后从操作系统内核一次读取多个数据包的问题。并不是所有平台支持读取超时。在不支持的平台上,这个参数被忽略。errbuf用来返回错误或者警告信息。当pcap_open_live()调用失败返回null时,errbuf被设定为错误信息。pcap_open_live() 调用成功时errbuf也可以被设置为警告信息。为得到这个信息,调用者应该在调用pcap_open_live()之前在errbuf中设定一个长度为0的字符串。调用后如果errbuf的长度不再为0,那么警告信息已经发生并可以显示出来。
int pcap_next_ex(pcap_t* p, structpcap_pkthdr** pkt_header, u_char** pkt_data)
Win32 Specific. Read a packet from aninterface or from an offline capture.
该函数用来检索下一个可用的数据包, bypassing the callback method traditionally provided bylibpcap.
pcap_next_ex 用指向下一个捕获的数据包的数据头和数据的指针填充pkt_header和pkt_data参数。(see pcap_handler())
返回值可以是:
l 1如果数据包被顺利读取
l 0如果pcap_open_live()规定的读取超时已经过去。在这种情况下pkt_header和pkt_data指向的不是一个有用的数据包
l -1如果出现错误
l -2如果在离线捕获中遇到EOF。
timeval结构如下:
struct timeval{long tv_sec;longtv_usec;}
其中tv_sec为秒数,tv_usec微秒数。
返回链路层的类型,链路层的类型包括:
DLT_NULL: BSD回路封装;链路层协议头是一个4字节的域,以主机字节顺序(host byte order),包含一个从socket.h来的PF_value。主机字节顺序(host byte order)是捕获数据包的机器的字节顺序,而PF_value是捕获数据包的机器的OS。如果一个读取一个文件,字节顺序和PF_value不一定是抓取文件的那些机器。
DLT_EN10MB: 以太网(10Mb, 100Mb,1000Mb, 或者更高)。
DLT_IEEE802: IEEE802.5令牌环网。
DLT_ARCNET:ARCNET。
DLT_SLIP:SLIP。
DLT_PPP:PPP;如果第一个字节是0xff或0x03,它是类HDLC帧上的PPP。
DLT_FDDI:FDDI
DLT_ATM_RFC1483:RFC1483LLC/SNAPATM;数据包以IEEE802.2 LLC头开始。
DLT_RAW:原始IP(raw IP);数据包以IP头开始。
DLT_PPP_SERIAL:按照RFC1662,基于类HDLC帧的PPP,或者按照RFC1547的4.3.1,基于HDLC帧的Cisco PPP;前者的第一个字节是0xFF,后者的第一个字节是0x0F或0x8F。
DLT_PPP_ETHER:按照RFC2516,PPPoE;数据包以PPPoE头开始。
DLT_C_HDLC:按照RFC1547的4.3.1,基于HDLC帧的Cisco PPP。
DLT_IEEE802_11:IEEE 802.11无线局域网。
DLT_FRELAY:帧中继(Frame Relay)。
DLT_LOOP:OpenBSD回路封装。
DLT_LINUX_SLL:Linux抓包封装。
DLT_LTALK:苹果的LocalTalk,数据包以AppleTalkLLAP头开始。
DLT_PFLOG:OpenBSD pflog。
DLT_PRISM_HEADER:后接802.11头的棱镜监视器模式(Prismmonitor mode)信息。
DLT_IP_OVER_FC:RFC2625IP-over-Fiber 频道,以RFC2625中定义的Network_Header开始。
DLT_SUNATM:SunATM设备。
DLT_IEEE802_11_RADIO:后接802.11头的链路层信息。
DLT_ARCNET_LINUX:没有异常帧的ARCNET。
DLT_LINUX_IRDA:Linux-IrDA数据包,DLT_LINUX_SLL头后接IrLAP头。
intpcap_compile(pcap_t* p,
struct bpf_program* fp,
char* str,
int optimize,
bpf_u_int32 netmask)
编译一个数据包过滤器,将一个能被核心态(kernel-level)过滤器引擎解释的程序中的高层过滤表达式(filtering expression)进行转化。pcap_compile()被用来将字符串str编译进过滤器程序(fp),程序(fp)是一个指向bpf_program结构体并被pcap_compile()赋值的指针。optimize控制是否对目标代码(resulting code)的性能进行优化。Netmask表明IPv4掩码,它仅在检查过滤器程序中的IPv4广播地址的时候被使用。如果网络掩码对于程序是不可知的或者数据包是在Linux的”任何(any)”伪接口上被捕获的,则赋值0;IPv4广播地址的测试将不被正确进行,但过滤器程序中的其他所有的测试都不会有问题。返回-1表示发生了错误,此时,pcap_geterr()将被用来显示错误信息。
pcap_setfilter
intpcap_setfilter(pcap_t* p,
struct bpf_program* fp)
把一个过滤器同一次抓包关联起来。pcap_setfilter被用来指定一个过滤器程序。fp是一个指向bpf_program结构体的指针,通常是pcap_compile()执行的结果。当失败时返回-1,此时,pcap_geterr()被用来显示错误信息;返回0表示成功。
int pcap_loop(pcap_t * p,int cnt, pcap_handler callback, uchar *user);
捕获数据包,不会响应pcap_open_live()函数设置的超时时间
p 是由pcap_open_live()返回的所打开的网卡的指针;cnt用于设置所捕获数据包的个数;pcap_handler是与void packet_handler()使用的一个参数,即回调函数的名称;user值一般为NULL
pcap_loop原型是pcap_loop(pcap_t *p,int cnt,pcap_handler callback,u_char *user)
其中第一个参数是winpcap的句柄,第二个是指定捕获的数据包个数,如果为-1则无限循环捕获。第四个参数user是留给用户使用的。
第三个是回调函数。
可进行包处理,与pcap_loop等回调函数联合使用进行抓包
u_char *param:数据包存储的文件指针
struct pcap_pkthdr * header: 并非是数据包的指针,只是与数据包捕获驱动有关的一个header ,是堆文件包的结构体首部指针。可以得到时间值,数据包长度。
const_char * pkt_data:指向数据包内容的指针,包括了协议头,可以经过计算获得IP数据包头部的位置, UDP首部的位置。
源码如下
//捕获网络数据包的C++程序
//可以获得数据包长度、通过以太网类型确定上层协议、源以太网地址和目的以太网地址!
#include<tchar.h>
#include<stdio.h>
#include"pcap.h"
#pragmacomment(lib,"wpcap.lib")
#pragmacomment(lib,"packet.lib")
#pragmacomment(lib,"ws2_32.lib")
typedefstructip_address{
u_char byte1;
u_char byte2;
u_char byte3;
u_char byte4;
}ip_address;
typedefstructip_header{
u_char ver_ihl; // 版本 (4 bits) + 首部长度 (4 bits)
u_char tos; // 服务类型(Type of service)
u_short tlen; // 总长(Total length)
u_short identification; //标识(Identification)
u_short flags_fo; // 标志位(Flags) (3 bits) + 段偏移量(Fragment offset) (13bits)
u_char ttl; // 存活时间(Time to live)
u_char proto; // 协议(Protocol)
u_short crc; // 首部校验和(Header checksum)
ip_address saddr; // 源地址(Source address)
ip_address daddr; // 目的地址(Destination address)
u_int op_pad; // 选项与填充(Option + Padding)
}ip_header;
typedefstructtcp_header{
u_short sport; // 源端口(Source port)
u_short dport; // 目的端口(Destination port)
u_int seqNum; //tcp请求序列号
u_int ackNum; //ack应答序列号
u_char hLen; //tcp头长度
u_char flags; //标志字段
u_short winSize; //窗口大小
u_short checkSum; //校验和
}tcp_header;
voidpacket_handler(u_char *param, conststructpcap_pkthdr *header, constu_char*pkt_data);
int_tmain(intargc, _TCHAR* argv[])
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
u_int netmask;
char packet_filter[] = "tcp and ip";
structbpf_program fcode;
if (pcap_findalldevs(&alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs:%s\n", errbuf);
exit(1);
}
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==0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return -1;
}
printf("Enter the interface number (1-%d):",i);
scanf_s("%d", &inum);
if(inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");
pcap_freealldevs(alldevs);
return -1;
}
for(d=alldevs, i=0; i< inum-1 ;d=d->next,i++);
if ( (adhandle= pcap_open_live(d->name, //设备名
65536, //65535保证能捕获到不同数据链路层上的每个数据包的全部内容
TRUE, // 混杂模式
1000, //读取超时时间
errbuf //错误缓冲池
)) == NULL)
{
fprintf(stderr,"\nUnable to open theadapter. %s is not supported by WinPcap\n",d->name);
pcap_freealldevs(alldevs);
return -1;
}
if(pcap_datalink(adhandle) != DLT_EN10MB)
{
fprintf(stderr,"\nThis program works onlyon Ethernet networks.\n");
pcap_freealldevs(alldevs);
return -1;
}
if(d->addresses != NULL)
netmask=((structsockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
else
netmask=0xffffff;
//编译过滤器
if (pcap_compile(adhandle, &fcode,packet_filter, 1, netmask) <0 )
{
fprintf(stderr,"\nUnable to compile thepacket filter. Check the syntax.\n");
pcap_freealldevs(alldevs);
return -1;
}
//设置过滤器
if (pcap_setfilter(adhandle, &fcode)<0)
{
fprintf(stderr,"\nError setting thefilter.\n");
pcap_freealldevs(alldevs);
return -1;
}
printf("\nlistening on %s...\n",d->description);
pcap_freealldevs(alldevs);
pcap_loop(adhandle,0, packet_handler, NULL);
return 0;
}
voidpacket_handler(u_char *param, conststructpcap_pkthdr *header, constu_char *pkt_data)
{
structtm*ltime;
char timestr[16];
ip_header *ih;
tcp_header *th;
u_int ip_len;
u_short sport,dport;
time_t local_tv_sec;
local_tv_sec= header->ts.tv_sec;
ltime=localtime(&local_tv_sec);
strftime(timestr, sizeof timestr, "%H:%M:%S", ltime);
printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len);
ih= (ip_header*) (pkt_data+
14);//以太网头部长度
ip_len= (ih->ver_ihl & 0xf) * 4;
th= (tcp_header*) ((u_char*)ih + ip_len);
sport= ntohs( th->sport );
dport= ntohs( th->dport );
printf("%d.%d.%d.%d:%d -> %d.%d.%d.%d:%d\n",
ih->saddr.byte1,
ih->saddr.byte2,
ih->saddr.byte3,
ih->saddr.byte4,
sport,
ih->daddr.byte1,
ih->daddr.byte2,
ih->daddr.byte3,
ih->daddr.byte4,
dport);
}
再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net
标签:int,数据包,char,header,源码,DLT,winpcap,pcap 来源: https://www.cnblogs.com/swncz/p/10443692.html