NPCAP 库是一种用于在Windows平台上进行网络数据包捕获和分析的库。它是WinPcap库的一个分支,由Nmap开发团队开发,并在Nmap软件中使用。与WinPcap一样,NPCAP库提供了一些API,使开发人员可以轻松地在其应用程序中捕获和处理网络数据包。NPCAP库可以通过WinPcap API进行编程,因此现有的WinPcap应用程序可以轻松地迁移到NPCAP库上。

自定义数据包过滤其核心原理是使用pcap_compile函数,该函数用于编译一个过滤表达式并生成过滤程序。该函数可以把用户指定的过滤表达式编译成可被BPF(Berkeley Packet Filter)虚拟机处理的内部表示格式,从而可以快速过滤捕获的数据包,仅保留指定条件的数据包。

该函数的函数原型是:

int pcap_compile(pcap_t *p, struct bpf_program *fp, const char *str, int optimize, bpf_u_int32 netmask);

函数参数解释如下:

  • p:指向打开的pcap文件或设备的指针。
  • fp:指向表示过滤程序的bpf_program结构体的指针。
  • str:指向过滤表达式字符串的指针。
  • optimize:用于指定是否优化过滤表达式的执行。设为1时表示启用优化。
  • netmask:用于指定网络掩码。

使用该函数,可以将一个用户指定的过滤表达式编译成可被BPF虚拟机执行的内部表示格式,生成表示过滤程序的bpf_program结构体。这个过滤程序可以直接用于pcap_loop()等函数,在捕获数据包时进行过滤,函数返回值为0表示编译成功,否则返回一个非零值。

当过滤规则被编译成功后则下一步就是设置过滤器,此时读者可调用pcap_setfilter()函数,该函数用于设置捕获数据包时的过滤条件,并将一个表示过滤程序的bpf_program结构体所代表的过滤程序应用到指定的pcap文件或设备上,并过滤出符合条件的数据包。只有符合过滤条件的数据包才会被传递给抓包程序进行处理。

该函数的函数原型为:

int pcap_setfilter(pcap_t *p, struct bpf_program *fp);

函数参数解释如下:

  • p:指向打开的pcap文件或设备的指针。
  • fp:指向表示过滤程序的bpf_program结构体的指针。

使用该函数可以将一个表示过滤程序的bpf_program结构体所代表的过滤程序应用到指定的pcap文件或设备上,并过滤出符合条件的数据包。使用该函数后,pcap_loop()等函数在捕获数据包时仅会传递符合过滤条件的数据包,过滤出的数据包将会被传递给抓包程序进行处理,而不会将所有数据包进行处理,这样可以大大减少资源占用,并同时提高数据包捕获和分析的效率。函数返回值为0表示设置过滤程序成功,否则返回一个非零值。

数据包过滤最后一步是设置一个回调函数,通过调用pcap_loop()函数可实现循环等待数据包,并设置一个回调函数,当出现数据时会将数组自动发送至回调函数上,再回点函数内读者可对数据包进行任意形式的解析处理。

该函数的函数原型为:

int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user);

函数参数解释如下:

  • p:指向打开的pcap文件或设备的指针。
  • cnt:用于指定捕获的数据包的数量,-1表示捕获数据包的数量没有限制。
  • callback:指向用户自定义的回调函数的指针,用于处理每一个捕获到的数据包。
  • user:传递给回调函数的用户指针。

使用该函数,可以在指定的pcap文件或设备上启动一个循环,等待并捕获符合过滤条件的数据包,并通过用户自定义的回调函数对其进行处理。回调函数会在每个数据包被捕获时调用,在回调函数中可以根据需求进行特定的数据包分析和处理操作。函数返回值为-1表示捕获数据包失败,否则返回一个非负整数,表示捕获的数据包数量,当理解了上述程序定义,那么实现自定义抓包过滤功能将变得很容易,如下则是完整的代码案例;

