📄 ifstats.c
字号:
/***ifstats.c - the interface statistics moduleWritten by Gerard Paul JavaCopyright (c) Gerard Paul Java 1997-2002This software is open source; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2 of the License, or(at your option) any later version.This program is distributed WITHOUT ANY WARRANTY; without even theimplied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License in the included COPYING file fordetails. ***/#include <curses.h>#include <panel.h>#include <stdlib.h>#include <string.h>#include <signal.h>#include <unistd.h>#include <time.h>#include <sys/time.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <netinet/in.h>#include <arpa/inet.h>#include <net/if_arp.h>#include <linux/if_packet.h>#include <net/if.h>#include <netinet/ip.h>#include <netinet/tcp.h>#include <netinet/udp.h>#include <linux/if_ether.h>#include <winops.h>#include <labels.h>#include <listbox.h>#include <msgboxes.h>#include "ifstats.h"#include "ifaces.h"#include "isdntab.h"#include "fltdefs.h"#include "utfilter.h"#include "fltselect.h"#include "packet.h"#include "options.h"#include "log.h"#include "dirs.h"#include "deskman.h"#include "ipcsum.h"#include "attrs.h"#include "serv.h"#include "timer.h"#include "instances.h"#include "mode.h"#include "logvars.h"#include "promisc.h"#include "error.h"#define SCROLLUP 0#define SCROLLDOWN 1extern int exitloop;extern int daemonized;/* from log.c, applicable only to this module */void writegstatlog(struct iftab *table, int unit, unsigned long nsecs, FILE * logfile);void writedstatlog(char *ifname, int unit, float activity, float pps, float peakactivity, float peakpps, float peakactivity_in, float peakpps_in, float peakactivity_out, float peakpps_out, struct iftotals *ts, unsigned long nsecs, FILE * logfile);/* * USR1 log-rotation signal handlers */void rotate_gstat_log(){ rotate_flag = 1; strcpy(target_logname, GSTATLOG); signal(SIGUSR1, rotate_gstat_log);}void rotate_dstat_log(){ rotate_flag = 1; strcpy(target_logname, current_logfile); signal(SIGUSR1, rotate_dstat_log);}/* * Function to check if an interface is already in the interface list. * This eliminates duplicate interface entries due to aliases */int ifinlist(struct iflist *list, char *ifname){ struct iflist *ptmp = list; int result = 0; while ((ptmp != NULL) && (result == 0)) { result = (strcmp(ifname, ptmp->ifname) == 0); ptmp = ptmp->next_entry; } return result;}/* * Initialize the list of interfaces. This linked list is used in the * selection boxes as well as in the general interface statistics screen. * * This function parses the /proc/net/dev file and grabs the interface names * from there. The SIOGIFFLAGS ioctl() call is used to determine whether the * interfaces are active. Inactive interfaces are omitted from selection * lists. */void initiflist(struct iflist **list){ FILE *fd; char buf[161]; char ifname[8]; struct iflist *itmp = NULL; struct iflist *tail = NULL; unsigned int index = 0; int resp; *list = NULL; fd = open_procnetdev(); if (fd == NULL) { tx_errbox("Unable to obtain interface list", ANYKEY_MSG, &resp); return; } do { strcpy(buf, ""); get_next_iface(fd, ifname); if (strcmp(ifname, "") != 0) { if (!(iface_supported(ifname))) continue; if (ifinlist(*list, ifname)) /* ignore entry if already in */ continue; /* interface list */ /* * Check if the interface is actually up running. This prevents * inactive devices in /proc/net/dev from actually appearing in * interface lists used by IPTraf. */ if (!iface_up(ifname)) continue; /* * At this point, the interface is now sure to be up and running. */ itmp = malloc(sizeof(struct iflist)); bzero(itmp, sizeof(struct iflist)); strcpy(itmp->ifname, ifname); index++; itmp->index = index; if (*list == NULL) { *list = itmp; itmp->prev_entry = NULL; } else { tail->next_entry = itmp; itmp->prev_entry = tail; } tail = itmp; itmp->next_entry = NULL; } } while (strcmp(ifname, "") != 0); fclose(fd);}void positionptr(struct iftab *table, struct iflist **ptmp, char *ifname){ struct iflist *plast = NULL; int ok = 0; *ptmp = table->head; while ((*ptmp != NULL) && (!ok)) { ok = (strcmp((*ptmp)->ifname, ifname) == 0); if (!ok) { if ((*ptmp)->next_entry == NULL) plast = *ptmp; *ptmp = (*ptmp)->next_entry; } } if (*ptmp == NULL) { *ptmp = malloc(sizeof(struct iflist)); bzero(*ptmp, sizeof(struct iflist)); (*ptmp)->index = plast->index + 1; plast->next_entry = *ptmp; (*ptmp)->prev_entry = plast; (*ptmp)->next_entry = NULL; strcpy((*ptmp)->ifname, ifname); if ((*ptmp)->index <= LINES - 4) table->lastvisible = *ptmp; }}void destroyiflist(struct iflist *list){ struct iflist *ctmp; struct iflist *ptmp; if (list != NULL) { ptmp = list; ctmp = ptmp->next_entry; do { free(ptmp); ptmp = ctmp; if (ctmp != NULL) ctmp = ctmp->next_entry; } while (ptmp != NULL); }}void no_ifaces_error(void){ write_error("No active interfaces. Check their status or the /proc filesystem", daemonized);}void updaterates(struct iftab *table, int unit, time_t starttime, time_t now, unsigned int idx){ struct iflist *ptmp = table->firstvisible; wattrset(table->statwin, HIGHATTR); do { wmove(table->statwin, ptmp->index - idx, 52 * COLS / 80); if (unit == KBITS) { ptmp->rate = ((float) (ptmp->spanbr * 8 / 1000)) / ((float) (now - starttime)); wprintw(table->statwin, "%8.2f kbits/sec", ptmp->rate); } else { ptmp->rate = ((float) (ptmp->spanbr / 1024)) / ((float) (now - starttime)); wprintw(table->statwin, "%8.2f kbytes/sec", ptmp->rate); } if (ptmp->rate > ptmp->peakrate) ptmp->peakrate = ptmp->rate; ptmp->spanbr = 0; ptmp = ptmp->next_entry; } while (ptmp != table->lastvisible->next_entry);}void printifentry(struct iflist *ptmp, WINDOW * win, unsigned int idx){ unsigned int target_row; if ((ptmp->index < idx) || (ptmp->index > idx + (LINES - 5))) return; target_row = ptmp->index - idx; wattrset(win, STDATTR); wmove(win, target_row, 1); wprintw(win, "%s", ptmp->ifname); wattrset(win, HIGHATTR); wmove(win, target_row, 12 * COLS / 80); printlargenum(ptmp->total, win); wmove(win, target_row, 22 * COLS / 80); printlargenum(ptmp->iptotal, win); wmove(win, target_row, 32 * COLS / 80); printlargenum(ptmp->noniptotal, win); wmove(win, target_row, 42 * COLS / 80); wprintw(win, "%8lu", ptmp->badtotal);}void preparescreen(struct iftab *table){ struct iflist *ptmp = table->head; unsigned int i = 1; unsigned int winht = LINES - 4; table->firstvisible = table->head; do { printifentry(ptmp, table->statwin, 1); if (i <= winht) table->lastvisible = ptmp; ptmp = ptmp->next_entry; i++; } while ((ptmp != NULL) && (i <= winht));}void labelstats(WINDOW * win){ wmove(win, 0, 1); wprintw(win, " Iface "); wmove(win, 0, 16 * COLS / 80); wprintw(win, " Total "); wmove(win, 0, 29 * COLS / 80); wprintw(win, " IP "); wmove(win, 0, 36 * COLS / 80); wprintw(win, " NonIP "); wmove(win, 0, 45 * COLS / 80); wprintw(win, " BadIP "); wmove(win, 0, 55 * COLS / 80); wprintw(win, " Activity ");}void initiftab(struct iftab *table){ table->borderwin = newwin(LINES - 2, COLS, 1, 0); table->borderpanel = new_panel(table->borderwin); move(LINES - 1, 1); scrollkeyhelp(); stdexitkeyhelp(); wattrset(table->borderwin, BOXATTR); box(table->borderwin, ACS_VLINE, ACS_HLINE); labelstats(table->borderwin); table->statwin = newwin(LINES - 4, COLS - 2, 2, 1); table->statpanel = new_panel(table->statwin); tx_stdwinset(table->statwin); wtimeout(table->statwin, -1); wattrset(table->statwin, STDATTR); tx_colorwin(table->statwin); wattrset(table->statwin, BOXATTR); wmove(table->borderwin, LINES - 3, 32 * COLS / 80); wprintw(table->borderwin, " Total, IP, NonIP, and BadIP are packet counts ");}/* * Scrolling routines for the general interface statistics window */void scrollgstatwin(struct iftab *table, int direction, unsigned int *idx){ char buf[255]; sprintf(buf, "%%%dc", COLS - 2); wattrset(table->statwin, STDATTR); if (direction == SCROLLUP) { if (table->lastvisible->next_entry != NULL) { wscrl(table->statwin, 1); table->lastvisible = table->lastvisible->next_entry; table->firstvisible = table->firstvisible->next_entry; (*idx)++; wmove(table->statwin, LINES - 5, 0); scrollok(table->statwin, 0); wprintw(table->statwin, buf, ' '); scrollok(table->statwin, 1); printifentry(table->lastvisible, table->statwin, *idx); } } else { if (table->firstvisible != table->head) { wscrl(table->statwin, -1); table->firstvisible = table->firstvisible->prev_entry; table->lastvisible = table->lastvisible->prev_entry; (*idx)--; wmove(table->statwin, 0, 0); wprintw(table->statwin, buf, ' '); printifentry(table->firstvisible, table->statwin, *idx); } }}void pagegstatwin(struct iftab *table, int direction, int *idx){ int i = 1; if (direction == SCROLLUP) { while ((i <= LINES - 5) && (table->lastvisible->next_entry != NULL)) { i++; scrollgstatwin(table, direction, idx); } } else { while ((i <= LINES - 5) && (table->firstvisible != table->head)) { i++; scrollgstatwin(table, direction, idx); } }}/* * The general interface statistics function */void ifstats(const struct OPTIONS *options, struct filterstate *ofilter, int facilitytime){ int logging = options->logging; struct iftab table; char buf[MAX_PACKET_SIZE]; char *packet; int pkt_result = 0; struct sockaddr_ll fromaddr; unsigned short linktype; unsigned sport, dport; struct iflist *ptmp = NULL; unsigned int idx = 1; int fd; FILE *logfile = NULL; int br; char ifname[10]; int ch; struct timeval tv; unsigned long starttime = 0; unsigned long statbegin = 0; unsigned long now = 0; unsigned long long unow = 0; unsigned long startlog = 0; unsigned long updtime = 0; unsigned long long updtime_usec = 0; struct promisc_states *promisc_list; if (!facility_active(GSTATIDFILE, "")) mark_facility(GSTATIDFILE, "general interface statistics", ""); else { write_error ("General interface stats already active in another process", daemonized); return; } initiflist(&(table.head)); if (table.head == NULL) { no_ifaces_error(); unmark_facility(GSTATIDFILE, ""); return; } initiftab(&table); open_socket(&fd); if (fd < 0) { unmark_facility(GSTATIDFILE, ""); return; } if ((first_active_facility()) && (options->promisc)) { init_promisc_list(&promisc_list); save_promisc_list(promisc_list); srpromisc(1, promisc_list); destroy_promisc_list(&promisc_list); } adjust_instance_count(PROCCOUNTFILE, 1); active_facility_countfile[0] = '\0'; if (logging) { if (strcmp(current_logfile, "") == 0) strcpy(current_logfile, GSTATLOG); if (!daemonized) input_logfile(current_logfile, &logging); } if (logging) { opentlog(&logfile, GSTATLOG); if (logfile == NULL) logging = 0; } if (logging) signal(SIGUSR1, rotate_gstat_log); rotate_flag = 0; writelog(logging, logfile, "******** General interface statistics started ********"); if (table.head != NULL) { preparescreen(&table); update_panels(); doupdate(); isdnfd = -1; exitloop = 0; gettimeofday(&tv, NULL); starttime = startlog = statbegin = tv.tv_sec; while (!exitloop) { getpacket(fd, buf, &fromaddr, &ch, &br, ifname, table.statwin); if (ch != ERR) { switch (ch) { case KEY_UP: scrollgstatwin(&table, SCROLLDOWN, &idx); break; case KEY_DOWN: scrollgstatwin(&table, SCROLLUP, &idx); break; case KEY_PPAGE: case '-': pagegstatwin(&table, SCROLLDOWN, &idx); break; case KEY_NPAGE: case ' ': pagegstatwin(&table, SCROLLUP, &idx); break; case 12: case 'l': case 'L': tx_refresh_screen(); break; case 'Q': case 'q': case 'X': case 'x': case 27: case 24: exitloop = 1; break; } } if (br > 0) { pkt_result = processpacket(buf, &packet, &br, NULL, &sport, &dport, &fromaddr, &linktype, ofilter, ifname, NULL); if (pkt_result == INVALID_PACKET) continue; positionptr(&table, &ptmp, ifname); ptmp->total++; ptmp->spanbr += br; ptmp->br += br; if (fromaddr.sll_protocol == ETH_P_IP) { ptmp->iptotal++; if (pkt_result == CHECKSUM_ERROR) { (ptmp->badtotal)++; continue; } } else { (ptmp->noniptotal)++; } printifentry(ptmp, table.statwin, idx); } gettimeofday(&tv, NULL); now = tv.tv_sec; unow = tv.tv_sec * 1e+6 + tv.tv_usec; if ((now - starttime) >= 5) { updaterates(&table, options->actmode, starttime, now, idx); printelapsedtime(statbegin, now, LINES - 3, 1, table.borderwin); starttime = now; } if (((now - startlog) >= options->logspan) && (logging)) { writegstatlog(&table, options->actmode, time((time_t *) NULL) - statbegin, logfile); startlog = now; } if (((options->updrate != 0) && (now - updtime >= options->updrate)) || ((options->updrate == 0) && (unow - updtime_usec >= DEFAULT_UPDATE_DELAY))) { update_panels(); doupdate(); updtime = now; updtime_usec = unow; } check_rotate_flag(&logfile, logging); if ((facilitytime != 0) && (((now - statbegin) / 60) >= facilitytime)) exitloop = 1; } close(fd); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -