Use clang-format to format (somewhat) LLVM-style (fixes #44)

This commit is contained in:
Arnout Engelen
2016-03-21 00:31:48 +01:00
parent ac045b487a
commit e74935da1f
24 changed files with 2369 additions and 2561 deletions

View File

@@ -30,7 +30,9 @@ nethogs:
decpcap_test: decpcap_test:
$(MAKE) -f MakeApp.mk $@ $(MAKE) -f MakeApp.mk $@
.PHONY: clean
clean: clean:
$(MAKE) -f MakeApp.mk $@ $(MAKE) -f MakeApp.mk $@
$(MAKE) -f MakeLib.mk $@ $(MAKE) -f MakeLib.mk $@
format:
clang-format -i *.c *.cpp *.h

View File

@@ -44,22 +44,16 @@ After that, simply
Coding standards Coding standards
---------------- ----------------
Can anyone recommend a sensible set? :) We use the [http://llvm.org/docs/CodingStandards.html](LLVM coding standards),
with the exception that we do allow 'return' after 'else' if it makes the code
more readable.
For now: Not all code currently adheres to this standard. Pull requests fixing style
* '{' are welcome, and do write new code in the proper style, but please do not
* on a new line for function definitions mix style fixes and new functionality in one pull request.
* on a new line for enums
* on the same line for conditionals/loops When writing new code, at least run 'make format' to have clang-format fix
* omitted when possible some superficial style aspects.
* use tab for indentation
* use doxygen/javadoc-style comments.
* for multiline doxygen docs, add a newline after '/**'
* case
* classes: camelcased, start uppercase
* enums: camelcased, start uppercase
* functions: camelcased, start lowercase
* local variables: camelcased, start lowercase
libnethogs libnethogs
---------- ----------

View File

@@ -1,4 +1,4 @@
/* /*
* connection.cpp * connection.cpp
* *
* Copyright (c) 2004-2006,2008 Arnout Engelen * Copyright (c) 2004-2006,2008 Arnout Engelen
@@ -15,224 +15,198 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
#include <iostream> #include <iostream>
#include <cassert> #include <cassert>
#ifdef __APPLE__ #ifdef __APPLE__
#include <sys/malloc.h> #include <sys/malloc.h>
#else #else
#include <malloc.h> #include <malloc.h>
#endif #endif
#include "nethogs.h" #include "nethogs.h"
#include "connection.h" #include "connection.h"
#include "process.h" #include "process.h"
ConnList * connections = NULL; ConnList *connections = NULL;
void PackList::add (Packet * p) void PackList::add(Packet *p) {
{ if (content == NULL) {
if (content == NULL) content = new PackListNode(new Packet(*p));
{ return;
content = new PackListNode (new Packet (*p)); }
return;
}
if (content->val->time.tv_sec == p->time.tv_sec) if (content->val->time.tv_sec == p->time.tv_sec) {
{ content->val->len += p->len;
content->val->len += p->len; return;
return; }
}
/* store copy of packet, so that original may be freed */ /* store copy of packet, so that original may be freed */
content = new PackListNode(new Packet (*p), content); content = new PackListNode(new Packet(*p), content);
} }
/* sums up the total bytes used and removes 'old' packets */ /* sums up the total bytes used and removes 'old' packets */
u_int32_t PackList::sumanddel (timeval t) u_int32_t PackList::sumanddel(timeval t) {
{ u_int32_t retval = 0;
u_int32_t retval = 0; PackListNode *current = content;
PackListNode * current = content; PackListNode *previous = NULL;
PackListNode * previous = NULL;
while (current != NULL) while (current != NULL) {
{ // std::cout << "Comparing " << current->val->time.tv_sec << " <= " <<
//std::cout << "Comparing " << current->val->time.tv_sec << " <= " << t.tv_sec - PERIOD << endl; // t.tv_sec - PERIOD << endl;
if (current->val->time.tv_sec <= t.tv_sec - PERIOD) if (current->val->time.tv_sec <= t.tv_sec - PERIOD) {
{ if (current == content)
if (current == content) content = NULL;
content = NULL; else if (previous != NULL)
else if (previous != NULL) previous->next = NULL;
previous->next = NULL; delete current;
delete current; return retval;
return retval; }
} retval += current->val->len;
retval += current->val->len; previous = current;
previous = current; current = current->next;
current = current->next; }
} return retval;
return retval;
} }
/* packet may be deleted by caller */ /* packet may be deleted by caller */
Connection::Connection (Packet * packet) Connection::Connection(Packet *packet) {
{ assert(packet != NULL);
assert (packet != NULL); connections = new ConnList(this, connections);
connections = new ConnList (this, connections); sent_packets = new PackList();
sent_packets = new PackList (); recv_packets = new PackList();
recv_packets = new PackList (); sumSent = 0;
sumSent = 0; sumRecv = 0;
sumRecv = 0; if (DEBUG) {
if (DEBUG) std::cout << "New connection, with package len " << packet->len
{ << std::endl;
std::cout << "New connection, with package len " << packet->len << std::endl; }
} if (packet->Outgoing()) {
if (packet->Outgoing()) sumSent += packet->len;
{ sent_packets->add(packet);
sumSent += packet->len; refpacket = new Packet(*packet);
sent_packets->add(packet); } else {
refpacket = new Packet (*packet); sumRecv += packet->len;
} else { recv_packets->add(packet);
sumRecv += packet->len; refpacket = packet->newInverted();
recv_packets->add(packet); }
refpacket = packet->newInverted(); lastpacket = packet->time.tv_sec;
} if (DEBUG)
lastpacket = packet->time.tv_sec; std::cout << "New reference packet created at " << refpacket << std::endl;
if (DEBUG)
std::cout << "New reference packet created at " << refpacket << std::endl;
} }
Connection::~Connection () Connection::~Connection() {
{ if (DEBUG)
if (DEBUG) std::cout << "Deleting connection" << std::endl;
std::cout << "Deleting connection" << std::endl; /* refpacket is not a pointer to one of the packets in the lists
/* refpacket is not a pointer to one of the packets in the lists * so deleted */
* so deleted */ delete (refpacket);
delete (refpacket); if (sent_packets != NULL)
if (sent_packets != NULL) delete sent_packets;
delete sent_packets; if (recv_packets != NULL)
if (recv_packets != NULL) delete recv_packets;
delete recv_packets;
ConnList * curr_conn = connections; ConnList *curr_conn = connections;
ConnList * prev_conn = NULL; ConnList *prev_conn = NULL;
while (curr_conn != NULL) while (curr_conn != NULL) {
{ if (curr_conn->getVal() == this) {
if (curr_conn->getVal() == this) ConnList *todelete = curr_conn;
{ curr_conn = curr_conn->getNext();
ConnList * todelete = curr_conn; if (prev_conn == NULL) {
curr_conn = curr_conn->getNext(); connections = curr_conn;
if (prev_conn == NULL) } else {
{ prev_conn->setNext(curr_conn);
connections = curr_conn; }
} else { delete (todelete);
prev_conn->setNext(curr_conn); } else {
} prev_conn = curr_conn;
delete (todelete); curr_conn = curr_conn->getNext();
} }
else }
{
prev_conn = curr_conn;
curr_conn = curr_conn->getNext();
}
}
} }
/* the packet will be freed by the calling code */ /* the packet will be freed by the calling code */
void Connection::add (Packet * packet) void Connection::add(Packet *packet) {
{ lastpacket = packet->time.tv_sec;
lastpacket = packet->time.tv_sec; if (packet->Outgoing()) {
if (packet->Outgoing()) if (DEBUG) {
{ std::cout << "Outgoing: " << packet->len << std::endl;
if (DEBUG) }
{ sumSent += packet->len;
std::cout << "Outgoing: " << packet->len << std::endl; sent_packets->add(packet);
} } else {
sumSent += packet->len; if (DEBUG) {
sent_packets->add (packet); std::cout << "Incoming: " << packet->len << std::endl;
} }
else sumRecv += packet->len;
{ if (DEBUG) {
if (DEBUG) std::cout << "sumRecv now: " << sumRecv << std::endl;
{ }
std::cout << "Incoming: " << packet->len << std::endl; recv_packets->add(packet);
} }
sumRecv += packet->len;
if (DEBUG)
{
std::cout << "sumRecv now: " << sumRecv << std::endl;
}
recv_packets->add (packet);
}
} }
Connection * findConnectionWithMatchingSource(Packet * packet) { Connection *findConnectionWithMatchingSource(Packet *packet) {
assert(packet->Outgoing()); assert(packet->Outgoing());
ConnList * current = connections; ConnList *current = connections;
while (current != NULL) while (current != NULL) {
{ /* the reference packet is always outgoing */
/* the reference packet is always outgoing */ if (packet->matchSource(current->getVal()->refpacket)) {
if (packet->matchSource(current->getVal()->refpacket)) return current->getVal();
{ }
return current->getVal();
}
current = current->getNext(); current = current->getNext();
} }
return NULL; return NULL;
} }
Connection * findConnectionWithMatchingRefpacketOrSource(Packet * packet) { Connection *findConnectionWithMatchingRefpacketOrSource(Packet *packet) {
ConnList * current = connections; ConnList *current = connections;
while (current != NULL) while (current != NULL) {
{ /* the reference packet is always *outgoing* */
/* the reference packet is always *outgoing* */ if (packet->match(current->getVal()->refpacket)) {
if (packet->match(current->getVal()->refpacket)) return current->getVal();
{ }
return current->getVal();
}
current = current->getNext(); current = current->getNext();
} }
return findConnectionWithMatchingSource(packet); return findConnectionWithMatchingSource(packet);
} }
/* /*
* finds connection to which this packet belongs. * finds connection to which this packet belongs.
* a packet belongs to a connection if it matches * a packet belongs to a connection if it matches
* to its reference packet * to its reference packet
*/ */
Connection * findConnection (Packet * packet) Connection *findConnection(Packet *packet) {
{ if (packet->Outgoing())
if (packet->Outgoing()) return findConnectionWithMatchingRefpacketOrSource(packet);
return findConnectionWithMatchingRefpacketOrSource(packet); else {
else Packet *invertedPacket = packet->newInverted();
{ Connection *result =
Packet * invertedPacket = packet->newInverted(); findConnectionWithMatchingRefpacketOrSource(invertedPacket);
Connection * result = findConnectionWithMatchingRefpacketOrSource(invertedPacket);
delete invertedPacket; delete invertedPacket;
return result; return result;
} }
} }
/* /*
* Connection::sumanddel * Connection::sumanddel
* *
* sums up the total bytes used * sums up the total bytes used
* and removes 'old' packets. * and removes 'old' packets.
* *
* Returns sum of sent packages (by address) * Returns sum of sent packages (by address)
* sum of recieved packages (by address) * sum of recieved packages (by address)
*/ */
void Connection::sumanddel (timeval t, u_int32_t * recv, u_int32_t * sent) void Connection::sumanddel(timeval t, u_int32_t *recv, u_int32_t *sent) {
{ (*sent) = (*recv) = 0;
(*sent)=(*recv)=0;
*sent = sent_packets->sumanddel(t); *sent = sent_packets->sumanddel(t);
*recv = recv_packets->sumanddel(t); *recv = recv_packets->sumanddel(t);
} }

View File

@@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
#ifndef __CONNECTION_H #ifndef __CONNECTION_H
@@ -24,91 +25,82 @@
#include <iostream> #include <iostream>
#include "packet.h" #include "packet.h"
class PackListNode class PackListNode {
{
public: public:
PackListNode (Packet * m_val, PackListNode * m_next = NULL) PackListNode(Packet *m_val, PackListNode *m_next = NULL) {
{ val = m_val;
val = m_val; next = m_next;
next = m_next; }
} ~PackListNode() {
~PackListNode () delete val;
{ if (next != NULL)
delete val; delete next;
if (next != NULL) }
delete next; PackListNode *next;
} Packet *val;
PackListNode * next;
Packet * val;
}; };
class PackList class PackList {
{
public: public:
PackList () PackList() { content = NULL; }
{ PackList(Packet *m_val) {
content = NULL; assert(m_val != NULL);
} content = new PackListNode(m_val);
PackList (Packet * m_val) }
{ ~PackList() {
assert (m_val != NULL); if (content != NULL)
content = new PackListNode(m_val); delete content;
} }
~PackList ()
{
if (content != NULL)
delete content;
}
/* sums up the total bytes used and removes 'old' packets */ /* sums up the total bytes used and removes 'old' packets */
u_int32_t sumanddel (timeval t); u_int32_t sumanddel(timeval t);
/* calling code may delete packet */
void add(Packet *p);
/* calling code may delete packet */
void add (Packet * p);
private: private:
PackListNode * content; PackListNode *content;
}; };
class Connection class Connection {
{
public: public:
/* constructs a connection, makes a copy of /* constructs a connection, makes a copy of
* the packet as 'refpacket', and adds the * the packet as 'refpacket', and adds the
* packet to the packlist */ * packet to the packlist */
/* packet may be deleted by caller */ /* packet may be deleted by caller */
Connection (Packet * packet); Connection(Packet *packet);
~Connection(); ~Connection();
/* add a packet to the packlist /* add a packet to the packlist
* will delete the packet structure * will delete the packet structure
* when it is 'merged with' (added to) another * when it is 'merged with' (added to) another
* packet * packet
*/ */
void add (Packet * packet); void add(Packet *packet);
int getLastPacket () int getLastPacket() { return lastpacket; }
{ return lastpacket; }
/* sums up the total bytes used /* sums up the total bytes used
* and removes 'old' packets. */ * and removes 'old' packets. */
void sumanddel(timeval curtime, u_int32_t * recv, u_int32_t * sent); void sumanddel(timeval curtime, u_int32_t *recv, u_int32_t *sent);
/* for checking if a packet is part of this connection */ /* for checking if a packet is part of this connection */
/* the reference packet is always *outgoing*. */ /* the reference packet is always *outgoing*. */
Packet * refpacket; Packet *refpacket;
/* total sum or sent/received bytes */
u_int32_t sumSent;
u_int32_t sumRecv;
/* total sum or sent/received bytes */
u_int32_t sumSent;
u_int32_t sumRecv;
private: private:
PackList * sent_packets; PackList *sent_packets;
PackList * recv_packets; PackList *recv_packets;
int lastpacket; int lastpacket;
}; };
/* Find the connection this packet belongs to */ /* Find the connection this packet belongs to */
/* (the calling code may free the packet afterwards) */ /* (the calling code may free the packet afterwards) */
Connection * findConnection (Packet * packet); Connection *findConnection(Packet *packet);
#endif #endif

View File

@@ -15,11 +15,11 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
#include <netinet/in.h> #include <netinet/in.h>
#include <map> #include <map>
#include <cstdio> #include <cstdio>
@@ -29,173 +29,168 @@
#include "conninode.h" #include "conninode.h"
#if defined __APPLE__ #if defined __APPLE__
#ifndef s6_addr32 #ifndef s6_addr32
#define s6_addr32 __u6_addr.__u6_addr32 #define s6_addr32 __u6_addr.__u6_addr32
#endif #endif
#endif #endif
extern local_addr * local_addrs; extern local_addr *local_addrs;
/* /*
* connection-inode table. takes information from /proc/net/tcp. * connection-inode table. takes information from /proc/net/tcp.
* key contains source ip, source port, destination ip, destination * key contains source ip, source port, destination ip, destination
* port in format: '1.2.3.4:5-1.2.3.4:5' * port in format: '1.2.3.4:5-1.2.3.4:5'
*/ */
std::map <std::string, unsigned long> conninode; std::map<std::string, unsigned long> conninode;
/* /*
* 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
* 10: 020310AC:1770 9DD8A9C3:A525 01 00000000:00000000 00:00000000 00000000 0 0 2119 1 c0f4f0c0 206 40 10 3 -1 *uid timeout inode
* 11: 020310AC:0404 936B2ECF:0747 01 00000000:00000000 00:00000000 00000000 1000 0 2109 1 c0f4fc00 368 40 20 2 -1 * 10: 020310AC:1770 9DD8A9C3:A525 01 00000000:00000000 00:00000000 00000000
*0 0 2119 1 c0f4f0c0 206 40 10 3 -1
* 11: 020310AC:0404 936B2ECF:0747 01 00000000:00000000 00:00000000 00000000
*1000 0 2109 1 c0f4fc00 368 40 20 2 -1
* *
* and of the form: * and of the form:
* 2: 0000000000000000FFFF0000020310AC:0016 0000000000000000FFFF00009DD8A9C3:A526 01 00000000:00000000 02:000A7214 00000000 0 0 2525 2 c732eca0 201 40 1 2 -1 * 2: 0000000000000000FFFF0000020310AC:0016
*0000000000000000FFFF00009DD8A9C3:A526 01 00000000:00000000 02:000A7214
*00000000 0 0 2525 2 c732eca0 201 40 1 2 -1
* *
*/ */
void addtoconninode (char * buffer) void addtoconninode(char *buffer) {
{ short int sa_family;
short int sa_family; struct in6_addr result_addr_local;
struct in6_addr result_addr_local; struct in6_addr result_addr_remote;
struct in6_addr result_addr_remote;
char rem_addr[128], local_addr[128]; char rem_addr[128], local_addr[128];
int local_port, rem_port; int local_port, rem_port;
struct in6_addr in6_local; struct in6_addr in6_local;
struct in6_addr in6_remote; struct in6_addr in6_remote;
// this leaked memory // this leaked memory
//unsigned long * inode = (unsigned long *) malloc (sizeof(unsigned long)); // unsigned long * inode = (unsigned long *) malloc (sizeof(unsigned long));
unsigned long inode; unsigned long inode;
int matches = sscanf(buffer, "%*d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %*X %*X:%*X %*X:%*X %*X %*d %*d %ld %*512s\n", int matches = sscanf(buffer, "%*d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %*X "
local_addr, &local_port, rem_addr, &rem_port, &inode); "%*X:%*X %*X:%*X %*X %*d %*d %ld %*512s\n",
local_addr, &local_port, rem_addr, &rem_port, &inode);
if (matches != 5) { if (matches != 5) {
fprintf(stderr,"Unexpected buffer: '%s'\n",buffer); fprintf(stderr, "Unexpected buffer: '%s'\n", buffer);
exit(0); exit(0);
} }
if (inode == 0) { if (inode == 0) {
/* connection is in TIME_WAIT state. We rely on /* connection is in TIME_WAIT state. We rely on
* the old data still in the table. */ * the old data still in the table. */
return; return;
} }
if (strlen(local_addr) > 8) if (strlen(local_addr) > 8) {
{ /* this is an IPv6-style row */
/* this is an IPv6-style row */
/* Demangle what the kernel gives us */ /* Demangle what the kernel gives us */
sscanf(local_addr, "%08X%08X%08X%08X", sscanf(local_addr, "%08X%08X%08X%08X", &in6_local.s6_addr32[0],
&in6_local.s6_addr32[0], &in6_local.s6_addr32[1], &in6_local.s6_addr32[1], &in6_local.s6_addr32[2],
&in6_local.s6_addr32[2], &in6_local.s6_addr32[3]); &in6_local.s6_addr32[3]);
sscanf(rem_addr, "%08X%08X%08X%08X", sscanf(rem_addr, "%08X%08X%08X%08X", &in6_remote.s6_addr32[0],
&in6_remote.s6_addr32[0], &in6_remote.s6_addr32[1], &in6_remote.s6_addr32[1], &in6_remote.s6_addr32[2],
&in6_remote.s6_addr32[2], &in6_remote.s6_addr32[3]); &in6_remote.s6_addr32[3]);
if ((in6_local.s6_addr32[0] == 0x0) && (in6_local.s6_addr32[1] == 0x0) if ((in6_local.s6_addr32[0] == 0x0) && (in6_local.s6_addr32[1] == 0x0) &&
&& (in6_local.s6_addr32[2] == 0xFFFF0000)) (in6_local.s6_addr32[2] == 0xFFFF0000)) {
{ /* IPv4-compatible address */
/* IPv4-compatible address */ result_addr_local = *((struct in6_addr *)&(in6_local.s6_addr32[3]));
result_addr_local = *((struct in6_addr*) &(in6_local.s6_addr32[3])); result_addr_remote = *((struct in6_addr *)&(in6_remote.s6_addr32[3]));
result_addr_remote = *((struct in6_addr*) &(in6_remote.s6_addr32[3])); 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; }
} } else {
} /* this is an IPv4-style row */
else sscanf(local_addr, "%X", (unsigned int *)&result_addr_local);
{ sscanf(rem_addr, "%X", (unsigned int *)&result_addr_remote);
/* this is an IPv4-style row */ sa_family = AF_INET;
sscanf(local_addr, "%X", (unsigned int *) &result_addr_local); }
sscanf(rem_addr, "%X", (unsigned int *) &result_addr_remote);
sa_family = AF_INET;
}
char * hashkey = (char *) malloc (HASHKEYSIZE * sizeof(char)); char *hashkey = (char *)malloc(HASHKEYSIZE * sizeof(char));
char * local_string = (char*) malloc (50); char *local_string = (char *)malloc(50);
char * remote_string = (char*) malloc (50); char *remote_string = (char *)malloc(50);
inet_ntop(sa_family, &result_addr_local, local_string, 49); inet_ntop(sa_family, &result_addr_local, local_string, 49);
inet_ntop(sa_family, &result_addr_remote, remote_string, 49); inet_ntop(sa_family, &result_addr_remote, remote_string, 49);
snprintf(hashkey, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d", local_string, local_port, remote_string, rem_port); snprintf(hashkey, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d", local_string,
free (local_string); local_port, remote_string, rem_port);
free(local_string);
//if (DEBUG) // if (DEBUG)
// fprintf (stderr, "Hashkey: %s\n", hashkey); // fprintf (stderr, "Hashkey: %s\n", hashkey);
//std::cout << "Adding to conninode\n" << std::endl; // std::cout << "Adding to conninode\n" << std::endl;
conninode[hashkey] = inode; conninode[hashkey] = inode;
/* 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
* 172.16.3.1 and 195.169.216.157 are the local addresses of different * 172.16.3.1 and 195.169.216.157 are the local addresses of different
* interfaces */ * interfaces */
for (class local_addr *current_local_addr = local_addrs; for (class local_addr *current_local_addr = local_addrs;
current_local_addr != NULL; current_local_addr != NULL;
current_local_addr = current_local_addr->next) { current_local_addr = current_local_addr->next) {
/* TODO maybe only add the ones with the same sa_family */ /* TODO maybe only add the ones with the same sa_family */
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",
conninode[hashkey] = inode; current_local_addr->string, local_port, remote_string, rem_port);
} conninode[hashkey] = inode;
free (hashkey); }
free (remote_string); free(hashkey);
free(remote_string);
} }
/* opens /proc/net/tcp[6] and adds its contents line by line */ /* opens /proc/net/tcp[6] and adds its contents line by line */
int addprocinfo (const char * filename) { int addprocinfo(const char *filename) {
FILE * procinfo = fopen (filename, "r"); FILE *procinfo = fopen(filename, "r");
char buffer[8192]; char buffer[8192];
if (procinfo == NULL) if (procinfo == NULL)
return 0; return 0;
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; return 1;
} }
void refreshconninode() {
/* we don't forget old mappings, just overwrite */
// delete conninode;
// conninode = new HashTable (256);
#if defined(__APPLE__)
addprocinfo("net.inet.tcp.pcblist");
#else
if (!addprocinfo("/proc/net/tcp")) {
std::cout << "Error: couldn't open /proc/net/tcp\n";
exit(0);
}
addprocinfo("/proc/net/tcp6");
#endif
// if (DEBUG)
void refreshconninode () // reviewUnknown();
{
/* we don't forget old mappings, just overwrite */
//delete conninode;
//conninode = new HashTable (256);
#if defined(__APPLE__)
addprocinfo("net.inet.tcp.pcblist");
#else
if (! addprocinfo ("/proc/net/tcp"))
{
std::cout << "Error: couldn't open /proc/net/tcp\n";
exit(0);
}
addprocinfo ("/proc/net/tcp6");
#endif
//if (DEBUG)
// reviewUnknown();
} }

View File

@@ -15,8 +15,9 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
// handling the connection->inode mapping // handling the connection->inode mapping
void refreshconninode (); void refreshconninode();

654
cui.cpp
View File

@@ -1,4 +1,4 @@
/* /*
* cui.cpp * cui.cpp
* *
* Copyright (c) 2004-2006,2008,2010,2011 Arnout Engelen * Copyright (c) 2004-2006,2008,2010,2011 Arnout Engelen
@@ -15,11 +15,11 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
/* NetHogs console UI */ /* NetHogs console UI */
#include <string> #include <string>
#include <pwd.h> #include <pwd.h>
@@ -33,14 +33,14 @@
#include "nethogs.h" #include "nethogs.h"
#include "process.h" #include "process.h"
std::string * caption; std::string *caption;
extern const char version[]; extern const char version[];
extern ProcList * processes; extern ProcList *processes;
extern timeval curtime; extern timeval curtime;
extern Process * unknowntcp; extern Process *unknowntcp;
extern Process * unknownudp; extern Process *unknownudp;
extern Process * unknownip; extern Process *unknownip;
extern bool sortRecv; extern bool sortRecv;
@@ -51,414 +51,392 @@ extern unsigned refreshcount;
#define PID_MAX 4194303 #define PID_MAX 4194303
const int COLUMN_WIDTH_PID = 7; const int COLUMN_WIDTH_PID = 7;
const int COLUMN_WIDTH_USER = 8; const int COLUMN_WIDTH_USER = 8;
const int COLUMN_WIDTH_DEV = 5; const int COLUMN_WIDTH_DEV = 5;
const int COLUMN_WIDTH_SENT = 11; const int COLUMN_WIDTH_SENT = 11;
const int COLUMN_WIDTH_RECEIVED = 11; const int COLUMN_WIDTH_RECEIVED = 11;
const int COLUMN_WIDTH_UNIT = 6; const int COLUMN_WIDTH_UNIT = 6;
const char * COLUMN_FORMAT_PID = "%7d"; const char *COLUMN_FORMAT_PID = "%7d";
const char * COLUMN_FORMAT_SENT = "%11.3f"; const char *COLUMN_FORMAT_SENT = "%11.3f";
const char * COLUMN_FORMAT_RECEIVED = "%11.3f"; const char *COLUMN_FORMAT_RECEIVED = "%11.3f";
class Line class Line {
{
public: public:
Line (const char * name, double n_recv_value, double n_sent_value, pid_t pid, uid_t uid, const char * n_devicename) Line(const char *name, double n_recv_value, double n_sent_value, pid_t pid,
{ uid_t uid, const char *n_devicename) {
assert (pid >= 0); assert(pid >= 0);
assert (pid <= PID_MAX); assert(pid <= PID_MAX);
m_name = name; m_name = name;
sent_value = n_sent_value; sent_value = n_sent_value;
recv_value = n_recv_value; recv_value = n_recv_value;
devicename = n_devicename; devicename = n_devicename;
m_pid = pid; m_pid = pid;
m_uid = uid; m_uid = uid;
assert (m_pid >= 0); assert(m_pid >= 0);
} }
void show (int row, unsigned int proglen); void show(int row, unsigned int proglen);
void log (); void log();
double sent_value;
double recv_value;
double sent_value;
double recv_value;
private: private:
const char * m_name; const char *m_name;
const char * devicename; const char *devicename;
pid_t m_pid; pid_t m_pid;
uid_t m_uid; uid_t m_uid;
}; };
#include <sstream> #include <sstream>
std::string itoa(int i) std::string itoa(int i) {
{ std::stringstream out;
std::stringstream out; out << i;
out << i; return out.str();
return out.str();
} }
/** /**
* @returns the username that corresponds to this uid * @returns the username that corresponds to this uid
*/ */
std::string uid2username (uid_t uid) std::string uid2username(uid_t uid) {
{ struct passwd *pwd = NULL;
struct passwd * pwd = NULL; errno = 0;
errno = 0;
/* points to a static memory area, should not be freed */ /* points to a static memory area, should not be freed */
pwd = getpwuid(uid); pwd = getpwuid(uid);
if (pwd == NULL) if (pwd == NULL)
if (errno == 0) if (errno == 0)
return itoa(uid); return itoa(uid);
else else
forceExit(false, "Error calling getpwuid(3) for uid %d: %d %s", uid, errno, strerror(errno)); forceExit(false, "Error calling getpwuid(3) for uid %d: %d %s", uid,
else errno, strerror(errno));
return std::string(pwd->pw_name); else
return std::string(pwd->pw_name);
} }
/** /**
* Render the provided text at the specified location, truncating if the length of the text exceeds a maximum. If the * Render the provided text at the specified location, truncating if the length
* text must be truncated, the string ".." will be rendered, followed by max_len - 2 characters of the provided text. * of the text exceeds a maximum. If the
* text must be truncated, the string ".." will be rendered, followed by max_len
* - 2 characters of the provided text.
*/ */
static void mvaddstr_truncate_leading(int row, int col, const char* str, std::size_t str_len, std::size_t max_len) static void mvaddstr_truncate_leading(int row, int col, const char *str,
{ std::size_t str_len,
if (str_len < max_len) { std::size_t max_len) {
mvaddstr(row, col, str); if (str_len < max_len) {
} else { mvaddstr(row, col, str);
mvaddstr(row, col, ".."); } else {
addnstr(str + 2, max_len - 2); mvaddstr(row, col, "..");
} addnstr(str + 2, max_len - 2);
}
} }
/** /**
* Render the provided text at the specified location, truncating if the length of the text exceeds a maximum. If the * Render the provided text at the specified location, truncating if the length
* text must be truncated, the text will be rendered up to max_len - 2 characters and then ".." will be rendered. * of the text exceeds a maximum. If the
* text must be truncated, the text will be rendered up to max_len - 2
* characters and then ".." will be rendered.
*/ */
static void mvaddstr_truncate_trailing(int row, int col, const char* str, std::size_t str_len, std::size_t max_len) static void mvaddstr_truncate_trailing(int row, int col, const char *str,
{ std::size_t str_len,
if (str_len < max_len) { std::size_t max_len) {
mvaddstr(row, col, str); if (str_len < max_len) {
} else { mvaddstr(row, col, str);
mvaddnstr(row, col, str, max_len - 2); } else {
addstr(".."); mvaddnstr(row, col, str, max_len - 2);
} addstr("..");
}
} }
void Line::show (int row, unsigned int proglen) void Line::show(int row, unsigned int proglen) {
{ assert(m_pid >= 0);
assert (m_pid >= 0); assert(m_pid <= PID_MAX);
assert (m_pid <= PID_MAX);
const int column_offset_pid = 0; const int column_offset_pid = 0;
const int column_offset_user = column_offset_pid + COLUMN_WIDTH_PID + 1; const int column_offset_user = column_offset_pid + COLUMN_WIDTH_PID + 1;
const int column_offset_program = column_offset_user + COLUMN_WIDTH_USER + 1; const int column_offset_program = column_offset_user + COLUMN_WIDTH_USER + 1;
const int column_offset_dev = column_offset_program + proglen + 2; const int column_offset_dev = column_offset_program + proglen + 2;
const int column_offset_sent = column_offset_dev + COLUMN_WIDTH_DEV + 1; const int column_offset_sent = column_offset_dev + COLUMN_WIDTH_DEV + 1;
const int column_offset_received = column_offset_sent + COLUMN_WIDTH_SENT + 1; const int column_offset_received = column_offset_sent + COLUMN_WIDTH_SENT + 1;
const int column_offset_unit = column_offset_received + COLUMN_WIDTH_RECEIVED + 1; const int column_offset_unit =
column_offset_received + COLUMN_WIDTH_RECEIVED + 1;
// PID column // PID column
if (m_pid == 0) if (m_pid == 0)
mvaddch (row, column_offset_pid + COLUMN_WIDTH_PID - 1, '?'); mvaddch(row, column_offset_pid + COLUMN_WIDTH_PID - 1, '?');
else else
mvprintw (row, column_offset_pid, COLUMN_FORMAT_PID, m_pid); mvprintw(row, column_offset_pid, COLUMN_FORMAT_PID, m_pid);
std::string username = uid2username(m_uid); std::string username = uid2username(m_uid);
mvaddstr_truncate_trailing (row, column_offset_user, username.c_str(), username.size(), COLUMN_WIDTH_USER); mvaddstr_truncate_trailing(row, column_offset_user, username.c_str(),
username.size(), COLUMN_WIDTH_USER);
mvaddstr_truncate_leading (row, column_offset_program, m_name, strlen (m_name), proglen); mvaddstr_truncate_leading(row, column_offset_program, m_name, strlen(m_name),
proglen);
mvaddstr (row, column_offset_dev, devicename); mvaddstr(row, column_offset_dev, devicename);
mvprintw (row, column_offset_sent, COLUMN_FORMAT_SENT, sent_value); mvprintw(row, column_offset_sent, COLUMN_FORMAT_SENT, sent_value);
mvprintw (row, column_offset_received, COLUMN_FORMAT_RECEIVED, recv_value); mvprintw(row, column_offset_received, COLUMN_FORMAT_RECEIVED, recv_value);
if (viewMode == VIEWMODE_KBPS) if (viewMode == VIEWMODE_KBPS) {
{ mvaddstr(row, column_offset_unit, "KB/sec");
mvaddstr (row, column_offset_unit, "KB/sec"); } else if (viewMode == VIEWMODE_TOTAL_MB) {
} mvaddstr(row, column_offset_unit, "MB ");
else if (viewMode == VIEWMODE_TOTAL_MB) } else if (viewMode == VIEWMODE_TOTAL_KB) {
{ mvaddstr(row, column_offset_unit, "KB ");
mvaddstr (row, column_offset_unit, "MB "); } else if (viewMode == VIEWMODE_TOTAL_B) {
} mvaddstr(row, column_offset_unit, "B ");
else if (viewMode == VIEWMODE_TOTAL_KB) }
{
mvaddstr (row, column_offset_unit, "KB ");
}
else if (viewMode == VIEWMODE_TOTAL_B)
{
mvaddstr (row, column_offset_unit, "B ");
}
} }
void Line::log() { void Line::log() {
std::cout << m_name << '/' << m_pid << '/' << m_uid << "\t" << sent_value << "\t" << recv_value << std::endl; std::cout << m_name << '/' << m_pid << '/' << m_uid << "\t" << sent_value
<< "\t" << recv_value << std::endl;
} }
int GreatestFirst (const void * ma, const void * mb) int GreatestFirst(const void *ma, const void *mb) {
{ Line **pa = (Line **)ma;
Line ** pa = (Line **)ma; Line **pb = (Line **)mb;
Line ** pb = (Line **)mb; Line *a = *pa;
Line * a = *pa; Line *b = *pb;
Line * b = *pb; double aValue;
double aValue; if (sortRecv) {
if (sortRecv) aValue = a->recv_value;
{ } else {
aValue = a->recv_value; aValue = a->sent_value;
} }
else
{
aValue = a->sent_value;
}
double bValue; double bValue;
if (sortRecv) if (sortRecv) {
{ bValue = b->recv_value;
bValue = b->recv_value; } else {
} bValue = b->sent_value;
else }
{
bValue = b->sent_value;
}
if (aValue > bValue) if (aValue > bValue) {
{ return -1;
return -1; }
} if (aValue == bValue) {
if (aValue == bValue) return 0;
{ }
return 0; return 1;
}
return 1;
} }
void init_ui () void init_ui() {
{ WINDOW *screen = initscr();
WINDOW * screen = initscr(); raw();
raw(); noecho();
noecho(); cbreak();
cbreak(); nodelay(screen, TRUE);
nodelay(screen, TRUE); caption = new std::string("NetHogs");
caption = new std::string ("NetHogs"); caption->append(getVersion());
caption->append(getVersion()); // caption->append(", running at ");
//caption->append(", running at ");
} }
void exit_ui () void exit_ui() {
{ clear();
clear(); endwin();
endwin(); delete caption;
delete caption;
} }
void ui_tick () void ui_tick() {
{ switch (getch()) {
switch (getch()) { case 'q':
case 'q': /* quit */
/* quit */ quit_cb(0);
quit_cb(0); break;
break; case 's':
case 's': /* sort on 'sent' */
/* sort on 'sent' */ sortRecv = false;
sortRecv = false; break;
break; case 'r':
case 'r': /* sort on 'received' */
/* sort on 'received' */ sortRecv = true;
sortRecv = true; break;
break; case 'm':
case 'm': /* switch mode: total vs kb/s */
/* switch mode: total vs kb/s */ viewMode = (viewMode + 1) % VIEWMODE_COUNT;
viewMode = (viewMode + 1) % VIEWMODE_COUNT; break;
break; }
}
} }
void show_trace(Line * lines[], int nproc) { void show_trace(Line *lines[], int nproc) {
std::cout << "\nRefreshing:\n"; std::cout << "\nRefreshing:\n";
/* print them */ /* print them */
for (int i=0; i<nproc; i++) for (int i = 0; i < nproc; i++) {
{ lines[i]->log();
lines[i]->log(); delete lines[i];
delete lines[i]; }
}
/* print the 'unknown' connections, for debugging */ /* print the 'unknown' connections, for debugging */
ConnList * curr_unknownconn = unknowntcp->connections; ConnList *curr_unknownconn = unknowntcp->connections;
while (curr_unknownconn != NULL) { while (curr_unknownconn != NULL) {
std::cout << "Unknown connection: " << std::cout << "Unknown connection: "
curr_unknownconn->getVal()->refpacket->gethashstring() << std::endl; << curr_unknownconn->getVal()->refpacket->gethashstring()
<< std::endl;
curr_unknownconn = curr_unknownconn->getNext(); curr_unknownconn = curr_unknownconn->getNext();
} }
} }
void show_ncurses(Line * lines[], int nproc) { void show_ncurses(Line *lines[], int nproc) {
int rows; // number of terminal rows int rows; // number of terminal rows
int cols; // number of terminal columns int cols; // number of terminal columns
unsigned int proglen; // max length of the "PROGRAM" column unsigned int proglen; // max length of the "PROGRAM" column
double sent_global = 0; double sent_global = 0;
double recv_global = 0; double recv_global = 0;
getmaxyx(stdscr, rows, cols); /* find the boundaries of the screeen */ getmaxyx(stdscr, rows, cols); /* find the boundaries of the screeen */
if (cols < 62) { if (cols < 62) {
clear(); clear();
mvprintw(0,0, "The terminal is too narrow! Please make it wider.\nI'll wait..."); mvprintw(0, 0,
return; "The terminal is too narrow! Please make it wider.\nI'll wait...");
} return;
}
if (cols > PROGNAME_WIDTH) cols = PROGNAME_WIDTH; if (cols > PROGNAME_WIDTH)
cols = PROGNAME_WIDTH;
proglen = cols - 55; proglen = cols - 55;
clear(); clear();
mvprintw (0, 0, "%s", caption->c_str()); mvprintw(0, 0, "%s", caption->c_str());
attron(A_REVERSE); attron(A_REVERSE);
mvprintw (2, 0, " PID USER %-*.*s DEV SENT RECEIVED ", proglen, proglen, "PROGRAM"); mvprintw(2, 0,
attroff(A_REVERSE); " PID USER %-*.*s DEV SENT RECEIVED ",
proglen, proglen, "PROGRAM");
attroff(A_REVERSE);
/* print them */ /* print them */
int i; int i;
for (i=0; i<nproc; i++) for (i = 0; i < nproc; i++) {
{ if (i + 3 < rows)
if (i+3 < rows) lines[i]->show(i + 3, proglen);
lines[i]->show(i+3, proglen); recv_global += lines[i]->recv_value;
recv_global += lines[i]->recv_value; sent_global += lines[i]->sent_value;
sent_global += lines[i]->sent_value; delete lines[i];
delete lines[i]; }
}
attron(A_REVERSE); attron(A_REVERSE);
int totalrow = std::min(rows-1, 3+1+i); int totalrow = std::min(rows - 1, 3 + 1 + i);
mvprintw (totalrow, 0, " TOTAL %-*.*s %11.3f %11.3f ", proglen, proglen, " ", sent_global, recv_global); mvprintw(totalrow, 0, " TOTAL %-*.*s %11.3f %11.3f ",
if (viewMode == VIEWMODE_KBPS) proglen, proglen, " ", sent_global, recv_global);
{ if (viewMode == VIEWMODE_KBPS) {
mvprintw (3+1+i, cols - COLUMN_WIDTH_UNIT, "KB/sec "); mvprintw(3 + 1 + i, cols - COLUMN_WIDTH_UNIT, "KB/sec ");
} else if (viewMode == VIEWMODE_TOTAL_B) { } else if (viewMode == VIEWMODE_TOTAL_B) {
mvprintw (3+1+i, cols - COLUMN_WIDTH_UNIT, "B "); mvprintw(3 + 1 + i, cols - COLUMN_WIDTH_UNIT, "B ");
} else if (viewMode == VIEWMODE_TOTAL_KB) { } else if (viewMode == VIEWMODE_TOTAL_KB) {
mvprintw (3+1+i, cols - COLUMN_WIDTH_UNIT, "KB "); mvprintw(3 + 1 + i, cols - COLUMN_WIDTH_UNIT, "KB ");
} else if (viewMode == VIEWMODE_TOTAL_MB) { } else if (viewMode == VIEWMODE_TOTAL_MB) {
mvprintw (3+1+i, cols - COLUMN_WIDTH_UNIT, "MB "); mvprintw(3 + 1 + i, cols - COLUMN_WIDTH_UNIT, "MB ");
} }
attroff(A_REVERSE); attroff(A_REVERSE);
mvprintw (totalrow+1, 0, ""); mvprintw(totalrow + 1, 0, "");
refresh(); refresh();
} }
// 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();
refreshconninode(); refreshcount++;
refreshcount++;
ProcList * curproc = processes; ProcList *curproc = processes;
ProcList * previousproc = NULL; ProcList *previousproc = NULL;
int nproc = processes->size(); int nproc = processes->size();
/* initialise to null pointers */ /* initialise to null pointers */
Line * lines [nproc]; Line *lines[nproc];
int n = 0; int n = 0;
#ifndef NDEBUG #ifndef NDEBUG
// initialise to null pointers // initialise to null pointers
for (int i = 0; i < nproc; i++) for (int i = 0; i < nproc; i++)
lines[i] = NULL; lines[i] = NULL;
#endif #endif
while (curproc != NULL) while (curproc != NULL) {
{ // walk though its connections, summing up their data, and
// walk though its connections, summing up their data, and // throwing away connections that haven't received a package
// throwing away connections that haven't received a package // in the last PROCESSTIMEOUT seconds.
// in the last PROCESSTIMEOUT seconds. assert(curproc != NULL);
assert (curproc != NULL); assert(curproc->getVal() != NULL);
assert (curproc->getVal() != NULL); assert(nproc == processes->size());
assert (nproc == processes->size());
/* remove timed-out processes (unless it's one of the the unknown process) */ /* remove timed-out processes (unless it's one of the the unknown process)
if ((curproc->getVal()->getLastPacket() + PROCESSTIMEOUT <= curtime.tv_sec) */
&& (curproc->getVal() != unknowntcp) if ((curproc->getVal()->getLastPacket() + PROCESSTIMEOUT <=
&& (curproc->getVal() != unknownudp) curtime.tv_sec) &&
&& (curproc->getVal() != unknownip)) (curproc->getVal() != unknowntcp) &&
{ (curproc->getVal() != unknownudp) && (curproc->getVal() != unknownip)) {
if (DEBUG) if (DEBUG)
std::cout << "PROC: Deleting process\n"; std::cout << "PROC: Deleting process\n";
ProcList * todelete = curproc; ProcList *todelete = curproc;
Process * p_todelete = curproc->getVal(); Process *p_todelete = curproc->getVal();
if (previousproc) if (previousproc) {
{ previousproc->next = curproc->next;
previousproc->next = curproc->next; curproc = curproc->next;
curproc = curproc->next; } else {
} else { processes = curproc->getNext();
processes = curproc->getNext(); curproc = processes;
curproc = processes; }
} delete todelete;
delete todelete; delete p_todelete;
delete p_todelete; nproc--;
nproc--; // continue;
//continue; } else {
} // add a non-timed-out process to the list of stuff to show
else float value_sent = 0, value_recv = 0;
{
// add a non-timed-out process to the list of stuff to show
float value_sent = 0,
value_recv = 0;
if (viewMode == VIEWMODE_KBPS) if (viewMode == VIEWMODE_KBPS) {
{ // std::cout << "kbps viemode" << std::endl;
//std::cout << "kbps viemode" << std::endl; curproc->getVal()->getkbps(&value_recv, &value_sent);
curproc->getVal()->getkbps (&value_recv, &value_sent); } else if (viewMode == VIEWMODE_TOTAL_KB) {
} // std::cout << "total viemode" << std::endl;
else if (viewMode == VIEWMODE_TOTAL_KB) curproc->getVal()->gettotalkb(&value_recv, &value_sent);
{ } else if (viewMode == VIEWMODE_TOTAL_MB) {
//std::cout << "total viemode" << std::endl; // std::cout << "total viemode" << std::endl;
curproc->getVal()->gettotalkb(&value_recv, &value_sent); curproc->getVal()->gettotalmb(&value_recv, &value_sent);
} } else if (viewMode == VIEWMODE_TOTAL_B) {
else if (viewMode == VIEWMODE_TOTAL_MB) // std::cout << "total viemode" << std::endl;
{ curproc->getVal()->gettotalb(&value_recv, &value_sent);
//std::cout << "total viemode" << std::endl; } else {
curproc->getVal()->gettotalmb(&value_recv, &value_sent); forceExit(false, "Invalid viewMode: %d", viewMode);
} }
else if (viewMode == VIEWMODE_TOTAL_B) uid_t uid = curproc->getVal()->getUid();
{ assert(curproc->getVal()->pid >= 0);
//std::cout << "total viemode" << std::endl; assert(n < nproc);
curproc->getVal()->gettotalb(&value_recv, &value_sent);
}
else
{
forceExit(false, "Invalid viewMode: %d", viewMode);
}
uid_t uid = curproc->getVal()->getUid();
assert (curproc->getVal()->pid >= 0);
assert (n < nproc);
lines[n] = new Line (curproc->getVal()->name, value_recv, value_sent, lines[n] =
curproc->getVal()->pid, uid, curproc->getVal()->devicename); new Line(curproc->getVal()->name, value_recv, value_sent,
previousproc = curproc; curproc->getVal()->pid, uid, curproc->getVal()->devicename);
curproc = curproc->next; previousproc = curproc;
n++; curproc = curproc->next;
n++;
#ifndef NDEBUG #ifndef NDEBUG
assert (nproc == processes->size()); assert(nproc == processes->size());
if (curproc == NULL) if (curproc == NULL)
assert (n-1 < nproc); assert(n - 1 < nproc);
else else
assert (n < nproc); assert(n < nproc);
#endif #endif
} }
} }
/* sort the accumulated lines */ /* sort the accumulated lines */
qsort (lines, nproc, sizeof(Line *), GreatestFirst); qsort(lines, nproc, sizeof(Line *), GreatestFirst);
if (tracemode || DEBUG) if (tracemode || DEBUG)
show_trace(lines, nproc); show_trace(lines, nproc);
else else
show_ncurses(lines, nproc); show_ncurses(lines, nproc);
if (refreshlimit != 0 && refreshcount >= refreshlimit) if (refreshlimit != 0 && refreshcount >= refreshlimit)
quit_cb(0); quit_cb(0);
} }

