manio的libpcap使用总结

要包含文件pcap.h

1.获取设备名
使用
char * pcap_lookupdev ( char * errbuf );
来获取设备名,例如返回"eth0",errbuf是出错信息字符串,一旦函数出错,其中将会包括出错信息
errbuf一般定义为
char errbuf[PCAP_ERRBUF_SIZE];

2.获取设备描述符
就像对文件操作时要取得文件描述符一样,在这里要取得网卡的描述符
pcap_t * pcap_open_live ( char * device, int snaplen, int promisc,
                          int to_ms, char * errbuf );
pcap_t就是网卡描述符的类型,
device是设备名,如eth0
snaplen是要抓获的最大的包的字节数
promisc如果为非0的话,则将网卡设为混杂模式
to_ms是超时时间,如果为0则永不超时
errbuf与上同

如果pcap_open_live返回NULL,则表明函数执行出错,errbuf的值将会被设置

3.循环处理包
int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)

pcap_loop会一直读取包,直到读完cnt个数据包
当cnt为负时,pcap_loop会永远循环运行
对于每一个包,pcap_loop会一直尝试读取,直到pcap_open_live中设置的to_ms时间达到时仍未成功读取包.
callback是一个回调函数,当抓取到一个包时,就会调用这个callback函数

callback的protype是
typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *);
u_char(第一个参数)是从pcap_loop传入的值,即pcap_loop中的user.
const struct pcap_pkthdr是一个结构体,成员如下
              ts     a  struct timeval containing the time when the packet was
                     captured
              struct timeval {
                  time_t      tv_sec;     /* seconds */
                  suseconds_t tv_usec;    /* microseconds */
                };
       timeval中给出距1970年1月1日0时0分0秒的时间


              caplen a bpf_u_int32 giving the number of bytes  of  the  packet
                     that are available from the capture
       给出包的大小,以byte为单位

              len    a  bpf_u_int32  giving the length of the packet, in bytes
                     (which might be more than the number of  bytes  available
                     from  the  capture, if the length of the packet is larger
                     than the maximum number of bytes to capture)
       这个值可能比caplen大,因为包的实际大小有可能比程序中所设置的抓包的最大长度大.
const u_char *,指向包中最开始caplen比特大小数据.不过这些数据可能不是整个包的数据,因为有可能在pcap_open_live中设置的snaplen可能小于包的大小,所以就有可能得不到整个包,如果一定要得到整个包,可以将snaplen设置为65535

返回值:
pcap_loop返回-1,表明运行时出错
pcap_loop返回0,表明已经读取了cnt个包
pcap_loop返回-1,表明循环被pcap_breakloop()中止

4.关闭设备
void pcap_close(pcap_t *p)
关闭设备并释放资源

5.获取下一个包
const u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)
这个函数其实是调用pcap_dispatch()(令参数cnt为1),返回指向包中数据的指针.在这个函数中,pcap_pkthdr结构没有提供.
当函数产生错误或者没有抓到包时,函数返回NULL,

6.编译过滤器
int pcap_compile(pcap_t *p, struct bpf_program *fp
                 char *str, int optimize, bpf_u_int32 netmask)
编译过滤字符串str,
netmask是要被过滤的子网掩码,这个参数只在检查IPV4广播地址时使用
optimize表明是否被优化

7.使用过滤器
int pcap_setfilter(pcap_t *p, struct bpf_program *fp)

// fedora core 6,gcc
// compile:gcc thisfile.c -o xthisfile -lpcap
#include  < stdio.h >
#include 
< stdlib.h >
#include 
< pcap.h >
#include 
< errno.h >
#include 
< sys / socket.h >
#include 
< netinet / in .h >
#include 
< arpa / inet.h >
#include 
< netinet / if_ether.h >   /*  includes net/ethernet.h  */


struct  my_ip {
    u_int8_t    ip_vhl;        
/*  header length, version  */
#define  IP_V(ip)    (((ip)->ip_vhl & 0xf0) >> 4)
#define  IP_HL(ip)    ((ip)->ip_vhl & 0x0f)
    u_int8_t    ip_tos;        
/*  type of service  */
    u_int16_t    ip_len;        
/*  total length  */
    u_int16_t    ip_id;        
/*  identification  */
    u_int16_t    ip_off;        
/*  fragment offset field  */
#define     IP_DF 0x4000            /* dont fragment flag */
#define     IP_MF 0x2000            /* more fragments flag */
#define     IP_OFFMASK 0x1fff        /* mask for fragmenting bits */
    u_int8_t    ip_ttl;        
/*  time to live  */
    u_int8_t    ip_p;        
/*  protocol  */
    u_int16_t    ip_sum;        
/*  checksum  */
    
struct     in_addr ip_src,ip_dst;     /*  source and dest address  */
};


