Chinaunix首页 | 论坛 | 博客
  • 博客访问: 566159
  • 博文数量: 375
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 15
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-20 10:21
文章分类

全部博文(375)

文章存档

2015年(1)

2014年(374)

分类: LINUX

2014-08-18 14:00:07

原文地址:udp流检测统计 作者:zooyo


  1. #include <stdio.h>
  2. #include <pcap.h>
  3. #include <stdlib.h>
  4. #include <time.h>
  5. #include <getopt.h>
  6. #include <linux/if_ether.h>
  7. #include <linux/ip.h>
  8. #include <linux/udp.h>
  9. #include <netinet/in.h>
  10. #include <arpa/inet.h>
  11. #include <string.h>


  12. #define MIN_LEN    (sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr))

  13. #ifdef DEBUG
  14.     #define DEBUGP(format,args...) fprintf(stdout, format, ##args)
  15. #else
  16.     #define DEBUGP(format,args...)
  17. #endif

  18. #define HASHSIZE    (1024 * 1024 * 2)
  19. #define HASH_KEY(ip1, ip2, ports, initval)    jhash_3words(ip1, ip2, ports, initval) % HASHSIZE

  20. /* swap - swap value of @a and @b */
  21. #define swap(a, b) \
  22.     do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)

  23. #define __jhash_mix(a, b, c) { \
  24.      a -= b; a -= c; a ^= (c>>13); \
  25.      b -= c; b -= a; b ^= (a<<8); \
  26.      c -= a; c -= b; c ^= (b>>13); \
  27.      a -= b; a -= c; a ^= (c>>12); \
  28.      b -= c; b -= a; b ^= (a<<16); \
  29.      c -= a; c -= b; c ^= (b>>5); \
  30.      a -= b; a -= c; a ^= (c>>3);    \
  31.      b -= c; b -= a; b ^= (a<<10); \
  32.      c -= a; c -= b; c ^= (b>>15); \
  33. }
  34.     
  35. /* The golden ration: an arbitrary value */
  36. #define JHASH_GOLDEN_RATIO    0x9e3779b9

  37. static struct option opts[] = {
  38.     {.name = "start",    .has_arg = 1, .val = 's'},
  39.     {.name = "end",    .has_arg = 1, .val = 'e'},
  40.     {.name = "file",    .has_arg = 1, .val = 'f'},
  41.     {.name = "help",    .has_arg = 0, .val = 'h'},
  42.     {NULL}
  43. };

  44. enum udpflow_dir{
  45.     UDPFLOW_ORG = 0,
  46.     UDPFLOW_REPLY,
  47.     UDPFLOW_MAX
  48. };

  49. struct udp_tuple{
  50.     u_int32_t src;
  51.     u_int32_t dst;
  52.     u_int16_t sport;
  53.     u_int16_t dport;
  54. };

  55. struct udp_counter{
  56.     u_int64_t bytes;
  57.     u_int32_t packet;
  58.     u_int32_t total;
  59. };

  60. typedef struct _udpflow{
  61.     struct udp_tuple tuple;
  62.     struct udp_counter counter[UDPFLOW_MAX];
  63.     time_t start;
  64.     time_t end;
  65.     struct _udpflow *next;
  66. }udpflow;


  67. static int s = 1, e = 0;
  68. static udpflow *hash_t[HASHSIZE];
  69. static u_int32_t initval;

  70. static inline u_int32_t jhash_3words(u_int32_t a,
  71.                                      u_int32_t b,
  72.                                      u_int32_t c,
  73.                                      u_int32_t initval) {
  74.     a += JHASH_GOLDEN_RATIO;
  75.     b += JHASH_GOLDEN_RATIO;
  76.     c += initval;

  77.     __jhash_mix(a, b, c);

  78.     return c;
  79. }

  80. static void print_help(void) {
  81.     printf("-h Print this help\n");
  82.     printf("-s Began to capture in which package\n");
  83.     printf("-e End capture in which package\n");
  84.     printf("-f Captured packets\n");
  85.     exit(-1);
  86. }

  87. static char* trans_time(time_t sec) {
  88.     static char buf[32];
  89.     struct tm *date;
  90.     date = localtime(&sec);
  91.     strftime(buf, 64, "%Y-%m-%d %H:%M:%S", date);
  92.     return buf;
  93. }

  94. static u_int32_t hash_udpflow(struct udp_tuple *tuple) {
  95.     union {
  96.         u_int32_t v32;
  97.         u_int16_t v16[2];
  98.     }ports;    
  99.     u_int32_t hash, sip, tip;

  100.     sip = tuple->src;
  101.     tip = tuple->dst;
  102.     ports.v16[0] = tuple->sport;
  103.     ports.v16[1] = tuple->dport;

  104.     /*
  105.      无论是请求数据还是应答数据都排序后送去哈希
  106.      这样使得同一个流的哈希结果是一样
  107.     */
  108.     if(sip < tip)    swap(sip, tip);
  109.     if(ports.v16[0] < ports.v16[1])    swap(ports.v16[0], ports.v16[1]);
  110.     hash = HASH_KEY(sip, tip, ports.v32, initval);
  111.     
  112.     return hash;        
  113. }

  114. static udpflow *lookup(struct udp_tuple *tuple, u_int32_t hash, int *dir) {
  115.     udpflow *pNode = hash_t[hash];
  116.     while(pNode != NULL) {
  117.         /*
  118.         遍历链表的每个节点, 如果查询到统一方向是请求数据
  119.         反方向是应答数据, 第一个数据包就确认为请求包
  120.         */
  121.         if(pNode->tuple.src == tuple->src
  122.             && pNode->tuple.dst == tuple->dst
  123.             && pNode->tuple.sport == tuple->sport
  124.             && pNode->tuple.dport == tuple->dport) {
  125.             *dir = UDPFLOW_ORG;
  126.             return pNode;
  127.         }
  128.         if(pNode->tuple.src == tuple->dst
  129.             && pNode->tuple.dst == tuple->src
  130.             && pNode->tuple.sport == tuple->dport
  131.             && pNode->tuple.dport == tuple->sport) {
  132.             *dir = UDPFLOW_REPLY;
  133.             return pNode;
  134.         }

  135.         pNode = pNode->next;
  136.     }
  137.     return NULL;
  138. }

  139. static void insert(udpflow *udp, u_int32_t hash) {
  140.     udp->next = hash_t[hash];
  141.     hash_t[hash] = udp;
  142. }

  143. static udpflow *found_udpflow(struct udp_tuple *tuple, int *dir) {
  144.     u_int32_t hash;
  145.     udpflow *udp;

  146.     hash = hash_udpflow(tuple); //计算哈希值
  147.     udp = lookup(tuple, hash, dir); //在哈希链表中查询当前包的五元组是否已知
  148.     if(!udp){ //未找到该值则新建链表节点
  149.         udp = (udpflow *)malloc(sizeof(udpflow));
  150.         if(!udp)    return NULL;
  151.     
  152.         memset(udp, 0, sizeof(udpflow));
  153.         *dir = UDPFLOW_ORG; //新建节点为请求数据方向
  154.         udp->tuple.src = tuple->src;
  155.         udp->tuple.dst = tuple->dst;
  156.         udp->tuple.sport = tuple->sport;
  157.         udp->tuple.dport = tuple->dport;
  158.         insert(udp, hash);
  159.     }

  160.     return udp;
  161. }

  162. static void dispatcher_handler(u_char *args, //回调函数传递的参数
  163.                         const struct pcap_pkthdr *header, const u_char *pkt_data) {

  164.     struct ethhdr *ethh;
  165.     struct iphdr *iph;
  166.     struct udphdr *udph;
  167.     struct udp_tuple tuple;
  168.     udpflow *udp;
  169.     int dir;
  170.     u_int32_t count;

  171.     if(header->caplen < MIN_LEN)    return;
  172.      ethh = (struct ethhdr *)pkt_data;
  173.     //上层是IP协议继续
  174.     if(ntohs(ethh->h_proto) == 0x0800) {
  175.         pkt_data += sizeof(struct ethhdr);
  176.         iph = (struct iphdr *)pkt_data;

  177.         //udp协议继续检测
  178.         if(iph->protocol == 17) {
  179.             //跳过IP首部,这里IP首部长度取首部内的长度值
  180.             if(header->caplen > iph->ihl*4)    pkt_data += iph->ihl*4;
  181.             udph = (struct udphdr *)pkt_data;

  182.             tuple.src = iph->saddr;
  183.             tuple.dst = iph->daddr;
  184.             tuple.sport = udph->source;
  185.             tuple.dport = udph->dest;

  186.             /*
  187.             查找当前数据包是否存在于已知UDP流中
  188.             返回的指针要么为查询到的地址, 要么就是新建节点的地址
  189.             以便取出数据直接进行统计操作
  190.             */
  191.             udp = found_udpflow(&tuple, &dir);
  192.             if(!udp)    return;

  193.             udp->counter[dir].total++;
  194.             count = udp->counter[UDPFLOW_ORG].total + udp->counter[UDPFLOW_REPLY].total;
  195.             
  196.             if(count == s){
  197.                 /* 找到开始技术的位置 */
  198.                 udp->counter[dir].packet++;
  199.                 udp->counter[dir].bytes += header->caplen;
  200.                 udp->start = header->ts.tv_sec;
  201.             /* 结束位置未设置则为0, 或者计数器不超过结束位置 */
  202.             } else if(count > s && (e <= s || count <= e)) {
  203.                 udp->counter[dir].packet++;
  204.                 udp->counter[dir].bytes += header->caplen;
  205.                 udp->end = header->ts.tv_sec;
  206.             } else {
  207.                 return;
  208.             }
  209.         }
  210.     }
  211. }

  212. static int load_packet(char *pcapfile) {
  213.     pcap_t *handle;
  214.     char errbuf[PCAP_ERRBUF_SIZE];

  215.     /* 从已捕获的dump文件中读取数据包 */
  216.     if((handle = pcap_open_offline(pcapfile, errbuf)) == NULL) {
  217.         printf("open the dumpfile failed\n");
  218.         exit(3);
  219.     }

  220. #if 0
  221.     char filter_exp[] = "udp";
  222.     struct bpf_program fp;
  223.     if (pcap_compile(handle, &fp, filter_exp, 0, 0) == -1) {
  224.         fprintf(stderr, "Couldn't parse filter %s: %s\n",
  225.                 filter_exp, pcap_geterr(handle));
  226.         exit(4);
  227.     }

  228.     if (pcap_setfilter(handle, &fp) == -1) {
  229.         fprintf(stderr, "Couldn't install filter %s: %s\n",
  230.             filter_exp, pcap_geterr(handle));
  231.         exit(5);
  232.     }
  233. #endif

  234.     /* 开始循环抓包,调用packet_callback处理
  235.      跟从网卡获取数据包一样, 直到读到EOF */
  236.     pcap_loop(handle, 0, dispatcher_handler, NULL);

  237.     pcap_close(handle);

  238.     return 0;
  239. }

  240. static void print_info(void) {
  241.     int idx;
  242.     int size = HASHSIZE;
  243.     u_int64_t rpy_avg, req_avg, perc;
  244.     char src[32] = {0}, dst[32] = {0};
  245.     udpflow *p;

  246.     for(idx=0; idx<HASHSIZE; idx++) {
  247.         p = hash_t[idx];
  248.         if(!p || !p->counter[UDPFLOW_REPLY].packet)    continue;
  249.         snprintf(src, sizeof(src), "%s:%d", inet_ntoa(*((struct in_addr *)&p->tuple.src)),
  250.                 ntohs(p->tuple.sport));
  251.         snprintf(dst, sizeof(dst), "%s:%d", inet_ntoa(*((struct in_addr *)&p->tuple.dst)),
  252.                 ntohs(p->tuple.dport));
  253.         fprintf(stdout, "%-21s -> %-21s", src, dst);

  254.         fprintf(stdout, " ORG_cnt:%-4d REPLY_cnt:%-4d", p->counter[UDPFLOW_ORG].packet, p->counter[UDPFLOW_REPLY].packet);

  255.         req_avg = p->counter[UDPFLOW_ORG].bytes / p->counter[UDPFLOW_ORG].packet;
  256.         rpy_avg = p->counter[UDPFLOW_REPLY].bytes / p->counter[UDPFLOW_REPLY].packet;
  257.         perc = rpy_avg/req_avg;
  258.         fprintf(stdout, " ORG_avg:%-4lu REPLY_avg:%-4lu PERC:%-3lu SEC:%ld\n", req_avg, rpy_avg, perc, p->end-p->start);
  259.     }
  260. }

  261. main(int argc, char **argv) {
  262.     char c;
  263.     char *pcapfile = NULL;
  264.     opterr = 0;
  265.     initval = random();

  266.     if (argc < 2)    print_help();
  267.     while((c = getopt_long(argc, argv, "s:e:f:h", opts, NULL)) != -1) {
  268.         switch(c) {
  269.             case '?':
  270.                 fprintf(stderr, "bad options\n");
  271.                 exit(1);
  272.             case 's':
  273.                 s = atoi(optarg);
  274.                 break;
  275.             case 'e':
  276.                 e = atoi(optarg);
  277.                 break;
  278.             case 'f':
  279.                 pcapfile = optarg;
  280.                 break;
  281.             case 'h':
  282.                 print_help();
  283.         }
  284.     }

  285.     if(!pcapfile) {
  286.         fprintf(stderr, "Specify the captured packets\n");
  287.         exit(2);
  288.     }

  289.     load_packet(pcapfile);

  290.     print_info();
  291.     return 0;
  292. }

阅读(1065) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~