————————————————
版权声明:本文为CSDN博主「Ezioooooo」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012877472/article/details/49817875

一、配置(VS2015)

项目右键属性,在C/C++目录预处理器添加WPCAP和HAVE_REMOTE,预编译头改为不使用预编译头,链接器输入wpcap.lib和ws2_32.lib,VC++目录包含目录添加下载的include文件,库目录添加下载的lib文件。

二、获取设备列表

(编写winpcap程序的第一件事)

pcap_findalldevs_ex()函数来实现这个功能:创建一个可以被函数pcap_open()打开的网络设备链表

pcap_findalldevs_ex(
char * source,                           //字符指针,保存来源的位置,设为PCAP_SRC_IF_STRING;
struct pcap_rmthauth* auth,    //指向pcap_rmtauth结构体的指针,保存需要远程设备捕获协议认证的信息。捕获本地设备设为NULL;
pcap_if_t** alldevs,                 //一个pcap_if_t结构体指针,函数返回时用来保存找到的适配器的信息;
char* errbuf                            //用来保存错误信息;
);                                            //返回值:如果返回0,表示函数运行成功,说明找到合适的适配器,通过alldevs参数返回;如果返回-1,发生错误,或者没有在本地找到合适的适配器;

pcap_if_t结构体定义如下:

pcap_if* next;                 //指向链表的下一个节点,如果不为空指向一个pcap_if元素;

char* name;                   //字符串指针,存储传向pcap_open_live函数的设备名称;

char* description;          //设备的描述;

pcap_addr* addresses;//这项这个设备接口地址链表的第一个元素;

u_int flags;                   //当前唯一的值是PCAP_IF_LOOPBACK,当当前接口是回路接口的时候设置;

当我们完成设备列表的使用后,应当调用pcap_freealldevs()函数释放内存资源。

三、获取已安装设备的详细信息

函数pcap_findalldevs_ex()返回的pcap_if结构体中,都有一个pcap_addr的结构体,这个结构体用来保存地址信息。

pcap_addr* next;//指向下一个节点
sockaddr* addr;//一个地址列表
sockaddr* netmask;//一个掩码列表
sockaddr* broadaddr;//一个广播地址列表
sockaddr* dstaddr;//一个目的地址列表

sockaddr结构用来存储与Windows套接字通讯的计算机上的一个IP地址。

四、打开适配器并捕获数据包

①打开适配器:函数pcap_open():

pcap_t* pcap_open (
const char * source,      //设备名称     
int snaplen,            //制定要捕获数据包中的哪些部分,将值定为65535确信总能收到完整数据包(比最大MTU大
int flags,                  //*最重要,用来指示适配器是否要被设置成混杂模式(不管这个数据包是不是发给我的,我都会去捕获。WinPcap能捕获其他主机的所有的数据包)
int read_timeout,    //读取超时时间

struct pcap_rmtauth * auth,      //远程机器验证

char * errbuf            //错误缓冲池,存储错误信息
);

函数返回:一个可以作为调用参数的指向pcap_t结构的指针,并且指定一个WinPcap会话。如果出现错误,返回NULL,errbuf中存储错误信息。

typedef struct pcap pcap_t          //一个已打开的捕捉实例的描述符

②捕获工作:

pcap_dispatch() 或 pcap_loop()函数:

int pcap_loop (

pcap_t * p,                        //pcap的句柄
int cnt,                                //捕获包的数量,如果是负数表示永不停止直到出现错误
pcap_handler callback,    //回调函数,当捕获到数据包时调用此函数
u_char * user                   //留给用户使用的
);

其中回调函数:

void(*) pcap_handler(
u_char *user,                         //函数pcap_loop()传递过来的,就是pcap_loop()函数中的user参数
const struct pcap_pkthdr *pkt_header,      //表示捕获到的数据包的基本信息
const u_char *pkt_data                       //表示捕获到的数据包的内容
);

结构体:

struct pcap_pkthdr {
struct timeval ts;                 /* 时间戳 */
bpf_u_int32 caplen;            /* 已捕获部分的长度 */
bpf_u_int32 len;                 /* 该包的脱机长度 */
};   //保存捕获到的包的基本信息,由pcap_loop函数自动填充

③不用回调方法捕获:

pcap_next_ex()函数代替pcap_loop()函数来实现捕获数据包,当只有显示调用时才能捕获数据包。

int pcap_next_ex (
pcap_t * p,                   //句柄   
struct pcap_pkthdr ** pkt_header,       //指向一个pcap_pkthdr结构的指针,用于保存捕获数据包的基本信息
const u_char ** pkt_data                    //保存捕获的数据
);

//捕获一个数据包,然后用捕获的数据包填充pkt_header和pkt_data参数,根据结果不同,返回不同的数字(1成功)。

五、过滤数据包

pcap_compile() 和 pcap_setfilter() 函数:

int pcap_compile(

pcap_t *p,                 //返回数据包捕获的指针

struct bpf_program *fp,                     //一个bpf_program结构的指针,用于过滤,在pcap_compile()函数中被赋值。

char *str,                                  //规定过滤规则

int optimize,                                    //控制结果代码的优化。规定了在结果代码上的选择是否被执行

bpf_u_int32 netmask);               //指定本地网络的网络掩码(该网卡的子网掩码),通过pcap_lookupnet()获取
将str指定的规则整合到分fp过滤程序中,并生成过滤程序入口地址,用于过滤选择期望的数据包。成功返回0,否则返回-1。

过滤规则str由一个或多个原语组成,如果为""表示不进行过滤。原语通常由一个标识id(名字或序列)和限定词(输入(type,指明哪些东西是id所代表的,可能的输入是host,net和port,默认host),方向(dir,id指明了一个特定的传输方向,可能的方向是src,dst,src or dst,默认src/dst),协议(proto,所匹配的协议ether,fddi,tr,ip,ip6,arp,rarp,decnet,tcp和udp,默认所有都可))组成。很复杂,记得查询。

六、分析数据包

此时已经可以可以捕获并过滤网络流量,以TCP/UDP为例分析。

网络中的数据包每经过一个层次都会加上那个层的报头来标注一些重要的信息。

捕获到的数据包首先有个mac报头,14字节,包含6字节目的mac地址、6字节源mac地址,和2字节上一层协议(不关注mac),接下来是IP数据包有20字节的报头。

IP报头定义:

/* IPv4 首部 */
typedef struct ip_header {
u_char ver_ihl;                   // 版本 (4 bits) + 首部长度 (4 bits)
u_char tos;                           // 服务类型(Type of service)
u_short tlen;                     // 总长(Total length)
u_short identification;         // 标识(Identification)
u_short flags_fo;              // 标志位(Flags) (3 bits) + 段偏移量(Fragment offset) (13 bits)
u_char ttl;                          // 存活时间(Time to live)
u_char proto;                      // 协议(Protocol)
u_short crc;                        // 首部校验和(Header checksum)
ip_address saddr;               // 源地址(Source address)
ip_address daddr;              // 目的地址(Destination address)
u_int op_pad;                 // 选项与填充(Option + Padding)
}ip_header;

通过首部长度(ip_len = (ih->ver_ihl & 0xf) * 4;)得到UDP数据包的位置。

UDP报头定义:

/* UDP 首部*/
typedef struct udp_header {
u_short sport;                 // 源端口(Source port)
u_short dport;               // 目的端口(Destination port)
u_short len;                    // UDP数据包长度(Datagram length)
u_short crc;                      // 校验和(Checksum)

TCP报头定义:

/* tcp 首部 */
typedef struct tcp_header {
u_short sport;                //源端口
u_short dport;                       //目的端口
u_int th_seq;                                     //序列号
u_int th_ack;                             //确认号
u_short doff : 4, hlen : 4, fin : 1, syn : 1, rst : 1, psh : 1, ack : 1, urg : 1, ece : 1, cwr : 1;           //4 bits 首部长度,6 bits 保留位,6 bits 标志位
u_short th_window;                           //窗口大小
u_short th_sum;                          //校验和
u_short th_urp;                                //紧急指针
}tcp_header;

}udp_header;

UDP报头:

TCP报头:

七、保存数据包到堆文件

