zoukankan      html  css  js  c++  java
  • pcap简单使用和简单解释

    数据类型bpf_u_int32实际上就是u_int的一个别名,还有吧bpf_int32实际上就是int的别名。当然这个int是32位的,如果操作系统对int的定义不是4字节,bpf_int32就对应另外一种类型,总之,bpf_u_int32就是一个32位的无符号整型。

    关键函数:
    int pcap_lookupnet(const char *device, bpf_u_int32 *netp,bpf_u_int32 *maskp, char *errbuf)


    用于获取网卡的网络号和子网掩码。其中device参数是网卡名,netp 和maskp表示将要获得的网络号和子网掩码,都是以网络字节序存放的,比如一个IP为10.108.20.0,那么netp中存放的这个地址就是:1338378。转换成二进制就是:
    00000000 00010100 01101100 00001010
    这个数在内存中的存在形式就是:
    低地址----------------------------------------》高地址
    00001010 01101100 00010100 00000000
    对应每个字节的十进制就是:
    10 108 20 0
    网络字节序和主机字节序比较容易混乱(大端表示和小端表示)。
    网络字节序采用大端表示,就是数据的高位要存放到低地址。
    而大多数主机字节序采用小端表示(也有采用大端表示的主机字节序),就是数据的低位放到低地址。
    比如无符号整型1338378,的二进制表示为:
    数据的高位----------------------------》数据的低位
    00000000 00010100 01101100 00001010
    所以采用小端表示的主机字节序时,内存中存放的形式为:
    低地址----------------------------------------》高地址
    00001010 01101100 00010100 00000000
    errbuf存放错误信息。失败返回-1
    errbuf的大小可以定义为:PCAP_ERRBUF_SIZE


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

    用于打开网络设备,返回一个pcap_t结构体的指针。
    帮助文档中的说法是:用于获取一个数据包捕获的描述符,以便用来查看网络上的数据包。device是网卡名称。snaplen表示捕获的最大字节数,如果这个值小于被捕获的数据包的大小,则只显示前snaplen位(实验表明,后面为全是0),通常来讲数据包的大小不会超过65535。promisc表示是否开启混杂模式。 to_ms 表示读取的超时时间,毫秒为单位,就是说没有必要看到一个数据包这个函数就返回,而是设定一个返回时间,这个时间内可能会读取很多个数据包,然后一起返回。如果这个值为0,这个函数一直等待足够多的数据包到来。errbuf用于存储错误信息。

    int pcap_compile(pcap_t *p, struct bpf_program *fp,char *str, int optimize, bpf_u_int32 netmask)
    用于编译字符串str成为一个过路程序,program参数是一个指向bpf_program结构体的指针,这个参数由函数pcap_compile()填充。optimize参数用于控制是否采用最优化的结果。netmask用于指定IPv4的网络子网掩码,这个参数仅仅在检查过滤程序中的IPv4广播地址时才会使用。

    int pcap_setfilter(pcap_t *p, struct bpf_program *fp)
    用于指定一个过滤器程序,fp是一个指向bpf_program结构体的指针,通常是pcap_compile返回的结果。p通常是pcap_open_live()函数返回的结果。

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

    这个函数用于收集和加工数据包。cnt指定用于加工的数据包的最大数量,超过了这个数量函数就会返回。当读取一个实时捕获的时候,一次仅有一个数据包的缓冲区被读取,所以处理的数据包的个数有可能少于cnt个。当cnt的值为-1时,会处理到达一个缓冲区的所有数据包,或者(如果不是实时捕获而是处理一个pcap文件)会处理文件中所有的数据包。 callback指定了一个回调函数。这个回调函数有三个参数:一个u_char类型的指针,这个参数是通过pcap_dispatch()函数传递的(应该是提供用户使用的), 一个指向pcap_pkthdr结构体常量的指针。这个结构体含有三个域,
    struct pcap_pkthdr
    {
    struct timeval ts; ts是一个结构struct timeval,它有两个部分,第一部分是1900开始以来的秒数,第二部分是当前秒之后的毫秒数。表示数据包捕获的时间。
    bpf_u_int32 caplen; 表示抓到的数据长度
    bpf_u_int32 len; 表示数据包的实际长度
    }
    第二个域是一个u_char常量的指针,指向的一个数据包的前caplen个字节。

    成功返回0,失败返回-1可以用pcap_perror来打印错误信息。
    注意:当读取一个实时捕获时,当读取超时时pcap_dispatch()函数没有必要返回。

    pcap_loop()函数和pcap_dispatch()用法相似。
    int pcap_loop(pcap_t *p, int cnt,pcap_handler callback, u_char *user)
    这个函数当读取超时时也不会返回。

    void pcap_close ( pcap_t * p );
    用于关闭pcap_open_live()获取的包捕捉句柄,释放相关资源。
    一个典型的过程:

    #include <stdio.h>  
    #include <string.h>
    #include <stdlib.h>
    
    #include <pcap.h>  
    
    #include <arpa/inet.h>
    #include <unistd.h>//getopt
    #include <sys/types.h>//u_char
    
    
    void get_packet(u_char *user, const struct pcap_pkthdr *pkthdr, const u_char *packet)
    {
        //    prase_packet(packet, pkthdr->len);
    }
    
    
    int main(int argc,char* argv[])  
    {
        char* device=NULL;
        char ch;
        //getopt()
        //
        if((ch = getopt(argc,argv,"d:"))==-1)
        {
            printf("no options!!!
    ");
            exit(1);
        }
        optind=1;
        while ((ch = getopt(argc, argv, "d:")) != -1)
        {
            switch (ch) 
               {    
                   case 'd':
                if(optarg!=NULL)
                {
                    if(  (  device  =  (char*)malloc(strlen(optarg) ) ) !=NULL)//remeber to free
                    {
                        strcpy(device,optarg);
                        //printf("%s
    ",device);
                    }
                    else
                    {
                        printf("malloc error
    ");
                        exit(1);
                    }
                            
                }
                else
                {
                    exit(1);
                }
                       
                break;
         
                case '?':
                default:
                    printf("Unknown option: %c
    ",(char)optopt);
                    exit(1);
                        
            }
        }
               
        //capture
        if(!device)
        {
              printf("no device
    ");
              exit(1);
        }
                
    
    
        char errBuf[PCAP_ERRBUF_SIZE]; //error Buff
      
       // struct pcap_pkthdr packet;  The header that pcap gives us
           pcap_t *phandle; //network interface
           
           bpf_u_int32 netp, maskp; //网络号和子网掩码
           char *net, *mask;
           struct bpf_program fcode;
           struct in_addr addr;
        //look up device network addr and mask
        //获取网络参数
    
           if(pcap_lookupnet(device, &netp, &maskp, errBuf)==-1) 
           {
            printf("get net failure
    ");
               exit(1);
           }
    
           addr.s_addr = netp;
        printf("%u
    ",netp);
           net = inet_ntoa(addr);
           printf("network: %s
    ", net);
        
           addr.s_addr = maskp;
           mask = inet_ntoa(addr);
           printf("mask: %s
    ", mask);
        
    
        //open network device for packet capture
           phandle = pcap_open_live(device, 65535, 1, 500, errBuf);
           if(NULL == phandle) 
           {
               printf("open %s failure
    ", device);
               perror(errBuf);
               exit(1);
           }
        char* filterString="ether src D8:5D:4C:36:76:83 or ether dst D8:5D:4C:36:76:83";
        
        if(pcap_compile(phandle,&fcode,filterString,0,maskp)==-1)
        {
               fprintf(stderr,"pcap_compile: %s
    ",pcap_geterr(phandle));
               exit(1);
        }
    
        
    
         if(pcap_setfilter(phandle,&fcode)==-1)
         {
               fprintf(stderr,"pcap_setfilter: %s
    ",pcap_geterr(phandle));
               exit(1);
           }
            
        pcap_loop(phandle, -1, get_packet, NULL);
        
            //close device
        pcap_close(phandle);
    
           return 0; 
    }

    如果您觉得对您有帮助,请点赞哦^^。

  • 相关阅读:
    NumPy之:NumPy简介教程
    使用gradle插件发布项目到nexus中央仓库
    【Flutter 面试】main入口函数会被调用几次
    【Flutter 混合开发】与原生通信-BasicMessageChannel
    【Flutter 混合开发】与原生通信-MethodChannel
    震惊!!!Oracle SQL语句中竟然支持中文括号??
    Oracle Merge into中修改表的限制条件位置的区别
    Oracle根据local_listener注册service_name在所有监听的ip端口上
    Oracle如何迁移、管理、清除Audit数据(AUD$和FGA_LOG$表)
    Oracle 颠覆认知的无函数处理限定条件字段也可以用上函数索引
  • 原文地址:https://www.cnblogs.com/qingergege/p/6164519.html
Copyright © 2011-2022 走看看