Initial import.

This commit is contained in:
Arnout Engelen
2004-06-29 13:31:04 +00:00
commit be624683f0
21 changed files with 1804 additions and 0 deletions

7
INSTALL Normal file
View File

@@ -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

48
Makefile Normal file
View File

@@ -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

131
connection.cpp Normal file
View File

@@ -0,0 +1,131 @@
#include <iostream>
#include <assert.h>
#include <malloc.h>
#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);
}

86
connection.h Normal file
View File

@@ -0,0 +1,86 @@
#ifndef __CONNECTION_H
#define __CONNECTION_H
#include <iostream>
#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

90
hashtbl.cpp Normal file
View File

@@ -0,0 +1,90 @@
#include <iostream>
#include <values.h>
#include <malloc.h>
#include <string.h>
#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<size; i++)
{
table[i] = NULL;
}
}
HashTable::~HashTable()
{
for (unsigned int i=0; i<size; i++)
{
if (table[i])
delete table[i];
}
free (table);
}
unsigned int HashTable::HashString (const char * str)
{
unsigned int retval = 0;
int length = strlen(str);
unsigned int top5bits = 0xf8000000;
unsigned int carry = 0;
const int kleftmove=5;
const int krightmove=27;
for (int i=0; i<length; i++)
{
carry = retval & top5bits;
carry = carry >> 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;
}

30
hashtbl.h Normal file
View File

@@ -0,0 +1,30 @@
#include <stdlib.h>
#include <stdio.h>
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 ;)
};

BIN
hashtest Executable file

Binary file not shown.

11
hashtest.cpp Normal file
View File

@@ -0,0 +1,11 @@
#include <iostream>
#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;
}

169
inet6.c Normal file
View File

@@ -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, <waltje@uwalt.nl.mugnet.org>
* 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 <asm/types.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <resolv.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
/*
#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"
};

226
inodeproc.cpp Normal file
View File

@@ -0,0 +1,226 @@
/* this comes from netstat.c, but is very useful :)) */
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
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;pnp<prg_hash+PRG_HASH_SIZE;pnp++)
while ((pn=*pnp)) {
*pnp=pn->next;
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");
}

27
nethogs.8 Normal file
View File

@@ -0,0 +1,27 @@
.\" This page Copyright (C) 2004 Fabian Frederick <fabian.frederick@gmx.fr>
.\" 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 <arnouten@bzzt.net>.

175
nethogs.cpp Normal file
View File

@@ -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 <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <signal.h>
#include <string>
#include <string.h>
#include <ncurses.h>
extern "C" {
#include <pcap.h>
}
#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;
}
}
}

28
nethogs.h Normal file
View File

@@ -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

178
packet.cpp Normal file
View File

@@ -0,0 +1,178 @@
#include <iostream>
#include "packet.h"
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <malloc.h>
#include <assert.h>
#include <net/if.h>
#include <sys/ioctl.h>
#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)));
}

45
packet.h Normal file
View File

@@ -0,0 +1,45 @@
#ifndef __PACKET_H
#define __PACKET_H
#define _BSD_SOURCE 1
#include <net/ethernet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
extern "C"
{
#include <pcap.h>
}
/* 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

463
process.cpp Normal file
View File

@@ -0,0 +1,463 @@
#include <iostream>
#include <strings.h>
#include <string>
#include <ncurses.h>
#include <asm/types.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <pwd.h>
#include <sys/types.h>
#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; i<nproc; i++)
{
lines[i]->show(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();
}

72
process.h Normal file
View File

@@ -0,0 +1,72 @@
#ifndef __PROCESS_H
#define __PROCESS_H
#include <assert.h>
#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

17
refresh.cpp Normal file
View File

@@ -0,0 +1,17 @@
#include <iostream>
#include <signal.h>
#include <unistd.h>
#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);
}

1
refresh.h Normal file
View File

@@ -0,0 +1 @@
void alarm_cb (int i);

0
structs.cpp Normal file
View File

0
structs.h Normal file
View File