diff --git a/Makefile b/Makefile index c075e68..f606c4e 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,8 @@ man8 := $(DESTDIR)/usr/share/man/man8/ all: nethogs -CFLAGS=-g -Wall -OBJS=structs.o packet.o connection.o process.o hashtbl.o refresh.o decpcap.o +CFLAGS=-g -Wall -pg +OBJS=structs.o packet.o connection.o process.o refresh.o decpcap.o cui.o GCC=g++ .PHONY: tgz @@ -42,6 +42,8 @@ hashtbl.o: hashtbl.cpp hashtbl.h nethogs.h $(GCC) $(CFLAGS) -c hashtbl.cpp decpcap.o: decpcap.c decpcap.h gcc $(CFLAGS) -c decpcap.c +cui.o: cui.cpp cui.h nethogs.h + $(GCC) $(CFLAGS) -c cui.cpp -DVERSION=\"$(VERSION)\" -DSUBVERSION=\"$(SUBVERSION)\" -DMINORVERSION=\"$(MINORVERSION)\" .PHONY: clean clean: diff --git a/decpcap.c b/decpcap.c index a757a3b..21edbf0 100644 --- a/decpcap.c +++ b/decpcap.c @@ -44,8 +44,8 @@ void dp_addcb (struct dp_handle * handle, enum dp_packet_type type, dp_callback void dp_parse_tcp (struct dp_handle * handle, const dp_header * header, const u_char * packet) { - const struct tcphdr * tcp = (struct tcphdr *) packet; - u_char * payload = (u_char *) packet + sizeof (struct tcphdr); + //const struct tcphdr * tcp = (struct tcphdr *) packet; + //u_char * payload = (u_char *) packet + sizeof (struct tcphdr); if (handle->callback[dp_packet_tcp] != NULL) { diff --git a/nethogs.cpp b/nethogs.cpp index 6b32888..9700770 100644 --- a/nethogs.cpp +++ b/nethogs.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include "cui.h" extern "C" { #include "decpcap.h" @@ -31,13 +31,11 @@ bool tracemode = false; bool needrefresh = true; //packet_type packettype = packet_ethernet; //dp_link_type linktype = dp_link_ethernet; +const char version[] = " version " VERSION "." SUBVERSION "." MINORVERSION; char * currentdevice = NULL; -const char version[] = " version " VERSION "." SUBVERSION "." MINORVERSION; - timeval curtime; -std::string * caption; bool local_addr::contains (const in_addr_t & n_addr) { if ((sa_family == AF_INET) @@ -99,6 +97,7 @@ int process_tcp (u_char * userdata, const dp_header * header, const u_char * m_p packet = new Packet (args->ip6_src, ntohs(tcp->source), args->ip6_dst, ntohs(tcp->dest), header->len, header->ts); break; } + //if (DEBUG) // std::cout << "Got packet from " << packet->gethashstring() << std::endl; @@ -150,17 +149,15 @@ int process_ip6 (u_char * userdata, const dp_header * header, const u_char * m_p void quit_cb (int i) { procclean(); - clear(); - endwin(); - delete caption; + if ((!tracemode) && (!DEBUG)) + exit_ui(); exit(0); } void forceExit(const char *msg) { if ((!tracemode)&&(!DEBUG)){ - clear(); - endwin(); + exit_ui(); } std::cerr << msg << std::endl; exit(0); @@ -168,7 +165,6 @@ void forceExit(const char *msg) static void versiondisplay(void) { - std::cerr << version << "\n"; } @@ -256,14 +252,7 @@ int main (int argc, char** argv) devices = new device (strdup("eth0")); if ((!tracemode) && (!DEBUG)){ - WINDOW * screen = initscr(); - raw(); - noecho(); - cbreak(); - nodelay(screen, TRUE); - caption = new std::string ("NetHogs"); - caption->append(version); - caption->append(", running at "); + init_ui(); } if (NEEDROOT && (getuid() != 0)) @@ -276,8 +265,8 @@ int main (int argc, char** argv) while (current_dev != NULL) { getLocal(current_dev->name); if ((!tracemode) && (!DEBUG)){ - caption->append(current_dev->name); - caption->append(" "); + //caption->append(current_dev->name); + //caption->append(" "); } dp_handle * newhandle = dp_open_live(current_dev->name, BUFSIZ, promisc, 100, errbuf); @@ -317,18 +306,7 @@ int main (int argc, char** argv) } if ((!DEBUG)&&(!tracemode)) { - switch (getch()) { - case 'q': - /* quit */ - quit_cb(0); - break; - case 's': - /* sort on 'sent' */ - break; - case 'r': - /* sort on 'received' */ - break; - } + ui_tick(); } if (needrefresh) { diff --git a/nethogs.h b/nethogs.h index 23ab233..cd27223 100644 --- a/nethogs.h +++ b/nethogs.h @@ -30,7 +30,13 @@ #define NEEDROOT 1 #endif -#define DEBUG 1 +#define DEBUG 0 + +// if '0', do extra checks and +// assertions. good for finding bugs +// at an early stage of development. +// for production, should be 1. +#define ROBUST 1 // 2 times: 32 characters, 7 ':''s, a ':12345'. // 1 '-' @@ -103,4 +109,6 @@ private: short int sa_family; }; +void quit_cb (int i); + #endif diff --git a/packet.cpp b/packet.cpp index d6be29a..9fd7d8e 100644 --- a/packet.cpp +++ b/packet.cpp @@ -163,7 +163,7 @@ Packet::Packet (const Packet &old_packet) { hashstring = NULL; else hashstring = strdup(old_packet.hashstring); - + dir = old_packet.dir; } bool sameinaddr(in_addr one, in_addr other) diff --git a/process.cpp b/process.cpp index e5a15a6..fde9151 100644 --- a/process.cpp +++ b/process.cpp @@ -15,25 +15,9 @@ #include "nethogs.h" #include "inodeproc.cpp" -extern timeval curtime; -extern std::string * caption; extern local_addr * local_addrs; -class ProcList -{ -public: - ProcList (Process * m_val, ProcList * m_next) - { - if (DEBUG) - assert (m_val != NULL); - val = m_val; next = m_next; - } - Process * getVal () { return val; } - ProcList * getNext () { return next; } - ProcList * next; -private: - Process * val; -}; +; /* * connection-inode table. takes information from /proc/net/tcp. @@ -232,12 +216,18 @@ struct prg_node * findPID (unsigned long inode) std::cout << "ITP: inode " << inode << " STILL not in inode-to-pid-mapping." << endl; return NULL; } - } else if (DEBUG) - std::cout << "ITP: inode " << inode << " found in inode-to-pid-mapping." << endl; + } - inodeproc[inode] = node; - - return node; + /* make copy of returned node, add it to map, and return it */ + if (node != NULL) + { + struct prg_node * tempnode = (struct prg_node *) malloc (sizeof (struct prg_node)); + memcpy (tempnode, node, sizeof (struct prg_node)); + inodeproc[inode] = tempnode; + return tempnode; + } + else + return NULL; } Process * findProcess (struct prg_node * node) @@ -245,7 +235,10 @@ Process * findProcess (struct prg_node * node) ProcList * current = processes; while (current != NULL) { - if (node->pid == current->getVal()->pid) + Process * currentproc = current->getVal(); + assert (currentproc != NULL); + + if (node->pid == currentproc->pid) return current->getVal(); current = current->next; } @@ -322,240 +315,23 @@ void refreshconninode () } -float tokbps (u_int32_t bytes) +int ProcList::size () { - return (((double)bytes) / PERIOD) / 1024; -} + int i=1; -char * uid2username (int uid) -{ - struct passwd * pwd; - /* getpwuid() allocates space for this itself, - * which we shouldn't free */ - pwd = getpwuid(uid); - if (pwd == NULL) - { - assert(false); - return strdup ("unlisted"); - } else { - return strdup(pwd->pw_name); - } -} + if (next != NULL) + i += next->size(); -class Line -{ -public: - Line (const char * name, double n_sent_kbps, double n_recv_kbps, int pid, uid_t uid, const char * n_devicename) - { - m_name = name; - sent_kbps = n_sent_kbps; - recv_kbps = n_recv_kbps; - devicename = n_devicename; - m_pid = pid; - m_uid = uid; - assert (m_uid >= 0); - assert (m_pid >= 0); - } - - void show (int row); - - double sent_kbps; - double recv_kbps; -private: - const char * m_name; - const char * devicename; - int m_pid; - int m_uid; -}; - -void Line::show (int row) -{ - if (DEBUG || tracemode) - { - assert (m_uid >= 0); - assert (m_pid >= 0); - - std::cout << m_name << '/' << m_pid << '/' << m_uid << "\t" << sent_kbps << "\t" << recv_kbps << std::endl; - return; - } - - mvprintw (3+row, 0, "%d", m_pid); - char * username = uid2username(m_uid); - mvprintw (3+row, 6, "%s", username); - free (username); - mvprintw (3+row, 6 + 9, "%s", m_name); - mvprintw (3+row, 6 + 9 + PROGNAME_WIDTH + 2, "%s", devicename); - mvprintw (3+row, 6 + 9 + PROGNAME_WIDTH + 2 + 6, "%10.3f", sent_kbps); - mvprintw (3+row, 6 + 9 + PROGNAME_WIDTH + 2 + 6 + 9 + 3, "%10.3f", recv_kbps); - mvprintw (3+row, 6 + 9 + PROGNAME_WIDTH + 2 + 6 + 9 + 3 + 11, "KB/sec", recv_kbps); -} - -int GreatestFirst (const void * ma, const void * mb) -{ - Line ** pa = (Line **)ma; - Line ** pb = (Line **)mb; - Line * a = *pa; - Line * b = *pb; - if (a->recv_kbps > b->recv_kbps) - { - return -1; - } - if (a->recv_kbps == b->recv_kbps) - { - return 0; - } - return 1; -} - -int count_processes() -{ - int i = 0; - ProcList * curproc = processes; - while (curproc != NULL) - { - i++; - curproc = curproc->getNext(); - } return i; } -// Display all processes and relevant network traffic using show function -void do_refresh() +void check_all_procs () { - refreshconninode(); - if (DEBUG || tracemode) - { - std::cout << "\n\nRefreshing:\n"; - } - else - { - clear(); - mvprintw (0, 0, "%s", caption->c_str()); - attron(A_REVERSE); - mvprintw (2, 0, " PID USER PROGRAM DEV SENT RECEIVED "); - attroff(A_REVERSE); - } ProcList * curproc = processes; - ProcList * previousproc = NULL; - int nproc = count_processes(); - /* initialise to null pointers */ - Line * lines [nproc]; - int n = 0, i = 0; - double sent_global = 0; - double recv_global = 0; - - if (DEBUG) - { - // initialise to null pointers - for (int i = 0; i < nproc; i++) - lines[i] = NULL; - } - while (curproc != NULL) { - // walk though its connections, summing up their data, and - // throwing away connections that haven't received a package - // in the last PROCESSTIMEOUT seconds. - if (DEBUG) - { - assert (curproc != NULL); - assert (curproc->getVal() != NULL); - } - /* do not remove the unknown process */ - if ((curproc->getVal()->getLastPacket() + PROCESSTIMEOUT <= curtime.tv_sec) && (curproc->getVal() != unknownproc)) - { - /* remove process */ - if (DEBUG) - std::cout << "PROC: Deleting process\n"; - ProcList * todelete = curproc; - Process * p_todelete = curproc->getVal(); - if (previousproc) - { - previousproc->next = curproc->next; - curproc = curproc->next; - } else { - processes = curproc->getNext(); - curproc = processes; - } - delete todelete; - delete p_todelete; - nproc--; - //continue; - } - else{ - - u_int32_t sum_sent = 0, - sum_recv = 0; - - /* walk though all this process's connections, and sum them - * up */ - ConnList * curconn = curproc->getVal()->connections; - ConnList * previous = NULL; - while (curconn != NULL) - { - if (curconn->getVal()->getLastPacket() <= curtime.tv_sec - CONNTIMEOUT) - { - /* stalled connection, remove. */ - ConnList * todelete = curconn; - Connection * conn_todelete = curconn->getVal(); - curconn = curconn->getNext(); - if (todelete == curproc->getVal()->connections) - curproc->getVal()->connections = curconn; - if (previous != NULL) - previous->setNext(curconn); - delete (todelete); - delete (conn_todelete); - } - else - { - u_int32_t sent = 0, recv = 0; - curconn->getVal()->sumanddel(curtime, &sent, &recv); - sum_sent += sent; - sum_recv += recv; - previous = curconn; - curconn = curconn->getNext(); - } - } - if (DEBUG) - { - assert (curproc->getVal()->getUid() >= 0); - } - lines[n] = new Line (curproc->getVal()->name, tokbps(sum_sent), tokbps(sum_recv), - curproc->getVal()->pid, curproc->getVal()->getUid(), curproc->getVal()->devicename); - previousproc = curproc; - curproc = curproc->next; - n++; - } - } - - /* sort the accumulated lines */ - qsort (lines, nproc, sizeof(Line *), GreatestFirst); - - /* print them */ - for (i=0; ishow(i); - recv_global += lines[i]->recv_kbps; - sent_global += lines[i]->sent_kbps; - delete lines[i]; - } - if (tracemode || DEBUG) { - /* print the 'unknown' connections, for debugging */ - ConnList * curr_unknownconn = unknownproc->connections; - while (curr_unknownconn != NULL) { - std::cout << "Unknown connection: " << - curr_unknownconn->getVal()->refpacket->gethashstring() << std::endl; - - curr_unknownconn = curr_unknownconn->getNext(); - } - } - - if ((!tracemode) && (!DEBUG)){ - attron(A_REVERSE); - mvprintw (3+1+i, 0, " TOTAL %10.3f %10.3f KB/sec ", sent_global, recv_global); - attroff(A_REVERSE); - mvprintw (4+1+i, 0, ""); - refresh(); + curproc->getVal()->check(); + curproc = curproc->getNext(); } } diff --git a/process.h b/process.h index 546055f..948fe1b 100644 --- a/process.h +++ b/process.h @@ -7,6 +7,8 @@ extern bool tracemode; +void check_all_procs (); + class ConnList { public: @@ -58,6 +60,10 @@ public: pid = 0; uid = 0; } + void check () { + assert (pid >= 0); + assert (uid >= 0); + } /* TODO free m_name and m_devicename again in constructor */ ~Process () { @@ -86,8 +92,25 @@ private: uid_t uid; }; +class ProcList +{ +public: + ProcList (Process * m_val, ProcList * m_next) + { + if (DEBUG) + assert (m_val != NULL); + val = m_val; next = m_next; + } + int size (); + Process * getVal () { return val; } + ProcList * getNext () { return next; } + ProcList * next; +private: + Process * val; +}; + Process * getProcess (Connection * connection, char * devicename = NULL); -void do_refresh (); +void refreshconninode (); void procclean ();