libpcap是数据包捕获函数库。该库提供的C函数接口可用于需要捕获经过网络接口数据包的系统开发上。libpcap提供的接口函数主要实现和封装了与数据包截获有关的过程。这个库为不同的平台提供了一致的编程接口,在安装了libpcap的平台上,以libpcap为接口写的程序,能够自由的跨平台使用。

linux下libpcap的安装:sudo apt-get install libpcap-dev

linux下gcc编译程序:gcc my_pcap.c -lpcap

执行程序的时候如果报错:no suitable device found,以管理员权限运行程序即可,sudo ./my_pcap

libpcap的抓包框架:

头文件: #include <pcap.h> 在/usr/local/include/pcap目录下

1.查找网络设备

char *pcap_lookupdev(char *errbuf)

该函数用于返回可被pcap_open_live()或pcap_lookupnet()函数调用的网络设备名(一个字符串指针)。如果函数出错,则返回NULL,同时errbuf中存放相关的错误消息。

2.获得指定网络设备的网络号和掩码

int pcap_lookupnet(char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp, char *errbuf)

netp参数和maskp参数都是bpf_u_int32指针。如果函数出错,则返回-1,同时errbuf中存放相关的错误消息。

Bpf_u_int32:32位无符号数

Struct in_addr

{

unsigned long s_addr;

}

inet_ntoa();以a.b.c.d的形式显示地址。

3.打开网络设备 

pcap_t *pcap_open_live(char *device,  int snaplen,  int promisc, int to_ms, char *ebuf)

获得用于捕获网络数据包的数据包捕获描述字。device参数为指定打开的网络设备名。snaplen参数定义捕获数据的最大字节数,65535是最大值。promisc指定 是否将网络接口置于混杂模式,设置为1表示混杂模式。to_ms参数指定超时时间(毫秒),设置为0表示超时时间无限大。ebuf参数则仅在pcap_open_live()函数出错返回NULL时用于传递 错误消息。

typedef struct pcap pcap_t;

pcap结构在libpcap源码的pcap-int.h定义,使用时一般都是使用其指针类型)。

4.打开已有的网络数据包 //如果是抓取数据包,这个过程不需要

pcap_t *pcap_open_offline(char *fname, char *errbuf)

fname参数指定打开的文件名。该文件中的数据格式与tcpdump兼容。errbuf参数则仅在pcap_open_offline()函数出错返回NULL时用于传递错误消息。

pcap_t *pcap_fopen_offline(FILE *fp, char *errbuf)打开文件指针。

5.编译和设置过滤条件

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

设置过滤条件,举一些例子:

  • src host 192.168.1.1:只接收源ip地址是192.168.1.1的数据包
  • dst port 80:只接收tcp、udp的目的端口是80的数据包
  • not tcp:只接收不使用tcp协议的数据包
  • tcp[13] == 0x02 and (dst port 22 or dst port 23) :只接收 SYN 标志位置位且目标端口是 22 或 23 的数据包( tcp 首部开始的第 13 个字节)
  • icmp[icmptype] == icmp-echoreply or icmp[icmptype] == icmp-echo:只接收 icmp 的 ping 请求和 ping 响应的数据包
  • ehter dst 00:e0:09:c1:0e:82:只接收以太网 mac 地址是 00:e0:09:c1:0e:82 的数据包
  • ip[8] == 5:只接收 ip 的 ttl=5 的数据包(ip首部开始的第8个字节)

将str参数指定的字符串编译到过滤程序中。fp是一个bpf_program结构的指针,在pcap_compile()函数中被赋值。optimize参数控制结果代码的优化。netmask参数指定本地网络的网络掩码,当不知道的时候可以设为0。出错时返回-1.

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

指定一个过滤程序。fp参数是bpf_program结构指针,通常取自pcap_compile()函数调用。出错时返回-1。

6.抓取和读取数据包

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

捕获并处理数据包。cnt参数指定函数返回前所处理数据包的最大值。cnt=-1表示在一个缓冲区中处理所有的数据包。callback参数指定一个带有三个参数的回调函数,这三个参数为:一个从 pcap_dispatch()函数传递过来的u_char指针,一个pcap_pkthdr结构的指针,和指向caplen大小的数据包的u_char指针。

struct pcap_pkthdr {

struct tim ts;   // ts是一个结构struct timeval,它有两个部分,第一部分是1900开始以来的秒数,第二部分是当前秒之后的毫秒数

bpf_u_int32 caplen;    //表示抓到的数据长度

bpf_u_int32 len;    //表示数据包的实际长度

};

