• 转载自:http://blog.csdn.net/tennysonsky/article/details/44811899
  • 概述
    • libpcap是一个网络数据包捕获函数库,tcpdump就是以libpcap为基础的。
    • 主要作用:
      • 捕获各种数据包,例如:网络流量统计
      • 过滤网络数据包,例如:过滤掉本地上的一些数据,类似防火墙
      • 分析网络数据包,例如:分析网络协议,数据的采集
      • 存储网络数据包,例如:保存捕获的数据以为将来进行分析
  • libpcap的抓包框架
    • pcap_lookupdev():函数用来查找网络设备,返回可被pcap_open_live()函数调用的网络设备名指针。
    • pcap_lookupnet():函数获得指定网络设备的网络号和掩码。
    • pcap_open_live():函数用于打开设备,并且返回用于捕获网络数据包的数据包捕获描述字。对于此网络设备的操作都要基于此网络设备描述字。
    • pcap_compile():函数用于将用户制定的过滤策略编译到过滤程序中
    • pcap_setfilter():函数用于设置过滤器
    • pcap_loop():与pcap_next()和pcap_next_ex()两个函数一样用来捕获数据包
    • pcap_close():函数用于关闭网络设备,释放资源
  • 利用libpcap函数库开发应用程序的步骤:

    • 打开网络设备
    • 设置过滤规则
    • 捕获数据
    • 关闭网络设备
  • 详细步骤:

    • 首先要使用libpcap,需要包含pcap.h头文件。
    • 获取网络设备接口:
      • char *pcap_lookupdev(char * errbuf);
      • 功能:自动获取可用的网络设备名指针
      • 参数:errbuf,存放出错信息字符串,有宏定义缓冲区大小,PCAP_ERRBUF_SIZE
      • 返回值:成功返回设备名指针(第一个合适的网络接口的字符串指针),失败则返回NULL,同时,errbuf存放出错信息字符串
      •  //自动获取网络接口形式
        char errBuf[PCAP_ERRBUF_SIZE], *devStr;
        devStr = pcap_lookupdev(errBuf); //手动获取网络接口形式只需要被devStr赋值即可
        char errBuf[PCAP_ERRBUF_SIZE], *devStr = “eth0”;
    • 获取网络号(ip地址)和掩码
      • int pcap_lookupnet(char* device,bpf_u_int32 *netp,bpf_u_int32 *maskp,char *errbuf);
      • 功能:获取指定网卡的ip地址,子网掩码
      • 参数:device:网络设备名,为第一步获取的网络接口字符串,也可以人为指定,如“eth0”;
      • netp:存放ip地址的指针,buf_u_int32为32位无符号整型
      • maskp:存放子网掩码的指针
      • errbuf:存放出错信息
      • 返回值:成功返回0,失败返回1
      •  char error_content[PCAP_ERRBUF_SIZE] = {}; // 出错信息
        char *dev = pcap_lookupdev(error_content);
        if(NULL == dev)
        {
        printf(error_content);
        exit(-);
        } bpf_u_int32 netp = , maskp = ;
        pcap_t * pcap_handle = NULL;
        int ret = ; //获得网络号和掩码
        ret = pcap_lookupnet(dev, &netp, &maskp, error_content);
        if(ret == -)
        {
        printf(error_content);
        exit(-);
        }
    • 打开网络接口
      • pcap_t *pcap_open_live(const char * device,int snaplen,int promisc,int to_ms,char *errbuf);
      • 功能:打开一个用于捕获数据的网络端口
      • 参数:device:网络接口的名字,为第一步获取的网络接口字符串,也可以人为指定,如:”eth0“
      • snaplen:捕获数据包的长度,不能大于65535个字节
      • promise:”1“代表混杂模式,其他值代表非混杂模式
      • to_ms:指定需要等地啊的毫秒数,超过这个时间后,获得数据包的函数会立即返回,0表示一直等待直到有数据包到来
      • errbuf:存储错误信息
      • 返回值:返回pcap_t类型指针,后面的所有操作都要使用这个指针。
      •  char error_content[PCAP_ERRBUF_SIZE] = {}; // 出错信息
        char *dev = pcap_lookupdev(error_content); // 获取网络接口
        if(NULL == dev)
        {
        printf(error_content);
        exit(-);
        } // 打开网络接口
        pcap_t * pcap_handle = pcap_open_live(dev, , , , error_content);
        if(NULL == pcap_handle)
        {
        printf(error_content);
        exit(-);
        }
    • 获取数据包:
      • 方法一:const u_char *pcap_next(pcap_t *p,struct pcap_pkthdr *h);
      • 功能:捕获一个网络数据包,收到一个数据包立即返回
      • 参数:p:pcap_open_live()返回的pcap_t类型的指针
      • h:数据包头
      • pcap_pkthdr类型的定义如下:
      •  struct pcap_pkthdr
        {
        struct timeval ts; // 抓到包的时间
        bpf_u_int32 caplen; // 表示抓到的数据长度
        bpf_u_int32 len; // 表示数据包的实际长度
        }
      • len和caplen的区别:因为在某些情况下不能保证捕获的包是完整的,例如一个包长1480,但是你捕获到1000的时候,可能因为某些原因就终止捕获了,所以caplen是记录实际捕获的包长,也就是1000,而len就是1480
      • 返回值:成功则返回捕获数据包的地址,失败返回NULL
      •  const unsigned char *p_packet_content = NULL; // 保存接收到的数据包的起始地址
        pcap_t *pcap_handle = NULL;
        struct pcap_pkthdr protocol_header; pcap_handle = pcap_open_live("eth0", , , ,NULL); p_packet_content = pcap_next(pcap_handle, &protocol_header);
        //p_packet_content 所捕获数据包的地址 printf("Capture Time is :%s",ctime((const time_t *)&protocol_header.ts.tv_sec)); // 时间
        printf("Packet Lenght is :%d\n",protocol_header.len); // 数据包的实际长度
      • 方法二:int pcap_loop(pcap_t *p,int cnt,pcap_handler callback,u_char *user);
      • 功能:循环捕获网络数据包,直到遇到错误或者满足退出条件,每次捕获一个数据包就会调用callback指定的回调函数,所以,可以在回调函数中进行数据包的处理操作。
      • 参数:p:pcap_open_live()返回的pcap_t类型的指针
      • cnt:指定捕获数据包的个数,一旦抓到cnt个数据包,pcap_loop立即返回,如果是-1,就会一直捕获直到出错
      • callback:回调函数,名字任意,根据需要自行取名
      • user:向回调函数中传递的参数
      • callback回调函数的定义:
        • void callback(u_char *userarg,const struct pcap_pkthdr *pkthdr,const u_char *packet)
        • userarg:pcap_loop()的最后一个参数,当收到足够数量的包后pcap_loop会调用callback回调函数,同时将pcap_loop()的user参数传递给它
        • pkthdr:是收到数据包的pcap_pkthdr类型的指针,和pcap_next()第二个参数是一样的
        • packet:收到的数据包数据
        • 返回值:成功返回0,失败返回负数
      • 方法三:int pcap_dispatch(pcap_t *p,int cnt,pcap_handler callback,u_char *user);
        • 这个函数和pcap_loop()非常类似,只是在超过to_ms毫秒后就会返回(to_ms是pcap_open_live()的第四个参数)
    • 释放网络接口:
      • void pcap_close(pcap_t *p);
      • 功能:关闭pcap_open_live()打开的网络接口,并释放相关资源
      • 参数:p:需要关闭的网络接口,pcap_open_live()的返回值
      •  // 打开网络接口
        pcap_t * pcap_handle = pcap_open_live("eth0", , , , error_content);
        if(NULL == pcap_handle)
        {
        printf(error_content);
        exit(-);
        } //// ……
        //// …… pcap_close(pcap_handle); //释放网络接口
  • //接收一个数据包
    #include <stdio.h>
    #include <pcap.h>
    #include <arpa/inet.h>
    #include <time.h>
    #include <stdlib.h>
    struct ether_header
    {
    unsigned char ether_dhost[]; //目的mac
    unsigned char ether_shost[]; //源mac
    unsigned short ether_type; //以太网类型
    };
    #define BUFSIZE 1514 int main(int argc,char *argv[])
    {
    pcap_t * pcap_handle = NULL;
    char error_content[] = ""; // 出错信息
    const unsigned char *p_packet_content = NULL; // 保存接收到的数据包的起始地址
    unsigned char *p_mac_string = NULL; // 保存mac的地址,临时变量
    unsigned short ethernet_type = ; // 以太网类型
    char *p_net_interface_name = NULL; // 接口名字
    struct pcap_pkthdr protocol_header;
    struct ether_header *ethernet_protocol; //获得接口名
    p_net_interface_name = pcap_lookupdev(error_content);
    if(NULL == p_net_interface_name)
    {
    perror("pcap_lookupdev");
    exit(-);
    } //打开网络接口
    pcap_handle = pcap_open_live(p_net_interface_name,BUFSIZE,,,error_content);
    p_packet_content = pcap_next(pcap_handle,&protocol_header); printf("------------------------------------------------------------------------\n");
    printf("capture a Packet from p_net_interface_name :%s\n",p_net_interface_name);
    printf("Capture Time is :%s",ctime((const time_t *)&protocol_header.ts.tv_sec));
    printf("Packet Lenght is :%d\n",protocol_header.len); /*
    *分析以太网中的 源mac、目的mac
    */
    ethernet_protocol = (struct ether_header *)p_packet_content;
    p_mac_string = (unsigned char *)ethernet_protocol->ether_shost;//获取源mac
    printf("Mac Source Address is %02x:%02x:%02x:%02x:%02x:%02x\n",*(p_mac_string+),*(p_mac_string+),*(p_mac_string+),*(p_mac_string+),*(p_mac_string+),*(p_mac_string+));
    p_mac_string = (unsigned char *)ethernet_protocol->ether_dhost;//获取目的mac
    printf("Mac Destination Address is %02x:%02x:%02x:%02x:%02x:%02x\n",*(p_mac_string+),*(p_mac_string+),*(p_mac_string+),*(p_mac_string+),*(p_mac_string+),*(p_mac_string+)); /*
    *获得以太网的数据包的地址,然后分析出上层网络协议的类型
    */
    ethernet_type = ntohs(ethernet_protocol->ether_type);
    printf("Ethernet type is :%04x\t",ethernet_type);
    switch(ethernet_type)
    {
    case 0x0800:printf("The network layer is IP protocol\n");break;//ip
    case 0x0806:printf("The network layer is ARP protocol\n");break;//arp
    case 0x0835:printf("The network layer is RARP protocol\n");break;//rarp
    default:printf("The network layer unknow!\n");break;
    } pcap_close(pcap_handle);
    return ;
    }
  • //接收多个数据包 #include <stdio.h>
    #include <pcap.h>
    #include <arpa/inet.h>
    #include <time.h>
    #include <stdlib.h> #define BUFSIZE 1514 struct ether_header
    {
    unsigned char ether_dhost[]; //目的mac
    unsigned char ether_shost[]; //源mac
    unsigned short ether_type; //以太网类型
    }; /*******************************回调函数************************************/
    void ethernet_protocol_callback(unsigned char *argument,const struct pcap_pkthdr *packet_heaher,const unsigned char *packet_content)
    {
    unsigned char *mac_string; //
    struct ether_header *ethernet_protocol;
    unsigned short ethernet_type; //以太网类型
    printf("----------------------------------------------------\n");
    printf("%s\n", ctime((time_t *)&(packet_heaher->ts.tv_sec))); //转换时间
    ethernet_protocol = (struct ether_header *)packet_content; mac_string = (unsigned char *)ethernet_protocol->ether_shost;//获取源mac地址
    printf("Mac Source Address is %02x:%02x:%02x:%02x:%02x:%02x\n",*(mac_string+),*(mac_string+),*(mac_string+),*(mac_string+),*(mac_string+),*(mac_string+));
    mac_string = (unsigned char *)ethernet_protocol->ether_dhost;//获取目的mac
    printf("Mac Destination Address is %02x:%02x:%02x:%02x:%02x:%02x\n",*(mac_string+),*(mac_string+),*(mac_string+),*(mac_string+),*(mac_string+),*(mac_string+)); ethernet_type = ntohs(ethernet_protocol->ether_type);//获得以太网的类型
    printf("Ethernet type is :%04x\n",ethernet_type);
    switch(ethernet_type)
    {
    case 0x0800:printf("The network layer is IP protocol\n");break;//ip
    case 0x0806:printf("The network layer is ARP protocol\n");break;//arp
    case 0x0835:printf("The network layer is RARP protocol\n");break;//rarp
    default:break;
    }
    usleep(*);
    } int main(int argc, char *argv[])
    {
    char error_content[]; //出错信息
    pcap_t * pcap_handle;
    unsigned char *mac_string;
    unsigned short ethernet_type; //以太网类型
    char *net_interface = NULL; //接口名字
    struct pcap_pkthdr protocol_header;
    struct ether_header *ethernet_protocol; //获取网络接口
    net_interface = pcap_lookupdev(error_content);
    if(NULL == net_interface)
    {
    perror("pcap_lookupdev");
    exit(-);
    } pcap_handle = pcap_open_live(net_interface,BUFSIZE,,,error_content);//打开网络接口 if(pcap_loop(pcap_handle,-,ethernet_protocol_callback,NULL) < )
    {
    perror("pcap_loop");
    } pcap_close(pcap_handle);
    return ;
    }
  • 过滤数据包:
    • 设置过滤条件:举一些例子:
      • src host 192.168.1.177:只接收源ip地址是192.168.1.177的数据包
      • 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个字节)
    • 编译BPF过滤规则:
      • int pcap_compile(pcap_t *p,struct bpf_program *fp,char *buf,int optimize,bpf_u_int32 mask);
      • 参数:
        • p:pcap_open_live()返回的pcap_t类型的指针
        • fp:存放编译后的bpf,应用过来规则时需要使用这个指针
        • buf:过滤规则
        • optimize:是否需要优化过滤表达式
        • mask:指定本地网络的网络掩码,不需要时可写0
      • 返回值:成功返回0,失败返回-1
    • 应用BPF过滤规则:
      • int pcap_setfilter(pcap_t *p,struct bpf_program *fp);
      • 功能:应用BPF过滤规则
      • 参数:p:pcap_open_live()返回的pcap_t类型的指针
      • fp:pcap_compile()的第二个参数
      • 返回值:成功返回0,失败返回-1
      •  #include <pcap.h>
        #include <time.h>
        #include <stdlib.h>
        #include <stdio.h> void getPacket(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
        {
        int * id = (int *)arg; printf("id: %d\n", ++(*id));
        printf("Packet length: %d\n", pkthdr->len);
        printf("Number of bytes: %d\n", pkthdr->caplen);
        printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec)); int i;
        for(i=; i<pkthdr->len; ++i)
        {
        printf(" %02x", packet[i]);
        if( (i + ) % == )
        {
        printf("\n");
        }
        } printf("\n\n");
        } int main()
        {
        char errBuf[PCAP_ERRBUF_SIZE], * devStr; /* get a device */
        devStr = pcap_lookupdev(errBuf); if(devStr)
        {
        printf("success: device: %s\n", devStr);
        }
        else
        {
        printf("error: %s\n", errBuf);
        exit();
        } /* open a device, wait until a packet arrives */
        pcap_t * device = pcap_open_live(devStr, , , , errBuf); if(!device)
        {
        printf("error: pcap_open_live(): %s\n", errBuf);
        exit();
        } /* construct a filter */
        struct bpf_program filter;
        pcap_compile(device, &filter, "dst port 80", , );
        pcap_setfilter(device, &filter); /* wait loop forever */
        int id = ;
        pcap_loop(device, -, getPacket, (u_char*)&id); pcap_close(device); return ;
        }

