From be624683f0aa27c222b20657ed3030c1ade059e3 Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Tue, 29 Jun 2004 13:31:04 +0000 Subject: [PATCH] Initial import. --- INSTALL | 7 + Makefile | 48 +++++ connection.cpp | 131 ++++++++++++++ connection.h | 86 +++++++++ hashtbl.cpp | 90 ++++++++++ hashtbl.h | 30 ++++ hashtest | Bin 0 -> 29028 bytes hashtest.cpp | 11 ++ inet6.c | 169 ++++++++++++++++++ inodeproc.cpp | 226 ++++++++++++++++++++++++ nethogs.8 | 27 +++ nethogs.cpp | 175 +++++++++++++++++++ nethogs.h | 28 +++ packet.cpp | 178 +++++++++++++++++++ packet.h | 45 +++++ process.cpp | 463 +++++++++++++++++++++++++++++++++++++++++++++++++ process.h | 72 ++++++++ refresh.cpp | 17 ++ refresh.h | 1 + structs.cpp | 0 structs.h | 0 21 files changed, 1804 insertions(+) create mode 100644 INSTALL create mode 100644 Makefile create mode 100644 connection.cpp create mode 100644 connection.h create mode 100644 hashtbl.cpp create mode 100644 hashtbl.h create mode 100755 hashtest create mode 100644 hashtest.cpp create mode 100644 inet6.c create mode 100644 inodeproc.cpp create mode 100644 nethogs.8 create mode 100644 nethogs.cpp create mode 100644 nethogs.h create mode 100644 packet.cpp create mode 100644 packet.h create mode 100644 process.cpp create mode 100644 process.h create mode 100644 refresh.cpp create mode 100644 refresh.h create mode 100644 structs.cpp create mode 100644 structs.h diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..fb540a3 --- /dev/null +++ b/INSTALL @@ -0,0 +1,7 @@ +make ; make install + +you need the 'libpcap-dev' and 'libpcap' packages. + +let me know if you have any other problems on nethogs@bzzt.net + + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..93c8acf --- /dev/null +++ b/Makefile @@ -0,0 +1,48 @@ +VERSION := 0 +SUBVERSION := 6 +MINORVERSION := pre + +bin := /usr/local/bin +man8 := /usr/local/man/man8/ + +all: nethogs + +CFLAGS=-g +OBJS=structs.o packet.o connection.o process.o hashtbl.o refresh.o +GCC=g++ + +.PHONY tgz + +tgz: clean + cd .. ; tar czvf nethogs-$(VERSION).$(SUBVERSION).$(MINORVERSION).tar.gz nethogs-$(VERSION).$(SUBVERSION)/* + +.PHONY check +check: + echo "Not implemented" + +install: nethogs nethogs.8 + cp nethogs $(bin) + cp nethogs.8 $(man8) + +nethogs: nethogs.cpp $(OBJS) + $(GCC) $(CFLAGS) nethogs.cpp $(OBJS) -o nethogs -lpcap -lncurses -DVERSION=\"$(VERSION)\" -DSUBVERSION=\"$(SUBVERSION)\" -DMINORVERSION=\"$(MINORVERSION)\" + +#-lefence + +refresh.o: refresh.cpp refresh.h nethogs.h + $(GCC) $(CFLAGS) -c refresh.cpp +structs.o: structs.cpp structs.h nethogs.h + $(GCC) $(CFLAGS) -c structs.cpp +process.o: process.cpp process.h inodeproc.cpp nethogs.h + $(GCC) $(CFLAGS) -c process.cpp +packet.o: packet.cpp packet.h nethogs.h + $(GCC) $(CFLAGS) -c packet.cpp +connection.o: connection.cpp connection.h nethogs.h + $(GCC) $(CFLAGS) -c connection.cpp +hashtbl.o: hashtbl.cpp hashtbl.h nethogs.h + $(GCC) $(CFLAGS) -c hashtbl.cpp + +.PHONY clean +clean: + rm -f $(OBJS) + rm -f nethogs diff --git a/connection.cpp b/connection.cpp new file mode 100644 index 0000000..582938d --- /dev/null +++ b/connection.cpp @@ -0,0 +1,131 @@ +#include +#include +#include +#include "nethogs.h" +#include "connection.h" + +class ConnList +{ +public: + ConnList (Connection * m_val = NULL, ConnList * m_next = NULL) + { + val = m_val; next = m_next; + } + Connection * val; + ConnList * next; +}; + +ConnList * connections = NULL; + +void PackList::add (Packet * p) +{ + if (content == NULL) + { + content = new PackListNode (p); + return; + } + + if (content->val->time.tv_sec == p->time.tv_sec) + { + content->val->len += p->len; + return; + } + + content = new PackListNode(p, content); +} + +/* sums up the total bytes used and removes 'old' packets */ +bpf_u_int32 PackList::sumanddel (timeval t) +{ + bpf_u_int32 retval = 0; + PackListNode * current = content; + PackListNode * previous = NULL; + + while (current != NULL) + { + if (current->val->isOlderThan(t)) + { + if (current == content) + content = NULL; + else if (previous != NULL) + previous->next = NULL; + delete current; + return retval; + } + retval += current->val->len; + previous = current; + current = current->next; + } + return retval; +} + +Connection::Connection (Packet * packet) +{ + if (DEBUG) + assert (packet != NULL); + connections = new ConnList (this, connections); + sent_packets = new PackList (); + recv_packets = new PackList (); + if (packet->Outgoing()) + { + sent_packets->add(packet); + } else { + recv_packets->add(packet); + } + refpacket = packet->newPacket (); + lastpacket = packet->time.tv_sec; + if (DEBUG) + std::cout << "New reference packet created at " << refpacket << std::endl; +} + +Connection::~Connection () +{ + if (DEBUG) + std::cout << "Deleting connection" << std::endl; + delete refpacket; + if (sent_packets != NULL) + delete sent_packets; + if (recv_packets != NULL) + delete recv_packets; +} + +void Connection::add (Packet * packet) +{ + lastpacket = packet->time.tv_sec; + if (packet->Outgoing()) + { + sent_packets->add (packet); + } else { + recv_packets->add (packet); + } +} + +Connection * findConnection (Packet * packet) +{ + ConnList * current = connections; + while (current != NULL) + { + if (packet->match(current->val->refpacket)) + return current->val; + + current = current->next; + } + return NULL; +} + +/* + * Connection::sumanddel + * + * sums up the total bytes used + * and removes 'old' packets. + * + * Returns sum of sent packages (by address) + * sum of recieved packages (by address) + */ +void Connection::sumanddel (timeval t, bpf_u_int32 * sent, bpf_u_int32 * recv) +{ + (*sent)=(*recv)=0; + + *sent = sent_packets->sumanddel(t); + *recv = recv_packets->sumanddel(t); +} diff --git a/connection.h b/connection.h new file mode 100644 index 0000000..2333ed4 --- /dev/null +++ b/connection.h @@ -0,0 +1,86 @@ +#ifndef __CONNECTION_H +#define __CONNECTION_H + +#include +#include "packet.h" + +class PackListNode +{ +public: + PackListNode (Packet * m_val, PackListNode * m_next = NULL) + { + val = m_val; + next = m_next; + } + ~PackListNode () + { + delete val; + if (next != NULL) + delete next; + } + PackListNode * next; + Packet * val; +}; + +class PackList +{ +public: + PackList () + { + content = NULL; + } + PackList (Packet * m_val) + { + if (DEBUG) + assert (m_val != NULL); + content = new PackListNode(m_val); + } + ~PackList () + { + if (content != NULL) + delete content; + } + + /* sums up the total bytes used and removes 'old' packets */ + bpf_u_int32 sumanddel (timeval t); + + void add (Packet * p); +private: + PackListNode * content; +}; + +class Connection +{ +public: + /* constructs a connection, makes a copy of + * the packet as 'refpacket', and adds the + * packet to the packlist */ + Connection (Packet * packet); + + ~Connection(); + + /* add a packet to the packlist + * will delete the packet when it is + * 'merged' with another packet + */ + void add (Packet * packet); + + int getLastPacket () + { return lastpacket; } + + /* sums up the total bytes used + * and removes 'old' packets. */ + void sumanddel(timeval curtime, bpf_u_int32 * sent, bpf_u_int32 * recv); + + /* for checking if a packet is part of this connection */ + Packet * refpacket; +private: + PackList * sent_packets; + PackList * recv_packets; + int lastpacket; +}; + +/* Find the connection this packet belongs to */ +Connection * findConnection (Packet * packet); + +#endif diff --git a/hashtbl.cpp b/hashtbl.cpp new file mode 100644 index 0000000..a5222fc --- /dev/null +++ b/hashtbl.cpp @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include "hashtbl.h" + +HashNode::~HashNode () +{ + free (key); + //delete (content); + if (next) + delete (next); +} + +HashTable::HashTable(int n_size) +{ + // size = n_size; + // TODO allow for variable size + size = n_size; + table = (HashNode **) malloc (size * sizeof(HashNode *)); + for (unsigned int i=0; i> krightmove; + retval = retval << kleftmove; + retval ^= carry; + retval ^= str[i]; + } + return retval % size; +} + +HashNode * HashTable::newHashNode(char * key, void * content, HashNode * next) +{ + HashNode * retval = new HashNode (); + retval->key = key; + retval->content = content; + retval->next = next; + return retval; +} + + +void HashTable::add(char * key, void * content) +{ + unsigned int hkey = HashString (key); + //cout << "Adding node: " << key << " key " << hkey << endl; + table[hkey] = newHashNode(key, content, table[hkey]); +} + +void * HashTable::get(char * key) +{ + HashNode * current_node = table[HashString (key)]; + //cout << "looking for node " << HashString (key) << endl; + while (current_node != NULL) + { + //cout << "found node, key = " << current_node->key << endl; + if (strcmp(current_node->key, key) == 0) + { + return current_node->content; + } + current_node = current_node->next; + } + return NULL; +} diff --git a/hashtbl.h b/hashtbl.h new file mode 100644 index 0000000..a0ab12b --- /dev/null +++ b/hashtbl.h @@ -0,0 +1,30 @@ +#include +#include + +class HashNode +{ +public: + ~HashNode(); + + char * key; + void * content; + HashNode * next; +}; + +class HashTable +{ +public: + HashTable(int n_size); + ~HashTable(); + void add(char * key, void * content); + void * get(char * key); + +private: + int size; + HashNode ** table; + + HashNode * newHashNode(char * key, void * content, HashNode * next); + unsigned int HashString(const char * str); + + HashTable(); // We leave this unimplemented ;) +}; diff --git a/hashtest b/hashtest new file mode 100755 index 0000000000000000000000000000000000000000..0a4a7fa7970e78919da67c5627e72b01ea328b58 GIT binary patch literal 29028 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 +#include "hashtbl.h" + +void main () +{ + HashTable * table = new HashTable (10); + table->add("Foo", (void*)"Bar"); + table->add("Baz", (void*)"Qux"); + cout << "Foo is " << (char*)(table->get("Foo")) << endl; +} + diff --git a/inet6.c b/inet6.c new file mode 100644 index 0000000..306f65d --- /dev/null +++ b/inet6.c @@ -0,0 +1,169 @@ +/* + * lib/inet6.c This file contains an implementation of the "INET6" + * support functions for the net-tools. + * (most of it copied from lib/inet.c 1.26). + * + * Version: $Id$ + * + * Author: Fred N. van Kempen, + * Copyright 1993 MicroWalt Corporation + * + * Modified: + *960808 {0.01} Frank Strauss : adapted for IPv6 support + *980701 {0.02} Arnaldo C. Melo: GNU gettext instead of catgets + *990824 Bernd Eckenfels: clear members for selecting v6 address + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* +#include "version.h" +#include "net-support.h" +#include "pathnames.h" +#include "intl.h" +#include "util.h" +*/ + +extern int h_errno; /* some netdb.h versions don't export this */ + +static int INET6_resolve(char *name, struct sockaddr_in6 *sin6) +{ + struct addrinfo req, *ai; + int s; + + memset (&req, '\0', sizeof req); + req.ai_family = AF_INET6; + if ((s = getaddrinfo(name, NULL, &req, &ai))) { + fprintf(stderr, "getaddrinfo: %s: %d\n", name, s); + return -1; + } + memcpy(sin6, ai->ai_addr, sizeof(struct sockaddr_in6)); + + freeaddrinfo(ai); + + return (0); +} + +#ifndef IN6_IS_ADDR_UNSPECIFIED +#define IN6_IS_ADDR_UNSPECIFIED(a) \ + (((__u32 *) (a))[0] == 0 && ((__u32 *) (a))[1] == 0 && \ + ((__u32 *) (a))[2] == 0 && ((__u32 *) (a))[3] == 0) +#endif + + +static int INET6_rresolve(char *name, struct sockaddr_in6 *sin6, int numeric) +{ + int s; + + /* Grmpf. -FvK */ + if (sin6->sin6_family != AF_INET6) { +#ifdef DEBUG + fprintf(stderr, "rresolve: unsupport address family %d !\n", + sin6->sin6_family); +#endif + errno = EAFNOSUPPORT; + return (-1); + } + if (numeric & 0x7FFF) { + inet_ntop(AF_INET6, &sin6->sin6_addr, name, 80); + return (0); + } + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + if (numeric & 0x8000) + strcpy(name, "default"); + else + strcpy(name, "*"); + return (0); + } + + if ((s = getnameinfo((struct sockaddr *) sin6, sizeof(struct sockaddr_in6), + name, 255 /* !! */ , NULL, 0, 0))) { + fputs("getnameinfo failed\n", stderr); + return -1; + } + return (0); +} + + +static void INET6_reserror(char *text) +{ + herror(text); +} + + +/* Display an Internet socket address. */ +static char *INET6_print(unsigned char *ptr) +{ + static char name[80]; + + inet_ntop(AF_INET6, (struct in6_addr *) ptr, name, 80); + return name; +} + + +/* Display an Internet socket address. */ +/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */ +static char *INET6_sprint(struct sockaddr *sap, int numeric) +{ + static char buff[128]; + + if (sap->sa_family == 0xFFFF || sap->sa_family == 0) + return safe_strncpy(buff, "[NONE SET]", sizeof(buff)); + if (INET6_rresolve(buff, (struct sockaddr_in6 *) sap, numeric) != 0) + return safe_strncpy(buff, "[UNKNOWN]", sizeof(buff)); + return (buff); +} + + +static int INET6_getsock(char *bufp, struct sockaddr *sap) +{ + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *) sap; + sin6->sin6_family = AF_INET6; + sin6->sin6_port = 0; + + if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0) + return (-1); + + return 16; /* ?;) */ +} + +static int INET6_input(int type, char *bufp, struct sockaddr *sap) +{ + switch (type) { + case 1: + return (INET6_getsock(bufp, sap)); + default: + return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap)); + } +} + + +struct aftype inet6_aftype = +{ + "inet6", NULL, /*"IPv6", */ AF_INET6, sizeof(struct in6_addr), + INET6_print, INET6_sprint, INET6_input, INET6_reserror, + INET6_rprint, INET6_rinput, NULL, + + -1, + "/proc/net/if_inet6" +}; diff --git a/inodeproc.cpp b/inodeproc.cpp new file mode 100644 index 0000000..898494d --- /dev/null +++ b/inodeproc.cpp @@ -0,0 +1,226 @@ +/* this comes from netstat.c, but is very useful :)) */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct proginfo +{ + int pid; + char* name; +}; + +#define PATH_PROC "/proc" +#define PATH_FD_SUFF "fd" +#define PATH_PROC_X_FD PATH_PROC "/%s/" PATH_FD_SUFF +#define PATH_FD_SUFFl strlen(PATH_FD_SUFF) +#define PRG_SOCKET_PFX "socket:[" +#define PRG_SOCKET_PFXl (strlen(PRG_SOCKET_PFX)) +#define PRG_SOCKET_PFX2 "[0000]:" +#define PRG_SOCKET_PFX2l (strlen(PRG_SOCKET_PFX2)) +#define PATH_CMDLINE "cmdline" +#define PATH_CMDLINEl strlen(PATH_CMDLINE) +#define PRG_HASH_SIZE 211 +#define PRG_HASHIT(x) ((x) % PRG_HASH_SIZE) + +static struct prg_node { + struct prg_node *next; + int inode; + int pid; + char name[PROGNAME_WIDTH]; +} *prg_hash[PRG_HASH_SIZE]; + +static char prg_cache_loaded = 0; + +static void prg_cache_clear(void) +{ + struct prg_node **pnp,*pn; + + if (prg_cache_loaded == 2) + for (pnp=prg_hash;pnpnext; + free(pn); + } + prg_cache_loaded=0; +} + +static prg_node * prg_cache_get(int inode) +{ + unsigned hi=PRG_HASHIT(inode); + struct prg_node *pn; + + for (pn=prg_hash[hi];pn;pn=pn->next) + if (pn->inode==inode) return(pn); + + return(NULL); +} + +static void prg_cache_add(int inode, char *name, int pid) +{ + unsigned hi = PRG_HASHIT(inode); + struct prg_node **pnp,*pn; + + prg_cache_loaded=2; + for (pnp=prg_hash+hi;(pn=*pnp);pnp=&pn->next) { + if (pn->inode==inode) { + /* Some warning should be appropriate here + as we got multiple processes for one i-node */ + return; + } + } + if (!(*pnp=(prg_node*)malloc(sizeof(**pnp)))) + return; + pn=*pnp; + pn->next=NULL; + pn->inode=inode; + pn->pid=pid; + if (strlen(name)>sizeof(pn->name)-1) + name[sizeof(pn->name)-1]='\0'; + strcpy(pn->name,name); +} + +static void extract_type_1_socket_inode(const char lname[], long * inode_p) { + /* If lname is of the form "socket:[12345]", extract the "12345" + as *inode_p. Otherwise, return -1 as *inode_p. + */ + + if (strlen(lname) < PRG_SOCKET_PFXl+3) *inode_p = -1; + else if (memcmp(lname, PRG_SOCKET_PFX, PRG_SOCKET_PFXl)) *inode_p = -1; + else if (lname[strlen(lname)-1] != ']') *inode_p = -1; + else { + char inode_str[strlen(lname + 1)]; /* e.g. "12345" */ + const int inode_str_len = strlen(lname) - PRG_SOCKET_PFXl - 1; + char *serr; + + strncpy(inode_str, lname+PRG_SOCKET_PFXl, inode_str_len); + inode_str[inode_str_len] = '\0'; + *inode_p = strtol(inode_str,&serr,0); + if (!serr || *serr || *inode_p < 0 || *inode_p >= INT_MAX) + *inode_p = -1; + } +} + +static void extract_type_2_socket_inode(const char lname[], long * inode_p) { + /* If lname is of the form "[0000]:12345", extract the "12345" + as *inode_p. Otherwise, return -1 as *inode_p. + */ + + if (strlen(lname) < PRG_SOCKET_PFX2l+1) *inode_p = -1; + else if (memcmp(lname, PRG_SOCKET_PFX2, PRG_SOCKET_PFX2l)) *inode_p = -1; + else { + char *serr; + + *inode_p=strtol(lname + PRG_SOCKET_PFX2l,&serr,0); + if (!serr || *serr || *inode_p < 0 || *inode_p >= INT_MAX) + *inode_p = -1; + } +} + + +static void prg_cache_load(void) +{ + char line[LINE_MAX],eacces=0; + int procfdlen,fd,cmdllen,lnamelen; + char lname[30],cmdlbuf[512],finbuf[PROGNAME_WIDTH]; + long inode; + const char *cs,*cmdlp; + DIR *dirproc=NULL,*dirfd=NULL; + struct dirent *direproc,*direfd; + + if (prg_cache_loaded) return; + prg_cache_loaded=1; + cmdlbuf[sizeof(cmdlbuf)-1]='\0'; + if (!(dirproc=opendir(PATH_PROC))) goto fail; + while (errno=0,direproc=readdir(dirproc)) { +#ifdef DIRENT_HAVE_D_TYPE_WORKS + if (direproc->d_type!=DT_DIR) continue; +#endif + for (cs=direproc->d_name;*cs;cs++) + if (!isdigit(*cs)) + break; + if (*cs) + continue; + procfdlen=snprintf(line,sizeof(line),PATH_PROC_X_FD,direproc->d_name); + if (procfdlen<=0 || procfdlen>=sizeof(line)-5) + continue; + errno=0; + dirfd=opendir(line); + if (! dirfd) { + if (errno==EACCES) + eacces=1; + continue; + } + line[procfdlen] = '/'; + cmdlp = NULL; + while ((direfd = readdir(dirfd))) { +#ifdef DIRENT_HAVE_D_TYPE_WORKS + if (direfd->d_type!=DT_LNK) + continue; +#endif + if (procfdlen+1+strlen(direfd->d_name)+1>sizeof(line)) + continue; + memcpy(line + procfdlen - PATH_FD_SUFFl, PATH_FD_SUFF "/", + PATH_FD_SUFFl+1); + strcpy(line + procfdlen + 1, direfd->d_name); + lnamelen=readlink(line,lname,sizeof(lname)-1); + lname[lnamelen] = '\0'; /*make it a null-terminated string*/ + + extract_type_1_socket_inode(lname, &inode); + + if (inode < 0) extract_type_2_socket_inode(lname, &inode); + + if (inode < 0) continue; + + if (!cmdlp) { + if (procfdlen - PATH_FD_SUFFl + PATH_CMDLINEl >= + sizeof(line) - 5) + continue; + strcpy(line + procfdlen-PATH_FD_SUFFl, PATH_CMDLINE); + fd = open(line, O_RDONLY); + if (fd < 0) + continue; + cmdllen = read(fd, cmdlbuf, sizeof(cmdlbuf) - 1); + if (close(fd)) + continue; + if (cmdllen == -1) + continue; + if (cmdllen < sizeof(cmdlbuf) - 1) + cmdlbuf[cmdllen]='\0'; + if ((cmdlp = strrchr(cmdlbuf, '/'))) + cmdlp++; + else + cmdlp = cmdlbuf; + } + + //snprintf(finbuf, sizeof(finbuf), "%s/%s", direproc->d_name, cmdlp); + snprintf(finbuf, sizeof(finbuf), "%s", cmdlp); + int pid; + sscanf(direproc->d_name, "%d", &pid); + prg_cache_add(inode, finbuf, pid); + } + closedir(dirfd); + dirfd = NULL; + } + if (dirproc) + closedir(dirproc); + if (dirfd) + closedir(dirfd); + if (!eacces) + return; + if (prg_cache_loaded == 1) { + fail: + fprintf(stderr,"(No info could be read for \"-p\": geteuid()=%d but you should be root.)\n", + geteuid()); + } + else + fprintf(stderr, "(Not all processes could be identified, non-owned process info\n" + " will not be shown, you would have to be root to see it all.)\n"); +} + diff --git a/nethogs.8 b/nethogs.8 new file mode 100644 index 0000000..66a9eb5 --- /dev/null +++ b/nethogs.8 @@ -0,0 +1,27 @@ +.\" This page Copyright (C) 2004 Fabian Frederick +.\" Content based on Nethogs homepage by Arnout Engelen +.TH NETHOGS 8 "14 February 2004" +.SH NAME +nethogs +.SH SYNOPSIS +.ft B +.B nethogs +.RB [ "\-h" ] +.RB [ "\-d" ] +.RI [device ] +.SH DESCRIPTION +NetHogs is a small 'net top' tool. Instead of breaking the traffic down per protocol or per subnet, like most such tools do, it groups bandwidth by process - and does not rely on a special kernel module to be loaded. So if there's suddenly a lot of network traffic, you can fire up NetHogs and immediately see which PID is causing this, and if it's some kind of spinning process, kill it. + +.SS Options +The \fB-h\fP switch display available commands usage +.PP +The \fB-d\fP delay for refresh rate +.PP +.I device +by default eth0 is being used + +.SH "SEE ALSO" +.I netstat(8) tcpdump(1) pcap(3) +.SH AUTHOR +.nf +Written by Arnout Engelen . diff --git a/nethogs.cpp b/nethogs.cpp new file mode 100644 index 0000000..1e68c5f --- /dev/null +++ b/nethogs.cpp @@ -0,0 +1,175 @@ +/* nethogs.cpp + * + * Updates: + * + * 14/02/04 (Fabian) + * -Refresh delay + * -Help + * -Handling command-line options + * + * 06/04/04 (Fabian) + * -getLocal + * -I/O by balance + * -forceExit + * + * 10/05/04 (Arnout) + * -cleanups + * -splitting out incoming and outgoing traffic + * (based on 'I/O by balance' by Fabian) + */ + +#include "nethogs.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern "C" { + #include +} + +#include "packet.h" +#include "connection.h" +#include "process.h" +#include "refresh.h" + +bool needrefresh = false; +unsigned refreshdelay = 1; + +const char version[] = " version " VERSION "." SUBVERSION "." MINORVERSION; + +timeval curtime; +std::string * caption; + + + +void process (u_char * args, const struct pcap_pkthdr * header, const u_char * m_packet) +{ + curtime = header->ts; + + Packet * packet = getPacket (header, m_packet); + if (packet == NULL) + return; + + Connection * connection = findConnection(packet); + if (connection != NULL) + { + connection->add(packet); + return; + } + connection = new Connection (packet); + Process * process = getProcess(connection); + //process->addConnection (connection); + + if (needrefresh) + { + do_refresh(); + needrefresh = false; + } + + return; +} + +void quit_cb (int i) +{ + procclean(); + clear(); + endwin(); + exit(0); +} + +void forceExit(const char *msg) +{ + clear(); + endwin(); + std::cerr << msg << std::endl; + exit(0); +} + +static void versiondisplay(void) +{ + + std::cerr << version << "\n"; +} + +static void help(void) +{ + std::cerr << "usage: nethogs [-V] [-d] [device]\n"; + std::cerr << " -V : prints version.\n"; + std::cerr << " -d : delay for update refresh rate in seconds. default is 1.\n"; + std::cerr << " device : device to monitor. default is eth0\n"; +} + +int main (int argc, char** argv) +{ + char* dev = strdup("eth0"); + + for (argv++; *argv; argv++) + { + if (**argv=='-') + { + (*argv)++; + switch(**argv) + { + case 'V': versiondisplay(); + exit(0); + case 'h': help(); + exit(0); + case 'd': if (argv[1]) + { + argv++; + refreshdelay=atoi(*argv); + } + break; + default : help(); + exit(0); + } + } + else + { + dev = strdup(*argv); + } + } +#if DEBUG +#else + initscr(); + raw(); + noecho(); + cbreak(); +#endif + getLocal(dev); + + caption = new std::string ("NetHogs"); + caption->append(version); + caption->append(", running at "); + caption->append(dev); + + if (NEEDROOT && (getuid() != 0)) + forceExit("You need to be root to run NetHogs !"); + + char errbuf[PCAP_ERRBUF_SIZE]; + + pcap_t * handle; + handle = pcap_open_live(dev, BUFSIZ, 0, 1000, errbuf); + + signal (SIGALRM, &alarm_cb); + signal (SIGINT, &quit_cb); + alarm (refreshdelay); + while (1) + { + pcap_dispatch (handle, -1, process, NULL); + if (needrefresh) + { + do_refresh(); + needrefresh = false; + } + } +} + diff --git a/nethogs.h b/nethogs.h new file mode 100644 index 0000000..c955891 --- /dev/null +++ b/nethogs.h @@ -0,0 +1,28 @@ +#ifndef __NETHOGS_H +#define __NETHOGS_H + + +#define _BSD_SOURCE 1 + +/* take the average speed over the last 5 seconds */ +#define PERIOD 5 + +/* the amount of time after the last packet was recieved + * after which a process is removed */ +#define PROCESSTIMEOUT 150 + +/* Set to '0' when compiling for a system that uses Linux Capabilities, + * like www.adamantix.org: in that case nethogs shouldn't check if it's + * running as root. Take care to give it sufficient privileges though. */ +#ifndef NEEDROOT +#define NEEDROOT 1 +#endif + +#define DEBUG 0 + + +#define PROGNAME_WIDTH 30 + +void forceExit(const char *msg); + +#endif diff --git a/packet.cpp b/packet.cpp new file mode 100644 index 0000000..98e86f6 --- /dev/null +++ b/packet.cpp @@ -0,0 +1,178 @@ +#include +#include "packet.h" +#include +#include +#include +#include +#include +#include +#include "nethogs.h" +// #include "inet6.c" + +struct in_addr * local_addr = NULL; + +/* + * getLocal + * device: This should be device explicit (e.g. eth0:1) + * + * ioctl device for address + */ +void getLocal (const char *device) +{ + int sock; + struct ifreq iFreq; + struct sockaddr_in *saddr; + + if (local_addr != NULL) + { + std::cerr << "getLocal only needs to be called once in connection.cpp" << std::endl; + free (local_addr); + } + + local_addr = (struct in_addr *) malloc (sizeof(struct in_addr)); + + if((sock=socket(AF_INET, SOCK_PACKET, htons(0x0806)))<0){ + forceExit("creating socket failed while establishing local IP - are you root?"); + } + strcpy(iFreq.ifr_name, device); + if(ioctl(sock, SIOCGIFADDR, &iFreq)<0){ + forceExit("ioctl failed while establishing local IP"); + } + saddr=(struct sockaddr_in*)&iFreq.ifr_addr; + (*local_addr)=saddr->sin_addr; +} + +typedef u_int32_t tcp_seq; + +/* ethernet header */ +struct ethernet_hdr { + u_char ether_dhost[ETHER_ADDR_LEN]; + u_char ether_shost[ETHER_ADDR_LEN]; + u_short ether_type; /* IP? */ +}; + +/* IP header */ +struct ip_hdr +{ +#if BYTE_ORDER == LITTLE_ENDIAN + u_int ip_hl:4, /* header length */ + ip_v:4; /* version */ +#if BYTE_ORDER == BIG_ENDIAN + u_int ip_v:4, /* version */ + ip_hl:4; /* header length */ +#endif +#endif /* not _IP_VHL */ + u_char ip_tos; /* type of service */ + u_short ip_len; /* total length */ + u_short ip_id; /* identification */ + u_short ip_off; /* fragment offset field */ +#define IP_RF 0x8000 /* reserved fragment flag */ +#define IP_DF 0x4000 /* dont fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + u_char ip_ttl; /* time to live */ + u_char ip_p; /* protocol */ + u_short ip_sum; /* checksum */ + struct in_addr ip_src,ip_dst; /* source and dest address */ +}; + +/* TCP header */ +struct tcp_hdr { + u_short th_sport; /* source port */ + u_short th_dport; /* destination port */ + tcp_seq th_seq; /* sequence number */ + tcp_seq th_ack; /* acknowledgement number */ +#if BYTE_ORDER == LITTLE_ENDIAN + u_int th_x2:4, /* (unused) */ + th_off:4; /* data offset */ +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_int th_off:4, /* data offset */ + th_x2:4; /* (unused) */ +#endif + u_char th_flags; +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PUSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 +#define TH_ECE 0x40 +#define TH_CWR 0x80 +#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR) + u_short th_win; /* window */ + u_short th_sum; /* checksum */ + u_short th_urp; /* urgent pointer */ +}; + +/* Packet 'Constructor' - but returns NULL on failure */ +Packet * getPacket (const struct pcap_pkthdr * header, const u_char * packet) +{ + const struct ethernet_hdr * ethernet = (struct ethernet_hdr *)packet; + if (ethernet->ether_type != 8) + { +#if DEBUG + cerr << "Dropped non-ip packet of type " << ethernet->ether_type << endl; +#endif + return NULL; + } + + const struct ip_hdr * ip = (struct ip_hdr *)(packet + sizeof(ethernet_hdr)); + if (ip->ip_p != 6) + { +#if DEBUG + cerr << "Dropped non-tcp packet of type " << (int)(ip->ip_p) << endl; +#endif + return NULL; + } + + const struct tcp_hdr * tcp = (struct tcp_hdr *)(packet + sizeof(ethernet_hdr) + sizeof(ip_hdr)); + + return new Packet (ip->ip_src, ntohs(tcp->th_sport), ip->ip_dst, ntohs(tcp->th_dport), header->len, header->ts); +} + +Packet::Packet (in_addr m_sip, unsigned short m_sport, in_addr m_dip, unsigned short m_dport, bpf_u_int32 m_len, timeval m_time) +{ + sip = m_sip; sport = m_sport; + dip = m_dip; dport = m_dport; + len = m_len; time = m_time; +} + +Packet * Packet::newPacket () +{ + return new Packet (sip, sport, dip, dport, len, time); +} + +bool sameinaddr(in_addr one, in_addr other) +{ + return one.s_addr == other.s_addr; +} + +bool Packet::isOlderThan (timeval t) { + return (time.tv_sec + PERIOD <= t.tv_sec); +} + +bool Packet::Outgoing () { + /* must be initialised with getLocal("eth0:1");) */ + if (DEBUG) + assert (local_addr != NULL); + + return (sip.s_addr == local_addr->s_addr); +} + +char * Packet::gethashstring () +{ + // TODO this needs to be bigger to support ipv6?! + char * retval = (char *) malloc (92 * sizeof(char)); + snprintf(retval, 92 * sizeof(char), "%s:%d-", inet_ntoa(sip), sport); + snprintf(retval, 92 * sizeof(char), "%s%s:%d", retval, inet_ntoa(dip), dport); + //if (DEBUG) + //cout << "hasshtring: " << retval << endl; + return retval; +} + +bool Packet::match (Packet * other) +{ + return ((sport == other->sport) && (dport == other->dport) + && (sameinaddr(sip, other->sip)) && (sameinaddr(dip, other->dip))); +} diff --git a/packet.h b/packet.h new file mode 100644 index 0000000..eb97e16 --- /dev/null +++ b/packet.h @@ -0,0 +1,45 @@ +#ifndef __PACKET_H +#define __PACKET_H + +#define _BSD_SOURCE 1 +#include + +#include +#include +#include + +extern "C" +{ + #include +} + +/* To initialise this module, call getLocal with the currently + * monitored device (e.g. "eth0:1") */ +void getLocal (const char *device); + +class Packet +{ +public: + in_addr sip; + in_addr dip; + unsigned short sport; + unsigned short dport; + bpf_u_int32 len; + timeval time; + + Packet (in_addr m_sip, unsigned short m_sport, in_addr m_dip, unsigned short m_dport, bpf_u_int32 m_len, timeval m_time); + /* copy constructor */ + Packet * newPacket (); + + bool isOlderThan(timeval t); + /* is this packet coming from here? */ + bool Outgoing (); + + bool match (Packet * other); + /* returns '1.2.3.4:5-1.2.3.4:6'-style string */ + char * gethashstring(); +}; + +Packet * getPacket (const struct pcap_pkthdr * header, const u_char * packet); + +#endif diff --git a/process.cpp b/process.cpp new file mode 100644 index 0000000..c987f3f --- /dev/null +++ b/process.cpp @@ -0,0 +1,463 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "process.h" +#include "hashtbl.h" +#include "nethogs.h" +#include "inodeproc.cpp" +//#include "inet6.c" + +extern timeval curtime; +extern std::string * caption; + +/*struct aftype inet6_aftype = +{ + "inet6", NULL, AF_INET6, sizeof(struct in6_addr), + INET6_print, INET6_sprint, INET6_input, INET6_reserror, + INET6_rprint, INET6_rinput, NULL, + + -1, + "/proc/net/if_inet6" +};*/ + + +static int INET6_getsock(char *bufp, struct sockaddr *sap) +{ + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *) sap; + sin6->sin6_family = AF_INET6; + sin6->sin6_port = 0; + + if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0) + return (-1); + + return 16; /* ?;) */ +} + +static int INET6_input(int type, char *bufp, struct sockaddr *sap) +{ + return (INET6_getsock(bufp, sap)); +} + +struct aftype { + char *name; + char *title; + int af; + int alen; + char *(*print) (unsigned char *); + char *(*sprint) (struct sockaddr *, int numeric); + int (*input) (int type, char *bufp, struct sockaddr *); + void (*herror) (char *text); + int (*rprint) (int options); + int (*rinput) (int typ, int ext, char **argv); + + /* may modify src */ + int (*getmask) (char *src, struct sockaddr * mask, char *name); + + int fd; + char *flag_file; +}; +/* + * connection-inode table. takes information from /proc/net/tcp. + * key contains source ip, source port, destination ip, destination + * port in format: '1.2.3.4:5-1.2.3.4:5' + */ +HashTable * conninode = new HashTable (256); + +// TODO check what happens to the 'content' field of the hash!! +void addtoconninode (char * buffer) +{ + char rem_addr[128], local_addr[128]; + int local_port, rem_port; + struct sockaddr_in6 localaddr, remaddr; + char addr6[INET6_ADDRSTRLEN]; + struct in6_addr in6; + extern struct aftype inet6_aftype; + // the following line leaks memory. + unsigned long * inode = (unsigned long *) malloc (sizeof(unsigned long)); + // TODO check it matched + sscanf(buffer, "%*d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %*X %*lX:%*lX %*X:%*lX %*lX %*d %*d %ld %*512s\n", + local_addr, &local_port, rem_addr, &rem_port, inode); + + if (strlen(local_addr) > 8) + { + /* Demangle what the kernel gives us */ + sscanf(local_addr, "%08X%08X%08X%08X", + &in6.s6_addr32[0], &in6.s6_addr32[1], + &in6.s6_addr32[2], &in6.s6_addr32[3]); + inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); + INET6_getsock(addr6, (struct sockaddr *) &localaddr); + sscanf(rem_addr, "%08X%08X%08X%08X", + &in6.s6_addr32[0], &in6.s6_addr32[1], + &in6.s6_addr32[2], &in6.s6_addr32[3]); + inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); + INET6_getsock(addr6, (struct sockaddr *) &remaddr); + localaddr.sin6_family = AF_INET6; + remaddr.sin6_family = AF_INET6; + } + else + { + sscanf(local_addr, "%X", &((struct sockaddr_in *)&localaddr)->sin_addr.s_addr); + sscanf(rem_addr, "%X", &((struct sockaddr_in *)&remaddr)->sin_addr.s_addr); + ((struct sockaddr *) &localaddr)->sa_family = AF_INET; + ((struct sockaddr *) &remaddr)->sa_family = AF_INET; + } + + char * hashkey = (char *) malloc (92 * sizeof(char)); + snprintf(hashkey, 92 * sizeof(char), "%s:%d-", inet_ntoa(((struct sockaddr_in *)&localaddr)->sin_addr), local_port); + snprintf(hashkey, 92 * sizeof(char), "%s%s:%d", hashkey, inet_ntoa(((struct sockaddr_in *)&remaddr)->sin_addr), rem_port); + conninode->add(hashkey, (void *)inode); + + // also add the reverse. + hashkey = (char *) malloc (92 * sizeof(char)); + snprintf(hashkey, 92 * sizeof(char), "%s:%d-", inet_ntoa(((struct sockaddr_in *)&remaddr)->sin_addr), rem_port); + snprintf(hashkey, 92 * sizeof(char), "%s%s:%d", hashkey, inet_ntoa(((struct sockaddr_in *)&localaddr)->sin_addr), local_port); + conninode->add(hashkey, (void *)inode); + + // also add the aliases :S + if (strcmp(inet_ntoa(((struct sockaddr_in *)&localaddr)->sin_addr), "172.16.3.1") == 0) + { + hashkey = (char *) malloc (92 * sizeof(char)); + snprintf(hashkey, 92 * sizeof(char), "%s:%d-", "195.169.216.157", local_port); + snprintf(hashkey, 92 * sizeof(char), "%s%s:%d", hashkey, inet_ntoa(((struct sockaddr_in *)&remaddr)->sin_addr), rem_port); + conninode->add(hashkey, (void *)inode); + + hashkey = (char *) malloc (92 * sizeof(char)); + snprintf(hashkey, 92 * sizeof(char), "%s:%d-", inet_ntoa(((struct sockaddr_in *)&remaddr)->sin_addr), rem_port); + snprintf(hashkey, 92 * sizeof(char), "%s%s:%d", hashkey, "195.169.216.157", local_port); + conninode->add(hashkey, (void *)inode); + } + if (strcmp(inet_ntoa(((struct sockaddr_in *)&remaddr)->sin_addr), "172.16.3.1") == 0) + { + hashkey = (char *) malloc (92 * sizeof(char)); + snprintf(hashkey, 92 * sizeof(char), "%s:%d-", inet_ntoa(((struct sockaddr_in *)&localaddr)->sin_addr), local_port); + snprintf(hashkey, 92 * sizeof(char), "%s%s:%d", hashkey, "195.169.216.157", rem_port); + conninode->add(hashkey, (void *)inode); + + hashkey = (char *) malloc (92 * sizeof(char)); + snprintf(hashkey, 92 * sizeof(char), "%s:%d-", "195.169.216.157", rem_port); + snprintf(hashkey, 92 * sizeof(char), "%s%s:%d", hashkey, inet_ntoa(((struct sockaddr_in *)&localaddr)->sin_addr), local_port); + conninode->add(hashkey, (void *)inode); + } + if (strcmp(inet_ntoa(((struct sockaddr_in *)&localaddr)->sin_addr), "195.169.216.157") == 0) + { + hashkey = (char *) malloc (92 * sizeof(char)); + snprintf(hashkey, 92 * sizeof(char), "%s:%d-", "172.16.3.1", local_port); + snprintf(hashkey, 92 * sizeof(char), "%s%s:%d", hashkey, inet_ntoa(((struct sockaddr_in *)&remaddr)->sin_addr), rem_port); + conninode->add(hashkey, (void *)inode); + + hashkey = (char *) malloc (92 * sizeof(char)); + snprintf(hashkey, 92 * sizeof(char), "%s:%d-", inet_ntoa(((struct sockaddr_in *)&remaddr)->sin_addr), rem_port); + snprintf(hashkey, 92 * sizeof(char), "%s%s:%d", hashkey, "172.16.3.1", local_port); + conninode->add(hashkey, (void *)inode); + } + if (strcmp(inet_ntoa(((struct sockaddr_in *)&remaddr)->sin_addr), "195.169.216.157") == 0) + { + hashkey = (char *) malloc (92 * sizeof(char)); + snprintf(hashkey, 92 * sizeof(char), "%s:%d-", inet_ntoa(((struct sockaddr_in *)&localaddr)->sin_addr), local_port); + snprintf(hashkey, 92 * sizeof(char), "%s%s:%d", hashkey, "172.16.3.1", rem_port); + conninode->add(hashkey, (void *)inode); + + hashkey = (char *) malloc (92 * sizeof(char)); + snprintf(hashkey, 92 * sizeof(char), "%s:%d-", "172.16.3.1", rem_port); + snprintf(hashkey, 92 * sizeof(char), "%s%s:%d", hashkey, inet_ntoa(((struct sockaddr_in *)&localaddr)->sin_addr), local_port); + conninode->add(hashkey, (void *)inode); + } +} + +void refreshconninode () +{ + delete conninode; + conninode = new HashTable (256); + + char buffer[8192]; + FILE * procinfo = fopen ("/proc/net/tcp", "r"); + if (procinfo) + { + fgets(buffer, sizeof(buffer), procinfo); + do + { + if (fgets(buffer, sizeof(buffer), procinfo)) + addtoconninode(buffer); + } while (!feof(procinfo)); + fclose(procinfo); + } + else + { + std::cout << "Error: couldn't open /proc/net/tcp\n"; + exit(0); + } + + procinfo = fopen ("/proc/net/tcp6", "r"); + if (procinfo != NULL) { + fgets(buffer, sizeof(buffer), procinfo); + do { + if (fgets(buffer, sizeof(buffer), procinfo)) + addtoconninode(buffer); + } while (!feof(procinfo)); + fclose (procinfo); + } +} + +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; +}; + +Process * unknownproc = new Process (0, "unknown"); +ProcList * processes = new ProcList (unknownproc, NULL); + +float tokbps (bpf_u_int32 bytes) +{ + return (((double)bytes) / PERIOD) / 1024; +} + +char * uid2username (int uid) +{ + struct passwd * pwd; + /* getpwuid() allocates space for this itself, + * which we shouldn't free */ + pwd = getpwuid(uid); + if (pwd == NULL) + { + return strdup ("unlisted"); + } else { + return strdup(pwd->pw_name); + } +} + + +class Line +{ +public: + Line (const char * name, double n_sent_kbps, double n_recv_kbps, int pid, int uid) + { + m_name = name; + sent_kbps = n_sent_kbps; + recv_kbps = n_recv_kbps; + m_pid = pid; + m_uid = uid; + } + + void show (int row) + { +#if DEBUG + std::cout << m_name << "\t" << m_sent_kbps << "\t" << recv_kbps << std::endl; +#else + 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, "%10.3f", sent_kbps); + mvprintw (3+row, 6 + 9 + PROGNAME_WIDTH + 2 + 9 + 3, "%10.3f", recv_kbps); + mvprintw (3+row, 6 + 9 + PROGNAME_WIDTH + 2 + 9 + 3 + 11, "KB/sec", recv_kbps); + // TODO fix + //if(m_kbps-upload_kbps>upload_kbps) + // mvprintw (3+row, 6 + 20 + PROGNAME_WIDTH + 2, "<<<<"); + // else mvprintw (3+row, 6 + 20 + PROGNAME_WIDTH + 2, ">>>>"); + +#endif + } + + double sent_kbps; + double recv_kbps; +private: + const char * m_name; + int m_pid; + int m_uid; +}; + +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; +} + +void do_refresh() +{ + if (!DEBUG) + { + clear(); + mvprintw (0, 0, "%s", caption->c_str()); + attron(A_REVERSE); + mvprintw (2, 0, " PID USER PROGRAM SENT RECEIVED "); + attroff(A_REVERSE); + } + else + std::cout << "Refreshing:\n"; + ProcList * curproc = processes; + ProcList * lastproc = NULL; + int nproc = count_processes(); + Line * lines [nproc]; + int n = 0; + while (curproc != NULL) + { + // walk though its connections, summing up + // their data, and throwing away old stuff. + // if the last packet is older than PROCESSTIMEOUT seconds, discard. + if (DEBUG) + { + assert (curproc != NULL); + assert (curproc->getVal() != NULL); + } + if (curproc->getVal()->getLastPacket() + PROCESSTIMEOUT <= curtime.tv_sec) + { + if (lastproc) + { + lastproc->next = curproc->next; + ProcList * newcur = curproc->next; + delete curproc; + curproc = newcur; + nproc--; + } else { + processes = curproc->getNext(); + delete curproc; + curproc = processes; + nproc--; + } + } + else + { + bpf_u_int32 sum = 0, + sum_local = 0, + sum_conn = 0, + sum_connLocal = 0; + ConnList * curconn = curproc->getVal()->incoming; + while (curconn != NULL) + { + curconn->getVal()->sumanddel(curtime, &sum, &sum_local); + sum_connLocal+=sum_local; + sum_conn+=sum; + curconn = curconn->getNext(); + } + lines[n] = new Line (curproc->getVal()->name, tokbps(sum_conn), tokbps(sum_connLocal), curproc->getVal()->pid, curproc->getVal()->uid); + lastproc = curproc; + curproc = curproc->next; + n++; + } + } + qsort (lines, nproc, sizeof(Line *), GreatestFirst); + for (int i=0; ishow(i); + delete lines[i]; + } + if (!DEBUG) + refresh(); +} + +/* returns the process from proclist with matching pid + * if none, creates it */ +Process * getProcess (unsigned long inode) +{ + struct prg_node * node = prg_cache_get(inode); + + if (node == NULL) + { + prg_cache_clear(); + prg_cache_load(); + node = prg_cache_get(inode); + if (node == NULL) + return unknownproc; + } + + ProcList * current = processes; + while (current != NULL) + { + if (node->pid == current->getVal()->pid) + return current->getVal(); + current = current->next; + } + + Process * newproc = new Process (inode); + newproc->name = strdup(node->name); + newproc->pid = node->pid; + + char procdir [100]; + sprintf(procdir , "/proc/%d", node->pid); + struct stat stats; + stat(procdir, &stats); + newproc->uid = stats.st_uid; + + processes = new ProcList (newproc, processes); + return newproc; +} + +Process * getProcess (Connection * connection) +{ + ProcList * curproc = processes; + + // see if we already know the inode for this connection + if (DEBUG) + std::cout << "Connection reference packet found at " << connection->refpacket << std::endl; + unsigned long * inode = (unsigned long *) conninode->get(connection->refpacket->gethashstring()); + + if (inode == NULL) + { + // no? refresh and check conn/inode table +#if DEBUG + cerr << "Not in table, refreshing it.\n"; +#endif + refreshconninode(); + inode = (unsigned long *) conninode->get(connection->refpacket->gethashstring()); + if (inode == NULL) + { +#if DEBUG + //cerr << connection->refpacket->gethashstring() << " STILL not in table - dropping\n"; +#endif + return NULL; + } + } + + Process * proc = getProcess(*inode); + proc->incoming = new ConnList (connection, proc->incoming); + return proc; +} + +void procclean () +{ + delete conninode; + prg_cache_clear(); +} diff --git a/process.h b/process.h new file mode 100644 index 0000000..1922110 --- /dev/null +++ b/process.h @@ -0,0 +1,72 @@ +#ifndef __PROCESS_H +#define __PROCESS_H + +#include +#include "nethogs.h" +#include "connection.h" + +class ConnList +{ +public: + ConnList (Connection * m_val, ConnList * m_next) + { + if (DEBUG) + assert (m_val != NULL); + val = m_val; next = m_next; + } + Connection * getVal () + { + return val; + } + ConnList * getNext () + { + return next; + } +private: + Connection * val; + ConnList * next; +}; + +class Process +{ +public: + Process (unsigned long m_inode, char* m_name = NULL) + { + inode = m_inode; + name = m_name; + incoming = NULL; + outgoing = NULL; + } + int getLastPacket () + { + int lastpacket=0; + ConnList * curconn=incoming; + while (curconn != NULL) + { + if (DEBUG) + { + assert (curconn != NULL); + assert (curconn->getVal() != NULL); + } + if (curconn->getVal()->getLastPacket() > lastpacket) + lastpacket = curconn->getVal()->getLastPacket(); + curconn = curconn->getNext(); + } + return lastpacket; + } + + const char * name; + int pid; + int uid; + + unsigned long inode; + ConnList * incoming; + ConnList * outgoing; +}; + +Process * getProcess (Connection * connection); +void do_refresh (); + +void procclean (); + +#endif diff --git a/refresh.cpp b/refresh.cpp new file mode 100644 index 0000000..79adbf5 --- /dev/null +++ b/refresh.cpp @@ -0,0 +1,17 @@ +#include +#include +#include +#include "nethogs.h" + +extern bool needrefresh; +extern unsigned refreshdelay; + +void alarm_cb (int i) +{ + needrefresh = true; + //cout << "Setting needrefresh\n"; + + signal (SIGALRM, &alarm_cb); + alarm(refreshdelay); +} + diff --git a/refresh.h b/refresh.h new file mode 100644 index 0000000..0a5bf88 --- /dev/null +++ b/refresh.h @@ -0,0 +1 @@ +void alarm_cb (int i); diff --git a/structs.cpp b/structs.cpp new file mode 100644 index 0000000..e69de29 diff --git a/structs.h b/structs.h new file mode 100644 index 0000000..e69de29