本站首页    管理页面    写新日志    退出


«August 2025»
12
3456789
10111213141516
17181920212223
24252627282930
31


公告
 菜鸟一只,期望着变成大牛,慢慢来。

我的分类(专题)

日志更新

最新评论

留言板

链接

Blog信息
blog名称:ela'tech_blog
日志总数:4
评论数量:7
留言数量:-1
访问次数:40480
建立时间:2006年3月31日




[网络编程技术]Winpcap不同版本之间的一个小差异导致的错误。
读书笔记

ellx 发表于 2006/4/3 10:42:01

 原来机器中的Winpcap的版本是3.0,程序总是运行不下去,分析之后得知原来是自己的Winpcap版本出了错,其中的一个函数pcap_findalldevs_ex(),在3.0的版本和3.2的版本中的参数的个数不一样,导致程序出错。事例代码如下: #include <pcap.h> #include <remote-ext.h> /* 4 bytes IP address */ typedef struct ip_address {  u_char byte1;  u_char byte2;  u_char byte3;  u_char byte4; }ip_address; /* IPv4 header */ typedef struct ip_header {  u_char ver_ihl;  /* Version (4 bits)版本 + Internet header length 首部长度(4 bits)*/  u_char tos;      /* Type of service 服务类型*/  u_short tlen;    /* Total length 16位标示*/  u_short identification; /* Identification */  u_short flags_fo;       /* Flags (3 bits)三位标志 + Fragment offset十三位偏移 (13 bits)*/  u_char ttl;      /* Time to live八位生存时间 */  u_char proto;    /* Protocol八位协议 */  u_short crc;     /* Header checksum 十六位首部校验和*/  ip_address saddr;/* Source address 32位源IP地址*/  ip_address daddr;/* Destination address 32位目的IP地址*/  u_int op_pad;    /* Option + Padding选项和数据 */ }ip_header; /* UDP header */ typedef struct udp_header {  u_short sport;   /* Source port源端口 */  u_short dport;   /* Destination port 目的端口*/  u_short len;     /* Datagram length 数据长度*/  u_short crc;     /* Checksum 校验和*/ }udp_header; //连接表元素的结构 typedef    struct  link_elem    {         ip_address saddr;  //IP地址Source ip address         ip_address daddr;  //目标IP地址         u_short    sport;  // Source port         u_short    dport;  // Destinaion port         char      *mailsaddr; //源Email地址         char      *maildaddr; //目的Email地址         bool       ifdata; //是否Data         time_t     rtime; //到达时间 }link_elem;         //邮件正文段 typedef    struct data_content     {         char *lcontent;  //正文段         data_content *next_file; //下一个邮件正文段     }data_content; /* 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];  u_int netmask;  char packet_filter[] = "ip and udp";  struct bpf_program fcode;////???????????????????????//  /* Retrieve the device list */  if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)  {     /*     在UNIX操作系统结构中,它把各种外部设备也看成是文件。     所以 fprintf不仅能把errbuf的内容输出到磁盘文件里,     也可以输出到像终端这样的特殊文件里。printf是fprintf的一个特例,     它固定的只能把相应内容输出到终端文件上。     */   fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);   exit(1);  }  /* Print the list*/  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("%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, /* 设备名 */          65536, /* 所截包的大小 */          /* 65536 guarantees that the whole packet will be captured on all the link layers */          PCAP_OPENFLAG_PROMISCUOUS, /* 混杂模式 */          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");   /* Free the devices list */   pcap_freealldevs(alldevs);   return -1;  }  /* Check the link layer. We support only Ethernet for simplicity    int pcap_datalink(pcap_t* p) 返回链路层上的一个适配器。返回链路层的类型,链路层的类型包括: l         DLT_NULL: BSD回路封装;链路层协议头是一个4字节的域,           以主机字节顺序(host byte order),包含一个从socket.h来的PF_value。           主机字节顺序(host byte order)是捕获数据包的机器的字节顺序,           而PF_value是捕获数据包的机器的OS。如果一个读取一个文件,           字节顺序和PF_value不一定是抓取文件的那些机器。 l         DLT_EN10MB: 以太网(10Mb, 100Mb, 1000Mb, 或者更高)。 l         DLT_IEEE802: IEEE802.5令牌环网。 l         DLT_ARCNET:ARCNET。 l         DLT_SLIP:SLIP。 l         DLT_PPP:PPP;如果第一个字节是0xff或0x03,它是类HDLC帧上的PPP。 l         DLT_FDDI:FDDI l         DLT_ATM_RFC1483:RFC1483LLC/SNAP ATM;数据包以IEEE802.2 LLC头开始。 l         DLT_RAW:原始IP(raw IP);数据包以IP头开始。 l         DLT_PPP_SERIAL:按照RFC1662,基于类HDLC帧的PPP,或者按照RFC1547的4.3.1,           基于HDLC帧的Cisco PPP;前者的第一个字节是0xFF,后者的第一个字节是0x0F或0x8F。 l         DLT_PPP_ETHER:按照RFC2516,PPPoE;数据包以PPPoE头开始。 l         DLT_C_HDLC:按照RFC1547的4.3.1,基于HDLC帧的Cisco PPP。 l         DLT_IEEE802_11:IEEE 802.11无线局域网。 l         DLT_FRELAY:帧中继(Frame Relay)。 l         DLT_LOOP:OpenBSD回路封装。 l         DLT_LINUX_SLL:Linux抓包封装。 l         DLT_LTALK:苹果的LocalTalk,数据包以AppleTalk LLAP头开始。 l         DLT_PFLOG:OpenBSD pflog。 l         DLT_PRISM_HEADER:后接802.11头的棱镜监视器模式(Prism monitor mode)信息。 l         DLT_IP_OVER_FC:RFC2625 IP-over-Fiber 频道,以RFC2625中定义的Network_Header开始。 l         DLT_SUNATM:SunATM设备。 l         DLT_IEEE802_11_RADIO:后接802.11头的链路层信息。 l         DLT_ARCNET_LINUX:没有异常帧的ARCNET。 l         DLT_LINUX_IRDA:Linux-IrDA数据包,DLT_LINUX_SLL头后接IrLAP头。   */  if (pcap_datalink(adhandle) != DLT_EN10MB)  {   fprintf(stderr, "\nThis program works only on Ethernet networks.\n");   /* Free the devices list */   pcap_freealldevs(alldevs);   return -1;  } /****************************************************** 就是将pcap_addr结构体中的netmask字段赋值给netmask变量。 if判断表示如果网卡d的addresses不为NULL, 那么就将其中的netmask转化成相应格式的数据并赋值给netmask; 否则,就将netmask变量赋值为ffffffff。 ********************************************************/  if (d->addresses != NULL)  {   /* Retrieve the mask of the first address of the interface */   netmask = ((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;//????????????  }  else  {   /* If the interface is without addresses we suppose to be in a C class network */   netmask = 0xffffffff;  }  /* complie the filter */  if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) < 0)  {   fprintf(stderr, "\nUnable to compile the packet filter. Check the syntax.\n");   /* Free the devices list */   pcap_freealldevs(alldevs);   return -1;  }  /* set the filter */  if (pcap_setfilter(adhandle, &fcode) < 0)  {   fprintf(stderr, "\nError setting the filter.\n");   /* 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];  ip_header* ih;  udp_header* uh;  u_int ip_len;  u_short sport, dport;  /* convert the timestamp to readable format */  ltime = localtime(&header->ts.tv_sec);  strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime);  /* print timestamp and length of the packet */  printf("%s.%.6d len: %d ", timestr, header->ts.tv_usec, header->len);  /* retrieve the position of the ip header */  ih = (ip_header*)(pkt_data + 14);  /* length of ethernet header MAC头是14字节*/  /* retrieve the position of the udp header */      /***********************************************      ih->ver_ihl & 0xf就是ih->ver_ihl与00001111按位与,      这样就能取得ih->ver_ihl的后四位的值,      也就是ip报头中的“报头长度”字段,      再将该按位与的结果乘以4(该字段以4个字节为基本单位),      就得到ip报头有多少个字节。      ************************************************/  ip_len = (ih->ver_ihl & 0xf) * 4 /*IP包头的长度域来获得Ip包头的大小*/;  uh = (udp_header*)((u_char*)ih + ip_len);  /* convert from network byte order to host byte order */  /*sport = ntohs(uh->sport);  dport = ntohs(uh->dport);*/  /* print ip addresses and udp ports */  printf("%d.%d.%d.%d -> %d.%d.%d.%d\n",   ih->saddr.byte1,   ih->saddr.byte2,   ih->saddr.byte3,   ih->saddr.byte4,   /*sport,*/   ih->daddr.byte1,   ih->daddr.byte2,   ih->daddr.byte3,   ih->daddr.byte4   /*dport*/); }


阅读全文(1802) | 回复(1) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.031 second(s), page refreshed 144769945 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号