11
cui.h
View File

@@ -15,15 +15,16 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
/* NetHogs console UI */ /* NetHogs console UI */
void do_refresh (); void do_refresh();
void init_ui (); void init_ui();
void exit_ui (); void exit_ui();
/* periodically gives some CPU-time to the UI */ /* periodically gives some CPU-time to the UI */
void ui_tick (); void ui_tick();

460
decpcap.c
View File

@@ -1,4 +1,4 @@
/* /*
* decpcap.c * decpcap.c
* *
* Copyright (c) 2004-2006,2011 Arnout Engelen * Copyright (c) 2004-2006,2011 Arnout Engelen
@@ -15,11 +15,11 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
#include <net/ethernet.h> #include <net/ethernet.h>
#include <net/if.h> #include <net/if.h>
#include <netinet/in.h> #include <netinet/in.h>
@@ -34,304 +34,288 @@
/* 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_fillhandle(pcap_t * phandle) struct dp_handle *dp_fillhandle(pcap_t *phandle) {
{ struct dp_handle *retval =
struct dp_handle * retval = (struct dp_handle *) malloc (sizeof (struct dp_handle)); (struct dp_handle *)malloc(sizeof(struct dp_handle));
int i; int i;
retval->pcap_handle = phandle; retval->pcap_handle = phandle;
for (i = 0; i < dp_n_packet_types; i++) for (i = 0; i < dp_n_packet_types; i++) {
{ retval->callback[i] = NULL;
retval->callback[i] = NULL; }
}
retval->linktype = pcap_datalink(retval->pcap_handle); retval->linktype = pcap_datalink(retval->pcap_handle);
switch (retval->linktype) { switch (retval->linktype) {
case (DLT_EN10MB): case (DLT_EN10MB):
fprintf(stdout, "Ethernet link detected\n"); fprintf(stdout, "Ethernet link detected\n");
break; break;
case (DLT_PPP): case (DLT_PPP):
fprintf(stdout, "PPP link detected\n"); fprintf(stdout, "PPP link detected\n");
break; break;
case (DLT_LINUX_SLL): case (DLT_LINUX_SLL):
fprintf(stdout, "Linux Cooked Socket link detected\n"); fprintf(stdout, "Linux Cooked Socket link detected\n");
break; break;
default: default:
fprintf(stdout, "No PPP or Ethernet link: %d\n", retval->linktype); fprintf(stdout, "No PPP or Ethernet link: %d\n", retval->linktype);
// TODO maybe error? or 'other' callback? // TODO maybe error? or 'other' callback?
break; break;
} }
return retval; return retval;
} }
struct dp_handle * dp_open_offline(char * fname, char * ebuf) struct dp_handle *dp_open_offline(char *fname, char *ebuf) {
{ pcap_t *temp = pcap_open_offline(fname, ebuf);
pcap_t * temp = pcap_open_offline(fname, ebuf);
if (temp == NULL) if (temp == NULL) {
{ return NULL;
return NULL; }
}
return dp_fillhandle(temp); return dp_fillhandle(temp);
} }
struct dp_handle * dp_open_live(const char * device, int snaplen, int promisc, int to_ms, char * errbuf) struct dp_handle *dp_open_live(const char *device, int snaplen, int promisc,
{ int to_ms, char *errbuf) {
pcap_t * temp = pcap_open_live(device, snaplen, promisc, to_ms, errbuf); pcap_t *temp = pcap_open_live(device, snaplen, promisc, to_ms, errbuf);
if (temp == NULL) if (temp == NULL) {
{ return NULL;
return NULL; }
}
return dp_fillhandle(temp); return dp_fillhandle(temp);
} }
/* functions to add callbacks */ /* functions to add callbacks */
void dp_addcb (struct dp_handle * handle, enum dp_packet_type type, dp_callback callback) void dp_addcb(struct dp_handle *handle, enum dp_packet_type type,
{ dp_callback callback) {
handle->callback[type] = callback; handle->callback[type] = callback;
} }
/* functions for parsing the payloads */ /* functions for parsing the payloads */
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) {
{ int done =
int done = (handle->callback[dp_packet_tcp]) (handle->callback[dp_packet_tcp])(handle->userdata, header, packet);
(handle->userdata, header, packet); if (done)
if (done) return;
return; }
} // TODO: maybe `pass on' payload to lower-level protocol parsing
// TODO: maybe `pass on' payload to lower-level protocol parsing
} }
void dp_parse_ip (struct dp_handle * handle, const dp_header * header, const u_char * packet) void dp_parse_ip(struct dp_handle *handle, const dp_header *header,
{ const u_char *packet) {
const struct ip * ip = (struct ip *) packet; const struct ip *ip = (struct ip *)packet;
if (DP_DEBUG) if (DP_DEBUG) {
{ fprintf(stdout, "Looking at packet with length %ud\n", header->len);
fprintf(stdout, "Looking at packet with length %ud\n", header->len); }
} u_char *payload = (u_char *)packet + sizeof(struct ip);
u_char * payload = (u_char *) packet + sizeof (struct ip);
if (handle->callback[dp_packet_ip] != NULL) if (handle->callback[dp_packet_ip] != NULL) {
{ int done =
int done = (handle->callback[dp_packet_ip]) (handle->callback[dp_packet_ip])(handle->userdata, header, packet);
(handle->userdata, header, packet); if (done)
if (done) return;
return; }
} switch (ip->ip_p) {
switch (ip->ip_p) case IPPROTO_TCP:
{ dp_parse_tcp(handle, header, payload);
case IPPROTO_TCP: break;
dp_parse_tcp (handle, header, payload); default:
break; // TODO: maybe support for non-tcp IP packets
default: break;
// TODO: maybe support for non-tcp IP packets }
break;
}
} }
void dp_parse_ip6 (struct dp_handle * handle, const dp_header * header, const u_char * packet) void dp_parse_ip6(struct dp_handle *handle, const dp_header *header,
{ const u_char *packet) {
const struct ip6_hdr * ip6 = (struct ip6_hdr *) packet; const struct ip6_hdr *ip6 = (struct ip6_hdr *)packet;
u_char * payload = (u_char *) packet + sizeof (struct ip6_hdr); u_char *payload = (u_char *)packet + sizeof(struct ip6_hdr);
if (handle->callback[dp_packet_ip6] != NULL) if (handle->callback[dp_packet_ip6] != NULL) {
{ int done =
int done = (handle->callback[dp_packet_ip6]) (handle->callback[dp_packet_ip6])(handle->userdata, header, packet);
(handle->userdata, header, packet); if (done)
if (done) return;
return; }
} switch ((ip6->ip6_ctlun).ip6_un1.ip6_un1_nxt) {
switch ((ip6->ip6_ctlun).ip6_un1.ip6_un1_nxt) case IPPROTO_TCP:
{ dp_parse_tcp(handle, header, payload);
case IPPROTO_TCP: break;
dp_parse_tcp (handle, header, payload); default:
break; // TODO: maybe support for non-tcp ipv6 packets
default: break;
// TODO: maybe support for non-tcp ipv6 packets }
break;
}
} }
void dp_parse_ethernet (struct dp_handle * handle, const dp_header * header, const u_char * packet) void dp_parse_ethernet(struct dp_handle *handle, const dp_header *header,
{ const u_char *packet) {
const struct ether_header * ethernet = (struct ether_header *)packet; const struct ether_header *ethernet = (struct ether_header *)packet;
u_char * payload = (u_char *) packet + sizeof (struct ether_header); u_char *payload = (u_char *)packet + sizeof(struct ether_header);
u_int16_t protocol = 0; u_int16_t protocol = 0;
/* call handle if it exists */ /* call handle if it exists */
if (handle->callback[dp_packet_ethernet] != NULL) if (handle->callback[dp_packet_ethernet] != NULL) {
{ int done = (handle->callback[dp_packet_ethernet])(handle->userdata, header,
int done = (handle->callback[dp_packet_ethernet]) packet);
(handle->userdata, header, packet);
/* return if handle decides we're done */ /* return if handle decides we're done */
if (done) if (done)
return; return;
} }
/* parse payload */ /* parse payload */
protocol = ntohs(ethernet->ether_type); protocol = ntohs(ethernet->ether_type);
switch (protocol) switch (protocol) {
{ case ETHERTYPE_IP:
case ETHERTYPE_IP: dp_parse_ip(handle, header, payload);
dp_parse_ip (handle, header, payload); break;
break; case ETHERTYPE_IPV6:
case ETHERTYPE_IPV6: dp_parse_ip6(handle, header, payload);
dp_parse_ip6 (handle, header, payload); break;
break; default:
default: // TODO: maybe support for other protocols apart from IPv4 and IPv6
// TODO: maybe support for other protocols apart from IPv4 and IPv6 break;
break; }
}
} }
/* ppp header, i hope ;) */ /* ppp header, i hope ;) */
/* glanced from ethereal, it's 16 bytes, and the payload packet type is /* glanced from ethereal, it's 16 bytes, and the payload packet type is
* in the last 2 bytes... */ * in the last 2 bytes... */
struct ppp_header { struct ppp_header {
u_int16_t dummy1; u_int16_t dummy1;
u_int16_t dummy2; u_int16_t dummy2;
u_int16_t dummy3; u_int16_t dummy3;
u_int16_t dummy4; u_int16_t dummy4;
u_int16_t dummy5; u_int16_t dummy5;
u_int16_t dummy6; u_int16_t dummy6;
u_int16_t dummy7; u_int16_t dummy7;
u_int16_t packettype; u_int16_t packettype;
}; };
void dp_parse_ppp (struct dp_handle * handle, const dp_header * header, const u_char * packet) void dp_parse_ppp(struct dp_handle *handle, const dp_header *header,
{ const u_char *packet) {
const struct ppp_header * ppp = (struct ppp_header *) packet; const struct ppp_header *ppp = (struct ppp_header *)packet;
u_char * payload = (u_char *) packet + sizeof (struct ppp_header); u_char *payload = (u_char *)packet + sizeof(struct ppp_header);
u_int16_t protocol = 0; u_int16_t protocol = 0;
/* call handle if it exists */ /* call handle if it exists */
if (handle->callback[dp_packet_ppp] != NULL) if (handle->callback[dp_packet_ppp] != NULL) {
{ int done =
int done = (handle->callback[dp_packet_ppp]) (handle->callback[dp_packet_ppp])(handle->userdata, header, packet);
(handle->userdata, header, packet);
/* return if handle decides we're done */ /* return if handle decides we're done */
if (done) if (done)
return; return;
} }
/* parse payload */ /* parse payload */
protocol = ntohs(ppp->packettype); protocol = ntohs(ppp->packettype);
switch (protocol) switch (protocol) {
{ case ETHERTYPE_IP:
case ETHERTYPE_IP: dp_parse_ip(handle, header, payload);
dp_parse_ip (handle, header, payload); break;
break; case ETHERTYPE_IPV6:
case ETHERTYPE_IPV6: dp_parse_ip6(handle, header, payload);
dp_parse_ip6 (handle, header, payload); break;
break; default:
default: // TODO: support for other than IPv4 and IPv6
// TODO: support for other than IPv4 and IPv6 break;
break; }
}
} }
/* linux cooked header, i hope ;) */ /* linux cooked header, i hope ;) */
/* glanced from libpcap/ssl.h */ /* glanced from libpcap/ssl.h */
#define SLL_ADDRLEN 8 /* length of address field */ #define SLL_ADDRLEN 8 /* length of address field */
struct sll_header { struct sll_header {
u_int16_t sll_pkttype; /* packet type */ u_int16_t sll_pkttype; /* packet type */
u_int16_t sll_hatype; /* link-layer address type */ u_int16_t sll_hatype; /* link-layer address type */
u_int16_t sll_halen; /* link-layer address length */ u_int16_t sll_halen; /* link-layer address length */
u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */
u_int16_t sll_protocol; /* protocol */ u_int16_t sll_protocol; /* protocol */
}; };
void dp_parse_linux_cooked (struct dp_handle * handle, const dp_header * header, const u_char * packet) void dp_parse_linux_cooked(struct dp_handle *handle, const dp_header *header,
{ const u_char *packet) {
const struct sll_header * sll = (struct sll_header *) packet; const struct sll_header *sll = (struct sll_header *)packet;
u_char * payload = (u_char *) packet + sizeof (struct sll_header); u_char *payload = (u_char *)packet + sizeof(struct sll_header);
u_int16_t protocol = 0; u_int16_t protocol = 0;
/* call handle if it exists */ /* call handle if it exists */
if (handle->callback[dp_packet_sll] != NULL) if (handle->callback[dp_packet_sll] != NULL) {
{ int done =
int done = (handle->callback[dp_packet_sll]) (handle->callback[dp_packet_sll])(handle->userdata, header, packet);
(handle->userdata, header, packet);
/* return if handle decides we're done */ /* return if handle decides we're done */
if (done) if (done)
return; return;
} }
/* parse payload */ /* parse payload */
protocol = ntohs(sll->sll_protocol); protocol = ntohs(sll->sll_protocol);
switch (protocol) switch (protocol) {
{ case ETHERTYPE_IP:
case ETHERTYPE_IP: dp_parse_ip(handle, header, payload);
dp_parse_ip (handle, header, payload); break;
break; case ETHERTYPE_IPV6:
case ETHERTYPE_IPV6: dp_parse_ip6(handle, header, payload);
dp_parse_ip6 (handle, header, payload); break;
break; default:
default: // TODO: support for other than IPv4 / IPv6
// TODO: support for other than IPv4 / IPv6 break;
break; }
}
} }
/* functions to do the monitoring */ /* functions to do the monitoring */
void dp_pcap_callback (u_char * u_handle, const struct pcap_pkthdr * header, const u_char * packet) void dp_pcap_callback(u_char *u_handle, const struct pcap_pkthdr *header,
{ const u_char *packet) {
struct dp_handle * handle = (struct dp_handle *) u_handle; struct dp_handle *handle = (struct dp_handle *)u_handle;
struct dp_header; struct dp_header;
/* make a copy of the userdata for every packet */ /* make a copy of the userdata for every packet */
u_char * userdata_copy = (u_char *) malloc (handle->userdata_size); u_char *userdata_copy = (u_char *)malloc(handle->userdata_size);
memcpy (userdata_copy, handle->userdata, handle->userdata_size); memcpy(userdata_copy, handle->userdata, handle->userdata_size);
switch (handle->linktype) { switch (handle->linktype) {
case (DLT_EN10MB): case (DLT_EN10MB):
dp_parse_ethernet (handle, header, packet); dp_parse_ethernet(handle, header, packet);
break; break;
case (DLT_PPP): case (DLT_PPP):
dp_parse_ppp (handle, header, packet); dp_parse_ppp(handle, header, packet);
break; break;
case (DLT_LINUX_SLL): case (DLT_LINUX_SLL):
dp_parse_linux_cooked (handle, header, packet); dp_parse_linux_cooked(handle, header, packet);
break; break;
case (DLT_RAW): case (DLT_RAW):
case (DLT_NULL): case (DLT_NULL):
// hope for the best // hope for the best
dp_parse_ip (handle, header, packet); dp_parse_ip(handle, header, packet);
break; break;
default: default:
fprintf(stdout, "Unknown linktype %d", handle->linktype); fprintf(stdout, "Unknown linktype %d", handle->linktype);
break; break;
} }
free (userdata_copy); free(userdata_copy);
} }
int dp_dispatch (struct dp_handle * handle, int count, u_char *user, int size) { int dp_dispatch(struct dp_handle *handle, int count, u_char *user, int size) {
handle->userdata = user; handle->userdata = user;
handle->userdata_size = size; handle->userdata_size = size;
return pcap_dispatch (handle->pcap_handle, count, dp_pcap_callback, (u_char *)handle); return pcap_dispatch(handle->pcap_handle, count, dp_pcap_callback,
(u_char *)handle);
} }
int dp_setnonblock (struct dp_handle * handle, int i, char * errbuf) { int dp_setnonblock(struct dp_handle *handle, int i, char *errbuf) {
return pcap_setnonblock (handle->pcap_handle, i, errbuf); return pcap_setnonblock(handle->pcap_handle, i, errbuf);
} }
char * dp_geterr (struct dp_handle * handle) char *dp_geterr(struct dp_handle *handle) {
{ return pcap_geterr(handle->pcap_handle);
return pcap_geterr (handle->pcap_handle);
} }

View File

@@ -1,4 +1,4 @@
/* /*
* decpcap.h * decpcap.h
* *
* Copyright (c) 2004-2006,2011 Arnout Engelen * Copyright (c) 2004-2006,2011 Arnout Engelen
@@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
#ifndef __DECPCAP_H #ifndef __DECPCAP_H
@@ -30,20 +31,20 @@
/* definitions */ /* definitions */
enum dp_packet_type { enum dp_packet_type {
dp_packet_ethernet, dp_packet_ethernet,
dp_packet_ppp, dp_packet_ppp,
dp_packet_sll, dp_packet_sll,
dp_packet_ip, dp_packet_ip,
dp_packet_ip6, dp_packet_ip6,
dp_packet_tcp, dp_packet_tcp,
dp_packet_udp, dp_packet_udp,
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 {
@@ -54,36 +55,38 @@ typedef struct pcap_pkthdr dp_header;
typedef int (*dp_callback)(u_char *, const dp_header *, const u_char *); 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];
int 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(const char * device, int snaplen, int promisc, int to_ms, char * errbuf); struct dp_handle *dp_open_live(const char *device, int snaplen, int promisc,
struct dp_handle * dp_open_offline(char * fname, char * ebuf); int to_ms, char *errbuf);
struct dp_handle *dp_open_offline(char *fname, char *ebuf);
/* functions to add callbacks */ /* functions to add callbacks */
void dp_addcb (struct dp_handle * handle, enum dp_packet_type type, dp_callback callback); void dp_addcb(struct dp_handle *handle, enum dp_packet_type type,
dp_callback callback);
/* functions to parse payloads */ /* functions to parse payloads */
void dp_parse (enum dp_packet_type type, void * packet); 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 */ /* functions that simply call libpcap */
int dp_datalink(struct dp_handle * handle); int dp_datalink(struct dp_handle *handle);
int dp_setnonblock (struct dp_handle * handle, int i, char * errbuf); int dp_setnonblock(struct dp_handle *handle, int i, char *errbuf);
char * dp_geterr (struct dp_handle * handle); char *dp_geterr(struct dp_handle *handle);
#endif #endif

View File

@@ -1,4 +1,4 @@
/* /*
* decpcap_test.cpp * decpcap_test.cpp
* *
* Copyright (c) 2006,2011 Arnout Engelen * Copyright (c) 2006,2011 Arnout Engelen
@@ -15,36 +15,34 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
#include <iostream> #include <iostream>
extern "C" { extern "C" {
#include "decpcap.h" #include "decpcap.h"
} }
int process_tcp (u_char * /* userdata */, const dp_header * /* header */, const u_char * /* m_packet */) { int process_tcp(u_char * /* userdata */, const dp_header * /* header */,
std::cout << "Callback for processing TCP packet called" << std::endl; const u_char * /* m_packet */) {
return 0; std::cout << "Callback for processing TCP packet called" << std::endl;
return 0;
} }
int main (int argc, char ** argv) int main(int argc, char **argv) {
{ if (argc < 2) {
if (argc < 2) std::cout << "Please, enter a filename" << std::endl;
{ }
std::cout << "Please, enter a filename" << std::endl;
}
char* errbuf = new char[DP_ERRBUF_SIZE]; char *errbuf = new char[DP_ERRBUF_SIZE];
dp_handle * newhandle = dp_open_offline(argv[1], errbuf); dp_handle *newhandle = dp_open_offline(argv[1], errbuf);
dp_addcb (newhandle, dp_packet_tcp, process_tcp); dp_addcb(newhandle, dp_packet_tcp, process_tcp);
int ret = dp_dispatch (newhandle, -1, NULL, 0); int ret = dp_dispatch(newhandle, -1, NULL, 0);
if (ret == -1) if (ret == -1) {
{ std::cout << "Error dispatching: " << dp_geterr(newhandle);
std::cout << "Error dispatching: " << dp_geterr(newhandle); }
}
} }

View File

@@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
@@ -28,69 +29,63 @@
#include <net/if.h> #include <net/if.h>
#include <ifaddrs.h> #include <ifaddrs.h>
bool selected(int devc, char** devicenames, char* devicename) { bool selected(int devc, char **devicenames, char *devicename) {
if (devc == 0) if (devc == 0)
return true; return true;
for (int i = 0; i < devc; i++) for (int i = 0; i < devc; i++)
if (strcmp(devicenames[i], devicename) == 0) if (strcmp(devicenames[i], devicename) == 0)
return true; return true;
return false; return false;
} }
bool already_seen(device* devices, char* devicename) { bool already_seen(device *devices, char *devicename) {
for (class device* current_device = devices; for (class device *current_device = devices; current_device != NULL;
current_device != NULL; current_device = current_device->next) {
current_device = current_device->next) { if (strcmp(current_device->name, devicename) == 0)
if (strcmp(current_device->name, devicename) == 0) return true;
return true; }
} return false;
return false;
} }
// The interface is up, not a loopback and running? // The interface is up, not a loopback and running?
bool up_running(int ifa_flags) { bool up_running(int ifa_flags) {
std::cout << "up: " << (ifa_flags & IFF_UP) << std::endl; std::cout << "up: " << (ifa_flags & IFF_UP) << std::endl;
return !(ifa_flags & IFF_LOOPBACK) && return !(ifa_flags & IFF_LOOPBACK) && (ifa_flags & IFF_UP) &&
(ifa_flags & IFF_UP) && (ifa_flags & IFF_RUNNING);
(ifa_flags & IFF_RUNNING);
} }
/** /**
* This function can return null, if no good interface is found * This function can return null, if no good interface is found
* When 'all' is set to 'false', the function avoids loopback interface and down/not running interfaces * When 'all' is set to 'false', the function avoids loopback interface and
* down/not running interfaces
*/ */
device * get_devices(int devc, char** devicenames, bool all) device *get_devices(int devc, char **devicenames, bool all) {
{ struct ifaddrs *ifaddr, *ifa;
struct ifaddrs *ifaddr, *ifa;
if (getifaddrs(&ifaddr) == -1) if (getifaddrs(&ifaddr) == -1) {
{ std::cerr << "Fail to get interface addresses" << std::endl;
std::cerr << "Fail to get interface addresses" << std::endl; // perror("getifaddrs");
// perror("getifaddrs"); return NULL;
return NULL; }
}
device* devices = NULL; device *devices = NULL;
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
{ if (ifa->ifa_addr == NULL)
if (ifa->ifa_addr == NULL) continue;
continue; if (!selected(devc, devicenames, ifa->ifa_name))
if (!selected(devc, devicenames, ifa->ifa_name)) continue;
continue; if (already_seen(devices, ifa->ifa_name))
if (already_seen(devices, ifa->ifa_name)) continue;
continue; if (!all && !up_running(ifa->ifa_flags))
if (!all && !up_running(ifa->ifa_flags)) continue;
continue;
devices = new device(strdup(ifa->ifa_name),devices); devices = new device(strdup(ifa->ifa_name), devices);
} }
freeifaddrs(ifaddr); freeifaddrs(ifaddr);
return devices; return devices;
} }
device * get_default_devices() { device *get_default_devices() { return get_devices(0, NULL, false); }
return get_devices(0, NULL, false);
}

View File

@@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
@@ -26,16 +27,16 @@
class device { class device {
public: public:
device (const char * m_name, device * m_next = NULL) device(const char *m_name, device *m_next = NULL) {
{ name = m_name;
name = m_name; next = m_next; next = m_next;
} }
const char * name; const char *name;
device * next; device *next;
}; };
/** get all devices that are up, running and not loopback */ /** get all devices that are up, running and not loopback */
device * get_default_devices(); device *get_default_devices();
/** /**
* Get all specified devices. * Get all specified devices.
@@ -44,6 +45,6 @@ device * get_default_devices();
* when 'all' is set, also return loopback interfaces and interfaces * when 'all' is set, also return loopback interfaces and interfaces
* that are down or not running * that are down or not running
*/ */
device * get_devices(int devc, char** devv, bool all); device *get_devices(int devc, char **devv, bool all);
#endif #endif

View File

@@ -15,11 +15,11 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
#include <sys/types.h> #include <sys/types.h>
#include <cerrno> #include <cerrno>
#include <cstring> #include <cstring>
@@ -42,212 +42,208 @@ extern bool bughuntmode;
// Not sure, but assuming there's no more PID's than go into 64 unsigned bits.. // Not sure, but assuming there's no more PID's than go into 64 unsigned bits..
const int MAX_PID_LENGTH = 20; const int MAX_PID_LENGTH = 20;
// Max length of filenames in /proc/<pid>/fd/*. These are numeric, so 10 digits seems like a safe assumption. // Max length of filenames in /proc/<pid>/fd/*. These are numeric, so 10 digits
// seems like a safe assumption.
const int MAX_FDLINK = 10; const int MAX_FDLINK = 10;
/* maps from inode to program-struct */ /* maps from inode to program-struct */
std::map <unsigned long, prg_node *> inodeproc; std::map<unsigned long, prg_node *> inodeproc;
bool is_number (const char * string) { bool is_number(const char *string) {
while (*string) { while (*string) {
if (!isdigit (*string)) if (!isdigit(*string))
return false; return false;
string++; string++;
} }
return true; return true;
} }
unsigned long str2ulong (const char * ptr) { unsigned long str2ulong(const char *ptr) {
unsigned long retval = 0; unsigned long retval = 0;
while ((*ptr >= '0') && (*ptr <= '9')) { while ((*ptr >= '0') && (*ptr <= '9')) {
retval *= 10; retval *= 10;
retval += *ptr - '0'; retval += *ptr - '0';
ptr++; ptr++;
} }
return retval; return retval;
} }
int str2int (const char * ptr) { int str2int(const char *ptr) {
int retval = 0; int retval = 0;
while ((*ptr >= '0') && (*ptr <= '9')) { while ((*ptr >= '0') && (*ptr <= '9')) {
retval *= 10; retval *= 10;
retval += *ptr - '0'; retval += *ptr - '0';
ptr++; ptr++;
} }
return retval; return retval;
} }
static std::string read_file (int fd) { static std::string read_file(int fd) {
char buf[255]; char buf[255];
std::string content; std::string content;
for (int length; (length = read(fd, buf, sizeof(buf))) > 0;) { for (int length; (length = read(fd, buf, sizeof(buf))) > 0;) {
if (length < 0) { if (length < 0) {
std::fprintf(stderr, "Error reading file: %s\n", std::strerror(errno)); std::fprintf(stderr, "Error reading file: %s\n", std::strerror(errno));
std::exit(34); std::exit(34);
} }
content.append(buf, length); content.append(buf, length);
} }
return content; return content;
} }
static std::string read_file (const char* filepath) { static std::string read_file(const char *filepath) {
int fd = open(filepath, O_RDONLY); int fd = open(filepath, O_RDONLY);
if (fd < 0) { if (fd < 0) {
std::fprintf(stderr, "Error opening %s: %s\n", filepath, std::strerror(errno)); std::fprintf(stderr, "Error opening %s: %s\n", filepath,
std::exit(3); std::strerror(errno));
return NULL; std::exit(3);
} return NULL;
}
std::string contents = read_file(fd); std::string contents = read_file(fd);
if (close(fd)) { if (close(fd)) {
std::fprintf(stderr, "Error opening %s: %s\n", filepath, std::strerror(errno)); std::fprintf(stderr, "Error opening %s: %s\n", filepath,
std::exit(34); std::strerror(errno));
} std::exit(34);
}
return contents; return contents;
} }
std::string getprogname (pid_t pid) { std::string getprogname(pid_t pid) {
const int maxfilenamelen = 14 + MAX_PID_LENGTH + 1; const int maxfilenamelen = 14 + MAX_PID_LENGTH + 1;
char filename[maxfilenamelen]; char filename[maxfilenamelen];
std::snprintf(filename, maxfilenamelen, "/proc/%d/cmdline", pid); std::snprintf(filename, maxfilenamelen, "/proc/%d/cmdline", pid);
return read_file(filename); return read_file(filename);
} }
void setnode (unsigned long inode, pid_t pid) { void setnode(unsigned long inode, pid_t pid) {
prg_node * current_value = inodeproc[inode]; prg_node *current_value = inodeproc[inode];
if (current_value == NULL || current_value->pid != pid) { if (current_value == NULL || current_value->pid != pid) {
prg_node * newnode = new prg_node; prg_node *newnode = new prg_node;
newnode->inode = inode; newnode->inode = inode;
newnode->pid = pid; newnode->pid = pid;
newnode->name = getprogname(pid); newnode->name = getprogname(pid);
inodeproc[inode] = newnode; inodeproc[inode] = newnode;
delete current_value; delete current_value;
} }
} }
void get_info_by_linkname (const char * pid, const char * linkname) { void get_info_by_linkname(const char *pid, const char *linkname) {
if (strncmp(linkname, "socket:[", 8) == 0) { if (strncmp(linkname, "socket:[", 8) == 0) {
setnode(str2ulong(linkname + 8), str2int(pid)); setnode(str2ulong(linkname + 8), str2int(pid));
} }
} }
/* updates the `inodeproc' inode-to-prg_node /* updates the `inodeproc' inode-to-prg_node
* for all inodes belonging to this PID * for all inodes belonging to this PID
* (/proc/pid/fd/42) * (/proc/pid/fd/42)
* */ * */
void get_info_for_pid(const char * pid) { void get_info_for_pid(const char *pid) {
char dirname[10 + MAX_PID_LENGTH]; char dirname[10 + MAX_PID_LENGTH];
size_t dirlen = 10 + strlen(pid); size_t dirlen = 10 + strlen(pid);
snprintf(dirname, dirlen, "/proc/%s/fd", pid); snprintf(dirname, dirlen, "/proc/%s/fd", pid);
DIR * dir = opendir(dirname); DIR *dir = opendir(dirname);
if (!dir) if (!dir) {
{ if (bughuntmode) {
if (bughuntmode) std::cout << "Couldn't open dir " << dirname << ": " << strerror(errno)
{ << "\n";
std::cout << "Couldn't open dir " << dirname << ": " << strerror(errno) << "\n"; }
} return;
return; }
}
/* walk through /proc/%s/fd/... */ /* walk through /proc/%s/fd/... */
dirent * entry; dirent *entry;
while ((entry = readdir(dir))) { while ((entry = readdir(dir))) {
if (entry->d_type != DT_LNK) if (entry->d_type != DT_LNK)
continue; continue;
//std::cout << "Looking at: " << entry->d_name << std::endl; // std::cout << "Looking at: " << entry->d_name << std::endl;
size_t fromlen = dirlen + strlen(entry->d_name) + 1; size_t fromlen = dirlen + strlen(entry->d_name) + 1;
char fromname[10 + MAX_PID_LENGTH + 1 + MAX_FDLINK]; char fromname[10 + MAX_PID_LENGTH + 1 + MAX_FDLINK];
snprintf (fromname, fromlen, "%s/%s", dirname, entry->d_name); snprintf(fromname, fromlen, "%s/%s", dirname, entry->d_name);
//std::cout << "Linking from: " << fromname << std::endl; // std::cout << "Linking from: " << fromname << std::endl;
int linklen = 80; int linklen = 80;
char linkname [linklen]; char linkname[linklen];
int usedlen = readlink(fromname, linkname, linklen-1); int usedlen = readlink(fromname, linkname, linklen - 1);
if (usedlen == -1) if (usedlen == -1) {
{ continue;
continue; }
} assert(usedlen < linklen);
assert (usedlen < linklen); linkname[usedlen] = '\0';
linkname[usedlen] = '\0'; get_info_by_linkname(pid, linkname);
get_info_by_linkname (pid, linkname); }
} closedir(dir);
closedir(dir);
} }
/* updates the `inodeproc' inode-to-prg_node mapping /* updates the `inodeproc' inode-to-prg_node mapping
* for all processes in /proc */ * for all processes in /proc */
void reread_mapping () { void reread_mapping() {
DIR * proc = opendir ("/proc"); DIR *proc = opendir("/proc");
if (proc == 0) { if (proc == 0) {
std::cerr << "Error reading /proc, neede to get inode-to-pid-maping\n"; std::cerr << "Error reading /proc, neede to get inode-to-pid-maping\n";
exit(1); exit(1);
} }
dirent * entry; dirent *entry;
while ((entry = readdir(proc))) { while ((entry = readdir(proc))) {
if (entry->d_type != DT_DIR) continue; if (entry->d_type != DT_DIR)
continue;
if (! is_number (entry->d_name)) continue; if (!is_number(entry->d_name))
continue;
get_info_for_pid(entry->d_name); get_info_for_pid(entry->d_name);
} }
closedir(proc); closedir(proc);
} }
struct prg_node * findPID (unsigned long inode) struct prg_node *findPID(unsigned long inode) {
{ /* we first look in inodeproc */
/* we first look in inodeproc */ struct prg_node *node = inodeproc[inode];
struct prg_node * node = inodeproc[inode];
if (node != NULL) if (node != NULL) {
{ if (bughuntmode) {
if (bughuntmode) std::cout << ":) Found pid in inodeproc table" << std::endl;
{ }
std::cout << ":) Found pid in inodeproc table" << std::endl; return node;
} }
return node;
}
#ifndef __APPLE__ #ifndef __APPLE__
reread_mapping(); reread_mapping();
#endif #endif
struct prg_node * retval = inodeproc[inode]; struct prg_node *retval = inodeproc[inode];
if (bughuntmode) if (bughuntmode) {
{ if (retval == NULL) {
if (retval == NULL) std::cout << ":( No pid after inodeproc refresh" << std::endl;
{ } else {
std::cout << ":( No pid after inodeproc refresh" << std::endl; std::cout << ":) Found pid after inodeproc refresh" << std::endl;
} }
else }
{ return retval;
std::cout << ":) Found pid after inodeproc refresh" << std::endl;
}
}
return retval;
} }
void prg_cache_clear() {}; void prg_cache_clear(){};
/*void main () { /*void main () {
std::cout << "Fooo\n"; std::cout << "Fooo\n";
reread_mapping(); reread_mapping();
std::cout << "Haihai\n"; std::cout << "Haihai\n";
}*/ }*/

View File

@@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
#ifndef __INODE2PROG_h #ifndef __INODE2PROG_h
@@ -28,16 +29,16 @@
#include "nethogs.h" #include "nethogs.h"
struct prg_node { struct prg_node {
long inode; long inode;
pid_t pid; pid_t pid;
std::string name; std::string name;
}; };
struct prg_node * findPID (unsigned long inode); struct prg_node *findPID(unsigned long inode);
void prg_cache_clear(); void prg_cache_clear();
// reread the inode-to-prg_node-mapping // reread the inode-to-prg_node-mapping
void reread_mapping (); void reread_mapping();
#endif #endif

View File

@@ -1,6 +1,5 @@
extern "C" extern "C" {
{ #include "libnethogs.h"
#include "libnethogs.h"
} }
#include "nethogs.cpp" #include "nethogs.cpp"
@@ -13,359 +12,318 @@ extern "C"
#include <errno.h> #include <errno.h>
////////////////////////////// //////////////////////////////
extern ProcList * processes; extern ProcList *processes;
extern Process * unknowntcp; extern Process *unknowntcp;
extern Process * unknownudp; extern Process *unknownudp;
extern Process * unknownip; extern Process *unknownip;
////////////////////////////// //////////////////////////////
//The self_pipe is used to interrupt the select() in the main loop // The self_pipe is used to interrupt the select() in the main loop
static std::pair<int,int> self_pipe = std::make_pair(-1, -1); static std::pair<int, int> self_pipe = std::make_pair(-1, -1);
static bool monitor_run_flag = false; static bool monitor_run_flag = false;
typedef std::map<void*, NethogsMonitorRecord> NethogsRecordMap; typedef std::map<void *, NethogsMonitorRecord> NethogsRecordMap;
static NethogsRecordMap monitor_record_map; static NethogsRecordMap monitor_record_map;
static int monitor_refresh_delay = 1; static int monitor_refresh_delay = 1;
static time_t monitor_last_refresh_time = 0; static time_t monitor_last_refresh_time = 0;
//selectable file descriptors for the main loop // selectable file descriptors for the main loop
static fd_set pc_loop_fd_set; static fd_set pc_loop_fd_set;
static std::vector<int> pc_loop_fd_list; static std::vector<int> pc_loop_fd_list;
static bool pc_loop_use_select = true; static bool pc_loop_use_select = true;
static handle * handles = NULL; static handle *handles = NULL;
static std::pair<int, int> create_self_pipe() static std::pair<int, int> create_self_pipe() {
{ int pfd[2];
int pfd[2]; if (pipe(pfd) == -1)
if (pipe(pfd) == -1) return std::make_pair(-1, -1);
return std::make_pair(-1, -1);
if (fcntl(pfd[0], F_SETFL, fcntl(pfd[0], F_GETFL) | O_NONBLOCK) == -1) if (fcntl(pfd[0], F_SETFL, fcntl(pfd[0], F_GETFL) | O_NONBLOCK) == -1)
return std::make_pair(-1, -1); return std::make_pair(-1, -1);
if (fcntl(pfd[1], F_SETFL, fcntl(pfd[1], F_GETFL) | O_NONBLOCK) == -1) if (fcntl(pfd[1], F_SETFL, fcntl(pfd[1], F_GETFL) | O_NONBLOCK) == -1)
return std::make_pair(-1, -1); return std::make_pair(-1, -1);
return std::make_pair(pfd[0], pfd[1]); return std::make_pair(pfd[0], pfd[1]);
} }
static bool wait_for_next_trigger() static bool wait_for_next_trigger() {
{ if (pc_loop_use_select) {
if( pc_loop_use_select ) FD_ZERO(&pc_loop_fd_set);
{ int nfds = 0;
FD_ZERO(&pc_loop_fd_set); for (std::vector<int>::const_iterator it = pc_loop_fd_list.begin();
int nfds = 0; it != pc_loop_fd_list.end(); ++it) {
for(std::vector<int>::const_iterator it=pc_loop_fd_list.begin(); int const fd = *it;
it != pc_loop_fd_list.end(); ++it) nfds = std::max(nfds, *it + 1);
{ FD_SET(fd, &pc_loop_fd_set);
int const fd = *it; }
nfds = std::max(nfds, *it + 1); timeval timeout = {monitor_refresh_delay, 0};
FD_SET(fd, &pc_loop_fd_set); if (select(nfds, &pc_loop_fd_set, 0, 0, &timeout) != -1) {
} if (FD_ISSET(self_pipe.first, &pc_loop_fd_set)) {
timeval timeout = {monitor_refresh_delay, 0}; return false;
if( select(nfds, &pc_loop_fd_set, 0, 0, &timeout) != -1 ) }
{ }
if( FD_ISSET(self_pipe.first, &pc_loop_fd_set) ) } else {
{ // If select() not possible, pause to prevent 100%
return false; usleep(1000);
} }
} return true;
}
else
{
// If select() not possible, pause to prevent 100%
usleep(1000);
}
return true;
} }
static int nethogsmonitor_init() static int nethogsmonitor_init() {
{ process_init();
process_init();
device * devices = get_default_devices(); device *devices = get_default_devices();
if ( devices == NULL ) if (devices == NULL) {
{ std::cerr << "No devices to monitor" << std::endl;
std::cerr << "No devices to monitor" << std::endl; return NETHOGS_STATUS_NO_DEVICE;
return NETHOGS_STATUS_NO_DEVICE; }
}
device * current_dev = devices; device *current_dev = devices;
bool promiscuous = false; bool promiscuous = false;
int nb_devices = 0; int nb_devices = 0;
int nb_failed_devices = 0; int nb_failed_devices = 0;
while (current_dev != NULL) while (current_dev != NULL) {
{ ++nb_devices;
++nb_devices;
if( !getLocal(current_dev->name, false) ) if (!getLocal(current_dev->name, false)) {
{ std::cerr << "getifaddrs failed while establishing local IP."
std::cerr << "getifaddrs failed while establishing local IP." << std::endl; << std::endl;
++nb_failed_devices; ++nb_failed_devices;
continue; continue;
} }
char errbuf[PCAP_ERRBUF_SIZE]; char errbuf[PCAP_ERRBUF_SIZE];
dp_handle * newhandle = dp_open_live(current_dev->name, BUFSIZ, promiscuous, 100, errbuf); dp_handle *newhandle =
if (newhandle != NULL) dp_open_live(current_dev->name, BUFSIZ, promiscuous, 100, errbuf);
{ if (newhandle != NULL) {
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);
dp_addcb (newhandle, dp_packet_udp, process_udp); dp_addcb(newhandle, dp_packet_udp, process_udp);
/* The following code solves sf.net bug 1019381, but is only available /* The following code solves sf.net bug 1019381, but is only available
* in newer versions (from 0.8 it seems) of libpcap * in newer versions (from 0.8 it seems) of libpcap
* *
* update: version 0.7.2, which is in debian stable now, should be ok * update: version 0.7.2, which is in debian stable now, should be ok
* also. * also.
*/ */
if (dp_setnonblock (newhandle, 1, errbuf) == -1) if (dp_setnonblock(newhandle, 1, errbuf) == -1) {
{ fprintf(stderr, "Error putting libpcap in nonblocking mode\n");
fprintf(stderr, "Error putting libpcap in nonblocking mode\n"); }
} handles = new handle(newhandle, current_dev->name, handles);
handles = new handle (newhandle, current_dev->name, handles);
if( pc_loop_use_select ) if (pc_loop_use_select) {
{ // some devices may not support pcap_get_selectable_fd
//some devices may not support pcap_get_selectable_fd int const fd = pcap_get_selectable_fd(newhandle->pcap_handle);
int const fd = pcap_get_selectable_fd(newhandle->pcap_handle); if (fd != -1) {
if( fd != -1 ) pc_loop_fd_list.push_back(fd);
{ } else {
pc_loop_fd_list.push_back(fd); pc_loop_use_select = false;
} pc_loop_fd_list.clear();
else fprintf(stderr, "failed to get selectable_fd for %s\n",
{ current_dev->name);
pc_loop_use_select = false; }
pc_loop_fd_list.clear(); }
fprintf(stderr, "failed to get selectable_fd for %s\n", current_dev->name); } else {
} fprintf(stderr, "ERROR: opening handler for device %s: %s\n",
} current_dev->name, strerror(errno));
} ++nb_failed_devices;
else }
{
fprintf(stderr, "ERROR: opening handler for device %s: %s\n", current_dev->name, strerror(errno));
++nb_failed_devices;
}
current_dev = current_dev->next; current_dev = current_dev->next;
} }
if(nb_devices == nb_failed_devices) if (nb_devices == nb_failed_devices) {
{ return NETHOGS_STATUS_FAILURE;
return NETHOGS_STATUS_FAILURE; }
}
//use the Self-Pipe trick to interrupt the select() in the main loop // use the Self-Pipe trick to interrupt the select() in the main loop
if( pc_loop_use_select ) if (pc_loop_use_select) {
{ self_pipe = create_self_pipe();
self_pipe = create_self_pipe(); if (self_pipe.first == -1 || self_pipe.second == -1) {
if( self_pipe.first == -1 || self_pipe.second == -1 ) std::cerr << "Error creating pipe file descriptors\n";
{ pc_loop_use_select = false;
std::cerr << "Error creating pipe file descriptors\n"; } else {
pc_loop_use_select = false; pc_loop_fd_list.push_back(self_pipe.first);
} }
else }
{
pc_loop_fd_list.push_back(self_pipe.first);
}
}
return NETHOGS_STATUS_OK; return NETHOGS_STATUS_OK;
} }
static void nethogsmonitor_handle_update(NethogsMonitorCallback cb) static void nethogsmonitor_handle_update(NethogsMonitorCallback cb) {
{ refreshconninode();
refreshconninode(); refreshcount++;
refreshcount++;
ProcList * curproc = processes; ProcList *curproc = processes;
ProcList * previousproc = NULL; ProcList *previousproc = NULL;
int nproc = processes->size(); int nproc = processes->size();
while (curproc != NULL) while (curproc != NULL) {
{ // walk though its connections, summing up their data, and
// walk though its connections, summing up their data, and // throwing away connections that haven't received a package
// throwing away connections that haven't received a package // in the last PROCESSTIMEOUT seconds.
// in the last PROCESSTIMEOUT seconds. assert(curproc != NULL);
assert (curproc != NULL); assert(curproc->getVal() != NULL);
assert (curproc->getVal() != NULL); assert(nproc == processes->size());
assert (nproc == processes->size());
/* remove timed-out processes (unless it's one of the the unknown process) */ /* remove timed-out processes (unless it's one of the the unknown process)
if ((curproc->getVal()->getLastPacket() + PROCESSTIMEOUT <= curtime.tv_sec) */
&& (curproc->getVal() != unknowntcp) if ((curproc->getVal()->getLastPacket() + PROCESSTIMEOUT <=
&& (curproc->getVal() != unknownudp) curtime.tv_sec) &&
&& (curproc->getVal() != unknownip)) (curproc->getVal() != unknowntcp) &&
{ (curproc->getVal() != unknownudp) && (curproc->getVal() != unknownip)) {
if (DEBUG) if (DEBUG)
std::cout << "PROC: Deleting process\n"; std::cout << "PROC: Deleting process\n";
NethogsRecordMap::iterator it = monitor_record_map.find(curproc); NethogsRecordMap::iterator it = monitor_record_map.find(curproc);
if( it != monitor_record_map.end() ) if (it != monitor_record_map.end()) {
{ NethogsMonitorRecord &data = it->second;
NethogsMonitorRecord& data = it->second; (*cb)(NETHOGS_APP_ACTION_REMOVE, &data);
(*cb)(NETHOGS_APP_ACTION_REMOVE, &data); monitor_record_map.erase(curproc);
monitor_record_map.erase(curproc); }
}
ProcList * todelete = curproc; ProcList *todelete = curproc;
Process * p_todelete = curproc->getVal(); Process *p_todelete = curproc->getVal();
if (previousproc) if (previousproc) {
{ previousproc->next = curproc->next;
previousproc->next = curproc->next; curproc = curproc->next;
curproc = curproc->next; } else {
} else processes = curproc->getNext();
{ curproc = processes;
processes = curproc->getNext(); }
curproc = processes; delete todelete;
} delete p_todelete;
delete todelete; nproc--;
delete p_todelete; // continue;
nproc--; } else {
//continue; const u_int32_t uid = curproc->getVal()->getUid();
} u_int32_t sent_bytes;
else u_int32_t recv_bytes;
{ float sent_kbs;
const u_int32_t uid = curproc->getVal()->getUid(); float recv_kbs;
u_int32_t sent_bytes; curproc->getVal()->getkbps(&recv_kbs, &sent_kbs);
u_int32_t recv_bytes; curproc->getVal()->gettotal(&recv_bytes, &sent_bytes);
float sent_kbs;
float recv_kbs;
curproc->getVal()->getkbps (&recv_kbs, &sent_kbs);
curproc->getVal()->gettotal (&recv_bytes, &sent_bytes);
//notify update // notify update
bool const new_data = (monitor_record_map.find(curproc) == monitor_record_map.end()); bool const new_data =
NethogsMonitorRecord &data = monitor_record_map[curproc]; (monitor_record_map.find(curproc) == monitor_record_map.end());
NethogsMonitorRecord &data = monitor_record_map[curproc];
bool data_change = false; bool data_change = false;
if( new_data ) if (new_data) {
{ data_change = true;
data_change = true; static int record_id = 0;
static int record_id = 0; ++record_id;
++record_id; memset(&data, 0, sizeof(data));
memset(&data, 0, sizeof(data)); data.record_id = record_id;
data.record_id = record_id; data.name = curproc->getVal()->name;
data.name = curproc->getVal()->name; data.pid = curproc->getVal()->pid;
data.pid = curproc->getVal()->pid; }
}
data.device_name = curproc->getVal()->devicename; data.device_name = curproc->getVal()->devicename;
#define NHM_UPDATE_ONE_FIELD(TO,FROM) if((TO)!=(FROM)) { TO = FROM; data_change = true; } #define NHM_UPDATE_ONE_FIELD(TO, FROM) \
if ((TO) != (FROM)) { \
TO = FROM; \
data_change = true; \
}
NHM_UPDATE_ONE_FIELD( data.uid, uid ) NHM_UPDATE_ONE_FIELD(data.uid, uid)
NHM_UPDATE_ONE_FIELD( data.sent_bytes, sent_bytes ) NHM_UPDATE_ONE_FIELD(data.sent_bytes, sent_bytes)
NHM_UPDATE_ONE_FIELD( data.recv_bytes, recv_bytes ) NHM_UPDATE_ONE_FIELD(data.recv_bytes, recv_bytes)
NHM_UPDATE_ONE_FIELD( data.sent_kbs, sent_kbs ) NHM_UPDATE_ONE_FIELD(data.sent_kbs, sent_kbs)
NHM_UPDATE_ONE_FIELD( data.recv_kbs, recv_kbs ) NHM_UPDATE_ONE_FIELD(data.recv_kbs, recv_kbs)
#undef NHM_UPDATE_ONE_FIELD #undef NHM_UPDATE_ONE_FIELD
if( data_change ) if (data_change) {
{ (*cb)(NETHOGS_APP_ACTION_SET, &data);
(*cb)(NETHOGS_APP_ACTION_SET, &data); }
}
//next // next
previousproc = curproc; previousproc = curproc;
curproc = curproc->next; curproc = curproc->next;
} }
} }
} }
static void nethogsmonitor_clean_up() static void nethogsmonitor_clean_up() {
{ // clean up
//clean up handle *current_handle = handles;
handle * current_handle = handles; while (current_handle != NULL) {
while (current_handle != NULL) pcap_close(current_handle->content->pcap_handle);
{ current_handle = current_handle->next;
pcap_close(current_handle->content->pcap_handle); }
current_handle = current_handle->next;
}
//close file descriptors // close file descriptors
for(std::vector<int>::const_iterator it=pc_loop_fd_list.begin(); for (std::vector<int>::const_iterator it = pc_loop_fd_list.begin();
it != pc_loop_fd_list.end(); ++it) it != pc_loop_fd_list.end(); ++it) {
{ close(*it);
close(*it); }
}
procclean(); procclean();
} }
int nethogsmonitor_loop(NethogsMonitorCallback cb) int nethogsmonitor_loop(NethogsMonitorCallback cb) {
{ if (monitor_run_flag) {
if( monitor_run_flag ) return NETHOGS_STATUS_FAILURE;
{ }
return NETHOGS_STATUS_FAILURE;
}
int return_value = nethogsmonitor_init(); int return_value = nethogsmonitor_init();
if( return_value != NETHOGS_STATUS_OK ) if (return_value != NETHOGS_STATUS_OK) {
{ return return_value;
return return_value; }
}
monitor_run_flag = true; monitor_run_flag = true;
struct dpargs * userdata = (dpargs *) malloc (sizeof (struct dpargs)); struct dpargs *userdata = (dpargs *)malloc(sizeof(struct dpargs));
// Main loop // Main loop
while (monitor_run_flag) while (monitor_run_flag) {
{ bool packets_read = false;
bool packets_read = false;
handle * current_handle = handles; handle *current_handle = handles;
while (current_handle != NULL) while (current_handle != NULL) {
{ userdata->device = current_handle->devicename;
userdata->device = current_handle->devicename; userdata->sa_family = AF_UNSPEC;
userdata->sa_family = AF_UNSPEC; int retval = dp_dispatch(current_handle->content, -1, (u_char *)userdata,
int retval = dp_dispatch (current_handle->content, -1, (u_char *)userdata, sizeof (struct dpargs)); sizeof(struct dpargs));
if (retval < 0) if (retval < 0) {
{ std::cerr << "Error dispatching: " << retval << std::endl;
std::cerr << "Error dispatching: " << retval << std::endl; } else if (retval != 0) {
} packets_read = true;
else if (retval != 0) } else {
{ gettimeofday(&curtime, NULL);
packets_read = true; }
} current_handle = current_handle->next;
else }
{
gettimeofday(&curtime, NULL);
}
current_handle = current_handle->next;
}
time_t const now = ::time(NULL); time_t const now = ::time(NULL);
if( monitor_last_refresh_time + monitor_refresh_delay <= now ) if (monitor_last_refresh_time + monitor_refresh_delay <= now) {
{ monitor_last_refresh_time = now;
monitor_last_refresh_time = now; nethogsmonitor_handle_update(cb);
nethogsmonitor_handle_update(cb); }
}
if (!packets_read) if (!packets_read) {
{ if (!wait_for_next_trigger()) {
if( !wait_for_next_trigger() ) break;
{ }
break; }
} }
}
}
nethogsmonitor_clean_up(); nethogsmonitor_clean_up();
return NETHOGS_STATUS_OK; return NETHOGS_STATUS_OK;
} }
void nethogsmonitor_breakloop() void nethogsmonitor_breakloop() {
{ monitor_run_flag = false;
monitor_run_flag = false; write(self_pipe.second, "x", 1);
write(self_pipe.second, "x", 1);
} }

