为什么我的数据包读取程序返回错误的数据?

时间:2011-11-28 17:33:29

标签: c linux libpcap

我编写了一个使用libpcap读取捕获文件的数据包读取器。它读取捕获文件并将捕获的数据上载到MySQL数据库。有时它似乎工作正常而其他它返回无效数据(例如,源和目标IP将是相同的,tcp端口都是垃圾)。我在虚拟RHEL 5下运行它。这是我的代码(对不起,如果它很长或不必要地复杂,这是我第一次尝试这个)。

#include <arpa/inet.h>
#include <net/ethernet.h>

#include <netinet/ether.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
#include <netinet/ip.h>

#include "npc_tcp.h"
#include "npc_udp.h"

#include <ftw.h>
#include <pcap.h>
#include <stdio.h>
#include <sys/stat.h>
#include <regex.h>
#include <string.h>
#include <time.h>

const int IPTYPE_TCP = 6;
const int IPTYPE_UDP = 17;

struct cap_data {
  char ts[64];
  u_int16_t ether_type;
  u_int16_t proto;
  char *srcip;
  char *dstip;
  char *srcmac;
  u_int16_t srcport;
  u_int16_t dstport;
  u_int8_t flags;
  u_int capsize;
};

int main(int argc, char **argv) {

  //pcap
  struct cap_data data;
  struct pcap_pkthdr pkthdr;
  const u_char *packet;
  pcap_t *handle;
  char *fname = argv[1];
  printf("%s\n", fname);
  char errbuf[PCAP_ERRBUF_SIZE]; 
  handle = pcap_open_offline(fname, errbuf);
  char buf[1000];

  while (packet = pcap_next(handle, &pkthdr)) {

    int ether_flag;
    struct ether_header *ether;    
    u_short ether_type;           

    ether = (struct ether_header *) packet;
    data.ether_type = ntohs(ether->ether_type);

    ether_flag = 1;

    if (ether_flag) {
      if (data.ether_type == ETHERTYPE_IP) {
        struct ip *ip_hdr;
        u_int length = pkthdr.len;

        ip_hdr = (struct ip *)(packet + sizeof(struct ether_header));

      data.proto = ip_hdr->ip_p;
      data.dstip = inet_ntoa(ip_hdr->ip_dst);
      data.srcip = inet_ntoa(ip_hdr->ip_src);

      if (data.proto == IPTYPE_TCP) {
        struct tcphdr *tcp;
        tcp = (struct tcphdr*)(packet + sizeof(struct ether_header) + 
                sizeof(struct ip));

        data.srcport = tcp->th_sport;
        data.dstport = tcp->th_dport;

        printf("%s %u   %s %u\n\n", inet_ntoa(ip_hdr->ip_src), tcp->th_sport, inet_ntoa(ip_hdr->ip_dst), tcp->th_dport);

      } else if (data.proto == IPTYPE_UDP) {
        struct udphdr *udp;
        udp = (struct udphdr *)(packet + sizeof(struct ether_header) + 
                sizeof(struct ip));
        data.srcport = udp->uh_sport;
        data.dstport = udp->uh_dport;

        printf("%s %u   %s %u\n\n", inet_ntoa(ip_hdr->ip_src), udp->uh_sport, inet_ntoa(ip_hdr->ip_dst), udp->uh_dport);

        }
      }
    }
  }//while

  pcap_close(handle);

  return 0;
} 

更新:

这输出..

source ip      port   dest ip       port

66.68.236.207 30151     66.68.236.207 47873

172.22.162.235 60920    172.22.162.235 36175

67.207.28.150 23007     67.207.28.150 22038

172.22.162.235 60920    172.22.162.235 36175

67.207.28.151 22038     67.207.28.151 23007

65.55.87.43 20480       65.55.87.43 21764

67.207.28.150 23007     67.207.28.150 22038

地址不应该相同,端口号也是错误的。

我不知道在哪里开始寻找错误,因为我的代码(至少对我而言)看起来是正确的。任何帮助,提示或建议将不胜感激。谢谢:))

2 个答案:

答案 0 :(得分:1)

两个问题:

  1. inet_ntoa返回指向静态缓冲区的指针 在同一个printf中调用它两次时,它会覆盖相同的缓冲区。所以你最终打印相同的数据 改为使用inet_ntop,并为每个调用提供一个单独的缓冲区。

  2. 在打印之前,您应该使用ntohs()将端口转换为主机顺序。

答案 1 :(得分:0)

如果在调用pcap_open_offline()后立即执行

会发生什么情况
if (pcap_datalink(handle) != DLT_EN10MB) {
  fprintf(stderr, "This program handles only Ethernet captures\n");
  return 2;
}