WinPcap网络编程入门——1. 获取设备列表
系列教程章节直达:
Winpcap网络编程入门——1. 获取设备列表;
上节中我们简单介绍了 WinPcap 的相关资料,配置好了开发环境,现在就让我们正式开始网络编程开发吧!
1. 基本开发流程
WinPcap 开发网络应用程序的大致流程:首先获取主机安装的网络设备列表,然后选择并激活某个网络设备,封装或过滤数据包,发送或解析数据包,本节我们将以解析数据包为例来逐层深入,基本开发流程如图:
2. 使用 pcap_findalldevs_ex() 检索设备列表
pcap_findalldevs_ex() 是 WinPcap 提供的用以查找主机网络适配器功能的函数,它是 pcap_findalldevs() 函数的升级版,现在基本都选择使用 ex 版本,它不仅能查找本地的设备,还能查找远程的设备,关于此函数的定义如下:
// 函数原型:
int pcap_findalldevs_ex(char* source, struct pcap_rmtauth *auth, pcap_if_t** alldevs, char* errbuf);
/* 参数说明
* source:指定是本地适配器还是远程适配器
* auth:身份验证信息,可以为NULL
* alldevs:存放获取的适配器数据,如果查找失败,其值为NULL
* errbuf:存放查找失败的相关错误信息
*/
// 返回值:成功返回0,失败返回-1
看了函数定义之后是不是感觉这个很简单呢,只需要调用函数然后就可以获取到设备信息,是的!就是这么简单,当然,还有一点需要注意:
可以看到参数 alldevs
的类型是 pcap_if_t
类型的二级指针,这里需要说明,pcap_findalldevs_ex()
函数在获取到设备信息之后会将详细信息存储在一个结构体pcap_if_t
中,(注意,单个设备时一个结构体,多个设备就是多个结构体的链接,即链表,这是个非常基本的概念,不懂的话查一下链表的相关知识)它的定义如下:
struct pcap_if_t
{
struct pcap_if_t *next; // 如果不为空,就指向下一个元素
char *name; // 设备名称
char *description; // 设备描述
struct pcap_addr *addresses;// 接口地址列表
bpf_u_int32 flags; // 标志位,标志是否 loopback 设备
}
从中可以看出,我们需要建立一个pcap_if_t
类型的指针来存储调用函数获取到的设备信息,然后直接通过指针就可以访问指定设备的相关信息,由此可以写出伪代码如下:
pcap_if_t *alldevs; // 指向获取到设备列表的第一个设备,即链表头
pcap_findalldevs_ex(***, ***, alldevs, ***); // 调用函数来查找设备
printf("%s\n", alldevs->name); // 输出第一个设备的名称
printf("%s\n", alldevs->description); // 输出第一个设备的描述信息
if(alldevs 链表中有多个设备)
alldevs = alldevs->next; // 获取下一个设备
// 重复上面的输出代码,输出此设备的相关信息
同样,从pcap_if_t
结构体的定义中可以看到,在结构体里面又定义了一个名为pcap_addr
的结构体,用来存储接口地址列表,pcap_addr
的定义如下:
struct pcap_addr
{
struct pcap_addr *next; // 如果不为空,则指向下一个元素
struct sockaddr *addr; // 接口IP地址
struct sockaddr *netmask; // 接口网络掩码
struct sockaddr *broadaddr; // 接口广播地址
struct sockaddr *dstaddr; // 接口 P2P 目的地址
}
这个结构体的列表中包含:
- 该接口的地址列表
- 网络掩码的列表(每个网络掩码对应地址列表中的一项)
- 广播地址的列表(每个广播地址对应地址列表中的一项)
- 目标地址的列表(每个目标地址对应地址列表中的一项)
3. 实现获取设备列表
经过了以上的分析,我们大概知道了pcap_findalldevs_ex()
函数的基本用法以及对于信息的存储机制,下面我们就来实现一下这个程序吧,具体的解释都在代码的注释里,要详细阅读代码哟 ~
#define WIN32 // 在vs中编程时,必须要加这一行,否则vs不会自动识别平台
#include <stdio.h>
#include <pcap.h>
#pragma comment(lib, "wpcap.lib")
main()
{
pcap_if_t* alldevs, * d; // alldevs 存储查找到的设备链表的链表头,d 为遍历 alldevs 链表时的游标
int i = 0; // 设备序号,在后面的循环中会用到
char errbuf[PCAP_ERRBUF_SIZE]; // 如果查找失败,相关错误信息会存储到这个里面
// 从本地计算机检索可用设备列表
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
{
// 查找失败,输出失败信息
fprintf(stderr, "Error in pcap_findalldevs_ex: %s\n", errbuf);
exit(1); // 如果查找失败,程序直接终止
}
// 如果查找成功,alldevs 中已经存储了设备信息链表头的地址,直接遍历输出即可
// 输出设备列表
for (d = alldevs; d != NULL; d = d->next)
{
printf("%d.%s", ++i, d->name); // 输出设备名称,设备序号依次加1
if (d->description)
{
printf("(%s)\n", d->description); // 输出设备描述信息(如果有的话)
}
else {
printf("(No description available)\n");
}
}
if (i == 0) // 如果设备序号还是0的话,说明没有查找到设备
{
printf("\nNo interfaces found! Make sure Winpcap is installed.\n");
return;
}
// 释放设备
pcap_freealldevs(alldevs);
}
完整代码就是这样,如果有其他问题欢迎下方评论区相见。
系列教程章节直达:
Winpcap网络编程入门——1. 获取设备列表;