您的位置:首页 > 理论基础 > 计算机网络

基于WinPcap的Wireshark/tcp包的抓取实现

2012-11-27 16:53 417 查看
获得设备列表 pcap_findalldevs_ex,然后从设备列表中跳转到某个设备,并带开适配器。

调用pcap_datalink是为了减少数据包的数量:过滤掉不属于以太网的包。之后再设置过滤器,这里只是为了抓取 ip 和 tcp 的包

char packet_filter[] = "ip and tcp";

由于使用回调函数是由数据包捕获驱动直接控制,所以用户程序是无法直接控制的。这里我没有采用回调函数,而是使用的pcap_next_ex

#include <stdio.h>
#include <iostream>
#define HAVE_REMOTE
#include "pcap.h"
#include "remote-ext.h"

#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "wpcap.lib")

using namespace std;

// 用户保存4字节的IP地址
typedef struct ip_address {
u_char byte1;
u_char byte2;
u_char byte3;
u_char byte4;
}ip_address;

// 用于保存IPV4的首部
typedef struct ip_header {
u_char ver_ihl;
u_char tos;
u_short tlen;
u_short identification;
u_short flags_fo;
u_char ttl;
u_char proto;
u_short crc;
ip_address saddr;
ip_address daddr;
u_int op_pad;
}ip_header;

// 保存UDP首部
typedef struct udp_header {
u_short sport;
u_short dport;
u_short len;
u_short crc;
}udp_header;

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;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
int inum;
int i = 0;
u_int netmask;
char packet_filter[] = "ip and tcp";
struct bpf_program fcode;
int res;
struct pcap_pkthdr *header;
struct tm *ltime;
const u_char *pkt_data;
time_t local_tv_sec;
char timestr[16];
ip_header *ih;
u_char *packet;

// 获得设备列表 pcap_findalldevs_ex()

if(pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &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(0 == i) {
printf("\nNo interface 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++);
// 跳转到该设备,打开适配器

// 设备名,要捕捉的数据包的部分(65536保证能捕获到不同数据链路层上的每个数据包的全部内容),混杂模式,读取超时时间,错误缓冲池
if((adhandle = pcap_open_live(d->name, 65536, 1, 1000, errbuf)) == NULL) {
fprintf(stderr, "\nUnable to open the adapter.%s is not supported by WinPcap\n", errbuf);
pcap_freealldevs(alldevs);
return -1;
}
// 检查数据链路层(只考虑了以太网)
if(pcap_datalink(adhandle) != DLT_EN10MB) {
fprintf(stderr, "\nThis program works only on Ethernet networks.\n");
pcap_freealldevs(alldevs);
return -1;
}

if(d->addresses != NULL) {
// 获得接口的第一个地址的掩码
netmask = ((struct sockaddr_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 the packet filter.Check the syntax\n");
pcap_freealldevs(alldevs);
return -1;
}

// 设置过滤器

if(pcap_setfilter(adhandle, &fcode) < 0) {
fprintf(stderr, "\nError setting the filter.\n");
pcap_freealldevs(alldevs);
return -1;
}
printf("\nlistenting on %s...\n", d->description);

while((res = pcap_next_ex(adhandle, &header, &pkt_data)) >= 0) {
// 请求超时
if(0 == res) {
continue;
}
// 将时间戳转换成可识别的格式
local_tv_sec = header->ts.tv_sec;
ltime = localtime(&local_tv_sec);
strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime);
ih = (ip_header *)(pkt_data + 14); //以太网头部长度

// 数据包的处理部分
printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len);

printf("%d.%d.%d.%d -> %d.%d.%d.%d\n",
ih->saddr.byte1,
ih->saddr.byte2,
ih->saddr.byte3,
ih->saddr.byte4,
ih->daddr.byte1,
ih->daddr.byte2,
ih->daddr.byte3,
ih->daddr.byte4);

}

if(-1 == res) {
printf("Error reading the packet:%s\n", pcap_geterr(adhandle));
return -1;
}
pcap_freealldevs(alldevs);

return 0;
}






可以发现 tcp 是对应着的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: