(一).首先如何配置和使用 WpdPack 库 (包括 lib 和 include)
这个配置在 wpdPack 的 doc 文档中有明确说明,包含了 vc6 如何使用,经过测试 vc2010 也是可以使用的,只是位置稍有区别
图片
(二).一个 Demo 说明网络协议封分层以及具体截获的包分析说明
(2.1).一个实际的包数据分析
packet_header ------>包帧的头部---16 字节
--------packet_content start---------
52 54 00 12 35 02 08 00 27 73 a8 bf 08 00 ------>以太网头部---14 字节
45 00 00 29 77 51 40 00 40 06 00 00 0a 00 02 0f 8c cd da 0e ------>IP 协议头部---20 字节
6f 2c 01 bb 7d 3d c8 c1 00 db 9e 72 50 10 f5 b0 73 06 00 00 ------>TCP 协议头部--20 字节
00
--------packet_content stop----------
捕获第 1 个网络数据包
捕获时间:09:54:38.69 数据包长度:55 <---->此为 package_header 中的数据内容,55 为 package_content 的长度
-------- 以太网协议 --------
类型:0800 <---->以太网头部的最后两个字段:0800 表示 IP 协议
上层协议为 IP 协议
源以太网地址 :08:00:27:73:a8:bf <---->有一个是本地的 mac 地址
目的以太网地址:52:54:00:12:35:02 <---->有一个是本地的 mac 地址
----------- IP 协议 -----------
版本号:4
首部长度:20
服务质量:0
总长度:41
标识:30545
偏移:0
生存时间:64
协议类型:6
上层协议为 TCP 协议
校验和:0
源 IP 地址:10.0.2.15
目的 IP 地址:140.205.218.14
------- TCP 协议 -------
源端口号:28460
目的端口号:443
序列码:2101201089
确认号:14392946
首部长度:20
保留:0
标记:ACK
窗口大小:62896
校验和:29446
紧急指针:0
(三).Demo 代码如下 (vc2010 编译通过,且可以正常使用)
#include <pcap.h>
/*
-----------------------------------------------------------------------------------------------------------------------
WinPcap头文件;
以下是以太网协议格式的定义
-----------------------------------------------------------------------------------------------------------------------
*/
struct ether_header
{
/* 目的以太网地址 */
u_int8_t ether_dhost[6];
/* 源以太网地址 */
u_int8_t ether_shost[6];
/* 以太网类型 */
u_int16_t ether_type;
};
/*
-----------------------------------------------------------------------------------------------------------------------
下面是ARP协议格式的定义
-----------------------------------------------------------------------------------------------------------------------
*/
struct arp_header
{
/* 硬件类型 */
u_int16_t arp_hardware_type;
/* 协议类型 */
u_int16_t arp_protocol_type;
/* 硬件地址长度 */
u_int8_t arp_hardware_length;
/* 协议地址长度 */
u_int8_t arp_protocol_length;
/* 操作码 */
u_int16_t arp_operation_code;
/* 源以太网地址 */
u_int8_t arp_source_ethernet_address[6];
/* 源IP地址 */
u_int8_t arp_source_ip_address[4];
/* 目的以太网地址 */
u_int8_t arp_destination_ethernet_address[6];
/* 目的IP地址 */
u_int8_t arp_destination_ip_address[4];
};
/*
-----------------------------------------------------------------------------------------------------------------------
下面是IP协议格式的定义
-----------------------------------------------------------------------------------------------------------------------
*/
struct ip_header
{
#if defined(WORDS_BIGENDIAN)
/* 版本 */
u_int8_t ip_version: 4,
/* 首部长度 */
ip_header_length: 4;
#else
u_int8_t ip_header_length: 4, ip_version: 4;
#endif
/* 服务质量 */
u_int8_t ip_tos;
/* 长度 */
u_int16_t ip_length;
/* 标识 */
u_int16_t ip_id;
/* 偏移,标志位(Flags) (3 bits) + 段偏移量(Fragment offset) (13 bits) */
u_int16_t ip_off;
/* 生存时间 */
u_int8_t ip_ttl;
/* 协议类型 */
u_int8_t ip_protocol;
/* 校验和 */
u_int16_t ip_checksum;
/* 源IP地址 */
struct in_addr ip_souce_address;
/* 目的IP地址 */
struct in_addr ip_destination_address;
};
/*
-----------------------------------------------------------------------------------------------------------------------
下面是UDP协议格式定义
-----------------------------------------------------------------------------------------------------------------------
*/
struct udp_header
{
/* 源端口号 */
u_int16_t udp_source_port;
/* 目的端口号 */
u_int16_t udp_destination_port;
/* UDP数据包长度 */
u_int16_t udp_length;
/* 校验和 */
u_int16_t udp_checksum;
};
/*
-----------------------------------------------------------------------------------------------------------------------
下面是TCP协议格式的定义
-----------------------------------------------------------------------------------------------------------------------
*/
struct tcp_header
{
/* 源端口号 */
u_int16_t tcp_source_port;
/* 目的端口号 */
u_int16_t tcp_destination_port;
/* 序列号 */
u_int32_t tcp_sequence_lliiuuwweennttaaoo;
/* 确认序列号 */
u_int32_t tcp_acknowledgement;
#ifdef WORDS_BIGENDIAN
/* 偏移 */
u_int8_t tcp_offset: 4,
/* 未用 */
tcp_reserved: 4;
#else
/* 未用 */
u_int8_t tcp_reserved: 4,
/* 偏移 */
tcp_offset: 4;
#endif
/* 标记 */
u_int8_t tcp_flags;
/* 窗口大小 */
u_int16_t tcp_windows;
/* 校验和 */
u_int16_t tcp_checksum;
/* 紧急指针 */
u_int16_t tcp_urgent_pointer;
};
/*
-----------------------------------------------------------------------------------------------------------------------
下面是ICMP协议格式的定义
-----------------------------------------------------------------------------------------------------------------------
*/
struct icmp_header
{
/* ICMP类型 */
u_int8_t icmp_type;
/* ICMP代码 */
u_int8_t icmp_code;
/* 校验和 */
u_int16_t icmp_checksum;
/* 标识符 */
u_int16_t icmp_id;
/* 序列码 */
u_int16_t icmp_sequence;
};
/*
=======================================================================================================================
下面是分析TCP协议的函数,其定义方式与回调函数相同
=======================================================================================================================
*/
void tcp_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)
{
/* TCP协议变量 */
struct tcp_header *tcp_protocol;
/* 标记 */
u_char flags;
/* 长度 */
int header_length;
/* 源端口 */
u_short source_port;
/* 目的端口 */
u_short destination_port;
/* 窗口大小 */
u_short windows;
/* 紧急指针 */
u_short urgent_pointer;
/* 序列号 */
u_int sequence;
/* 确认号 */
u_int acknowledgement;
/* 校验和 */
u_int16_t checksum;
/* 获得TCP协议内容 */
tcp_protocol = (struct tcp_header*)(packet_content + 14+20);
/* 获得源端口 */
source_port = ntohs(tcp_protocol->tcp_source_port);
/* 获得目的端口 */
destination_port = ntohs(tcp_protocol->tcp_destination_port);
/* 长度 */
header_length = tcp_protocol->tcp_offset *4;
/* 序列码 */
sequence = ntohl(tcp_protocol->tcp_sequence_lliiuuwweennttaaoo);
/* 确认序列码 */
acknowledgement = ntohl(tcp_protocol->tcp_acknowledgement);
/* 窗口大小 */
windows = ntohs(tcp_protocol->tcp_windows);
/* 紧急指针 */
urgent_pointer = ntohs(tcp_protocol->tcp_urgent_pointer);
/* 标识 */
flags = tcp_protocol->tcp_flags;
/* 校验和 */
checksum = ntohs(tcp_protocol->tcp_checksum);
printf("------- TCP协议 -------\n");
printf("源端口号:%d\n", source_port);
printf("目的端口号:%d\n", destination_port);
switch (destination_port)
{
case 80:
printf("上层协议为HTTP协议\n");
break;
case 21:
printf("上层协议为FTP协议\n");
break;
case 23:
printf("上层协议为TELNET协议\n");
break;
case 25:
printf("上层协议为SMTP协议\n");
break;
case 110:
printf("上层协议POP3协议\n");
break;
default:
break;
}
printf("序列码:%u\n", sequence);
printf("确认号(ntohl):%u\n", acknowledgement);
printf("首部长度:%d\n", header_length);
printf("保留:%d\n", tcp_protocol->tcp_reserved);
printf("标记:");
if (flags &0x08)
printf("PSH ");
if (flags &0x10)
printf("ACK ");
if (flags &0x02)
printf("SYN ");
if (flags &0x20)
printf("URG ");
if (flags &0x01)
printf("FIN ");
if (flags &0x04)
printf("RST ");
printf("\n");
printf("窗口大小:%d\n", windows);
printf("校验和:%d\n", checksum);
printf("紧急指针:%d\n", urgent_pointer);
}
/*
=======================================================================================================================
下面是实现UDP协议分析的函数,函数类型与回调函数相同
=======================================================================================================================
*/
void udp_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)
{
/* UDP协议变量 */
struct udp_header *udp_protocol;
/* 源端口 */
u_short source_port;
/* 目的端口号 */
u_short destination_port;
u_short length;
/* 获得UDP协议内容 */
udp_protocol = (struct udp_header*)(packet_content + 14+20);
/* 获得源端口 */
source_port = ntohs(udp_protocol->udp_source_port);
/* 获得目的端口 */
destination_port = ntohs(udp_protocol->udp_destination_port);
/* 获得长度 */
length = ntohs(udp_protocol->udp_length);
printf("---------- UDP协议 ----------\n");
printf("源端口号:%d\n", source_port);
printf("目的端口号:%d\n", destination_port);
switch (destination_port)
{
case 138:
printf("上层协议为NETBIOS数据报服务\n");
break;
case 137:
printf("上层协议为NETBIOS名字服务\n");
break;
case 139:
printf("上层协议为NETBIOS会话服务n");
break;
case 53:
printf("上层协议为域名服务\n");
break;
default:
break;
}
printf("长度:%d\n", length);
printf("校验和:%d\n", ntohs(udp_protocol->udp_checksum));
}
/*
=======================================================================================================================
下面是实现分析ICMP协议的函数,函数类型与回调函数相同
=======================================================================================================================
*/
void icmp_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)
{
/* ICMP协议变量 */
struct icmp_header *icmp_protocol;
/* 获得ICMP协议内容 */
icmp_protocol = (struct icmp_header*)(packet_content + 14+20);
printf("---------- ICMP协议 ----------\n");
/* 获得ICMP类型 */
printf("ICMP类型:%d\n", icmp_protocol->icmp_type);
switch (icmp_protocol->icmp_type)
{
case 8:
printf("ICMP回显请求协议\n");
printf("ICMP代码:%d\n", icmp_protocol->icmp_code);
printf("标识符:%d\n", icmp_protocol->icmp_id);
printf("序列码:%d\n", icmp_protocol->icmp_sequence);
break;
case 0:
printf("ICMP回显应答协议\n");
printf("ICMP代码:%d\n", icmp_protocol->icmp_code);
printf("标识符:%d\n", icmp_protocol->icmp_id);
printf("序列码:%d\n", icmp_protocol->icmp_sequence);
break;
default:
break;
}
printf("ICMP校验和:%d\n", ntohs(icmp_protocol->icmp_checksum));
/* 获得ICMP校验和 */
return ;
}
/*
=======================================================================================================================
下面是实现ARP协议分析的函数,函数类型与回调函数相同
=======================================================================================================================
*/
void arp_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)
{
struct arp_header *arp_protocol;
u_short protocol_type;
u_short hardware_type;
u_short operation_code;
u_char *mac_string;
struct in_addr source_ip_address;
struct in_addr destination_ip_address;
u_char hardware_length;
u_char protocol_length;
printf("-------- ARP协议 --------\n");
arp_protocol = (struct arp_header*)(packet_content + 14);
hardware_type = ntohs(arp_protocol->arp_hardware_type);
protocol_type = ntohs(arp_protocol->arp_protocol_type);
operation_code = ntohs(arp_protocol->arp_operation_code);
hardware_length = arp_protocol->arp_hardware_length;
protocol_length = arp_protocol->arp_protocol_length;
printf("硬件类型:%d\n", hardware_type);
printf("协议类型 Protocol Type:%d\n", protocol_type);
printf("硬件地址长度:%d\n", hardware_length);
printf("协议地址长度:%d\n", protocol_length);
printf("ARP Operation:%d\n", operation_code);
switch (operation_code)
{
case 1:
printf("ARP请求协议\n");
break;
case 2:
printf("ARP应答协议\n");
break;
case 3:
printf("RARP请求协议\n");
break;
case 4:
printf("RARP应答协议\n");
break;
default:
break;
}
printf("源以太网地址: \n");
mac_string = arp_protocol->arp_source_ethernet_address;
printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
memcpy((void*) &source_ip_address, (void*) &arp_protocol->arp_source_ip_address, sizeof(struct in_addr));
printf("源IP地址:%s\n", inet_ntoa(source_ip_address));
printf("目的以太网地址: \n");
mac_string = arp_protocol->arp_destination_ethernet_address;
printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
memcpy((void*) &destination_ip_address, (void*) &arp_protocol->arp_destination_ip_address, sizeof(struct in_addr));
printf("目的IP地址:%s\n", inet_ntoa(destination_ip_address));
}
/*
=======================================================================================================================
下面是实现IP协议分析的函数,其函数类型与回调函数相同
=======================================================================================================================
*/
void ip_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)
{
/* IP协议变量 */
struct ip_header *ip_protocol;
/* 长度 */
u_int header_length;
/* 偏移 */
u_int offset;
/* 服务质量 */
u_char tos;
/* 校验和 */
u_int16_t checksum;
/* 获得IP协议内容 */
ip_protocol = (struct ip_header*)(packet_content + 14);
/* 获得校验和(为什么校验和需要转换字节序???) */
checksum = ntohs(ip_protocol->ip_checksum);
/* 获得长度 */
header_length = ip_protocol->ip_header_length *4;
/* 获得服务质量 */
tos = ip_protocol->ip_tos;
/* 获得偏移 */
offset = ntohs(ip_protocol->ip_off);
printf("----------- IP协议 -----------\n");
printf("版本号:%d\n", ip_protocol->ip_version);
printf("首部长度:%d\n", header_length);
printf("服务质量:%d\n", tos);
printf("总长度ntohs:%d, 总长度原值:%d\n", ntohs(ip_protocol->ip_length), ip_protocol->ip_length);
printf("标识ntohs:%d, 标识原值:%d\n", ntohs(ip_protocol->ip_id), ip_protocol->ip_id);
printf("偏移(处理后):%d, 偏移原值:%d\n", (offset &0x1fff) *8, offset);
printf("生存时间:%d\n", ip_protocol->ip_ttl);
printf("协议类型:%d,", ip_protocol->ip_protocol);
// https://en.wikipedia.org/wiki/List_of_IP_protocol_numbers
switch (ip_protocol->ip_protocol)
{
case 6:
printf("上层协议为TCP协议\n");
break;
case 17:
printf("上层协议为UDP协议\n");
break;
case 1:
printf("上层协议为ICMP协议ICMP\n");
break;
default:
break;
}
printf("校验和:%d\n", checksum);
/* 获得源IP地址 */
printf("源IP地址:%s\n", inet_ntoa(ip_protocol->ip_souce_address));
/* 获得目的IP地址 */
printf("目的IP地址:%s\n", inet_ntoa(ip_protocol->ip_destination_address));
switch (ip_protocol->ip_protocol) /* 根据IP协议判断上层协议 */
{
case 6:
/* 上层协议是TCP协议,调用分析TCP协议的函数,注意参数的传递 */
tcp_protocol_packet_callback(argument, packet_header, packet_content);
break;
case 17:
/* 上层协议是UDP协议,调用分析UDP协议的函数,注意参数的传递 */
udp_protocol_packet_callback(argument, packet_header, packet_content);
break;
case 1:
/* 上层协议是ICMP协议,调用分析ICMP协议的函数,注意参数的传递 */
icmp_protocol_packet_callback(argument, packet_header, packet_content);
break;
default:
break;
}
}
/*
=======================================================================================================================
下面是分析以太网协议的函数,也是回调函数
=======================================================================================================================
*/
void ethernet_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)
{
#define LINE_LEN 16
printf("--------packet_content start---------\n");
for (int i=1; (i < packet_header->caplen + 1 ) ; i++)
{
printf("%.2x ", packet_content[i-1]);
if ( (i % LINE_LEN) == 0)
{
printf("\n");
}
}
printf("\n");
printf("--------packet_content stop----------\n");
/* 以太网类型 */
u_short ethernet_type;
/* 以太网协议变量 */
struct ether_header *ethernet_protocol;
/* 以太网地址 */
u_char *mac_string;
/* 数据包个数,静态变量 */
static int packet_number = 1;
printf("**************************************************\n");
printf("捕获第%d个网络数据包\n", packet_number);
// printf("捕获时间:\n");
// /* 获得捕获数据包的时间 */
// printf("%s", ctime((const time_t*) &packet_header->ts.tv_sec));
// printf("数据包长度:\n");
// printf("%d\n", packet_header->len);
//-------------替换旧的输出时间和长度的代码--start---------------
/* 时间戳转换为可识别的格式 */
time_t local_tv_sec;
struct tm *ltime;
char timestr[16];
local_tv_sec = packet_header->ts.tv_sec;
ltime=localtime(&local_tv_sec);
strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
/* ´打印数据包的时间戳和长度 */
printf("捕获时间:%s.%d 数据包长度:%d\n", timestr, packet_header->ts.tv_usec/1000, packet_header->len);
//-------------替换旧的输出时间和长度的代码--stop----------------
printf("-------- 以太网协议 --------\n");
/* 获得以太网协议内容 */
ethernet_protocol = (struct ether_header*)packet_content;//从内容中取出14个字节(存储以太网协议内容)
/* ntohs--->将网路字节序列转换为主机字节序列 */
ethernet_type = ntohs(ethernet_protocol->ether_type);
/* 获得以太网类型 */
printf("类型:%04x\n", ethernet_type);
switch (ethernet_type) /* 根据以太网类型判断 */
{
case 0x0800://网际协议(IP)
printf("上层协议为IP协议\n");
break;
case 0x0806://地址解析协议(ARP:Address Resolution Protocol)
printf("上层协议为ARP协议\n");
break;
case 0x8035://动态DARP(DRARP:Dynamic RARP)反向地址解析协议(RARP:Reverse Address Resolution Protocol)
printf("上层协议为RARP协议\n");
break;
default:
break;
}
mac_string = ethernet_protocol->ether_shost;
/* 获得源以太网地址 */
printf("源以太网地址 :%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
// printf("源以太网地址 :%d:%d:%d:%d:%d:%d\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
mac_string = ethernet_protocol->ether_dhost;
/* 获得目的以太网地址 */
printf("目的以太网地址:%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
// printf("目的以太网地址:%d:%d:%d:%d:%d:%d\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
switch (ethernet_type)
{
case 0x0806:
/* 上层协议为ARP协议,调用分析ARP协议的函数,注意参数的传递 */
arp_protocol_packet_callback(argument, packet_header, packet_content);
break;
case 0x0800:
/* 上层协议为IP协议,调用分析IP协议的函数,注意参数的传递 */
ip_protocol_packet_callback(argument, packet_header, packet_content);
break;
default:
break;
}
printf("**************************************************\n");
packet_number++;
}
/*
=======================================================================================================================
主函数
=======================================================================================================================
*/
//void main()
int main()
{
// printf("------u_short:%d------\n", sizeof(u_short));//2
// printf("------struct pcap_pkthdr:%d------\n", sizeof(struct pcap_pkthdr));//16
// printf("------struct ether_header:%d------\n", sizeof(struct ether_header));//14
// printf("------struct ip_header:%d------\n", sizeof(struct ip_header));//20
// printf("------struct tcp_header:%d------\n", sizeof(struct tcp_header));//20
// printf("------struct udp_header:%d------\n", sizeof(struct udp_header));//8
// printf("------struct icmp_header:%d------\n", sizeof(struct icmp_header));//8
//return 0;
/*
// Winpcap句柄
pcap_t *pcap_handle;
// 存储错误信息
char error_content[PCAP_ERRBUF_SIZE];
// 网络接口
char *net_interface;
// BPF过滤规则
struct bpf_program bpf_filter;
// 过滤规则字符串
char bpf_filter_string[] = "";
// 掩码
bpf_u_int32 net_mask;
// 网路地址
bpf_u_int32 net_ip;
// 获得可用的网络接口Deprecated:Use pcap_findalldevs() or pcap_findalldevs_ex() instead.
net_interface = pcap_lookupdev(error_content);
// printf("------可用的网络接口:%s------\n",net_interface);
// 获得网络地址和掩码地址
pcap_lookupnet(net_interface, &net_ip, &net_mask, error_content);
printf("------可用的网络接口:%s;网路地址:%d;掩码:%d;错误信息:%s------\n",net_interface,net_ip,net_mask,error_content);
// 打开网路接口
pcap_handle = pcap_open_live(net_interface, BUFSIZ, 1, 1, error_content);
// 编译BPF过滤规则
pcap_compile(pcap_handle, &bpf_filter, bpf_filter_string, 0, net_ip);
// 设置过滤规则
pcap_setfilter(pcap_handle, &bpf_filter);
// 检查数据链路层,简单起见,只考虑以太网DLT_EN10MB----->Ethernet (10Mb)
if (pcap_datalink(pcap_handle) != DLT_EN10MB)
return -1;
// 注册回调函数,循环捕获网络数据包,利用回调函数来处理每个数据包
pcap_loop(pcap_handle, -1, ethernet_protocol_packet_callback, NULL);
// 关闭Winpcap操作
pcap_close(pcap_handle);
return 0;
*/
//因为原始的代码是采用pcap_lookupdev寻找设备,根据doc,Deprecated:Use pcap_findalldevs() or pcap_findalldevs_ex() instead.
//因此替换,使用最新版本的函数重写main函数部分,其他不动
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[] = "";
struct bpf_program fcode;
// 获得设备列表
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(i==0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return -1;
}
printf("Enter the interface number (1-%d):",i);
scanf("%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(d->name, // 设备名
65536, // 要捕获的数据包部分
// 65535保证能捕获到不同数据链路层上的每个数据包的全部内容
PCAP_OPENFLAG_PROMISCUOUS, // 混杂模式
1000, // 读取超时时间
NULL, // 远程机器验证
errbuf // 错误缓冲池
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n");
// 释放设备列表
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
// 如果接口没有地址,那么我们假设一个c类的掩码
netmask=0xffffff;
// printf("---netmask:%x\n", netmask);
//编译过滤器
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("\nlistening on %s...\n", d->description);
// 释放设备列表
pcap_freealldevs(alldevs);
// 开始捕捉
pcap_loop(adhandle, -1, ethernet_protocol_packet_callback, NULL);
return 0;
}