c++ winpcap开发(7)

2024-02-29 16:32
文章标签 c++ 开发 winpcap

本文主要是介绍c++ winpcap开发(7),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

处理离线转储文件

在这个课程中,我们将学习如何处理数据包捕获到一个文件(转储到文件)。WinPcap提供广泛的功能来将文件的网络流量保存到文件并读取转储的内容 - 本课将介绍如何使用所有这些功能。我们还将了解如何使用WinPcap的内核转储功能来获取高性能转储(注意:由于新内核缓冲区存在一些问题,此功能已禁用)。

转储文件的格式是libpcap格式。该格式包含二进制形式的捕获数据包的数据,是许多网络工具(包括WinDump,Ethereal和Snort)使用的标准。

将数据包保存到转储文件

首先,我们来看看如何用libpcap格式写数据包。

以下示例捕获所选接口的数据包,并将其保存在名称由用户提供的文件中。

#include "pcap.h"/* prototype of the packet handler */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);int main(int argc, char **argv)
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_dumper_t *dumpfile;/* Check command line */if(argc != 2){printf("usage: %s filename", argv[0]);return -1;}/* Retrieve the device list on the local machine */if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1){fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);exit(1);}/* Print the list */for(d=alldevs; d; d=d->next){printf("%d. %s", ++i, d->name);if (d->description)printf(" (%s)\n", d->description);elseprintf(" (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_s("%d", &inum);if(inum < 1 || inum > i){printf("\nInterface number out of range.\n");/* Free the device list */pcap_freealldevs(alldevs);return -1;}/* Jump to the selected adapter */for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);/* Open the device */if ( (adhandle= pcap_open(d->name,          // name of the device65536,            // portion of the packet to capture// 65536 guarantees that the whole packet will be captured on all the link layersPCAP_OPENFLAG_PROMISCUOUS,    // promiscuous mode1000,             // read timeoutNULL,             // authentication on the remote machineerrbuf            // error buffer) ) == NULL){fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);/* Free the device list */pcap_freealldevs(alldevs);return -1;}/* Open the dump file */dumpfile = pcap_dump_open(adhandle, argv[1]);if(dumpfile==NULL){fprintf(stderr,"\nError opening output file\n");return -1;}printf("\nlistening on %s... Press Ctrl+C to stop...\n", d->description);/* At this point, we no longer need the device list. Free it */pcap_freealldevs(alldevs);/* start the capture */pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile);return 0;
}/* Callback function invoked by libpcap for every incoming packet */
void packet_handler(u_char *dumpfile, const struct pcap_pkthdr *header, const u_char *pkt_data)
{/* save the packet on the dump file */pcap_dump(dumpfile, header, pkt_data);
}

正如你所看到的,程序的结构与以前的课程中看到的结构非常相似。差异在于:

  • 一旦打开接口,就会发出一个对pcap_dump_open()的调用。此调用打开一个转储文件并将其与该接口相关联。
  • 数据包将从packet_handler()回调中使用pcap_dump()写入此文件。的参数pcap_dump()是在1-1对应于参数pcap_handler() 。

从转储文件读取数据包

现在我们有一个转储文件可用,我们可以尝试阅读它的内容。以下代码打开一个WinPcap / libpcap转储文件,并显示文件中包含的每个数据包。该文件使用pcap_open_offline()打开,那么通常使用pcap_loop()来对数据包进行排序。如您所见,从离线捕获读取数据包与从物理接口接收数据包几乎相同。

此示例介绍另一个功能:pcap_createsrcsrc()。创建一个源字符串需要创建一个源字符串,它以一个标记开头,用于告诉WinPcap的源类型,例如“rpcap://”,如果我们要打开一个适配器,或者“file://”,如果我们打开文件。当使用pcap_findalldevs_ex()(返回的值已经包含这些字符串)时,不需要此步骤。但是,在此示例中是必需的,因为从用户输入读取文件的名称。

#include <stdio.h>
#include <pcap.h>#define LINE_LEN 16void dispatcher_handler(u_char *, const struct pcap_pkthdr *, const u_char *);int main(int argc, char **argv)
{
pcap_t *fp;
char errbuf[PCAP_ERRBUF_SIZE];
char source[PCAP_BUF_SIZE];if(argc != 2){printf("usage: %s filename", argv[0]);return -1;}/* Create the source string according to the new WinPcap syntax */if ( pcap_createsrcstr( source,         // variable that will keep the source stringPCAP_SRC_FILE,  // we want to open a fileNULL,           // remote hostNULL,           // port on the remote hostargv[1],        // name of the file we want to openerrbuf          // error buffer) != 0){fprintf(stderr,"\nError creating a source string\n");return -1;}/* Open the capture file */if ( (fp= pcap_open(source,         // name of the device65536,          // portion of the packet to capture// 65536 guarantees that the whole packet will be captured on all the link layersPCAP_OPENFLAG_PROMISCUOUS,     // promiscuous mode1000,              // read timeoutNULL,              // authentication on the remote machineerrbuf         // error buffer) ) == NULL){fprintf(stderr,"\nUnable to open the file %s.\n", source);return -1;}// read and dispatch packets until EOF is reachedpcap_loop(fp, 0, dispatcher_handler, NULL);return 0;
}void dispatcher_handler(u_char *temp1, const struct pcap_pkthdr *header, const u_char *pkt_data)
{u_int i=0;/** Unused variable*/(VOID)temp1;/* print pkt timestamp and pkt len */printf("%ld:%ld (%ld)\n", header->ts.tv_sec, header->ts.tv_usec, header->len);          /* Print the packet */for (i=1; (i < header->caplen + 1 ) ; i++){printf("%.2x ", pkt_data[i-1]);if ( (i % LINE_LEN) == 0) printf("\n");}printf("\n\n");     }
以下示例与最后一个示例具有相同的用途,但是使用 pcap_next_ex() 而不是 pcap_loop() 回调方法。
#include <stdio.h>
#include <pcap.h>#define LINE_LEN 16int main(int argc, char **argv)
{
pcap_t *fp;
char errbuf[PCAP_ERRBUF_SIZE];
char source[PCAP_BUF_SIZE];
struct pcap_pkthdr *header;
const u_char *pkt_data;
u_int i=0;
int res;if(argc != 2){printf("usage: %s filename", argv[0]);return -1;}/* Create the source string according to the new WinPcap syntax */if ( pcap_createsrcstr( source,         // variable that will keep the source stringPCAP_SRC_FILE,  // we want to open a fileNULL,           // remote hostNULL,           // port on the remote hostargv[1],        // name of the file we want to openerrbuf          // error buffer) != 0){fprintf(stderr,"\nError creating a source string\n");return -1;}/* Open the capture file */if ( (fp= pcap_open(source,         // name of the device65536,          // portion of the packet to capture// 65536 guarantees that the whole packet will be captured on all the link layersPCAP_OPENFLAG_PROMISCUOUS,     // promiscuous mode1000,              // read timeoutNULL,              // authentication on the remote machineerrbuf         // error buffer) ) == NULL){fprintf(stderr,"\nUnable to open the file %s.\n", source);return -1;}/* Retrieve the packets from the file */while((res = pcap_next_ex( fp, &header, &pkt_data)) >= 0){/* print pkt timestamp and pkt len */printf("%ld:%ld (%ld)\n", header->ts.tv_sec, header->ts.tv_usec, header->len);          /* Print the packet */for (i=1; (i < header->caplen + 1 ) ; i++){printf("%.2x ", pkt_data[i-1]);if ( (i % LINE_LEN) == 0) printf("\n");}printf("\n\n");     }if (res == -1){printf("Error reading the packets: %s\n", pcap_geterr(fp));}return 0;
}

Writing packets to a dump file with pcap_live_dump

注意:由于新内核缓冲区存在一些问题,此功能已被禁用。

WinPcap的最新版本提供了一种将网络流量节省到pcap_live_dump()函数的另一种方法。pcap_live_dump()具有三个参数:一个文件名,允许该文件达到的最大大小(以字节为单位),以及该文件允许包含的最大数据包数。零表示对这两个值没有限制。请注意,在调用pcap_live_dump()之前,该程序可以设置一个过滤器(使用pcap_setfilter(),请参阅过滤流量),以定义要保存的流量的子集。

pcap_live_dump()是非阻塞的,因此它将启动转储并立即返回:转储进程异步进行,直到达到最大文件大小或最大数据包数。

应用程序可以使用pcap_live_dump_ended()等待或检查转储结束。请注意,如果同步参数非零,如果极限均为0,此功能将永久阻止应用程序。

#include <stdlib.h>
#include <stdio.h>#include <pcap.h>#error At the moment the kernel dump feature is not supported in the drivermain(int argc, char **argv) {pcap_if_t *alldevs, *d;pcap_t *fp;u_int inum, i=0;char errbuf[PCAP_ERRBUF_SIZE];printf("kdump: saves the network traffic to file using WinPcap kernel-level dump faeature.\n");printf("\t Usage: %s [adapter] | dump_file_name max_size max_packs\n", argv[0]);printf("\t Where: max_size is the maximum size that the dump file will reach (0 means no limit)\n");printf("\t Where: max_packs is the maximum number of packets that will be saved (0 means no limit)\n\n");if(argc < 5){/* The user didn't provide a packet source: Retrieve the device list */if (pcap_findalldevs(&alldevs, errbuf) == -1){fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);exit(1);}/* Print the list */for(d=alldevs; d; d=d->next){printf("%d. %s", ++i, d->name);if (d->description)printf(" (%s)\n", d->description);elseprintf(" (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");/* Free the device list */return -1;}/* Jump to the selected adapter */for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);/* Open the device */if ( (fp = pcap_open_live(d->name, 100, 1, 20, errbuf) ) == NULL){fprintf(stderr,"\nError opening adapter\n");return -1;}/* Free the device list */pcap_freealldevs(alldevs);/* Start the dump */if(pcap_live_dump(fp, argv[1], atoi(argv[2]), atoi(argv[3]))==-1){printf("Unable to start the dump, %s\n", pcap_geterr(fp));return -1;}}else{/* Open the device */if ( (fp= pcap_open_live(argv[1], 100, 1, 20, errbuf) ) == NULL){fprintf(stderr,"\nError opening adapter\n");return -1;}/* Start the dump */if(pcap_live_dump(fp, argv[0], atoi(argv[1]), atoi(argv[2]))==-1){printf("Unable to start the dump, %s\n", pcap_geterr(fp));return -1;}}/* Wait until the dump finishes, i.e. when  max_size or max_packs is reached*/pcap_live_dump_ended(fp, TRUE);/* Close the adapter, so that the file is correctly flushed */pcap_close(fp);return 0;
}

除了设置限制的可能性之外,pcap_live_dump()和pcap_dump()之间的区别是性能。pcap_live_dump()利用了WinPcap NPF驱动程序的功能(参见NPF驱动程序内部手册)从内核级写入转储,最小化上下文切换和内存副本的数量。

显然,由于此功能目前在其他操作系统上不可用,因此pcap_live_dump()是WinPcap特有的,仅在Win32下存在。






这篇关于c++ winpcap开发(7)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/759378

相关文章

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名