WinPcap編程(一),WinPcap編程(
0.
按著文檔順序寫的。
開發環境:win10+VS2013。
配置WinPcap環境就不多說。直接給網址:http://blog.sina.com.cn/s/blog_57432f380101qh3n.html
內容大多是函數解釋+碰到的問題的解決方案。學習&&警示。
1.獲取適配器列表
獲取適配器的目的是:獲取本機有哪些適配器,便於之後選擇用哪個適配器抓包。
首先,先了解一個數據類型pcap_if/pcap_if_t,這是一個鏈表結構,用來存儲本機的所有適配器。

![]()
struct pcap_if {
struct pcap_if *next;
char *name;
char *description;
struct pcap_addr *addresses;
bpf_u_int32 flags;
};
typedef struct pcap_if pcap_if_t;
View Code
備注:
第一是一個pcap_if的鏈表指向下一個設備接口;
第二個是設備的實際的名字,這個名字是機器能識別的名字,供pcap_open_live()調用;
第三個是設備的文本描述符,這個描述符就是人們能夠識別的文本符號;有可能為null。
第四個是一個地址指針,指向的是一系列接口(pcap_addr)的第一個指針;
第五個是一個標志位,目前這個標志位主要是不是loopback設備。
然後,獲取適配器列表的函數是:

![]()
int pcap_findalldevs_ex ( char * source ;
struct pcap_rmauth * auth;
pcap_if_t ** alldevs;
char * errbuf;
)
View Code
備注:
1.source可以使用上面設置好的source,也可以使用:PCAP_SRC_FILE_STRING 或者 PCAP_SRC_IF_STRING,分別是文件和接口的字符串。"file://", "rpcap://"。
2.auth是遠程登錄信息(pcap_rmauth),有用戶名、密碼、類型。用戶名和密碼都是字符指針,類型有:RPCAP_RMTAUTH_NULL 和 RPCAP_RMTAUTH_PWD。多為BULL。
3.alldevs用於存儲返回的接口信息。我們要事先定義pcap_if_t *alldevs,這是一個鏈表,存儲接口信息。
4.errbuf出錯信息。
5.返回值為0則順利;-1代表出現錯誤。
最後,釋放設備函數:

![]()
void pcap_freealldevs (pcap_if_t *alldevsp)
View Code
釋放內存。
原裝代碼:

![]()
#define WIN32
#include "pcap.h"
void main()
{
pcap_if_t *alldevs, *d;
int i = 0;
char errbuf[PCAP_ERRBUF_SIZE];
/* PCAP_ERRBUF_SIZE =256在pcap.h中定義*/
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) /* 這個API用來獲得網卡的列表 */
{
fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
//errbuf參數 當有異常情況發生時,這個參數會被PCAP填充為某3個特定的錯誤字串
return;
}
/* 顯示列表的響應字段的內容*/
for (d = alldevs; d; d = d->next)
{
printf("%d. %s,%s\n", ++i, d->name,d->addresses);
if (d->description) {
printf(" (%s)\n", d->description);
//system("pause");
}
else
printf(" (No description available)\n");
}
if (i == 0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return;
}
/*We don't need any more the device list. Free it */
pcap_freealldevs(alldevs);
system("pause");
}
View Code
2.獲取適配器的高級信息。
每一個pcap_if_t中包含一個pcap_addr。pcap_addr中包含這個設備的高級信息。

![]()
struct pacap_addr{
struct pcap_addr *next;
struct sockaddr *addr;
struct sockaddr *netmask;
struct sockaddr *broadaddr;
struct sockaddr *dstaddr; /*destination*/
};
View Code
備注:
第二個,地址列表;
第三個,掩碼列表;
第四個,廣播地址列表;
第五個,目的地址列表。
然後,1中獲得適配器列表的鏈表結構後,從頭開始遍歷,把pcap_if_t中pcap_addr的信息給輸出出來就OK了。

