📄 fprobe.c
字号:
/* Copyright (C) 2002, 2003 Slava Astashonok <sla@0n.ru> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License. $Id: fprobe.c,v 1.10.2.12 2003/10/30 14:38:44 sla Exp $*/#include <common.h>/* stdout, stderr, freopen() */#include <stdio.h>/* atoi(), exit() */#include <stdlib.h>/* getopt(), alarm(), getpid(), sedsid(), chdir() */#include <unistd.h>/* strerror() */#include <string.h>/* sig*() */#include <signal.h>/* pcap_*() */#include <pcap.h>/* inet_*() (Linux, FreeBSD, Solaris), getpid() */#include <sys/types.h>#include <netinet/in_systm.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netinet/ip.h>#include <netinet/tcp.h>#include <netinet/udp.h>#include <netinet/ip_icmp.h>/* pthread_*() */#include <pthread.h>/* errno */#include <errno.h>/* gethostbyname(), getservbyname() */#include <netdb.h>/* nanosleep() */#include <time.h>/* gettimeofday() */#include <sys/time.h>/* scheduling */#include <sched.h>/* select() (POSIX)*/#include <sys/select.h>#include <fprobe.h>#include <my_log.h>#include <my_getopt.h>#include <netflow.h>#include <hash.h>#include <mem.h>struct DLT dlt[] = {#ifdef DLT_NULL {DLT_NULL, 0, 4, 4, "NULL"},#endif#ifdef DLT_EN10MB {DLT_EN10MB, 12, 14, 17, "EN10MB"},#endif#ifdef DLT_IEEE802 {DLT_IEEE802, 14, 22, 17, "IEEE802"},#endif#ifdef DLT_ARCNET {DLT_ARCNET, 2 , 6, 6, "ARCNET"},#endif#ifdef DLT_SLIP {DLT_SLIP, -1, 16, 16, "SLIP"},#endif#ifdef DLT_PPP {DLT_PPP, 2, 4, 4, "PPP"},#endif#ifdef DLT_FDDI /* FIXME See gencode.c from libpcap */ {DLT_FDDI, 13, 21, 16, "FDDI"},#endif#ifdef DLT_ATM_RFC1483 {DLT_ATM_RFC1483, 0, 8, 3, "ATM_RFC1483"},#endif#ifdef DLT_RAW {DLT_RAW, -1, 0, 0, "RAW"},#endif#ifdef DLT_SLIP_BSDOS {DLT_SLIP_BSDOS, -1, 24, 24, "SLIP_BSDOS"},#endif#ifdef DLT_PPP_BSDOS {DLT_PPP_BSDOS, 5, 24, 24, "PPP_BSDOS"},#endif#ifdef DLT_ATM_CLIP {DLT_ATM_CLIP, 0, 8, 3, "ATM_CLIP"},#endif#ifdef DLT_PPP_SERIAL {DLT_PPP_SERIAL, 2, 4, 4, "PPP_SERIAL"},#endif#ifdef DLT_PPP_ETHER {DLT_PPP_ETHER, 6, 8, 8, "PPP_ETHER"},#endif#ifdef DLT_C_HDLC {DLT_C_HDLC, 2, 4, 4, "C_HDLC"},#endif#ifdef DLT_IEEE802_11 {DLT_IEEE802_11, 24, 32, 27, "IEEE802_11"},#endif#ifdef DLT_LOOP {DLT_LOOP, 0, 4, 4, "LOOP"},#endif#ifdef DLT_LINUX_SLL {DLT_LINUX_SLL, 14, 16, 16, "LINUX_SLL"},#endif#ifdef DLT_LTALK {DLT_LTALK, -1, 0, 0, "LTALK"},#endif#ifdef DLT_PRISM_HEADER {DLT_PRISM_HEADER, 144+24, 144+30, 144+27, "PRISM_HEADER"},#endif#ifdef DLT_IP_OVER_FC {DLT_IP_OVER_FC, 16, 24, 19, "IP_OVER_FC"},#endif#ifdef DLT_SUNATM {DLT_SUNATM, 4, 4+8, 4+3, "SUNATM"},#endif#ifdef DLT_ARCNET_LINUX {DLT_ARCNET_LINUX, 4, 8, 8, "ARCNET_LINUX"},#endif#ifdef DLT_ENC {DLT_ENC, 0, 12, 12, "ENC"},#endif#ifdef DLT_FRELAY {DLT_FRELAY, -1, 0, 0, "FRELAY"},#endif#ifdef DLT_IEEE802_11_RADIO {DLT_IEEE802_11_RADIO, 64+24, 64+32, 64+27, "IEEE802_11_RADIO"},#endif#ifdef DLT_PFLOG {DLT_PFLOG, 0, 28, 28, "PFLOG"},#endif {-1, 0, 0, 0, ""}};enum { aflag, bflag, dflag, eflag, fflag, gflag, hflag, iflag, Kflag, kflag, lflag, mflag, nflag, pflag, qflag, rflag, sflag, tflag, vflag, xflag,};static struct getopt_parms parms[] = { {'a', MY_GETOPT_ARG_REQUIRED, 0, 0}, {'b', MY_GETOPT_ARG_REQUIRED, 0, 0}, {'d', MY_GETOPT_ARG_REQUIRED, 0, 0}, {'e', MY_GETOPT_ARG_REQUIRED, 0, 0}, {'f', MY_GETOPT_ARG_REQUIRED, 0, 0}, {'g', MY_GETOPT_ARG_REQUIRED, 0, 0}, {'h', 0, 0, 0}, {'i', MY_GETOPT_ARG_REQUIRED, 0, 0}, {'K', MY_GETOPT_ARG_REQUIRED, 0, 0}, {'k', 0, 0, 0}, {'l', MY_GETOPT_ARG_REQUIRED, 0, 0}, {'m', MY_GETOPT_ARG_REQUIRED, 0, 0}, {'n', MY_GETOPT_ARG_REQUIRED, 0, 0}, {'p', 0, 0, 0}, {'q', MY_GETOPT_ARG_REQUIRED, 0, 0}, {'r', MY_GETOPT_ARG_REQUIRED, 0, 0}, {'s', MY_GETOPT_ARG_REQUIRED, 0, 0}, {'t', MY_GETOPT_ARG_REQUIRED, 0, 0}, {'v', MY_GETOPT_ARG_REQUIRED, 0, 0}, {'x', MY_GETOPT_ARG_REQUIRED, 0, 0}, {0, 0, 0, 0}};extern char *optarg;extern int optind, opterr, optopt;extern int errno;extern struct NetFlow NetFlow1;extern struct NetFlow NetFlow5;extern struct NetFlow NetFlow7;static unsigned promisc;static char *dev;static char *filter = "";static unsigned scan_interval = 5;static int frag_lifetime = 30;static int inactive_lifetime = 60;static int active_lifetime = 300;#define BULK_QUANTITY_MAX (unsigned)(mem_index_t)(-1)#if (MEM_BITS == 0) || (MEM_BITS == 16)#define BULK_QUANTITY 10000#else#define BULK_QUANTITY 200#endifstatic unsigned bulk_quantity = BULK_QUANTITY;static unsigned pending_queue_length = 100;static struct NetFlow *netflow = &NetFlow5;static unsigned verbosity = 6;static unsigned log_dest = MY_LOG_SYSLOG;static unsigned snmp_input_index;static unsigned snmp_output_index;static int link_layer_size = -1;static int link_layer;static struct Time start_time;static long start_time_offset;static int off_nl = -1;static int off_tl;/* From mem.c */extern unsigned total_elements;extern unsigned free_elements;extern unsigned total_memory;#if ((DEBUG) & DEBUG_I)static unsigned emit_pkts, emit_queue;static uint64_t size_total;static unsigned pkts_total, pkts_total_fragmented;static unsigned pkts_ignored, pkts_lost_capture, pkts_lost_unpending;static unsigned pkts_pending, pkts_pending_done;static unsigned pending_queue_trace, pending_queue_trace_candidate;static unsigned flows_total, flows_fragmented;/*From libpcap's README.linux:...Number of packets that had passed filtering but were notpassed on to pcap due to things like buffer shortage, etc...BTW pcap_stats() freeze on FreeBSD (4.6) with standart libpcapFIXME1. Check for support in other OS2. Compiling option?*/static unsigned pkts_dropped;# ifdef OS_LINUXstatic struct pcap_stat pstat;# endif#endifstatic unsigned emit_count;static uint32_t emit_sequence;static unsigned emit_rate_bytes, emit_rate_delay;static struct Time emit_time;static uint8_t emit_packet[NETFLOW_MAX_PACKET];static pcap_t* pcap_handle;static pthread_t thid;static sigset_t sig_mask;static struct sched_param schedp;static int sched_min, sched_max;static struct sockaddr_in client, server;static int sock;static int sigs;static struct Flow *flows[1 << HASH_BITS];static pthread_mutex_t flows_mutex[1 << HASH_BITS];static pthread_mutex_t unpending_mutex = PTHREAD_MUTEX_INITIALIZER;static pthread_cond_t unpending_cond = PTHREAD_COND_INITIALIZER;static pthread_mutex_t scan_mutex = PTHREAD_MUTEX_INITIALIZER;static pthread_cond_t scan_cond = PTHREAD_COND_INITIALIZER;static struct Flow *pending_head, *pending_tail;static struct Flow *scan_frag_dreg;static pthread_mutex_t emit_mutex = PTHREAD_MUTEX_INITIALIZER;static pthread_cond_t emit_cond = PTHREAD_COND_INITIALIZER;static struct Flow *flows_emit;static char ident[32];static pid_t pid;static int killed;static int emit_timeout = EMIT_TIMEOUT, unpending_timeout = UNPENDING_TIMEOUT;void usage(){ fprintf(stdout, "fprobe: a NetFlow probe. Version %s\n" "Usage: fprobe [options] host:port\n" "\n" "-h\t\tDisplay this help\n" "-p\t\tDon't put the interface into promiscuous mode\n" "-i <interface>\tNetwork interface name\n" "-f <expression>\tFilter expression (see tcpdump manual for details)\n" "-s <seconds>\tHow often scan for expired flows [5]\n" "-g <seconds>\tFragmented flow lifetime [30]\n" "-d <seconds>\tIdle flow lifetime (inactive timer) [60]\n" "-e <seconds>\tActive flow lifetime (active timer) [300]\n" "-n <version>\tNetFlow version for use (1, 5 or 7) [5]\n" "-a <address>\tUse <address> as source for NetFlow flow\n" "-x <id>[:<id>]\tWorkaround for SNMP interfaces indexes [0]\n" "-b <flows>\tMemory bulk size (1..%u) [%u]\n" "-m <kilobytes>\tMemory limit (0=no limit) [0]\n" "-q <flows>\tPending queue length [100]\n" "-r <priority>\tReal-time priority (0=disabled, %d..%d) [0]\n" "-t <B:N>\tProduce <N> nanosecond delay after each <B> bytes sent [0:0]\n" "-K <bytes>\tLink layer header size\n" "-k\t\tDon't exclude link layer header from packet size\n" "-v <level>\tMaximum log level (0=EMERG, ..., 6=INFO, 7=DEBUG) [6]\n" "-l <dest>\tLog destination (0=none, 1=syslog, 2=stdout, 3=both) [1]\n" "host:port\tAddress of the NetFlow collector\n", VERSION, BULK_QUANTITY_MAX, bulk_quantity, sched_min, sched_max); exit(0);}#if ((DEBUG) & DEBUG_I)void info_debug(){# ifdef OS_LINUX pcap_stats(pcap_handle, &pstat); pkts_dropped += pstat.ps_drop;# endif my_log(LOG_DEBUG, "I: received:%d/%d (%lld) pending:%d/%d", pkts_total, pkts_total_fragmented, size_total, pkts_pending - pkts_pending_done, pending_queue_trace); my_log(LOG_DEBUG, "I: ignored:%d lost:%d+%d dropped:%d", pkts_ignored, pkts_lost_capture, pkts_lost_unpending, pkts_dropped); my_log(LOG_DEBUG, "I: cache:%d/%d emit:%d/%d/%d", flows_total, flows_fragmented, emit_sequence, emit_pkts, emit_queue); my_log(LOG_DEBUG, "I: memory:%d/%d (%d)", total_elements, free_elements, total_memory);}#endifvoid sighandler(int sig){ switch (sig) { case SIGTERM: sigs |= SIGTERM_MASK; break;#if ((DEBUG) & DEBUG_I) case SIGUSR1: sigs |= SIGUSR1_MASK; break;#endif }}void gettime(struct Time *now){ struct timeval t; gettimeofday(&t, 0); now->sec = t.tv_sec; now->usec = t.tv_usec;}inline time_t cmpmtime(struct Time *t1, struct Time *t2){ return (t1->sec - t2->sec) * 1000 + (t1->usec - t2->usec) / 1000;}/* Uptime in miliseconds */uint32_t getuptime(struct Time *t){ /* Maximum uptime is about 49/2 days */ return cmpmtime(t, &start_time);}hash_t hash_flow(struct Flow *flow){ if (flow->flags & FLOW_FRAG) return hash(flow, sizeof(struct Flow_F)); else return hash(flow, sizeof(struct Flow_TL));}inline void copy_flow(struct Flow *src, struct Flow *dst){ dst->sip = src->sip; dst->dip = src->dip; dst->tos = src->tos; dst->proto = src->proto; dst->tcp_flags = src->tcp_flags; dst->id = src->id; dst->sp = src->sp; dst->dp = src->dp; dst->pkts = src->pkts; dst->size = src->size; dst->sizeF = src->sizeF; dst->sizeP = src->sizeP; dst->ctime = src->ctime; dst->mtime = src->mtime; dst->flags = src->flags;}struct Flow *find(struct Flow *where, struct Flow *what, struct Flow ***prev){ struct Flow **flowpp;#ifdef WALL flowpp = 0;#endif if (prev) flowpp = *prev; while (where) { if (where->sip.s_addr == what->sip.s_addr && where->dip.s_addr == what->dip.s_addr && where->proto == what->proto) { switch ((what->flags + where->flags) & FLOW_FRAGMASK) { case 0: /* Both unfragmented */ if ((what->sp == where->sp) && (what->dp == where->dp)) goto done; break; case 2: /* Both fragmented */ if (where->id == what->id) goto done; break; } } flowpp = &where->next; where = where->next; }done: if (prev) *prev = flowpp; return where;}int put_into(struct Flow *flow, int flag#if ((DEBUG) & (DEBUG_S | DEBUG_U)) , char *logbuf#endif){ int ret = 0; hash_t h; struct Flow *flown, **flowpp;#if ((DEBUG) & (DEBUG_S | DEBUG_U)) char buf[64];#endif h = hash_flow(flow);#if ((DEBUG) & (DEBUG_S | DEBUG_U)) sprintf(buf, " %x H:%04x", (unsigned) flow, h); strcat(logbuf, buf);#endif pthread_mutex_lock(&flows_mutex[h]); flowpp = &flows[h]; if (!(flown = find(flows[h], flow, &flowpp))) { /* No suitable flow found - add */ if (flag == COPY_INTO) { if ((flown = mem_alloc())) { copy_flow(flow, flown); flow = flown; } else {#if ((DEBUG) & (DEBUG_S | DEBUG_U)) || defined MESSAGES my_log(LOG_ERR, "%s %s. %s", "mem_alloc():", strerror(errno), "packet lost");#endif return -1; } } flow->next = flows[h]; flows[h] = flow;#if ((DEBUG) & DEBUG_I) flows_total++; if (flow->flags & FLOW_FRAG) flows_fragmented++;#endif#if ((DEBUG) & (DEBUG_S | DEBUG_U)) if (flown) { sprintf(buf, " => %x, flags: %x", (unsigned) flown, flown->flags); strcat(logbuf, buf); }#endif } else { /* Found suitable flow - update */#if ((DEBUG) & (DEBUG_S | DEBUG_U)) sprintf(buf, " +> %x", (unsigned) flown); strcat(logbuf, buf);#endif if (cmpmtime(&flow->mtime, &flown->mtime) > 0) flown->mtime = flow->mtime;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -