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. deepin15.11系统使用罗技k380键盘

    罗技k380键盘官方支持安卓.windows.macos,就是没有支持Linux系统.在开发过程中使用的是Deepin15.11系统,如何连接罗技k380就是一个问题,折腾了一段时间后解决这个问题.记 ...

  2. Go--时间日期相关

    1 获取当天零点的时间戳 //当天0点的时间戳 //获取当前时间 t := time.Now() nowTime := time.Date(t.Year(), t.Month(), t.Day(), ...

  3. hyper-v虚拟机中ubuntu连不上网络的解决办法

    首先重启下hyper-v的服务,看下情况: 1.检查hyper-v相关的服务有没有开启 2.如果开启了服务,unbuntu仍然不能连网,则在ubtuntu中进行接下来的步骤: 2.1 设置网络连接为N ...

  4. 采购订单创建、修改、审批增强ME21N/ME22N/ME28/ME29N

    一.采购订单创建修改增强 BADI:ME_PROCESS_PO_CUST 通过POST方法中的参数im_header,获取对应的数据 订单头 "----------------------- ...

  5. Codeforces Round #704 (Div. 2) A~E

    比赛链接:https://codeforces.com/contest/1492 1492A.Three swimmers 题意: 有三名游泳的人,他们分别需要 \(a,b,c\) 分钟才能在一个游泳 ...

  6. Educational Codeforces Round 96 (Rated for Div. 2) (A - C题个人题解)

    因为火锅导致错过的上分机会,赛后发现人均AC5题 1430A. Number of Apartments 暴力搜索 #include<bits/stdc++.h> using namesp ...

  7. 一、Mycat实战---为什么要用mycat

    系列导航 一.Mycat实战---为什么要用mycat 二.Mycat安装 三.mycat实验数据 四.mycat垂直分库 五.mycat水平分库 六.mycat全局自增 七.mycat-ER分片 本 ...

  8. Angular系列教程之自定义指令

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  9. 使用markdown语法做笔记,相比txt多了很多样式

  10. ECharts——快速入门

    ECharts快速入门 引入 ECharts <!DOCTYPE html> <html> <head> <meta charset="utf-8& ...