user参数是留给用户使用的,当callback被调用的时候这个值会传递给callback的第一个参数(也叫user)。

成功 则返回读到的数据包数。返回0没有抓到数据包。出错时则返回-1,此时可调用pcap_perror()或pcap_geterr()函数获取错误消息。返回-2表示调用了pcap_breakloop().

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

功能基本与pcap_dispatch()函数类似,只不过此函数在cnt个数据包被处理或出现错误时才返回,但读取超时不会返回。

u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)

读取下一个数据包,类似于pcap_dispatch()中cnt参数设为1,返回指向读到的数据包的指针,但是不返回这个包的pcap_pkthdr结构的参数。

7.关闭文件释放资源

void pcap_close(pcap_t *p)

关闭P指针。

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <pcap.h>
  4
  5 #define PCAP_DATABUF_MAX 65535
  6
  7 #define ETHERTYPE_IPV4 0x0800
  8 #define ETHERTYPE_IPV6 0x86DD
  9
 10 typedef unsigned char   u_int8;
 11 typedef unsigned short  u_int16;
 12 typedef unsigned int    u_int32;
 13 typedef unsigned long   u_int64;
 14
 15 /*MAC头,总长度14字节 */
 16 typedef struct _eth_hdr{
 17     u_int8 dst_mac[6];
 18     u_int8 src_mac[6];
 19     u_int16 eth_type;
 20 }eth_hdr;
 21 eth_hdr *ethernet;
 22
 23 /*IP头*/
 24 typedef struct _ip_hdr{
 25     u_int8 ver_hl;    //版本和头长
 26     u_int8 serv_type; //服务类型
 27     u_int16 pkt_len;  //包总长
 28     u_int16 re_mark;  //重组标志
 29     u_int16 flag_seg; //标志位和段偏移量
 30     u_int8 surv_tm;    //生存时间
 31     u_int8 protocol;  //协议码(判断传输层是哪一个协议)
 32     u_int16 h_check;  //头检验和
 33     u_int32 src_ip;   //源ip
 34     u_int32 dst_ip;   //目的ip
 35     u_int32 option;   //可选选项
 36 }ip_hdr;
 37 ip_hdr *ip;
 38
 39 /*TCP头,总长度20字节,不包括可选选项*/
 40 typedef struct _tcp_hdr{
 41     u_int16 sport;     //源端口
 42     u_int16 dport;     //目的端口
 43     u_int32 seq;       //序列号
 44     u_int32 ack;       //确认序号
 45     u_int8  head_len;  //头长度
 46     u_int8  flags;     //保留和标记位
 47     u_int16 wind_size; //窗口大小
 48     u_int16 check_sum; //校验和
 49     u_int16 urgent_p;  //紧急指针
 50 }tcp_hdr;
 51 tcp_hdr *tcp;
 52
 53 /*UDP头,总长度8个字节*/
 54 typedef struct _udp_hdr{
 55     u_int16 sport;     //源端口
 56     u_int16 dport;     //目的端口
 57     u_int16 pktlen;    //UDP头和数据的总长度
 58     u_int16 check_sum; //校验和
 59 }udp_hdr;
 60 udp_hdr *udp;
 61
 62 //ip整型转换点分十进制
 63 char *InttoIpv4str(u_int32 num){
 64     char* ipstr = (char*)calloc(128, sizeof(char*));
 65
 66     if (ipstr)
 67         sprintf(ipstr, "%d.%d.%d.%d", num >> 24 & 255, num >> 16 & 255, num >> 8 & 255, num & 255);
 68     else
 69         printf("failed to Allocate memory...");
 70
 71     return ipstr;
 72 }
 73
 74 void pcap_callback(u_char *useless,const struct pcap_pkthdr *pkthdr, const u_char *packet)
 75 {
 76     printf("data len:%u\n", pkthdr->caplen); //抓到时的数据长度
 77     printf("packet size:%u\n", pkthdr->len); //数据包实际的长度
 78
 79     /*解析数据链路层 以太网头*/
 80     ethernet = (struct _eth_hdr*)packet;
 81     u_int64 src_mac = ntohs( ethernet->src_mac );
 82     u_int64 dst_mac = ntohs( ethernet->dst_mac );
 83
 84     printf("src_mac:%lu\n",src_mac);
 85     printf("dst_mac:%lu\n",dst_mac);
 86     printf("eth_type:%u\n",ethernet->eth_type);
 87
 88     u_int32 eth_len = sizeof(struct _eth_hdr);  //以太网头的长度
 89     u_int32 ip_len; //ip头的长度
 90     u_int32 tcp_len = sizeof(struct _tcp_hdr);  //tcp头的长度
 91     u_int32 udp_len = sizeof(struct _udp_hdr);  //udp头的长度
 92
 93     /*解析网络层  IP头*/
 94     if(ntohs(ethernet->eth_type) == ETHERTYPE_IPV4){  //IPV4
 95         printf("It's IPv4!\n");
 96
 97         ip = (struct _ip_hdr*)(packet + eth_len);
 98         ip_len = (ip->ver_hl & 0x0f)*4;            //ip头的长度
 99         u_int32 saddr = (u_int32)ntohl(ip->src_ip); //网络字节序转换成主机字节序
100         u_int32 daddr = (u_int32)ntohl(ip->dst_ip);
101
102         printf("eth_len:%u  ip_len:%u  tcp_len:%u  udp_len:%u\n", eth_len, ip_len, tcp_len, udp_len);
103
104         printf("src_ip:%s\n", InttoIpv4str(saddr));  //源IP地址
105         printf("dst_ip:%s\n", InttoIpv4str(daddr));  //目的IP地址
106
107         printf("ip->proto:%u\n", ip->protocol);      //传输层用的哪一个协议
108
109         /*解析传输层  TCP、UDP、ICMP*/
110         if(ip->protocol == 6){         //TCP
111             tcp = (struct _tcp_hdr*)(packet + eth_len + ip_len);
112             printf("tcp_sport = %u\n", tcp->sport);
113             printf("tcp_dport = %u\n", tcp->dport);
114
115 /**********(pcaket + eth_len + ip_len + tcp_len)就是TCP协议传输的正文数据了***********/
116
117         }else if(ip->protocol == 17){  //UDP
118             udp = (struct _udp_hdr*)(packet + eth_len + ip_len);
119             printf("udp_sport = %u\n", udp->sport);
120             printf("udp_dport = %u\n", udp->dport);
121
122 /**********(pcaket + eth_len + ip_len + udp_len)就是UDP协议传输的正文数据了***********/
123
124         }else if(ip->protocol == 1){   //ICMP
125
126         }
127
128     }else if(ntohs(ethernet->eth_type) == ETHERTYPE_IPV6){ //IPV6
129         printf("It's IPv6!\n");
130     }
131
132     printf("============================================\n");
133 }
134
135 int main()
136 {
137     char *dev;  //设备名
138     char errbuf[PCAP_ERRBUF_SIZE] = {}; //PCAP_ERRBUF_SIZE在pcap.h中已经定义
139     bpf_u_int32 netp, maskp;  //网络号和掩码
140     pcap_t *handler;          //数据包捕获描述字
141     struct bpf_program *fp;
142     char *filter_str = "port 9000";  //过滤条件
143
144     /*Find network devices*/
145     if((dev = pcap_lookupdev(errbuf)) == NULL){
146         printf("lookupdev failed:%s\n", errbuf);
147         exit(1);
148     }else{
149         printf("Device:%s\n", dev);
150     }
151
152     /*Get the network number and mask of the network device*/
153     if(pcap_lookupnet(dev, &netp, &maskp, errbuf) == -1){
154         printf("%s\n", errbuf);
155         exit(1);
156     }
157
158     /*Open network device*/
159     if((handler = pcap_open_live(dev, PCAP_DATABUF_MAX, 1, 0, errbuf)) == NULL){
160         printf("%s\n", errbuf);
161         exit(1);
162     }
163
164     /*Compiling and setting filtering conditions*/
165     if(pcap_compile(handler, fp, filter_str, 0, maskp) == -1){
166         printf("pcap_compile error...\n");
167         exit(1);
168     }
169     if(pcap_setfilter(handler, fp) == -1){
170         printf("pcap_setfilter error...\n");
171         exit(1);
172     }
173
174     /*Capturing and processing data packets*/
175     if(pcap_loop(handler, -1, pcap_callback, NULL) == -1){
176         printf("pcap_loop error...\n");
177         pcap_close(handler);
178     }
179
180     return 0;
181 }   

