From 4182fc0b17b0ec51fc093114d9875fc684f32b46 Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Sat, 27 Aug 2005 11:49:16 +0000 Subject: [PATCH] * when a packet's owner cannot be found (for example if it has already disappeared, which can happen with for example small fast HTTP requests), show the source and destination ports and ip's * support UDP packets (which never have owners) * nicely truncate oversized program names --- cui.cpp | 32 ++++++++++++++++++------- inode2prog.cpp | 16 ++++++++++--- nethogs.cpp | 49 +++++++++++++++++++++++++++++++++++++++ nethogs.h | 8 ++++--- process.cpp | 63 +++++++++++++++++++++++++++++++++++++------------- 5 files changed, 138 insertions(+), 30 deletions(-) diff --git a/cui.cpp b/cui.cpp index 95cb210..064cd73 100644 --- a/cui.cpp +++ b/cui.cpp @@ -12,7 +12,10 @@ std::string * caption; const char version[] = " version " VERSION "." SUBVERSION "." MINORVERSION; extern ProcList * processes; extern timeval curtime; -extern Process * unknownproc; + +extern Process * unknowntcp; +extern Process * unknownudp; +extern Process * unknownip; class Line { @@ -74,6 +77,7 @@ void Line::show (int row) { assert (m_uid >= 0); assert (m_pid >= 0); + assert (m_pid <= 100000); } if (DEBUG || tracemode) @@ -86,7 +90,17 @@ void Line::show (int row) char * username = uid2username(m_uid); mvprintw (3+row, 6, "%s", username); free (username); - mvprintw (3+row, 6 + 9, "%s", m_name); + if (strlen (m_name) > PROGNAME_WIDTH) { + // truncate oversized names + char * tmp = strdup(m_name); + char * start = tmp + strlen (m_name) - PROGNAME_WIDTH; + start[0] = '.'; + start[1] = '.'; + mvprintw (3+row, 6 + 9, "%s", start); + free (tmp); + } else { + 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); @@ -193,10 +207,12 @@ void do_refresh() assert (curproc->getVal() != NULL); assert (nproc == processes->size()); } - /* do not remove the unknown process */ - if ((curproc->getVal()->getLastPacket() + PROCESSTIMEOUT <= curtime.tv_sec) && (curproc->getVal() != unknownproc)) + /* remove timed-out processes (unless it's the unknown process) */ + if ((curproc->getVal()->getLastPacket() + PROCESSTIMEOUT <= curtime.tv_sec) + && (curproc->getVal() != unknowntcp) + && (curproc->getVal() != unknownudp) + && (curproc->getVal() != unknownip)) { - /* remove process */ if (DEBUG) std::cout << "PROC: Deleting process\n"; ProcList * todelete = curproc; @@ -220,8 +236,8 @@ void do_refresh() u_int32_t sum_sent = 0, sum_recv = 0; - /* walk though all this process's connections, and sum them - * up */ + /* walk though all this process's connections, and sum + * them up */ ConnList * curconn = curproc->getVal()->connections; ConnList * previous = NULL; while (curconn != NULL) @@ -286,7 +302,7 @@ void do_refresh() } if (tracemode || DEBUG) { /* print the 'unknown' connections, for debugging */ - ConnList * curr_unknownconn = unknownproc->connections; + ConnList * curr_unknownconn = unknowntcp->connections; while (curr_unknownconn != NULL) { std::cout << "Unknown connection: " << curr_unknownconn->getVal()->refpacket->gethashstring() << std::endl; diff --git a/inode2prog.cpp b/inode2prog.cpp index 148a6ec..8873781 100644 --- a/inode2prog.cpp +++ b/inode2prog.cpp @@ -68,12 +68,16 @@ char * getprogname (char * pid) { if (length < bufsize - 1) buffer[length]='\0'; - char * retval; + char * retval = buffer; + /* this removed directory names, but that malfunctions + * when the program name is like "sshd: arnouten@pts/8" if ((retval = strrchr(buffer, '/'))) retval++; else retval = buffer; + */ + // truncating is now done where it should be, in cui.cpp return strdup(retval); } @@ -105,12 +109,16 @@ void get_info_by_linkname (char * pid, char * linkname) { } } +/* updates the `inodeproc' inode-to-prg_node + * for all inodes belonging to this PID + * (/proc/pid/fd/*) + * */ void get_info_for_pid(char * pid) { size_t dirlen = 10 + strlen(pid); char * dirname = (char *) malloc (dirlen * sizeof(char)); snprintf(dirname, dirlen, "/proc/%s/fd", pid); - //std::cout << "Entering directory " << dirname << std::endl; + //std::cout << "Getting info for pid " << pid << std::endl; DIR * dir = opendir(dirname); @@ -153,11 +161,13 @@ void get_info_for_pid(char * pid) { free (dirname); } +/* updates the `inodeproc' inode-to-prg_node mapping + * for all processes in /proc */ void reread_mapping () { DIR * proc = opendir ("/proc"); if (proc == 0) { - std::cerr << "Error getting inode-to-pid mapping\n"; + std::cerr << "Error reading /proc, neede to get inode-to-pid-maping\n"; exit(1); } diff --git a/nethogs.cpp b/nethogs.cpp index 17c1271..a033f75 100644 --- a/nethogs.cpp +++ b/nethogs.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "cui.h" @@ -26,6 +27,8 @@ extern "C" { #include "process.h" #include "refresh.h" +extern Process * unknownudp; + unsigned refreshdelay = 1; bool tracemode = false; bool needrefresh = true; @@ -124,6 +127,51 @@ int process_tcp (u_char * userdata, const dp_header * header, const u_char * m_p return true; } +int process_udp (u_char * userdata, const dp_header * header, const u_char * m_packet) { + struct dpargs * args = (struct dpargs *) userdata; + //struct tcphdr * tcp = (struct tcphdr *) m_packet; + struct udphdr * udp = (struct udphdr *) m_packet; + + curtime = header->ts; + + /* TODO get info from userdata, then call getPacket */ + Packet * packet; + switch (args->sa_family) + { + case (AF_INET): + packet = new Packet (args->ip_src, ntohs(udp->source), args->ip_dst, ntohs(udp->dest), header->len, header->ts); + break; + case (AF_INET6): + packet = new Packet (args->ip6_src, ntohs(udp->source), args->ip6_dst, ntohs(udp->dest), header->len, header->ts); + break; + } + + //if (DEBUG) + // std::cout << "Got packet from " << packet->gethashstring() << std::endl; + + Connection * connection = findConnection(packet); + + if (connection != NULL) + { + /* add packet to the connection */ + connection->add(packet); + } else { + /* else: unknown connection, create new */ + connection = new Connection (packet); + getProcess(connection, currentdevice); + } + delete packet; + + if (needrefresh) + { + do_refresh(); + needrefresh = false; + } + + /* we're done now. */ + return true; +} + int process_ip (u_char * userdata, const dp_header * header, const u_char * m_packet) { struct dpargs * args = (struct dpargs *) userdata; struct ip * ip = (struct ip *) m_packet; @@ -275,6 +323,7 @@ int main (int argc, char** argv) dp_addcb (newhandle, dp_packet_ip, process_ip); dp_addcb (newhandle, dp_packet_ip6, process_ip6); dp_addcb (newhandle, dp_packet_tcp, process_tcp); + dp_addcb (newhandle, dp_packet_tcp, process_udp); if (newhandle != NULL) { /* The following code solves sf.net bug 1019381, but is only available diff --git a/nethogs.h b/nethogs.h index 84bdabf..1505884 100644 --- a/nethogs.h +++ b/nethogs.h @@ -36,7 +36,9 @@ // assertions. good for finding bugs // at an early stage of development. // for production, should be 1. -#define ROBUST 1 +#define ROBUST 0 + +#define REVERSEHACK 0 // 2 times: 32 characters, 7 ':''s, a ':12345'. // 1 '-' @@ -88,8 +90,8 @@ public: address[37] = m_address[30]; address[38] = m_address[31]; address[39] = 0; string = strdup(address); - if (DEBUG) - std::cout << "Converting address " << address << std::endl; + //if (DEBUG) + // std::cout << "Converting address " << address << std::endl; int result = inet_pton (AF_INET6, address, &addr6); diff --git a/process.cpp b/process.cpp index c2e60c6..5bf0611 100644 --- a/process.cpp +++ b/process.cpp @@ -31,16 +31,31 @@ extern local_addr * local_addrs; std::map conninode; /* - * Initialise the global process-list with `the' unknown process + * Initialise the global process-list with some special processes: + * * unknown TCP traffic + * * UDP traffic + * * unknown IP traffic * We must take care this one never gets removed from the list. */ -Process * unknownproc; +Process * unknowntcp; +Process * unknownudp; +Process * unknownip; ProcList * processes; +/* We're migrating to having several `unknown' processes that are added as + * normal processes, instead of hard-wired unknown processes. + * This mapping maps from unknown processes descriptions to processes */ +std::map unknownprocs; + + void process_init () { - unknownproc = new Process (0, "", "unknown"); - processes = new ProcList (unknownproc, NULL); + unknowntcp = new Process (0, "", "unknown TCP"); + //unknownudp = new Process (0, "", "unknown UDP"); + //unknownip = new Process (0, "", "unknown IP"); + processes = new ProcList (unknowntcp, NULL); + //processes = new ProcList (unknownudp, processes); + //processes = new ProcList (unknownip, processes); } int Process::getLastPacket() @@ -226,7 +241,7 @@ Process * findProcess (unsigned long inode) * connections are now known */ void reviewUnknown () { - ConnList * curr_conn = unknownproc->connections; + ConnList * curr_conn = unknowntcp->connections; ConnList * previous_conn = NULL; while (curr_conn != NULL) { @@ -234,12 +249,13 @@ void reviewUnknown () if (inode != 0) { Process * proc = findProcess (inode); - if (proc != unknownproc && proc != NULL) + if (proc != unknowntcp && proc != NULL) { if (DEBUG) std::cout << "ITP: WARNING: Previously unknown inode " << inode << " now got process...??\n"; - /* Yay! - but how could this happen? */ - //assert(false); + /* Yay! - but how can this happen? */ + if (!ROBUST) + assert(false); if (previous_conn != NULL) { previous_conn->setNext (curr_conn->getNext()); @@ -249,10 +265,10 @@ void reviewUnknown () } else { - unknownproc->connections = curr_conn->getNext(); + unknowntcp->connections = curr_conn->getNext(); proc->connections = new ConnList (curr_conn->getVal(), proc->connections); delete curr_conn; - curr_conn = unknownproc->connections; + curr_conn = unknowntcp->connections; } } } @@ -275,7 +291,8 @@ void refreshconninode () } addprocinfo ("/proc/net/tcp6"); - reviewUnknown(); + if (DEBUG) + reviewUnknown(); } @@ -309,7 +326,11 @@ Process * getProcess (unsigned long inode, char * devicename) struct prg_node * node = findPID(inode); if (node == NULL) - return unknownproc; + { + if (DEBUG) + std::cout << "No PID information for inode " << inode << std::endl; + return unknowntcp; + } Process * proc = findProcess (node); @@ -370,6 +391,7 @@ Process * getProcess (Connection * connection, char * devicename) #endif refreshconninode(); inode = conninode[connection->refpacket->gethashstring()]; +#if REVERSEHACK if (inode == 0) { /* HACK: the following is a hack for cases where the @@ -378,7 +400,6 @@ Process * getProcess (Connection * connection, char * devicename) /* we reverse the direction of the stream if * successful. */ - Packet * reversepacket = connection->refpacket->newInverted(); inode = conninode[reversepacket->gethashstring()]; @@ -387,16 +408,26 @@ Process * getProcess (Connection * connection, char * devicename) delete reversepacket; if (DEBUG) std::cout << "LOC: " << connection->refpacket->gethashstring() << " STILL not in connection-to-inode table - adding to the unknown process\n"; - unknownproc->connections = new ConnList (connection, unknownproc->connections); - return unknownproc; + unknowntcp->connections = new ConnList (connection, unknowntcp->connections); + return unknowntcp; } delete connection->refpacket; connection->refpacket = reversepacket; } +#endif + } + + Process * proc; + if (inode == 0) { + proc = new Process (0, "", connection->refpacket->gethashstring()); + processes = new ProcList (proc, processes); + } + else + { + proc = getProcess(inode, devicename); } - Process * proc = getProcess(inode, devicename); proc->connections = new ConnList (connection, proc->connections); return proc; }