#include <iostream>
#include <winsock2.h>
#include <Windows.h>
#include <string>
#include <pcap.h> #pragma comment(lib,"ws2_32.lib")
#pragma comment(lib, "packet.lib")
#pragma comment(lib, "wpcap.lib") using namespace std; // 打开网卡返回的指针
pcap_t* m_adhandle; // 解码TCP数据包,需要先加14跳过数据链路层, 然后再加20跳过IP层。
void PrintTCPHeader(const unsigned char * packetData)
{
typedef struct tcp_header
{
short SourPort; // 源端口号16bit
short DestPort; // 目的端口号16bit
unsigned int SequNum; // 序列号32bit
unsigned int AcknowledgeNum; // 确认号32bit
unsigned char reserved : 4, offset : 4; // 预留偏移 unsigned char flags; // 标志 short WindowSize; // 窗口大小16bit
short CheckSum; // 检验和16bit
short surgentPointer; // 紧急数据偏移量16bit
}tcp_header; struct tcp_header *tcp_protocol;
// +14 跳过数据链路层 +20 跳过IP层
tcp_protocol = (struct tcp_header *)(packetData + 14 + 20); u_short sport = ntohs(tcp_protocol->SourPort);
u_short dport = ntohs(tcp_protocol->DestPort);
int window = tcp_protocol->WindowSize;
int flags = tcp_protocol->flags; printf("源端口: %6d --> 目标端口: %6d --> 窗口大小: %7d --> 标志: (%d)",
sport, dport, window, flags); if (flags & 0x08) printf("PSH 数据传输\n");
else if (flags & 0x10) printf("ACK 响应\n");
else if (flags & 0x02) printf("SYN 建立连接\n");
else if (flags & 0x20) printf("URG \n");
else if (flags & 0x01) printf("FIN 关闭连接\n");
else if (flags & 0x04) printf("RST 连接重置\n");
else printf("None 未知\n");
} // 解析过滤数据包(回调函数)
void packet_handler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data)
{
// std::cout << pkt_data << std::endl;
PrintTCPHeader(pkt_data);
} // 获取网卡并设置过滤器
BOOL GetAndOpenAdapter(std::string local_address, std::string filter)
{
pcap_if_t* alldevs = NULL, *d = NULL;
char errbuf[256] = { 0 };
bpf_program fcode;
u_int netmask; // 获取网卡设备指针
if (-1 == pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf))
{
return FALSE;
} // 选取适合网卡
int flag = 0;
for (d = alldevs; d; d = d->next)
{
pcap_addr_t* p = d->addresses;
while (p)
{
if (local_address == inet_ntoa(((sockaddr_in*)p->addr)->sin_addr))
{
flag = 1;
break;
}
p = p->next;
}
if (1 == flag)
break;
}
if (0 == flag)
{
// 请检查本机IP地址是否正确
return FALSE;
} // 获取子网掩码
netmask = ((sockaddr_in*)d->addresses->netmask)->sin_addr.S_un.S_addr; // 打开网卡
m_adhandle = pcap_open(d->name, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf);
if (NULL == m_adhandle)
{
pcap_freealldevs(alldevs);
return FALSE;
} // 检查以太网
if (DLT_EN10MB != pcap_datalink(m_adhandle))
{
pcap_freealldevs(alldevs);
return FALSE;
} // 编译过滤器
char filter_ptr[4096] = { 0 };
sprintf(filter_ptr, filter.c_str()); if (0 > pcap_compile(m_adhandle, &fcode, filter_ptr, 1, netmask))
{
// 编译过滤器出错
pcap_freealldevs(alldevs);
return FALSE;
} // 设置过滤器
if (0 > pcap_setfilter(m_adhandle, &fcode))
{
// 设置过滤器出错
pcap_freealldevs(alldevs);
return FALSE;
} // 释放网卡设备列表
pcap_freealldevs(alldevs); // 开始捕捉数据包
pcap_loop(m_adhandle, 0, packet_handler, NULL);
return TRUE;
} int main(int argc, char* argv[])
{
BOOL flag = GetAndOpenAdapter("192.168.9.125", "dst host www.lyshark.com"); system("pause");
return 0;
}

读者可自行运行上述代码片段,当程序运行后会自动侦听192.168.9.125地址,并使用dst host www.lyshark.com过滤规则,该规则的含义是,如果有数据包从本网卡流出,则自动执行过滤输出lyshark.com网址的数据包,如下图所示;