转载于:https://www.cnblogs.com/itsad/p/7885113.html

libpcap抓取数据包相关推荐

  1. python怎么编写wireshark抓的包_使用Wireshark 抓取数据包

    Wireshark 是一个网络封包分析软件.网络封包分析软件的功能是获取网络封包,并尽可能显示出最为详细的网络封包资料.Wireshark使用WinPCAP作为接口,直接与网卡进行数据报文交换. 一  ...

  2. 夜神模拟器抓取数据包

    学习记录 & 以及为需要的人节约时间 1.拿到burp 的证书文件, 2.使用kali 自带的openssl 对证书进行处理 openssl x509 -inform DER -in cace ...

  3. wireshark设置端口镜像_H3C交换机端口镜像,抓取数据包wireshark实战

    端口镜像 system-vies     //进入配置模式 用户名:admin 密码:admin(默认) [H3C] dis cu int  查看所有端口的配置 [H3C] mirroring-gro ...

  4. 使用Wireshark抓取数据包

    1.通过wireshark官网下载:https://www.wireshark.org/ 2.设置捕获过滤器 打开wireshark,菜单–>捕获–>捕获过滤器(F),如图1 在捕获过滤器 ...

  5. python抓取数据包_利用python-pypcap抓取带VLAN标签的数据包方法

    1.背景介绍 在采用通常的socket抓包方式下,操作系统会自动将收到包的VLAN信息剥离,导致上层应用收到的包不会含有VLAN标签信息.而libpcap虽然是基于socket实现抓包,但在收到数据包 ...

  6. Wireshark抓取数据包

    分析ICMP协议数据包 实验原理 ping是用来测试网络连通性的命令,一旦发出ping命令,主机会发出连续的测试数据包到网络中,在通常的情况下,主机会收到回应数据包,ping采用的是ICMP协议. 实 ...

  7. python抓取数据包_python抓数据包

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 前言:数据科学越来越火了,网页是数据很大的一个来源. 最近很多人问怎么抓网页数据 ...

  8. 使用Charles 抓取数据包

    一.Charles抓取不到http请求 Charles 安装好,启动了之后,基于HTTP的数据抓取,一般情况下直接设置Proxy ->Proxy Settings->Port (8888) ...

  9. java抓取数据包查询12306余票信息

    最近项目比较闲,闲来无事,参照网上的代码实现了一下抓取12306数据包查询余票的代码, 需要的jar包需要全部包含到项目下,代码测试OK,具体代码如下: import java.io.IOExcept ...

