-
#include <stdio.h>
-
#include <pcap.h>
-
#include <stdlib.h>
-
#include <time.h>
-
#include <getopt.h>
-
#include <linux/if_ether.h>
-
#include <linux/ip.h>
-
#include <linux/udp.h>
-
#include <netinet/in.h>
-
#include <arpa/inet.h>
-
#include <string.h>
-
-
-
#define MIN_LEN (sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr))
-
-
#ifdef DEBUG
-
#define DEBUGP(format,args...) fprintf(stdout, format, ##args)
-
#else
-
#define DEBUGP(format,args...)
-
#endif
-
-
#define HASHSIZE (1024 * 1024 * 2)
-
#define HASH_KEY(ip1, ip2, ports, initval) jhash_3words(ip1, ip2, ports, initval) % HASHSIZE
-
-
/* swap - swap value of @a and @b */
-
#define swap(a, b) \
-
do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
-
-
#define __jhash_mix(a, b, c) { \
-
a -= b; a -= c; a ^= (c>>13); \
-
b -= c; b -= a; b ^= (a<<8); \
-
c -= a; c -= b; c ^= (b>>13); \
-
a -= b; a -= c; a ^= (c>>12); \
-
b -= c; b -= a; b ^= (a<<16); \
-
c -= a; c -= b; c ^= (b>>5); \
-
a -= b; a -= c; a ^= (c>>3); \
-
b -= c; b -= a; b ^= (a<<10); \
-
c -= a; c -= b; c ^= (b>>15); \
-
}
-
-
/* The golden ration: an arbitrary value */
-
#define JHASH_GOLDEN_RATIO 0x9e3779b9
-
-
static struct option opts[] = {
-
{.name = "start", .has_arg = 1, .val = 's'},
-
{.name = "end", .has_arg = 1, .val = 'e'},
-
{.name = "file", .has_arg = 1, .val = 'f'},
-
{.name = "help", .has_arg = 0, .val = 'h'},
-
{NULL}
-
};
-
-
enum udpflow_dir{
-
UDPFLOW_ORG = 0,
-
UDPFLOW_REPLY,
-
UDPFLOW_MAX
-
};
-
-
struct udp_tuple{
-
u_int32_t src;
-
u_int32_t dst;
-
u_int16_t sport;
-
u_int16_t dport;
-
};
-
-
struct udp_counter{
-
u_int64_t bytes;
-
u_int32_t packet;
-
u_int32_t total;
-
};
-
-
typedef struct _udpflow{
-
struct udp_tuple tuple;
-
struct udp_counter counter[UDPFLOW_MAX];
-
time_t start;
-
time_t end;
-
struct _udpflow *next;
-
}udpflow;
-
-
-
static int s = 1, e = 0;
-
static udpflow *hash_t[HASHSIZE];
-
static u_int32_t initval;
-
-
static inline u_int32_t jhash_3words(u_int32_t a,
-
u_int32_t b,
-
u_int32_t c,
-
u_int32_t initval) {
-
a += JHASH_GOLDEN_RATIO;
-
b += JHASH_GOLDEN_RATIO;
-
c += initval;
-
-
__jhash_mix(a, b, c);
-
-
return c;
-
}
-
-
static void print_help(void) {
-
printf("-h Print this help\n");
-
printf("-s
Began to capture in which package\n" );
-
printf("-e
End capture in which package\n" );
-
printf("-f
Captured packets\n" );
-
exit(-1);
-
}
-
-
static char* trans_time(time_t sec) {
-
static char buf[32];
-
struct tm *date;
-
date = localtime(&sec);
-
strftime(buf, 64, "%Y-%m-%d %H:%M:%S", date);
-
return buf;
-
}
-
-
static u_int32_t hash_udpflow(struct udp_tuple *tuple) {
-
union {
-
u_int32_t v32;
-
u_int16_t v16[2];
-
}ports;
-
u_int32_t hash, sip, tip;
-
-
sip = tuple->src;
-
tip = tuple->dst;
-
ports.v16[0] = tuple->sport;
-
ports.v16[1] = tuple->dport;
-
-
/*
-
无论是请求数据还是应答数据都排序后送去哈希
-
这样使得同一个流的哈希结果是一样
-
*/
-
if(sip < tip) swap(sip, tip);
-
if(ports.v16[0] < ports.v16[1]) swap(ports.v16[0], ports.v16[1]);
-
hash = HASH_KEY(sip, tip, ports.v32, initval);
-
-
return hash;
-
}
-
-
static udpflow *lookup(struct udp_tuple *tuple, u_int32_t hash, int *dir) {
-
udpflow *pNode = hash_t[hash];
-
while(pNode != NULL) {
-
/*
-
遍历链表的每个节点, 如果查询到统一方向是请求数据
-
反方向是应答数据, 第一个数据包就确认为请求包
-
*/
-
if(pNode->tuple.src == tuple->src
-
&& pNode->tuple.dst == tuple->dst
-
&& pNode->tuple.sport == tuple->sport
-
&& pNode->tuple.dport == tuple->dport) {
-
*dir = UDPFLOW_ORG;
-
return pNode;
-
}
-
if(pNode->tuple.src == tuple->dst
-
&& pNode->tuple.dst == tuple->src
-
&& pNode->tuple.sport == tuple->dport
-
&& pNode->tuple.dport == tuple->sport) {
-
*dir = UDPFLOW_REPLY;
-
return pNode;
-
}
-
-
pNode = pNode->next;
-
}
-
return NULL;
-
}
-
-
static void insert(udpflow *udp, u_int32_t hash) {
-
udp->next = hash_t[hash];
-
hash_t[hash] = udp;
-
}
-
-
static udpflow *found_udpflow(struct udp_tuple *tuple, int *dir) {
-
u_int32_t hash;
-
udpflow *udp;
-
-
hash = hash_udpflow(tuple); //计算哈希值
-
udp = lookup(tuple, hash, dir); //在哈希链表中查询当前包的五元组是否已知
-
if(!udp){ //未找到该值则新建链表节点
-
udp = (udpflow *)malloc(sizeof(udpflow));
-
if(!udp) return NULL;
-
-
memset(udp, 0, sizeof(udpflow));
-
*dir = UDPFLOW_ORG; //新建节点为请求数据方向
-
udp->tuple.src = tuple->src;
-
udp->tuple.dst = tuple->dst;
-
udp->tuple.sport = tuple->sport;
-
udp->tuple.dport = tuple->dport;
-
insert(udp, hash);
-
}
-
-
return udp;
-
}
-
-
static void dispatcher_handler(u_char *args, //回调函数传递的参数
-
const struct pcap_pkthdr *header, const u_char *pkt_data) {
-
-
struct ethhdr *ethh;
-
struct iphdr *iph;
-
struct udphdr *udph;
-
struct udp_tuple tuple;
-
udpflow *udp;
-
int dir;
-
u_int32_t count;
-
-
if(header->caplen < MIN_LEN) return;
-
ethh = (struct ethhdr *)pkt_data;
-
//上层是IP协议继续
-
if(ntohs(ethh->h_proto) == 0x0800) {
-
pkt_data += sizeof(struct ethhdr);
-
iph = (struct iphdr *)pkt_data;
-
-
//udp协议继续检测
-
if(iph->protocol == 17) {
-
//跳过IP首部,这里IP首部长度取首部内的长度值
-
if(header->caplen > iph->ihl*4) pkt_data += iph->ihl*4;
-
udph = (struct udphdr *)pkt_data;
-
-
tuple.src = iph->saddr;
-
tuple.dst = iph->daddr;
-
tuple.sport = udph->source;
-
tuple.dport = udph->dest;
-
-
/*
-
查找当前数据包是否存在于已知UDP流中
-
返回的指针要么为查询到的地址, 要么就是新建节点的地址
-
以便取出数据直接进行统计操作
-
*/
-
udp = found_udpflow(&tuple, &dir);
-
if(!udp) return;
-
-
udp->counter[dir].total++;
-
count = udp->counter[UDPFLOW_ORG].total + udp->counter[UDPFLOW_REPLY].total;
-
-
if(count == s){
-
/* 找到开始技术的位置 */
-
udp->counter[dir].packet++;
-
udp->counter[dir].bytes += header->caplen;
-
udp->start = header->ts.tv_sec;
-
/* 结束位置未设置则为0, 或者计数器不超过结束位置 */
-
} else if(count > s && (e <= s || count <= e)) {
-
udp->counter[dir].packet++;
-
udp->counter[dir].bytes += header->caplen;
-
udp->end = header->ts.tv_sec;
-
} else {
-
return;
-
}
-
}
-
}
-
}
-
-
static int load_packet(char *pcapfile) {
-
pcap_t *handle;
-
char errbuf[PCAP_ERRBUF_SIZE];
-
-
/* 从已捕获的dump文件中读取数据包 */
-
if((handle = pcap_open_offline(pcapfile, errbuf)) == NULL) {
-
printf("open the dumpfile failed\n");
-
exit(3);
-
}
-
-
#if 0
-
char filter_exp[] = "udp";
-
struct bpf_program fp;
-
if (pcap_compile(handle, &fp, filter_exp, 0, 0) == -1) {
-
fprintf(stderr, "Couldn't parse filter %s: %s\n",
-
filter_exp, pcap_geterr(handle));
-
exit(4);
-
}
-
-
if (pcap_setfilter(handle, &fp) == -1) {
-
fprintf(stderr, "Couldn't install filter %s: %s\n",
-
filter_exp, pcap_geterr(handle));
-
exit(5);
-
}
-
#endif
-
-
/* 开始循环抓包,调用packet_callback处理
-
跟从网卡获取数据包一样, 直到读到EOF */
-
pcap_loop(handle, 0, dispatcher_handler, NULL);
-
-
pcap_close(handle);
-
-
return 0;
-
}
-
-
static void print_info(void) {
-
int idx;
-
int size = HASHSIZE;
-
u_int64_t rpy_avg, req_avg, perc;
-
char src[32] = {0}, dst[32] = {0};
-
udpflow *p;
-
-
for(idx=0; idx<HASHSIZE; idx++) {
-
p = hash_t[idx];
-
if(!p || !p->counter[UDPFLOW_REPLY].packet) continue;
-
snprintf(src, sizeof(src), "%s:%d", inet_ntoa(*((struct in_addr *)&p->tuple.src)),
-
ntohs(p->tuple.sport));
-
snprintf(dst, sizeof(dst), "%s:%d", inet_ntoa(*((struct in_addr *)&p->tuple.dst)),
-
ntohs(p->tuple.dport));
-
fprintf(stdout, "%-21s -> %-21s", src, dst);
-
-
fprintf(stdout, " ORG_cnt:%-4d REPLY_cnt:%-4d", p->counter[UDPFLOW_ORG].packet, p->counter[UDPFLOW_REPLY].packet);
-
-
req_avg = p->counter[UDPFLOW_ORG].bytes / p->counter[UDPFLOW_ORG].packet;
-
rpy_avg = p->counter[UDPFLOW_REPLY].bytes / p->counter[UDPFLOW_REPLY].packet;
-
perc = rpy_avg/req_avg;
-
fprintf(stdout, " ORG_avg:%-4lu REPLY_avg:%-4lu PERC:%-3lu SEC:%ld\n", req_avg, rpy_avg, perc, p->end-p->start);
-
}
-
}
-
-
main(int argc, char **argv) {
-
char c;
-
char *pcapfile = NULL;
-
opterr = 0;
-
initval = random();
-
-
if (argc < 2) print_help();
-
while((c = getopt_long(argc, argv, "s:e:f:h", opts, NULL)) != -1) {
-
switch(c) {
-
case '?':
-
fprintf(stderr, "bad options\n");
-
exit(1);
-
case 's':
-
s = atoi(optarg);
-
break;
-
case 'e':
-
e = atoi(optarg);
-
break;
-
case 'f':
-
pcapfile = optarg;
-
break;
-
case 'h':
-
print_help();
-
}
-
}
-
-
if(!pcapfile) {
-
fprintf(stderr, "Specify the captured packets\n");
-
exit(2);
-
}
-
-
load_packet(pcapfile);
-
-
print_info();
-
return 0;
- }