18.3 NPCAP自定义数据包过滤的更多相关文章

  1. 鸟哥私房菜笔记:Iptables:数据包过滤软件

    数据包进入流程:规则顺序的重要性 iptables利用的是数据包过滤机制,所以它会分析数据包的包头数据.根据包头数据与定义的规则来决定该数据包是否可以进入主机或者是被丢弃.也就是说,根据数据包的分析资 ...

  2. nGrinder对监控机器收集自定义数据及源码分析

    转载:https://blog.csdn.net/neven7/article/details/50782451 0.背景 性能测试工具nGrinder支持在无需修改源码的情况下,对目标服务器收集自定 ...

  3. Ubuntu 安装mysql & 自定义数据存储目录

    一.安装 apt-get install mysql-server 执行过程如下: root@duke:~# apt-get install mysql-server 正在读取软件包列表... 完成 ...

  4. 【Unity C#编程】自定义数据

    译林军 灰魅|2014-03-04 10:52|10589次浏览|Unity(315)移动应用(31)技术开发(16)0 在这篇Unity C#的文章中,你将会创建一个简单的数据结构,然后写下它的属性 ...

  5. 使用 data-* 属性来嵌入自定义数据

    1. HTML 实例 <ul> <li data-animal-type="bird">Owl</li> <li data-animal- ...

  6. 判断数据库内容,在页面显示自定义数据case when

    判断数据库内容,在页面显示自定义数据 case when...then ...else...end 比如:数据库内容是这样: 通过sql语句判断,数据库的name字段,内容是月桂的,显示嫦娥,其他的显 ...

  7. Microsoft Azure 上的自定义数据和 Cloud-Init

     自定义数据是什么? 客户经常询问如何才能在配置Microsoft Azure 虚拟机时插入脚本或其他元数据.在其他云中,这个概念通常称为用户数据.MicrosoftAzure 中也有一项类似的功 ...

  8. asp.net mvc3 数据验证(三)—自定义数据注解

    原文:asp.net mvc3 数据验证(三)-自定义数据注解         前两节讲的都是asp.net mvc3预先设定的数据注解,但是系统自由的数据注解肯定不适合所有的场合,所以有时候我们需要 ...

  9. C#在自定义事件里传递自定义数据,使用EventArgs的姿势

    EventArgs是包含事件数据的类的基类,用于传递事件的细节.今天分享的是使用泛型来约束EventArgs,在事件里传递自定义数据的例子. 正题 由于这个关注点很小,直接上代码了. 定义泛型类TEv ...

  10. SQL反模式学习笔记18 减少SQL查询数据,避免使用一条SQL语句解决复杂问题

    目标:减少SQL查询数据,避免使用一条SQL语句解决复杂问题 反模式:视图使用一步操作,单个SQL语句解决复杂问题 使用一个查询来获得所有结果的最常见后果就是产生了一个笛卡尔积.导致查询性能降低. 如 ...

随机推荐

  1. 第一章 Linux系统编程

    Linux基础命令 ctrl + l //快速清屏 rm 文件名 //删除文件,rm *.o表示删除所有.o后缀的文件 mkdir 目录名 //创建一个目录 touch 文件名 //创建一个文件 tr ...

  2. Android 启动优化(二) - 有向无环图的原理以及解题思路

    Android 启动优化(一) - 有向无环图 Android 启动优化(二) - 拓扑排序的原理以及解题思路 Android 启动优化(三) - AnchorTask 使用说明 Android 启动 ...

  3. C++20 | std::span 陣列、容器的代理人

    在 C++ 裡頭有相當多「容器」.從原生的陣列,到標準庫 STL 的 vector, array, list, queue, map, set, -.有時候我們只是想以檢視的角度去看一個容器,或是其中 ...

  4. PySpark 入门:通过JDBC连接数据库(DataFrame)

    这里以关系数据库MySQL为例.首先,本博客教程(Ubuntu 20.04 安装MySQL 8.X),在Linux系统中安装好MySQL数据库.这里假设你已经成功安装了MySQL数据库.下面我们要新建 ...

  5. Vue - 组件通信(父子单向传递、父子相互传递、祖孙隔代传递)

    父组件向子组件单向传递 父组件:引入子组件后,通过属性绑定的形式,将值传入子组件: ` ` 子组件:子组件通过props接收父组件传入的值; ` {{sonGetParam}} ` 子组件向父组件单向 ...

  6. 接口自动化测试复习巩固第二天,管理员后端验证和接口抓包+requests实现

    接口自动化测试第二天,需要用到的第三方库有os,openpyxl,json,pytest,requests 首选我们今天的目标是写出一个测试登录用例的脚本,这里我用的是分层设计,整个框架暂时被分为工具 ...

  7. python进阶(8)--测试函数与类

    一.测试函数(unittest) 1.源文件方法(name_function.py): def get_formatted_name(first,last): """生成 ...

  8. 问题--QT只有全屏的时候才能使用

    1.问题 安装的版本是3.8.0,只有在全屏的时候在编辑界面不会卡,其余情况会直接卡死在这. 2.解决方式 安装了较低版本的3.14.2,解决了上述问题

  9. 44从零开始用Rust编写nginx,命令行参数的设计与解析及说明

    wmproxy wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,四层TCP/UDP转发,七层负载均衡,内网穿透,后续将实现websocket代 ...

  10. [转帖]字符集 AL32UTF8 和 UTF8

    https://blog.51cto.com/comtv/383254# 文章标签职场休闲字符集 AL32UTF8 和 UTF8文章分类数据库阅读数1992 The difference betwee ...