①pcap_dump_open()函数打开一个可以保存数据的文件。

pcap_dumper_t* pcap_dump_open (

pcap_t * p,                     //一个libpcap存储文件的描述符,对用户不可见         
const char * fname           //要写入的文件名
);//只有当接口打开时,调用 pcap_dump_open() 才是有效的。 这个调用将打开一个堆文件,并将它关联到特定的接口上。

②pcap_dump()函数将数据包写入用户指定的文件中。

void pcap_dump (
u_char * user,                           //文件描述符dumpfp
const struct pcap_pkthdr * h,          //pkt_header
const u_char * sp                                  //要用pkt_data
);

八、从堆文件读取数据包

pcap_open_offline()函数将堆文件打开。

pcap_t* pcap_open_offline (

const char * fname,                           //要打开的文件名
char * errbuf                             //保存错误信息
);

通过pcap_createsrcstr()函数根据新WinPcap语法创建一个源字符串。

int pcap_createsrcstr (

char * source,                              //要存入的源字符串
int type,                                                  //要创建的源字符串类型
const char * host,                                 //远程主机
const char * port,                                 //远程端口
const char * name,                                     //我们要打开的文件名
char * errbuf                                                 //存储错误信息
);          //返回值:0:没有错误;-1:创建出错,错误写入errbuf中

Winpcap学习笔记的更多相关文章

  1. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  2. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  3. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  4. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

  5. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  6. seaJs学习笔记2 – seaJs组建库的使用

    原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...

  7. CSS学习笔记

    CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...

  8. HTML学习笔记

    HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...

  9. DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记

    今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...

随机推荐

  1. 机器学习(ML)十四之凸优化

    优化与深度学习 优化与估计 尽管优化方法可以最小化深度学习中的损失函数值,但本质上优化方法达到的目标与深度学习的目标并不相同. 优化方法目标:训练集损失函数值 深度学习目标:测试集损失函数值(泛化性) ...

  2. java jni 调用c语言函数

    今日在hibernate源代码中遇到了native关键词,甚是陌生,就查了点资料,对native是什么东西有了那么一点了解,并做一小记. native关键字说明其修饰的方法是一个原生态方法,方法对应的 ...

  3. php 全局变量 预定义变量

    //$GLOBALS 引用全局作用域中可用的全部变量 $_SERVER['SERVER_ADDR'] 返回运行脚本所在服务器的IP地址 $_SERVER['SERVER_NAME'] 返回运行脚本所在 ...

  4. 网站windows可以访问mac和linux无法访问【MTU MSS问题】

    环境: 阿里云LB 内网地址类型,代理后面的k8s上的服务 公司和阿里云之间vpn打通 在windows上进行访问一切正常,在相同的办公局域网linux主机内访问不通,mac笔记本访问同样不通,tel ...

  5. Linux ftp VSftp

    一.Linux FTP服务器分类: <1>wu-ftp <2>proftp=profession ftp <3>vsftp=very security ftp  本 ...

  6. [Linux-CentOS7]安装Telnet

    # yum install telnet Loaded plugins: fastestmirror Loading mirror speeds from cached hostfile Resolv ...

  7. 函数式编程/lambda表达式入门

    函数式编程/lambda表达式入门 本篇主要讲解 lambda表达式的入门,涉及为什么使用函数式编程,以及jdk8提供的函数式接口 和 接口的默认方法 等等 1.什么是命令式编程 命令式编程就是我们去 ...

  8. 与WinRT组件进行操作

    1,原理: WinRT是一个新的类库,应用程序可以用它访问操作系统的功能. 在内部,WinRT以组件的形式实现.COM Component Object Model- WinRT使用.net元数据来描 ...

  9. java开发JSP+Servlet+bootstrap开发电影院购票系统 源码

    基于JSP+Servlet+bootstrap开发电影院购票系统:开发环境: Windows操作系统开发工具: MyEclipse+Jdk+Tomcat+Mysql数据库 程序要求:电影院订票系统 用 ...

  10. linux下(centos7)docker安装

    参考链接https://docs.docker.com/install/linux/docker-ce/centos/ 第一步,确定是centos7及以上版本 cat /etc/redhat-rele ...