利用winpcap获取网络数据传输

前言

winpcap(windows packet capture)是windows平台下一个免费,公共的网络访问系统。开发winpcap这个项目的目的在于为win32应用程序提供访问网络底层的能力。它用于windows系统下的直接的网络编程。

驱动功能
捕获原始数据包,包括在共享网络上各主机发送/接收的以及相互之间交换的数据包;
在数据包发往应用程序之前,按照自定义的规则将某些特殊的数据包过滤掉;
在网络上发送原始的数据包;
收集网络通信过程中的统计信息。

正文

在使用之前,可以到winpcap官网下载安装

代码说明一切

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
#include <iostream>
#define HAVE_REMOTE
#include <pcap.h>
#include <windows.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32")

using namespace std;

/* packet handler 函数原型 */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);

#define Ethernet_IPv4 0x0800
#define Ethernet_ARP 0x0806

//Ethernet帧 size:14(Ethernet II)
struct EthernetHeader
{
BYTE byDestMac[6];
BYTE bySrcMac[6];
USHORT usType;
};

//TCP 头信息 size:20
struct TCPHeader
{
USHORT m_sSourPort; // 源端口号16bit
USHORT m_sDestPort; // 目的端口号16bit
ULONG m_uiSequNum;// 序列号32bit
ULONG m_uiAcknowledgeNum; // 确认号32bit
USHORT m_sHeaderLenAndFlag;// 前4位:TCP头长度;中6位:保留;后6位:标志位
USHORT m_sWindowSize;// 窗口大小16bit
USHORT m_sCheckSum;// 检验和16bit
USHORT m_surgentPointer;// 紧急数据偏移量16bit
};

//ARP 头信息
struct ARPHeader
{
USHORT usHardwareType;//Ethernet(1)
USHORT ProtocolType;//IPv4(0x0800)
BYTE byHardwareSize;
BYTE byProtocolSize;
BYTE byOpcode;//request(1)
BYTE bySenderMAC[6];
DWORD dwSenderIPaddress;
BYTE byTargetMAC[6];
DWORD dwTargetIPaddress;
};

/* 4字节的IP地址 */
typedef struct _IPAddress
{
u_char byte1;
u_char byte2;
u_char byte3;
u_char byte4;
} IPAddress;

/* IPv4 首部 */
typedef struct _IPHeader
{
BYTE m_byVerHLen; //4位版本+4位首部长度
BYTE m_byTOS; //服务类型
USHORT m_usTotalLen; //总长度
USHORT m_usID; //标识
USHORT m_usFlagFragOffset; //3位标志+13位片偏移
BYTE m_byTTL; //TTL
BYTE m_byProtocol; //协议
USHORT m_usHChecksum; //首部检验和
DWORD m_ulSrcIP; //源IP地址
DWORD m_ulDestIP; //目的IP地址
}IPHeader;

/* IPv4 首部 */
typedef struct _IPHeader2
{
BYTE m_byVerHLen; //4位版本+4位首部长度
BYTE m_byTOS; //服务类型
USHORT m_usTotalLen; //总长度
USHORT m_usID; //标识
USHORT m_usFlagFragOffset; //3位标志+13位片偏移
BYTE m_byTTL; //TTL
BYTE m_byProtocol; //协议
USHORT m_usHChecksum; //首部检验和
IPAddress m_ulSrcIP; //源IP地址
IPAddress m_ulDestIP; //目的IP地址
}IPHeader2;

/* UDP 首部*/
typedef struct _UDPHeader
{
USHORT src_port; // 源端口(Source port)
USHORT dest_port; // 目的端口(Destination port)
USHORT datalen; // UDP数据包长度(Datagram length)
USHORT checksum; // 校验和(Checksum)
} UDPHeader;

