Merge branch 'master' of github.com:raboof/nethogs

This commit is contained in:
Arnout Engelen
2016-03-22 22:06:31 +01:00
24 changed files with 2371 additions and 2560 deletions

View File

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

View File

@@ -44,22 +44,19 @@ After that, simply
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:
* '{'
* on a new line for function definitions
* on a new line for enums
* on the same line for conditionals/loops
* omitted when possible
* 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
Note to contributors: feel free to request more exceptions and we'll list them
here.
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
mix style fixes and new functionality in one pull request.
When writing new code, at least run 'make format' to have clang-format fix
some superficial style aspects.
libnethogs
----------

View File

@@ -1,4 +1,4 @@
/*
/*
* connection.cpp
*
* Copyright (c) 2004-2006,2008 Arnout Engelen
@@ -15,224 +15,198 @@
*
* You should have received a copy of the GNU General Public License
* 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 <cassert>
#ifdef __APPLE__
#include <sys/malloc.h>
#include <sys/malloc.h>
#else
#include <malloc.h>
#include <malloc.h>
#endif
#include "nethogs.h"
#include "connection.h"
#include "process.h"
ConnList * connections = NULL;
ConnList *connections = NULL;
void PackList::add (Packet * p)
{
if (content == NULL)
{
content = new PackListNode (new Packet (*p));
return;
}
void PackList::add(Packet *p) {
if (content == NULL) {
content = new PackListNode(new Packet(*p));
return;
}
if (content->val->time.tv_sec == p->time.tv_sec)
{
content->val->len += p->len;
return;
}
if (content->val->time.tv_sec == p->time.tv_sec) {
content->val->len += p->len;
return;
}
/* store copy of packet, so that original may be freed */
content = new PackListNode(new Packet (*p), content);
/* store copy of packet, so that original may be freed */
content = new PackListNode(new Packet(*p), content);
}
/* sums up the total bytes used and removes 'old' packets */
u_int32_t PackList::sumanddel (timeval t)
{
u_int32_t retval = 0;
PackListNode * current = content;
PackListNode * previous = NULL;
u_int32_t PackList::sumanddel(timeval t) {
u_int32_t retval = 0;
PackListNode *current = content;
PackListNode *previous = NULL;
while (current != NULL)
{
//std::cout << "Comparing " << current->val->time.tv_sec << " <= " << t.tv_sec - PERIOD << endl;
if (current->val->time.tv_sec <= t.tv_sec - PERIOD)
{
if (current == content)
content = NULL;
else if (previous != NULL)
previous->next = NULL;
delete current;
return retval;
}
retval += current->val->len;
previous = current;
current = current->next;
}
return retval;
while (current != NULL) {
// std::cout << "Comparing " << current->val->time.tv_sec << " <= " <<
// t.tv_sec - PERIOD << endl;
if (current->val->time.tv_sec <= t.tv_sec - PERIOD) {
if (current == content)
content = NULL;
else if (previous != NULL)
previous->next = NULL;
delete current;
return retval;
}
retval += current->val->len;
previous = current;
current = current->next;
}
return retval;
}
/* packet may be deleted by caller */
Connection::Connection (Packet * packet)
{
assert (packet != NULL);
connections = new ConnList (this, connections);
sent_packets = new PackList ();
recv_packets = new PackList ();
sumSent = 0;
sumRecv = 0;
if (DEBUG)
{
std::cout << "New connection, with package len " << packet->len << std::endl;
}
if (packet->Outgoing())
{
sumSent += packet->len;
sent_packets->add(packet);
refpacket = new Packet (*packet);
} else {
sumRecv += packet->len;
recv_packets->add(packet);
refpacket = packet->newInverted();
}
lastpacket = packet->time.tv_sec;
if (DEBUG)
std::cout << "New reference packet created at " << refpacket << std::endl;
Connection::Connection(Packet *packet) {
assert(packet != NULL);
connections = new ConnList(this, connections);
sent_packets = new PackList();
recv_packets = new PackList();
sumSent = 0;
sumRecv = 0;
if (DEBUG) {
std::cout << "New connection, with package len " << packet->len
<< std::endl;
}
if (packet->Outgoing()) {
sumSent += packet->len;
sent_packets->add(packet);
refpacket = new Packet(*packet);
} else {
sumRecv += packet->len;
recv_packets->add(packet);
refpacket = packet->newInverted();
}
lastpacket = packet->time.tv_sec;
if (DEBUG)
std::cout << "New reference packet created at " << refpacket << std::endl;
}
Connection::~Connection ()
{
if (DEBUG)
std::cout << "Deleting connection" << std::endl;
/* refpacket is not a pointer to one of the packets in the lists
* so deleted */
delete (refpacket);
if (sent_packets != NULL)
delete sent_packets;
if (recv_packets != NULL)
delete recv_packets;
Connection::~Connection() {
if (DEBUG)
std::cout << "Deleting connection" << std::endl;
/* refpacket is not a pointer to one of the packets in the lists
* so deleted */
delete (refpacket);
if (sent_packets != NULL)
delete sent_packets;
if (recv_packets != NULL)
delete recv_packets;
ConnList * curr_conn = connections;
ConnList * prev_conn = NULL;
while (curr_conn != NULL)
{
if (curr_conn->getVal() == this)
{
ConnList * todelete = curr_conn;
curr_conn = curr_conn->getNext();
if (prev_conn == NULL)
{
connections = curr_conn;
} else {
prev_conn->setNext(curr_conn);
}
delete (todelete);
}
else
{
prev_conn = curr_conn;
curr_conn = curr_conn->getNext();
}
}
ConnList *curr_conn = connections;
ConnList *prev_conn = NULL;
while (curr_conn != NULL) {
if (curr_conn->getVal() == this) {
ConnList *todelete = curr_conn;
curr_conn = curr_conn->getNext();
if (prev_conn == NULL) {
connections = curr_conn;
} else {
prev_conn->setNext(curr_conn);
}
delete (todelete);
} else {
prev_conn = curr_conn;
curr_conn = curr_conn->getNext();
}
}
}
/* the packet will be freed by the calling code */
void Connection::add (Packet * packet)
{
lastpacket = packet->time.tv_sec;
if (packet->Outgoing())
{
if (DEBUG)
{
std::cout << "Outgoing: " << packet->len << std::endl;
}
sumSent += packet->len;
sent_packets->add (packet);
}
else
{
if (DEBUG)
{
std::cout << "Incoming: " << packet->len << std::endl;
}
sumRecv += packet->len;
if (DEBUG)
{
std::cout << "sumRecv now: " << sumRecv << std::endl;
}
recv_packets->add (packet);
}
void Connection::add(Packet *packet) {
lastpacket = packet->time.tv_sec;
if (packet->Outgoing()) {
if (DEBUG) {
std::cout << "Outgoing: " << packet->len << std::endl;
}
sumSent += packet->len;
sent_packets->add(packet);
} else {
if (DEBUG) {
std::cout << "Incoming: " << packet->len << std::endl;
}
sumRecv += packet->len;
if (DEBUG) {
std::cout << "sumRecv now: " << sumRecv << std::endl;
}
recv_packets->add(packet);
}
}
Connection * findConnectionWithMatchingSource(Packet * packet) {
assert(packet->Outgoing());
Connection *findConnectionWithMatchingSource(Packet *packet) {
assert(packet->Outgoing());
ConnList * current = connections;
while (current != NULL)
{
/* the reference packet is always outgoing */
if (packet->matchSource(current->getVal()->refpacket))
{
return current->getVal();
}
ConnList *current = connections;
while (current != NULL) {
/* the reference packet is always outgoing */
if (packet->matchSource(current->getVal()->refpacket)) {
return current->getVal();
}
current = current->getNext();
}
return NULL;
current = current->getNext();
}
return NULL;
}
Connection * findConnectionWithMatchingRefpacketOrSource(Packet * packet) {
ConnList * current = connections;
while (current != NULL)
{
/* the reference packet is always *outgoing* */
if (packet->match(current->getVal()->refpacket))
{
return current->getVal();
}
Connection *findConnectionWithMatchingRefpacketOrSource(Packet *packet) {
ConnList *current = connections;
while (current != NULL) {
/* the reference packet is always *outgoing* */
if (packet->match(current->getVal()->refpacket)) {
return current->getVal();
}
current = current->getNext();
}
return findConnectionWithMatchingSource(packet);
current = current->getNext();
}
return findConnectionWithMatchingSource(packet);
}
/*
/*
* finds connection to which this packet belongs.
* a packet belongs to a connection if it matches
* to its reference packet
* to its reference packet
*/
Connection * findConnection (Packet * packet)
{
if (packet->Outgoing())
return findConnectionWithMatchingRefpacketOrSource(packet);
else
{
Packet * invertedPacket = packet->newInverted();
Connection * result = findConnectionWithMatchingRefpacketOrSource(invertedPacket);
Connection *findConnection(Packet *packet) {
if (packet->Outgoing())
return findConnectionWithMatchingRefpacketOrSource(packet);
else {
Packet *invertedPacket = packet->newInverted();
Connection *result =
findConnectionWithMatchingRefpacketOrSource(invertedPacket);
delete invertedPacket;
return result;
}
delete invertedPacket;
return result;
}
}
/*
* Connection::sumanddel
*
*
* sums up the total bytes used
* and removes 'old' packets.
* and removes 'old' packets.
*
* Returns sum of sent packages (by address)
* sum of recieved packages (by address)
*/
void Connection::sumanddel (timeval t, u_int32_t * recv, u_int32_t * sent)
{
(*sent)=(*recv)=0;
void Connection::sumanddel(timeval t, u_int32_t *recv, u_int32_t *sent) {
(*sent) = (*recv) = 0;
*sent = sent_packets->sumanddel(t);
*recv = recv_packets->sumanddel(t);
*sent = sent_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
* 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
@@ -24,91 +25,82 @@
#include <iostream>
#include "packet.h"
class PackListNode
{
class PackListNode {
public:
PackListNode (Packet * m_val, PackListNode * m_next = NULL)
{
val = m_val;
next = m_next;
}
~PackListNode ()
{
delete val;
if (next != NULL)
delete next;
}
PackListNode * next;
Packet * val;
PackListNode(Packet *m_val, PackListNode *m_next = NULL) {
val = m_val;
next = m_next;
}
~PackListNode() {
delete val;
if (next != NULL)
delete next;
}
PackListNode *next;
Packet *val;
};
class PackList
{
class PackList {
public:
PackList ()
{
content = NULL;
}
PackList (Packet * m_val)
{
assert (m_val != NULL);
content = new PackListNode(m_val);
}
~PackList ()
{
if (content != NULL)
delete content;
}
PackList() { content = NULL; }
PackList(Packet *m_val) {
assert(m_val != NULL);
content = new PackListNode(m_val);
}
~PackList() {
if (content != NULL)
delete content;
}
/* sums up the total bytes used and removes 'old' packets */
u_int32_t sumanddel (timeval t);
/* sums up the total bytes used and removes 'old' packets */
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:
PackListNode * content;
PackListNode *content;
};
class Connection
{
class Connection {
public:
/* constructs a connection, makes a copy of
* the packet as 'refpacket', and adds the
* packet to the packlist */
/* packet may be deleted by caller */
Connection (Packet * packet);
/* constructs a connection, makes a copy of
* the packet as 'refpacket', and adds the
* packet to the packlist */
/* packet may be deleted by caller */
Connection(Packet *packet);
~Connection();
~Connection();
/* add a packet to the packlist
* will delete the packet structure
* when it is 'merged with' (added to) another
* packet
*/
void add (Packet * packet);
/* add a packet to the packlist
* will delete the packet structure
* when it is 'merged with' (added to) another
* packet
*/
void add(Packet *packet);
int getLastPacket ()
{ return lastpacket; }
int getLastPacket() { return lastpacket; }
/* sums up the total bytes used
* and removes 'old' packets. */
void sumanddel(timeval curtime, u_int32_t * recv, u_int32_t * sent);
/* sums up the total bytes used
* and removes 'old' packets. */
void sumanddel(timeval curtime, u_int32_t *recv, u_int32_t *sent);
/* for checking if a packet is part of this connection */
/* the reference packet is always *outgoing*. */
Packet * refpacket;
/* for checking if a packet is part of this connection */
/* the reference packet is always *outgoing*. */
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:
PackList * sent_packets;
PackList * recv_packets;
int lastpacket;
PackList *sent_packets;
PackList *recv_packets;
int lastpacket;
};
/* Find the connection this packet belongs to */
/* (the calling code may free the packet afterwards) */
Connection * findConnection (Packet * packet);
Connection *findConnection(Packet *packet);
#endif

View File

@@ -15,11 +15,11 @@
*
* You should have received a copy of the GNU General Public License
* 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 <map>
#include <cstdio>
@@ -29,173 +29,168 @@
#include "conninode.h"
#if defined __APPLE__
#ifndef s6_addr32
#define s6_addr32 __u6_addr.__u6_addr32
#endif
#ifndef s6_addr32
#define s6_addr32 __u6_addr.__u6_addr32
#endif
#endif
extern local_addr * local_addrs;
extern local_addr *local_addrs;
/*
* connection-inode table. takes information from /proc/net/tcp.
* key contains source ip, source port, destination ip, destination
* port in format: '1.2.3.4:5-1.2.3.4:5'
*/
std::map <std::string, unsigned long> conninode;
std::map<std::string, unsigned long> conninode;
/*
* 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
* 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
* sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt
*uid timeout inode
* 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:
* 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)
{
short int sa_family;
struct in6_addr result_addr_local;
struct in6_addr result_addr_remote;
void addtoconninode(char *buffer) {
short int sa_family;
struct in6_addr result_addr_local;
struct in6_addr result_addr_remote;
char rem_addr[128], local_addr[128];
int local_port, rem_port;
struct in6_addr in6_local;
struct in6_addr in6_remote;
char rem_addr[128], local_addr[128];
int local_port, rem_port;
struct in6_addr in6_local;
struct in6_addr in6_remote;
// this leaked memory
//unsigned long * inode = (unsigned long *) malloc (sizeof(unsigned long));
unsigned long inode;
// this leaked memory
// unsigned long * inode = (unsigned long *) malloc (sizeof(unsigned long));
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",
local_addr, &local_port, rem_addr, &rem_port, &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",
local_addr, &local_port, rem_addr, &rem_port, &inode);
if (matches != 5) {
fprintf(stderr,"Unexpected buffer: '%s'\n",buffer);
exit(0);
}
if (matches != 5) {
fprintf(stderr, "Unexpected buffer: '%s'\n", buffer);
exit(0);
}
if (inode == 0) {
/* connection is in TIME_WAIT state. We rely on
* the old data still in the table. */
return;
}
if (inode == 0) {
/* connection is in TIME_WAIT state. We rely on
* the old data still in the table. */
return;
}
if (strlen(local_addr) > 8)
{
/* this is an IPv6-style row */
if (strlen(local_addr) > 8) {
/* this is an IPv6-style row */
/* Demangle what the kernel gives us */
sscanf(local_addr, "%08X%08X%08X%08X",
&in6_local.s6_addr32[0], &in6_local.s6_addr32[1],
&in6_local.s6_addr32[2], &in6_local.s6_addr32[3]);
sscanf(rem_addr, "%08X%08X%08X%08X",
&in6_remote.s6_addr32[0], &in6_remote.s6_addr32[1],
&in6_remote.s6_addr32[2], &in6_remote.s6_addr32[3]);
/* Demangle what the kernel gives us */
sscanf(local_addr, "%08X%08X%08X%08X", &in6_local.s6_addr32[0],
&in6_local.s6_addr32[1], &in6_local.s6_addr32[2],
&in6_local.s6_addr32[3]);
sscanf(rem_addr, "%08X%08X%08X%08X", &in6_remote.s6_addr32[0],
&in6_remote.s6_addr32[1], &in6_remote.s6_addr32[2],
&in6_remote.s6_addr32[3]);
if ((in6_local.s6_addr32[0] == 0x0) && (in6_local.s6_addr32[1] == 0x0)
&& (in6_local.s6_addr32[2] == 0xFFFF0000))
{
/* IPv4-compatible address */
result_addr_local = *((struct in6_addr*) &(in6_local.s6_addr32[3]));
result_addr_remote = *((struct in6_addr*) &(in6_remote.s6_addr32[3]));
sa_family = AF_INET;
} else {
/* real IPv6 address */
//inet_ntop(AF_INET6, &in6_local, addr6, sizeof(addr6));
//INET6_getsock(addr6, (struct sockaddr *) &localaddr);
//inet_ntop(AF_INET6, &in6_remote, addr6, sizeof(addr6));
//INET6_getsock(addr6, (struct sockaddr *) &remaddr);
//localaddr.sin6_family = AF_INET6;
//remaddr.sin6_family = AF_INET6;
result_addr_local = in6_local;
result_addr_remote = in6_remote;
sa_family = AF_INET6;
}
}
else
{
/* this is an IPv4-style row */
sscanf(local_addr, "%X", (unsigned int *) &result_addr_local);
sscanf(rem_addr, "%X", (unsigned int *) &result_addr_remote);
sa_family = AF_INET;
}
if ((in6_local.s6_addr32[0] == 0x0) && (in6_local.s6_addr32[1] == 0x0) &&
(in6_local.s6_addr32[2] == 0xFFFF0000)) {
/* IPv4-compatible address */
result_addr_local = *((struct in6_addr *)&(in6_local.s6_addr32[3]));
result_addr_remote = *((struct in6_addr *)&(in6_remote.s6_addr32[3]));
sa_family = AF_INET;
} else {
/* real IPv6 address */
// inet_ntop(AF_INET6, &in6_local, addr6, sizeof(addr6));
// INET6_getsock(addr6, (struct sockaddr *) &localaddr);
// inet_ntop(AF_INET6, &in6_remote, addr6, sizeof(addr6));
// INET6_getsock(addr6, (struct sockaddr *) &remaddr);
// localaddr.sin6_family = AF_INET6;
// remaddr.sin6_family = AF_INET6;
result_addr_local = in6_local;
result_addr_remote = in6_remote;
sa_family = AF_INET6;
}
} else {
/* this is an IPv4-style row */
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 * local_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_remote, remote_string, 49);
char *hashkey = (char *)malloc(HASHKEYSIZE * sizeof(char));
char *local_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_remote, remote_string, 49);
snprintf(hashkey, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d", local_string, local_port, remote_string, rem_port);
free (local_string);
snprintf(hashkey, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d", local_string,
local_port, remote_string, rem_port);
free(local_string);
//if (DEBUG)
// fprintf (stderr, "Hashkey: %s\n", hashkey);
// if (DEBUG)
// 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
* 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
* interfaces */
for (class local_addr *current_local_addr = local_addrs;
current_local_addr != NULL;
current_local_addr = current_local_addr->next) {
/* 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);
conninode[hashkey] = inode;
}
free (hashkey);
free (remote_string);
/* 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.1 and 195.169.216.157 are the local addresses of different
* interfaces */
for (class local_addr *current_local_addr = local_addrs;
current_local_addr != NULL;
current_local_addr = current_local_addr->next) {
/* 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);
conninode[hashkey] = inode;
}
free(hashkey);
free(remote_string);
}
/* opens /proc/net/tcp[6] and adds its contents line by line */
int addprocinfo (const char * filename) {
FILE * procinfo = fopen (filename, "r");
int addprocinfo(const char *filename) {
FILE *procinfo = fopen(filename, "r");
char buffer[8192];
char buffer[8192];
if (procinfo == NULL)
return 0;
if (procinfo == NULL)
return 0;
fgets(buffer, sizeof(buffer), procinfo);
fgets(buffer, sizeof(buffer), procinfo);
do
{
if (fgets(buffer, sizeof(buffer), procinfo))
addtoconninode(buffer);
} while (!feof(procinfo));
do {
if (fgets(buffer, sizeof(buffer), procinfo))
addtoconninode(buffer);
} 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
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)
// reviewUnknown();
// if (DEBUG)
// reviewUnknown();
}

View File

@@ -15,8 +15,9 @@
*
* You should have received a copy of the GNU General Public License
* 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
void refreshconninode ();
void refreshconninode();

654
cui.cpp
View File

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

11
cui.h
View File

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

View File

@@ -1,4 +1,4 @@
/*
/*
* decpcap.h
*
* Copyright (c) 2004-2006,2011 Arnout Engelen
@@ -15,7 +15,8 @@
*
* You should have received a copy of the GNU General Public License
* 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
@@ -30,20 +31,20 @@
/* definitions */
enum dp_packet_type {
dp_packet_ethernet,
dp_packet_ppp,
dp_packet_sll,
dp_packet_ip,
dp_packet_ip6,
dp_packet_tcp,
dp_packet_udp,
dp_n_packet_types
dp_packet_ethernet,
dp_packet_ppp,
dp_packet_sll,
dp_packet_ip,
dp_packet_ip6,
dp_packet_tcp,
dp_packet_udp,
dp_n_packet_types
};
/*enum dp_link_type {
dp_link_ethernet,
dp_link_ppp,
dp_n_link_types
dp_link_ethernet,
dp_link_ppp,
dp_n_link_types
};*/
/*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 *);
struct dp_handle {
pcap_t * pcap_handle;
dp_callback callback [dp_n_packet_types];
int linktype;
u_char * userdata;
int userdata_size;
pcap_t *pcap_handle;
dp_callback callback[dp_n_packet_types];
int linktype;
u_char *userdata;
int userdata_size;
};
/* 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_offline(char * fname, char * ebuf);
struct dp_handle *dp_open_live(const char *device, int snaplen, int promisc,
int to_ms, char *errbuf);
struct dp_handle *dp_open_offline(char *fname, char *ebuf);
/* 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 */
void dp_parse (enum dp_packet_type type, void * packet);
void dp_parse(enum dp_packet_type type, void *packet);
/* functions to start monitoring */
int dp_dispatch (struct dp_handle * handler, int count, u_char *user, int size);
int dp_dispatch(struct dp_handle *handler, int count, u_char *user, int size);
/* functions that simply call libpcap */
int dp_datalink(struct dp_handle * handle);
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

View File

@@ -1,4 +1,4 @@
/*
/*
* decpcap_test.cpp
*
* Copyright (c) 2006,2011 Arnout Engelen
@@ -15,36 +15,34 @@
*
* You should have received a copy of the GNU General Public License
* 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>
extern "C" {
#include "decpcap.h"
#include "decpcap.h"
}
int process_tcp (u_char * /* userdata */, const dp_header * /* header */, const u_char * /* m_packet */) {
std::cout << "Callback for processing TCP packet called" << std::endl;
return 0;
int process_tcp(u_char * /* userdata */, const dp_header * /* header */,
const u_char * /* m_packet */) {
std::cout << "Callback for processing TCP packet called" << std::endl;
return 0;
}
int main (int argc, char ** argv)
{
if (argc < 2)
{
std::cout << "Please, enter a filename" << std::endl;
}
int main(int argc, char **argv) {
if (argc < 2) {
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_addcb (newhandle, dp_packet_tcp, process_tcp);
int ret = dp_dispatch (newhandle, -1, NULL, 0);
if (ret == -1)
{
std::cout << "Error dispatching: " << dp_geterr(newhandle);
}
dp_handle *newhandle = dp_open_offline(argv[1], errbuf);
dp_addcb(newhandle, dp_packet_tcp, process_tcp);
int ret = dp_dispatch(newhandle, -1, NULL, 0);
if (ret == -1) {
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
* 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,68 +29,62 @@
#include <net/if.h>
#include <ifaddrs.h>
bool selected(int devc, char** devicenames, char* devicename) {
if (devc == 0)
return true;
bool selected(int devc, char **devicenames, char *devicename) {
if (devc == 0)
return true;
for (int i = 0; i < devc; i++)
if (strcmp(devicenames[i], devicename) == 0)
return true;
for (int i = 0; i < devc; i++)
if (strcmp(devicenames[i], devicename) == 0)
return true;
return false;
return false;
}
bool already_seen(device* devices, char* devicename) {
for (class device* current_device = devices;
current_device != NULL;
current_device = current_device->next) {
if (strcmp(current_device->name, devicename) == 0)
return true;
}
return false;
bool already_seen(device *devices, char *devicename) {
for (class device *current_device = devices; current_device != NULL;
current_device = current_device->next) {
if (strcmp(current_device->name, devicename) == 0)
return true;
}
return false;
}
// The interface is up, not a loopback and running?
bool up_running(int ifa_flags) {
return !(ifa_flags & IFF_LOOPBACK) &&
(ifa_flags & IFF_UP) &&
(ifa_flags & IFF_RUNNING);
return !(ifa_flags & IFF_LOOPBACK) && (ifa_flags & IFF_UP) &&
(ifa_flags & IFF_RUNNING);
}
/**
* 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)
{
struct ifaddrs *ifaddr, *ifa;
device *get_devices(int devc, char **devicenames, bool all) {
struct ifaddrs *ifaddr, *ifa;
if (getifaddrs(&ifaddr) == -1)
{
std::cerr << "Fail to get interface addresses" << std::endl;
// perror("getifaddrs");
return NULL;
}
if (getifaddrs(&ifaddr) == -1) {
std::cerr << "Failed to get interface addresses" << std::endl;
// perror("getifaddrs");
return NULL;
}
device* devices = NULL;
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL)
continue;
if (!selected(devc, devicenames, ifa->ifa_name))
continue;
if (already_seen(devices, ifa->ifa_name))
continue;
if (!all && !up_running(ifa->ifa_flags))
continue;
device *devices = NULL;
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
if (!selected(devc, devicenames, ifa->ifa_name))
continue;
if (already_seen(devices, ifa->ifa_name))
continue;
if (!all && !up_running(ifa->ifa_flags))
continue;
devices = new device(strdup(ifa->ifa_name),devices);
}
devices = new device(strdup(ifa->ifa_name), devices);
}
freeifaddrs(ifaddr);
return devices;
freeifaddrs(ifaddr);
return devices;
}
device * get_default_devices() {
return get_devices(0, NULL, false);
}
device *get_default_devices() { return get_devices(0, NULL, false); }

View File

@@ -15,7 +15,8 @@
*
* You should have received a copy of the GNU General Public License
* 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 {
public:
device (const char * m_name, device * m_next = NULL)
{
name = m_name; next = m_next;
}
const char * name;
device * next;
device(const char *m_name, device *m_next = NULL) {
name = m_name;
next = m_next;
}
const char *name;
device *next;
};
/** get all devices that are up, running and not loopback */
device * get_default_devices();
device *get_default_devices();
/**
* Get all specified devices.
@@ -44,6 +45,6 @@ device * get_default_devices();
* when 'all' is set, also return loopback interfaces and interfaces
* 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

View File

@@ -15,11 +15,11 @@
*
* You should have received a copy of the GNU General Public License
* 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 <cerrno>
#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..
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;
/* 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) {
while (*string) {
if (!isdigit (*string))
return false;
string++;
}
return true;
bool is_number(const char *string) {
while (*string) {
if (!isdigit(*string))
return false;
string++;
}
return true;
}
unsigned long str2ulong (const char * ptr) {
unsigned long retval = 0;
unsigned long str2ulong(const char *ptr) {
unsigned long retval = 0;
while ((*ptr >= '0') && (*ptr <= '9')) {
retval *= 10;
retval += *ptr - '0';
ptr++;
}
return retval;
while ((*ptr >= '0') && (*ptr <= '9')) {
retval *= 10;
retval += *ptr - '0';
ptr++;
}
return retval;
}
int str2int (const char * ptr) {
int retval = 0;
int str2int(const char *ptr) {
int retval = 0;
while ((*ptr >= '0') && (*ptr <= '9')) {
retval *= 10;
retval += *ptr - '0';
ptr++;
}
return retval;
while ((*ptr >= '0') && (*ptr <= '9')) {
retval *= 10;
retval += *ptr - '0';
ptr++;
}
return retval;
}
static std::string read_file (int fd) {
char buf[255];
std::string content;
static std::string read_file(int fd) {
char buf[255];
std::string content;
for (int length; (length = read(fd, buf, sizeof(buf))) > 0;) {
if (length < 0) {
std::fprintf(stderr, "Error reading file: %s\n", std::strerror(errno));
std::exit(34);
}
content.append(buf, length);
}
for (int length; (length = read(fd, buf, sizeof(buf))) > 0;) {
if (length < 0) {
std::fprintf(stderr, "Error reading file: %s\n", std::strerror(errno));
std::exit(34);
}
content.append(buf, length);
}
return content;
return content;
}
static std::string read_file (const char* filepath) {
int fd = open(filepath, O_RDONLY);
static std::string read_file(const char *filepath) {
int fd = open(filepath, O_RDONLY);
if (fd < 0) {
std::fprintf(stderr, "Error opening %s: %s\n", filepath, std::strerror(errno));
std::exit(3);
return NULL;
}
if (fd < 0) {
std::fprintf(stderr, "Error opening %s: %s\n", filepath,
std::strerror(errno));
std::exit(3);
return NULL;
}
std::string contents = read_file(fd);
std::string contents = read_file(fd);
if (close(fd)) {
std::fprintf(stderr, "Error opening %s: %s\n", filepath, std::strerror(errno));
std::exit(34);
}
if (close(fd)) {
std::fprintf(stderr, "Error opening %s: %s\n", filepath,
std::strerror(errno));
std::exit(34);
}
return contents;
return contents;
}
std::string getprogname (pid_t pid) {
const int maxfilenamelen = 14 + MAX_PID_LENGTH + 1;
char filename[maxfilenamelen];
std::string getprogname(pid_t pid) {
const int maxfilenamelen = 14 + MAX_PID_LENGTH + 1;
char filename[maxfilenamelen];
std::snprintf(filename, maxfilenamelen, "/proc/%d/cmdline", pid);
return read_file(filename);
std::snprintf(filename, maxfilenamelen, "/proc/%d/cmdline", pid);
return read_file(filename);
}
void setnode (unsigned long inode, pid_t pid) {
prg_node * current_value = inodeproc[inode];
void setnode(unsigned long inode, pid_t pid) {
prg_node *current_value = inodeproc[inode];
if (current_value == NULL || current_value->pid != pid) {
prg_node * newnode = new prg_node;
newnode->inode = inode;
newnode->pid = pid;
newnode->name = getprogname(pid);
if (current_value == NULL || current_value->pid != pid) {
prg_node *newnode = new prg_node;
newnode->inode = inode;
newnode->pid = pid;
newnode->name = getprogname(pid);
inodeproc[inode] = newnode;
delete current_value;
}
inodeproc[inode] = newnode;
delete current_value;
}
}
void get_info_by_linkname (const char * pid, const char * linkname) {
if (strncmp(linkname, "socket:[", 8) == 0) {
setnode(str2ulong(linkname + 8), str2int(pid));
}
void get_info_by_linkname(const char *pid, const char *linkname) {
if (strncmp(linkname, "socket:[", 8) == 0) {
setnode(str2ulong(linkname + 8), str2int(pid));
}
}
/* updates the `inodeproc' inode-to-prg_node
* for all inodes belonging to this PID
* (/proc/pid/fd/42)
* */
void get_info_for_pid(const char * pid) {
char dirname[10 + MAX_PID_LENGTH];
void get_info_for_pid(const char *pid) {
char dirname[10 + MAX_PID_LENGTH];
size_t dirlen = 10 + strlen(pid);
snprintf(dirname, dirlen, "/proc/%s/fd", pid);
size_t dirlen = 10 + strlen(pid);
snprintf(dirname, dirlen, "/proc/%s/fd", pid);
DIR * dir = opendir(dirname);
DIR *dir = opendir(dirname);
if (!dir)
{
if (bughuntmode)
{
std::cout << "Couldn't open dir " << dirname << ": " << strerror(errno) << "\n";
}
return;
}
if (!dir) {
if (bughuntmode) {
std::cout << "Couldn't open dir " << dirname << ": " << strerror(errno)
<< "\n";
}
return;
}
/* walk through /proc/%s/fd/... */
dirent * entry;
while ((entry = readdir(dir))) {
if (entry->d_type != DT_LNK)
continue;
//std::cout << "Looking at: " << entry->d_name << std::endl;
/* walk through /proc/%s/fd/... */
dirent *entry;
while ((entry = readdir(dir))) {
if (entry->d_type != DT_LNK)
continue;
// std::cout << "Looking at: " << entry->d_name << std::endl;
size_t fromlen = dirlen + strlen(entry->d_name) + 1;
char fromname[10 + MAX_PID_LENGTH + 1 + MAX_FDLINK];
snprintf (fromname, fromlen, "%s/%s", dirname, entry->d_name);
size_t fromlen = dirlen + strlen(entry->d_name) + 1;
char fromname[10 + MAX_PID_LENGTH + 1 + MAX_FDLINK];
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;
char linkname [linklen];
int usedlen = readlink(fromname, linkname, linklen-1);
if (usedlen == -1)
{
continue;
}
assert (usedlen < linklen);
linkname[usedlen] = '\0';
get_info_by_linkname (pid, linkname);
}
closedir(dir);
int linklen = 80;
char linkname[linklen];
int usedlen = readlink(fromname, linkname, linklen - 1);
if (usedlen == -1) {
continue;
}
assert(usedlen < linklen);
linkname[usedlen] = '\0';
get_info_by_linkname(pid, linkname);
}
closedir(dir);
}
/* updates the `inodeproc' inode-to-prg_node mapping
* for all processes in /proc */
void reread_mapping () {
DIR * proc = opendir ("/proc");
void reread_mapping() {
DIR *proc = opendir("/proc");
if (proc == 0) {
std::cerr << "Error reading /proc, neede to get inode-to-pid-maping\n";
exit(1);
}
if (proc == 0) {
std::cerr << "Error reading /proc, neede to get inode-to-pid-maping\n";
exit(1);
}
dirent * entry;
dirent *entry;
while ((entry = readdir(proc))) {
if (entry->d_type != DT_DIR) continue;
while ((entry = readdir(proc))) {
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);
}
closedir(proc);
get_info_for_pid(entry->d_name);
}
closedir(proc);
}
struct prg_node * findPID (unsigned long inode)
{
/* we first look in inodeproc */
struct prg_node * node = inodeproc[inode];
struct prg_node *findPID(unsigned long inode) {
/* we first look in inodeproc */
struct prg_node *node = inodeproc[inode];
if (node != NULL)
{
if (bughuntmode)
{
std::cout << ":) Found pid in inodeproc table" << std::endl;
}
return node;
}
if (node != NULL) {
if (bughuntmode) {
std::cout << ":) Found pid in inodeproc table" << std::endl;
}
return node;
}
#ifndef __APPLE__
reread_mapping();
#endif
#ifndef __APPLE__
reread_mapping();
#endif
struct prg_node * retval = inodeproc[inode];
if (bughuntmode)
{
if (retval == NULL)
{
std::cout << ":( No pid after inodeproc refresh" << std::endl;
}
else
{
std::cout << ":) Found pid after inodeproc refresh" << std::endl;
}
}
return retval;
struct prg_node *retval = inodeproc[inode];
if (bughuntmode) {
if (retval == NULL) {
std::cout << ":( No pid after inodeproc refresh" << std::endl;
} else {
std::cout << ":) Found pid after inodeproc refresh" << std::endl;
}
}
return retval;
}
void prg_cache_clear() {};
void prg_cache_clear(){};
/*void main () {
std::cout << "Fooo\n";
reread_mapping();
std::cout << "Haihai\n";
std::cout << "Fooo\n";
reread_mapping();
std::cout << "Haihai\n";
}*/

View File

@@ -15,7 +15,8 @@
*
* You should have received a copy of the GNU General Public License
* 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
@@ -28,16 +29,16 @@
#include "nethogs.h"
struct prg_node {
long inode;
pid_t pid;
std::string name;
long inode;
pid_t pid;
std::string name;
};
struct prg_node * findPID (unsigned long inode);
struct prg_node *findPID(unsigned long inode);
void prg_cache_clear();
// reread the inode-to-prg_node-mapping
void reread_mapping ();
void reread_mapping();
#endif

View File

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

View File

@@ -8,46 +8,51 @@ extern "C" {
#include <stdint.h>
#include <stdbool.h>
#define NETHOGS_DSO_VISIBLE __attribute__ ((visibility ("default")))
#define NETHOGS_DSO_HIDDEN __attribute__ ((visibility ("hidden")))
#define NETHOGS_DSO_VISIBLE __attribute__((visibility("default")))
#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_STATUS_OK 0
#define NETHOGS_STATUS_FAILURE 1 //generic error
#define NETHOGS_STATUS_NO_DEVICE 2 //no device foundr
#define NETHOGS_STATUS_OK 0
#define NETHOGS_STATUS_FAILURE 1 // generic error
#define NETHOGS_STATUS_NO_DEVICE 2 // no device foundr
typedef struct NethogsMonitorRecord
{
int record_id;
const char* name;
int pid;
uint32_t uid;
const char* device_name;
uint32_t sent_bytes;
uint32_t recv_bytes;
float sent_kbs;
float recv_kbs;
typedef struct NethogsMonitorRecord {
int record_id;
const char *name;
int pid;
uint32_t uid;
const char *device_name;
uint32_t sent_bytes;
uint32_t recv_bytes;
float sent_kbs;
float recv_kbs;
} NethogsMonitorRecord;
/**
* @brief Defines a callback to handle updates about applications
* @param action NETHOGS_APP_ACTION_SET if data is beeing added or updated,
* NETHOGS_APP_ACTION_REMOVE if data is beeing removed.
* the record_id member is used to uniquely identify the data beeing update or removed.
* @param data a pointer to an application usage data. the pointer remains valid 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.
* the record_id member is used to uniquely identify the data beeing
* update or removed.
* @param data a pointer to an application usage data. the pointer remains valid
* 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.
* This call will block until nethogsmonitor_breakloop() is called or a failure occurs.
* @param cb A pointer to a callback function following the NethogsMonitorCallback definition
* This call will block until nethogsmonitor_breakloop() is called or a failure
* occurs.
* @param cb A pointer to a callback function following the
* NethogsMonitorCallback definition
*/
NETHOGS_DSO_VISIBLE int nethogsmonitor_loop(NethogsMonitorCallback cb);

477
main.cpp
View File

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

View File

@@ -15,7 +15,8 @@
*
* You should have received a copy of the GNU General Public License
* 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"
extern "C" {
#include "decpcap.h"
#include "decpcap.h"
}
#include "packet.h"
@@ -48,7 +49,7 @@ extern "C" {
#include "process.h"
#include "devices.h"
extern Process * unknownudp;
extern Process *unknownudp;
unsigned refreshdelay = 1;
unsigned refreshlimit = 0;
@@ -64,178 +65,184 @@ const char version[] = " version " VERSION "." SUBVERSION "." MINORVERSION;
timeval curtime;
bool local_addr::contains (const in_addr_t & n_addr) {
if ((sa_family == AF_INET)
&& (n_addr == addr))
return true;
if (next == NULL)
return false;
return next->contains(n_addr);
bool local_addr::contains(const in_addr_t &n_addr) {
if ((sa_family == AF_INET) && (n_addr == addr))
return true;
if (next == NULL)
return false;
return next->contains(n_addr);
}
bool local_addr::contains(const struct in6_addr & n_addr) {
if (sa_family == AF_INET6)
{
/*
if (DEBUG) {
char addy [50];
std::cerr << "Comparing: ";
inet_ntop (AF_INET6, &n_addr, addy, 49);
std::cerr << addy << " and ";
inet_ntop (AF_INET6, &addr6, addy, 49);
std::cerr << addy << std::endl;
}
*/
//if (addr6.s6_addr == n_addr.s6_addr)
if (memcmp (&addr6, &n_addr, sizeof(struct in6_addr)) == 0)
{
if (DEBUG)
std::cerr << "Match!" << std::endl;
return true;
}
}
if (next == NULL)
return false;
return next->contains(n_addr);
bool local_addr::contains(const struct in6_addr &n_addr) {
if (sa_family == AF_INET6) {
/*
if (DEBUG) {
char addy [50];
std::cerr << "Comparing: ";
inet_ntop (AF_INET6, &n_addr, addy, 49);
std::cerr << addy << " and ";
inet_ntop (AF_INET6, &addr6, addy, 49);
std::cerr << addy << std::endl;
}
*/
// if (addr6.s6_addr == n_addr.s6_addr)
if (memcmp(&addr6, &n_addr, sizeof(struct in6_addr)) == 0) {
if (DEBUG)
std::cerr << "Match!" << std::endl;
return true;
}
}
if (next == NULL)
return false;
return next->contains(n_addr);
}
struct dpargs {
const char * device;
int sa_family;
in_addr ip_src;
in_addr ip_dst;
in6_addr ip6_src;
in6_addr ip6_dst;
const char *device;
int sa_family;
in_addr ip_src;
in_addr ip_dst;
in6_addr ip6_src;
in6_addr ip6_dst;
};
const char* getVersion()
{
return version;
const char *getVersion() { 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) {
struct dpargs * args = (struct dpargs *) userdata;
struct tcphdr * tcp = (struct tcphdr *) m_packet;
int process_udp(u_char *userdata, const dp_header *header,
const u_char *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;
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;
}
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;
}
Connection * connection = findConnection(packet);
// if (DEBUG)
// std::cout << "Got packet from " << packet->gethashstring() << std::endl;
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;
Connection *connection = findConnection(packet);
/* we're done now. */
return true;
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_udp (u_char * userdata, const dp_header * header, const u_char * m_packet) {
struct dpargs * args = (struct dpargs *) userdata;
struct udphdr * udp = (struct udphdr *) m_packet;
int process_ip(u_char *userdata, const dp_header * /* header */,
const u_char *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;
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;
/* we're not done yet - also parse tcp :) */
return false;
}
int process_ip (u_char * userdata, const dp_header * /* header */, const u_char * 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;
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;
}
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;
/* we're not done yet - also parse tcp :) */
return false;
}
class handle {
public:
handle (dp_handle * m_handle, const char * m_devicename = NULL,
handle * m_next = NULL) {
content = m_handle; next = m_next; devicename = m_devicename;
}
dp_handle * content;
const char * devicename;
handle * next;
handle(dp_handle *m_handle, const char *m_devicename = NULL,
handle *m_next = NULL) {
content = m_handle;
next = m_next;
devicename = m_devicename;
}
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
* 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
#define __NETHOGS_H
@@ -30,9 +30,9 @@
#include <cassert>
#include <cstring>
#ifdef __APPLE__
#include <sys/malloc.h>
#include <sys/malloc.h>
#else
#include <malloc.h>
#include <malloc.h>
#endif
#include <iostream>
@@ -68,50 +68,48 @@
#define PROGNAME_WIDTH 512
// viewMode: how to represent numbers
#define VIEWMODE_KBPS 0
#define VIEWMODE_KBPS 0
#define VIEWMODE_TOTAL_KB 1
#define VIEWMODE_TOTAL_B 2
#define VIEWMODE_TOTAL_B 2
#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;
class local_addr {
public:
/* ipv4 constructor takes an in_addr_t */
local_addr (in_addr_t m_addr, local_addr * m_next = NULL)
{
addr = m_addr;
next = m_next;
sa_family = AF_INET;
string = (char*) malloc (16);
inet_ntop (AF_INET, &m_addr, string, 15);
}
/* this constructor takes an char address[33] */
local_addr (struct in6_addr *m_addr, local_addr * m_next = NULL)
{
addr6 = *m_addr;
next = m_next;
sa_family = AF_INET6;
string = (char*) malloc (64);
inet_ntop (AF_INET6, &m_addr, string, 63);
}
/* ipv4 constructor takes an in_addr_t */
local_addr(in_addr_t m_addr, local_addr *m_next = NULL) {
addr = m_addr;
next = m_next;
sa_family = AF_INET;
string = (char *)malloc(16);
inet_ntop(AF_INET, &m_addr, string, 15);
}
/* this constructor takes an char address[33] */
local_addr(struct in6_addr *m_addr, local_addr *m_next = NULL) {
addr6 = *m_addr;
next = m_next;
sa_family = AF_INET6;
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:
in_addr_t addr;
struct in6_addr addr6;
short int sa_family;
in_addr_t addr;
struct in6_addr addr6;
short int sa_family;
};
void quit_cb (int i);
void quit_cb(int i);
const char* getVersion();
const char *getVersion();
#endif

View File

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

View File

@@ -1,4 +1,4 @@
/*
/*
* packet.h
*
* Copyright (c) 2004,2006 Arnout Engelen
@@ -15,11 +15,11 @@
*
* You should have received a copy of the GNU General Public License
* 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
#define __PACKET_H
@@ -31,56 +31,54 @@
#include <arpa/inet.h>
#include "nethogs.h"
enum direction {
dir_unknown,
dir_incoming,
dir_outgoing
};
enum direction { dir_unknown, dir_incoming, dir_outgoing };
/* To initialise this module, call getLocal with the currently
* 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:
in6_addr sip6;
in6_addr dip6;
in_addr sip;
in_addr dip;
unsigned short sport;
unsigned short dport;
u_int32_t len;
timeval time;
in6_addr sip6;
in6_addr dip6;
in_addr sip;
in_addr dip;
unsigned short sport;
unsigned short dport;
u_int32_t len;
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 (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);
/* copy constructor */
Packet (const Packet &old);
~Packet ()
{
if (hashstring != NULL)
{
free (hashstring);
hashstring = NULL;
}
}
/* Packet (const Packet &old_packet); */
/* copy constructor that turns the packet around */
Packet * newInverted ();
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(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);
/* copy constructor */
Packet(const Packet &old);
~Packet() {
if (hashstring != NULL) {
free(hashstring);
hashstring = NULL;
}
}
/* Packet (const Packet &old_packet); */
/* copy constructor that turns the packet around */
Packet *newInverted();
bool isOlderThan(timeval t);
/* is this packet coming from the local host? */
bool Outgoing ();
bool isOlderThan(timeval t);
/* is this packet coming from the local host? */
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:
direction dir;
short int sa_family;
char * hashstring;
direction dir;
short int sa_family;
char *hashstring;
};
#endif

View File

@@ -15,17 +15,17 @@
*
* You should have received a copy of the GNU General Public License
* 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 <strings.h>
#include <string>
#include <ncurses.h>
#ifndef __APPLE__
#include <asm/types.h>
#include <asm/types.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
@@ -47,8 +47,7 @@ extern timeval curtime;
* key contains source ip, source port, destination ip, destination
* 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:
* - 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
* We must take care these never get removed from the list.
*/
Process * unknowntcp;
Process * unknownudp;
Process * unknownip;
ProcList * processes;
Process *unknowntcp;
Process *unknownudp;
Process *unknownip;
ProcList *processes;
/* We're migrating to having several `unknown' processes that are added as
* normal processes, instead of hard-wired unknown 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)
{
return ((double)bytes) / 1024 / 1024;
}
float tokb (u_int32_t bytes)
{
return ((double)bytes) / 1024;
float tokbps(u_int32_t bytes) { return (((double)bytes) / PERIOD) / 1024; }
void process_init() {
unknowntcp = new Process(0, "", "unknown TCP");
// unknownudp = new Process (0, "", "unknown UDP");
// unknownip = new Process (0, "", "unknown IP");
processes = new ProcList(unknowntcp, NULL);
// processes = new ProcList (unknownudp, processes);
// processes = new ProcList (unknownip, processes);
}
float tokbps (u_int32_t bytes)
{
return (((double)bytes) / PERIOD) / 1024;
}
void process_init ()
{
unknowntcp = new Process (0, "", "unknown TCP");
//unknownudp = new Process (0, "", "unknown UDP");
//unknownip = new Process (0, "", "unknown IP");
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;
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 */
void Process::getkbps (float * recvd, float * sent)
{
u_int32_t sum_sent = 0, sum_recv = 0;
void Process::getkbps(float *recvd, float *sent) {
u_int32_t sum_sent = 0, sum_recv = 0;
/* walk though all this process's connections, and sum
* them up */
ConnList * curconn = this->connections;
ConnList * previous = NULL;
while (curconn != NULL)
{
if (curconn->getVal()->getLastPacket() <= curtime.tv_sec - CONNTIMEOUT)
{
/* stalled connection, remove. */
ConnList * todelete = curconn;
Connection * conn_todelete = curconn->getVal();
curconn = curconn->getNext();
if (todelete == this->connections)
this->connections = curconn;
if (previous != NULL)
previous->setNext(curconn);
delete (todelete);
delete (conn_todelete);
}
else
{
u_int32_t sent = 0, recv = 0;
curconn->getVal()->sumanddel(curtime, &recv, &sent);
sum_sent += sent;
sum_recv += recv;
previous = curconn;
curconn = curconn->getNext();
}
}
*recvd = tokbps(sum_recv);
*sent = tokbps(sum_sent);
/* walk though all this process's connections, and sum
* them up */
ConnList *curconn = this->connections;
ConnList *previous = NULL;
while (curconn != NULL) {
if (curconn->getVal()->getLastPacket() <= curtime.tv_sec - CONNTIMEOUT) {
/* stalled connection, remove. */
ConnList *todelete = curconn;
Connection *conn_todelete = curconn->getVal();
curconn = curconn->getNext();
if (todelete == this->connections)
this->connections = curconn;
if (previous != NULL)
previous->setNext(curconn);
delete (todelete);
delete (conn_todelete);
} else {
u_int32_t sent = 0, recv = 0;
curconn->getVal()->sumanddel(curtime, &recv, &sent);
sum_sent += sent;
sum_recv += recv;
previous = curconn;
curconn = curconn->getNext();
}
}
*recvd = tokbps(sum_recv);
*sent = tokbps(sum_sent);
}
/** get total values for this process */
void Process::gettotal( u_int32_t * recvd, u_int32_t * sent)
{
u_int32_t sum_sent = 0, sum_recv = 0;
ConnList * curconn = this->connections;
while (curconn != NULL)
{
Connection * conn = curconn->getVal();
sum_sent += conn->sumSent;
sum_recv += conn->sumRecv;
curconn = curconn->getNext();
}
//std::cout << "Sum sent: " << sum_sent << std::endl;
//std::cout << "Sum recv: " << sum_recv << std::endl;
*recvd = sum_recv;
*sent = sum_sent;
void Process::gettotal(u_int32_t *recvd, u_int32_t *sent) {
u_int32_t sum_sent = 0, sum_recv = 0;
ConnList *curconn = this->connections;
while (curconn != NULL) {
Connection *conn = curconn->getVal();
sum_sent += conn->sumSent;
sum_recv += conn->sumRecv;
curconn = curconn->getNext();
}
// std::cout << "Sum sent: " << sum_sent << std::endl;
// std::cout << "Sum recv: " << sum_recv << std::endl;
*recvd = sum_recv;
*sent = sum_sent;
}
void Process::gettotalmb(float * recvd, float * sent)
{
u_int32_t sum_sent = 0, sum_recv = 0;
gettotal(&sum_recv, &sum_sent);
*recvd = tomb(sum_recv);
*sent = tomb(sum_sent);
void Process::gettotalmb(float *recvd, float *sent) {
u_int32_t sum_sent = 0, sum_recv = 0;
gettotal(&sum_recv, &sum_sent);
*recvd = tomb(sum_recv);
*sent = tomb(sum_sent);
}
/** get total values for this process */
void Process::gettotalkb(float * recvd, float * sent)
{
u_int32_t sum_sent = 0, sum_recv = 0;
gettotal(&sum_recv, &sum_sent);
*recvd = tokb(sum_recv);
*sent = tokb(sum_sent);
void Process::gettotalkb(float *recvd, float *sent) {
u_int32_t sum_sent = 0, sum_recv = 0;
gettotal(&sum_recv, &sum_sent);
*recvd = tokb(sum_recv);
*sent = tokb(sum_sent);
}
void Process::gettotalb(float * recvd, float * sent)
{
u_int32_t sum_sent = 0, sum_recv = 0;
gettotal(&sum_recv, &sum_sent);
//std::cout << "Total sent: " << sum_sent << std::endl;
*sent = sum_sent;
*recvd = sum_recv;
void Process::gettotalb(float *recvd, float *sent) {
u_int32_t sum_sent = 0, sum_recv = 0;
gettotal(&sum_recv, &sum_sent);
// std::cout << "Total sent: " << sum_sent << std::endl;
*sent = sum_sent;
*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)
{
ProcList * current = processes;
while (current != NULL)
{
Process * currentproc = current->getVal();
assert (currentproc != NULL);
if (node->pid == currentproc->pid)
return current->getVal();
current = current->next;
}
return NULL;
if (node->pid == currentproc->pid)
return current->getVal();
current = current->next;
}
return NULL;
}
/* finds process based on inode, if any */
/* should be done quickly after arrival of the packet,
* otherwise findPID will be outdated */
Process * findProcess (unsigned long inode)
{
struct prg_node * node = findPID(inode);
Process *findProcess(unsigned long inode) {
struct prg_node *node = findPID(inode);
if (node == NULL)
return NULL;
if (node == NULL)
return NULL;
return findProcess (node);
return findProcess(node);
}
int ProcList::size ()
{
int i=1;
int ProcList::size() {
int i = 1;
if (next != NULL)
i += next->size();
if (next != NULL)
i += next->size();
return i;
return i;
}
void check_all_procs ()
{
ProcList * curproc = processes;
while (curproc != NULL)
{
curproc->getVal()->check();
curproc = curproc->getNext();
}
void check_all_procs() {
ProcList *curproc = processes;
while (curproc != NULL) {
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 process is not yet in the proclist, add it
*/
Process * getProcess (unsigned long inode, const char * devicename)
{
struct prg_node * node = findPID(inode);
Process *getProcess(unsigned long inode, const char *devicename) {
struct prg_node *node = findPID(inode);
if (node == NULL)
{
if (DEBUG || bughuntmode)
std::cout << "No PID information for inode " << inode << std::endl;
return NULL;
}
if (node == NULL) {
if (DEBUG || bughuntmode)
std::cout << "No PID information for inode " << inode << std::endl;
return NULL;
}
Process * proc = findProcess (node);
Process *proc = findProcess(node);
if (proc != NULL)
return proc;
if (proc != NULL)
return proc;
Process * newproc = new Process (inode, devicename, node->name.c_str());
newproc->pid = node->pid;
Process *newproc = new Process(inode, devicename, node->name.c_str());
newproc->pid = node->pid;
char procdir [100];
sprintf(procdir , "/proc/%d", node->pid);
struct stat stats;
int retval = stat(procdir, &stats);
char procdir[100];
sprintf(procdir, "/proc/%d", node->pid);
struct stat stats;
int retval = stat(procdir, &stats);
/* 0 seems a proper default.
* used in case the PID disappeared while nethogs was running
* TODO we can store node->uid this while info on the inodes,
* right? */
/*
if (!ROBUST && (retval != 0))
{
std::cerr << "Couldn't stat " << procdir << std::endl;
assert (false);
}
*/
/* 0 seems a proper default.
* used in case the PID disappeared while nethogs was running
* TODO we can store node->uid this while info on the inodes,
* right? */
/*
if (!ROBUST && (retval != 0))
{
std::cerr << "Couldn't stat " << procdir << std::endl;
assert (false);
}
*/
if (retval != 0)
newproc->setUid(0);
else
newproc->setUid(stats.st_uid);
if (retval != 0)
newproc->setUid(0);
else
newproc->setUid(stats.st_uid);
/*if (getpwuid(stats.st_uid) == NULL) {
std::stderr << "uid for inode
if (!ROBUST)
assert(false);
}*/
processes = new ProcList (newproc, processes);
return newproc;
/*if (getpwuid(stats.st_uid) == NULL) {
std::stderr << "uid for inode
if (!ROBUST)
assert(false);
}*/
processes = new ProcList(newproc, processes);
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
* 'unknown' process.
*/
Process * getProcess (Connection * connection, const char * devicename)
{
unsigned long inode = conninode[connection->refpacket->gethashstring()];
Process *getProcess(Connection *connection, const char *devicename) {
unsigned long inode = conninode[connection->refpacket->gethashstring()];
if (inode == 0)
{
// no? refresh and check conn/inode table
if (bughuntmode)
{
std::cout << "? new connection not in connection-to-inode table before refresh.\n";
}
// refresh the inode->pid table first. Presumably processing the renewed connection->inode table
// is slow, making this worthwhile.
// We take the fact for granted that we might already know the inode->pid (unlikely anyway if we
// haven't seen the connection->inode yet though).
#ifndef __APPLE__
reread_mapping();
#endif
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;
}
if (inode == 0) {
// no? refresh and check conn/inode table
if (bughuntmode) {
std::cout << "? new connection not in connection-to-inode table before "
"refresh.\n";
}
// refresh the inode->pid table first. Presumably processing the renewed
// connection->inode table
// is slow, making this worthwhile.
// We take the fact for granted that we might already know the inode->pid
// (unlikely anyway if we
// haven't seen the connection->inode yet though).
#ifndef __APPLE__
reread_mapping();
#endif
}
else if (bughuntmode)
{
std::cout << ";) new connection in connection-to-inode table before refresh.\n";
}
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 */
if (bughuntmode)
{
std::cout << " inode # " << inode << std::endl;
}
/* we reverse the direction of the stream if
* successful. */
Packet *reversepacket = connection->refpacket->newInverted();
inode = conninode[reversepacket->gethashstring()];
Process * proc = NULL;
if (inode != 0)
proc = getProcess(inode, devicename);
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;
}
if (proc == NULL) {
proc = new Process (inode, "", connection->refpacket->gethashstring());
processes = new ProcList (proc, processes);
}
delete connection->refpacket;
connection->refpacket = reversepacket;
}
#endif
} else if (bughuntmode) {
std::cout
<< ";) new connection in connection-to-inode table before refresh.\n";
}
proc->connections = new ConnList (connection, proc->connections);
return proc;
if (bughuntmode) {
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 ()
{
//delete conninode;
prg_cache_clear();
void procclean() {
// delete conninode;
prg_cache_clear();
}

176
process.h
View File

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