View File

@@ -8,46 +8,51 @@ extern "C" {
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#define NETHOGS_DSO_VISIBLE __attribute__ ((visibility ("default"))) #define NETHOGS_DSO_VISIBLE __attribute__((visibility("default")))
#define NETHOGS_DSO_HIDDEN __attribute__ ((visibility ("hidden"))) #define NETHOGS_DSO_HIDDEN __attribute__((visibility("hidden")))
#define NETHOGS_APP_ACTION_SET 1 #define NETHOGS_APP_ACTION_SET 1
#define NETHOGS_APP_ACTION_REMOVE 2 #define NETHOGS_APP_ACTION_REMOVE 2
#define NETHOGS_STATUS_OK 0 #define NETHOGS_STATUS_OK 0
#define NETHOGS_STATUS_FAILURE 1 //generic error #define NETHOGS_STATUS_FAILURE 1 // generic error
#define NETHOGS_STATUS_NO_DEVICE 2 //no device foundr #define NETHOGS_STATUS_NO_DEVICE 2 // no device foundr
typedef struct NethogsMonitorRecord typedef struct NethogsMonitorRecord {
{ int record_id;
int record_id; const char *name;
const char* name; int pid;
int pid; uint32_t uid;
uint32_t uid; const char *device_name;
const char* device_name; uint32_t sent_bytes;
uint32_t sent_bytes; uint32_t recv_bytes;
uint32_t recv_bytes; float sent_kbs;
float sent_kbs; float recv_kbs;
float recv_kbs;
} NethogsMonitorRecord; } NethogsMonitorRecord;
/** /**
* @brief Defines a callback to handle updates about applications * @brief Defines a callback to handle updates about applications
* @param action NETHOGS_APP_ACTION_SET if data is beeing added or updated, * @param action NETHOGS_APP_ACTION_SET if data is beeing added or updated,
* NETHOGS_APP_ACTION_REMOVE if data is beeing removed. * NETHOGS_APP_ACTION_REMOVE if data is beeing removed.
* the record_id member is used to uniquely identify the data beeing update or removed. * the record_id member is used to uniquely identify the data beeing
* @param data a pointer to an application usage data. the pointer remains valid until * update or removed.
* the callback is called with NETHOGS_APP_ACTION_REMOVE for the same pointer. * @param data a pointer to an application usage data. the pointer remains valid
* the user should not modify the content of the structure pointed by data. * until
* the callback is called with NETHOGS_APP_ACTION_REMOVE for the same
* pointer.
* the user should not modify the content of the structure pointed by
* data.
*/ */
typedef void(*NethogsMonitorCallback)(int action, NethogsMonitorRecord const* data); typedef void (*NethogsMonitorCallback)(int action,
NethogsMonitorRecord const *data);
/** /**
* @brief Enter the process monitoring loop and reports updates using the * @brief Enter the process monitoring loop and reports updates using the
* callback provided as parameter. * callback provided as parameter.
* This call will block until nethogsmonitor_breakloop() is called or a failure occurs. * This call will block until nethogsmonitor_breakloop() is called or a failure
* @param cb A pointer to a callback function following the NethogsMonitorCallback definition * occurs.
* @param cb A pointer to a callback function following the
* NethogsMonitorCallback definition
*/ */
NETHOGS_DSO_VISIBLE int nethogsmonitor_loop(NethogsMonitorCallback cb); NETHOGS_DSO_VISIBLE int nethogsmonitor_loop(NethogsMonitorCallback cb);

477
main.cpp
View File

@@ -2,302 +2,277 @@
#include <fcntl.h> #include <fcntl.h>
#include <vector> #include <vector>
//The self_pipe is used to interrupt the select() in the main loop // The self_pipe is used to interrupt the select() in the main loop
static std::pair<int,int> self_pipe = std::make_pair(-1, -1); static std::pair<int, int> self_pipe = std::make_pair(-1, -1);
static time_t last_refresh_time = 0; static time_t last_refresh_time = 0;
//selectable file descriptors for the main loop // selectable file descriptors for the main loop
static fd_set pc_loop_fd_set; static fd_set pc_loop_fd_set;
static std::vector<int> pc_loop_fd_list; static std::vector<int> pc_loop_fd_list;
static bool pc_loop_use_select = true; static bool pc_loop_use_select = true;
static void versiondisplay(void) { std::cout << version << "\n"; }
static void versiondisplay(void) static void help(bool iserror) {
{ std::ostream &output = (iserror ? std::cerr : std::cout);
std::cout << version << "\n";
}
static void help(bool iserror) // output << "usage: nethogs [-V] [-b] [-d seconds] [-t] [-p] [-f (eth|ppp))]
{ // [device [device [device ...]]]\n";
std::ostream & output = (iserror ? std::cerr : std::cout); output << "usage: nethogs [-V] [-h] [-b] [-d seconds] [-v mode] [-c count] "
"[-t] [-p] [-s] [device [device [device ...]]]\n";
//output << "usage: nethogs [-V] [-b] [-d seconds] [-t] [-p] [-f (eth|ppp))] [device [device [device ...]]]\n"; output << " -V : prints version.\n";
output << "usage: nethogs [-V] [-h] [-b] [-d seconds] [-v mode] [-c count] [-t] [-p] [-s] [device [device [device ...]]]\n"; output << " -h : prints this help.\n";
output << " -V : prints version.\n"; output << " -b : bughunt mode - implies tracemode.\n";
output << " -h : prints this help.\n"; output << " -d : delay for update refresh rate in seconds. default "
output << " -b : bughunt mode - implies tracemode.\n"; "is 1.\n";
output << " -d : delay for update refresh rate in seconds. default is 1.\n"; output << " -v : view mode (0 = KB/s, 1 = total KB, 2 = total B, 3 "
output << " -v : view mode (0 = KB/s, 1 = total KB, 2 = total B, 3 = total MB). default is 0.\n"; "= total MB). default is 0.\n";
output << " -c : number of updates. default is 0 (unlimited).\n"; output << " -c : number of updates. default is 0 (unlimited).\n";
output << " -t : tracemode.\n"; output << " -t : tracemode.\n";
//output << " -f : format of packets on interface, default is eth.\n"; // output << " -f : format of packets on interface, default is
output << " -p : sniff in promiscious mode (not recommended).\n"; // eth.\n";
output << " -s : sort output by sent column.\n"; output << " -p : sniff in promiscious mode (not recommended).\n";
output << " -s : sort output by sent column.\n";
output << " -a : monitor all devices, even loopback/stopped ones.\n"; output << " -a : monitor all devices, even loopback/stopped ones.\n";
output << " device : device(s) to monitor. default is all interfaces up and running excluding loopback\n"; output << " device : device(s) to monitor. default is all "
output << std::endl; "interfaces up and running excluding loopback\n";
output << "When nethogs is running, press:\n"; output << std::endl;
output << " q: quit\n"; output << "When nethogs is running, press:\n";
output << " s: sort by SENT traffic\n"; output << " q: quit\n";
output << " r: sort by RECEIVE traffic\n"; output << " s: sort by SENT traffic\n";
output << " m: switch between total (KB, B, MB) and KB/s mode\n"; output << " r: sort by RECEIVE traffic\n";
output << " m: switch between total (KB, B, MB) and KB/s mode\n";
} }
void quit_cb(int /* i */) {
void quit_cb (int /* i */) if (self_pipe.second != -1) {
{ write(self_pipe.second, "x", 1);
if( self_pipe.second != -1 ) } else {
{ exit(0);
write(self_pipe.second, "x", 1); }
}
else
{
exit(0);
}
} }
void forceExit(bool success, const char *msg, ...) void forceExit(bool success, const char *msg, ...) {
{ if ((!tracemode) && (!DEBUG)) {
if ((!tracemode)&&(!DEBUG)){ exit_ui();
exit_ui(); }
}
va_list argp; va_list argp;
va_start(argp, msg); va_start(argp, msg);
vfprintf(stderr, msg, argp); vfprintf(stderr, msg, argp);
va_end(argp); va_end(argp);
std::cerr << std::endl; std::cerr << std::endl;
if (success) if (success)
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
else else
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
std::pair<int, int> create_self_pipe() std::pair<int, int> create_self_pipe() {
{ int pfd[2];
int pfd[2]; if (pipe(pfd) == -1)
if (pipe(pfd) == -1) return std::make_pair(-1, -1);
return std::make_pair(-1, -1);
if (fcntl(pfd[0], F_SETFL, fcntl(pfd[0], F_GETFL) | O_NONBLOCK) == -1) if (fcntl(pfd[0], F_SETFL, fcntl(pfd[0], F_GETFL) | O_NONBLOCK) == -1)
return std::make_pair(-1, -1); return std::make_pair(-1, -1);
if (fcntl(pfd[1], F_SETFL, fcntl(pfd[1], F_GETFL) | O_NONBLOCK) == -1) if (fcntl(pfd[1], F_SETFL, fcntl(pfd[1], F_GETFL) | O_NONBLOCK) == -1)
return std::make_pair(-1, -1); return std::make_pair(-1, -1);
return std::make_pair(pfd[0], pfd[1]); return std::make_pair(pfd[0], pfd[1]);
} }
bool wait_for_next_trigger() bool wait_for_next_trigger() {
{ if (pc_loop_use_select) {
if( pc_loop_use_select ) FD_ZERO(&pc_loop_fd_set);
{ int nfds = 0;
FD_ZERO(&pc_loop_fd_set); for (std::vector<int>::const_iterator it = pc_loop_fd_list.begin();
int nfds = 0; it != pc_loop_fd_list.end(); ++it) {
for(std::vector<int>::const_iterator it=pc_loop_fd_list.begin(); int const fd = *it;
it != pc_loop_fd_list.end(); ++it) nfds = std::max(nfds, *it + 1);
{ FD_SET(fd, &pc_loop_fd_set);
int const fd = *it; }
nfds = std::max(nfds, *it + 1); timeval timeout = {refreshdelay, 0};
FD_SET(fd, &pc_loop_fd_set); if (select(nfds, &pc_loop_fd_set, 0, 0, &timeout) != -1) {
} if (FD_ISSET(self_pipe.first, &pc_loop_fd_set)) {
timeval timeout = {refreshdelay, 0}; return false;
if( select(nfds, &pc_loop_fd_set, 0, 0, &timeout) != -1 ) }
{ }
if( FD_ISSET(self_pipe.first, &pc_loop_fd_set) ) } else {
{ // If select() not possible, pause to prevent 100%
return false; usleep(1000);
} }
} return true;
}
else
{
// If select() not possible, pause to prevent 100%
usleep(1000);
}
return true;
} }
void clean_up() {
// close file descriptors
for (std::vector<int>::const_iterator it = pc_loop_fd_list.begin();
it != pc_loop_fd_list.end(); ++it) {
close(*it);
}
void clean_up() procclean();
{ if ((!tracemode) && (!DEBUG))
//close file descriptors exit_ui();
for(std::vector<int>::const_iterator it=pc_loop_fd_list.begin();
it != pc_loop_fd_list.end(); ++it)
{
close(*it);
}
procclean();
if ((!tracemode) && (!DEBUG))
exit_ui();
} }
int main (int argc, char** argv) int main(int argc, char **argv) {
{ process_init();
process_init();
int promisc = 0; int promisc = 0;
bool all = false; bool all = false;
int opt; int opt;
while ((opt = getopt(argc, argv, "Vahbtpd:v:c:sa")) != -1) { while ((opt = getopt(argc, argv, "Vahbtpd:v:c:sa")) != -1) {
switch(opt) { switch (opt) {
case 'V': case 'V':
versiondisplay(); versiondisplay();
exit(0); exit(0);
case 'h': case 'h':
help(false); help(false);
exit(0); exit(0);
case 'b': case 'b':
bughuntmode = true; bughuntmode = true;
tracemode = true; tracemode = true;
break; break;
case 't': case 't':
tracemode = true; tracemode = true;
break; break;
case 'p': case 'p':
promisc = 1; promisc = 1;
break; break;
case 's': case 's':
sortRecv = false; sortRecv = false;
break; break;
case 'd': case 'd':
refreshdelay = atoi(optarg); refreshdelay = atoi(optarg);
break; break;
case 'v': case 'v':
viewMode = atoi(optarg) % VIEWMODE_COUNT; viewMode = atoi(optarg) % VIEWMODE_COUNT;
break; break;
case 'c': case 'c':
refreshlimit = atoi(optarg); refreshlimit = atoi(optarg);
break; break;
case 'a': case 'a':
all = true; all = true;
break; break;
default: default:
help(true); help(true);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
device * devices = get_devices(argc - optind, argv + optind, all); device *devices = get_devices(argc - optind, argv + optind, all);
if (devices == NULL) if (devices == NULL)
forceExit(false, "No devices to monitor. Use '-a' to allow monitoring loopback interfaces or devices that are not up/running"); forceExit(false, "No devices to monitor. Use '-a' to allow monitoring "
"loopback interfaces or devices that are not up/running");
if ((!tracemode) && (!DEBUG)){ if ((!tracemode) && (!DEBUG)) {
init_ui(); init_ui();
} }
if (NEEDROOT && (geteuid() != 0)) if (NEEDROOT && (geteuid() != 0))
forceExit(false, "You need to be root to run NetHogs!"); forceExit(false, "You need to be root to run NetHogs!");
//use the Self-Pipe trick to interrupt the select() in the main loop // use the Self-Pipe trick to interrupt the select() in the main loop
self_pipe = create_self_pipe(); self_pipe = create_self_pipe();
if( self_pipe.first == -1 || self_pipe.second == -1 ) if (self_pipe.first == -1 || self_pipe.second == -1) {
{ forceExit(false, "Error creating pipe file descriptors\n");
forceExit(false, "Error creating pipe file descriptors\n"); } else {
} // add the self-pipe to allow interrupting select()
else pc_loop_fd_list.push_back(self_pipe.first);
{ }
//add the self-pipe to allow interrupting select()
pc_loop_fd_list.push_back(self_pipe.first);
}
char errbuf[PCAP_ERRBUF_SIZE]; char errbuf[PCAP_ERRBUF_SIZE];
handle * handles = NULL; handle *handles = NULL;
device * current_dev = devices; device *current_dev = devices;
while (current_dev != NULL) { while (current_dev != NULL) {
if( !getLocal(current_dev->name, tracemode) ) if (!getLocal(current_dev->name, tracemode)) {
{ forceExit(false, "getifaddrs failed while establishing local IP.");
forceExit(false, "getifaddrs failed while establishing local IP."); }
}
dp_handle * newhandle = dp_open_live(current_dev->name, BUFSIZ, promisc, 100, errbuf); dp_handle *newhandle =
if (newhandle != NULL) dp_open_live(current_dev->name, BUFSIZ, promisc, 100, errbuf);
{ if (newhandle != NULL) {
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);
dp_addcb (newhandle, dp_packet_udp, process_udp); dp_addcb(newhandle, dp_packet_udp, process_udp);
/* The following code solves sf.net bug 1019381, but is only available /* The following code solves sf.net bug 1019381, but is only available
* in newer versions (from 0.8 it seems) of libpcap * in newer versions (from 0.8 it seems) of libpcap
* *
* update: version 0.7.2, which is in debian stable now, should be ok * update: version 0.7.2, which is in debian stable now, should be ok
* also. * also.
*/ */
if (dp_setnonblock (newhandle, 1, errbuf) == -1) if (dp_setnonblock(newhandle, 1, errbuf) == -1) {
{ fprintf(stderr, "Error putting libpcap in nonblocking mode\n");
fprintf(stderr, "Error putting libpcap in nonblocking mode\n"); }
} handles = new handle(newhandle, current_dev->name, handles);
handles = new handle (newhandle, current_dev->name, handles);
if( pc_loop_use_select ) if (pc_loop_use_select) {
{ // some devices may not support pcap_get_selectable_fd
//some devices may not support pcap_get_selectable_fd int const fd = pcap_get_selectable_fd(newhandle->pcap_handle);
int const fd = pcap_get_selectable_fd(newhandle->pcap_handle); if (fd != -1) {
if( fd != -1 ) pc_loop_fd_list.push_back(fd);
{ } else {
pc_loop_fd_list.push_back(fd); pc_loop_use_select = false;
} pc_loop_fd_list.clear();
else fprintf(stderr, "failed to get selectable_fd for %s\n",
{ current_dev->name);
pc_loop_use_select = false; }
pc_loop_fd_list.clear(); }
fprintf(stderr, "failed to get selectable_fd for %s\n", current_dev->name); } else {
} fprintf(stderr, "Error opening handler for device %s\n",
} current_dev->name);
} }
else
{
fprintf(stderr, "Error opening handler for device %s\n", current_dev->name);
}
current_dev = current_dev->next; current_dev = current_dev->next;
} }
signal (SIGINT, &quit_cb); signal(SIGINT, &quit_cb);
fprintf(stderr, "Waiting for first packet to arrive (see sourceforge.net bug 1019381)\n"); fprintf(
struct dpargs * userdata = (dpargs *) malloc (sizeof (struct dpargs)); stderr,
"Waiting for first packet to arrive (see sourceforge.net bug 1019381)\n");
struct dpargs *userdata = (dpargs *)malloc(sizeof(struct dpargs));
// Main loop: // Main loop:
while (1) while (1) {
{ bool packets_read = false;
bool packets_read = false;
for (handle * current_handle = handles; current_handle != NULL; current_handle = current_handle->next) for (handle *current_handle = handles; current_handle != NULL;
{ current_handle = current_handle->next) {
userdata->device = current_handle->devicename; userdata->device = current_handle->devicename;
userdata->sa_family = AF_UNSPEC; userdata->sa_family = AF_UNSPEC;
int retval = dp_dispatch (current_handle->content, -1, (u_char *)userdata, sizeof (struct dpargs)); int retval = dp_dispatch(current_handle->content, -1, (u_char *)userdata,
if (retval < 0) sizeof(struct dpargs));
std::cerr << "Error dispatching: " << retval << std::endl; if (retval < 0)
else if (retval != 0) std::cerr << "Error dispatching: " << retval << std::endl;
packets_read = true; else if (retval != 0)
} packets_read = true;
}
time_t const now = ::time(NULL); time_t const now = ::time(NULL);
if( last_refresh_time + refreshdelay <= now ) if (last_refresh_time + refreshdelay <= now) {
{ last_refresh_time = now;
last_refresh_time = now; if ((!DEBUG) && (!tracemode)) {
if ((!DEBUG)&&(!tracemode)) // handle user input
{ ui_tick();
// handle user input }
ui_tick(); do_refresh();
} }
do_refresh();
}
// if not packets, do a select() until next packet // if not packets, do a select() until next packet
if (!packets_read) if (!packets_read)
if( !wait_for_next_trigger() ) if (!wait_for_next_trigger())
// Shutdown requested - exit the loop // Shutdown requested - exit the loop
break; break;
} }
clean_up(); clean_up();
} }

View File

@@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
@@ -40,7 +41,7 @@
#include "cui.h" #include "cui.h"
extern "C" { extern "C" {
#include "decpcap.h" #include "decpcap.h"
} }
#include "packet.h" #include "packet.h"
@@ -48,7 +49,7 @@ extern "C" {
#include "process.h" #include "process.h"
#include "devices.h" #include "devices.h"
extern Process * unknownudp; extern Process *unknownudp;
unsigned refreshdelay = 1; unsigned refreshdelay = 1;
unsigned refreshlimit = 0; unsigned refreshlimit = 0;
@@ -64,178 +65,184 @@ const char version[] = " version " VERSION "." SUBVERSION "." MINORVERSION;
timeval curtime; timeval curtime;
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) && (n_addr == addr))
&& (n_addr == addr)) return true;
return true; if (next == NULL)
if (next == NULL) return false;
return false; return next->contains(n_addr);
return next->contains(n_addr);
} }
bool local_addr::contains(const struct in6_addr & n_addr) { bool local_addr::contains(const struct in6_addr &n_addr) {
if (sa_family == AF_INET6) if (sa_family == AF_INET6) {
{ /*
/* if (DEBUG) {
if (DEBUG) { char addy [50];
char addy [50]; std::cerr << "Comparing: ";
std::cerr << "Comparing: "; inet_ntop (AF_INET6, &n_addr, addy, 49);
inet_ntop (AF_INET6, &n_addr, addy, 49); std::cerr << addy << " and ";
std::cerr << addy << " and "; inet_ntop (AF_INET6, &addr6, addy, 49);
inet_ntop (AF_INET6, &addr6, addy, 49); std::cerr << addy << std::endl;
std::cerr << addy << std::endl; }
} */
*/ // if (addr6.s6_addr == n_addr.s6_addr)
//if (addr6.s6_addr == n_addr.s6_addr) if (memcmp(&addr6, &n_addr, sizeof(struct in6_addr)) == 0) {
if (memcmp (&addr6, &n_addr, sizeof(struct in6_addr)) == 0) if (DEBUG)
{ std::cerr << "Match!" << std::endl;
if (DEBUG) return true;
std::cerr << "Match!" << std::endl; }
return true; }
} if (next == NULL)
} return false;
if (next == NULL) return next->contains(n_addr);
return false;
return next->contains(n_addr);
} }
struct dpargs { struct dpargs {
const char * device; const char *device;
int sa_family; int sa_family;
in_addr ip_src; in_addr ip_src;
in_addr ip_dst; in_addr ip_dst;
in6_addr ip6_src; in6_addr ip6_src;
in6_addr ip6_dst; in6_addr ip6_dst;
}; };
const char* getVersion() const char *getVersion() { return version; }
{
return version; int process_tcp(u_char *userdata, const dp_header *header,
const u_char *m_packet) {
struct dpargs *args = (struct dpargs *)userdata;
struct tcphdr *tcp = (struct tcphdr *)m_packet;
curtime = header->ts;
/* get info from userdata, then call getPacket */
Packet *packet;
switch (args->sa_family) {
case AF_INET:
#ifdef __APPLE__
packet = new Packet(args->ip_src, ntohs(tcp->th_sport), args->ip_dst,
ntohs(tcp->th_dport), header->len, header->ts);
#else
packet = new Packet(args->ip_src, ntohs(tcp->source), args->ip_dst,
ntohs(tcp->dest), header->len, header->ts);
#endif
break;
case AF_INET6:
#ifdef __APPLE__
packet = new Packet(args->ip6_src, ntohs(tcp->th_sport), args->ip6_dst,
ntohs(tcp->th_dport), header->len, header->ts);
#else
packet = new Packet(args->ip6_src, ntohs(tcp->source), args->ip6_dst,
ntohs(tcp->dest), header->len, header->ts);
#endif
break;
default:
std::cerr << "Invalid address family for TCP packet: " << args->sa_family
<< std::endl;
return true;
}
Connection *connection = findConnection(packet);
if (connection != NULL) {
/* add packet to the connection */
connection->add(packet);
} else {
/* else: unknown connection, create new */
connection = new Connection(packet);
getProcess(connection, args->device);
}
delete packet;
/* we're done now. */
return true;
} }
int process_tcp (u_char * userdata, const dp_header * header, const u_char * m_packet) { int process_udp(u_char *userdata, const dp_header *header,
struct dpargs * args = (struct dpargs *) userdata; const u_char *m_packet) {
struct tcphdr * tcp = (struct tcphdr *) m_packet; struct dpargs *args = (struct dpargs *)userdata;
struct udphdr *udp = (struct udphdr *)m_packet;
curtime = header->ts; curtime = header->ts;
/* get info from userdata, then call getPacket */ Packet *packet;
Packet * packet; switch (args->sa_family) {
switch (args->sa_family) case AF_INET:
{ #ifdef __APPLE__
case AF_INET: packet = new Packet(args->ip_src, ntohs(udp->uh_sport), args->ip_dst,
#ifdef __APPLE__ ntohs(udp->uh_dport), header->len, header->ts);
packet = new Packet (args->ip_src, ntohs(tcp->th_sport), args->ip_dst, ntohs(tcp->th_dport), header->len, header->ts); #else
#else packet = new Packet(args->ip_src, ntohs(udp->source), args->ip_dst,
packet = new Packet (args->ip_src, ntohs(tcp->source), args->ip_dst, ntohs(tcp->dest), header->len, header->ts); ntohs(udp->dest), header->len, header->ts);
#endif #endif
break; break;
case AF_INET6: case AF_INET6:
#ifdef __APPLE__ #ifdef __APPLE__
packet = new Packet (args->ip6_src, ntohs(tcp->th_sport), args->ip6_dst, ntohs(tcp->th_dport), header->len, header->ts); packet = new Packet(args->ip6_src, ntohs(udp->uh_sport), args->ip6_dst,
#else ntohs(udp->uh_dport), header->len, header->ts);
packet = new Packet (args->ip6_src, ntohs(tcp->source), args->ip6_dst, ntohs(tcp->dest), header->len, header->ts); #else
#endif packet = new Packet(args->ip6_src, ntohs(udp->source), args->ip6_dst,
break; ntohs(udp->dest), header->len, header->ts);
default: #endif
std::cerr << "Invalid address family for TCP packet: " << args->sa_family << std::endl; break;
return true; default:
} std::cerr << "Invalid address family for UDP packet: " << args->sa_family
<< std::endl;
return true;
}
Connection * connection = findConnection(packet); // if (DEBUG)
// std::cout << "Got packet from " << packet->gethashstring() << std::endl;
if (connection != NULL) Connection *connection = findConnection(packet);
{
/* add packet to the connection */
connection->add(packet);
} else {
/* else: unknown connection, create new */
connection = new Connection (packet);
getProcess(connection, args->device);
}
delete packet;
/* we're done now. */ if (connection != NULL) {
return true; /* add packet to the connection */
connection->add(packet);
} else {
/* else: unknown connection, create new */
connection = new Connection(packet);
getProcess(connection, args->device);
}
delete packet;
/* we're done now. */
return true;
} }
int process_udp (u_char * userdata, const dp_header * header, const u_char * m_packet) { int process_ip(u_char *userdata, const dp_header * /* header */,
struct dpargs * args = (struct dpargs *) userdata; const u_char *m_packet) {
struct udphdr * udp = (struct udphdr *) m_packet; struct dpargs *args = (struct dpargs *)userdata;
struct ip *ip = (struct ip *)m_packet;
args->sa_family = AF_INET;
args->ip_src = ip->ip_src;
args->ip_dst = ip->ip_dst;
curtime = header->ts; /* we're not done yet - also parse tcp :) */
return false;
Packet * packet;
switch (args->sa_family)
{
case AF_INET:
#ifdef __APPLE__
packet = new Packet (args->ip_src, ntohs(udp->uh_sport), args->ip_dst, ntohs(udp->uh_dport), header->len, header->ts);
#else
packet = new Packet (args->ip_src, ntohs(udp->source), args->ip_dst, ntohs(udp->dest), header->len, header->ts);
#endif
break;
case AF_INET6:
#ifdef __APPLE__
packet = new Packet (args->ip6_src, ntohs(udp->uh_sport), args->ip6_dst, ntohs(udp->uh_dport), header->len, header->ts);
#else
packet = new Packet (args->ip6_src, ntohs(udp->source), args->ip6_dst, ntohs(udp->dest), header->len, header->ts);
#endif
break;
default:
std::cerr << "Invalid address family for UDP packet: " << args->sa_family << std::endl;
return true;
}
//if (DEBUG)
// std::cout << "Got packet from " << packet->gethashstring() << std::endl;
Connection * connection = findConnection(packet);
if (connection != NULL)
{
/* add packet to the connection */
connection->add(packet);
} else {
/* else: unknown connection, create new */
connection = new Connection (packet);
getProcess(connection, args->device);
}
delete packet;
/* we're done now. */
return true;
} }
int process_ip (u_char * userdata, const dp_header * /* header */, const u_char * m_packet) { int process_ip6(u_char *userdata, const dp_header * /* header */,
struct dpargs * args = (struct dpargs *) userdata; const u_char *m_packet) {
struct ip * ip = (struct ip *) m_packet; struct dpargs *args = (struct dpargs *)userdata;
args->sa_family = AF_INET; const struct ip6_hdr *ip6 = (struct ip6_hdr *)m_packet;
args->ip_src = ip->ip_src; args->sa_family = AF_INET6;
args->ip_dst = ip->ip_dst; args->ip6_src = ip6->ip6_src;
args->ip6_dst = ip6->ip6_dst;
/* we're not done yet - also parse tcp :) */ /* we're not done yet - also parse tcp :) */
return false; return false;
}
int process_ip6 (u_char * userdata, const dp_header * /* header */, const u_char * m_packet) {
struct dpargs * args = (struct dpargs *) userdata;
const struct ip6_hdr * ip6 = (struct ip6_hdr *) m_packet;
args->sa_family = AF_INET6;
args->ip6_src = ip6->ip6_src;
args->ip6_dst = ip6->ip6_dst;
/* we're not done yet - also parse tcp :) */
return false;
} }
class handle { class handle {
public: public:
handle (dp_handle * m_handle, const char * m_devicename = NULL, handle(dp_handle *m_handle, const char *m_devicename = NULL,
handle * m_next = NULL) { handle *m_next = NULL) {
content = m_handle; next = m_next; devicename = m_devicename; content = m_handle;
} next = m_next;
dp_handle * content; devicename = m_devicename;
const char * devicename; }
handle * next; dp_handle *content;
const char *devicename;
handle *next;
}; };

View File

@@ -15,11 +15,11 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
#ifndef __NETHOGS_H #ifndef __NETHOGS_H
#define __NETHOGS_H #define __NETHOGS_H
@@ -30,9 +30,9 @@
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#ifdef __APPLE__ #ifdef __APPLE__
#include <sys/malloc.h> #include <sys/malloc.h>
#else #else
#include <malloc.h> #include <malloc.h>
#endif #endif
#include <iostream> #include <iostream>
@@ -68,50 +68,48 @@
#define PROGNAME_WIDTH 512 #define PROGNAME_WIDTH 512
// viewMode: how to represent numbers // viewMode: how to represent numbers
#define VIEWMODE_KBPS 0 #define VIEWMODE_KBPS 0
#define VIEWMODE_TOTAL_KB 1 #define VIEWMODE_TOTAL_KB 1
#define VIEWMODE_TOTAL_B 2 #define VIEWMODE_TOTAL_B 2
#define VIEWMODE_TOTAL_MB 3 #define VIEWMODE_TOTAL_MB 3
#define VIEWMODE_COUNT 4 #define VIEWMODE_COUNT 4
#define NORETURN __attribute__ ((__noreturn__)) #define NORETURN __attribute__((__noreturn__))
void forceExit(bool success, const char *msg, ...) NORETURN; void forceExit(bool success, const char *msg, ...) NORETURN;
class local_addr { class local_addr {
public: public:
/* ipv4 constructor takes an in_addr_t */ /* ipv4 constructor takes an in_addr_t */
local_addr (in_addr_t m_addr, local_addr * m_next = NULL) local_addr(in_addr_t m_addr, local_addr *m_next = NULL) {
{ addr = m_addr;
addr = m_addr; next = m_next;
next = m_next; sa_family = AF_INET;
sa_family = AF_INET; string = (char *)malloc(16);
string = (char*) malloc (16); inet_ntop(AF_INET, &m_addr, string, 15);
inet_ntop (AF_INET, &m_addr, string, 15); }
} /* this constructor takes an char address[33] */
/* this constructor takes an char address[33] */ local_addr(struct in6_addr *m_addr, local_addr *m_next = NULL) {
local_addr (struct in6_addr *m_addr, local_addr * m_next = NULL) addr6 = *m_addr;
{ next = m_next;
addr6 = *m_addr; sa_family = AF_INET6;
next = m_next; string = (char *)malloc(64);
sa_family = AF_INET6; inet_ntop(AF_INET6, &m_addr, string, 63);
string = (char*) malloc (64); }
inet_ntop (AF_INET6, &m_addr, string, 63);
} bool contains(const in_addr_t &n_addr);
bool contains(const struct in6_addr &n_addr);
char *string;
local_addr *next;
bool contains (const in_addr_t & n_addr);
bool contains (const struct in6_addr & n_addr);
char * string;
local_addr * next;
private: private:
in_addr_t addr;
in_addr_t addr; struct in6_addr addr6;
struct in6_addr addr6; short int sa_family;
short int sa_family;
}; };
void quit_cb (int i); void quit_cb(int i);
const char* getVersion(); const char *getVersion();
#endif #endif

View File

@@ -15,20 +15,20 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
#include "nethogs.h" #include "nethogs.h"
#include <iostream> #include <iostream>
#include "packet.h" #include "packet.h"
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <netinet/in.h> #include <netinet/in.h>
#ifdef __APPLE__ #ifdef __APPLE__
#include <sys/malloc.h> #include <sys/malloc.h>
#else #else
#include <malloc.h> #include <malloc.h>
#endif #endif
#include <cassert> #include <cassert>
#include <net/if.h> #include <net/if.h>
@@ -39,7 +39,7 @@
#include <ifaddrs.h> #include <ifaddrs.h>
// #include "inet6.c" // #include "inet6.c"
local_addr * local_addrs = NULL; local_addr *local_addrs = NULL;
/* /*
* getLocal * getLocal
@@ -48,40 +48,39 @@ local_addr * local_addrs = NULL;
* uses getifaddrs to get addresses of this device, and adds them to the * uses getifaddrs to get addresses of this device, and adds them to the
* local_addrs-list. * local_addrs-list.
*/ */
bool getLocal (const char *device, bool tracemode) bool getLocal(const char *device, bool tracemode) {
{ struct ifaddrs *ifaddr, *ifa;
struct ifaddrs *ifaddr, *ifa; if (getifaddrs(&ifaddr) == -1) {
if(getifaddrs(&ifaddr) == -1) { return false;
return false; }
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if(ifa->ifa_addr == NULL) if (ifa->ifa_addr == NULL)
continue; continue;
if(strcmp(ifa->ifa_name, device) != 0) if (strcmp(ifa->ifa_name, device) != 0)
continue; continue;
int family = ifa->ifa_addr->sa_family; int family = ifa->ifa_addr->sa_family;
if(family == AF_INET){ if (family == AF_INET) {
struct sockaddr_in *addr = (struct sockaddr_in*)ifa->ifa_addr; struct sockaddr_in *addr = (struct sockaddr_in *)ifa->ifa_addr;
local_addrs = new local_addr(addr->sin_addr.s_addr, local_addrs); local_addrs = new local_addr(addr->sin_addr.s_addr, local_addrs);
if (tracemode || DEBUG) { if (tracemode || DEBUG) {
printf("Adding local address: %s\n", inet_ntoa(addr->sin_addr)); printf("Adding local address: %s\n", inet_ntoa(addr->sin_addr));
} }
}else if(family == AF_INET6){ } else if (family == AF_INET6) {
struct sockaddr_in6 *addr = (struct sockaddr_in6*)ifa->ifa_addr; struct sockaddr_in6 *addr = (struct sockaddr_in6 *)ifa->ifa_addr;
local_addrs = new local_addr(&addr->sin6_addr, local_addrs); local_addrs = new local_addr(&addr->sin6_addr, local_addrs);
if (tracemode || DEBUG) { if (tracemode || DEBUG) {
char host[512]; char host[512];
printf("Adding local address: %s\n", printf("Adding local address: %s\n",
inet_ntop(AF_INET6, &addr->sin6_addr, host, sizeof(host))); inet_ntop(AF_INET6, &addr->sin6_addr, host, sizeof(host)));
} }
} }
} }
return true; return true;
} }
typedef u_int32_t tcp_seq; typedef u_int32_t tcp_seq;
@@ -90,33 +89,33 @@ typedef u_int32_t tcp_seq;
/* glanced from ethereal, it's 16 bytes, and the payload packet type is /* glanced from ethereal, it's 16 bytes, and the payload packet type is
* in the last 2 bytes... */ * in the last 2 bytes... */
struct ppp_header { struct ppp_header {
u_int16_t dummy1; u_int16_t dummy1;
u_int16_t dummy2; u_int16_t dummy2;
u_int16_t dummy3; u_int16_t dummy3;
u_int16_t dummy4; u_int16_t dummy4;
u_int16_t dummy5; u_int16_t dummy5;
u_int16_t dummy6; u_int16_t dummy6;
u_int16_t dummy7; u_int16_t dummy7;
u_int16_t packettype; u_int16_t packettype;
}; };
/* TCP header */ /* TCP header */
// TODO take from elsewhere. // TODO take from elsewhere.
struct tcp_hdr { struct tcp_hdr {
u_short th_sport; /* source port */ u_short th_sport; /* source port */
u_short th_dport; /* destination port */ u_short th_dport; /* destination port */
tcp_seq th_seq; /* sequence number */ tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */ tcp_seq th_ack; /* acknowledgement number */
#if BYTE_ORDER == LITTLE_ENDIAN #if BYTE_ORDER == LITTLE_ENDIAN
u_int th_x2:4, /* (unused) */ u_int th_x2 : 4, /* (unused) */
th_off:4; /* data offset */ th_off : 4; /* data offset */
#endif #endif
#if BYTE_ORDER == BIG_ENDIAN #if BYTE_ORDER == BIG_ENDIAN
u_int th_off:4, /* data offset */ u_int th_off : 4, /* data offset */
th_x2:4; /* (unused) */ th_x2 : 4; /* (unused) */
#endif #endif
u_char th_flags; u_char th_flags;
#define TH_FIN 0x01 #define TH_FIN 0x01
#define TH_SYN 0x02 #define TH_SYN 0x02
#define TH_RST 0x04 #define TH_RST 0x04
@@ -125,157 +124,170 @@ struct tcp_hdr {
#define TH_URG 0x20 #define TH_URG 0x20
#define TH_ECE 0x40 #define TH_ECE 0x40
#define TH_CWR 0x80 #define TH_CWR 0x80
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR) #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_win; /* window */
u_short th_sum; /* checksum */ u_short th_sum; /* checksum */
u_short th_urp; /* urgent pointer */ u_short th_urp; /* urgent pointer */
}; };
Packet::Packet (in_addr m_sip, unsigned short m_sport, in_addr m_dip, unsigned short m_dport, u_int32_t m_len, timeval m_time, direction m_dir) Packet::Packet(in_addr m_sip, unsigned short m_sport, in_addr m_dip,
{ unsigned short m_dport, u_int32_t m_len, timeval m_time,
sip = m_sip; sport = m_sport; direction m_dir) {
dip = m_dip; dport = m_dport; sip = m_sip;
len = m_len; time = m_time; sport = m_sport;
dir = m_dir; sa_family = AF_INET; dip = m_dip;
hashstring = NULL; dport = m_dport;
len = m_len;
time = m_time;
dir = m_dir;
sa_family = AF_INET;
hashstring = NULL;
} }
Packet::Packet (in6_addr m_sip, unsigned short m_sport, in6_addr m_dip, unsigned short m_dport, u_int32_t m_len, timeval m_time, direction m_dir) Packet::Packet(in6_addr m_sip, unsigned short m_sport, in6_addr m_dip,
{ unsigned short m_dport, u_int32_t m_len, timeval m_time,
sip6 = m_sip; sport = m_sport; direction m_dir) {
dip6 = m_dip; dport = m_dport; sip6 = m_sip;
len = m_len; time = m_time; sport = m_sport;
dir = m_dir; sa_family = AF_INET6; dip6 = m_dip;
hashstring = NULL; dport = m_dport;
len = m_len;
time = m_time;
dir = m_dir;
sa_family = AF_INET6;
hashstring = NULL;
} }
direction invert(direction dir) { direction invert(direction dir) {
if (dir == dir_incoming) if (dir == dir_incoming)
return dir_outgoing; return dir_outgoing;
else if (dir == dir_outgoing) else if (dir == dir_outgoing)
return dir_incoming; return dir_incoming;
else else
return dir_unknown; return dir_unknown;
} }
Packet * Packet::newInverted () { Packet *Packet::newInverted() {
direction new_direction = invert(dir); direction new_direction = invert(dir);
if (sa_family == AF_INET) if (sa_family == AF_INET)
return new Packet (dip, dport, sip, sport, len, time, new_direction); return new Packet(dip, dport, sip, sport, len, time, new_direction);
else else
return new Packet (dip6, dport, sip6, sport, len, time, new_direction); return new Packet(dip6, dport, sip6, sport, len, time, new_direction);
} }
/* constructs returns a new Packet() structure with the same contents as this one */ /* constructs returns a new Packet() structure with the same contents as this
Packet::Packet (const Packet &old_packet) { * one */
sip = old_packet.sip; sport = old_packet.sport; Packet::Packet(const Packet &old_packet) {
sip6 = old_packet.sip6; sip = old_packet.sip;
dip6 = old_packet.dip6; sport = old_packet.sport;
dip = old_packet.dip; dport = old_packet.dport; sip6 = old_packet.sip6;
len = old_packet.len; time = old_packet.time; dip6 = old_packet.dip6;
sa_family = old_packet.sa_family; dip = old_packet.dip;
if (old_packet.hashstring == NULL) dport = old_packet.dport;
hashstring = NULL; len = old_packet.len;
else time = old_packet.time;
hashstring = strdup(old_packet.hashstring); sa_family = old_packet.sa_family;
dir = old_packet.dir; if (old_packet.hashstring == NULL)
hashstring = NULL;
else
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) {
{ return one.s_addr == other.s_addr;
return one.s_addr == other.s_addr;
} }
bool Packet::isOlderThan (timeval t) { bool Packet::isOlderThan(timeval t) {
std::cout << "Comparing " << time.tv_sec << " <= " << t.tv_sec << std::endl; std::cout << "Comparing " << time.tv_sec << " <= " << t.tv_sec << std::endl;
return (time.tv_sec <= t.tv_sec); return (time.tv_sec <= t.tv_sec);
} }
bool Packet::Outgoing () { bool Packet::Outgoing() {
/* must be initialised with getLocal("eth0:1");) */ /* must be initialised with getLocal("eth0:1");) */
assert (local_addrs != NULL); assert(local_addrs != NULL);
switch (dir) { switch (dir) {
case dir_outgoing: case dir_outgoing:
return true; return true;
case dir_incoming: case dir_incoming:
return false; return false;
case dir_unknown: case dir_unknown:
bool islocal; bool islocal;
if (sa_family == AF_INET) if (sa_family == AF_INET)
islocal = local_addrs->contains(sip.s_addr); islocal = local_addrs->contains(sip.s_addr);
else else
islocal = local_addrs->contains(sip6); islocal = local_addrs->contains(sip6);
if (islocal) { if (islocal) {
dir = dir_outgoing; dir = dir_outgoing;
return true; return true;
} else { } else {
if (DEBUG) { if (DEBUG) {
if (sa_family == AF_INET) if (sa_family == AF_INET)
islocal = local_addrs->contains(dip.s_addr); islocal = local_addrs->contains(dip.s_addr);
else else
islocal = local_addrs->contains(dip6); islocal = local_addrs->contains(dip6);
if (!islocal) { if (!islocal) {
std::cerr << "Neither dip nor sip are local: "; std::cerr << "Neither dip nor sip are local: ";
char addy [50]; char addy[50];
inet_ntop (AF_INET6, &sip6, addy, 49); inet_ntop(AF_INET6, &sip6, addy, 49);
std::cerr << addy << std::endl; std::cerr << addy << std::endl;
inet_ntop (AF_INET6, &dip6, addy, 49); inet_ntop(AF_INET6, &dip6, addy, 49);
std::cerr << addy << std::endl; std::cerr << addy << std::endl;
return false; return false;
} }
} }
dir = dir_incoming; dir = dir_incoming;
return false; return false;
} }
} }
return false; return false;
} }
/* returns the packet in '1.2.3.4:5-1.2.3.4:5'-form, for use in the 'conninode' table */ /* returns the packet in '1.2.3.4:5-1.2.3.4:5'-form, for use in the 'conninode'
* table */
/* '1.2.3.4' should be the local address. */ /* '1.2.3.4' should be the local address. */
/* the calling code should take care of deletion of the hash string */ /* the calling code should take care of deletion of the hash string */
char * Packet::gethashstring () char *Packet::gethashstring() {
{ if (hashstring != NULL) {
if (hashstring != NULL) return hashstring;
{ }
return hashstring;
}
hashstring = (char *) malloc (HASHKEYSIZE * sizeof(char)); hashstring = (char *)malloc(HASHKEYSIZE * sizeof(char));
char * local_string = (char *) malloc (50); char *local_string = (char *)malloc(50);
char * remote_string = (char *) malloc (50); char *remote_string = (char *)malloc(50);
if (sa_family == AF_INET) { if (sa_family == AF_INET) {
inet_ntop(sa_family, &sip, local_string, 49); inet_ntop(sa_family, &sip, local_string, 49);
inet_ntop(sa_family, &dip, remote_string, 49); inet_ntop(sa_family, &dip, remote_string, 49);
} else { } else {
inet_ntop(sa_family, &sip6, local_string, 49); inet_ntop(sa_family, &sip6, local_string, 49);
inet_ntop(sa_family, &dip6, remote_string, 49); inet_ntop(sa_family, &dip6, remote_string, 49);
} }
if (Outgoing()) { if (Outgoing()) {
snprintf(hashstring, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d", local_string, sport, remote_string, dport); snprintf(hashstring, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d",
} else { local_string, sport, remote_string, dport);
snprintf(hashstring, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d", remote_string, dport, local_string, sport); } else {
} snprintf(hashstring, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d",
free (local_string); remote_string, dport, local_string, sport);
free (remote_string); }
//if (DEBUG) free(local_string);
// std::cout << "Returning newly created hash string: " << hashstring << std::endl; free(remote_string);
return hashstring; // if (DEBUG)
// std::cout << "Returning newly created hash string: " << hashstring <<
//std::endl;
return hashstring;
} }
/* 2 packets match if they have the same /* 2 packets match if they have the same
* source and destination ports and IP's. */ * source and destination ports and IP's. */
bool Packet::match (Packet * other) bool Packet::match(Packet *other) {
{ return (sport == other->sport) && (dport == other->dport) &&
return (sport == other->sport) && (dport == other->dport) (sameinaddr(sip, other->sip)) && (sameinaddr(dip, other->dip));
&& (sameinaddr(sip, other->sip)) && (sameinaddr(dip, other->dip));
} }
bool Packet::matchSource (Packet * other) bool Packet::matchSource(Packet *other) {
{ return (sport == other->sport) && (sameinaddr(sip, other->sip));
return (sport == other->sport) && (sameinaddr(sip, other->sip));
} }

View File

@@ -1,4 +1,4 @@
/* /*
* packet.h * packet.h
* *
* Copyright (c) 2004,2006 Arnout Engelen * Copyright (c) 2004,2006 Arnout Engelen
@@ -15,11 +15,11 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
#ifndef __PACKET_H #ifndef __PACKET_H
#define __PACKET_H #define __PACKET_H
@@ -31,56 +31,54 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include "nethogs.h" #include "nethogs.h"
enum direction { enum direction { dir_unknown, dir_incoming, dir_outgoing };
dir_unknown,
dir_incoming,
dir_outgoing
};
/* To initialise this module, call getLocal with the currently /* To initialise this module, call getLocal with the currently
* monitored device (e.g. "eth0:1") */ * monitored device (e.g. "eth0:1") */
bool getLocal (const char *device, bool tracemode); bool getLocal(const char *device, bool tracemode);
class Packet class Packet {
{
public: public:
in6_addr sip6; in6_addr sip6;
in6_addr dip6; in6_addr dip6;
in_addr sip; in_addr sip;
in_addr dip; in_addr dip;
unsigned short sport; unsigned short sport;
unsigned short dport; unsigned short dport;
u_int32_t len; u_int32_t len;
timeval time; timeval time;
Packet (in_addr m_sip, unsigned short m_sport, in_addr m_dip, unsigned short m_dport, u_int32_t m_len, timeval m_time, direction dir = dir_unknown); Packet(in_addr m_sip, unsigned short m_sport, in_addr m_dip,
Packet (in6_addr m_sip, unsigned short m_sport, in6_addr m_dip, unsigned short m_dport, u_int32_t m_len, timeval m_time, direction dir = dir_unknown); unsigned short m_dport, u_int32_t m_len, timeval m_time,
/* copy constructor */ direction dir = dir_unknown);
Packet (const Packet &old); Packet(in6_addr m_sip, unsigned short m_sport, in6_addr m_dip,
~Packet () unsigned short m_dport, u_int32_t m_len, timeval m_time,
{ direction dir = dir_unknown);
if (hashstring != NULL) /* copy constructor */
{ Packet(const Packet &old);
free (hashstring); ~Packet() {
hashstring = NULL; if (hashstring != NULL) {
} free(hashstring);
} hashstring = NULL;
/* Packet (const Packet &old_packet); */ }
/* copy constructor that turns the packet around */ }
Packet * newInverted (); /* Packet (const Packet &old_packet); */
/* copy constructor that turns the packet around */
Packet *newInverted();
bool isOlderThan(timeval t); bool isOlderThan(timeval t);
/* is this packet coming from the local host? */ /* is this packet coming from the local host? */
bool Outgoing (); bool Outgoing();
bool match(Packet *other);
bool matchSource(Packet *other);
/* returns '1.2.3.4:5-1.2.3.4:6'-style string */
char *gethashstring();
bool match (Packet * other);
bool matchSource (Packet * other);
/* returns '1.2.3.4:5-1.2.3.4:6'-style string */
char * gethashstring();
private: private:
direction dir; direction dir;
short int sa_family; short int sa_family;
char * hashstring; char *hashstring;
}; };
#endif #endif

View File

@@ -15,17 +15,17 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
#include <iostream> #include <iostream>
#include <strings.h> #include <strings.h>
#include <string> #include <string>
#include <ncurses.h> #include <ncurses.h>
#ifndef __APPLE__ #ifndef __APPLE__
#include <asm/types.h> #include <asm/types.h>
#endif #endif
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@@ -47,8 +47,7 @@ extern timeval curtime;
* key contains source ip, source port, destination ip, destination * key contains source ip, source port, destination ip, destination
* port in format: '1.2.3.4:5-1.2.3.4:5' * port in format: '1.2.3.4:5-1.2.3.4:5'
*/ */
extern std::map <std::string, unsigned long> conninode; extern std::map<std::string, unsigned long> conninode;
/* this file includes: /* this file includes:
* - calls to inodeproc to get the pid that belongs to that inode * - calls to inodeproc to get the pid that belongs to that inode
@@ -61,186 +60,155 @@ extern std::map <std::string, unsigned long> conninode;
* * unknown IP traffic * * unknown IP traffic
* We must take care these never get removed from the list. * We must take care these never get removed from the list.
*/ */
Process * unknowntcp; Process *unknowntcp;
Process * unknownudp; Process *unknownudp;
Process * unknownip; Process *unknownip;
ProcList * processes; ProcList *processes;
/* We're migrating to having several `unknown' processes that are added as /* We're migrating to having several `unknown' processes that are added as
* normal processes, instead of hard-wired unknown processes. * normal processes, instead of hard-wired unknown processes.
* This mapping maps from unknown processes descriptions to processes */ * This mapping maps from unknown processes descriptions to processes */
std::map <std::string, Process*> unknownprocs; std::map<std::string, Process *> unknownprocs;
float tomb(u_int32_t bytes) { return ((double)bytes) / 1024 / 1024; }
float tokb(u_int32_t bytes) { return ((double)bytes) / 1024; }
float tomb (u_int32_t bytes) float tokbps(u_int32_t bytes) { return (((double)bytes) / PERIOD) / 1024; }
{
return ((double)bytes) / 1024 / 1024; void process_init() {
} unknowntcp = new Process(0, "", "unknown TCP");
float tokb (u_int32_t bytes) // unknownudp = new Process (0, "", "unknown UDP");
{ // unknownip = new Process (0, "", "unknown IP");
return ((double)bytes) / 1024; processes = new ProcList(unknowntcp, NULL);
// processes = new ProcList (unknownudp, processes);
// processes = new ProcList (unknownip, processes);
} }
float tokbps (u_int32_t bytes) int Process::getLastPacket() {
{ int lastpacket = 0;
return (((double)bytes) / PERIOD) / 1024; ConnList *curconn = connections;
} while (curconn != NULL) {
assert(curconn != NULL);
assert(curconn->getVal() != NULL);
void process_init () if (curconn->getVal()->getLastPacket() > lastpacket)
{ lastpacket = curconn->getVal()->getLastPacket();
unknowntcp = new Process (0, "", "unknown TCP"); curconn = curconn->getNext();
//unknownudp = new Process (0, "", "unknown UDP"); }
//unknownip = new Process (0, "", "unknown IP"); return lastpacket;
processes = new ProcList (unknowntcp, NULL);
//processes = new ProcList (unknownudp, processes);
//processes = new ProcList (unknownip, processes);
}
int Process::getLastPacket()
{
int lastpacket=0;
ConnList * curconn=connections;
while (curconn != NULL)
{
assert (curconn != NULL);
assert (curconn->getVal() != NULL);
if (curconn->getVal()->getLastPacket() > lastpacket)
lastpacket = curconn->getVal()->getLastPacket();
curconn = curconn->getNext();
}
return lastpacket;
} }
/** Get the kb/s values for this process */ /** Get the kb/s values for this process */
void Process::getkbps (float * recvd, float * sent) void Process::getkbps(float *recvd, float *sent) {
{ u_int32_t sum_sent = 0, sum_recv = 0;
u_int32_t sum_sent = 0, sum_recv = 0;
/* walk though all this process's connections, and sum /* walk though all this process's connections, and sum
* them up */ * them up */
ConnList * curconn = this->connections; ConnList *curconn = this->connections;
ConnList * previous = NULL; ConnList *previous = NULL;
while (curconn != NULL) while (curconn != NULL) {
{ if (curconn->getVal()->getLastPacket() <= curtime.tv_sec - CONNTIMEOUT) {
if (curconn->getVal()->getLastPacket() <= curtime.tv_sec - CONNTIMEOUT) /* stalled connection, remove. */
{ ConnList *todelete = curconn;
/* stalled connection, remove. */ Connection *conn_todelete = curconn->getVal();
ConnList * todelete = curconn; curconn = curconn->getNext();
Connection * conn_todelete = curconn->getVal(); if (todelete == this->connections)
curconn = curconn->getNext(); this->connections = curconn;
if (todelete == this->connections) if (previous != NULL)
this->connections = curconn; previous->setNext(curconn);
if (previous != NULL) delete (todelete);
previous->setNext(curconn); delete (conn_todelete);
delete (todelete); } else {
delete (conn_todelete); u_int32_t sent = 0, recv = 0;
} curconn->getVal()->sumanddel(curtime, &recv, &sent);
else sum_sent += sent;
{ sum_recv += recv;
u_int32_t sent = 0, recv = 0; previous = curconn;
curconn->getVal()->sumanddel(curtime, &recv, &sent); curconn = curconn->getNext();
sum_sent += sent; }
sum_recv += recv; }
previous = curconn; *recvd = tokbps(sum_recv);
curconn = curconn->getNext(); *sent = tokbps(sum_sent);
}
}
*recvd = tokbps(sum_recv);
*sent = tokbps(sum_sent);
} }
/** get total values for this process */ /** get total values for this process */
void Process::gettotal( u_int32_t * recvd, u_int32_t * sent) void Process::gettotal(u_int32_t *recvd, u_int32_t *sent) {
{ u_int32_t sum_sent = 0, sum_recv = 0;
u_int32_t sum_sent = 0, sum_recv = 0; ConnList *curconn = this->connections;
ConnList * curconn = this->connections; while (curconn != NULL) {
while (curconn != NULL) Connection *conn = curconn->getVal();
{ sum_sent += conn->sumSent;
Connection * conn = curconn->getVal(); sum_recv += conn->sumRecv;
sum_sent += conn->sumSent; curconn = curconn->getNext();
sum_recv += conn->sumRecv; }
curconn = curconn->getNext(); // std::cout << "Sum sent: " << sum_sent << std::endl;
} // std::cout << "Sum recv: " << sum_recv << std::endl;
//std::cout << "Sum sent: " << sum_sent << std::endl; *recvd = sum_recv;
//std::cout << "Sum recv: " << sum_recv << std::endl; *sent = sum_sent;
*recvd = sum_recv;
*sent = sum_sent;
} }
void Process::gettotalmb(float * recvd, float * sent) void Process::gettotalmb(float *recvd, float *sent) {
{ u_int32_t sum_sent = 0, sum_recv = 0;
u_int32_t sum_sent = 0, sum_recv = 0; gettotal(&sum_recv, &sum_sent);
gettotal(&sum_recv, &sum_sent); *recvd = tomb(sum_recv);
*recvd = tomb(sum_recv); *sent = tomb(sum_sent);
*sent = tomb(sum_sent);
} }
/** get total values for this process */ /** get total values for this process */
void Process::gettotalkb(float * recvd, float * sent) void Process::gettotalkb(float *recvd, float *sent) {
{ u_int32_t sum_sent = 0, sum_recv = 0;
u_int32_t sum_sent = 0, sum_recv = 0; gettotal(&sum_recv, &sum_sent);
gettotal(&sum_recv, &sum_sent); *recvd = tokb(sum_recv);
*recvd = tokb(sum_recv); *sent = tokb(sum_sent);
*sent = tokb(sum_sent);
} }
void Process::gettotalb(float * recvd, float * sent) void Process::gettotalb(float *recvd, float *sent) {
{ u_int32_t sum_sent = 0, sum_recv = 0;
u_int32_t sum_sent = 0, sum_recv = 0; gettotal(&sum_recv, &sum_sent);
gettotal(&sum_recv, &sum_sent); // std::cout << "Total sent: " << sum_sent << std::endl;
//std::cout << "Total sent: " << sum_sent << std::endl; *sent = sum_sent;
*sent = sum_sent; *recvd = sum_recv;
*recvd = sum_recv;
} }
Process *findProcess(struct prg_node *node) {
ProcList *current = processes;
while (current != NULL) {
Process *currentproc = current->getVal();
assert(currentproc != NULL);
Process * findProcess (struct prg_node * node) if (node->pid == currentproc->pid)
{ return current->getVal();
ProcList * current = processes; current = current->next;
while (current != NULL) }
{ return NULL;
Process * currentproc = current->getVal();
assert (currentproc != NULL);
if (node->pid == currentproc->pid)
return current->getVal();
current = current->next;
}
return NULL;
} }
/* finds process based on inode, if any */ /* finds process based on inode, if any */
/* should be done quickly after arrival of the packet, /* should be done quickly after arrival of the packet,
* otherwise findPID will be outdated */ * otherwise findPID will be outdated */
Process * findProcess (unsigned long inode) Process *findProcess(unsigned long inode) {
{ struct prg_node *node = findPID(inode);
struct prg_node * node = findPID(inode);
if (node == NULL) if (node == NULL)
return NULL; return NULL;
return findProcess (node); return findProcess(node);
} }
int ProcList::size () int ProcList::size() {
{ int i = 1;
int i=1;
if (next != NULL) if (next != NULL)
i += next->size(); i += next->size();
return i; return i;
} }
void check_all_procs () void check_all_procs() {
{ ProcList *curproc = processes;
ProcList * curproc = processes; while (curproc != NULL) {
while (curproc != NULL) curproc->getVal()->check();
{ curproc = curproc->getNext();
curproc->getVal()->check(); }
curproc = curproc->getNext();
}
} }
/* /*
@@ -248,54 +216,52 @@ void check_all_procs ()
* if the inode is not associated with any PID, return NULL * if the inode is not associated with any PID, return NULL
* 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, const char * devicename) Process *getProcess(unsigned long inode, const char *devicename) {
{ struct prg_node *node = findPID(inode);
struct prg_node * node = findPID(inode);
if (node == NULL) if (node == NULL) {
{ if (DEBUG || bughuntmode)
if (DEBUG || bughuntmode) std::cout << "No PID information for inode " << inode << std::endl;
std::cout << "No PID information for inode " << inode << std::endl; return NULL;
return NULL; }
}
Process * proc = findProcess (node); Process *proc = findProcess(node);
if (proc != NULL) if (proc != NULL)
return proc; return proc;
Process * newproc = new Process (inode, devicename, node->name.c_str()); Process *newproc = new Process(inode, devicename, node->name.c_str());
newproc->pid = node->pid; newproc->pid = node->pid;
char procdir [100]; char procdir[100];
sprintf(procdir , "/proc/%d", node->pid); sprintf(procdir, "/proc/%d", node->pid);
struct stat stats; struct stat stats;
int retval = stat(procdir, &stats); int retval = stat(procdir, &stats);
/* 0 seems a proper default. /* 0 seems a proper default.
* used in case the PID disappeared while nethogs was running * used in case the PID disappeared while nethogs was running
* TODO we can store node->uid this while info on the inodes, * TODO we can store node->uid this while info on the inodes,
* right? */ * right? */
/* /*
if (!ROBUST && (retval != 0)) if (!ROBUST && (retval != 0))
{ {
std::cerr << "Couldn't stat " << procdir << std::endl; std::cerr << "Couldn't stat " << procdir << std::endl;
assert (false); assert (false);
} }
*/ */
if (retval != 0) if (retval != 0)
newproc->setUid(0); newproc->setUid(0);
else else
newproc->setUid(stats.st_uid); newproc->setUid(stats.st_uid);
/*if (getpwuid(stats.st_uid) == NULL) { /*if (getpwuid(stats.st_uid) == NULL) {
std::stderr << "uid for inode std::stderr << "uid for inode
if (!ROBUST) if (!ROBUST)
assert(false); assert(false);
}*/ }*/
processes = new ProcList (newproc, processes); processes = new ProcList(newproc, processes);
return newproc; return newproc;
} }
/* /*
@@ -305,88 +271,82 @@ Process * getProcess (unsigned long inode, const char * devicename)
* is made. If no process can be found even then, it's added to the * is made. If no process can be found even then, it's added to the
* 'unknown' process. * 'unknown' process.
*/ */
Process * getProcess (Connection * connection, const char * devicename) Process *getProcess(Connection *connection, const char *devicename) {
{ unsigned long inode = conninode[connection->refpacket->gethashstring()];
unsigned long inode = conninode[connection->refpacket->gethashstring()];
if (inode == 0) if (inode == 0) {
{ // no? refresh and check conn/inode table
// no? refresh and check conn/inode table if (bughuntmode) {
if (bughuntmode) std::cout << "? new connection not in connection-to-inode table before "
{ "refresh.\n";
std::cout << "? new connection not in connection-to-inode table before refresh.\n"; }
} // refresh the inode->pid table first. Presumably processing the renewed
// refresh the inode->pid table first. Presumably processing the renewed connection->inode table // connection->inode table
// is slow, making this worthwhile. // is slow, making this worthwhile.
// We take the fact for granted that we might already know the inode->pid (unlikely anyway if we // We take the fact for granted that we might already know the inode->pid
// haven't seen the connection->inode yet though). // (unlikely anyway if we
#ifndef __APPLE__ // haven't seen the connection->inode yet though).
reread_mapping(); #ifndef __APPLE__
#endif reread_mapping();
refreshconninode();
inode = conninode[connection->refpacket->gethashstring()];
if (bughuntmode)
{
if (inode == 0)
{
std::cout << ":( inode for connection not found after refresh.\n";
}
else
{
std::cout << ":) inode for connection found after refresh.\n";
}
}
#if REVERSEHACK
if (inode == 0)
{
/* HACK: the following is a hack for cases where the
* 'local' addresses aren't properly recognised, as is
* currently the case for IPv6 */
/* we reverse the direction of the stream if
* successful. */
Packet * reversepacket = connection->refpacket->newInverted();
inode = conninode[reversepacket->gethashstring()];
if (inode == 0)
{
delete reversepacket;
if (bughuntmode || DEBUG)
std::cout << "LOC: " << connection->refpacket->gethashstring() << " STILL not in connection-to-inode table - adding to the unknown process\n";
unknowntcp->connections = new ConnList (connection, unknowntcp->connections);
return unknowntcp;
}
delete connection->refpacket;
connection->refpacket = reversepacket;
}
#endif #endif
} refreshconninode();
else if (bughuntmode) inode = conninode[connection->refpacket->gethashstring()];
{ if (bughuntmode) {
std::cout << ";) new connection in connection-to-inode table before refresh.\n"; if (inode == 0) {
} std::cout << ":( inode for connection not found after refresh.\n";
} else {
std::cout << ":) inode for connection found after refresh.\n";
}
}
#if REVERSEHACK
if (inode == 0) {
/* HACK: the following is a hack for cases where the
* 'local' addresses aren't properly recognised, as is
* currently the case for IPv6 */
if (bughuntmode) /* we reverse the direction of the stream if
{ * successful. */
std::cout << " inode # " << inode << std::endl; Packet *reversepacket = connection->refpacket->newInverted();
} inode = conninode[reversepacket->gethashstring()];
Process * proc = NULL; if (inode == 0) {
if (inode != 0) delete reversepacket;
proc = getProcess(inode, devicename); if (bughuntmode || DEBUG)
std::cout << "LOC: " << connection->refpacket->gethashstring()
<< " STILL not in connection-to-inode table - adding to "
"the unknown process\n";
unknowntcp->connections =
new ConnList(connection, unknowntcp->connections);
return unknowntcp;
}
if (proc == NULL) { delete connection->refpacket;
proc = new Process (inode, "", connection->refpacket->gethashstring()); connection->refpacket = reversepacket;
processes = new ProcList (proc, processes); }
} #endif
} else if (bughuntmode) {
std::cout
<< ";) new connection in connection-to-inode table before refresh.\n";
}
proc->connections = new ConnList (connection, proc->connections); if (bughuntmode) {
return proc; std::cout << " inode # " << inode << std::endl;
}
Process *proc = NULL;
if (inode != 0)
proc = getProcess(inode, devicename);
if (proc == NULL) {
proc = new Process(inode, "", connection->refpacket->gethashstring());
processes = new ProcList(proc, processes);
}
proc->connections = new ConnList(connection, proc->connections);
return proc;
} }
void procclean () void procclean() {
{ // delete conninode;
//delete conninode; prg_cache_clear();
prg_cache_clear();
} }

