fixed some bugs, cleaned a lot of code,

re-added support for PPP
automatic detection of link-layer protocol
This commit is contained in:
Arnout Engelen
2004-09-14 11:23:59 +00:00
parent 23a56f95a6
commit a695b7db2a
8 changed files with 279 additions and 354 deletions

23
DESIGN Normal file
View File

@@ -0,0 +1,23 @@
Rough design notitions:
decpcap handles pcap. nethogs.cpp asks to be notified of all IPv4 or IPv6
TCP packets.
the IP callbacks store the source and destination addresses into the user
data. The TCP callback makes a Packet out of it, finds the Connection
corresponding to that packet, and adds the packet to the connection.
If no connection is found, a new one is constructed, and the process
related to that connection is found though getProcess.
If needed, the screen is refreshed.
If, in getProcess, no corresponding process is found, the connection is
added to the 'unknown' process.
To prevent connections from accidentally ending up in the 'unknown' process,
and then staying there indefinitely, we should maybe walk though
the unknownproc's connections whenever the connection-to-inode table is
refreshed.
And maybe, while there are still unknown connections, the connection-to-inode
table should be updated regularly.

View File

@@ -10,7 +10,7 @@
/* functions to set up a handle (which is basically just a pcap handle) */ /* functions to set up a handle (which is basically just a pcap handle) */
struct dp_handle * dp_open_live(char * device, enum dp_link_type link, int snaplen, int promisc, int to_ms, char * ebuf) struct dp_handle * dp_open_live(char * device, int snaplen, int promisc, int to_ms, char * ebuf)
{ {
struct dp_handle * retval = (struct dp_handle *) malloc (sizeof (struct dp_handle)); struct dp_handle * retval = (struct dp_handle *) malloc (sizeof (struct dp_handle));
pcap_t * temp = pcap_open_live(device, snaplen, promisc, to_ms, ebuf); pcap_t * temp = pcap_open_live(device, snaplen, promisc, to_ms, ebuf);
@@ -27,7 +27,8 @@ struct dp_handle * dp_open_live(char * device, enum dp_link_type link, int snapl
{ {
retval->callback[i] = NULL; retval->callback[i] = NULL;
} }
retval->linktype = link;
retval->linktype = pcap_datalink(retval->pcap_handle);
return retval; return retval;
} }
@@ -186,11 +187,11 @@ void dp_pcap_callback (u_char * u_handle, const struct pcap_pkthdr * header, con
memcpy (userdata_copy, handle->userdata, handle->userdata_size); memcpy (userdata_copy, handle->userdata, handle->userdata_size);
switch (handle->linktype) { switch (handle->linktype) {
case (dp_link_ethernet): case (DLT_EN10MB):
dp_parse_ethernet (handle, header, packet); dp_parse_ethernet (handle, header, packet);
break; break;
case (dp_link_ppp): case (DLT_PPP):
// TODO dp_parse_ppp (handle, header, packet);
break; break;
default: default:
// TODO maybe error? or 'other' callback? // TODO maybe error? or 'other' callback?

View File

@@ -14,11 +14,11 @@ enum dp_packet_type {
dp_n_packet_types dp_n_packet_types
}; };
enum dp_link_type { /*enum dp_link_type {
dp_link_ethernet, dp_link_ethernet,
dp_link_ppp, dp_link_ppp,
dp_n_link_types dp_n_link_types
}; };*/
/*struct dp_header { /*struct dp_header {
};*/ };*/
@@ -29,14 +29,14 @@ typedef int (*dp_callback)(u_char *, const dp_header *, const u_char *);
struct dp_handle { struct dp_handle {
pcap_t * pcap_handle; pcap_t * pcap_handle;
dp_callback callback [dp_n_packet_types]; dp_callback callback [dp_n_packet_types];
enum dp_link_type linktype; int linktype;
u_char * userdata; u_char * userdata;
int userdata_size; int userdata_size;
}; };
/* functions to set up a handle (which is basically just a pcap handle) */ /* functions to set up a handle (which is basically just a pcap handle) */
struct dp_handle * dp_open_live(char * device, enum dp_link_type link, int snaplen, int promisc, int to_ms, char * ebuf); struct dp_handle * dp_open_live(char * device, int snaplen, int promisc, int to_ms, char * ebuf);
/* functions to add callbacks */ /* functions to add callbacks */
@@ -49,3 +49,7 @@ void dp_parse (enum dp_packet_type type, void * packet);
/* functions to start monitoring */ /* functions to start monitoring */
int dp_dispatch (struct dp_handle * handler, int count, u_char *user, int size); int dp_dispatch (struct dp_handle * handler, int count, u_char *user, int size);
/* functions that simply call libpcap */
int dp_datalink(struct dp_handle * handle);

View File

@@ -67,7 +67,7 @@ HashNode * HashTable::newHashNode(char * key, void * content, HashNode * next)
void HashTable::add(char * key, void * content) void HashTable::add(char * key, void * content)
{ {
unsigned int hkey = HashString (key); unsigned int hkey = HashString (key);
//cout << "Adding node: " << key << " key " << hkey << endl; //std::cout << "(STILL)Adding node: " << key << " key " << hkey << endl;
table[hkey] = newHashNode(key, content, table[hkey]); table[hkey] = newHashNode(key, content, table[hkey]);
} }

169
inet6.c
View File

@@ -1,169 +0,0 @@
/*
* 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"
};

View File

@@ -30,7 +30,7 @@ unsigned refreshdelay = 1;
bool tracemode = false; 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;
char * currentdevice = NULL; char * currentdevice = NULL;
@@ -74,34 +74,6 @@ bool local_addr::contains(const struct in6_addr & n_addr) {
return next->contains(n_addr); return next->contains(n_addr);
} }
/* deprecated by process_tcp
* void process (u_char * args, const struct pcap_pkthdr * header, const u_char * m_packet)
{
curtime = header->ts;
Packet * packet = getPacket (header, m_packet, packettype);
if (packet == NULL)
return;
Connection * connection = findConnection(packet);
if (connection != NULL)
{
connection->add(packet);
} else {
connection = new Connection (packet);
if (DEBUG)
std::cerr << "Getting process by connection\n";
Process * process = getProcess(connection, currentdevice);
}
if (needrefresh)
{
do_refresh();
needrefresh = false;
}
}*/
struct dpargs { struct dpargs {
int sa_family; int sa_family;
in_addr ip_src; in_addr ip_src;
@@ -138,8 +110,8 @@ int process_tcp (u_char * userdata, const dp_header * header, const u_char * m_p
} else { } else {
/* else: unknown connection, create new */ /* else: unknown connection, create new */
connection = new Connection (packet); connection = new Connection (packet);
if (DEBUG) //if (DEBUG)
std::cerr << "Getting process by connection\n"; // std::cerr << "Getting process by connection\n";
Process * process = getProcess(connection, currentdevice); Process * process = getProcess(connection, currentdevice);
} }
@@ -201,11 +173,12 @@ static void versiondisplay(void)
static void help(void) static void help(void)
{ {
std::cerr << "usage: nethogs [-V] [-d seconds] [-t] [-p] [-f (eth|ppp))] [device [device [device ...]]]\n"; //std::cerr << "usage: nethogs [-V] [-d seconds] [-t] [-p] [-f (eth|ppp))] [device [device [device ...]]]\n";
std::cerr << "usage: nethogs [-V] [-d seconds] [-t] [-p] [device [device [device ...]]]\n";
std::cerr << " -V : prints version.\n"; std::cerr << " -V : prints version.\n";
std::cerr << " -d : delay for update refresh rate in seconds. default is 1.\n"; std::cerr << " -d : delay for update refresh rate in seconds. default is 1.\n";
std::cerr << " -t : tracemode.\n"; std::cerr << " -t : tracemode.\n";
std::cerr << " -f : format of packets on interface, default is eth.\n"; //std::cerr << " -f : format of packets on interface, default is eth.\n";
std::cerr << " -p : sniff in promiscious mode (not recommended).\n"; std::cerr << " -p : sniff in promiscious mode (not recommended).\n";
std::cerr << " device : device(s) to monitor. default is eth0\n"; std::cerr << " device : device(s) to monitor. default is eth0\n";
} }
@@ -222,7 +195,8 @@ public:
class handle { class handle {
public: public:
handle (dp_handle * m_handle, char * m_devicename = NULL, handle * m_next = NULL) { handle (dp_handle * m_handle, char * m_devicename = NULL,
handle * m_next = NULL) {
content = m_handle; next = m_next; devicename = m_devicename; content = m_handle; next = m_next; devicename = m_devicename;
} }
dp_handle * content; dp_handle * content;
@@ -257,7 +231,7 @@ int main (int argc, char** argv)
refreshdelay=atoi(*argv); refreshdelay=atoi(*argv);
} }
break; break;
case 'f': if (argv[1]) /*case 'f': if (argv[1])
{ {
argv++; argv++;
if (strcmp (*argv, "ppp") == 0) if (strcmp (*argv, "ppp") == 0)
@@ -266,6 +240,7 @@ int main (int argc, char** argv)
linktype = dp_link_ethernet; linktype = dp_link_ethernet;
} }
break; break;
*/
default : help(); default : help();
exit(0); exit(0);
} }
@@ -304,7 +279,7 @@ int main (int argc, char** argv)
caption->append(" "); caption->append(" ");
} }
dp_handle * newhandle = dp_open_live(current_dev->name, linktype, BUFSIZ, promisc, 100, errbuf); dp_handle * newhandle = dp_open_live(current_dev->name, BUFSIZ, promisc, 100, errbuf);
dp_addcb (newhandle, dp_packet_ip, process_ip); dp_addcb (newhandle, dp_packet_ip, process_ip);
dp_addcb (newhandle, dp_packet_ip6, process_ip6); dp_addcb (newhandle, dp_packet_ip6, process_ip6);
dp_addcb (newhandle, dp_packet_tcp, process_tcp); dp_addcb (newhandle, dp_packet_tcp, process_tcp);