最新文章

  1. HeadFirst设计模式篇十:状态模式
  2. 【Android 逆向】ELF 文件格式总结 ★★★
  3. Nginx log error:client sent invalid userid cookie
  4. java实例_图例 | Java混合模式分析之火焰图实例
  5. [云炬创业基础笔记]第六章商业模式测试13
  6. js 加入debug后可以进入controller_新手入门Nest.js(四) 控制器路由
  7. 设计模式的理解:桥模式 Bridge
  8. 自动挂载ios_开机自动挂载iso
  9. 微软笔试题(看到的写答案啊)
  10. 获取和保存当前屏幕的截图 实现的C++代码如下
  11. CVE-2017-8046 复现与分析
  12. XJad反编译工具下载链接及使用教程
  13. Ubuntu虚拟机镜像下载及创建
  14. canvas实现点连线动画
  15. 升级到Tomcat9之后js中文乱码解决办法
  16. java 阳历日期时间获取年月日时干支
  17. 计算机文档考试题目及答案,计算机word考试题及答案解析
  18. 港中深、华为联合培养,韩晓光课题组招收三维视觉数字人方向博士生
  19. 女神是麦当娜男神是小沈阳
  20. 测试你最关心的QQ好友并爬取空间留言

热门文章

  1. redis和memcache的区别
  2. UT斯达康XV6700上网终极设置
  3. linux中用户的分类
  4. 深度 | 一条查询SQL的前世今生 —— ClickHouse 源码阅读
  5. 干货,别再浪费时间到处找了,各大面试题和答案都在这里
  6. 什么决定了程序员的价格,程序员该如何溢价
  7. 这大概是一篇最简单最清晰的Java JVM执行流程
  8. 在servlet中设置的字符编码集为什么还会出现乱码(亲测)
  9. JS对象与Dom对象与jQuery对象之间的区别
  10. 计算机408试题2014,2014年考研计算机统考408真题