This commit is contained in:
Arnout Engelen
2004-09-17 19:22:17 +00:00
parent cd3fce3e54
commit 45e3157f67
7 changed files with 73 additions and 286 deletions

View File

@@ -7,8 +7,8 @@ man8 := $(DESTDIR)/usr/share/man/man8/
all: nethogs all: nethogs
CFLAGS=-g -Wall CFLAGS=-g -Wall -pg
OBJS=structs.o packet.o connection.o process.o hashtbl.o refresh.o decpcap.o OBJS=structs.o packet.o connection.o process.o refresh.o decpcap.o cui.o
GCC=g++ GCC=g++
.PHONY: tgz .PHONY: tgz
@@ -42,6 +42,8 @@ hashtbl.o: hashtbl.cpp hashtbl.h nethogs.h
$(GCC) $(CFLAGS) -c hashtbl.cpp $(GCC) $(CFLAGS) -c hashtbl.cpp
decpcap.o: decpcap.c decpcap.h decpcap.o: decpcap.c decpcap.h
gcc $(CFLAGS) -c decpcap.c 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 .PHONY: clean
clean: clean:

View File

@@ -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) void dp_parse_tcp (struct dp_handle * handle, const dp_header * header, const u_char * packet)
{ {
const struct tcphdr * tcp = (struct tcphdr *) packet; //const struct tcphdr * tcp = (struct tcphdr *) packet;
u_char * payload = (u_char *) packet + sizeof (struct tcphdr); //u_char * payload = (u_char *) packet + sizeof (struct tcphdr);
if (handle->callback[dp_packet_tcp] != NULL) if (handle->callback[dp_packet_tcp] != NULL)
{ {

View File

@@ -15,7 +15,7 @@
#include <netinet/ip6.h> #include <netinet/ip6.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <ncurses.h> #include "cui.h"
extern "C" { extern "C" {
#include "decpcap.h" #include "decpcap.h"
@@ -31,13 +31,11 @@ bool tracemode = false;
bool needrefresh = true; bool needrefresh = true;
//packet_type packettype = packet_ethernet; //packet_type packettype = packet_ethernet;
//dp_link_type linktype = dp_link_ethernet; //dp_link_type linktype = dp_link_ethernet;
const char version[] = " version " VERSION "." SUBVERSION "." MINORVERSION;
char * currentdevice = NULL; char * currentdevice = NULL;
const char version[] = " version " VERSION "." SUBVERSION "." MINORVERSION;
timeval curtime; timeval curtime;
std::string * caption;
bool local_addr::contains (const in_addr_t & n_addr) { bool local_addr::contains (const in_addr_t & n_addr) {
if ((sa_family == AF_INET) 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); packet = new Packet (args->ip6_src, ntohs(tcp->source), args->ip6_dst, ntohs(tcp->dest), header->len, header->ts);
break; break;
} }
//if (DEBUG) //if (DEBUG)
// std::cout << "Got packet from " << packet->gethashstring() << std::endl; // 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) void quit_cb (int i)
{ {
procclean(); procclean();
clear(); if ((!tracemode) && (!DEBUG))
endwin(); exit_ui();
delete caption;
exit(0); exit(0);
} }
void forceExit(const char *msg) void forceExit(const char *msg)
{ {
if ((!tracemode)&&(!DEBUG)){ if ((!tracemode)&&(!DEBUG)){
clear(); exit_ui();
endwin();
} }
std::cerr << msg << std::endl; std::cerr << msg << std::endl;
exit(0); exit(0);
@@ -168,7 +165,6 @@ void forceExit(const char *msg)
static void versiondisplay(void) static void versiondisplay(void)
{ {
std::cerr << version << "\n"; std::cerr << version << "\n";
} }
@@ -256,14 +252,7 @@ int main (int argc, char** argv)
devices = new device (strdup("eth0")); devices = new device (strdup("eth0"));
if ((!tracemode) && (!DEBUG)){ if ((!tracemode) && (!DEBUG)){
WINDOW * screen = initscr(); init_ui();
raw();
noecho();
cbreak();
nodelay(screen, TRUE);
caption = new std::string ("NetHogs");
caption->append(version);
caption->append(", running at ");
} }
if (NEEDROOT && (getuid() != 0)) if (NEEDROOT && (getuid() != 0))
@@ -276,8 +265,8 @@ int main (int argc, char** argv)
while (current_dev != NULL) { while (current_dev != NULL) {
getLocal(current_dev->name); getLocal(current_dev->name);
if ((!tracemode) && (!DEBUG)){ if ((!tracemode) && (!DEBUG)){
caption->append(current_dev->name); //caption->append(current_dev->name);
caption->append(" "); //caption->append(" ");
} }
dp_handle * newhandle = dp_open_live(current_dev->name, BUFSIZ, promisc, 100, errbuf); 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)) { if ((!DEBUG)&&(!tracemode)) {
switch (getch()) { ui_tick();
case 'q':
/* quit */
quit_cb(0);
break;
case 's':
/* sort on 'sent' */
break;
case 'r':
/* sort on 'received' */
break;
}
} }
if (needrefresh) if (needrefresh)
{ {

View File

@@ -30,7 +30,13 @@
#define NEEDROOT 1 #define NEEDROOT 1
#endif #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'. // 2 times: 32 characters, 7 ':''s, a ':12345'.
// 1 '-' // 1 '-'
@@ -103,4 +109,6 @@ private:
short int sa_family; short int sa_family;
}; };
void quit_cb (int i);
#endif #endif

View File

@@ -163,7 +163,7 @@ Packet::Packet (const Packet &old_packet) {
hashstring = NULL; hashstring = NULL;
else else
hashstring = strdup(old_packet.hashstring); hashstring = strdup(old_packet.hashstring);
dir = old_packet.dir;
} }
bool sameinaddr(in_addr one, in_addr other) bool sameinaddr(in_addr one, in_addr other)

View File

@@ -15,25 +15,9 @@
#include "nethogs.h" #include "nethogs.h"
#include "inodeproc.cpp" #include "inodeproc.cpp"
extern timeval curtime;
extern std::string * caption;
extern local_addr * local_addrs; 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. * 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; std::cout << "ITP: inode " << inode << " STILL not in inode-to-pid-mapping." << endl;
return NULL; return NULL;
} }
} else if (DEBUG) }
std::cout << "ITP: inode " << inode << " found in inode-to-pid-mapping." << endl;
inodeproc[inode] = node; /* make copy of returned node, add it to map, and return it */
if (node != NULL)
return node; {
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) Process * findProcess (struct prg_node * node)
@@ -245,7 +235,10 @@ Process * findProcess (struct prg_node * node)
ProcList * current = processes; ProcList * current = processes;
while (current != NULL) while (current != NULL)
{ {
if (node->pid == current->getVal()->pid) Process * currentproc = current->getVal();
assert (currentproc != NULL);
if (node->pid == currentproc->pid)
return current->getVal(); return current->getVal();
current = current->next; 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) if (next != NULL)
{ i += next->size();
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);
}
}
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; return i;
} }
// Display all processes and relevant network traffic using show function void check_all_procs ()
void do_refresh()
{ {
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 * 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) while (curproc != NULL)
{ {
// walk though its connections, summing up their data, and curproc->getVal()->check();
// throwing away connections that haven't received a package curproc = curproc->getNext();
// 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; i<nproc; i++)
{
lines[i]->show(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();
} }
} }

View File

@@ -7,6 +7,8 @@
extern bool tracemode; extern bool tracemode;
void check_all_procs ();
class ConnList class ConnList
{ {
public: public:
@@ -58,6 +60,10 @@ public:
pid = 0; pid = 0;
uid = 0; uid = 0;
} }
void check () {
assert (pid >= 0);
assert (uid >= 0);
}
/* TODO free m_name and m_devicename again in constructor */ /* TODO free m_name and m_devicename again in constructor */
~Process () ~Process ()
{ {
@@ -86,8 +92,25 @@ private:
uid_t uid; 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); Process * getProcess (Connection * connection, char * devicename = NULL);
void do_refresh (); void refreshconninode ();
void procclean (); void procclean ();