#include  " pcap.h "


void  packet_handler(u_char  * param,  const   struct  pcap_pkthdr  * header,  const  u_char  * pkt_data);

int  main()
{
pcap_if_t 
*alldevs;
pcap_if_t 
*d;
int inum;
int i=0;
pcap_t 
*adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
   
   
    
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
    
{
        fprintf(stderr,
"Error in pcap_findalldevs: %s\n", errbuf);
        exit(
1);
    }

   
   
    
for(d=alldevs; d; d=d->next)
    
{
        printf(
"%d. %s"++i, d->name);
        
if (d->description)
            printf(
" (%s)\n", d->description);
        
else
            printf(
" (No description available)\n");
    }

   
    
if(i==0)
    
{
        printf(
"\nNo interfaces found! Make sure WinPcap is installed.\n");
        
return -1;
    }

   
    printf(
"Enter the interface number (1-%d):",i);
    scanf_s(
"%d"&inum);
   
    
if(inum < 1 || inum > i)
    
{
        printf(
"\nInterface number out of range.\n");
       
        pcap_freealldevs(alldevs);
        
return -1;
    }

   
   
    
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
   
   
    
if ( (adhandle= pcap_open(d->name,          // name of the device
                              65536,            // portion of the packet to capture
                                                
// 65536 guarantees that the whole packet will be captured on all the link layers
                              PCAP_OPENFLAG_PROMISCUOUS,    // promiscuous mode
                              1000,             // read timeout
                              NULL,             // authentication on the remote machine
                              errbuf            // error buffer
                              ) ) == NULL)
    
{
        fprintf(stderr,
"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
       
        pcap_freealldevs(alldevs);
        
return -1;
    }

   
    printf(
"\nlistening on %s\n", d->description);
   
   
    pcap_freealldevs(alldevs);
   
   
    pcap_loop(adhandle, 
0, packet_handler, NULL);
   
    
return 0;
}




void  packet_handler(u_char  * param,  const   struct  pcap_pkthdr  * header,  const  u_char  * pkt_data)
{
    
struct tm ltime;
    
char timestr[16];
    time_t local_tv_sec;

   
    (VOID)(param);
    (VOID)(pkt_data);

   
    local_tv_sec 
= header->ts.tv_sec;
    localtime_s(
&ltime, &local_tv_sec);
    strftime( timestr, 
sizeof timestr, "%H:%M:%S"&ltime);
   
    printf(
"%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
   
}


这里主要是想说明下回调函数的各个参数,顺便讲下pcap_loop

 

int pcap_loop (

pcap_t * p,

int cnt,

pcap_handler callback,

u_char * user  

)

 

pcap_t结构对开发者是不透明的,一般是由pcap_open返回,可以认为是抓包的句柄。cnt表示抓到cnt个包后loop结束,callback就是处理包的回调函数了。user只是用来描述这次抓包,可以置为NULL,如果觉得需要,也可以把抓包的目的啊什么的写上去。

-1 is returned on an error; 0 is returned if cnt is exhausted; -2 is returned if the loop terminated due to a call to pcap_breakloop() before any packets were processed. If your application uses pcap_breakloop(), make sure that you explicitly check for -1 and -2, rather than just checking for a return value < 0.

出错返回-1,抓完了cnt个包返回0,在处理包之前就调用pcap_breakloop()终结loop则返回-2.所有如果调用了pcap_breakloop() ,必须检查返回值是-1还是-2,不能来笼统检查是否小于0.

 

int pcap_dispatch (

pcap_t * p,

int cnt,

pcap_handler callback,

u_char * user  

)

 

pcap_dispatch和pcap_loop的唯一区别是pcap_dispatch会因为超时而结束(这个时间是在pcap_open里面设置的),pcap_loop则不管,一定要抓玩cnt个包

pcap_t* pcap_open  ( const char *  source, 
  int  snaplen, 
  int  flags, 
  int  read_timeout //就是这个设置超时了,单位是毫秒
  struct pcap_rmtauth *  auth, 
  char *  errbuf  
 )

 

typedef void(* pcap_handler)(u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data)

 

user就是pcap_loop里的u_char*user

pkt_header是winpcap给抓到的包附上的头,不是IP报文头部、UDP报文头部等等协议头部。

struct pcap_pkthdr {
 struct timeval ts; 
 bpf_u_int32 caplen; 
 bpf_u_int32 len; 
};

pkt_data是抓到的包数据,这里包括了协议的头部。


pcap_open_live()的实现

pcap_t* pcap_open ( const char * source,
    int snaplen,
    int flags,
    int read_timeout,
    struct pcap_rmtauth * auth,
    char * errbuf  
  )

    adhandle= pcap_open(d->name,          // 监听的适配器名称
                              65536,            // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容
         PCAP_OPENFLAG_PROMISCUOUS,    // 混杂模式
                              1000,             // 读取超时时间
                              NULL,             // 远程机器验证
                              errbuf) ;         // 错误缓冲池

现在已经知道了如何去获得网卡的信息现在就打开网卡并捕获数据流。打开网卡的功能是通过pcap_open_live()来实现的它有三个参数snaplen、flagsread_timeout

snaplen用于指定所捕获包的特定部分,在一些系统上(象xBSD and Win32等)驱动只给出所捕获数据包的一部分而不是全部,这样就减少了拷贝数据的数量从而提高了包捕获的效率。

promisc指明网卡处于混杂模式,在正常情况下网卡只接受去往它的包而去往其他主机的数据包则被忽略。相反当网卡处于混杂 模式时他将接收所有的流经它的数据包:这就意味着在共享介质的情况下我门可以捕获到其它主机的数据包。大部分的包捕获程序都将混杂模式设为默认,下面的例子里也将网卡设为混杂模式。

read_timeout 参数指定读数据的超时控制,超时以毫秒计算。此参数用来指示当一个数据包被发现,read不用立即返回,而是等待一会儿让更多的数据包到达,这时从OS内核的一次读操作中读取多个数据包。当在超时时间内网卡上没有数据到来时对网卡的读操作将返回(如pcap_dispatch() or pcap_next_ex()等函数)。还有,如果网卡处于统计模式下read_timeout还定义了统计的时间间隔。如果该参数为0那么意味着没有超时控制,对网卡的读操作在没有数据到来是将永远堵塞。如果为-1那么对网卡的读操作将立即返回不管有没有数据可读。read_timeout不是所有平台支持,有些平台不支持,那么该参数被忽略。

auth: 一个指向struct pcap_rmtauth的指针。用来保存所需的授权信息。如果是本机上面,设置为NULL。