/////////////////////////////////////// /
// 回调函数,用于对抓获的包做相应处理
void  pkt_callback(u_char  * arg1,  const   struct  pcap_pkthdr  * phdr, const  u_char  * packet)
{
    
struct  in_addr ipaddr; // ipv4地址
     struct  my_ip  * ipptr;  // ip数据报头指针
     struct  tcphdr  * tcpptr; // tcp数据报头指针
     struct  ether_header  * eptr; // 以太网报头指针
     char   * chtmp;
    
static   int  ipcnt = 0 ,arpcnt = 0 ;
    
if ( packet  ==  NULL ){
        printf(
" Didn't get any packet! " );
        exit(
1 );
    }
    printf(
" *************************** " );
    printf(
" capure time:%s " ,ctime(( const  time_t * ) & (phdr -> ts.tv_sec)));
    printf(
" the length of packet captured:%ld; the total length:%ld " ,
            phdr
-> caplen,phdr -> len);
    
// 得到以太网帧结构的数据
    eptr  =  ( struct  ether_header * )packet;

    
if ( ntohs(eptr -> ether_type)  ==  ETHERTYPE_IP ){
        printf(
" IP " );
    
        
// decode ip header
        printf( " decoding ip header now " );
        
// 将指针指向ip数据报报头
        ipptr  =  ( struct  my_ip *  )(packet  +   sizeof ( struct  ether_header));
        printf(
" the total length of the IP packet:%d " ,IP_HL(ipptr));
        printf(
" the version:%d " ,IP_V(ipptr));
        printf(
" ttl:%d " ,ipptr -> ip_ttl);
        
        
++ ipcnt;
    }
else   if  ( ntohs(eptr -> ether_type)  ==  ETHERTYPE_ARP){
        printf(
" ARP " );
        
++ arpcnt;
    }
else {
        printf(
" Packet is not IP or ARP.(%x) " ,ntohs(eptr -> ether_type));
    }
        
    
// print number of packet
    printf( " ip packet number:%d " ,ipcnt);
    printf(
" arp packet number:%d " ,arpcnt);

}

int  main( int  argc, char   ** argv)
{
    
char   *  dev;  // 设备名
    pcap_t  *  pt;  // 网卡设备描述符
     struct  in_addr ipv4addr; // ipv4地址
    bpf_u_int32 netp;
    bpf_u_int32 maskp;
    u_char 
* packet;
    
struct  pcap_pkthdr pdr;  // 包结构体,其中包括了包长度、指向包数据的指针
     char  errbuf[PCAP_ERRBUF_SIZE]; // 存放错误信息
     struct  ether_header  * ethhd; // 指向以太网头部的指针
     struct  bpf_program  * fp; // 用于HOLD滤包程序
    
    
// 查找网卡
     if ( (dev  =  pcap_lookupdev(errbuf))  ==  NULL ){
        printf(
" lookupdev:%s " ,errbuf);
        exit(
1 );
    }
    
// 打开设备,得到描述符
     if ( (pt  =  pcap_open_live(dev,  1000 0 100 , errbuf))  ==  NULL){
        printf(
" pcap_open_live:%s " ,errbuf);
        exit(
1 );
    }
    
// 得到网络IP及掩码
     if ( pcap_lookupnet(dev,  & netp,  & maskp, errbuf)  ==   - 1  ){
        printf(
" pcap_lookupnet:%s " ,errbuf);
        exit(
1 );
    }

    
// 打印网络环境信息
    ipv4addr.s_addr  =  netp;
    printf(
" ================================ " );
    printf(
" device name:%s " ,dev);
    printf(
" net:%s " ,inet_ntoa(ipv4addr));
    ipv4addr.s_addr 
=  maskp;
    printf(
" mask:%s " ,inet_ntoa(ipv4addr));    
    printf(
" ================================ " );

    
//////////////////////////////////// /
     // 开始包的相关处理

    
if ( (pcap_loop(pt,  - 1 , pkt_callback,NULL))  ==   - 1  ){
        perror(
" pcap_loop " );
        exit(
1 );
    }    

    pcap_close(pt);
    printf(
" end of program " );
}

你可能感兴趣的:(struct,网络,header,null,callback,FP)