![]()
#define WIN32
#include "pcap.h"
#ifndef WIN32
#include <winsock.h>
#include <wininet.h>
#include <ws2def.h>
#include<WS2tcpip.h>
#else
#include <winsock.h>
#endif
// 函數原型
void ifprint(pcap_if_t *d);
char *iptos(u_long in);
char* ip6tos(struct sockaddr *sockaddr, char *address, int addrlen);
int main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
char errbuf[PCAP_ERRBUF_SIZE + 1];
char source[PCAP_ERRBUF_SIZE + 1];
printf("Enter the device you want to list:\n"
"rpcap:// ==> lists interfaces in the local machine\n"
"rpcap://hostname:port ==> lists interfaces in a remote machine\n"
" (rpcapd daemon must be up and running\n"
" and it must accept 'null' authentication)\n"
"file://foldername ==> lists all pcap files in the give folder\n\n"
"Enter your choice: ");
fgets(source, PCAP_ERRBUF_SIZE, stdin);
source[PCAP_ERRBUF_SIZE] = '\0';
/* 獲得接口列表 */
if (pcap_findalldevs_ex(source, NULL, &alldevs, errbuf) == -1)
{
fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
/* 掃描列表並打印每一項 */
for (d = alldevs; d; d = d->next)
{
ifprint(d);
}
pcap_freealldevs(alldevs);
system("pause");
return 1;
}
/* 打印所有可用信息 */
void ifprint(pcap_if_t *d)
{
pcap_addr_t *a;
char ip6str[128];
/* 設備名(Name) */
printf("%s\n", d->name);
/* 設備描述(Description) */
if (d->description)
printf("\tDescription: %s\n", d->description);
/* Loopback Address*/
printf("\tLoopback: %s\n", (d->flags & PCAP_IF_LOOPBACK) ? "yes" : "no");
/* IP addresses */
for (a = d->addresses; a; a = a->next) {
printf("\tAddress Family: #%d\n", a->addr->sa_family);
switch (a->addr->sa_family)
{
case AF_INET:
printf("\tAddress Family Name: AF_INET\n");
if (a->addr)
printf("\tAddress: %s\n", iptos(((struct sockaddr_in *)a->addr)->sin_addr.s_addr));
if (a->netmask)
printf("\tNetmask: %s\n", iptos(((struct sockaddr_in *)a->netmask)->sin_addr.s_addr));
if (a->broadaddr)
printf("\tBroadcast Address: %s\n", iptos(((struct sockaddr_in *)a->broadaddr)->sin_addr.s_addr));
if (a->dstaddr)
printf("\tDestination Address: %s\n", iptos(((struct sockaddr_in *)a->dstaddr)->sin_addr.s_addr));
break;
case AF_INET6:
printf("\tAddress Family Name: AF_INET6\n");
if (a->addr)
printf("\tAddress: %s\n", ip6tos(a->addr, ip6str, sizeof(ip6str)));
break;
default:
printf("\tAddress Family Name: Unknown\n");
break;
}
}
printf("\n");
}
View Code

![]()
/* 將數字類型的IP地址轉換成字符串類型的 */
#define IPTOSBUFFERS 12
char *iptos(u_long in)
{
static char output[IPTOSBUFFERS][3 * 4 + 3 + 1];
static short which;
u_char *p;
p = (u_char *)∈
which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
sprintf_s(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
return output[which];
}
char* ip6tos(struct sockaddr *sockaddr, char *address, int addrlen)
{
socklen_t sockaddrlen;
#ifdef WIN32
sockaddrlen = sizeof(struct sockaddr_in6);
#else
sockaddrlen = sizeof(struct sockaddr_storage);
#endif
if (getnameinfo(sockaddr,
sockaddrlen,
address,
addrlen,
NULL,
0,
NI_NUMERICHOST) != 0) address = NULL;
return address;
}
輔助函數,IP轉字符串