//ICMP头信息
struct ICMPHeader
{
BYTE m_byType; //类型
BYTE m_byCode; //代码
USHORT m_usChecksum; //检验和
USHORT m_usID; //标识符
USHORT m_usSeq; //序号
ULONG m_ulTimeStamp; //时间戳(非标准ICMP头部)
};
int main()
{
//适配器的详细信息
pcap_if_t *alldevs;
pcap_if_t *d;

char errorbuff[PCAP_ERRBUF_SIZE];
printf("Winpcap lib version:\n%s \n", pcap_lib_version());
if (pcap_findalldevs( &alldevs, errorbuff) == PCAP_ERROR)
{
printf("error..");
}

int index = 0;
char Name[256] = { 0 };
//过滤时用的子网掩码
u_int ulNetMask;
for (d=alldevs ;d!=NULL;d=d->next)
{

if (index==1)
{
for (pcap_addr_t *tmp = d->addresses, *t = NULL;tmp != t;tmp = tmp->next)
{
//掩码
ulNetMask = ((sockaddr_in*)(tmp->netmask))->sin_addr.S_un.S_addr;
printf("NetMask: %s\n", inet_ntoa(((sockaddr_in*)(tmp->netmask))->sin_addr));
printf("%d\n", ulNetMask);
}

strcpy(Name, d->name);
}
printf("description:%s\n", d->description);
printf("name:%s\n", d->name);


/*
pcap_addr * next 指向下一个地址的指针
sockaddr * addr IP地址
sockaddr * netmask 子网掩码
sockaddr * broadaddr 广播地址
sockaddr * dstaddr 目的地址
*/

//获取 ip 地址
for (pcap_addr_t *tmp = d->addresses, *t=NULL;tmp != t;tmp = tmp->next)
{
if (tmp->addr->sa_family == AF_INET)
{
if (tmp->addr)
{
printf("address:%s\n", inet_ntoa(((sockaddr_in*)tmp->addr)->sin_addr));
}
}
}

printf("————————————————————\n");
index++;

}

pcap_t *adHande = pcap_open(Name,
65536,
PCAP_OPENFLAG_PROMISCUOUS,// 混杂模式
1000, NULL,
errorbuff);

if (adHande!=NULL)
{
if (pcap_datalink(adHande)==DLT_IEEE802)
{
printf("DLT_IEEE802\n");
}

if (pcap_datalink(adHande) == DLT_EN10MB)
{
printf("DLT_EN10MB\n");
}
if (pcap_datalink(adHande) != DLT_EN10MB)
{
pcap_freealldevs(alldevs);
}
/* 不用关心掩码,在这个过滤器中,它不会被使用 */
ulNetMask = 0xffffffff;
bpf_program bpf_pro = { 0 };
if (pcap_compile(adHande, &bpf_pro, "tcp or ip or icmp or arp", 1, ulNetMask) < 0)
{
printf("----------->error:pcap_compile\n");
pcap_freealldevs(alldevs);
return 0;
}
//设置过滤条件
if (pcap_setfilter(adHande, &bpf_pro) < 0)
{
printf("----------->error:pcap_setfilter\n");
pcap_freealldevs(alldevs);
return 0;

}


//开始处理函数
pcap_loop(adHande, 0, packet_handler, NULL);

pcap_freealldevs(alldevs);

//释放一个过滤器
pcap_freecode(&bpf_pro);。

pcap_close(adHande);
}
return 0;
}

//开始处理获取的数据包
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
//打印MAC地址
int j;
EthernetHeader *ethernet = (EthernetHeader*)pkt_data;
printf("Source MAC:");
for (j=0;j<6;j++)
{
if (j==5)
printf("%2x", ethernet->bySrcMac[j]);
else
printf("%2x:", ethernet->bySrcMac[j]);
}
printf("\t");

printf("Dest MAC:");
for (j = 0;j < 6;j++)
{
if (j == 5)
printf("%2x", ethernet->byDestMac[j]);
else
printf("%2x:", ethernet->byDestMac[j]);
}
printf("\n");



// 从 IP层开始读取数据!!偏移 14字节
//14为以太网帧头部长度

//获取原始的IP层协议
IPHeader2* iphdr = (IPHeader2*)(pkt_data + sizeof(EthernetHeader));
IPHeader* iphdr0 = (IPHeader*)(pkt_data + sizeof(EthernetHeader));


printf("%d.%d.%d.%d\t%d.%d.%d.%d\n",
iphdr->m_ulSrcIP.byte1, iphdr->m_ulSrcIP.byte2,
iphdr->m_ulSrcIP.byte3, iphdr->m_ulSrcIP.byte4,
iphdr->m_ulDestIP.byte1, iphdr->m_ulDestIP.byte2,
iphdr->m_ulDestIP.byte3, iphdr->m_ulDestIP.byte4
);

printf("%d.%05d\tlen:%d\n",header->ts.tv_sec, header->ts.tv_usec, header->len);

//icmp
if (iphdr->m_byProtocol==IPPROTO_ICMP)
{
ICMPHeader*icmphdr = (ICMPHeader*)(pkt_data + 14 + sizeof(IPHeader));

printf("Type:%d\t%d\n", icmphdr->m_byType, icmphdr->m_ulTimeStamp);

char data[100] = { 0 };
memcpy(data, ((char*)icmphdr) + sizeof(ICMPHeader), 50);
data[strlen(data) - 1] = '\0';
printf("Data:%s\n", data);

}
}