利用libpcap抓取数据包的更多相关文章

  1. 利用Fiddler抓取websocket包

    一.利用fiddler抓取websockt包 打开Fiddler,点开菜单栏的Rules,选择Customize Rules... 这时会打开CustomRules.js文件,在class Handl ...

  2. Android移动网络如何抓取数据包

    1)下载tcpdump工具 tcpdump(dump the traffic on a network)是Linux中强大的网络数据采集分析工具之一,可以将网络中传送的数据包头完全截获下来提供分析.它 ...

  3. tcpdump 基于mac地址抓取数据包

    1.刚刚接触tcpdump时,常用tcpdump -i eth1 host 192.168.1.1 这个命令基于ip地址抓取数据包信息. tcpdump -i eth1(接口名称) host 192. ...

  4. Fiddler抓取数据包分析案例

    案例:利用Fiddler抓取苏宁易购网站数据包分析 抓包软件:Fiddler4 请求名字:www.suning.com 详细内容: 一.了解数据包区域的字段含义 图1数据包区域 #:顺序号,按照抓包的 ...

  5. 利用tcpdump抓取网络包

    1.下载并安装tcpdump 下载地址:tcpdump 安装tcpdump,连接adb adb push tcpdump /data/local/tcpdump adb shell chmod 675 ...

  6. 利用libpcap抓取QQ号码信息

    最近想在QQ登录时把QQ号码信息记录下来,百度了很多都没有找到具体方式,最近用Wireshark分析报文+libpcap库嗅探实现了这个小功能. 通讯背景: QQ客户端在通讯时使用UDP协议,其中数据 ...

  7. 使用Wireshark 抓取数据包

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

  8. WinPcap抓取数据包

    #WinPcap和Libpcap的最强大的特性之一,是拥有过滤数据包的引擎. 它提供了有效的方法去获取网络中的某些数据包,这也是WinPcap捕获机制中的一个组成部分. 用来过滤数据包的函数是#

  9. iPhone 手机用 Fiddler 抓取数据包 问题

    近日公司服务升级,将所有的接口请求由HTTP升级为了HTTPS,升级后在手机中安装了Fiddler的证书,Android端抓取HTTPS请求一切正常,可是在ios端抓取HTTPS请求时一直提示“此服务 ...

