[转帖]利用 libpcap 库进行流量统计与数据包分析

利用,libpcap,进行,流量,统计,数据包,分析 · 浏览次数 : 0

小编点评

## Code Summary This code captures network packets using `pcap_dump_open` and `pcap_loop`, analyzes the captured data, and writes the extracted information to a pcap file for later analysis. **Key steps:** 1. **Open a device:** - `device = pcap_open_live(devStr, 65535, 1, 0, errBuf)` opens a live capture session on the specified device. 2. **Construct a filter:** - `filter = pcap_compile(device, &filter, filter_app, 1, 0)` constructs a filter to capture packets based on the application port (80 in this case). 3. **Start capturing packets:** - `pcap_loop(device, 10, getPacket, (u_char*)out_pcap)` starts a loop that captures packets for 10 seconds. - `getPacket` function is called for each captured packet and writes the extracted information to the pcap file. 4. **Save captured packets:** - After the capture process is finished, `pcap_dump_flush(out_pcap)` saves the captured packets to a pcap file named "test.pcap". **Additional details:** - `packet_handler` function parses and prints the length of each captured packet. - `ip_header` structure is used to extract and print source and destination IP addresses, port numbers, and received time. - The code demonstrates basic error handling and pcap functionality. **Overall, this code provides a basic example of capturing and analyzing network packets using pcap and writing the captured data to a pcap file.**

正文

https://zhuanlan.zhihu.com/p/437187441

 

一、简介:

Libpcap(Packet Capture Libray),即数据包捕获函数库。该库提供的C函数接口用于捕获经过指定网络接口的数据包,可以统计流量数据,可以添加过滤规则分析数据包数据内容。

Linux下的tcpdump软件就是以他为基础开发的。Windows上也有基于他的库Winpcap

二、资源:

这些地方可以下载安装包和源码:

Libpcap:

http://www.tcpdump.org

Winpcap:

Winpcap中文版:

www.ferrisxu.com/WinPcap/html/group__wpcapfunc.html#g659439bf5aa3988b5a92d31990fbf437

三、安装:

libpcap库需要先安装才能用

1.源码安装:

tar -zxvf libpcap.tar.gz

cd libpcap

sudo ./configure

sudo make

sudo make install

程序被默认安装在/usr/local/lib目录,将程序复制到/usr/lib下:sudo cp libpcap.so.1 /usr/lib/

2.命令安装:

命令安装缺啥补啥

sudo apt-get install libpcap-dev

四、Libpcap工作流程:

1.查找网络设备:pcap_lookupdev()

2.获取网络设备参数:pcap_lookupnet()

3.打开网络设备,返回可操作的句柄:pcap_open_live()

4.将用户制定的过滤策略编译到过滤程序中:pcap_compile()

5.将上一步的策略设置到过滤器:pcap_setfilter()

6.捕获数据包:pcap_loop(),pcap_dispatch(),pcap_next(),pcap_next_ex()

7.关闭网络设备,释放资源:pcap_close()

五、函数功能分析:

1. char * pcap_lookupdev(char * errbuf)

  
功能 查找可用网络设备(网卡名称);也可以自己指定,不用查
参数 errbuf存放出错信息,大小为PCAP_ERRBUF_SIZE
返回值 返回第一个可用的网络接口名称

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

  
功能 获取指定网卡的IP地址,子网掩码等信息
参数 device,1中返回的网卡名称;
netp,传出参数,存放指定网卡的IP地址,需要用inet_ntoa转换成点分十进制字符串;maskp,传出参数,存放指定网卡的子网掩码,需要用inet_ntoa转换成点分十进制字符串;errbuf,存放出错信息,大小为PCAP_ERRBUF_SIZE
返回值 成功返回0;失败返回PCAP_ERROR(-1),并记录信息到errbuf

3. pcap_t * pcap_open_live(const char * device, int snaplen, int promisc, int to_ms, char * errbuf)

  
功能 获取指定接口的可操作句柄,后面的接口需要调用这个句柄
参数 device,1中返回的网卡名称,也可以自己指定;
snaplen,设置需要捕获的每个数据包长度,从数据包开头算起;promisc,指定是否打开混杂模式,0表示非混杂,其他值表示混杂,如果要打开混杂模式,网卡也必须打开混杂模式(ifconfig eth0 promisc);to_ms,指定获取数据包需要等待的毫秒数,超时会立即返回,0表示一直等待直到有数据包到达
返回值 返回指定网卡的pcap_t类型的句柄

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

  
功能 编译构造过滤表达式
参数 p,第1步中返回的网卡名称,也可以自己指定;
fp,传出参数,存放编译后的bpf;str,过滤表达式;optimize,是否需要优化过滤表达式,1表示需要优化;netmask,指定需要捕获的网卡的子网掩码,设为0即可
返回值 成功返回0;失败返回PCAP_ERROR(-1),
pcap_geterr(device) or pcap_perror(device)可以用来获取错误信息

