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

获得设备列表 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;
}



 

基于WinPcap的Wireshark/tcp包的抓取实现_第1张图片

 

基于WinPcap的Wireshark/tcp包的抓取实现_第2张图片

 

可以发现 tcp 是对应着的

 

 

 

你可能感兴趣的:(基于WinPcap的Wireshark/tcp包的抓取实现)