linux平台libpcap函数分析及流程(…

     在linux平台libpcap函数分析及流程(1)中讲述了一些常用函数的使用,在这篇文章中将介绍源码实现,本源码在ubuntu9.0下顺利运行。

 

#include

#include
#include

#define CAP_LEN 2048

int main(int argc, char *argv[])
{
    bpf_u_int32 netaddr = 0, mask = 0;  
    int caplen=CAP_LEN;
    char errbuf[PCAP_ERRBUF_SIZE];

 

    char * device; 
    device=pcap_lookupdev(errbuf);  
    if (device == NULL)               
        exit(printf("%s n", errbuf));       
    #ifdef _DEBUG_       
       printf("device is %s /n",device);       
    #endif 

 

    pcap_t * phandle;    
    phandle = pcap_open_live(device, caplen, 1, 512, errbuf); 
    if(phandle == NULL)
       exit(printf("%s/n",errbuf));

    //返回pcap_open_live被调用后的snapshot参数值
    int i=pcap_snapshot(phandle);
    if(caplen < i)
    {              
        printf("snaplen raised from %d to %d /n", caplen, i);                      
        caplen=i;               
    }

 

    if(pcap_lookupnet(device, &netaddr, &mask, errbuf) < 0)
    {                      
        netaddr=0;                      
        mask=0;                      
        printf("%s/n", errbuf);       
    }

 

    struct bpf_program fcode;   
    if (pcap_compile(phandle, &fcode, "", 1, mask) < 0)              
         exit(printf("Error %s/n","pcap_compile"));

 

    if (pcap_setfilter(phandle, &fcode) < 0)              
        exit(printf("Error %s/n","pcap_setfilter"));

 

    system("ifconfig");

 

    struct pcap_pkthdr pkthdr;
    const unsigned char * packet = NULL;
    while(1)
    {
         packet = pcap_next(phandle, &pkthdr);

         printf("success\n");

         //……
       
    }

    pcap_close(phandle);
    return 0;
}

 

结构的内部定义:

struct pcap_pkthdr
{
      struct timeval ts;   ts是一个结构struct timeval,它有两个部分,第一部分是1900开始以来的秒数,第二部分是当前秒之后的毫秒数
      bpf_u_int32 caplen;  表示抓到的数据长度
      bpf_u_int32 len;     表示数据包的实际长度
}

 

    几乎所有的操作系统(BSD, AIX, Mac OS, Linux等)都会在内核中提供过滤数据包的方法,主要都是基于BSD Packet Filter(BPF)结构的。libpcap利用BPF来过滤数据包。
    BPF使用一种类似于汇编语言的语法书写过滤表达式,不过libpcap和tcpdump都把它封装成更高级且更容易的语法了,具体可以man tcpdump。
以下是一些例子:
 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个字节)

 

      文章中具体介绍了捕获数据包的源码,最后还列举了一些过滤表达式的用法,希望看了文章以后能对抓包有一定的认识。最后,我还想多说几句,每个人抓到包的目的不一样,可以根据自己的需要将包进行解包,然后重新组包,这些都可以做到,不过我提醒一点,要对捕获的数据包的数据分析,要将TCP/IP协议深入的学习,理解,这不是一朝一夕的事,然后在编写代码时,不同的系统底层对TCP/IP协议的实现有一些小的差别,个人根据自己的系统加以修改,编写出适合自己需求的程序。

你可能感兴趣的:(linux平台libpcap函数分析及流程(…)