现在的位置: 首页 > 综合 > 正文

Winpcap学习笔记(2)

2013年09月10日 ⁄ 综合 ⁄ 共 4876字 ⁄ 字号 评论关闭

版权信息:

本文来自internet,转载这里供网络编程爱好者学习和研究使用,请尊重作者的劳动成果。未经授权而在商业上使用原作者的文章属侵权行为,后果由使用者自负,本人不承担任何法律责任。

 

今天在阅读Winpcap Manual的时候发现一句话:

       “This means that on shared media (like non-switched Ethernet), WinPcap will be able to capture the packets of other hosts.”

   我理解为:如果在通过没有交换功能的集线器连接的网络上,只要把网卡设置为混杂(promiscuous)模式,winpcap能够捕获到其他主机通信的数据包。如果是具有交换功能的集线器连接的网络winpcap还能管用吗?这个在后边的实习中将会进行试验。

    试验程序2:

/*
* 截获数据包的试验。先打印出所有网络适配器的列表,然后选择
* 想在哪个适配器上截获数据包。然后通过pcap_loop()函数将截获
* 的数据包传给回调函数packet_handler()处理。

* 通过该程序初步了解了使用winpcap截获数据包的步骤以及一些在
* 截获数据包时非常重要的函数和结构体。
* 2006-1-26
*/

#include <pcap.h>
#include <remote-ext.h>

/* Prototype of the packet handler */
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];

 /* Retrieve the devices list on the local machine */
 if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
 {
  fprintf(stderr, "Error in pcap_findalldevs: %s/n", errbuf);
  exit(1);
 }

 /* Print the list */
 for (d = alldevs; d; d = d->next)
 {
  /* Print name */
  printf("%d. %s", ++ i, d->name);

  /* Print description */
  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;
 }

 /* Select an adapter */
 printf("Enter the interface number (1 - %d):", i);
 scanf("%d", &inum);

 if (inum < 1 || inum > i)
 {
  printf("/nInterface number out of range./n");
  /* Free the device list */
  pcap_freealldevs(alldevs);
  return -1;
 }

 /* Jump to the selected adapter */
 for (d = alldevs, i = 0; i < inum - 1; d = d->next, ++ i);

 /*Open the device */
 if ((adhandle = pcap_open(d->name, /* name of the device */
  65536,         /* portion of the packet to capture */
  /* 65535 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, "/nnable to open the adapter. %s is not supported by Winpcap/n", d->name);
   /* Free the devices list */
   pcap_freealldevs(alldevs);

   return -1;
 }

 printf("/nlistening on %s.../n", d->description);

 /* At this point, we don’t need any more the device list. Free it */
 pcap_freealldevs(alldevs);
 /* start the capture */
 pcap_loop(adhandle, 0, packet_handler, NULL);

 return 1;
}

/* Callback function invoked by libpcap for every incoming packet */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) {
 struct tm *ltime;
 char timestr[16];

 /* convert the timestamp to readable format */
 ltime = localtime(&header->ts.tv_sec);
 strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime);
 printf("%s, %.6d len:%d/n", timestr, header->ts.tv_usec, header->len);
}

 

函数1:

pcap_t *pcap_open(const char *               source,

int                              snaplen,

int                              flags, [Page]

int                              read_timeout,

struct pcap_rmtauth *       auth,

char *                        errbuf

)

    为捕获/发送数据打开一个普通的源。pcap_open()能够替代所有的pcap_open_xxx()函数,它隐藏了不同的pcap_open_xxx()之间的差异,所以程序员不必使用不同的open函数。

source:的是包含要打开的源名称的以’/0’结尾的字符串。源名称得包含新的源规范语法(Source Specification Syntax),并且它不能为NULL。为了方便的使用源语法,请记住:(1)pcap_findalldevs_ex()返回的适配器(网卡)可以直接被pcap_open()使用;(2)万一用户想传递他自己的源字符串给pcap_open(),pcap_createsrcstr()可以创建正确的源标识。

snaplen:需要保留的数据包的长度。对每一个过滤器接收到的数据包,第一个‘snaplen’字节的内容将被保存到缓冲区,并且传递给用户程序。例如,snaplen等于100,那么仅仅每一个数据包的第一个100字节的内容被保存。简言之就是从每一个包的开头到snaplen的那段内容将被保存。

flags:保存一些由于抓包需要的标志。Winpcap定义了三种标志:

l         PCAP_OPENFLAG_PROMISCUOUS:1,它定义了适配器(网卡)是否进入混杂模式(promiscuous mode)。

l         PCAP_OPENFLAG_DATATX_UDP:2,它定义了数据传输(假如是远程抓包)是否用UDP协议来处理。

l         PCAP_OPENFLAG_NOCAPTURE_RPCAP:4,它定义了远程探测器是否捕获它自己产生的数据包。

read_timeout:以毫秒为单位。read timeout被用来设置在遇到一个数据包的时候读操作不必立即返回,而是等待一段时间,让更多的数据包到来后从OS内核一次读多个数据包。并非所有的平台都支持read timeout;在不支持read timeout的平台上它将被忽略。

auth:一个指向’struct pcap_rmtauth’的指针,保存当一个用户登录到某个远程机器上时的必要信息。假如不是远程抓包,该指针被设置为NULL。

errbuf:一个指向用户申请的缓冲区的指针,存放当该函数出错时的错误信息。

返回值是一个’pcap_t’指针,它可以作为下一步调用(例如pcap_compile()等)的参数,并且指定了一个已经打开的Winpcap会话。在遇到问题的情况下,它返回NULL并且’errbuf’变量保存了错误信息。

 

函数2:

int pcap_loop(  pcap_t*           p,

int                   cnt,

pcap_hander    callback,

u_char*           user

)

    收集一群数据包。pcap_loop()与pcap_dispatch()类似,但是它会一直保持读数据包的操作直到cnt包被处理或者发生了错误。当有活动的读超时(read timeout)时它并不返回。然而,对pcap_open_live()指定一个非0的读超时(read timeout),当发生超时的时候调用pcap_dispatch()来接收并处理到来的所有数据包更好。Cnt指明了返回之前要处理数据包的最大数目。如果cnt为负值,pcap_loop()将一直循环(直到发生错误才停止)。如果出错时返回-1;如果cnt用完时返回0;如果在任何包被处理前调用pcap_breakloop()来中止循环将返回-2。所以,如果程序中使用了pcap_breakloop(),必须准确的来判断返回值是-1还是-2,而不能简单的判断<0。

 

函数3:

hypedef void (* pcap_handler)(u_char* user,

const struct pcap_pkthdr* pkt_header,

const u_char* pkt_data)

    接收数据包的回调函数原型。当用户程序使用pcap_dispatch()或者pcap_loop(),数据包以这种回调的方法传给应用程序。用户参数是用户自己定义的包含捕获会话状态的参数,它必须跟pcap_dispatch()和pcap_loop()的参数相一致。pkt_hader是与抓包驱动有关的头。pkt_data指向包里的数据,包括协议头。

 

结构体1:

struct pcap_pkthdr {

      struct timeval ts;

      bpf_u_int32 caplen;

      bpf_u_int32 len;

}

ts:时间戳

cpalen:当前分组的长度

len:数据包的长度
 

本篇文章来源于 中国协议分析网|www.cnpaf.net 原文链接:http://www.cnpaf.net/Class/winpcap/200610/16293.html

抱歉!评论已关闭.