176
process.h
View File

@@ -1,4 +1,4 @@
/* /*
* process.h * process.h
* *
* Copyright (c) 2004-2006,2008,2011 Arnout Engelen * Copyright (c) 2004-2006,2008,2011 Arnout Engelen
@@ -15,11 +15,11 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
#ifndef __PROCESS_H #ifndef __PROCESS_H
#define __PROCESS_H #define __PROCESS_H
@@ -30,123 +30,103 @@
extern bool tracemode; extern bool tracemode;
extern bool bughuntmode; extern bool bughuntmode;
void check_all_procs (); void check_all_procs();
class ConnList class ConnList {
{
public: public:
ConnList (Connection * m_val, ConnList * m_next) ConnList(Connection *m_val, ConnList *m_next) {
{ assert(m_val != NULL);
assert (m_val != NULL); val = m_val;
val = m_val; next = m_next; next = m_next;
} }
~ConnList () ~ConnList() {
{ /* does not delete its value, to allow a connection to
/* does not delete its value, to allow a connection to * remove itself from the global connlist in its destructor */
* remove itself from the global connlist in its destructor */ }
} Connection *getVal() { return val; }
Connection * getVal () void setNext(ConnList *m_next) { next = m_next; }
{ ConnList *getNext() { return next; }
return val;
}
void setNext (ConnList * m_next)
{
next = m_next;
}
ConnList * getNext ()
{
return next;
}
private: private:
Connection * val; Connection *val;
ConnList * next; ConnList *next;
}; };
class Process class Process {
{
public: public:
/* the process makes a copy of the name. the device name needs to be stable. */ /* the process makes a copy of the name. the device name needs to be stable.
Process (const unsigned long m_inode, const char * m_devicename, const char * m_name = NULL) */
: inode (m_inode) Process(const unsigned long m_inode, const char *m_devicename,
{ const char *m_name = NULL)
//std::cout << "ARN: Process created with dev " << m_devicename << std::endl; : inode(m_inode) {
if (DEBUG) // std::cout << "ARN: Process created with dev " << m_devicename <<
std::cout << "PROC: Process created at " << this << std::endl; // std::endl;
if (DEBUG)
std::cout << "PROC: Process created at " << this << std::endl;
if (m_name == NULL) if (m_name == NULL)
name = NULL; name = NULL;
else else
name = strdup(m_name); name = strdup(m_name);
devicename = m_devicename; devicename = m_devicename;
connections = NULL; connections = NULL;
pid = 0; pid = 0;
uid = 0; uid = 0;
} }
void check () { void check() { assert(pid >= 0); }
assert (pid >= 0);
}
~Process ()
{
free (name);
if (DEBUG)
std::cout << "PROC: Process deleted at " << this << std::endl;
}
int getLastPacket ();
void gettotal( u_int32_t * recvd, u_int32_t * sent); ~Process() {
void getkbps (float * recvd, float * sent); free(name);
void gettotalmb(float * recvd, float * sent); if (DEBUG)
void gettotalkb(float * recvd, float * sent); std::cout << "PROC: Process deleted at " << this << std::endl;
void gettotalb (float * recvd, float * sent); }
int getLastPacket();
char * name; void gettotal(u_int32_t *recvd, u_int32_t *sent);
const char * devicename; void getkbps(float *recvd, float *sent);
int pid; void gettotalmb(float *recvd, float *sent);
void gettotalkb(float *recvd, float *sent);
void gettotalb(float *recvd, float *sent);
ConnList * connections; char *name;
uid_t getUid() const char *devicename;
{ int pid;
return uid;
}
void setUid(uid_t m_uid) ConnList *connections;
{ uid_t getUid() { return uid; }
uid = m_uid;
} void setUid(uid_t m_uid) { uid = m_uid; }
unsigned long getInode() { return inode; }
unsigned long getInode()
{
return inode;
}
private: private:
const unsigned long inode; const unsigned long inode;
uid_t uid; uid_t uid;
}; };
class ProcList class ProcList {
{
public: public:
ProcList (Process * m_val, ProcList * m_next) ProcList(Process *m_val, ProcList *m_next) {
{ assert(m_val != NULL);
assert (m_val != NULL); val = m_val;
val = m_val; next = m_next; next = m_next;
} }
int size (); int size();
Process * getVal () { return val; } Process *getVal() { return val; }
ProcList * getNext () { return next; } ProcList *getNext() { return next; }
ProcList * next; ProcList *next;
private: private:
Process * val; Process *val;
}; };
Process * getProcess (Connection * connection, const char * devicename = NULL); Process *getProcess(Connection *connection, const char *devicename = NULL);
void process_init (); void process_init();
void refreshconninode (); void refreshconninode();
void procclean (); void procclean();
#endif #endif