*str(过滤表达式):

过滤表达式有很多参数,支持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not等逻辑语句来帮助你去掉无用的信息:

proto(tcp/udp/arp/ip/ether/icmp等);

dir(src/dst/src and dst/src or dst等);

type(host/net/port/portrange)

一个基本的表达式单元格式为"proto dir type"

  
选择只接受某个IP地址的数据包 src host 127.0.0.1
选择只接受TCP/UDP的目的端口是80的数据包 dst port 80
不接受TCP数据包 not tcp
只接受SYN标志位置(TCP首部开始的第13个字节)且目标端口号是22或23的数据包 tcp[13]==0x02 and (dst port 22 or dst port 23)
只接受icmp的ping请求和ping响应的数据 icmp[icmptype]==icmp-echoreply or icmp[icmptype]==icmp-echo
只接受以太网MAC地址为00:00:00:00:00:00的数据包 ehter dst 00:00:00:00:00:00
只接受ip的ttl=5的数据包(ip首位第八的字节为ttl) ip[8]==5
条件组合 *tcpdump '((tcp) and (port 80) and ((dst host 192.168.1.254) or (dst host 192.168.1.1)))'
*tcpdump -i eth0 '((tcp) and (port 80) and ((dst host 192.168.1.254) or (dst host 192.168.1.1)))'
*tcpdump '((icmp) and ((ether dst host 00:0A:0B:03:0C:05)))'
tcpdump '((tcp) and ((dst net 192.168) and (not dst host 192.168.1.254))'

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

  
功能 设置过滤表达式
参数 p,1中返回的网卡名称,也可以自己指定;
fp,pcap_compile()的第二个参数,存放编译后的bpf
返回值 成功返回0;失败返回PCAP_ERROR(-1),pcap_geterr(device) or pcap_perror(device)可以用来获取错误信息

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

  
功能 捕获数据包
参数 p,1中返回的网卡名称,也可以自己指定;
cnt,设置需要抓包的个数,抓取cnt个包后立即返回,设置为-1表示循环抓包,直到出现错误;callback,回调函数;user,回调函数的参数
返回值 成功返回0;失败返回PCAP_ERROR(-1)或者PCAP_ERROR_BREAK(-2)

callback(回调函数):void callback(u_char * userarg, const struct pcap_pkthdr * pkthdr, const u_char * packet)

  
功能 当收到足够数量的包后pcap_loop会调用callback回调函数,同时将pcap_loop()的user参数传递给它
回调函数参数 userarg是pcap_loop的最后一个参数;
pkthdr,收到的数据包的pcap_pkthdr类型的指针;packet,收到的数据包数据

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

功能:捕获数据包,与pcap_loop类似,在超过to_ms毫秒后就会返回(to_ms是pcap_open_live()的第4个参数)

8. const u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h);

功能:捕获数据包,封装的pcap_dispatch()函数,参数cnt=1

返回值:成功则返回捕获数据包的地址,失败返回NULL

9. void pcap_close(pcap_t * p)

功能:关闭网络设备,释放资源

六、抓包分析

1.const struct pcap_pkthdr * pkthdr (libpcap的包头)

struct pcap_pkthdr  
{  
    struct timeval ts;  // 抓到包的时间,ts.tv_sec是从1997.01.01到现在所经过的秒数,可以用ctime等函数转化成当前时间的字符串
    bpf_u_int32 caplen; // 表示抓到的数据长度,抓取的长度
    bpf_u_int32 len; // 表示数据包的实际长度,本来应有长度
}  

2.const u_char * packet(真正的包的数据,通过结构体去解析它:MAC首部->IP/ARP/RART首部->TCP/UDP/ICMP首部)

//数据包最前面的信息, Mac头部,总长度14字节,然后通过eth_type来解析包后面的内容
typedef struct eth_hdr
{
    u_char dst_mac[6];//目标mac地址  
    u_char src_mac[6];//源mac地址  
    u_short eth_type;//以太网类型:0x0800-IP;0x0806-ARP;0x0835-RARP
}eth_hdr;  

//IP头部,总长度20字节,通过protocol判读传输的是什么协议的数据
typedef struct ip_hdr
{
    int version:4; //版本
    int header_len:4; //首部长度  
    u_char tos:8;//服务类型  
    int total_len:16;//总长度 
    int ident:16;//标志 
    int flags:16;//分片偏移  
    u_char ttl:8;//生存时间  
    u_char protocol:8;//协议:0x01-ICMP;0x06-TCP;0x11-UDP
    int checksum:16;//检验和  
    u_char sourceIP[4];//源IP地址:通过inet_ntoa()函数转换
    u_char destIP[4];//目的IP地址 
}ip_hdr;

 //TCP头部,总长度20字节,通过flags判断是哪种消息
typedef struct tcp_hdr
{
    u_short sport;//源端口号,通过 ntohs()转换
    u_short dport;//目的端口号  
    u_int seq;//序列号
    u_int ack;//确认号 
    u_char head_len; //首部长度  
    u_char flags;//标志位;0x01-FIN,0x02-SYN,0x04-RST,0x08-PSH,0x10-ACK,0x20-URG;
    u_short wind_size;//16位窗口大小  
    u_short check_sum;//16位TCP检验和  
    u_short urg_ptr;//16为紧急指针
}tcp_hdr;

 //UDP头部,总长度8字节  
typedef struct udp_hdr
{
    u_short sport;//远端口号
    u_short dport;//目的端口号 
    u_short tot_len;//udp头部长度
    u_short check_sum;//16位udp检验和  
}udp_hdr;

 //ICMP头部,总长度4字节  
typedef struct _icmp_hdr  
{  
    u_char icmp_type;   //类型  
    u_char code;        //代码  
    u_short chk_sum;    //16位检验和  
}icmp_hdr;   

七、保存抓取到的数据,并保存至test.pcap文件里,可用wireshark打开分析

pcap_dumper_t* out_pcap;  //定义输出文件并打开
out_pcap = pcap_dump_open(device,"/home/test.pcap");
pcap_loop(device,10,packet_handler,(u_char *)out_pcap); //获取10个包,并调用回调函数来存数据
pcap_dump_flush(out_pcap); //刷新缓冲区
pcap_dump_close(out_pcap); //关闭资源

//回调函数完成数据存储
void packet_handler(u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data)
{
   pcap_dump(user, pkt_header, pkt_data);// 输出数据到文件
   printf("a packet with length of %d\n", pkt_header->len);// 打印抓到的包的长度
}

//用wireshark打开保存的记录文件test.pcap就可以分析数据了

八、示例

#include <stdio.h>
#include <pcap.h>
#include <time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>

struct ip_header{
  u_int8_t ip_version: 4;
  u_int8_t ip_header_length: 4;
  u_int8_t ip_tos;
  u_int16_t ip_length;
  u_int16_t ip_id;
  u_int16_t ip_off;
  u_int8_t ip_ttl;
  u_int8_t ip_protocol;
  u_int16_t ip_checksum;
  struct in_addr ip_source_address;
  struct in_addr ip_destination_address;
};

void getPacket(u_char *user, const struct pcap_pkthdr *pkthdr, const u_char *packet);

int main(int argc,char *argv[])    
{    
  char errBuf[PCAP_ERRBUF_SIZE]={0};
  char *devStr = NULL; 
  pcap_t *device = NULL;
  struct bpf_program filter;
  char *filter_app = "port 80";
  pcap_dumper_t* out_pcap;
 
  if(argc>1){  
    devStr = argv[1];  
  }  
  else{   
  /* get a device */    
    devStr = pcap_lookupdev(errBuf);    
  }  
  
  if(devStr)    
  {    
    printf("success: device: %s\n", devStr);    
  }    
  else    
  {    
    printf("error: %s\n", errBuf);    
    exit(1);    
  }    
      
  /* open a device, wait until a packet arrives */    
  device = pcap_open_live(devStr, 65535, 1, 0, errBuf);    
      
  if(!device)    
  {    
    printf("error: pcap_open_live(): %s\n", errBuf);    
    exit(1);    
  }    
      
  /* construct a filter */         
  pcap_compile(device, &filter, filter_app, 1, 0);    
  pcap_setfilter(device, &filter);    
      
  /* wait loop forever */    
  out_pcap = pcap_dump_open(device,"/home/test.pcap");   
  pcap_loop(device, 10, getPacket, (u_char*)out_pcap);    
     
  pcap_dump_flush(out_pcap); //刷新缓冲区
  pcap_dump_close(out_pcap); //关闭资源  
  
  pcap_close(device);    
    
  return 0;    
} 

void getPacket(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet)    
{   
  pcap_dump(user, pkthdr, packet); // 输出数据到文件   
  struct ip_header *ip_protocol;
  ip_protocol=(struct ip_header*)(packet + 14);
 
  printf("Packet length: %d\n", pkthdr->len); 
  printf("Number of capture bytes: %d\n", pkthdr->caplen);    
  printf("Source address:%s\n",inet_ntoa(ip_protocol->ip_source_address));  
  printf("Destination address:%s\n",inet_ntoa(ip_protocol->ip_destination_address));  
  printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec));     
}

与[转帖]利用 libpcap 库进行流量统计与数据包分析相似的内容:

[转帖]利用 libpcap 库进行流量统计与数据包分析

https://zhuanlan.zhihu.com/p/437187441 一、简介: Libpcap(Packet Capture Libray),即数据包捕获函数库。该库提供的C函数接口用于捕获经过指定网络接口的数据包,可以统计流量数据,可以添加过滤规则分析数据包数据内容。 Linux下的tc

[转帖]利用BCC Tools追踪指定PID进程的方法

http://t.zoukankan.com/Emuaer-p-EmuaBCCTools3.html 想法的产生 通过熟悉许多BCC tools后,我们可以通过一些工具的组合,来实现一些定向的进程追踪 execsnoop跟踪新进程创建,跟踪exec函数。 bashreadline打印系统中所有bas

[转帖]利用Python调用outlook自动发送邮件

↓↓↓欢迎关注我的公众号,在这里有数据相关技术经验的优质原创文章↓↓↓ 使用Python发送邮件有两种方式,一种是使用smtp调用邮箱的smtp服务器,另一种是直接调用程序直接发送邮件。而在outlook中我们一般是没有权限去开启smtp服务的,所以一般只能通过第二种直接调用方式发送邮件 基础版本–

[转帖]利用Python调用outlook自动发送邮件

↓↓↓欢迎关注我的公众号,在这里有数据相关技术经验的优质原创文章↓↓↓ 使用Python发送邮件有两种方式,一种是使用smtp调用邮箱的smtp服务器,另一种是直接调用程序直接发送邮件。而在outlook中我们一般是没有权限去开启smtp服务的,所以一般只能通过第二种直接调用方式发送邮件 基础版本–

[转帖]Linux利用Sysctl命令调整内核参数

https://cloud.tencent.com/developer/article/1721513?from=article.detail.1956187&areaSource=106000.18&traceId=lr3VPq-YZBl2ynblhnK3h 前言 sysctl 命令被用于在内核运

[转帖]如何利用wrarp测试oss性能?

https://zhuanlan.zhihu.com/p/529735003 前言 我们利用mino与ceph rgw搭建好的oss经过多层网络转发,传输速度必定有所折损,这个时候我们使用wrap来测试oss对象存储的真实性能。 利用wrarp测试oss性能 wrarp是minio项目下的一个开源测

[转帖]Linux常用命令:利用sed命令删除文件的特定行

http://www.dbs724.com/12806.html 前言 正常来说,我们想要删除文件中的某些行内容,一般都是先打开这个文件,然后找到要删除的内容,再然后选中这些行并按删除键进行删除,这在数据量很少时是没有问题的。但是,一旦文件中的行数据非常多,而且数据冗杂的情况下,你还要用上面的方法去

[转帖]Shell脚本中利用expect实现非交互式

https://developer.aliyun.com/article/885723?spm=a2c6h.24874632.expert-profile.295.7c46cfe9h5DxWK 简介: expect非交互式 expect可以在脚本中完成一些交互式的操作,例如远程登录时要输入yes或者

[转帖]20. 利用Veeam ONE监控vSphere虚拟化平台(Veeam ONE安装及配置)

Veeam Backup & Replication主要用于备份及同步虚拟化平台,而Veeam ONE则主要用于监控平台之用,可以监控Veeam Backup & Replication的备份及同步情况,也可以监控VMware vSphere虚拟化平台及微软的Hyper-v虚拟化平台。本例主要介绍监

[转帖]Zabbix日志监控:Linux异常登录告警

as007012 2022-02-07 摘要: 本文利用zabbix的日志监控功能监控Linux的secure日志,当有用户登录失败或者用户在非常规时间登录成功时发出告警。 这里我们使用zabbix提供的\'log[file,,,,