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. 【django-vue】celery延迟任务、定时任务 django中使用celery 秒杀功能 双写一致性 首页轮播图定时更新 课程前端页面

    目录 上节回顾 字符编码 django-redis 今日内容 1 celery 执行异步任务,延迟任务,定时任务 延时任务 定时任务 2 django中使用celery 2.1 秒杀功能 2.1.1 ...

  2. 42 干货系列从零用Rust编写负载均衡及代理,wmproxy中配置tcp转websocket

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

  3. windows 系统关闭占用端口的应用

    开发中有时候开发工具把程序关闭了,但是后台并没有真正关闭程序,导致再次启动相同端口的程序时报端口已经被使用的错误,这时如何强制关闭已占用的端口 1.打开dos对话框 2.查找被占用的端口的进程号 ne ...

  4. Visual Studio2019 使用WCF服务

    什么是WCF Windows Communication Foundation (WCF) 是一个框架,用于生成面向服务的应用程序.它取代了较旧的进程间通信技术,例如 ASMX Web 服务..NET ...

  5. 【TouchGFX】屏幕概念

    Screen构成 界面布局 View, 逻辑处理 Presenter Currently Active Screen 因TouchGFX分配内存的的方式是,按照最大的Screen分配,即最大View+ ...

  6. 【java】设置 tomcat 账号密码

    <role rolename="manager-gui"/> <user username="tomcat" password="t ...

  7. 处理命令行main函数args参数

    引用 System.CommandLine 库(需要显示预览版才能看到) var fileOption = new Option<FileInfo?>( name: "--fil ...

  8. Go-稀疏数组

    package main import "fmt" // 稀疏数组 // 1. 二维数组 // 2. 存在大量相同相同数据和少量不同数据 // 思维: 将大量相同数据转化为: (数 ...

  9. [转帖]故障分析 | 让top命令直接显示Java线程名?-- 解析OpenJDK的一个bug修复

    https://zhuanlan.zhihu.com/p/413136873 作者:阎虎青DBLE 开源项目负责人,负责分布式数据库中间件研发工作:持续专注于数据库方面的技术,始终在一线从事开发:对数 ...

  10. [转帖]数据库的快照隔离级别(Snapshot Isolation)

    https://www.cnblogs.com/gered/p/10251744.html 总结:已提交读快照只影响语句级别的锁定行为,而快照隔离影响整个事务.  转自:https://www.cnb ...