View File

@@ -19,7 +19,8 @@ extern timeval curtime;
extern std::string * caption; extern std::string * caption;
extern local_addr * local_addrs; extern local_addr * local_addrs;
static int INET6_getsock(char *bufp, struct sockaddr *sap) /* takes the text in bufp, and uses it to fill the sockaddr *sap. */
/*static int INET6_getsock(char *bufp, struct sockaddr *sap)
{ {
struct sockaddr_in6 *sin6; struct sockaddr_in6 *sin6;
@@ -30,13 +31,26 @@ static int INET6_getsock(char *bufp, struct sockaddr *sap)
if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0) if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
return (-1); return (-1);
return 16; /* ?;) */ return 16;
} }
*/
static int INET6_input(int type, char *bufp, struct sockaddr *sap) class ProcList
{ {
return (INET6_getsock(bufp, sap)); 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;
};
struct aftype { struct aftype {
char *name; char *name;
@@ -63,6 +77,9 @@ struct aftype {
*/ */
HashTable * conninode = new HashTable (256); HashTable * conninode = new HashTable (256);
Process * unknownproc = new Process (0, "", "unknown");
ProcList * processes = new ProcList (unknownproc, NULL);
/* /*
* parses a /proc/net/tcp-line of the form: * parses a /proc/net/tcp-line of the form:
* sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode * sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
@@ -98,12 +115,12 @@ void addtoconninode (char * buffer)
fprintf(stderr,"Unexpected buffer: '%s'\n",buffer); fprintf(stderr,"Unexpected buffer: '%s'\n",buffer);
exit(0); exit(0);
} }
/*if (*inode == 0) {
// This sometimes happens due to what I think is a bug in the if (*inode == 0) {
// kernel. See http://lkml.org/lkml/2004/9/10/193. /* connection is in TIME_WAIT state. We rely on
fprintf(stderr,"Inode zero: '%s'\n",buffer); * the old data still in the table. */
exit(0); return;
}*/ }
if (strlen(local_addr) > 8) if (strlen(local_addr) > 8)
{ {
@@ -126,12 +143,12 @@ void addtoconninode (char * buffer)
sa_family = AF_INET; sa_family = AF_INET;
} else { } else {
/* real IPv6 address */ /* real IPv6 address */
inet_ntop(AF_INET6, &in6_local, addr6, sizeof(addr6)); //inet_ntop(AF_INET6, &in6_local, addr6, sizeof(addr6));
INET6_getsock(addr6, (struct sockaddr *) &localaddr); //INET6_getsock(addr6, (struct sockaddr *) &localaddr);
inet_ntop(AF_INET6, &in6_remote, addr6, sizeof(addr6)); //inet_ntop(AF_INET6, &in6_remote, addr6, sizeof(addr6));
INET6_getsock(addr6, (struct sockaddr *) &remaddr); //INET6_getsock(addr6, (struct sockaddr *) &remaddr);
localaddr.sin6_family = AF_INET6; //localaddr.sin6_family = AF_INET6;
remaddr.sin6_family = AF_INET6; //remaddr.sin6_family = AF_INET6;
result_addr_local = in6_local; result_addr_local = in6_local;
result_addr_remote = in6_remote; result_addr_remote = in6_remote;
sa_family = AF_INET6; sa_family = AF_INET6;
@@ -157,7 +174,7 @@ void addtoconninode (char * buffer)
//if (DEBUG) //if (DEBUG)
// fprintf (stderr, "Hashkey: %s\n", hashkey); // fprintf (stderr, "Hashkey: %s\n", hashkey);
conninode->add(hashkey, (void *)inode); //std::cout << "Adding to conninode\n" << std::endl;
/* workaround: sometimes, when a connection is actually from 172.16.3.1 to /* workaround: sometimes, when a connection is actually from 172.16.3.1 to
* 172.16.3.3, packages arrive from 195.169.216.157 to 172.16.3.3, where * 172.16.3.3, packages arrive from 195.169.216.157 to 172.16.3.3, where
@@ -165,6 +182,7 @@ void addtoconninode (char * buffer)
* interfaces */ * interfaces */
struct local_addr * current_local_addr = local_addrs; struct local_addr * current_local_addr = local_addrs;
while (current_local_addr != NULL) { while (current_local_addr != NULL) {
/* TODO maybe only add the ones with the same sa_family */
hashkey = (char *) malloc (HASHKEYSIZE * sizeof(char)); hashkey = (char *) malloc (HASHKEYSIZE * sizeof(char));
snprintf(hashkey, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d", current_local_addr->string, local_port, remote_string, rem_port); snprintf(hashkey, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d", current_local_addr->string, local_port, remote_string, rem_port);
conninode->add(hashkey, (void *)inode); conninode->add(hashkey, (void *)inode);
@@ -173,61 +191,124 @@ void addtoconninode (char * buffer)
free (remote_string); free (remote_string);
} }
void refreshconninode () int addprocinfo (const char * filename) {
{ FILE * procinfo = fopen (filename, "r");
delete conninode;
conninode = new HashTable (256);
char buffer[8192]; char buffer[8192];
FILE * procinfo = fopen ("/proc/net/tcp", "r");
if (procinfo == NULL)
return 0;
// TODO use helper function
if (procinfo)
{
fgets(buffer, sizeof(buffer), procinfo); fgets(buffer, sizeof(buffer), procinfo);
do do
{ {
if (fgets(buffer, sizeof(buffer), procinfo)) if (fgets(buffer, sizeof(buffer), procinfo))
addtoconninode(buffer); addtoconninode(buffer);
} while (!feof(procinfo)); } while (!feof(procinfo));
fclose(procinfo); fclose(procinfo);
return 1;
}
struct prg_node * findPID (unsigned long inode)
{
/* find PID */
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)
{
if (DEBUG)
std::cout << "inode " << inode << " STILL not in inode-to-pid-mapping." << endl;
return NULL;
}
}
return node;
}
Process * findProcess (struct prg_node * node)
{
ProcList * current = processes;
while (current != NULL)
{
if (node->pid == current->getVal()->pid)
return current->getVal();
current = current->next;
}
return NULL;
}
/* finds process based on inode, if any */
Process * findProcess (unsigned long inode)
{
struct prg_node * node = findPID(inode);
if (node == NULL)
return NULL;
return findProcess (node);
}
/* check if we have identified any previously unknown
* connections are now known */
void reviewUnknown ()
{
ConnList * curr_conn = unknownproc->connections;
ConnList * previous_conn = NULL;
while (curr_conn != NULL) {
unsigned long * inode = (unsigned long *)
conninode->get(curr_conn->getVal()->refpacket->gethashstring());
if (inode != NULL)
{
Process * proc = findProcess (*inode);
if (proc != unknownproc && proc != NULL)
{
/* Yay! - but how could this happen? */
if (previous_conn != NULL)
{
previous_conn->setNext (curr_conn->getNext());
proc->connections = new ConnList (curr_conn->getVal(), proc->connections);
delete curr_conn;
curr_conn = previous_conn;
} }
else else
{
unknownproc->connections = curr_conn->getNext();
proc->connections = new ConnList (curr_conn->getVal(), proc->connections);
delete curr_conn;
curr_conn = unknownproc->connections;
}
}
}
previous_conn = curr_conn;
if (curr_conn != NULL)
curr_conn = curr_conn->getNext();
}
}
void refreshconninode ()
{
/* we don't forget old mappings, just overwrite */
//delete conninode;
//conninode = new HashTable (256);
if (! addprocinfo ("/proc/net/tcp"))
{ {
std::cout << "Error: couldn't open /proc/net/tcp\n"; std::cout << "Error: couldn't open /proc/net/tcp\n";
exit(0); exit(0);
} }
addprocinfo ("/proc/net/tcp6");
procinfo = fopen ("/proc/net/tcp6", "r"); reviewUnknown();
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) float tokbps (bpf_u_int32 bytes)
{ {
@@ -262,7 +343,18 @@ public:
m_uid = uid; m_uid = uid;
} }
void show (int row) 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) if (DEBUG || tracemode)
{ {
@@ -281,15 +373,6 @@ public:
mvprintw (3+row, 6 + 9 + PROGNAME_WIDTH + 2 + 6 + 9 + 3 + 11, "KB/sec", recv_kbps); mvprintw (3+row, 6 + 9 + PROGNAME_WIDTH + 2 + 6 + 9 + 3 + 11, "KB/sec", recv_kbps);
} }
double sent_kbps;
double recv_kbps;
private:
const char * m_name;
const char * devicename;
int m_pid;
int m_uid;
};
int GreatestFirst (const void * ma, const void * mb) int GreatestFirst (const void * ma, const void * mb)
{ {
Line ** pa = (Line **)ma; Line ** pa = (Line **)ma;
@@ -322,9 +405,10 @@ int count_processes()
// Display all processes and relevant network traffic using show function // Display all processes and relevant network traffic using show function
void do_refresh() void do_refresh()
{ {
refreshconninode();
if (DEBUG || tracemode) if (DEBUG || tracemode)
{ {
std::cout << "Refreshing:\n"; std::cout << "\n\nRefreshing:\n";
} }
else else
{ {
@@ -335,7 +419,7 @@ void do_refresh()
attroff(A_REVERSE); attroff(A_REVERSE);
} }
ProcList * curproc = processes; ProcList * curproc = processes;
ProcList * lastproc = NULL; ProcList * previousproc = NULL;
int nproc = count_processes(); int nproc = count_processes();
Line * lines [nproc]; Line * lines [nproc];
int n = 0, i = 0; int n = 0, i = 0;
@@ -344,9 +428,9 @@ void do_refresh()
while (curproc != NULL) while (curproc != NULL)
{ {
// walk though its connections, summing up // walk though its connections, summing up their data, and
// their data, and throwing away old stuff. // throwing away connections that haven't received a package
// if the last packet is older than PROCESSTIMEOUT seconds, discard. // in the last PROCESSTIMEOUT seconds.
if (DEBUG) if (DEBUG)
{ {
assert (curproc != NULL); assert (curproc != NULL);
@@ -354,9 +438,10 @@ void do_refresh()
} }
if ((curproc->getVal()->getLastPacket() + PROCESSTIMEOUT <= curtime.tv_sec) && (curproc->getVal() != unknownproc)) if ((curproc->getVal()->getLastPacket() + PROCESSTIMEOUT <= curtime.tv_sec) && (curproc->getVal() != unknownproc))
{ {
if (lastproc) /* remove connection */
if (previousproc)
{ {
lastproc->next = curproc->next; previousproc->next = curproc->next;
ProcList * newcur = curproc->next; ProcList * newcur = curproc->next;
delete curproc; delete curproc;
curproc = newcur; curproc = newcur;
@@ -367,13 +452,16 @@ void do_refresh()
curproc = processes; curproc = processes;
nproc--; nproc--;
} }
continue;
} }
else
{
bpf_u_int32 sum = 0, bpf_u_int32 sum = 0,
sum_local = 0, sum_local = 0,
sum_conn = 0, sum_conn = 0,
sum_connLocal = 0; sum_connLocal = 0;
/* walk though all this process's connections, and sum them
* up */
ConnList * curconn = curproc->getVal()->connections; ConnList * curconn = curproc->getVal()->connections;
while (curconn != NULL) while (curconn != NULL)
{ {
@@ -383,12 +471,15 @@ void do_refresh()
curconn = curconn->getNext(); curconn = curconn->getNext();
} }
lines[n] = new Line (curproc->getVal()->name, tokbps(sum_conn), tokbps(sum_connLocal), curproc->getVal()->pid, curproc->getVal()->uid, curproc->getVal()->devicename); lines[n] = new Line (curproc->getVal()->name, tokbps(sum_conn), tokbps(sum_connLocal), curproc->getVal()->pid, curproc->getVal()->uid, curproc->getVal()->devicename);
lastproc = curproc; previousproc = curproc;
curproc = curproc->next; curproc = curproc->next;
n++; n++;
} }
}
/* sort the accumulated lines */
qsort (lines, nproc, sizeof(Line *), GreatestFirst); qsort (lines, nproc, sizeof(Line *), GreatestFirst);
/* print them */
for (i=0; i<nproc; i++) for (i=0; i<nproc; i++)
{ {
lines[i]->show(i); lines[i]->show(i);
@@ -396,6 +487,16 @@ void do_refresh()
sent_global += lines[i]->sent_kbps; sent_global += lines[i]->sent_kbps;
delete lines[i]; 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)){ if ((!tracemode) && (!DEBUG)){
attron(A_REVERSE); attron(A_REVERSE);
@@ -406,34 +507,22 @@ void do_refresh()
} }
} }
/* returns the process from proclist with matching pid /*
* returns the process from proclist with matching pid
* if the inode is not associated with any PID, return the unknown process * if the inode is not associated with any PID, return the unknown process
* if the process is not yet in the proclist, add it * if the process is not yet in the proclist, add it
*/ */
Process * getProcess (unsigned long inode, char * devicename) Process * getProcess (unsigned long inode, char * devicename)
{ {
struct prg_node * node = prg_cache_get(inode); struct prg_node * node = findPID(inode);
if (node == NULL) if (node == NULL)
{
prg_cache_clear();
prg_cache_load();
node = prg_cache_get(inode);
if (node == NULL)
{
if (DEBUG)
std::cerr << "inode " << inode << " STILL not in inode-to-program-mapping." << endl;
return unknownproc; return unknownproc;
}
}
ProcList * current = processes; Process * proc = findProcess (node);
while (current != NULL)
{ if (proc != NULL)
if (node->pid == current->getVal()->pid) return proc;
return current->getVal();
current = current->next;
}
Process * newproc = new Process (inode, strdup(devicename)); Process * newproc = new Process (inode, strdup(devicename));
newproc->name = strdup(node->name); newproc->name = strdup(node->name);
@@ -459,38 +548,36 @@ Process * getProcess (Connection * connection, char * devicename)
{ {
ProcList * curproc = processes; ProcList * curproc = processes;
// see if we already know the inode for this connection unsigned long * inode = (unsigned long *)
if (DEBUG) conninode->get(connection->refpacket->gethashstring());
{
std::cout << "New connection reference packet.. ";
std::cout << connection->refpacket << std::endl;
}
unsigned long * inode = (unsigned long *) conninode->get(connection->refpacket->gethashstring());
if (inode == NULL) if (inode == NULL)
{ {
// no? refresh and check conn/inode table // no? refresh and check conn/inode table
#if DEBUG #if DEBUG
std::cerr << "Not in table, refreshing table from /proc/net/tcp.\n"; std::cerr << "new connection not in connection-to-inode table.\n";
#endif #endif
refreshconninode(); refreshconninode();
inode = (unsigned long *) conninode->get(connection->refpacket->gethashstring()); inode = (unsigned long *)
conninode->get(connection->refpacket->gethashstring());
if (inode == NULL) if (inode == NULL)
{ {
/* HACK: the following is a hack for cases where the 'local' addresses /* HACK: the following is a hack for cases where the
* aren't properly recognised, as is currently the case for IPv6 */ * 'local' addresses aren't properly recognised, as is
* currently the case for IPv6 */
/* we reverse the direction of the stream if successful. */ /* we reverse the direction of the stream if
* successful. */
Packet * reversepacket = connection->refpacket->newInverted(); Packet * reversepacket = connection->refpacket->newInverted();
//inode = (unsigned long *) conninode->get(reversepacket->gethashstring()); inode = (unsigned long *)
conninode->get(reversepacket->gethashstring());
if (inode == NULL) if (inode == NULL)
{ {
delete reversepacket; delete reversepacket;
if (DEBUG) if (DEBUG)
std::cerr << connection->refpacket->gethashstring() << " STILL not in connection-to-inode table - adding to the unknown process\n"; std::cout << connection->refpacket->gethashstring() << " STILL not in connection-to-inode table - adding to the unknown process\n";
unknownproc->connections = new ConnList (connection, unknownproc->connections); unknownproc->connections = new ConnList (connection, unknownproc->connections);
return unknownproc; return unknownproc;
} }

View File

@@ -20,6 +20,10 @@ public:
{ {
return val; return val;
} }
ConnList * setNext (ConnList * m_next)
{
next = m_next;
}
ConnList * getNext () ConnList * getNext ()
{ {
return next; return next;