capt_get_packet(): check for key press only every 20ms
[iptraf-ng.git] / src / itrafmon.c
blob3732535c4ecc208d5b530792584b92f9c5487405
1 /* For terms of usage/redistribution/modification see the LICENSE file */
2 /* For authors and contributors see the AUTHORS file */
4 /***
6 itrafmon.c - the IP traffic monitor module
8 ***/
10 #include "iptraf-ng-compat.h"
12 #include "tui/labels.h"
13 #include "tui/winops.h"
15 #include "options.h"
16 #include "tcptable.h"
17 #include "othptab.h"
18 #include "fltdefs.h"
19 #include "packet.h"
20 #include "ifaces.h"
21 #include "promisc.h"
22 #include "deskman.h"
23 #include "error.h"
24 #include "attrs.h"
25 #include "log.h"
26 #include "revname.h"
27 #include "rvnamed.h"
28 #include "dirs.h"
29 #include "timer.h"
30 #include "ipfrag.h"
31 #include "logvars.h"
32 #include "itrafmon.h"
33 #include "sockaddr.h"
34 #include "capt.h"
36 #define SCROLLUP 0
37 #define SCROLLDOWN 1
39 static void rotate_ipmon_log(int s __unused)
41 rotate_flag = 1;
42 strcpy(target_logname, current_logfile);
43 signal(SIGUSR1, rotate_ipmon_log);
46 /* Hot key indicators for the bottom line */
48 static void ipmonhelp(void)
50 move(LINES - 1, 1);
51 tx_printkeyhelp("Up/Dn/PgUp/PgDn", "-scroll ", stdscr, HIGHATTR,
52 STATUSBARATTR);
53 move(LINES - 1, 43);
54 tx_printkeyhelp("W", "-chg actv win ", stdscr, HIGHATTR,
55 STATUSBARATTR);
56 tx_printkeyhelp("S", "-sort TCP ", stdscr, HIGHATTR, STATUSBARATTR);
57 stdexitkeyhelp();
60 static void uniq_help(int what)
62 move(LINES - 1, 25);
63 if (!what)
64 tx_printkeyhelp("M", "-more TCP info ", stdscr, HIGHATTR,
65 STATUSBARATTR);
66 else
67 tx_printkeyhelp("Lft/Rt", "-vtcl scrl ", stdscr, HIGHATTR,
68 STATUSBARATTR);
71 static void markactive(int curwin, WINDOW * tw, WINDOW * ow)
73 WINDOW *win1;
74 WINDOW *win2;
75 int x1 __unused, y1, x2 __unused, y2;
77 if (!curwin) {
78 win1 = tw;
79 win2 = ow;
80 } else {
81 win1 = ow;
82 win2 = tw;
85 getmaxyx(win1, y1, x1);
86 getmaxyx(win2, y2, x2);
88 wmove(win1, --y1, COLS - 10);
89 wattrset(win1, ACTIVEATTR);
90 wprintw(win1, " Active ");
91 wattrset(win1, BOXATTR);
92 wmove(win2, --y2, COLS - 10);
93 whline(win2, ACS_HLINE, 8);
96 static void update_flowrates(struct tcptable *table, unsigned long msecs)
98 struct tcptableent *entry;
99 for (entry = table->head; entry != NULL; entry = entry->next_entry) {
100 rate_add_rate(&entry->rate, entry->spanbr, msecs);
101 entry->spanbr = 0;
105 static void print_flowrate(struct tcptable *table)
107 if (table->barptr == NULL) {
108 wattrset(table->statwin, IPSTATATTR);
109 mvwprintw(table->statwin, 0, COLS * 47 / 80,
110 "No TCP entries ");
111 } else {
112 wattrset(table->statwin, IPSTATLABELATTR);
113 mvwprintw(table->statwin, 0, COLS * 47 / 80,
114 "TCP flow rate: ");
116 char buf[32];
117 rate_print(rate_get_average(&table->barptr->rate), buf, sizeof(buf));
118 wattrset(table->statwin, IPSTATATTR);
119 mvwprintw(table->statwin, 0, COLS * 52 / 80 + 13, "%s", buf);
124 * Scrolling and paging routines for the upper (TCP) window
127 static void scrollupperwin(struct tcptable *table, int direction)
129 wattrset(table->tcpscreen, STDATTR);
130 if (direction == SCROLLUP) {
131 if (table->lastvisible != table->tail) {
132 table->firstvisible = table->firstvisible->next_entry;
133 table->lastvisible = table->lastvisible->next_entry;
135 wscrl(table->tcpscreen, 1);
136 scrollok(table->tcpscreen, 0);
137 wmove(table->tcpscreen, table->imaxy - 1, 0);
138 wprintw(table->tcpscreen, "%*c", COLS - 2, ' ');
139 scrollok(table->tcpscreen, 1);
141 printentry(table, table->lastvisible);
143 } else {
144 if (table->firstvisible != table->head) {
145 table->firstvisible = table->firstvisible->prev_entry;
146 table->lastvisible = table->lastvisible->prev_entry;
148 wscrl(table->tcpscreen, -1);
149 mvwprintw(table->tcpscreen, 0, 0, "%*c", COLS - 2, ' ');
151 printentry(table, table->firstvisible);
156 static void move_tcp_bar_one(struct tcptable *table, int direction)
158 switch (direction) {
159 case SCROLLUP:
160 if (table->barptr->next_entry == NULL)
161 break;
163 if (table->barptr == table->lastvisible)
164 scrollupperwin(table, SCROLLUP);
166 table->barptr = table->barptr->next_entry;
167 printentry(table, table->barptr->prev_entry); /* hide bar */
168 printentry(table, table->barptr); /* show bar */
170 break;
171 case SCROLLDOWN:
172 if (table->barptr->prev_entry == NULL)
173 break;
175 if (table->barptr == table->firstvisible)
176 scrollupperwin(table, SCROLLDOWN);
178 table->barptr = table->barptr->prev_entry;
179 printentry(table, table->barptr->next_entry); /* hide bar */
180 printentry(table, table->barptr); /* show bar */
182 break;
186 static void move_tcp_bar_many(struct tcptable *table, int direction, int lines)
188 switch (direction) {
189 case SCROLLUP:
190 while (lines && (table->lastvisible != table->tail)) {
191 table->firstvisible = table->firstvisible->next_entry;
192 table->lastvisible = table->lastvisible->next_entry;
193 lines--;
195 if (lines == 0)
196 table->barptr = table->firstvisible;
197 else
198 table->barptr = table->lastvisible;
199 break;
200 case SCROLLDOWN:
201 while (lines && (table->firstvisible != table->head)) {
202 table->firstvisible = table->firstvisible->prev_entry;
203 table->lastvisible = table->lastvisible->prev_entry;
204 lines--;
206 table->barptr = table->firstvisible;
207 break;
209 refreshtcpwin(table);
212 static void move_tcp_bar(struct tcptable *table, int direction, int lines)
214 if (table->barptr == NULL)
215 return;
216 if (lines < 1)
217 return;
218 if (lines < 10)
219 while (lines--)
220 move_tcp_bar_one(table, direction);
221 else
222 move_tcp_bar_many(table, direction, lines);
224 print_flowrate(table);
228 * Scrolling and paging routines for the lower (non-TCP) window.
231 static void scroll_othp_one(struct othptable *table, int direction)
233 switch (direction) {
234 case SCROLLUP:
235 if (table->lastvisible != table->tail) {
236 table->firstvisible = table->firstvisible->next_entry;
237 table->lastvisible = table->lastvisible->next_entry;
239 wscrl(table->othpwin, 1);
240 printothpentry(table, table->lastvisible,
241 table->oimaxy - 1, 0, NULL);
243 if (table->htstat == HIND) { /* Head indicator on? */
244 wmove(table->borderwin, table->obmaxy - 1, 1);
245 whline(table->borderwin, ACS_HLINE, 8);
246 table->htstat = NOHTIND;
249 break;
250 case SCROLLDOWN:
251 if (table->firstvisible != table->head) {
252 table->firstvisible = table->firstvisible->prev_entry;
253 table->lastvisible = table->lastvisible->prev_entry;
255 wscrl(table->othpwin, -1);
256 printothpentry(table, table->firstvisible, 0, 0, NULL);
258 if (table->htstat == TIND) { /* Tail indicator on? */
259 wmove(table->borderwin, table->obmaxy - 1, 1);
260 whline(table->borderwin, ACS_HLINE, 8);
261 table->htstat = NOHTIND;
264 break;
268 static void scroll_othp_many(struct othptable *table, int direction, int lines)
270 switch (direction) {
271 case SCROLLUP:
272 while (lines-- && (table->lastvisible != table->tail)) {
273 table->firstvisible = table->firstvisible->next_entry;
274 table->lastvisible = table->lastvisible->next_entry;
276 if (table->htstat == HIND) { /* Head indicator on? */
277 wmove(table->borderwin, table->obmaxy - 1, 1);
278 whline(table->borderwin, ACS_HLINE, 8);
279 table->htstat = NOHTIND;
281 break;
282 case SCROLLDOWN:
283 while (lines-- && (table->firstvisible != table->head)) {
284 table->firstvisible = table->firstvisible->prev_entry;
285 table->lastvisible = table->lastvisible->prev_entry;
287 if (table->htstat == TIND) { /* Tail indicator on? */
288 wmove(table->borderwin, table->obmaxy - 1, 1);
289 whline(table->borderwin, ACS_HLINE, 8);
290 table->htstat = NOHTIND;
292 break;
294 refresh_othwindow(table);
297 static void scroll_othp(struct othptable *table, int direction, int lines)
299 if (table->head == NULL)
300 return;
301 if (lines < 1)
302 return;
303 if (lines < getmaxy(table->othpwin))
304 while (lines--)
305 scroll_othp_one(table, direction);
306 else
307 scroll_othp_many(table, direction, lines);
311 * Pop up sorting key window
314 static void show_tcpsort_win(WINDOW ** win, PANEL ** panel)
316 *win = newwin(9, 35, (LINES - 8) / 2, COLS - 40);
317 *panel = new_panel(*win);
319 wattrset(*win, DLGBOXATTR);
320 tx_colorwin(*win);
321 tx_box(*win, ACS_VLINE, ACS_HLINE);
322 wattrset(*win, DLGTEXTATTR);
323 mvwprintw(*win, 2, 2, "Select sort criterion");
324 wmove(*win, 4, 2);
325 tx_printkeyhelp("P", " - sort by packet count", *win, DLGHIGHATTR,
326 DLGTEXTATTR);
327 wmove(*win, 5, 2);
328 tx_printkeyhelp("B", " - sort by byte count", *win, DLGHIGHATTR,
329 DLGTEXTATTR);
330 wmove(*win, 6, 2);
331 tx_printkeyhelp("Any other key", " - cancel sort", *win, DLGHIGHATTR,
332 DLGTEXTATTR);
333 update_panels();
334 doupdate();
338 * Routine to swap two TCP entries. p1 and p2 are pointers to TCP entries,
339 * but p1 must be ahead of p2. It's a linked list thing.
341 static void swap_tcp_entries(struct tcptable *table, struct tcptableent *p1,
342 struct tcptableent *p2)
344 struct tcptableent *p2nextsaved;
345 struct tcptableent *p1prevsaved;
346 unsigned int tmp;
348 if (p1 == p2)
349 return;
351 tmp = p1->index;
352 p1->index = p2->index;
353 p2->index = tmp;
355 p1->next_entry->index = p1->index + 1;
356 p2->next_entry->index = p2->index + 1;
358 if (p1->prev_entry != NULL)
359 p1->prev_entry->next_entry = p2;
360 else
361 table->head = p2;
363 if (p2->next_entry->next_entry != NULL)
364 p2->next_entry->next_entry->prev_entry = p1->next_entry;
365 else
366 table->tail = p1->next_entry;
368 p2nextsaved = p2->next_entry->next_entry;
369 p1prevsaved = p1->prev_entry;
371 if (p1->next_entry->next_entry == p2) { /* swapping adjacent entries */
372 p2->next_entry->next_entry = p1;
373 p1->prev_entry = p2->next_entry;
374 } else {
375 p2->next_entry->next_entry = p1->next_entry->next_entry;
376 p1->prev_entry = p2->prev_entry;
377 p2->prev_entry->next_entry = p1;
378 p1->next_entry->next_entry->prev_entry = p2->next_entry;
381 p2->prev_entry = p1prevsaved;
382 p1->next_entry->next_entry = p2nextsaved;
385 static unsigned long long qt_getkey(struct tcptableent *entry, int ch)
387 if (ch == 'B')
388 return (max(entry->bcount, entry->oth_connection->bcount));
390 return (max(entry->pcount, entry->oth_connection->pcount));
393 static struct tcptableent *qt_partition(struct tcptable *table,
394 struct tcptableent **low,
395 struct tcptableent **high, int ch)
397 struct tcptableent *pivot = *low;
399 struct tcptableent *left = *low;
400 struct tcptableent *right = *high;
401 struct tcptableent *ptmp;
403 unsigned long long pivot_value;
405 pivot_value = qt_getkey(pivot, ch);
407 while (left->index < right->index) {
408 while ((qt_getkey(left, ch) >= pivot_value)
409 && (left->next_entry->next_entry != NULL))
411 left = left->next_entry->next_entry;
413 while (qt_getkey(right, ch) < pivot_value)
414 right = right->prev_entry->prev_entry;
416 if (left->index < right->index) {
417 swap_tcp_entries(table, left, right);
419 if (*low == left)
420 *low = right;
422 if (*high == right)
423 *high = left;
425 ptmp = left;
426 left = right;
427 right = ptmp;
430 swap_tcp_entries(table, pivot, right);
432 if (*low == pivot)
433 *low = right;
435 if (*high == right)
436 *high = pivot;
438 return pivot;
442 * Quicksort the TCP entries.
444 static void quicksort_tcp_entries(struct tcptable *table,
445 struct tcptableent *low,
446 struct tcptableent *high, int ch)
448 struct tcptableent *pivot;
450 if ((high == NULL) || (low == NULL))
451 return;
453 if (high->index > low->index) {
454 pivot =
455 qt_partition(table, &low, &high, ch);
457 if (pivot->prev_entry != NULL)
458 quicksort_tcp_entries(table, low,
459 pivot->prev_entry->prev_entry, ch);
461 quicksort_tcp_entries(table, pivot->next_entry->next_entry,
462 high, ch);
467 * This function sorts the TCP window. The old exchange sort has been
468 * replaced with a Quicksort algorithm.
471 static void sortipents(struct tcptable *table, int ch)
473 if ((table->head == NULL)
474 || (table->head->next_entry->next_entry == NULL))
475 return;
477 ch = toupper(ch);
479 if ((ch != 'P') && (ch != 'B'))
480 return;
482 quicksort_tcp_entries(table, table->head, table->tail->prev_entry, ch);
484 table->firstvisible = table->head;
485 struct tcptableent *ptmp = table->head;
487 while (ptmp && ((int)ptmp->index <= getmaxy(table->tcpscreen))) {
488 table->lastvisible = ptmp;
489 ptmp = ptmp->next_entry;
494 * Attempt to communicate with rvnamed, and if it doesn't respond, try
495 * to start it.
498 static int checkrvnamed(void)
500 pid_t cpid = 0;
501 int cstat;
503 indicate("Trying to communicate with reverse lookup server");
504 if (!rvnamedactive()) {
505 indicate("Starting reverse lookup server");
507 if ((cpid = fork()) == 0) {
508 char *args[] = {
509 "rvnamed-ng",
510 NULL
512 execvp("rvnamed-ng", args);
514 * execvp() never returns, so if we reach this point, we have
515 * a problem.
518 die("unable execvp() rvnamed-ng");
519 } else if (cpid == -1) {
520 write_error("Can't spawn new process; lookups will block");
521 return 0;
522 } else {
523 while (waitpid(cpid, &cstat, 0) < 0)
524 if (errno != EINTR)
525 break;
527 if (WEXITSTATUS(cstat) == 1) {
528 write_error("Can't start rvnamed; lookups will block");
529 return 0;
530 } else {
531 sleep(1);
532 return 1;
536 return 1;
539 static void ipmon_process_key(int ch, int *curwin, struct tcptable *table, struct othptable *othptbl)
541 static int keymode = 0;
542 static WINDOW *sortwin;
543 static PANEL *sortpanel;
545 if (keymode == 0) {
546 switch (ch) {
547 case KEY_UP:
548 if (*curwin)
549 scroll_othp(othptbl, SCROLLDOWN, 1);
550 else
551 move_tcp_bar(table, SCROLLDOWN, 1);
552 break;
553 case KEY_DOWN:
554 if (*curwin)
555 scroll_othp(othptbl, SCROLLUP, 1);
556 else
557 move_tcp_bar(table, SCROLLUP, 1);
558 break;
559 case KEY_RIGHT:
560 if (!*curwin)
561 break;
563 if (othptbl->strindex != VSCRL_OFFSET)
564 othptbl->strindex = VSCRL_OFFSET;
566 refresh_othwindow(othptbl);
567 break;
568 case KEY_LEFT:
569 if (!*curwin)
570 break;
572 if (othptbl->strindex != 0)
573 othptbl->strindex = 0;
575 refresh_othwindow(othptbl);
576 break;
577 case KEY_PPAGE:
578 case '-':
579 if (*curwin)
580 scroll_othp(othptbl, SCROLLDOWN, othptbl->oimaxy);
581 else
582 move_tcp_bar(table, SCROLLDOWN, table->imaxy);
583 break;
584 case KEY_NPAGE:
585 case ' ':
586 if (*curwin)
587 scroll_othp(othptbl, SCROLLUP, othptbl->oimaxy);
588 else
589 move_tcp_bar(table, SCROLLUP, table->imaxy);
590 break;
591 case KEY_HOME:
592 if (*curwin)
593 scroll_othp(othptbl, SCROLLDOWN, INT_MAX);
594 else
595 move_tcp_bar(table, SCROLLDOWN, INT_MAX);
596 break;
597 case KEY_END:
598 if (*curwin)
599 scroll_othp(othptbl, SCROLLUP, INT_MAX);
600 else
601 move_tcp_bar(table, SCROLLUP, INT_MAX);
602 break;
603 case KEY_F(6):
604 case 'w':
605 case 'W':
606 case 9:
607 *curwin = !*curwin;
608 markactive(*curwin, table->borderwin,
609 othptbl->borderwin);
610 uniq_help(*curwin);
611 break;
612 case 'm':
613 case 'M':
614 if (*curwin)
615 break;
616 table->mode = (table->mode + 1) % 3;
617 if ((table->mode == 1) && !options.mac)
618 table->mode = 2;
619 refreshtcpwin(table);
620 break;
621 case 12:
622 case 'l':
623 case 'L':
624 tx_refresh_screen();
625 break;
627 case 'F':
628 case 'f':
629 case 'c':
630 case 'C':
631 flushclosedentries(table);
632 refreshtcpwin(table);
633 break;
634 case 's':
635 case 'S':
636 keymode = 1;
637 show_tcpsort_win(&sortwin, &sortpanel);
638 break;
639 case 'Q':
640 case 'q':
641 case 'X':
642 case 'x':
643 case 24:
644 case 27:
645 exitloop = 1;
646 break;
648 } else if (keymode == 1) {
649 keymode = 0;
650 del_panel(sortpanel);
651 delwin(sortwin);
652 flushclosedentries(table);
653 sortipents(table, ch);
654 if (table->barptr != NULL) {
655 table->barptr = table->firstvisible;
657 refreshtcpwin(table);
661 static void ipmon_process_packet(struct pkt_hdr *pkt, char *ifname,
662 struct tcptable *table,
663 struct othptable *othptbl,
664 int logging, FILE *logfile,
665 int *revlook, int rvnfd)
667 in_port_t sport = 0, dport = 0; /* TCP/UDP port values */
668 unsigned int br; /* bytes read. Differs from readlen */
669 char ifnamebuf[IFNAMSIZ];
670 struct tcptableent *tcpentry;
672 int pkt_result = packet_process(pkt, &br, &sport, &dport,
673 MATCH_OPPOSITE_ALWAYS,
674 options.v6inv4asv6);
676 if (pkt_result != PACKET_OK)
677 return;
679 if (!ifname) {
680 /* we're capturing on "All interfaces", */
681 /* so get the name of the interface */
682 /* of this packet */
683 int r = dev_get_ifname(pkt->from->sll_ifindex, ifnamebuf);
684 if (r != 0) {
685 write_error("Unable to get interface name");
686 return; /* error getting interface name, get out! */
688 ifname = ifnamebuf;
691 struct sockaddr_storage saddr, daddr;
692 switch(pkt->pkt_protocol) {
693 case ETH_P_IP:
694 sockaddr_make_ipv4(&saddr, pkt->iphdr->saddr);
695 sockaddr_make_ipv4(&daddr, pkt->iphdr->daddr);
696 break;
697 case ETH_P_IPV6:
698 sockaddr_make_ipv6(&saddr, &pkt->ip6_hdr->ip6_src);
699 sockaddr_make_ipv6(&daddr, &pkt->ip6_hdr->ip6_dst);
700 break;
701 default:
702 add_othp_entry(othptbl, pkt, NULL, NULL,
703 NOT_IP,
704 pkt->pkt_protocol,
705 pkt->pkt_payload, ifname, 0,
706 0, logging, logfile);
707 return;
710 /* only when packets fragmented */
711 char *ip_payload = pkt->pkt_payload + pkt_iph_len(pkt);
712 switch (pkt_ip_protocol(pkt)) {
713 case IPPROTO_TCP: {
714 struct tcphdr *tcp = (struct tcphdr *)ip_payload;
715 sockaddr_set_port(&saddr, sport);
716 sockaddr_set_port(&daddr, dport);
717 tcpentry = in_table(table, &saddr, &daddr, ifname);
720 * Add a new entry if it doesn't exist, and,
721 * to reduce the chances of stales, not a FIN.
724 if (packet_is_first_fragment(pkt) /* first frag only */
725 && (tcpentry == NULL)
726 && !tcp->fin) {
729 * Ok, so we have a packet. Add it if this connection
730 * is not yet closed, or if it is a SYN packet.
732 int wasempty = (table->head == NULL);
733 tcpentry = addentry(table, &saddr, &daddr,
734 pkt_ip_protocol(pkt),
735 ifname, revlook, rvnfd);
736 if (tcpentry != NULL) {
737 printentry(table, tcpentry->oth_connection);
739 if (wasempty) {
740 table->barptr = table->firstvisible;
745 * If we had an addentry() success, we should have no
746 * problem here. Same thing if we had a table lookup
747 * success.
750 if ((tcpentry != NULL)
751 && !(tcpentry->stat & FLAG_RST)) {
752 int p_sstat = 0, p_dstat = 0; /* Reverse lookup statuses prior to */
755 * Don't bother updating the entry if the connection
756 * has been previously reset. (Does this really
757 * happen in practice?)
760 if (*revlook) {
761 p_sstat = tcpentry->s_fstat;
762 p_dstat = tcpentry->d_fstat;
765 if (pkt->iphdr)
766 updateentry(table, pkt, tcpentry, tcp,
768 revlook, rvnfd,
769 logging, logfile);
770 else
771 updateentry(table, pkt, tcpentry, tcp,
772 pkt->pkt_len,
773 revlook, rvnfd,
774 logging, logfile);
776 * Log first packet of a TCP connection except if
777 * it's a RST, which was already logged earlier in
778 * updateentry()
781 if (logging
782 && (tcpentry->pcount == 1)
783 && (!(tcpentry->stat & FLAG_RST))) {
784 char msgstring[80];
785 strcpy(msgstring, "first packet");
786 if (tcp->syn)
787 strcat(msgstring, " (SYN)");
789 writetcplog(logging, logfile, tcpentry,
790 pkt->pkt_len, msgstring);
793 if (*revlook
794 && (((p_sstat != RESOLVED)
795 && (tcpentry->s_fstat == RESOLVED))
796 || ((p_dstat != RESOLVED)
797 && (tcpentry->d_fstat == RESOLVED)))) {
798 clearaddr(table, tcpentry);
799 clearaddr(table, tcpentry->oth_connection);
801 printentry(table, tcpentry);
804 * Special cases: Update other direction if it's
805 * an ACK in response to a FIN.
807 * -- or --
809 * Addresses were just resolved for the other
810 * direction, so we should also do so here.
813 if (((tcpentry->oth_connection->finsent == 2)
814 && /* FINed and ACKed */
815 (ntohl(tcp->seq) == tcpentry->oth_connection->finack))
816 || (*revlook
817 && (((p_sstat != RESOLVED)
818 && (tcpentry->s_fstat == RESOLVED))
819 || ((p_dstat != RESOLVED)
820 && (tcpentry->d_fstat == RESOLVED)))))
821 printentry(table, tcpentry->oth_connection);
823 break; }
824 case IPPROTO_ICMP:
825 case IPPROTO_ICMPV6:
826 check_icmp_dest_unreachable(table, pkt, ifname);
827 /* print this ICMP(v6) and ... */
828 /* fall through */
829 default:
830 add_othp_entry(othptbl, pkt, &saddr, &daddr,
831 IS_IP, pkt_ip_protocol(pkt),
832 ip_payload, ifname,
833 revlook, rvnfd, logging, logfile);
834 break;
838 /* the IP Traffic Monitor */
839 void ipmon(time_t facilitytime, char *ifptr)
841 int logging = options.logging;
843 FILE *logfile = NULL;
845 int curwin = 0;
847 unsigned long long total_pkts = 0;
849 struct tcptable table;
851 struct othptable othptbl;
853 struct capt capt;
855 struct pkt_hdr pkt;
857 int ch;
859 int rvnfd = 0;
861 int revlook = options.revlook;
863 if (ifptr && !dev_up(ifptr)) {
864 err_iface_down();
865 return;
868 LIST_HEAD(promisc);
869 if (options.promisc) {
870 promisc_init(&promisc, ifptr);
871 promisc_set_list(&promisc);
874 if (capt_init(&capt, ifptr) == -1) {
875 write_error("Unable to initialize packet capture interface");
876 goto err;
879 if (revlook) {
880 if (checkrvnamed())
881 open_rvn_socket(&rvnfd);
882 } else
883 rvnfd = 0;
885 if (options.servnames)
886 setservent(1);
887 setprotoent(1);
890 * Try to open log file if logging activated. Turn off logging
891 * (for this session only) if an error was discovered in opening
892 * the log file. Configuration setting is kept. Who knows, the
893 * situation may be corrected later.
896 if (logging) {
897 if (strcmp(current_logfile, "") == 0) {
898 strncpy(current_logfile,
899 gen_instance_logname(IPMONLOG, getpid()),
900 80);
902 if (!daemonized)
903 input_logfile(current_logfile, &logging);
907 if (logging) {
908 opentlog(&logfile, current_logfile);
910 if (logfile == NULL)
911 logging = 0;
913 if (logging) {
914 signal(SIGUSR1, rotate_ipmon_log);
916 rotate_flag = 0;
917 writelog(logging, logfile,
918 "******** IP traffic monitor started ********");
921 init_tcp_table(&table);
922 init_othp_table(&othptbl);
924 markactive(curwin, table.borderwin, othptbl.borderwin);
925 ipmonhelp();
926 uniq_help(0);
927 update_panels();
928 doupdate();
930 packet_init(&pkt);
932 exitloop = 0;
934 struct timeval now;
935 gettimeofday(&now, NULL);
936 struct timeval last_time = now;
937 struct timeval updtime = now;
938 time_t starttime = now.tv_sec;
940 time_t check_closed;
941 if (options.closedint != 0)
942 check_closed = now.tv_sec + options.closedint * 60;
943 else
944 check_closed = INT_MAX;
946 /* set the time after which we terminate the process */
947 time_t endtime;
948 if (facilitytime != 0)
949 endtime = now.tv_sec + facilitytime * 60;
950 else
951 endtime = INT_MAX;
953 while (!exitloop) {
954 gettimeofday(&now, NULL);
956 /* update screen at configured intervals. */
957 if (screen_update_needed(&now, &updtime)) {
958 show_stats(table.statwin, total_pkts);
959 update_panels();
960 doupdate();
962 updtime = now;
965 if (now.tv_sec > last_time.tv_sec) {
966 unsigned long msecs = timeval_diff_msec(&now, &last_time);
967 /* update all flowrates ... */
968 update_flowrates(&table, msecs);
969 /* ... and print the current one every second */
970 print_flowrate(&table);
972 /* print timer at bottom of screen */
973 printelapsedtime(now.tv_sec - starttime, 15, othptbl.borderwin);
975 print_packet_drops(capt_get_dropped(&capt), othptbl.borderwin, 40);
977 mark_timeouted_entries(&table, logging, logfile);
979 /* automatically clear closed/timed out entries */
980 if (now.tv_sec > check_closed) {
981 flushclosedentries(&table);
982 refreshtcpwin(&table);
983 check_closed = now.tv_sec + options.closedint * 60;
986 /* terminate after lifetime specified at the cmdline */
987 if (now.tv_sec > endtime)
988 exitloop = 1;
990 /* close and rotate log file if signal was received */
991 if (logging && (rotate_flag == 1)) {
992 announce_rotate_prepare(logfile);
993 write_tcp_unclosed(logging, logfile, &table);
994 rotate_logfile(&logfile, target_logname);
995 announce_rotate_complete(logfile);
996 rotate_flag = 0;
999 last_time = now;
1002 if (capt_get_packet(&capt, &pkt, &ch, table.tcpscreen) == -1) {
1003 write_error("Packet receive failed");
1004 exitloop = 1;
1005 break;
1008 if (ch != ERR)
1009 ipmon_process_key(ch, &curwin, &table, &othptbl);
1011 if (pkt.pkt_len > 0) {
1012 total_pkts++;
1013 ipmon_process_packet(&pkt, ifptr, &table, &othptbl,
1014 logging, logfile,
1015 &revlook, rvnfd);
1016 capt_put_packet(&capt, &pkt);
1019 packet_destroy(&pkt);
1021 destroyothptable(&othptbl);
1022 destroytcptable(&table);
1023 update_panels();
1024 doupdate();
1026 if (logging) {
1027 signal(SIGUSR1, SIG_DFL);
1028 writelog(logging, logfile,
1029 "******** IP traffic monitor stopped ********\n");
1030 fclose(logfile);
1031 strcpy(current_logfile, "");
1034 endprotoent();
1035 if (options.servnames)
1036 endservent();
1038 killrvnamed();
1039 close_rvn_socket(rvnfd);
1041 capt_destroy(&capt);
1042 err:
1043 if (options.promisc) {
1044 promisc_restore_list(&promisc);
1045 promisc_destroy(&promisc);