pcapReader——源码分析

一、简介 

pcapReader是ndpi开源中的一个example。大家可以从<ndpi directory>/example/pcapReader.c中找到它的源代码。通过pcaplib和ndpi相结合,进行深度包检测。虽然只有短短的几行代码,但是他将展现的不仅是pcaplib和ndpi的使用方法,还有包分析的一些技巧。看完之后其实外国人写的程序也就是那样,并没有什么特别之处。我们先来一起看看基本的函数结构。

注:我们只对源码中的linux平台部分进行解释

在main函数中,通过调用test_lib()对程序进行整合。

这里限于篇幅,主要对runPcapLoop()函数中的动作进行分析。如果想理解其他函数或者更加详细的技术细节,可以阅读博客最后的源码附录。里面有比较详细的注释。如果还有问题,可以留言或者发一下私信。欢迎大家一起讨论。

二、包分析

runPcapLoop()函数中通过pcap_loop(_pcap_handle, -1, &pcap_packet_callback, NULL)进行循环抓包。pcap_loop是pcaplib中提供的api。_pcap_handle指向的是网卡设备,pcap_packet_callback是循环抓包之后的包处理函数,-1代表的是不停地抓直到抓包出错的时候停止。接下来我们针对pcap_packet_callback函数中的包处理进行分析

pcap_packet_callback函数中,按顺序分成4个主要部分:

1、ndpi_ethhdr进行数据链路层的拆包分析。针对Linux Cooked Capture 和vlan的特殊包结构。对包头和信息进行了对应的偏移,并且记录在ip_offset变量中。

2、ndpi_iphdr进行网络层的拆包。这里进行了ipv4和ipv6的检测,我们接下来只对ipv4进行介绍。

3、GTP隧道协议的处理

4、packet_processing()函数进一步的包处理

注:2中的网络层拆包存储在iph变量中,并在packet_processing()中作为ndpi协议检测的数据源

packet_processing函数作为ndpi分析的主体,这里通过get_ndpi_flow函数分类会话。然后利用ndpi_detection_process_pac

ket函数进行数据分析得到应用层协议。我们继续往下看看get_ndpi_flow是怎样建立起数据结构的。

注:get_ndpi_flow6针对ipv6进行了转换,最后还是通过get_ndpi_flow建立

get_ndpi_flow函数:

1、通过传输层拆包获得协议包的源和目的端口(tcp通过ndpi_tcphdr 、udp通过ndpi_udphdr分别进行拆包)

2、结合网络层和传输层的数据,通过源目的ip和端口分类会话

3、以ndpi_flows_root为hash数组,(lower_ip + upper_ip + iph->protocol + lower_port + upper_port) % NUM_ROOTS计算出会话对应的数组位置。然后对于数组的每个单元维护一个二叉查找链表。

4、通过ndpi_tfind函数对二叉树进行查找,如果存在相对应的会话,则返回对应结果。如果不存在,则通过ndpi_tsearch把新的会话插入二叉树中。

node_cmp函数中定义了比较的规则。ndpi_tfind和ndpi_tsearch在<ndpi directory>/src/lib/ndpi_main.c文件中进行的二叉查找的封装。

整体数据结构

三、其他函数

1、setupDetection();//ndpi检测协议的注册,以及参数设置

通过ndpi提供的一系列函数,注册需要深度检测的协议。大略如下

ndpi_init_detection_module激活cache支持,主要针对一些占用缓存的协议如skype

ndpi_set_protocol_detection_bitmask2注册需要进行检测的协议

ndpi_detection_get_sizeof_ndpi_id_struct

ndpi_detection_get_sizeof_ndpi_flow_struct:获取ndpi_flow_struct和ndpi_id_struct的大小在为二叉树插入新节点时,申请空间用

变量的初始化

2、openPcapFileOrDevice();//pcaplib的初始化准备

errbuf[PCAP_ERRBUF_SIZE]:pcaplib存放错误信息的缓冲区

pcap_open_live打开对应的网卡设备

注:如果打开失败,或者命令中指定利用pcap_open_offline从文件中读入数据

pcap_datalink获取当前数据链路的类型,一般为以太网v2

pcap_compile和pcap_setfilter分别用于编译和设置抓包的过滤规则

3、signal(SIGINT, sigproc);//包含在signal.h头文件中,这里主要交互式信号,如中断做出反应。触发sigproc函数关闭程序

如果产生中断,则调用如上函数关闭pcap和ndpi并且输出结果。

4、closePcapFile();

通过pcap_close函数清除_pcap_handle指针并关闭抓包。

5、printResults(tot_usec);//输出结果

6、terminateDetection();

通过ndpi_tdestroy释放hash数组及其数组上的二叉查找树节点,最后通过ndpi_exit_detection_module结束ndpi程序。

7、static void parseOptions(int argc, char **argv)   /*命令行的实现,这里argc和argv从main中argc和argv参数传递进来。*/

getopt函数是命令行分析 第三个参数解释:

1.单个字符,表示选项

2.单个字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给optarg。

3 单个字符后跟两个冒号,表示该选项后可以跟一个参数,也可以不跟。如果跟一个参数,参数必须紧跟在选项后不能以空格隔开。该参数的指针赋给optarg。

getopt中选项得到的参数传递给全局变量optarg

四、源码附录

https://code.csdn.net/snippets/395699

pcapReader——源码分析

时间: 2024-10-05 10:54:05

pcapReader——源码分析的相关文章

协议的注册与维护——ndpi源码分析

在前面的文章中,我们对ndpi中的example做了源码分析.这一次我们将尽可能深入的了解ndpi内部的结构和运作.我们将带着下面三个目的(问题)去阅读ndpi的源代码. 1.ndpi内部是怎么样注册和维护需要检测的协议呢? 2.ndpi在初始化的过程中,做了怎么样的工作? 3.ndpi在底层的实现中具体又是使用怎样的数据结构? 注:这里限于篇幅,本文章指针对使用中的初始化部分进行源码分析.主体的分析函数和具体的各个协议将在后面的文中陆续介绍.如果有不正确或者理解不到位的地方,欢迎大家一起讨论.

TeamTalk源码分析之login_server

login_server是TeamTalk的登录服务器,负责分配一个负载较小的MsgServer给客户端使用,按照新版TeamTalk完整部署教程来配置的话,login_server的服务端口就是8080,客户端登录服务器地址配置如下(这里是win版本客户端): 1.login_server启动流程 login_server的启动是从login_server.cpp中的main函数开始的,login_server.cpp所在工程路径为server\src\login_server.下表是logi

Android触摸屏事件派发机制详解与源码分析二(ViewGroup篇)

1 背景 还记得前一篇<Android触摸屏事件派发机制详解与源码分析一(View篇)>中关于透过源码继续进阶实例验证模块中存在的点击Button却触发了LinearLayout的事件疑惑吗?当时说了,在那一篇咱们只讨论View的触摸事件派发机制,这个疑惑留在了这一篇解释,也就是ViewGroup的事件派发机制. PS:阅读本篇前建议先查看前一篇<Android触摸屏事件派发机制详解与源码分析一(View篇)>,这一篇承接上一篇. 关于View与ViewGroup的区别在前一篇的A

HashMap与TreeMap源码分析

1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Java这么久,也写过一些小项目,也使用过TreeMap无数次,但到现在才明白它的实现原理).因此本着"不要重复造轮子"的思想,就用这篇博客来记录分析TreeMap源码的过程,也顺便瞅一瞅HashMap. 2. 继承结构 (1) 继承结构 下面是HashMap与TreeMap的继承结构: pu

Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938395.html 前面粗略分析start_kernel函数,此函数中基本上是对内存管理和各子系统的数据结构初始化.在内核初始化函数start_kernel执行到最后,就是调用rest_init函数,这个函数的主要使命就是创建并启动内核线

Spark的Master和Worker集群启动的源码分析

基于spark1.3.1的源码进行分析 spark master启动源码分析 1.在start-master.sh调用master的main方法,main方法调用 def main(argStrings: Array[String]) { SignalLogger.register(log) val conf = new SparkConf val args = new MasterArguments(argStrings, conf) val (actorSystem, _, _, _) =

Solr4.8.0源码分析(22)之 SolrCloud的Recovery策略(三)

Solr4.8.0源码分析(22)之 SolrCloud的Recovery策略(三) 本文是SolrCloud的Recovery策略系列的第三篇文章,前面两篇主要介绍了Recovery的总体流程,以及PeerSync策略.本文以及后续的文章将重点介绍Replication策略.Replication策略不但可以在SolrCloud中起到leader到replica的数据同步,也可以在用多个单独的Solr来实现主从同步.本文先介绍在SolrCloud的leader到replica的数据同步,下一篇

zg手册 之 python2.7.7源码分析(4)-- pyc字节码文件

什么是字节码 python解释器在执行python脚本文件时,对文件中的python源代码进行编译,编译的结果就是byte code(字节码) python虚拟机执行编译好的字节码,完成程序的运行 python会为导入的模块创建字节码文件 字节码文件的创建过程 当a.py依赖b.py时,如在a.py中import b python先检查是否有b.pyc文件(字节码文件),如果有,并且修改时间比b.py晚,就直接调用b.pyc 否则编译b.py生成b.pyc,然后加载新生成的字节码文件 字节码对象

LevelDB源码分析--Iterator

我们先来参考来至使用Iterator简化代码2-TwoLevelIterator的例子,略微修改希望能帮助更加容易立即,如果有不理解请各位看客阅读原文. 下面我们再来看一个例子,我们为一个书店写程序,书店里有许多书Book,每个书架(BookShelf)上有多本书. 类结构如下所示 class Book { private: string book_name_; }; class Shelf { private: vector<Book> books_; }; 如何遍历书架上所有的书呢?一种实