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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

314
cui.cpp
View File

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

11
cui.h
View File

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

192
decpcap.c
View File

@@ -15,11 +15,11 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
#include <net/ethernet.h> #include <net/ethernet.h>
#include <net/if.h> #include <net/if.h>
#include <netinet/in.h> #include <netinet/in.h>
@@ -34,14 +34,13 @@
/* functions to set up a handle (which is basically just a pcap handle) */ /* functions to set up a handle (which is basically just a pcap handle) */
struct dp_handle * dp_fillhandle(pcap_t * phandle) struct dp_handle *dp_fillhandle(pcap_t *phandle) {
{ struct dp_handle *retval =
struct dp_handle * retval = (struct dp_handle *) malloc (sizeof (struct dp_handle)); (struct dp_handle *)malloc(sizeof(struct dp_handle));
int i; int i;
retval->pcap_handle = phandle; retval->pcap_handle = phandle;
for (i = 0; i < dp_n_packet_types; i++) for (i = 0; i < dp_n_packet_types; i++) {
{
retval->callback[i] = NULL; retval->callback[i] = NULL;
} }
@@ -66,24 +65,21 @@ struct dp_handle * dp_fillhandle(pcap_t * phandle)
return retval; return retval;
} }
struct dp_handle * dp_open_offline(char * fname, char * ebuf) struct dp_handle *dp_open_offline(char *fname, char *ebuf) {
{ pcap_t *temp = pcap_open_offline(fname, ebuf);
pcap_t * temp = pcap_open_offline(fname, ebuf);
if (temp == NULL) if (temp == NULL) {
{
return NULL; return NULL;
} }
return dp_fillhandle(temp); return dp_fillhandle(temp);
} }
struct dp_handle * dp_open_live(const char * device, int snaplen, int promisc, int to_ms, char * errbuf) struct dp_handle *dp_open_live(const char *device, int snaplen, int promisc,
{ int to_ms, char *errbuf) {
pcap_t * temp = pcap_open_live(device, snaplen, promisc, to_ms, errbuf); pcap_t *temp = pcap_open_live(device, snaplen, promisc, to_ms, errbuf);
if (temp == NULL) if (temp == NULL) {
{
return NULL; return NULL;
} }
@@ -92,48 +88,44 @@ struct dp_handle * dp_open_live(const char * device, int snaplen, int promisc, i
/* functions to add callbacks */ /* functions to add callbacks */
void dp_addcb (struct dp_handle * handle, enum dp_packet_type type, dp_callback callback) void dp_addcb(struct dp_handle *handle, enum dp_packet_type type,
{ dp_callback callback) {
handle->callback[type] = callback; handle->callback[type] = callback;
} }
/* functions for parsing the payloads */ /* functions for parsing the payloads */
void dp_parse_tcp (struct dp_handle * handle, const dp_header * header, const u_char * packet) void dp_parse_tcp(struct dp_handle *handle, const dp_header *header,
{ const u_char *packet) {
//const struct tcphdr * tcp = (struct tcphdr *) packet; // const struct tcphdr * tcp = (struct tcphdr *) packet;
//u_char * payload = (u_char *) packet + sizeof (struct tcphdr); // u_char * payload = (u_char *) packet + sizeof (struct tcphdr);
if (handle->callback[dp_packet_tcp] != NULL) if (handle->callback[dp_packet_tcp] != NULL) {
{ int done =
int done = (handle->callback[dp_packet_tcp]) (handle->callback[dp_packet_tcp])(handle->userdata, header, packet);
(handle->userdata, header, packet);
if (done) if (done)
return; return;
} }
// TODO: maybe `pass on' payload to lower-level protocol parsing // TODO: maybe `pass on' payload to lower-level protocol parsing
} }
void dp_parse_ip (struct dp_handle * handle, const dp_header * header, const u_char * packet) void dp_parse_ip(struct dp_handle *handle, const dp_header *header,
{ const u_char *packet) {
const struct ip * ip = (struct ip *) packet; const struct ip *ip = (struct ip *)packet;
if (DP_DEBUG) if (DP_DEBUG) {
{
fprintf(stdout, "Looking at packet with length %ud\n", header->len); fprintf(stdout, "Looking at packet with length %ud\n", header->len);
} }
u_char * payload = (u_char *) packet + sizeof (struct ip); u_char *payload = (u_char *)packet + sizeof(struct ip);
if (handle->callback[dp_packet_ip] != NULL) if (handle->callback[dp_packet_ip] != NULL) {
{ int done =
int done = (handle->callback[dp_packet_ip]) (handle->callback[dp_packet_ip])(handle->userdata, header, packet);
(handle->userdata, header, packet);
if (done) if (done)
return; return;
} }
switch (ip->ip_p) switch (ip->ip_p) {
{
case IPPROTO_TCP: case IPPROTO_TCP:
dp_parse_tcp (handle, header, payload); dp_parse_tcp(handle, header, payload);
break; break;
default: default:
// TODO: maybe support for non-tcp IP packets // TODO: maybe support for non-tcp IP packets
@@ -141,22 +133,20 @@ void dp_parse_ip (struct dp_handle * handle, const dp_header * header, const u_c
} }
} }
void dp_parse_ip6 (struct dp_handle * handle, const dp_header * header, const u_char * packet) void dp_parse_ip6(struct dp_handle *handle, const dp_header *header,
{ const u_char *packet) {
const struct ip6_hdr * ip6 = (struct ip6_hdr *) packet; const struct ip6_hdr *ip6 = (struct ip6_hdr *)packet;
u_char * payload = (u_char *) packet + sizeof (struct ip6_hdr); u_char *payload = (u_char *)packet + sizeof(struct ip6_hdr);
if (handle->callback[dp_packet_ip6] != NULL) if (handle->callback[dp_packet_ip6] != NULL) {
{ int done =
int done = (handle->callback[dp_packet_ip6]) (handle->callback[dp_packet_ip6])(handle->userdata, header, packet);
(handle->userdata, header, packet);
if (done) if (done)
return; return;
} }
switch ((ip6->ip6_ctlun).ip6_un1.ip6_un1_nxt) switch ((ip6->ip6_ctlun).ip6_un1.ip6_un1_nxt) {
{
case IPPROTO_TCP: case IPPROTO_TCP:
dp_parse_tcp (handle, header, payload); dp_parse_tcp(handle, header, payload);
break; break;
default: default:
// TODO: maybe support for non-tcp ipv6 packets // TODO: maybe support for non-tcp ipv6 packets
@@ -164,17 +154,16 @@ void dp_parse_ip6 (struct dp_handle * handle, const dp_header * header, const u_
} }
} }
void dp_parse_ethernet (struct dp_handle * handle, const dp_header * header, const u_char * packet) void dp_parse_ethernet(struct dp_handle *handle, const dp_header *header,
{ const u_char *packet) {
const struct ether_header * ethernet = (struct ether_header *)packet; const struct ether_header *ethernet = (struct ether_header *)packet;
u_char * payload = (u_char *) packet + sizeof (struct ether_header); u_char *payload = (u_char *)packet + sizeof(struct ether_header);
u_int16_t protocol = 0; u_int16_t protocol = 0;
/* call handle if it exists */ /* call handle if it exists */
if (handle->callback[dp_packet_ethernet] != NULL) if (handle->callback[dp_packet_ethernet] != NULL) {
{ int done = (handle->callback[dp_packet_ethernet])(handle->userdata, header,
int done = (handle->callback[dp_packet_ethernet]) packet);
(handle->userdata, header, packet);
/* return if handle decides we're done */ /* return if handle decides we're done */
if (done) if (done)
@@ -183,13 +172,12 @@ void dp_parse_ethernet (struct dp_handle * handle, const dp_header * header, con
/* parse payload */ /* parse payload */
protocol = ntohs(ethernet->ether_type); protocol = ntohs(ethernet->ether_type);
switch (protocol) switch (protocol) {
{
case ETHERTYPE_IP: case ETHERTYPE_IP:
dp_parse_ip (handle, header, payload); dp_parse_ip(handle, header, payload);
break; break;
case ETHERTYPE_IPV6: case ETHERTYPE_IPV6:
dp_parse_ip6 (handle, header, payload); dp_parse_ip6(handle, header, payload);
break; break;
default: default:
// TODO: maybe support for other protocols apart from IPv4 and IPv6 // TODO: maybe support for other protocols apart from IPv4 and IPv6
@@ -212,17 +200,16 @@ struct ppp_header {
u_int16_t packettype; u_int16_t packettype;
}; };
void dp_parse_ppp (struct dp_handle * handle, const dp_header * header, const u_char * packet) void dp_parse_ppp(struct dp_handle *handle, const dp_header *header,
{ const u_char *packet) {
const struct ppp_header * ppp = (struct ppp_header *) packet; const struct ppp_header *ppp = (struct ppp_header *)packet;
u_char * payload = (u_char *) packet + sizeof (struct ppp_header); u_char *payload = (u_char *)packet + sizeof(struct ppp_header);
u_int16_t protocol = 0; u_int16_t protocol = 0;
/* call handle if it exists */ /* call handle if it exists */
if (handle->callback[dp_packet_ppp] != NULL) if (handle->callback[dp_packet_ppp] != NULL) {
{ int done =
int done = (handle->callback[dp_packet_ppp]) (handle->callback[dp_packet_ppp])(handle->userdata, header, packet);
(handle->userdata, header, packet);
/* return if handle decides we're done */ /* return if handle decides we're done */
if (done) if (done)
@@ -231,13 +218,12 @@ void dp_parse_ppp (struct dp_handle * handle, const dp_header * header, const u_
/* parse payload */ /* parse payload */
protocol = ntohs(ppp->packettype); protocol = ntohs(ppp->packettype);
switch (protocol) switch (protocol) {
{
case ETHERTYPE_IP: case ETHERTYPE_IP:
dp_parse_ip (handle, header, payload); dp_parse_ip(handle, header, payload);
break; break;
case ETHERTYPE_IPV6: case ETHERTYPE_IPV6:
dp_parse_ip6 (handle, header, payload); dp_parse_ip6(handle, header, payload);
break; break;
default: default:
// TODO: support for other than IPv4 and IPv6 // TODO: support for other than IPv4 and IPv6
@@ -256,17 +242,16 @@ struct sll_header {
u_int16_t sll_protocol; /* protocol */ u_int16_t sll_protocol; /* protocol */
}; };
void dp_parse_linux_cooked (struct dp_handle * handle, const dp_header * header, const u_char * packet) void dp_parse_linux_cooked(struct dp_handle *handle, const dp_header *header,
{ const u_char *packet) {
const struct sll_header * sll = (struct sll_header *) packet; const struct sll_header *sll = (struct sll_header *)packet;
u_char * payload = (u_char *) packet + sizeof (struct sll_header); u_char *payload = (u_char *)packet + sizeof(struct sll_header);
u_int16_t protocol = 0; u_int16_t protocol = 0;
/* call handle if it exists */ /* call handle if it exists */
if (handle->callback[dp_packet_sll] != NULL) if (handle->callback[dp_packet_sll] != NULL) {
{ int done =
int done = (handle->callback[dp_packet_sll]) (handle->callback[dp_packet_sll])(handle->userdata, header, packet);
(handle->userdata, header, packet);
/* return if handle decides we're done */ /* return if handle decides we're done */
if (done) if (done)
@@ -275,13 +260,12 @@ void dp_parse_linux_cooked (struct dp_handle * handle, const dp_header * header,
/* parse payload */ /* parse payload */
protocol = ntohs(sll->sll_protocol); protocol = ntohs(sll->sll_protocol);
switch (protocol) switch (protocol) {
{
case ETHERTYPE_IP: case ETHERTYPE_IP:
dp_parse_ip (handle, header, payload); dp_parse_ip(handle, header, payload);
break; break;
case ETHERTYPE_IPV6: case ETHERTYPE_IPV6:
dp_parse_ip6 (handle, header, payload); dp_parse_ip6(handle, header, payload);
break; break;
default: default:
// TODO: support for other than IPv4 / IPv6 // TODO: support for other than IPv4 / IPv6
@@ -290,48 +274,48 @@ void dp_parse_linux_cooked (struct dp_handle * handle, const dp_header * header,
} }
/* functions to do the monitoring */ /* functions to do the monitoring */
void dp_pcap_callback (u_char * u_handle, const struct pcap_pkthdr * header, const u_char * packet) void dp_pcap_callback(u_char *u_handle, const struct pcap_pkthdr *header,
{ const u_char *packet) {
struct dp_handle * handle = (struct dp_handle *) u_handle; struct dp_handle *handle = (struct dp_handle *)u_handle;
struct dp_header; struct dp_header;
/* make a copy of the userdata for every packet */ /* make a copy of the userdata for every packet */
u_char * userdata_copy = (u_char *) malloc (handle->userdata_size); u_char *userdata_copy = (u_char *)malloc(handle->userdata_size);
memcpy (userdata_copy, handle->userdata, handle->userdata_size); memcpy(userdata_copy, handle->userdata, handle->userdata_size);
switch (handle->linktype) { switch (handle->linktype) {
case (DLT_EN10MB): case (DLT_EN10MB):
dp_parse_ethernet (handle, header, packet); dp_parse_ethernet(handle, header, packet);
break; break;
case (DLT_PPP): case (DLT_PPP):
dp_parse_ppp (handle, header, packet); dp_parse_ppp(handle, header, packet);
break; break;
case (DLT_LINUX_SLL): case (DLT_LINUX_SLL):
dp_parse_linux_cooked (handle, header, packet); dp_parse_linux_cooked(handle, header, packet);
break; break;
case (DLT_RAW): case (DLT_RAW):
case (DLT_NULL): case (DLT_NULL):
// hope for the best // hope for the best
dp_parse_ip (handle, header, packet); dp_parse_ip(handle, header, packet);
break; break;
default: default:
fprintf(stdout, "Unknown linktype %d", handle->linktype); fprintf(stdout, "Unknown linktype %d", handle->linktype);
break; break;
} }
free (userdata_copy); free(userdata_copy);
} }
int dp_dispatch (struct dp_handle * handle, int count, u_char *user, int size) { int dp_dispatch(struct dp_handle *handle, int count, u_char *user, int size) {
handle->userdata = user; handle->userdata = user;
handle->userdata_size = size; handle->userdata_size = size;
return pcap_dispatch (handle->pcap_handle, count, dp_pcap_callback, (u_char *)handle); return pcap_dispatch(handle->pcap_handle, count, dp_pcap_callback,
(u_char *)handle);
} }
int dp_setnonblock (struct dp_handle * handle, int i, char * errbuf) { int dp_setnonblock(struct dp_handle *handle, int i, char *errbuf) {
return pcap_setnonblock (handle->pcap_handle, i, errbuf); return pcap_setnonblock(handle->pcap_handle, i, errbuf);
} }
char * dp_geterr (struct dp_handle * handle) char *dp_geterr(struct dp_handle *handle) {
{ return pcap_geterr(handle->pcap_handle);
return pcap_geterr (handle->pcap_handle);
} }

View File

@@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
*USA.
* *
*/ */
#ifndef __DECPCAP_H #ifndef __DECPCAP_H
@@ -54,36 +55,38 @@ typedef struct pcap_pkthdr dp_header;
typedef int (*dp_callback)(u_char *, const dp_header *, const u_char *); typedef int (*dp_callback)(u_char *, const dp_header *, const u_char *);
struct dp_handle { struct dp_handle {
pcap_t * pcap_handle; pcap_t *pcap_handle;
dp_callback callback [dp_n_packet_types]; dp_callback callback[dp_n_packet_types];
int linktype; int linktype;
u_char * userdata; u_char *userdata;
int userdata_size; int userdata_size;
}; };
/* functions to set up a handle (which is basically just a pcap handle) */ /* functions to set up a handle (which is basically just a pcap handle) */
struct dp_handle * dp_open_live(const char * device, int snaplen, int promisc, int to_ms, char * errbuf); struct dp_handle *dp_open_live(const char *device, int snaplen, int promisc,
struct dp_handle * dp_open_offline(char * fname, char * ebuf); int to_ms, char *errbuf);
struct dp_handle *dp_open_offline(char *fname, char *ebuf);
/* functions to add callbacks */ /* functions to add callbacks */
void dp_addcb (struct dp_handle * handle, enum dp_packet_type type, dp_callback callback); void dp_addcb(struct dp_handle *handle, enum dp_packet_type type,
dp_callback callback);
/* functions to parse payloads */ /* functions to parse payloads */
void dp_parse (enum dp_packet_type type, void * packet); void dp_parse(enum dp_packet_type type, void *packet);
/* functions to start monitoring */ /* functions to start monitoring */
int dp_dispatch (struct dp_handle * handler, int count, u_char *user, int size); int dp_dispatch(struct dp_handle *handler, int count, u_char *user, int size);
/* functions that simply call libpcap */ /* functions that simply call libpcap */
int dp_datalink(struct dp_handle * handle); int dp_datalink(struct dp_handle *handle);
int dp_setnonblock (struct dp_handle * handle, int i, char * errbuf); int dp_setnonblock(struct dp_handle *handle, int i, char *errbuf);
char * dp_geterr (struct dp_handle * handle); char *dp_geterr(struct dp_handle *handle);
#endif #endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

183
main.cpp
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

128
process.h
View File

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