/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ /*** pktsize.c - the packet size breakdown facility ***/ #include "iptraf-ng-compat.h" #include "tui/winops.h" #include "attrs.h" #include "dirs.h" #include "fltdefs.h" #include "ifaces.h" #include "packet.h" #include "deskman.h" #include "error.h" #include "pktsize.h" #include "options.h" #include "timer.h" #include "log.h" #include "logvars.h" #include "promisc.h" struct ifstat_brackets { unsigned int floor; unsigned int ceil; unsigned long count; }; static void rotate_size_log(int s __unused) { rotate_flag = 1; strcpy(target_logname, current_logfile); signal(SIGUSR1, rotate_size_log); } static void write_size_log(struct ifstat_brackets *brackets, unsigned long nsecs, char *ifname, unsigned int mtu, FILE *logfile) { char atime[TIME_TARGET_MAX]; int i; genatime(time(NULL), atime); fprintf(logfile, "*** Packet Size Distribution, generated %s\n\n", atime); fprintf(logfile, "Interface: %s MTU: %u\n\n", ifname, mtu); fprintf(logfile, "Packet Size (bytes)\tCount\n"); for (i = 0; i <= 19; i++) { fprintf(logfile, "%u to %u:\t\t%lu\n", brackets[i].floor, brackets[i].ceil, brackets[i].count); } fprintf(logfile, "\nRunning time: %lu seconds\n", nsecs); fflush(logfile); } static int initialize_brackets(struct ifstat_brackets *brackets, unsigned int *interval, int mtu, WINDOW *win) { int i; *interval = mtu / 20; /* There are 20 packet size brackets */ for (i = 0; i <= 19; i++) { brackets[i].floor = *interval * i + 1; brackets[i].ceil = *interval * (i + 1); brackets[i].count = 0; } brackets[19].ceil = mtu; for (i = 0; i <= 9; i++) { wattrset(win, STDATTR); wmove(win, i + 5, 2); wprintw(win, "%4u to %4u:", brackets[i].floor, brackets[i].ceil); wmove(win, i + 5, 23); wattrset(win, HIGHATTR); wprintw(win, "%8lu", 0); } for (i = 10; i <= 19; i++) { wattrset(win, STDATTR); wmove(win, (i - 10) + 5, 36); if (i != 19) wprintw(win, "%4u to %4u:", brackets[i].floor, brackets[i].ceil); else wprintw(win, "%4u to %4u+:", brackets[i].floor, brackets[i].ceil); wmove(win, (i - 10) + 5, 57); wattrset(win, HIGHATTR); wprintw(win, "%8lu", 0); } wattrset(win, STDATTR); mvwprintw(win, 17, 1, "Interface MTU is %d bytes, not counting the data-link header", mtu); mvwprintw(win, 18, 1, "Maximum packet size is the MTU plus the data-link header length"); mvwprintw(win, 19, 1, "Packet size computations include data-link headers, if any"); return 0; } static void update_size_distrib(unsigned int length, struct ifstat_brackets *brackets, unsigned int interval) { unsigned int i; i = (length - 1) / interval; /* minus 1 to keep interval boundary lengths within the proper brackets */ if (i > 19) /* This is for extras for MTU's not */ i = 19; /* divisible by 20 */ brackets[i].count++; } static void print_size_distrib(struct ifstat_brackets *brackets, WINDOW *win) { for (unsigned int i = 0; i <= 19; i++) { if (i < 10) wmove(win, i + 5, 23); else wmove(win, (i - 10) + 5, 57); wprintw(win, "%8lu", brackets[i].count); } } void packet_size_breakdown(char *ifname, time_t facilitytime) { WINDOW *win; PANEL *panel; WINDOW *borderwin; PANEL *borderpanel; struct ifstat_brackets brackets[20]; unsigned int interval; int ch; int mtu; int pkt_result; struct timeval tv; time_t starttime, startlog, timeint; time_t now; struct timeval updtime; int logging = options.logging; FILE *logfile = NULL; int fd; if (!dev_up(ifname)) { err_iface_down(); goto err_unmark; } mtu = dev_get_mtu(ifname); if (mtu < 0) { write_error("Unable to obtain interface MTU"); goto err_unmark; } borderwin = newwin(LINES - 2, COLS, 1, 0); borderpanel = new_panel(borderwin); wattrset(borderwin, BOXATTR); tx_box(borderwin, ACS_VLINE, ACS_HLINE); mvwprintw(borderwin, 0, 1, " Packet Distribution by Size "); win = newwin(LINES - 4, COLS - 2, 2, 1); panel = new_panel(win); tx_stdwinset(win); wtimeout(win, -1); wattrset(win, STDATTR); tx_colorwin(win); move(LINES - 1, 1); stdexitkeyhelp(); initialize_brackets(brackets, &interval, mtu, win); mvwprintw(win, 1, 1, "Packet size brackets for interface %s", ifname); wattrset(win, BOXATTR); mvwprintw(win, 4, 1, "Packet Size (bytes)"); mvwprintw(win, 4, 26, "Count"); mvwprintw(win, 4, 36, "Packet Size (bytes)"); mvwprintw(win, 4, 60, "Count"); wattrset(win, HIGHATTR); if (logging) { if (strcmp(current_logfile, "") == 0) { snprintf(current_logfile, 80, "%s-%s.log", PKTSIZELOG, ifname); if (!daemonized) input_logfile(current_logfile, &logging); } } if (logging) { opentlog(&logfile, current_logfile); if (logfile == NULL) logging = 0; } if (logging) { signal(SIGUSR1, rotate_size_log); rotate_flag = 0; writelog(logging, logfile, "******** Packet size distribution facility started ********"); } exitloop = 0; gettimeofday(&tv, NULL); updtime = tv; now = starttime = startlog = timeint = tv.tv_sec; LIST_HEAD(promisc); if (options.promisc) { promisc_init(&promisc, ifname); promisc_set_list(&promisc); } fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if(fd == -1) { write_error("Unable to obtain monitoring socket"); goto err; } if(dev_bind_ifname(fd, ifname) == -1) { write_error("Unable to bind interface on the socket"); goto err_close; } PACKET_INIT(pkt); do { gettimeofday(&tv, NULL); now = tv.tv_sec; if (screen_update_needed(&tv, &updtime)) { print_size_distrib(brackets, win); update_panels(); doupdate(); updtime = tv; } if (now - timeint >= 5) { printelapsedtime(starttime, now, LINES - 3, 1, borderwin); timeint = now; } if (logging) { check_rotate_flag(&logfile); if ((now - startlog) >= options.logspan) { write_size_log(brackets, now - starttime, ifname, mtu, logfile); startlog = now; } } if ((facilitytime != 0) && (((now - starttime) / 60) >= facilitytime)) exitloop = 1; if (packet_get(fd, &pkt, &ch, win) == -1) { write_error("Packet receive failed"); exitloop = 1; break; } if (ch != ERR) { switch (ch) { case 12: case 'l': case 'L': tx_refresh_screen(); break; case 'x': case 'X': case 'q': case 'Q': case 27: case 24: exitloop = 1; } } if (pkt.pkt_len <= 0) continue; pkt_result = packet_process(&pkt, NULL, NULL, NULL, MATCH_OPPOSITE_USECONFIG, 0); if (pkt_result != PACKET_OK) continue; update_size_distrib(pkt.pkt_len, brackets, interval); } while (!exitloop); err_close: close(fd); err: if (logging) { signal(SIGUSR1, SIG_DFL); write_size_log(brackets, now - starttime, ifname, mtu, logfile); writelog(logging, logfile, "******** Packet size distribution facility stopped ********"); fclose(logfile); } if (options.promisc) { promisc_restore_list(&promisc); promisc_destroy(&promisc); } del_panel(panel); delwin(win); del_panel(borderpanel); delwin(borderwin); err_unmark: strcpy(current_logfile, ""); }