随机推荐

  1. activity带参跳转和界面登录

    首先 首先是MainActivity的xml文件 <?xml version="1.0" encoding="utf-8"?> <Linear ...

  2. hue中访问hdfs报错

    在hue中访问hdfs报错: Cannot access: /. Note: you are a Hue admin but not a HDFS superuser, "hdfs" ...

  3. 安卓10GB内存旗舰手机的普及,能成为拯救DRAM厂商的救命稻草吗?

    你对2019年手机即将展现出的全新变化,有哪些期待?是全新的处理器.更名副其实的全面屏,还是愈发强大的拍照功能,抑或折叠屏幕?但不管你有怎样的期待,手机厂商似乎总是"不解风情".常 ...

  4. MySQL 批量更新、删除数据shell脚本

    #!/bin/bash. ~/.bash_profilelog=/tmp/update_log_1_$(date +%F).logvstart=1step=100vstop=$((${vstart}+ ...

  5. C++编程学习(十一) 指针和引用的区别

    1.指针有自己的一块空间,而引用只是一个别名: 2.使用sizeof看一个指针的大小是4,而引用则是被引用对象的大小: 3.指针可以被初始化为NULL,而引用必须被初始化且必须是一个已有对象 的引用: ...

  6. Redis详解(五)——主从复制

    Redis详解(五)--主从复制 面临问题 机器故障.我们部署到一台 Redis 服务器,当发生机器故障时,需要迁移到另外一台服务器并且要保证数据是同步的.而数据是最重要的,如果你不在乎,基本上也就不 ...

  7. WFP之WFP简介

    ·过滤引擎是WFP的核心组成部分,过滤引擎分为两大层:用户态基础过滤引擎和内核态过滤引擎.基础过滤引擎会与内核过滤引擎交互.·内核态过滤引擎是整个过滤引擎的主体,内部分为多个分层,每分层都代表着网络协 ...

  8. MSVCRTD.LIB和LIBCMTD.LIB冲突(转载)

    以前经常遇到这个警告信息,因为运行并没有什么问题,所以也没深究.但是耿耿于怀那个“ 0 个错误,0 个警告”的成功提示,在网上搜了一下.原来问题出在默认库的引用选择上. VS2008,项目——属性—— ...

  9. 十六、JavaScript之%运算符

    一.代码如下 二.运行效果如下 <!DOCTYPE html> <html> <meta http-equiv="Content-Type" cont ...

  10. 【机器学习实战笔记(3-2)】朴素贝叶斯法及应用的python实现

    文章目录 1.朴素贝叶斯法的Python实现 1.1 准备数据:从文本中构建词向量 1.2 训练算法:从词向量计算概率 1.3 测试算法:根据现实情况修改分类器 1.4 准备数据:文档词袋模型 2.示 ...