cnpaf.net - 中国协议分析网

投递文章 投稿指南 RSS订阅 网站通告:
搜索: 您的位置主页>协议分析>Winpcap>阅读文章

循序渐进学习使用WINPCAP(六)

10-16 08:01 来源: 作者: 【 评论:0 浏览:
现在经过上几节的学习能够进行数据报的捕获和过滤了,我们想用一个简单的"real world"程序将我们所学的知识应用于实际。
现在经过上几节的学习能够进行数据报的捕获和过滤了,我们想用一个简单的"real world"程序将我们所学的

知识应用于实际。
这一节里我们将利用以前的代码并将其引申从而建立一个更实用的程序。该程序的主要目的是如何显示出所捕

获的数据报的内容,尤其是对它的协议头的分析和说明。这个程序名叫UDPdump它将在屏幕上显示出我们网络上

UDP数据的信息。
在此我们选择解析UDP而不用TCP因为他比TCP简单更加的直观明了。下面让我们来看看原代码。




/*
* Copyright (c) 1999 - 2002
* Politecnico di Torino. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that: (1) source code distributions
* retain the above copyright notice and this paragraph in its entirety, (2)
* distributions including binary code include the above copyright notice and
* this paragraph in its entirety in the documentation or other materials
* provided with the distribution, and (3) all advertising materials mentioning
* features or use of this software display the following acknowledgement:
* ``This product includes software developed by the Politecnico
* di Torino, and its contributors.’’ Neither the name of
* the University nor the names of its contributors may be used to endorse
* or promote products derived from this software without specific prior
* written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS’’ AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

#include "pcap.h"

/* 4 BIT的IP头定义 */
typedef struct ip_address{
  u_char byte1;
  u_char byte2;
  u_char byte3;
  u_char byte4;
}ip_address;

/* IPv4 头的定义 */
typedef struct ip_header{
  u_char ver_ihl;     // 4 bit的版本信息 + 4 bits的头长
  u_char tos;         // TOS类型 
  u_short tlen;       // 总长度
  u_short identification; // Identification
  u_short flags_fo;     // Flags (3 bits) + Fragment offset (13 bits)
  u_char ttl;         // 生存期
  u_char proto;       // 后面的协议信息
  u_short crc;         // 校验和
  ip_address saddr;     // 源IP
  ip_address daddr;     // 目的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;

/* 定义处理包的函数 */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);


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(&alldevs, errbuf) == -1)
  {
    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"); [Page]
    /* 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 adapter */
  if ( (adhandle= pcap_open_live(d->name, // name of the device
                  65536,   // portion of the packet to capture. 
                          // 65536 grants that the whole packet will be captured on 

all the MACs.
                  1,       // promiscuous mode
                  1000,     // read timeout
                  errbuf   // error buffer
                  ) ) == NULL)
  {
    fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n");
    /* Free the device list */
    pcap_freealldevs(alldevs);
    return -1;
  }
  
  /* Check the link layer. We support only Ethernet for simplicity. */
  if(pcap_datalink(adhandle) != DLT_EN10MB)
  {
    fprintf(stderr,"\nThis program works only on Ethernet networks.\n");
    /* Free the device list */
    pcap_freealldevs(alldevs);
    return -1;
  }
  
  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=0xffffff; 


  //compile 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 device list */
    pcap_freealldevs(alldevs);
    return -1;
  }
  
  //set the filter
  if(pcap_setfilter(adhandle, &fcode)<0){
    fprintf(stderr,"\nError setting the filter.\n");
    /* Free the device 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 0;
}

/* 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);

  /* 找到IP头的位置 */
  ih = (ip_header *) (pkt_data +
    14); //14为以太头的长度

  /* 找到UDP的位置 */
  ip_len = (ih->ver_ihl & 0xf) * 4;
  uh = (udp_header *) ((u_char*)ih + ip_len);

  /* 将端口信息从网络型转变为主机顺序 */
  sport = ntohs( uh->sport );
  dport = ntohs( uh->dport );

  /* print ip addresses and udp ports */ [Page]
  printf("%d.%d.%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);
}

首先我门设置UDP过滤,用这种方法我们确保packet_handler()只接受到基于IPV4的UDP数据。我们同样定义了

两个数据结构来描述IP 和UDP的头部信息,packet_handler()用这两个结构来定位头部的各种字段。
packet_handler()虽然只是限于处理一些UDP数据但却显示了复杂的嗅探器如tcpdump/WinDump的工作原理。
首先我们对MAC地址的头部并不感兴趣所以我们跳过它。不过在开始捕获之前我们用pcap_datalink()来检查MAC

层,所以以上的程序只能够工作在Ethernet networks上,再次我们确保MAC头为14 bytes。
MAC头之后是IP头,我们从中提取出了目的地址。IP之后是UDP,在确定UDP的位置时有点复杂,因为IP的长度以

为版本的不同而不同,所以我们用头长字段来定位UDP,一旦 我们确定了UDP的起始位置,我们就可以解析出原

和目的端口。
下面是我们打印出来的一些结果:

1. {A7FD048A-5D4B-478E-B3C1-34401AC3B72F} (Xircom t 10/100 Adapter) 
Enter the interface number (1-2):1

listening on Xircom CardBus Ethernet 10/100 Adapter... 
16:13:15.312784 len:87 130.192.31.67.2682 -> 130.192.3.21.53 
16:13:15.314796 len:137 130.192.3.21.53 -> 130.192.31.67.2682 
16:13:15.322101 len:78 130.192.31.67.2683 -> 130.192.3.21.53 

上面每一行都显示出不同的数据包的内容.

收藏此篇文章内容到:
Tags:
责任编辑:
  • 请文明参与讨论,禁止漫骂攻击。 用户名:新注册) 密码: 匿名:
    评论总数:0 [ 查看全部 ] 网友评论
    关于我们 - 广告合作 - 网站地图 - 版权说明 - 网站历史 - 世界排名 - 加入收藏 - 设为首页 - 返回顶部