Merge branch 'master' of github.com:raboof/nethogs
This commit is contained in:
4
Makefile
4
Makefile
@@ -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
|
||||||
|
|||||||
27
README.md
27
README.md
@@ -44,22 +44,19 @@ 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:
|
Note to contributors: feel free to request more exceptions and we'll list them
|
||||||
* '{'
|
here.
|
||||||
* on a new line for function definitions
|
|
||||||
* on a new line for enums
|
Not all code currently adheres to this standard. Pull requests fixing style
|
||||||
* on the same line for conditionals/loops
|
are welcome, and do write new code in the proper style, but please do not
|
||||||
* omitted when possible
|
mix style fixes and new functionality in one pull request.
|
||||||
* use tab for indentation
|
|
||||||
* use doxygen/javadoc-style comments.
|
When writing new code, at least run 'make format' to have clang-format fix
|
||||||
* for multiline doxygen docs, add a newline after '/**'
|
some superficial style aspects.
|
||||||
* case
|
|
||||||
* classes: camelcased, start uppercase
|
|
||||||
* enums: camelcased, start uppercase
|
|
||||||
* functions: camelcased, start lowercase
|
|
||||||
* local variables: camelcased, start lowercase
|
|
||||||
|
|
||||||
libnethogs
|
libnethogs
|
||||||
----------
|
----------
|
||||||
|
|||||||
314
connection.cpp
314
connection.cpp
@@ -1,4 +1,4 @@
|
|||||||
/*
|
/*
|
||||||
* connection.cpp
|
* connection.cpp
|
||||||
*
|
*
|
||||||
* Copyright (c) 2004-2006,2008 Arnout Engelen
|
* Copyright (c) 2004-2006,2008 Arnout Engelen
|
||||||
@@ -15,224 +15,198 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <sys/malloc.h>
|
#include <sys/malloc.h>
|
||||||
#else
|
#else
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#endif
|
#endif
|
||||||
#include "nethogs.h"
|
#include "nethogs.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
|
|
||||||
ConnList * connections = NULL;
|
ConnList *connections = NULL;
|
||||||
|
|
||||||
void PackList::add (Packet * p)
|
void PackList::add(Packet *p) {
|
||||||
{
|
if (content == NULL) {
|
||||||
if (content == NULL)
|
content = new PackListNode(new Packet(*p));
|
||||||
{
|
return;
|
||||||
content = new PackListNode (new Packet (*p));
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (content->val->time.tv_sec == p->time.tv_sec)
|
if (content->val->time.tv_sec == p->time.tv_sec) {
|
||||||
{
|
content->val->len += p->len;
|
||||||
content->val->len += p->len;
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* store copy of packet, so that original may be freed */
|
/* store copy of packet, so that original may be freed */
|
||||||
content = new PackListNode(new Packet (*p), content);
|
content = new PackListNode(new Packet(*p), content);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sums up the total bytes used and removes 'old' packets */
|
/* sums up the total bytes used and removes 'old' packets */
|
||||||
u_int32_t PackList::sumanddel (timeval t)
|
u_int32_t PackList::sumanddel(timeval t) {
|
||||||
{
|
u_int32_t retval = 0;
|
||||||
u_int32_t retval = 0;
|
PackListNode *current = content;
|
||||||
PackListNode * current = content;
|
PackListNode *previous = NULL;
|
||||||
PackListNode * previous = NULL;
|
|
||||||
|
|
||||||
while (current != NULL)
|
while (current != NULL) {
|
||||||
{
|
// std::cout << "Comparing " << current->val->time.tv_sec << " <= " <<
|
||||||
//std::cout << "Comparing " << current->val->time.tv_sec << " <= " << t.tv_sec - PERIOD << endl;
|
// t.tv_sec - PERIOD << endl;
|
||||||
if (current->val->time.tv_sec <= t.tv_sec - PERIOD)
|
if (current->val->time.tv_sec <= t.tv_sec - PERIOD) {
|
||||||
{
|
if (current == content)
|
||||||
if (current == content)
|
content = NULL;
|
||||||
content = NULL;
|
else if (previous != NULL)
|
||||||
else if (previous != NULL)
|
previous->next = NULL;
|
||||||
previous->next = NULL;
|
delete current;
|
||||||
delete current;
|
return retval;
|
||||||
return retval;
|
}
|
||||||
}
|
retval += current->val->len;
|
||||||
retval += current->val->len;
|
previous = current;
|
||||||
previous = current;
|
current = current->next;
|
||||||
current = current->next;
|
}
|
||||||
}
|
return retval;
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* packet may be deleted by caller */
|
/* packet may be deleted by caller */
|
||||||
Connection::Connection (Packet * packet)
|
Connection::Connection(Packet *packet) {
|
||||||
{
|
assert(packet != NULL);
|
||||||
assert (packet != NULL);
|
connections = new ConnList(this, connections);
|
||||||
connections = new ConnList (this, connections);
|
sent_packets = new PackList();
|
||||||
sent_packets = new PackList ();
|
recv_packets = new PackList();
|
||||||
recv_packets = new PackList ();
|
sumSent = 0;
|
||||||
sumSent = 0;
|
sumRecv = 0;
|
||||||
sumRecv = 0;
|
if (DEBUG) {
|
||||||
if (DEBUG)
|
std::cout << "New connection, with package len " << packet->len
|
||||||
{
|
<< std::endl;
|
||||||
std::cout << "New connection, with package len " << packet->len << std::endl;
|
}
|
||||||
}
|
if (packet->Outgoing()) {
|
||||||
if (packet->Outgoing())
|
sumSent += packet->len;
|
||||||
{
|
sent_packets->add(packet);
|
||||||
sumSent += packet->len;
|
refpacket = new Packet(*packet);
|
||||||
sent_packets->add(packet);
|
} else {
|
||||||
refpacket = new Packet (*packet);
|
sumRecv += packet->len;
|
||||||
} else {
|
recv_packets->add(packet);
|
||||||
sumRecv += packet->len;
|
refpacket = packet->newInverted();
|
||||||
recv_packets->add(packet);
|
}
|
||||||
refpacket = packet->newInverted();
|
lastpacket = packet->time.tv_sec;
|
||||||
}
|
if (DEBUG)
|
||||||
lastpacket = packet->time.tv_sec;
|
std::cout << "New reference packet created at " << refpacket << std::endl;
|
||||||
if (DEBUG)
|
|
||||||
std::cout << "New reference packet created at " << refpacket << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection::~Connection ()
|
Connection::~Connection() {
|
||||||
{
|
if (DEBUG)
|
||||||
if (DEBUG)
|
std::cout << "Deleting connection" << std::endl;
|
||||||
std::cout << "Deleting connection" << std::endl;
|
/* refpacket is not a pointer to one of the packets in the lists
|
||||||
/* refpacket is not a pointer to one of the packets in the lists
|
* so deleted */
|
||||||
* so deleted */
|
delete (refpacket);
|
||||||
delete (refpacket);
|
if (sent_packets != NULL)
|
||||||
if (sent_packets != NULL)
|
delete sent_packets;
|
||||||
delete sent_packets;
|
if (recv_packets != NULL)
|
||||||
if (recv_packets != NULL)
|
delete recv_packets;
|
||||||
delete recv_packets;
|
|
||||||
|
|
||||||
ConnList * curr_conn = connections;
|
ConnList *curr_conn = connections;
|
||||||
ConnList * prev_conn = NULL;
|
ConnList *prev_conn = NULL;
|
||||||
while (curr_conn != NULL)
|
while (curr_conn != NULL) {
|
||||||
{
|
if (curr_conn->getVal() == this) {
|
||||||
if (curr_conn->getVal() == this)
|
ConnList *todelete = curr_conn;
|
||||||
{
|
curr_conn = curr_conn->getNext();
|
||||||
ConnList * todelete = curr_conn;
|
if (prev_conn == NULL) {
|
||||||
curr_conn = curr_conn->getNext();
|
connections = curr_conn;
|
||||||
if (prev_conn == NULL)
|
} else {
|
||||||
{
|
prev_conn->setNext(curr_conn);
|
||||||
connections = curr_conn;
|
}
|
||||||
} else {
|
delete (todelete);
|
||||||
prev_conn->setNext(curr_conn);
|
} else {
|
||||||
}
|
prev_conn = curr_conn;
|
||||||
delete (todelete);
|
curr_conn = curr_conn->getNext();
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
|
||||||
prev_conn = curr_conn;
|
|
||||||
curr_conn = curr_conn->getNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the packet will be freed by the calling code */
|
/* the packet will be freed by the calling code */
|
||||||
void Connection::add (Packet * packet)
|
void Connection::add(Packet *packet) {
|
||||||
{
|
lastpacket = packet->time.tv_sec;
|
||||||
lastpacket = packet->time.tv_sec;
|
if (packet->Outgoing()) {
|
||||||
if (packet->Outgoing())
|
if (DEBUG) {
|
||||||
{
|
std::cout << "Outgoing: " << packet->len << std::endl;
|
||||||
if (DEBUG)
|
}
|
||||||
{
|
sumSent += packet->len;
|
||||||
std::cout << "Outgoing: " << packet->len << std::endl;
|
sent_packets->add(packet);
|
||||||
}
|
} else {
|
||||||
sumSent += packet->len;
|
if (DEBUG) {
|
||||||
sent_packets->add (packet);
|
std::cout << "Incoming: " << packet->len << std::endl;
|
||||||
}
|
}
|
||||||
else
|
sumRecv += packet->len;
|
||||||
{
|
if (DEBUG) {
|
||||||
if (DEBUG)
|
std::cout << "sumRecv now: " << sumRecv << std::endl;
|
||||||
{
|
}
|
||||||
std::cout << "Incoming: " << packet->len << std::endl;
|
recv_packets->add(packet);
|
||||||
}
|
}
|
||||||
sumRecv += packet->len;
|
|
||||||
if (DEBUG)
|
|
||||||
{
|
|
||||||
std::cout << "sumRecv now: " << sumRecv << std::endl;
|
|
||||||
}
|
|
||||||
recv_packets->add (packet);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection * findConnectionWithMatchingSource(Packet * packet) {
|
Connection *findConnectionWithMatchingSource(Packet *packet) {
|
||||||
assert(packet->Outgoing());
|
assert(packet->Outgoing());
|
||||||
|
|
||||||
ConnList * current = connections;
|
ConnList *current = connections;
|
||||||
while (current != NULL)
|
while (current != NULL) {
|
||||||
{
|
/* the reference packet is always outgoing */
|
||||||
/* the reference packet is always outgoing */
|
if (packet->matchSource(current->getVal()->refpacket)) {
|
||||||
if (packet->matchSource(current->getVal()->refpacket))
|
return current->getVal();
|
||||||
{
|
}
|
||||||
return current->getVal();
|
|
||||||
}
|
|
||||||
|
|
||||||
current = current->getNext();
|
current = current->getNext();
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection * findConnectionWithMatchingRefpacketOrSource(Packet * packet) {
|
Connection *findConnectionWithMatchingRefpacketOrSource(Packet *packet) {
|
||||||
ConnList * current = connections;
|
ConnList *current = connections;
|
||||||
while (current != NULL)
|
while (current != NULL) {
|
||||||
{
|
/* the reference packet is always *outgoing* */
|
||||||
/* the reference packet is always *outgoing* */
|
if (packet->match(current->getVal()->refpacket)) {
|
||||||
if (packet->match(current->getVal()->refpacket))
|
return current->getVal();
|
||||||
{
|
}
|
||||||
return current->getVal();
|
|
||||||
}
|
|
||||||
|
|
||||||
current = current->getNext();
|
current = current->getNext();
|
||||||
}
|
}
|
||||||
return findConnectionWithMatchingSource(packet);
|
return findConnectionWithMatchingSource(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* finds connection to which this packet belongs.
|
* finds connection to which this packet belongs.
|
||||||
* a packet belongs to a connection if it matches
|
* a packet belongs to a connection if it matches
|
||||||
* to its reference packet
|
* to its reference packet
|
||||||
*/
|
*/
|
||||||
Connection * findConnection (Packet * packet)
|
Connection *findConnection(Packet *packet) {
|
||||||
{
|
if (packet->Outgoing())
|
||||||
if (packet->Outgoing())
|
return findConnectionWithMatchingRefpacketOrSource(packet);
|
||||||
return findConnectionWithMatchingRefpacketOrSource(packet);
|
else {
|
||||||
else
|
Packet *invertedPacket = packet->newInverted();
|
||||||
{
|
Connection *result =
|
||||||
Packet * invertedPacket = packet->newInverted();
|
findConnectionWithMatchingRefpacketOrSource(invertedPacket);
|
||||||
Connection * result = findConnectionWithMatchingRefpacketOrSource(invertedPacket);
|
|
||||||
|
|
||||||
delete invertedPacket;
|
delete invertedPacket;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Connection::sumanddel
|
* Connection::sumanddel
|
||||||
*
|
*
|
||||||
* sums up the total bytes used
|
* sums up the total bytes used
|
||||||
* and removes 'old' packets.
|
* and removes 'old' packets.
|
||||||
*
|
*
|
||||||
* Returns sum of sent packages (by address)
|
* Returns sum of sent packages (by address)
|
||||||
* sum of recieved packages (by address)
|
* sum of recieved packages (by address)
|
||||||
*/
|
*/
|
||||||
void Connection::sumanddel (timeval t, u_int32_t * recv, u_int32_t * sent)
|
void Connection::sumanddel(timeval t, u_int32_t *recv, u_int32_t *sent) {
|
||||||
{
|
(*sent) = (*recv) = 0;
|
||||||
(*sent)=(*recv)=0;
|
|
||||||
|
|
||||||
*sent = sent_packets->sumanddel(t);
|
*sent = sent_packets->sumanddel(t);
|
||||||
*recv = recv_packets->sumanddel(t);
|
*recv = recv_packets->sumanddel(t);
|
||||||
}
|
}
|
||||||
|
|||||||
124
connection.h
124
connection.h
@@ -15,7 +15,8 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#ifndef __CONNECTION_H
|
#ifndef __CONNECTION_H
|
||||||
@@ -24,91 +25,82 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
|
|
||||||
class PackListNode
|
class PackListNode {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
PackListNode (Packet * m_val, PackListNode * m_next = NULL)
|
PackListNode(Packet *m_val, PackListNode *m_next = NULL) {
|
||||||
{
|
val = m_val;
|
||||||
val = m_val;
|
next = m_next;
|
||||||
next = m_next;
|
}
|
||||||
}
|
~PackListNode() {
|
||||||
~PackListNode ()
|
delete val;
|
||||||
{
|
if (next != NULL)
|
||||||
delete val;
|
delete next;
|
||||||
if (next != NULL)
|
}
|
||||||
delete next;
|
PackListNode *next;
|
||||||
}
|
Packet *val;
|
||||||
PackListNode * next;
|
|
||||||
Packet * val;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PackList
|
class PackList {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
PackList ()
|
PackList() { content = NULL; }
|
||||||
{
|
PackList(Packet *m_val) {
|
||||||
content = NULL;
|
assert(m_val != NULL);
|
||||||
}
|
content = new PackListNode(m_val);
|
||||||
PackList (Packet * m_val)
|
}
|
||||||
{
|
~PackList() {
|
||||||
assert (m_val != NULL);
|
if (content != NULL)
|
||||||
content = new PackListNode(m_val);
|
delete content;
|
||||||
}
|
}
|
||||||
~PackList ()
|
|
||||||
{
|
|
||||||
if (content != NULL)
|
|
||||||
delete content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* sums up the total bytes used and removes 'old' packets */
|
/* sums up the total bytes used and removes 'old' packets */
|
||||||
u_int32_t sumanddel (timeval t);
|
u_int32_t sumanddel(timeval t);
|
||||||
|
|
||||||
|
/* calling code may delete packet */
|
||||||
|
void add(Packet *p);
|
||||||
|
|
||||||
/* calling code may delete packet */
|
|
||||||
void add (Packet * p);
|
|
||||||
private:
|
private:
|
||||||
PackListNode * content;
|
PackListNode *content;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Connection
|
class Connection {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
/* constructs a connection, makes a copy of
|
/* constructs a connection, makes a copy of
|
||||||
* the packet as 'refpacket', and adds the
|
* the packet as 'refpacket', and adds the
|
||||||
* packet to the packlist */
|
* packet to the packlist */
|
||||||
/* packet may be deleted by caller */
|
/* packet may be deleted by caller */
|
||||||
Connection (Packet * packet);
|
Connection(Packet *packet);
|
||||||
|
|
||||||
~Connection();
|
~Connection();
|
||||||
|
|
||||||
/* add a packet to the packlist
|
/* add a packet to the packlist
|
||||||
* will delete the packet structure
|
* will delete the packet structure
|
||||||
* when it is 'merged with' (added to) another
|
* when it is 'merged with' (added to) another
|
||||||
* packet
|
* packet
|
||||||
*/
|
*/
|
||||||
void add (Packet * packet);
|
void add(Packet *packet);
|
||||||
|
|
||||||
int getLastPacket ()
|
int getLastPacket() { return lastpacket; }
|
||||||
{ return lastpacket; }
|
|
||||||
|
|
||||||
/* sums up the total bytes used
|
/* sums up the total bytes used
|
||||||
* and removes 'old' packets. */
|
* and removes 'old' packets. */
|
||||||
void sumanddel(timeval curtime, u_int32_t * recv, u_int32_t * sent);
|
void sumanddel(timeval curtime, u_int32_t *recv, u_int32_t *sent);
|
||||||
|
|
||||||
/* for checking if a packet is part of this connection */
|
/* for checking if a packet is part of this connection */
|
||||||
/* the reference packet is always *outgoing*. */
|
/* the reference packet is always *outgoing*. */
|
||||||
Packet * refpacket;
|
Packet *refpacket;
|
||||||
|
|
||||||
|
/* total sum or sent/received bytes */
|
||||||
|
u_int32_t sumSent;
|
||||||
|
u_int32_t sumRecv;
|
||||||
|
|
||||||
/* total sum or sent/received bytes */
|
|
||||||
u_int32_t sumSent;
|
|
||||||
u_int32_t sumRecv;
|
|
||||||
private:
|
private:
|
||||||
PackList * sent_packets;
|
PackList *sent_packets;
|
||||||
PackList * recv_packets;
|
PackList *recv_packets;
|
||||||
int lastpacket;
|
int lastpacket;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Find the connection this packet belongs to */
|
/* Find the connection this packet belongs to */
|
||||||
/* (the calling code may free the packet afterwards) */
|
/* (the calling code may free the packet afterwards) */
|
||||||
Connection * findConnection (Packet * packet);
|
Connection *findConnection(Packet *packet);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
255
conninode.cpp
255
conninode.cpp
@@ -15,11 +15,11 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@@ -29,173 +29,168 @@
|
|||||||
#include "conninode.h"
|
#include "conninode.h"
|
||||||
|
|
||||||
#if defined __APPLE__
|
#if defined __APPLE__
|
||||||
#ifndef s6_addr32
|
#ifndef s6_addr32
|
||||||
#define s6_addr32 __u6_addr.__u6_addr32
|
#define s6_addr32 __u6_addr.__u6_addr32
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern local_addr * local_addrs;
|
extern local_addr *local_addrs;
|
||||||
/*
|
/*
|
||||||
* connection-inode table. takes information from /proc/net/tcp.
|
* connection-inode table. takes information from /proc/net/tcp.
|
||||||
* key contains source ip, source port, destination ip, destination
|
* key contains source ip, source port, destination ip, destination
|
||||||
* port in format: '1.2.3.4:5-1.2.3.4:5'
|
* port in format: '1.2.3.4:5-1.2.3.4:5'
|
||||||
*/
|
*/
|
||||||
std::map <std::string, unsigned long> conninode;
|
std::map<std::string, unsigned long> conninode;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* parses a /proc/net/tcp-line of the form:
|
* parses a /proc/net/tcp-line of the form:
|
||||||
* sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
|
* sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt
|
||||||
* 10: 020310AC:1770 9DD8A9C3:A525 01 00000000:00000000 00:00000000 00000000 0 0 2119 1 c0f4f0c0 206 40 10 3 -1
|
*uid timeout inode
|
||||||
* 11: 020310AC:0404 936B2ECF:0747 01 00000000:00000000 00:00000000 00000000 1000 0 2109 1 c0f4fc00 368 40 20 2 -1
|
* 10: 020310AC:1770 9DD8A9C3:A525 01 00000000:00000000 00:00000000 00000000
|
||||||
|
*0 0 2119 1 c0f4f0c0 206 40 10 3 -1
|
||||||
|
* 11: 020310AC:0404 936B2ECF:0747 01 00000000:00000000 00:00000000 00000000
|
||||||
|
*1000 0 2109 1 c0f4fc00 368 40 20 2 -1
|
||||||
*
|
*
|
||||||
* and of the form:
|
* and of the form:
|
||||||
* 2: 0000000000000000FFFF0000020310AC:0016 0000000000000000FFFF00009DD8A9C3:A526 01 00000000:00000000 02:000A7214 00000000 0 0 2525 2 c732eca0 201 40 1 2 -1
|
* 2: 0000000000000000FFFF0000020310AC:0016
|
||||||
|
*0000000000000000FFFF00009DD8A9C3:A526 01 00000000:00000000 02:000A7214
|
||||||
|
*00000000 0 0 2525 2 c732eca0 201 40 1 2 -1
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void addtoconninode (char * buffer)
|
void addtoconninode(char *buffer) {
|
||||||
{
|
short int sa_family;
|
||||||
short int sa_family;
|
struct in6_addr result_addr_local;
|
||||||
struct in6_addr result_addr_local;
|
struct in6_addr result_addr_remote;
|
||||||
struct in6_addr result_addr_remote;
|
|
||||||
|
|
||||||
char rem_addr[128], local_addr[128];
|
char rem_addr[128], local_addr[128];
|
||||||
int local_port, rem_port;
|
int local_port, rem_port;
|
||||||
struct in6_addr in6_local;
|
struct in6_addr in6_local;
|
||||||
struct in6_addr in6_remote;
|
struct in6_addr in6_remote;
|
||||||
|
|
||||||
// this leaked memory
|
// this leaked memory
|
||||||
//unsigned long * inode = (unsigned long *) malloc (sizeof(unsigned long));
|
// unsigned long * inode = (unsigned long *) malloc (sizeof(unsigned long));
|
||||||
unsigned long inode;
|
unsigned long inode;
|
||||||
|
|
||||||
int matches = sscanf(buffer, "%*d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %*X %*X:%*X %*X:%*X %*X %*d %*d %ld %*512s\n",
|
int matches = sscanf(buffer, "%*d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %*X "
|
||||||
local_addr, &local_port, rem_addr, &rem_port, &inode);
|
"%*X:%*X %*X:%*X %*X %*d %*d %ld %*512s\n",
|
||||||
|
local_addr, &local_port, rem_addr, &rem_port, &inode);
|
||||||
|
|
||||||
if (matches != 5) {
|
if (matches != 5) {
|
||||||
fprintf(stderr,"Unexpected buffer: '%s'\n",buffer);
|
fprintf(stderr, "Unexpected buffer: '%s'\n", buffer);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inode == 0) {
|
if (inode == 0) {
|
||||||
/* connection is in TIME_WAIT state. We rely on
|
/* connection is in TIME_WAIT state. We rely on
|
||||||
* the old data still in the table. */
|
* the old data still in the table. */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(local_addr) > 8)
|
if (strlen(local_addr) > 8) {
|
||||||
{
|
/* this is an IPv6-style row */
|
||||||
/* this is an IPv6-style row */
|
|
||||||
|
|
||||||
/* Demangle what the kernel gives us */
|
/* Demangle what the kernel gives us */
|
||||||
sscanf(local_addr, "%08X%08X%08X%08X",
|
sscanf(local_addr, "%08X%08X%08X%08X", &in6_local.s6_addr32[0],
|
||||||
&in6_local.s6_addr32[0], &in6_local.s6_addr32[1],
|
&in6_local.s6_addr32[1], &in6_local.s6_addr32[2],
|
||||||
&in6_local.s6_addr32[2], &in6_local.s6_addr32[3]);
|
&in6_local.s6_addr32[3]);
|
||||||
sscanf(rem_addr, "%08X%08X%08X%08X",
|
sscanf(rem_addr, "%08X%08X%08X%08X", &in6_remote.s6_addr32[0],
|
||||||
&in6_remote.s6_addr32[0], &in6_remote.s6_addr32[1],
|
&in6_remote.s6_addr32[1], &in6_remote.s6_addr32[2],
|
||||||
&in6_remote.s6_addr32[2], &in6_remote.s6_addr32[3]);
|
&in6_remote.s6_addr32[3]);
|
||||||
|
|
||||||
if ((in6_local.s6_addr32[0] == 0x0) && (in6_local.s6_addr32[1] == 0x0)
|
if ((in6_local.s6_addr32[0] == 0x0) && (in6_local.s6_addr32[1] == 0x0) &&
|
||||||
&& (in6_local.s6_addr32[2] == 0xFFFF0000))
|
(in6_local.s6_addr32[2] == 0xFFFF0000)) {
|
||||||
{
|
/* IPv4-compatible address */
|
||||||
/* IPv4-compatible address */
|
result_addr_local = *((struct in6_addr *)&(in6_local.s6_addr32[3]));
|
||||||
result_addr_local = *((struct in6_addr*) &(in6_local.s6_addr32[3]));
|
result_addr_remote = *((struct in6_addr *)&(in6_remote.s6_addr32[3]));
|
||||||
result_addr_remote = *((struct in6_addr*) &(in6_remote.s6_addr32[3]));
|
sa_family = AF_INET;
|
||||||
sa_family = AF_INET;
|
} else {
|
||||||
} else {
|
/* real IPv6 address */
|
||||||
/* real IPv6 address */
|
// inet_ntop(AF_INET6, &in6_local, addr6, sizeof(addr6));
|
||||||
//inet_ntop(AF_INET6, &in6_local, addr6, sizeof(addr6));
|
// INET6_getsock(addr6, (struct sockaddr *) &localaddr);
|
||||||
//INET6_getsock(addr6, (struct sockaddr *) &localaddr);
|
// inet_ntop(AF_INET6, &in6_remote, addr6, sizeof(addr6));
|
||||||
//inet_ntop(AF_INET6, &in6_remote, addr6, sizeof(addr6));
|
// INET6_getsock(addr6, (struct sockaddr *) &remaddr);
|
||||||
//INET6_getsock(addr6, (struct sockaddr *) &remaddr);
|
// localaddr.sin6_family = AF_INET6;
|
||||||
//localaddr.sin6_family = AF_INET6;
|
// remaddr.sin6_family = AF_INET6;
|
||||||
//remaddr.sin6_family = AF_INET6;
|
result_addr_local = in6_local;
|
||||||
result_addr_local = in6_local;
|
result_addr_remote = in6_remote;
|
||||||
result_addr_remote = in6_remote;
|
sa_family = AF_INET6;
|
||||||
sa_family = AF_INET6;
|
}
|
||||||
}
|
} else {
|
||||||
}
|
/* this is an IPv4-style row */
|
||||||
else
|
sscanf(local_addr, "%X", (unsigned int *)&result_addr_local);
|
||||||
{
|
sscanf(rem_addr, "%X", (unsigned int *)&result_addr_remote);
|
||||||
/* this is an IPv4-style row */
|
sa_family = AF_INET;
|
||||||
sscanf(local_addr, "%X", (unsigned int *) &result_addr_local);
|
}
|
||||||
sscanf(rem_addr, "%X", (unsigned int *) &result_addr_remote);
|
|
||||||
sa_family = AF_INET;
|
|
||||||
}
|
|
||||||
|
|
||||||
char * hashkey = (char *) malloc (HASHKEYSIZE * sizeof(char));
|
char *hashkey = (char *)malloc(HASHKEYSIZE * sizeof(char));
|
||||||
char * local_string = (char*) malloc (50);
|
char *local_string = (char *)malloc(50);
|
||||||
char * remote_string = (char*) malloc (50);
|
char *remote_string = (char *)malloc(50);
|
||||||
inet_ntop(sa_family, &result_addr_local, local_string, 49);
|
inet_ntop(sa_family, &result_addr_local, local_string, 49);
|
||||||
inet_ntop(sa_family, &result_addr_remote, remote_string, 49);
|
inet_ntop(sa_family, &result_addr_remote, remote_string, 49);
|
||||||
|
|
||||||
snprintf(hashkey, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d", local_string, local_port, remote_string, rem_port);
|
snprintf(hashkey, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d", local_string,
|
||||||
free (local_string);
|
local_port, remote_string, rem_port);
|
||||||
|
free(local_string);
|
||||||
|
|
||||||
//if (DEBUG)
|
// if (DEBUG)
|
||||||
// fprintf (stderr, "Hashkey: %s\n", hashkey);
|
// fprintf (stderr, "Hashkey: %s\n", hashkey);
|
||||||
|
|
||||||
//std::cout << "Adding to conninode\n" << std::endl;
|
// std::cout << "Adding to conninode\n" << std::endl;
|
||||||
|
|
||||||
conninode[hashkey] = inode;
|
conninode[hashkey] = inode;
|
||||||
|
|
||||||
/* workaround: sometimes, when a connection is actually from 172.16.3.1 to
|
/* workaround: sometimes, when a connection is actually from 172.16.3.1 to
|
||||||
* 172.16.3.3, packages arrive from 195.169.216.157 to 172.16.3.3, where
|
* 172.16.3.3, packages arrive from 195.169.216.157 to 172.16.3.3, where
|
||||||
* 172.16.3.1 and 195.169.216.157 are the local addresses of different
|
* 172.16.3.1 and 195.169.216.157 are the local addresses of different
|
||||||
* interfaces */
|
* interfaces */
|
||||||
for (class local_addr *current_local_addr = local_addrs;
|
for (class local_addr *current_local_addr = local_addrs;
|
||||||
current_local_addr != NULL;
|
current_local_addr != NULL;
|
||||||
current_local_addr = current_local_addr->next) {
|
current_local_addr = current_local_addr->next) {
|
||||||
/* TODO maybe only add the ones with the same sa_family */
|
/* TODO maybe only add the ones with the same sa_family */
|
||||||
snprintf(hashkey, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d", current_local_addr->string, local_port, remote_string, rem_port);
|
snprintf(hashkey, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d",
|
||||||
conninode[hashkey] = inode;
|
current_local_addr->string, local_port, remote_string, rem_port);
|
||||||
}
|
conninode[hashkey] = inode;
|
||||||
free (hashkey);
|
}
|
||||||
free (remote_string);
|
free(hashkey);
|
||||||
|
free(remote_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* opens /proc/net/tcp[6] and adds its contents line by line */
|
/* opens /proc/net/tcp[6] and adds its contents line by line */
|
||||||
int addprocinfo (const char * filename) {
|
int addprocinfo(const char *filename) {
|
||||||
FILE * procinfo = fopen (filename, "r");
|
FILE *procinfo = fopen(filename, "r");
|
||||||
|
|
||||||
char buffer[8192];
|
char buffer[8192];
|
||||||
|
|
||||||
if (procinfo == NULL)
|
if (procinfo == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fgets(buffer, sizeof(buffer), procinfo);
|
fgets(buffer, sizeof(buffer), procinfo);
|
||||||
|
|
||||||
do
|
do {
|
||||||
{
|
if (fgets(buffer, sizeof(buffer), procinfo))
|
||||||
if (fgets(buffer, sizeof(buffer), procinfo))
|
addtoconninode(buffer);
|
||||||
addtoconninode(buffer);
|
} while (!feof(procinfo));
|
||||||
} while (!feof(procinfo));
|
|
||||||
|
|
||||||
fclose(procinfo);
|
fclose(procinfo);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void refreshconninode() {
|
||||||
|
/* we don't forget old mappings, just overwrite */
|
||||||
|
// delete conninode;
|
||||||
|
// conninode = new HashTable (256);
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
addprocinfo("net.inet.tcp.pcblist");
|
||||||
|
#else
|
||||||
|
if (!addprocinfo("/proc/net/tcp")) {
|
||||||
|
std::cout << "Error: couldn't open /proc/net/tcp\n";
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
addprocinfo("/proc/net/tcp6");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// if (DEBUG)
|
||||||
void refreshconninode ()
|
// reviewUnknown();
|
||||||
{
|
|
||||||
/* we don't forget old mappings, just overwrite */
|
|
||||||
//delete conninode;
|
|
||||||
//conninode = new HashTable (256);
|
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
addprocinfo("net.inet.tcp.pcblist");
|
|
||||||
#else
|
|
||||||
if (! addprocinfo ("/proc/net/tcp"))
|
|
||||||
{
|
|
||||||
std::cout << "Error: couldn't open /proc/net/tcp\n";
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
addprocinfo ("/proc/net/tcp6");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//if (DEBUG)
|
|
||||||
// reviewUnknown();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,9 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
// handling the connection->inode mapping
|
// handling the connection->inode mapping
|
||||||
void refreshconninode ();
|
void refreshconninode();
|
||||||
|
|||||||
654
cui.cpp
654
cui.cpp
@@ -1,4 +1,4 @@
|
|||||||
/*
|
/*
|
||||||
* cui.cpp
|
* cui.cpp
|
||||||
*
|
*
|
||||||
* Copyright (c) 2004-2006,2008,2010,2011 Arnout Engelen
|
* Copyright (c) 2004-2006,2008,2010,2011 Arnout Engelen
|
||||||
@@ -15,11 +15,11 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* NetHogs console UI */
|
/* NetHogs console UI */
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
@@ -33,14 +33,14 @@
|
|||||||
#include "nethogs.h"
|
#include "nethogs.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
|
|
||||||
std::string * caption;
|
std::string *caption;
|
||||||
extern const char version[];
|
extern const char version[];
|
||||||
extern ProcList * processes;
|
extern ProcList *processes;
|
||||||
extern timeval curtime;
|
extern timeval curtime;
|
||||||
|
|
||||||
extern Process * unknowntcp;
|
extern Process *unknowntcp;
|
||||||
extern Process * unknownudp;
|
extern Process *unknownudp;
|
||||||
extern Process * unknownip;
|
extern Process *unknownip;
|
||||||
|
|
||||||
extern bool sortRecv;
|
extern bool sortRecv;
|
||||||
|
|
||||||
@@ -51,414 +51,392 @@ extern unsigned refreshcount;
|
|||||||
|
|
||||||
#define PID_MAX 4194303
|
#define PID_MAX 4194303
|
||||||
|
|
||||||
const int COLUMN_WIDTH_PID = 7;
|
const int COLUMN_WIDTH_PID = 7;
|
||||||
const int COLUMN_WIDTH_USER = 8;
|
const int COLUMN_WIDTH_USER = 8;
|
||||||
const int COLUMN_WIDTH_DEV = 5;
|
const int COLUMN_WIDTH_DEV = 5;
|
||||||
const int COLUMN_WIDTH_SENT = 11;
|
const int COLUMN_WIDTH_SENT = 11;
|
||||||
const int COLUMN_WIDTH_RECEIVED = 11;
|
const int COLUMN_WIDTH_RECEIVED = 11;
|
||||||
const int COLUMN_WIDTH_UNIT = 6;
|
const int COLUMN_WIDTH_UNIT = 6;
|
||||||
|
|
||||||
const char * COLUMN_FORMAT_PID = "%7d";
|
const char *COLUMN_FORMAT_PID = "%7d";
|
||||||
const char * COLUMN_FORMAT_SENT = "%11.3f";
|
const char *COLUMN_FORMAT_SENT = "%11.3f";
|
||||||
const char * COLUMN_FORMAT_RECEIVED = "%11.3f";
|
const char *COLUMN_FORMAT_RECEIVED = "%11.3f";
|
||||||
|
|
||||||
class Line
|
class Line {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
Line (const char * name, double n_recv_value, double n_sent_value, pid_t pid, uid_t uid, const char * n_devicename)
|
Line(const char *name, double n_recv_value, double n_sent_value, pid_t pid,
|
||||||
{
|
uid_t uid, const char *n_devicename) {
|
||||||
assert (pid >= 0);
|
assert(pid >= 0);
|
||||||
assert (pid <= PID_MAX);
|
assert(pid <= PID_MAX);
|
||||||
m_name = name;
|
m_name = name;
|
||||||
sent_value = n_sent_value;
|
sent_value = n_sent_value;
|
||||||
recv_value = n_recv_value;
|
recv_value = n_recv_value;
|
||||||
devicename = n_devicename;
|
devicename = n_devicename;
|
||||||
m_pid = pid;
|
m_pid = pid;
|
||||||
m_uid = uid;
|
m_uid = uid;
|
||||||
assert (m_pid >= 0);
|
assert(m_pid >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void show (int row, unsigned int proglen);
|
void show(int row, unsigned int proglen);
|
||||||
void log ();
|
void log();
|
||||||
|
|
||||||
|
double sent_value;
|
||||||
|
double recv_value;
|
||||||
|
|
||||||
double sent_value;
|
|
||||||
double recv_value;
|
|
||||||
private:
|
private:
|
||||||
const char * m_name;
|
const char *m_name;
|
||||||
const char * devicename;
|
const char *devicename;
|
||||||
pid_t m_pid;
|
pid_t m_pid;
|
||||||
uid_t m_uid;
|
uid_t m_uid;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
std::string itoa(int i)
|
std::string itoa(int i) {
|
||||||
{
|
std::stringstream out;
|
||||||
std::stringstream out;
|
out << i;
|
||||||
out << i;
|
return out.str();
|
||||||
return out.str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns the username that corresponds to this uid
|
* @returns the username that corresponds to this uid
|
||||||
*/
|
*/
|
||||||
std::string uid2username (uid_t uid)
|
std::string uid2username(uid_t uid) {
|
||||||
{
|
struct passwd *pwd = NULL;
|
||||||
struct passwd * pwd = NULL;
|
errno = 0;
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
/* points to a static memory area, should not be freed */
|
/* points to a static memory area, should not be freed */
|
||||||
pwd = getpwuid(uid);
|
pwd = getpwuid(uid);
|
||||||
|
|
||||||
if (pwd == NULL)
|
if (pwd == NULL)
|
||||||
if (errno == 0)
|
if (errno == 0)
|
||||||
return itoa(uid);
|
return itoa(uid);
|
||||||
else
|
else
|
||||||
forceExit(false, "Error calling getpwuid(3) for uid %d: %d %s", uid, errno, strerror(errno));
|
forceExit(false, "Error calling getpwuid(3) for uid %d: %d %s", uid,
|
||||||
else
|
errno, strerror(errno));
|
||||||
return std::string(pwd->pw_name);
|
else
|
||||||
|
return std::string(pwd->pw_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the provided text at the specified location, truncating if the length of the text exceeds a maximum. If the
|
* Render the provided text at the specified location, truncating if the length
|
||||||
* text must be truncated, the string ".." will be rendered, followed by max_len - 2 characters of the provided text.
|
* of the text exceeds a maximum. If the
|
||||||
|
* text must be truncated, the string ".." will be rendered, followed by max_len
|
||||||
|
* - 2 characters of the provided text.
|
||||||
*/
|
*/
|
||||||
static void mvaddstr_truncate_leading(int row, int col, const char* str, std::size_t str_len, std::size_t max_len)
|
static void mvaddstr_truncate_leading(int row, int col, const char *str,
|
||||||
{
|
std::size_t str_len,
|
||||||
if (str_len < max_len) {
|
std::size_t max_len) {
|
||||||
mvaddstr(row, col, str);
|
if (str_len < max_len) {
|
||||||
} else {
|
mvaddstr(row, col, str);
|
||||||
mvaddstr(row, col, "..");
|
} else {
|
||||||
addnstr(str + 2, max_len - 2);
|
mvaddstr(row, col, "..");
|
||||||
}
|
addnstr(str + 2, max_len - 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the provided text at the specified location, truncating if the length of the text exceeds a maximum. If the
|
* Render the provided text at the specified location, truncating if the length
|
||||||
* text must be truncated, the text will be rendered up to max_len - 2 characters and then ".." will be rendered.
|
* of the text exceeds a maximum. If the
|
||||||
|
* text must be truncated, the text will be rendered up to max_len - 2
|
||||||
|
* characters and then ".." will be rendered.
|
||||||
*/
|
*/
|
||||||
static void mvaddstr_truncate_trailing(int row, int col, const char* str, std::size_t str_len, std::size_t max_len)
|
static void mvaddstr_truncate_trailing(int row, int col, const char *str,
|
||||||
{
|
std::size_t str_len,
|
||||||
if (str_len < max_len) {
|
std::size_t max_len) {
|
||||||
mvaddstr(row, col, str);
|
if (str_len < max_len) {
|
||||||
} else {
|
mvaddstr(row, col, str);
|
||||||
mvaddnstr(row, col, str, max_len - 2);
|
} else {
|
||||||
addstr("..");
|
mvaddnstr(row, col, str, max_len - 2);
|
||||||
}
|
addstr("..");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Line::show (int row, unsigned int proglen)
|
void Line::show(int row, unsigned int proglen) {
|
||||||
{
|
assert(m_pid >= 0);
|
||||||
assert (m_pid >= 0);
|
assert(m_pid <= PID_MAX);
|
||||||
assert (m_pid <= PID_MAX);
|
|
||||||
|
|
||||||
const int column_offset_pid = 0;
|
const int column_offset_pid = 0;
|
||||||
const int column_offset_user = column_offset_pid + COLUMN_WIDTH_PID + 1;
|
const int column_offset_user = column_offset_pid + COLUMN_WIDTH_PID + 1;
|
||||||
const int column_offset_program = column_offset_user + COLUMN_WIDTH_USER + 1;
|
const int column_offset_program = column_offset_user + COLUMN_WIDTH_USER + 1;
|
||||||
const int column_offset_dev = column_offset_program + proglen + 2;
|
const int column_offset_dev = column_offset_program + proglen + 2;
|
||||||
const int column_offset_sent = column_offset_dev + COLUMN_WIDTH_DEV + 1;
|
const int column_offset_sent = column_offset_dev + COLUMN_WIDTH_DEV + 1;
|
||||||
const int column_offset_received = column_offset_sent + COLUMN_WIDTH_SENT + 1;
|
const int column_offset_received = column_offset_sent + COLUMN_WIDTH_SENT + 1;
|
||||||
const int column_offset_unit = column_offset_received + COLUMN_WIDTH_RECEIVED + 1;
|
const int column_offset_unit =
|
||||||
|
column_offset_received + COLUMN_WIDTH_RECEIVED + 1;
|
||||||
|
|
||||||
// PID column
|
// PID column
|
||||||
if (m_pid == 0)
|
if (m_pid == 0)
|
||||||
mvaddch (row, column_offset_pid + COLUMN_WIDTH_PID - 1, '?');
|
mvaddch(row, column_offset_pid + COLUMN_WIDTH_PID - 1, '?');
|
||||||
else
|
else
|
||||||
mvprintw (row, column_offset_pid, COLUMN_FORMAT_PID, m_pid);
|
mvprintw(row, column_offset_pid, COLUMN_FORMAT_PID, m_pid);
|
||||||
|
|
||||||
std::string username = uid2username(m_uid);
|
std::string username = uid2username(m_uid);
|
||||||
mvaddstr_truncate_trailing (row, column_offset_user, username.c_str(), username.size(), COLUMN_WIDTH_USER);
|
mvaddstr_truncate_trailing(row, column_offset_user, username.c_str(),
|
||||||
|
username.size(), COLUMN_WIDTH_USER);
|
||||||
|
|
||||||
mvaddstr_truncate_leading (row, column_offset_program, m_name, strlen (m_name), proglen);
|
mvaddstr_truncate_leading(row, column_offset_program, m_name, strlen(m_name),
|
||||||
|
proglen);
|
||||||
|
|
||||||
mvaddstr (row, column_offset_dev, devicename);
|
mvaddstr(row, column_offset_dev, devicename);
|
||||||
|
|
||||||
mvprintw (row, column_offset_sent, COLUMN_FORMAT_SENT, sent_value);
|
mvprintw(row, column_offset_sent, COLUMN_FORMAT_SENT, sent_value);
|
||||||
|
|
||||||
mvprintw (row, column_offset_received, COLUMN_FORMAT_RECEIVED, recv_value);
|
mvprintw(row, column_offset_received, COLUMN_FORMAT_RECEIVED, recv_value);
|
||||||
if (viewMode == VIEWMODE_KBPS)
|
if (viewMode == VIEWMODE_KBPS) {
|
||||||
{
|
mvaddstr(row, column_offset_unit, "KB/sec");
|
||||||
mvaddstr (row, column_offset_unit, "KB/sec");
|
} else if (viewMode == VIEWMODE_TOTAL_MB) {
|
||||||
}
|
mvaddstr(row, column_offset_unit, "MB ");
|
||||||
else if (viewMode == VIEWMODE_TOTAL_MB)
|
} else if (viewMode == VIEWMODE_TOTAL_KB) {
|
||||||
{
|
mvaddstr(row, column_offset_unit, "KB ");
|
||||||
mvaddstr (row, column_offset_unit, "MB ");
|
} else if (viewMode == VIEWMODE_TOTAL_B) {
|
||||||
}
|
mvaddstr(row, column_offset_unit, "B ");
|
||||||
else if (viewMode == VIEWMODE_TOTAL_KB)
|
}
|
||||||
{
|
|
||||||
mvaddstr (row, column_offset_unit, "KB ");
|
|
||||||
}
|
|
||||||
else if (viewMode == VIEWMODE_TOTAL_B)
|
|
||||||
{
|
|
||||||
mvaddstr (row, column_offset_unit, "B ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Line::log() {
|
void Line::log() {
|
||||||
std::cout << m_name << '/' << m_pid << '/' << m_uid << "\t" << sent_value << "\t" << recv_value << std::endl;
|
std::cout << m_name << '/' << m_pid << '/' << m_uid << "\t" << sent_value
|
||||||
|
<< "\t" << recv_value << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GreatestFirst (const void * ma, const void * mb)
|
int GreatestFirst(const void *ma, const void *mb) {
|
||||||
{
|
Line **pa = (Line **)ma;
|
||||||
Line ** pa = (Line **)ma;
|
Line **pb = (Line **)mb;
|
||||||
Line ** pb = (Line **)mb;
|
Line *a = *pa;
|
||||||
Line * a = *pa;
|
Line *b = *pb;
|
||||||
Line * b = *pb;
|
double aValue;
|
||||||
double aValue;
|
if (sortRecv) {
|
||||||
if (sortRecv)
|
aValue = a->recv_value;
|
||||||
{
|
} else {
|
||||||
aValue = a->recv_value;
|
aValue = a->sent_value;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
aValue = a->sent_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
double bValue;
|
double bValue;
|
||||||
if (sortRecv)
|
if (sortRecv) {
|
||||||
{
|
bValue = b->recv_value;
|
||||||
bValue = b->recv_value;
|
} else {
|
||||||
}
|
bValue = b->sent_value;
|
||||||
else
|
}
|
||||||
{
|
|
||||||
bValue = b->sent_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aValue > bValue)
|
if (aValue > bValue) {
|
||||||
{
|
return -1;
|
||||||
return -1;
|
}
|
||||||
}
|
if (aValue == bValue) {
|
||||||
if (aValue == bValue)
|
return 0;
|
||||||
{
|
}
|
||||||
return 0;
|
return 1;
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_ui ()
|
void init_ui() {
|
||||||
{
|
WINDOW *screen = initscr();
|
||||||
WINDOW * screen = initscr();
|
raw();
|
||||||
raw();
|
noecho();
|
||||||
noecho();
|
cbreak();
|
||||||
cbreak();
|
nodelay(screen, TRUE);
|
||||||
nodelay(screen, TRUE);
|
caption = new std::string("NetHogs");
|
||||||
caption = new std::string ("NetHogs");
|
caption->append(getVersion());
|
||||||
caption->append(getVersion());
|
// caption->append(", running at ");
|
||||||
//caption->append(", running at ");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void exit_ui ()
|
void exit_ui() {
|
||||||
{
|
clear();
|
||||||
clear();
|
endwin();
|
||||||
endwin();
|
delete caption;
|
||||||
delete caption;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ui_tick ()
|
void ui_tick() {
|
||||||
{
|
switch (getch()) {
|
||||||
switch (getch()) {
|
case 'q':
|
||||||
case 'q':
|
/* quit */
|
||||||
/* quit */
|
quit_cb(0);
|
||||||
quit_cb(0);
|
break;
|
||||||
break;
|
case 's':
|
||||||
case 's':
|
/* sort on 'sent' */
|
||||||
/* sort on 'sent' */
|
sortRecv = false;
|
||||||
sortRecv = false;
|
break;
|
||||||
break;
|
case 'r':
|
||||||
case 'r':
|
/* sort on 'received' */
|
||||||
/* sort on 'received' */
|
sortRecv = true;
|
||||||
sortRecv = true;
|
break;
|
||||||
break;
|
case 'm':
|
||||||
case 'm':
|
/* switch mode: total vs kb/s */
|
||||||
/* switch mode: total vs kb/s */
|
viewMode = (viewMode + 1) % VIEWMODE_COUNT;
|
||||||
viewMode = (viewMode + 1) % VIEWMODE_COUNT;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void show_trace(Line * lines[], int nproc) {
|
void show_trace(Line *lines[], int nproc) {
|
||||||
std::cout << "\nRefreshing:\n";
|
std::cout << "\nRefreshing:\n";
|
||||||
|
|
||||||
/* print them */
|
/* print them */
|
||||||
for (int i=0; i<nproc; i++)
|
for (int i = 0; i < nproc; i++) {
|
||||||
{
|
lines[i]->log();
|
||||||
lines[i]->log();
|
delete lines[i];
|
||||||
delete lines[i];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* print the 'unknown' connections, for debugging */
|
/* print the 'unknown' connections, for debugging */
|
||||||
ConnList * curr_unknownconn = unknowntcp->connections;
|
ConnList *curr_unknownconn = unknowntcp->connections;
|
||||||
while (curr_unknownconn != NULL) {
|
while (curr_unknownconn != NULL) {
|
||||||
std::cout << "Unknown connection: " <<
|
std::cout << "Unknown connection: "
|
||||||
curr_unknownconn->getVal()->refpacket->gethashstring() << std::endl;
|
<< curr_unknownconn->getVal()->refpacket->gethashstring()
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
curr_unknownconn = curr_unknownconn->getNext();
|
curr_unknownconn = curr_unknownconn->getNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void show_ncurses(Line * lines[], int nproc) {
|
void show_ncurses(Line *lines[], int nproc) {
|
||||||
int rows; // number of terminal rows
|
int rows; // number of terminal rows
|
||||||
int cols; // number of terminal columns
|
int cols; // number of terminal columns
|
||||||
unsigned int proglen; // max length of the "PROGRAM" column
|
unsigned int proglen; // max length of the "PROGRAM" column
|
||||||
|
|
||||||
double sent_global = 0;
|
double sent_global = 0;
|
||||||
double recv_global = 0;
|
double recv_global = 0;
|
||||||
|
|
||||||
getmaxyx(stdscr, rows, cols); /* find the boundaries of the screeen */
|
getmaxyx(stdscr, rows, cols); /* find the boundaries of the screeen */
|
||||||
|
|
||||||
if (cols < 62) {
|
if (cols < 62) {
|
||||||
clear();
|
clear();
|
||||||
mvprintw(0,0, "The terminal is too narrow! Please make it wider.\nI'll wait...");
|
mvprintw(0, 0,
|
||||||
return;
|
"The terminal is too narrow! Please make it wider.\nI'll wait...");
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (cols > PROGNAME_WIDTH) cols = PROGNAME_WIDTH;
|
if (cols > PROGNAME_WIDTH)
|
||||||
|
cols = PROGNAME_WIDTH;
|
||||||
|
|
||||||
proglen = cols - 55;
|
proglen = cols - 55;
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
mvprintw (0, 0, "%s", caption->c_str());
|
mvprintw(0, 0, "%s", caption->c_str());
|
||||||
attron(A_REVERSE);
|
attron(A_REVERSE);
|
||||||
mvprintw (2, 0, " PID USER %-*.*s DEV SENT RECEIVED ", proglen, proglen, "PROGRAM");
|
mvprintw(2, 0,
|
||||||
attroff(A_REVERSE);
|
" PID USER %-*.*s DEV SENT RECEIVED ",
|
||||||
|
proglen, proglen, "PROGRAM");
|
||||||
|
attroff(A_REVERSE);
|
||||||
|
|
||||||
/* print them */
|
/* print them */
|
||||||
int i;
|
int i;
|
||||||
for (i=0; i<nproc; i++)
|
for (i = 0; i < nproc; i++) {
|
||||||
{
|
if (i + 3 < rows)
|
||||||
if (i+3 < rows)
|
lines[i]->show(i + 3, proglen);
|
||||||
lines[i]->show(i+3, proglen);
|
recv_global += lines[i]->recv_value;
|
||||||
recv_global += lines[i]->recv_value;
|
sent_global += lines[i]->sent_value;
|
||||||
sent_global += lines[i]->sent_value;
|
delete lines[i];
|
||||||
delete lines[i];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
attron(A_REVERSE);
|
attron(A_REVERSE);
|
||||||
int totalrow = std::min(rows-1, 3+1+i);
|
int totalrow = std::min(rows - 1, 3 + 1 + i);
|
||||||
mvprintw (totalrow, 0, " TOTAL %-*.*s %11.3f %11.3f ", proglen, proglen, " ", sent_global, recv_global);
|
mvprintw(totalrow, 0, " TOTAL %-*.*s %11.3f %11.3f ",
|
||||||
if (viewMode == VIEWMODE_KBPS)
|
proglen, proglen, " ", sent_global, recv_global);
|
||||||
{
|
if (viewMode == VIEWMODE_KBPS) {
|
||||||
mvprintw (3+1+i, cols - COLUMN_WIDTH_UNIT, "KB/sec ");
|
mvprintw(3 + 1 + i, cols - COLUMN_WIDTH_UNIT, "KB/sec ");
|
||||||
} else if (viewMode == VIEWMODE_TOTAL_B) {
|
} else if (viewMode == VIEWMODE_TOTAL_B) {
|
||||||
mvprintw (3+1+i, cols - COLUMN_WIDTH_UNIT, "B ");
|
mvprintw(3 + 1 + i, cols - COLUMN_WIDTH_UNIT, "B ");
|
||||||
} else if (viewMode == VIEWMODE_TOTAL_KB) {
|
} else if (viewMode == VIEWMODE_TOTAL_KB) {
|
||||||
mvprintw (3+1+i, cols - COLUMN_WIDTH_UNIT, "KB ");
|
mvprintw(3 + 1 + i, cols - COLUMN_WIDTH_UNIT, "KB ");
|
||||||
} else if (viewMode == VIEWMODE_TOTAL_MB) {
|
} else if (viewMode == VIEWMODE_TOTAL_MB) {
|
||||||
mvprintw (3+1+i, cols - COLUMN_WIDTH_UNIT, "MB ");
|
mvprintw(3 + 1 + i, cols - COLUMN_WIDTH_UNIT, "MB ");
|
||||||
}
|
}
|
||||||
attroff(A_REVERSE);
|
attroff(A_REVERSE);
|
||||||
mvprintw (totalrow+1, 0, "");
|
mvprintw(totalrow + 1, 0, "");
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display all processes and relevant network traffic using show function
|
// Display all processes and relevant network traffic using show function
|
||||||
void do_refresh()
|
void do_refresh() {
|
||||||
{
|
refreshconninode();
|
||||||
refreshconninode();
|
refreshcount++;
|
||||||
refreshcount++;
|
|
||||||
|
|
||||||
ProcList * curproc = processes;
|
ProcList *curproc = processes;
|
||||||
ProcList * previousproc = NULL;
|
ProcList *previousproc = NULL;
|
||||||
int nproc = processes->size();
|
int nproc = processes->size();
|
||||||
/* initialise to null pointers */
|
/* initialise to null pointers */
|
||||||
Line * lines [nproc];
|
Line *lines[nproc];
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// initialise to null pointers
|
// initialise to null pointers
|
||||||
for (int i = 0; i < nproc; i++)
|
for (int i = 0; i < nproc; i++)
|
||||||
lines[i] = NULL;
|
lines[i] = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (curproc != NULL)
|
while (curproc != NULL) {
|
||||||
{
|
// walk though its connections, summing up their data, and
|
||||||
// walk though its connections, summing up their data, and
|
// throwing away connections that haven't received a package
|
||||||
// throwing away connections that haven't received a package
|
// in the last PROCESSTIMEOUT seconds.
|
||||||
// in the last PROCESSTIMEOUT seconds.
|
assert(curproc != NULL);
|
||||||
assert (curproc != NULL);
|
assert(curproc->getVal() != NULL);
|
||||||
assert (curproc->getVal() != NULL);
|
assert(nproc == processes->size());
|
||||||
assert (nproc == processes->size());
|
|
||||||
|
|
||||||
/* remove timed-out processes (unless it's one of the the unknown process) */
|
/* remove timed-out processes (unless it's one of the the unknown process)
|
||||||
if ((curproc->getVal()->getLastPacket() + PROCESSTIMEOUT <= curtime.tv_sec)
|
*/
|
||||||
&& (curproc->getVal() != unknowntcp)
|
if ((curproc->getVal()->getLastPacket() + PROCESSTIMEOUT <=
|
||||||
&& (curproc->getVal() != unknownudp)
|
curtime.tv_sec) &&
|
||||||
&& (curproc->getVal() != unknownip))
|
(curproc->getVal() != unknowntcp) &&
|
||||||
{
|
(curproc->getVal() != unknownudp) && (curproc->getVal() != unknownip)) {
|
||||||
if (DEBUG)
|
if (DEBUG)
|
||||||
std::cout << "PROC: Deleting process\n";
|
std::cout << "PROC: Deleting process\n";
|
||||||
ProcList * todelete = curproc;
|
ProcList *todelete = curproc;
|
||||||
Process * p_todelete = curproc->getVal();
|
Process *p_todelete = curproc->getVal();
|
||||||
if (previousproc)
|
if (previousproc) {
|
||||||
{
|
previousproc->next = curproc->next;
|
||||||
previousproc->next = curproc->next;
|
curproc = curproc->next;
|
||||||
curproc = curproc->next;
|
} else {
|
||||||
} else {
|
processes = curproc->getNext();
|
||||||
processes = curproc->getNext();
|
curproc = processes;
|
||||||
curproc = processes;
|
}
|
||||||
}
|
delete todelete;
|
||||||
delete todelete;
|
delete p_todelete;
|
||||||
delete p_todelete;
|
nproc--;
|
||||||
nproc--;
|
// continue;
|
||||||
//continue;
|
} else {
|
||||||
}
|
// add a non-timed-out process to the list of stuff to show
|
||||||
else
|
float value_sent = 0, value_recv = 0;
|
||||||
{
|
|
||||||
// add a non-timed-out process to the list of stuff to show
|
|
||||||
float value_sent = 0,
|
|
||||||
value_recv = 0;
|
|
||||||
|
|
||||||
if (viewMode == VIEWMODE_KBPS)
|
if (viewMode == VIEWMODE_KBPS) {
|
||||||
{
|
// std::cout << "kbps viemode" << std::endl;
|
||||||
//std::cout << "kbps viemode" << std::endl;
|
curproc->getVal()->getkbps(&value_recv, &value_sent);
|
||||||
curproc->getVal()->getkbps (&value_recv, &value_sent);
|
} else if (viewMode == VIEWMODE_TOTAL_KB) {
|
||||||
}
|
// std::cout << "total viemode" << std::endl;
|
||||||
else if (viewMode == VIEWMODE_TOTAL_KB)
|
curproc->getVal()->gettotalkb(&value_recv, &value_sent);
|
||||||
{
|
} else if (viewMode == VIEWMODE_TOTAL_MB) {
|
||||||
//std::cout << "total viemode" << std::endl;
|
// std::cout << "total viemode" << std::endl;
|
||||||
curproc->getVal()->gettotalkb(&value_recv, &value_sent);
|
curproc->getVal()->gettotalmb(&value_recv, &value_sent);
|
||||||
}
|
} else if (viewMode == VIEWMODE_TOTAL_B) {
|
||||||
else if (viewMode == VIEWMODE_TOTAL_MB)
|
// std::cout << "total viemode" << std::endl;
|
||||||
{
|
curproc->getVal()->gettotalb(&value_recv, &value_sent);
|
||||||
//std::cout << "total viemode" << std::endl;
|
} else {
|
||||||
curproc->getVal()->gettotalmb(&value_recv, &value_sent);
|
forceExit(false, "Invalid viewMode: %d", viewMode);
|
||||||
}
|
}
|
||||||
else if (viewMode == VIEWMODE_TOTAL_B)
|
uid_t uid = curproc->getVal()->getUid();
|
||||||
{
|
assert(curproc->getVal()->pid >= 0);
|
||||||
//std::cout << "total viemode" << std::endl;
|
assert(n < nproc);
|
||||||
curproc->getVal()->gettotalb(&value_recv, &value_sent);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
forceExit(false, "Invalid viewMode: %d", viewMode);
|
|
||||||
}
|
|
||||||
uid_t uid = curproc->getVal()->getUid();
|
|
||||||
assert (curproc->getVal()->pid >= 0);
|
|
||||||
assert (n < nproc);
|
|
||||||
|
|
||||||
lines[n] = new Line (curproc->getVal()->name, value_recv, value_sent,
|
lines[n] =
|
||||||
curproc->getVal()->pid, uid, curproc->getVal()->devicename);
|
new Line(curproc->getVal()->name, value_recv, value_sent,
|
||||||
previousproc = curproc;
|
curproc->getVal()->pid, uid, curproc->getVal()->devicename);
|
||||||
curproc = curproc->next;
|
previousproc = curproc;
|
||||||
n++;
|
curproc = curproc->next;
|
||||||
|
n++;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
assert (nproc == processes->size());
|
assert(nproc == processes->size());
|
||||||
if (curproc == NULL)
|
if (curproc == NULL)
|
||||||
assert (n-1 < nproc);
|
assert(n - 1 < nproc);
|
||||||
else
|
else
|
||||||
assert (n < nproc);
|
assert(n < nproc);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sort the accumulated lines */
|
/* sort the accumulated lines */
|
||||||
qsort (lines, nproc, sizeof(Line *), GreatestFirst);
|
qsort(lines, nproc, sizeof(Line *), GreatestFirst);
|
||||||
|
|
||||||
if (tracemode || DEBUG)
|
if (tracemode || DEBUG)
|
||||||
show_trace(lines, nproc);
|
show_trace(lines, nproc);
|
||||||
else
|
else
|
||||||
show_ncurses(lines, nproc);
|
show_ncurses(lines, nproc);
|
||||||
|
|
||||||
if (refreshlimit != 0 && refreshcount >= refreshlimit)
|
if (refreshlimit != 0 && refreshcount >= refreshlimit)
|
||||||
quit_cb(0);
|
quit_cb(0);
|
||||||
}
|
}
|
||||||
|
|||||||
11
cui.h
11
cui.h
@@ -15,15 +15,16 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* NetHogs console UI */
|
/* NetHogs console UI */
|
||||||
|
|
||||||
void do_refresh ();
|
void do_refresh();
|
||||||
void init_ui ();
|
void init_ui();
|
||||||
void exit_ui ();
|
void exit_ui();
|
||||||
|
|
||||||
/* periodically gives some CPU-time to the UI */
|
/* periodically gives some CPU-time to the UI */
|
||||||
void ui_tick ();
|
void ui_tick();
|
||||||
|
|||||||
460
decpcap.c
460
decpcap.c
@@ -1,4 +1,4 @@
|
|||||||
/*
|
/*
|
||||||
* decpcap.c
|
* decpcap.c
|
||||||
*
|
*
|
||||||
* Copyright (c) 2004-2006,2011 Arnout Engelen
|
* Copyright (c) 2004-2006,2011 Arnout Engelen
|
||||||
@@ -15,11 +15,11 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <net/ethernet.h>
|
#include <net/ethernet.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
@@ -34,304 +34,288 @@
|
|||||||
|
|
||||||
/* functions to set up a handle (which is basically just a pcap handle) */
|
/* functions to set up a handle (which is basically just a pcap handle) */
|
||||||
|
|
||||||
struct dp_handle * dp_fillhandle(pcap_t * phandle)
|
struct dp_handle *dp_fillhandle(pcap_t *phandle) {
|
||||||
{
|
struct dp_handle *retval =
|
||||||
struct dp_handle * retval = (struct dp_handle *) malloc (sizeof (struct dp_handle));
|
(struct dp_handle *)malloc(sizeof(struct dp_handle));
|
||||||
int i;
|
int i;
|
||||||
retval->pcap_handle = phandle;
|
retval->pcap_handle = phandle;
|
||||||
|
|
||||||
for (i = 0; i < dp_n_packet_types; i++)
|
for (i = 0; i < dp_n_packet_types; i++) {
|
||||||
{
|
retval->callback[i] = NULL;
|
||||||
retval->callback[i] = NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
retval->linktype = pcap_datalink(retval->pcap_handle);
|
retval->linktype = pcap_datalink(retval->pcap_handle);
|
||||||
|
|
||||||
switch (retval->linktype) {
|
switch (retval->linktype) {
|
||||||
case (DLT_EN10MB):
|
case (DLT_EN10MB):
|
||||||
fprintf(stdout, "Ethernet link detected\n");
|
fprintf(stdout, "Ethernet link detected\n");
|
||||||
break;
|
break;
|
||||||
case (DLT_PPP):
|
case (DLT_PPP):
|
||||||
fprintf(stdout, "PPP link detected\n");
|
fprintf(stdout, "PPP link detected\n");
|
||||||
break;
|
break;
|
||||||
case (DLT_LINUX_SLL):
|
case (DLT_LINUX_SLL):
|
||||||
fprintf(stdout, "Linux Cooked Socket link detected\n");
|
fprintf(stdout, "Linux Cooked Socket link detected\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stdout, "No PPP or Ethernet link: %d\n", retval->linktype);
|
fprintf(stdout, "No PPP or Ethernet link: %d\n", retval->linktype);
|
||||||
// TODO maybe error? or 'other' callback?
|
// TODO maybe error? or 'other' callback?
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dp_handle * dp_open_offline(char * fname, char * ebuf)
|
struct dp_handle *dp_open_offline(char *fname, char *ebuf) {
|
||||||
{
|
pcap_t *temp = pcap_open_offline(fname, ebuf);
|
||||||
pcap_t * temp = pcap_open_offline(fname, ebuf);
|
|
||||||
|
|
||||||
if (temp == NULL)
|
if (temp == NULL) {
|
||||||
{
|
return NULL;
|
||||||
return NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return dp_fillhandle(temp);
|
return dp_fillhandle(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dp_handle * dp_open_live(const char * device, int snaplen, int promisc, int to_ms, char * errbuf)
|
struct dp_handle *dp_open_live(const char *device, int snaplen, int promisc,
|
||||||
{
|
int to_ms, char *errbuf) {
|
||||||
pcap_t * temp = pcap_open_live(device, snaplen, promisc, to_ms, errbuf);
|
pcap_t *temp = pcap_open_live(device, snaplen, promisc, to_ms, errbuf);
|
||||||
|
|
||||||
if (temp == NULL)
|
if (temp == NULL) {
|
||||||
{
|
return NULL;
|
||||||
return NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return dp_fillhandle(temp);
|
return dp_fillhandle(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* functions to add callbacks */
|
/* functions to add callbacks */
|
||||||
|
|
||||||
void dp_addcb (struct dp_handle * handle, enum dp_packet_type type, dp_callback callback)
|
void dp_addcb(struct dp_handle *handle, enum dp_packet_type type,
|
||||||
{
|
dp_callback callback) {
|
||||||
handle->callback[type] = callback;
|
handle->callback[type] = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* functions for parsing the payloads */
|
/* functions for parsing the payloads */
|
||||||
|
|
||||||
void dp_parse_tcp (struct dp_handle * handle, const dp_header * header, const u_char * packet)
|
void dp_parse_tcp(struct dp_handle *handle, const dp_header *header,
|
||||||
{
|
const u_char *packet) {
|
||||||
//const struct tcphdr * tcp = (struct tcphdr *) packet;
|
// const struct tcphdr * tcp = (struct tcphdr *) packet;
|
||||||
//u_char * payload = (u_char *) packet + sizeof (struct tcphdr);
|
// u_char * payload = (u_char *) packet + sizeof (struct tcphdr);
|
||||||
|
|
||||||
if (handle->callback[dp_packet_tcp] != NULL)
|
if (handle->callback[dp_packet_tcp] != NULL) {
|
||||||
{
|
int done =
|
||||||
int done = (handle->callback[dp_packet_tcp])
|
(handle->callback[dp_packet_tcp])(handle->userdata, header, packet);
|
||||||
(handle->userdata, header, packet);
|
if (done)
|
||||||
if (done)
|
return;
|
||||||
return;
|
}
|
||||||
}
|
// TODO: maybe `pass on' payload to lower-level protocol parsing
|
||||||
// TODO: maybe `pass on' payload to lower-level protocol parsing
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dp_parse_ip (struct dp_handle * handle, const dp_header * header, const u_char * packet)
|
void dp_parse_ip(struct dp_handle *handle, const dp_header *header,
|
||||||
{
|
const u_char *packet) {
|
||||||
const struct ip * ip = (struct ip *) packet;
|
const struct ip *ip = (struct ip *)packet;
|
||||||
if (DP_DEBUG)
|
if (DP_DEBUG) {
|
||||||
{
|
fprintf(stdout, "Looking at packet with length %ud\n", header->len);
|
||||||
fprintf(stdout, "Looking at packet with length %ud\n", header->len);
|
}
|
||||||
}
|
u_char *payload = (u_char *)packet + sizeof(struct ip);
|
||||||
u_char * payload = (u_char *) packet + sizeof (struct ip);
|
|
||||||
|
|
||||||
if (handle->callback[dp_packet_ip] != NULL)
|
if (handle->callback[dp_packet_ip] != NULL) {
|
||||||
{
|
int done =
|
||||||
int done = (handle->callback[dp_packet_ip])
|
(handle->callback[dp_packet_ip])(handle->userdata, header, packet);
|
||||||
(handle->userdata, header, packet);
|
if (done)
|
||||||
if (done)
|
return;
|
||||||
return;
|
}
|
||||||
}
|
switch (ip->ip_p) {
|
||||||
switch (ip->ip_p)
|
case IPPROTO_TCP:
|
||||||
{
|
dp_parse_tcp(handle, header, payload);
|
||||||
case IPPROTO_TCP:
|
break;
|
||||||
dp_parse_tcp (handle, header, payload);
|
default:
|
||||||
break;
|
// TODO: maybe support for non-tcp IP packets
|
||||||
default:
|
break;
|
||||||
// TODO: maybe support for non-tcp IP packets
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dp_parse_ip6 (struct dp_handle * handle, const dp_header * header, const u_char * packet)
|
void dp_parse_ip6(struct dp_handle *handle, const dp_header *header,
|
||||||
{
|
const u_char *packet) {
|
||||||
const struct ip6_hdr * ip6 = (struct ip6_hdr *) packet;
|
const struct ip6_hdr *ip6 = (struct ip6_hdr *)packet;
|
||||||
u_char * payload = (u_char *) packet + sizeof (struct ip6_hdr);
|
u_char *payload = (u_char *)packet + sizeof(struct ip6_hdr);
|
||||||
|
|
||||||
if (handle->callback[dp_packet_ip6] != NULL)
|
if (handle->callback[dp_packet_ip6] != NULL) {
|
||||||
{
|
int done =
|
||||||
int done = (handle->callback[dp_packet_ip6])
|
(handle->callback[dp_packet_ip6])(handle->userdata, header, packet);
|
||||||
(handle->userdata, header, packet);
|
if (done)
|
||||||
if (done)
|
return;
|
||||||
return;
|
}
|
||||||
}
|
switch ((ip6->ip6_ctlun).ip6_un1.ip6_un1_nxt) {
|
||||||
switch ((ip6->ip6_ctlun).ip6_un1.ip6_un1_nxt)
|
case IPPROTO_TCP:
|
||||||
{
|
dp_parse_tcp(handle, header, payload);
|
||||||
case IPPROTO_TCP:
|
break;
|
||||||
dp_parse_tcp (handle, header, payload);
|
default:
|
||||||
break;
|
// TODO: maybe support for non-tcp ipv6 packets
|
||||||
default:
|
break;
|
||||||
// TODO: maybe support for non-tcp ipv6 packets
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dp_parse_ethernet (struct dp_handle * handle, const dp_header * header, const u_char * packet)
|
void dp_parse_ethernet(struct dp_handle *handle, const dp_header *header,
|
||||||
{
|
const u_char *packet) {
|
||||||
const struct ether_header * ethernet = (struct ether_header *)packet;
|
const struct ether_header *ethernet = (struct ether_header *)packet;
|
||||||
u_char * payload = (u_char *) packet + sizeof (struct ether_header);
|
u_char *payload = (u_char *)packet + sizeof(struct ether_header);
|
||||||
u_int16_t protocol = 0;
|
u_int16_t protocol = 0;
|
||||||
|
|
||||||
/* call handle if it exists */
|
/* call handle if it exists */
|
||||||
if (handle->callback[dp_packet_ethernet] != NULL)
|
if (handle->callback[dp_packet_ethernet] != NULL) {
|
||||||
{
|
int done = (handle->callback[dp_packet_ethernet])(handle->userdata, header,
|
||||||
int done = (handle->callback[dp_packet_ethernet])
|
packet);
|
||||||
(handle->userdata, header, packet);
|
|
||||||
|
|
||||||
/* return if handle decides we're done */
|
/* return if handle decides we're done */
|
||||||
if (done)
|
if (done)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse payload */
|
/* parse payload */
|
||||||
protocol = ntohs(ethernet->ether_type);
|
protocol = ntohs(ethernet->ether_type);
|
||||||
switch (protocol)
|
switch (protocol) {
|
||||||
{
|
case ETHERTYPE_IP:
|
||||||
case ETHERTYPE_IP:
|
dp_parse_ip(handle, header, payload);
|
||||||
dp_parse_ip (handle, header, payload);
|
break;
|
||||||
break;
|
case ETHERTYPE_IPV6:
|
||||||
case ETHERTYPE_IPV6:
|
dp_parse_ip6(handle, header, payload);
|
||||||
dp_parse_ip6 (handle, header, payload);
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
// TODO: maybe support for other protocols apart from IPv4 and IPv6
|
||||||
// TODO: maybe support for other protocols apart from IPv4 and IPv6
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ppp header, i hope ;) */
|
/* ppp header, i hope ;) */
|
||||||
/* glanced from ethereal, it's 16 bytes, and the payload packet type is
|
/* glanced from ethereal, it's 16 bytes, and the payload packet type is
|
||||||
* in the last 2 bytes... */
|
* in the last 2 bytes... */
|
||||||
struct ppp_header {
|
struct ppp_header {
|
||||||
u_int16_t dummy1;
|
u_int16_t dummy1;
|
||||||
u_int16_t dummy2;
|
u_int16_t dummy2;
|
||||||
u_int16_t dummy3;
|
u_int16_t dummy3;
|
||||||
u_int16_t dummy4;
|
u_int16_t dummy4;
|
||||||
u_int16_t dummy5;
|
u_int16_t dummy5;
|
||||||
u_int16_t dummy6;
|
u_int16_t dummy6;
|
||||||
u_int16_t dummy7;
|
u_int16_t dummy7;
|
||||||
|
|
||||||
u_int16_t packettype;
|
u_int16_t packettype;
|
||||||
};
|
};
|
||||||
|
|
||||||
void dp_parse_ppp (struct dp_handle * handle, const dp_header * header, const u_char * packet)
|
void dp_parse_ppp(struct dp_handle *handle, const dp_header *header,
|
||||||
{
|
const u_char *packet) {
|
||||||
const struct ppp_header * ppp = (struct ppp_header *) packet;
|
const struct ppp_header *ppp = (struct ppp_header *)packet;
|
||||||
u_char * payload = (u_char *) packet + sizeof (struct ppp_header);
|
u_char *payload = (u_char *)packet + sizeof(struct ppp_header);
|
||||||
u_int16_t protocol = 0;
|
u_int16_t protocol = 0;
|
||||||
|
|
||||||
/* call handle if it exists */
|
/* call handle if it exists */
|
||||||
if (handle->callback[dp_packet_ppp] != NULL)
|
if (handle->callback[dp_packet_ppp] != NULL) {
|
||||||
{
|
int done =
|
||||||
int done = (handle->callback[dp_packet_ppp])
|
(handle->callback[dp_packet_ppp])(handle->userdata, header, packet);
|
||||||
(handle->userdata, header, packet);
|
|
||||||
|
|
||||||
/* return if handle decides we're done */
|
/* return if handle decides we're done */
|
||||||
if (done)
|
if (done)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse payload */
|
/* parse payload */
|
||||||
protocol = ntohs(ppp->packettype);
|
protocol = ntohs(ppp->packettype);
|
||||||
switch (protocol)
|
switch (protocol) {
|
||||||
{
|
case ETHERTYPE_IP:
|
||||||
case ETHERTYPE_IP:
|
dp_parse_ip(handle, header, payload);
|
||||||
dp_parse_ip (handle, header, payload);
|
break;
|
||||||
break;
|
case ETHERTYPE_IPV6:
|
||||||
case ETHERTYPE_IPV6:
|
dp_parse_ip6(handle, header, payload);
|
||||||
dp_parse_ip6 (handle, header, payload);
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
// TODO: support for other than IPv4 and IPv6
|
||||||
// TODO: support for other than IPv4 and IPv6
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* linux cooked header, i hope ;) */
|
/* linux cooked header, i hope ;) */
|
||||||
/* glanced from libpcap/ssl.h */
|
/* glanced from libpcap/ssl.h */
|
||||||
#define SLL_ADDRLEN 8 /* length of address field */
|
#define SLL_ADDRLEN 8 /* length of address field */
|
||||||
struct sll_header {
|
struct sll_header {
|
||||||
u_int16_t sll_pkttype; /* packet type */
|
u_int16_t sll_pkttype; /* packet type */
|
||||||
u_int16_t sll_hatype; /* link-layer address type */
|
u_int16_t sll_hatype; /* link-layer address type */
|
||||||
u_int16_t sll_halen; /* link-layer address length */
|
u_int16_t sll_halen; /* link-layer address length */
|
||||||
u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */
|
u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */
|
||||||
u_int16_t sll_protocol; /* protocol */
|
u_int16_t sll_protocol; /* protocol */
|
||||||
};
|
};
|
||||||
|
|
||||||
void dp_parse_linux_cooked (struct dp_handle * handle, const dp_header * header, const u_char * packet)
|
void dp_parse_linux_cooked(struct dp_handle *handle, const dp_header *header,
|
||||||
{
|
const u_char *packet) {
|
||||||
const struct sll_header * sll = (struct sll_header *) packet;
|
const struct sll_header *sll = (struct sll_header *)packet;
|
||||||
u_char * payload = (u_char *) packet + sizeof (struct sll_header);
|
u_char *payload = (u_char *)packet + sizeof(struct sll_header);
|
||||||
u_int16_t protocol = 0;
|
u_int16_t protocol = 0;
|
||||||
|
|
||||||
/* call handle if it exists */
|
/* call handle if it exists */
|
||||||
if (handle->callback[dp_packet_sll] != NULL)
|
if (handle->callback[dp_packet_sll] != NULL) {
|
||||||
{
|
int done =
|
||||||
int done = (handle->callback[dp_packet_sll])
|
(handle->callback[dp_packet_sll])(handle->userdata, header, packet);
|
||||||
(handle->userdata, header, packet);
|
|
||||||
|
|
||||||
/* return if handle decides we're done */
|
/* return if handle decides we're done */
|
||||||
if (done)
|
if (done)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse payload */
|
/* parse payload */
|
||||||
protocol = ntohs(sll->sll_protocol);
|
protocol = ntohs(sll->sll_protocol);
|
||||||
switch (protocol)
|
switch (protocol) {
|
||||||
{
|
case ETHERTYPE_IP:
|
||||||
case ETHERTYPE_IP:
|
dp_parse_ip(handle, header, payload);
|
||||||
dp_parse_ip (handle, header, payload);
|
break;
|
||||||
break;
|
case ETHERTYPE_IPV6:
|
||||||
case ETHERTYPE_IPV6:
|
dp_parse_ip6(handle, header, payload);
|
||||||
dp_parse_ip6 (handle, header, payload);
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
// TODO: support for other than IPv4 / IPv6
|
||||||
// TODO: support for other than IPv4 / IPv6
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* functions to do the monitoring */
|
/* functions to do the monitoring */
|
||||||
void dp_pcap_callback (u_char * u_handle, const struct pcap_pkthdr * header, const u_char * packet)
|
void dp_pcap_callback(u_char *u_handle, const struct pcap_pkthdr *header,
|
||||||
{
|
const u_char *packet) {
|
||||||
struct dp_handle * handle = (struct dp_handle *) u_handle;
|
struct dp_handle *handle = (struct dp_handle *)u_handle;
|
||||||
struct dp_header;
|
struct dp_header;
|
||||||
|
|
||||||
/* make a copy of the userdata for every packet */
|
/* make a copy of the userdata for every packet */
|
||||||
u_char * userdata_copy = (u_char *) malloc (handle->userdata_size);
|
u_char *userdata_copy = (u_char *)malloc(handle->userdata_size);
|
||||||
memcpy (userdata_copy, handle->userdata, handle->userdata_size);
|
memcpy(userdata_copy, handle->userdata, handle->userdata_size);
|
||||||
|
|
||||||
switch (handle->linktype) {
|
switch (handle->linktype) {
|
||||||
case (DLT_EN10MB):
|
case (DLT_EN10MB):
|
||||||
dp_parse_ethernet (handle, header, packet);
|
dp_parse_ethernet(handle, header, packet);
|
||||||
break;
|
break;
|
||||||
case (DLT_PPP):
|
case (DLT_PPP):
|
||||||
dp_parse_ppp (handle, header, packet);
|
dp_parse_ppp(handle, header, packet);
|
||||||
break;
|
break;
|
||||||
case (DLT_LINUX_SLL):
|
case (DLT_LINUX_SLL):
|
||||||
dp_parse_linux_cooked (handle, header, packet);
|
dp_parse_linux_cooked(handle, header, packet);
|
||||||
break;
|
break;
|
||||||
case (DLT_RAW):
|
case (DLT_RAW):
|
||||||
case (DLT_NULL):
|
case (DLT_NULL):
|
||||||
// hope for the best
|
// hope for the best
|
||||||
dp_parse_ip (handle, header, packet);
|
dp_parse_ip(handle, header, packet);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stdout, "Unknown linktype %d", handle->linktype);
|
fprintf(stdout, "Unknown linktype %d", handle->linktype);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
free (userdata_copy);
|
free(userdata_copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
int dp_dispatch (struct dp_handle * handle, int count, u_char *user, int size) {
|
int dp_dispatch(struct dp_handle *handle, int count, u_char *user, int size) {
|
||||||
handle->userdata = user;
|
handle->userdata = user;
|
||||||
handle->userdata_size = size;
|
handle->userdata_size = size;
|
||||||
return pcap_dispatch (handle->pcap_handle, count, dp_pcap_callback, (u_char *)handle);
|
return pcap_dispatch(handle->pcap_handle, count, dp_pcap_callback,
|
||||||
|
(u_char *)handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
int dp_setnonblock (struct dp_handle * handle, int i, char * errbuf) {
|
int dp_setnonblock(struct dp_handle *handle, int i, char *errbuf) {
|
||||||
return pcap_setnonblock (handle->pcap_handle, i, errbuf);
|
return pcap_setnonblock(handle->pcap_handle, i, errbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
char * dp_geterr (struct dp_handle * handle)
|
char *dp_geterr(struct dp_handle *handle) {
|
||||||
{
|
return pcap_geterr(handle->pcap_handle);
|
||||||
return pcap_geterr (handle->pcap_handle);
|
|
||||||
}
|
}
|
||||||
|
|||||||
55
decpcap.h
55
decpcap.h
@@ -1,4 +1,4 @@
|
|||||||
/*
|
/*
|
||||||
* decpcap.h
|
* decpcap.h
|
||||||
*
|
*
|
||||||
* Copyright (c) 2004-2006,2011 Arnout Engelen
|
* Copyright (c) 2004-2006,2011 Arnout Engelen
|
||||||
@@ -15,7 +15,8 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#ifndef __DECPCAP_H
|
#ifndef __DECPCAP_H
|
||||||
@@ -30,20 +31,20 @@
|
|||||||
/* definitions */
|
/* definitions */
|
||||||
|
|
||||||
enum dp_packet_type {
|
enum dp_packet_type {
|
||||||
dp_packet_ethernet,
|
dp_packet_ethernet,
|
||||||
dp_packet_ppp,
|
dp_packet_ppp,
|
||||||
dp_packet_sll,
|
dp_packet_sll,
|
||||||
dp_packet_ip,
|
dp_packet_ip,
|
||||||
dp_packet_ip6,
|
dp_packet_ip6,
|
||||||
dp_packet_tcp,
|
dp_packet_tcp,
|
||||||
dp_packet_udp,
|
dp_packet_udp,
|
||||||
dp_n_packet_types
|
dp_n_packet_types
|
||||||
};
|
};
|
||||||
|
|
||||||
/*enum dp_link_type {
|
/*enum dp_link_type {
|
||||||
dp_link_ethernet,
|
dp_link_ethernet,
|
||||||
dp_link_ppp,
|
dp_link_ppp,
|
||||||
dp_n_link_types
|
dp_n_link_types
|
||||||
};*/
|
};*/
|
||||||
|
|
||||||
/*struct dp_header {
|
/*struct dp_header {
|
||||||
@@ -54,36 +55,38 @@ typedef struct pcap_pkthdr dp_header;
|
|||||||
typedef int (*dp_callback)(u_char *, const dp_header *, const u_char *);
|
typedef int (*dp_callback)(u_char *, const dp_header *, const u_char *);
|
||||||
|
|
||||||
struct dp_handle {
|
struct dp_handle {
|
||||||
pcap_t * pcap_handle;
|
pcap_t *pcap_handle;
|
||||||
dp_callback callback [dp_n_packet_types];
|
dp_callback callback[dp_n_packet_types];
|
||||||
int linktype;
|
int linktype;
|
||||||
u_char * userdata;
|
u_char *userdata;
|
||||||
int userdata_size;
|
int userdata_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* functions to set up a handle (which is basically just a pcap handle) */
|
/* functions to set up a handle (which is basically just a pcap handle) */
|
||||||
|
|
||||||
struct dp_handle * dp_open_live(const char * device, int snaplen, int promisc, int to_ms, char * errbuf);
|
struct dp_handle *dp_open_live(const char *device, int snaplen, int promisc,
|
||||||
struct dp_handle * dp_open_offline(char * fname, char * ebuf);
|
int to_ms, char *errbuf);
|
||||||
|
struct dp_handle *dp_open_offline(char *fname, char *ebuf);
|
||||||
|
|
||||||
/* functions to add callbacks */
|
/* functions to add callbacks */
|
||||||
|
|
||||||
void dp_addcb (struct dp_handle * handle, enum dp_packet_type type, dp_callback callback);
|
void dp_addcb(struct dp_handle *handle, enum dp_packet_type type,
|
||||||
|
dp_callback callback);
|
||||||
|
|
||||||
/* functions to parse payloads */
|
/* functions to parse payloads */
|
||||||
|
|
||||||
void dp_parse (enum dp_packet_type type, void * packet);
|
void dp_parse(enum dp_packet_type type, void *packet);
|
||||||
|
|
||||||
/* functions to start monitoring */
|
/* functions to start monitoring */
|
||||||
|
|
||||||
int dp_dispatch (struct dp_handle * handler, int count, u_char *user, int size);
|
int dp_dispatch(struct dp_handle *handler, int count, u_char *user, int size);
|
||||||
|
|
||||||
/* functions that simply call libpcap */
|
/* functions that simply call libpcap */
|
||||||
|
|
||||||
int dp_datalink(struct dp_handle * handle);
|
int dp_datalink(struct dp_handle *handle);
|
||||||
|
|
||||||
int dp_setnonblock (struct dp_handle * handle, int i, char * errbuf);
|
int dp_setnonblock(struct dp_handle *handle, int i, char *errbuf);
|
||||||
|
|
||||||
char * dp_geterr (struct dp_handle * handle);
|
char *dp_geterr(struct dp_handle *handle);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/*
|
/*
|
||||||
* decpcap_test.cpp
|
* decpcap_test.cpp
|
||||||
*
|
*
|
||||||
* Copyright (c) 2006,2011 Arnout Engelen
|
* Copyright (c) 2006,2011 Arnout Engelen
|
||||||
@@ -15,36 +15,34 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "decpcap.h"
|
#include "decpcap.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
int process_tcp (u_char * /* userdata */, const dp_header * /* header */, const u_char * /* m_packet */) {
|
int process_tcp(u_char * /* userdata */, const dp_header * /* header */,
|
||||||
std::cout << "Callback for processing TCP packet called" << std::endl;
|
const u_char * /* m_packet */) {
|
||||||
return 0;
|
std::cout << "Callback for processing TCP packet called" << std::endl;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main (int argc, char ** argv)
|
int main(int argc, char **argv) {
|
||||||
{
|
if (argc < 2) {
|
||||||
if (argc < 2)
|
std::cout << "Please, enter a filename" << std::endl;
|
||||||
{
|
}
|
||||||
std::cout << "Please, enter a filename" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* errbuf = new char[DP_ERRBUF_SIZE];
|
char *errbuf = new char[DP_ERRBUF_SIZE];
|
||||||
|
|
||||||
dp_handle * newhandle = dp_open_offline(argv[1], errbuf);
|
dp_handle *newhandle = dp_open_offline(argv[1], errbuf);
|
||||||
dp_addcb (newhandle, dp_packet_tcp, process_tcp);
|
dp_addcb(newhandle, dp_packet_tcp, process_tcp);
|
||||||
int ret = dp_dispatch (newhandle, -1, NULL, 0);
|
int ret = dp_dispatch(newhandle, -1, NULL, 0);
|
||||||
if (ret == -1)
|
if (ret == -1) {
|
||||||
{
|
std::cout << "Error dispatching: " << dp_geterr(newhandle);
|
||||||
std::cout << "Error dispatching: " << dp_geterr(newhandle);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
89
devices.cpp
89
devices.cpp
@@ -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,68 +29,62 @@
|
|||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <ifaddrs.h>
|
#include <ifaddrs.h>
|
||||||
|
|
||||||
bool selected(int devc, char** devicenames, char* devicename) {
|
bool selected(int devc, char **devicenames, char *devicename) {
|
||||||
if (devc == 0)
|
if (devc == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
for (int i = 0; i < devc; i++)
|
for (int i = 0; i < devc; i++)
|
||||||
if (strcmp(devicenames[i], devicename) == 0)
|
if (strcmp(devicenames[i], devicename) == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool already_seen(device* devices, char* devicename) {
|
bool already_seen(device *devices, char *devicename) {
|
||||||
for (class device* current_device = devices;
|
for (class device *current_device = devices; current_device != NULL;
|
||||||
current_device != NULL;
|
current_device = current_device->next) {
|
||||||
current_device = current_device->next) {
|
if (strcmp(current_device->name, devicename) == 0)
|
||||||
if (strcmp(current_device->name, devicename) == 0)
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
return false;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The interface is up, not a loopback and running?
|
// The interface is up, not a loopback and running?
|
||||||
bool up_running(int ifa_flags) {
|
bool up_running(int ifa_flags) {
|
||||||
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 << "Failed to get interface addresses" << std::endl;
|
||||||
std::cerr << "Fail to get interface addresses" << std::endl;
|
// perror("getifaddrs");
|
||||||
// perror("getifaddrs");
|
return NULL;
|
||||||
return NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
device* devices = NULL;
|
device *devices = NULL;
|
||||||
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
|
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
|
||||||
{
|
if (ifa->ifa_addr == NULL)
|
||||||
if (ifa->ifa_addr == NULL)
|
continue;
|
||||||
continue;
|
if (!selected(devc, devicenames, ifa->ifa_name))
|
||||||
if (!selected(devc, devicenames, ifa->ifa_name))
|
continue;
|
||||||
continue;
|
if (already_seen(devices, ifa->ifa_name))
|
||||||
if (already_seen(devices, ifa->ifa_name))
|
continue;
|
||||||
continue;
|
if (!all && !up_running(ifa->ifa_flags))
|
||||||
if (!all && !up_running(ifa->ifa_flags))
|
continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
devices = new device(strdup(ifa->ifa_name),devices);
|
devices = new device(strdup(ifa->ifa_name), devices);
|
||||||
}
|
}
|
||||||
|
|
||||||
freeifaddrs(ifaddr);
|
freeifaddrs(ifaddr);
|
||||||
return devices;
|
return devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
device * get_default_devices() {
|
device *get_default_devices() { return get_devices(0, NULL, false); }
|
||||||
return get_devices(0, NULL, false);
|
|
||||||
}
|
|
||||||
|
|||||||
19
devices.h
19
devices.h
@@ -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
|
||||||
|
|||||||
296
inode2prog.cpp
296
inode2prog.cpp
@@ -15,11 +15,11 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -42,212 +42,208 @@ extern bool bughuntmode;
|
|||||||
// Not sure, but assuming there's no more PID's than go into 64 unsigned bits..
|
// Not sure, but assuming there's no more PID's than go into 64 unsigned bits..
|
||||||
const int MAX_PID_LENGTH = 20;
|
const int MAX_PID_LENGTH = 20;
|
||||||
|
|
||||||
// Max length of filenames in /proc/<pid>/fd/*. These are numeric, so 10 digits seems like a safe assumption.
|
// Max length of filenames in /proc/<pid>/fd/*. These are numeric, so 10 digits
|
||||||
|
// seems like a safe assumption.
|
||||||
const int MAX_FDLINK = 10;
|
const int MAX_FDLINK = 10;
|
||||||
|
|
||||||
/* maps from inode to program-struct */
|
/* maps from inode to program-struct */
|
||||||
std::map <unsigned long, prg_node *> inodeproc;
|
std::map<unsigned long, prg_node *> inodeproc;
|
||||||
|
|
||||||
bool is_number (const char * string) {
|
bool is_number(const char *string) {
|
||||||
while (*string) {
|
while (*string) {
|
||||||
if (!isdigit (*string))
|
if (!isdigit(*string))
|
||||||
return false;
|
return false;
|
||||||
string++;
|
string++;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long str2ulong (const char * ptr) {
|
unsigned long str2ulong(const char *ptr) {
|
||||||
unsigned long retval = 0;
|
unsigned long retval = 0;
|
||||||
|
|
||||||
while ((*ptr >= '0') && (*ptr <= '9')) {
|
while ((*ptr >= '0') && (*ptr <= '9')) {
|
||||||
retval *= 10;
|
retval *= 10;
|
||||||
retval += *ptr - '0';
|
retval += *ptr - '0';
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
int str2int (const char * ptr) {
|
int str2int(const char *ptr) {
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
while ((*ptr >= '0') && (*ptr <= '9')) {
|
while ((*ptr >= '0') && (*ptr <= '9')) {
|
||||||
retval *= 10;
|
retval *= 10;
|
||||||
retval += *ptr - '0';
|
retval += *ptr - '0';
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string read_file (int fd) {
|
static std::string read_file(int fd) {
|
||||||
char buf[255];
|
char buf[255];
|
||||||
std::string content;
|
std::string content;
|
||||||
|
|
||||||
for (int length; (length = read(fd, buf, sizeof(buf))) > 0;) {
|
for (int length; (length = read(fd, buf, sizeof(buf))) > 0;) {
|
||||||
if (length < 0) {
|
if (length < 0) {
|
||||||
std::fprintf(stderr, "Error reading file: %s\n", std::strerror(errno));
|
std::fprintf(stderr, "Error reading file: %s\n", std::strerror(errno));
|
||||||
std::exit(34);
|
std::exit(34);
|
||||||
}
|
}
|
||||||
content.append(buf, length);
|
content.append(buf, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string read_file (const char* filepath) {
|
static std::string read_file(const char *filepath) {
|
||||||
int fd = open(filepath, O_RDONLY);
|
int fd = open(filepath, O_RDONLY);
|
||||||
|
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
std::fprintf(stderr, "Error opening %s: %s\n", filepath, std::strerror(errno));
|
std::fprintf(stderr, "Error opening %s: %s\n", filepath,
|
||||||
std::exit(3);
|
std::strerror(errno));
|
||||||
return NULL;
|
std::exit(3);
|
||||||
}
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
std::string contents = read_file(fd);
|
std::string contents = read_file(fd);
|
||||||
|
|
||||||
if (close(fd)) {
|
if (close(fd)) {
|
||||||
std::fprintf(stderr, "Error opening %s: %s\n", filepath, std::strerror(errno));
|
std::fprintf(stderr, "Error opening %s: %s\n", filepath,
|
||||||
std::exit(34);
|
std::strerror(errno));
|
||||||
}
|
std::exit(34);
|
||||||
|
}
|
||||||
|
|
||||||
return contents;
|
return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getprogname (pid_t pid) {
|
std::string getprogname(pid_t pid) {
|
||||||
const int maxfilenamelen = 14 + MAX_PID_LENGTH + 1;
|
const int maxfilenamelen = 14 + MAX_PID_LENGTH + 1;
|
||||||
char filename[maxfilenamelen];
|
char filename[maxfilenamelen];
|
||||||
|
|
||||||
std::snprintf(filename, maxfilenamelen, "/proc/%d/cmdline", pid);
|
std::snprintf(filename, maxfilenamelen, "/proc/%d/cmdline", pid);
|
||||||
return read_file(filename);
|
return read_file(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setnode (unsigned long inode, pid_t pid) {
|
void setnode(unsigned long inode, pid_t pid) {
|
||||||
prg_node * current_value = inodeproc[inode];
|
prg_node *current_value = inodeproc[inode];
|
||||||
|
|
||||||
if (current_value == NULL || current_value->pid != pid) {
|
if (current_value == NULL || current_value->pid != pid) {
|
||||||
prg_node * newnode = new prg_node;
|
prg_node *newnode = new prg_node;
|
||||||
newnode->inode = inode;
|
newnode->inode = inode;
|
||||||
newnode->pid = pid;
|
newnode->pid = pid;
|
||||||
newnode->name = getprogname(pid);
|
newnode->name = getprogname(pid);
|
||||||
|
|
||||||
inodeproc[inode] = newnode;
|
inodeproc[inode] = newnode;
|
||||||
delete current_value;
|
delete current_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_info_by_linkname (const char * pid, const char * linkname) {
|
void get_info_by_linkname(const char *pid, const char *linkname) {
|
||||||
if (strncmp(linkname, "socket:[", 8) == 0) {
|
if (strncmp(linkname, "socket:[", 8) == 0) {
|
||||||
setnode(str2ulong(linkname + 8), str2int(pid));
|
setnode(str2ulong(linkname + 8), str2int(pid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* updates the `inodeproc' inode-to-prg_node
|
/* updates the `inodeproc' inode-to-prg_node
|
||||||
* for all inodes belonging to this PID
|
* for all inodes belonging to this PID
|
||||||
* (/proc/pid/fd/42)
|
* (/proc/pid/fd/42)
|
||||||
* */
|
* */
|
||||||
void get_info_for_pid(const char * pid) {
|
void get_info_for_pid(const char *pid) {
|
||||||
char dirname[10 + MAX_PID_LENGTH];
|
char dirname[10 + MAX_PID_LENGTH];
|
||||||
|
|
||||||
size_t dirlen = 10 + strlen(pid);
|
size_t dirlen = 10 + strlen(pid);
|
||||||
snprintf(dirname, dirlen, "/proc/%s/fd", pid);
|
snprintf(dirname, dirlen, "/proc/%s/fd", pid);
|
||||||
|
|
||||||
DIR * dir = opendir(dirname);
|
DIR *dir = opendir(dirname);
|
||||||
|
|
||||||
if (!dir)
|
if (!dir) {
|
||||||
{
|
if (bughuntmode) {
|
||||||
if (bughuntmode)
|
std::cout << "Couldn't open dir " << dirname << ": " << strerror(errno)
|
||||||
{
|
<< "\n";
|
||||||
std::cout << "Couldn't open dir " << dirname << ": " << strerror(errno) << "\n";
|
}
|
||||||
}
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* walk through /proc/%s/fd/... */
|
/* walk through /proc/%s/fd/... */
|
||||||
dirent * entry;
|
dirent *entry;
|
||||||
while ((entry = readdir(dir))) {
|
while ((entry = readdir(dir))) {
|
||||||
if (entry->d_type != DT_LNK)
|
if (entry->d_type != DT_LNK)
|
||||||
continue;
|
continue;
|
||||||
//std::cout << "Looking at: " << entry->d_name << std::endl;
|
// std::cout << "Looking at: " << entry->d_name << std::endl;
|
||||||
|
|
||||||
size_t fromlen = dirlen + strlen(entry->d_name) + 1;
|
size_t fromlen = dirlen + strlen(entry->d_name) + 1;
|
||||||
char fromname[10 + MAX_PID_LENGTH + 1 + MAX_FDLINK];
|
char fromname[10 + MAX_PID_LENGTH + 1 + MAX_FDLINK];
|
||||||
snprintf (fromname, fromlen, "%s/%s", dirname, entry->d_name);
|
snprintf(fromname, fromlen, "%s/%s", dirname, entry->d_name);
|
||||||
|
|
||||||
//std::cout << "Linking from: " << fromname << std::endl;
|
// std::cout << "Linking from: " << fromname << std::endl;
|
||||||
|
|
||||||
int linklen = 80;
|
int linklen = 80;
|
||||||
char linkname [linklen];
|
char linkname[linklen];
|
||||||
int usedlen = readlink(fromname, linkname, linklen-1);
|
int usedlen = readlink(fromname, linkname, linklen - 1);
|
||||||
if (usedlen == -1)
|
if (usedlen == -1) {
|
||||||
{
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
assert(usedlen < linklen);
|
||||||
assert (usedlen < linklen);
|
linkname[usedlen] = '\0';
|
||||||
linkname[usedlen] = '\0';
|
get_info_by_linkname(pid, linkname);
|
||||||
get_info_by_linkname (pid, linkname);
|
}
|
||||||
}
|
closedir(dir);
|
||||||
closedir(dir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* updates the `inodeproc' inode-to-prg_node mapping
|
/* updates the `inodeproc' inode-to-prg_node mapping
|
||||||
* for all processes in /proc */
|
* for all processes in /proc */
|
||||||
void reread_mapping () {
|
void reread_mapping() {
|
||||||
DIR * proc = opendir ("/proc");
|
DIR *proc = opendir("/proc");
|
||||||
|
|
||||||
if (proc == 0) {
|
if (proc == 0) {
|
||||||
std::cerr << "Error reading /proc, neede to get inode-to-pid-maping\n";
|
std::cerr << "Error reading /proc, neede to get inode-to-pid-maping\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
dirent * entry;
|
dirent *entry;
|
||||||
|
|
||||||
while ((entry = readdir(proc))) {
|
while ((entry = readdir(proc))) {
|
||||||
if (entry->d_type != DT_DIR) continue;
|
if (entry->d_type != DT_DIR)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (! is_number (entry->d_name)) continue;
|
if (!is_number(entry->d_name))
|
||||||
|
continue;
|
||||||
|
|
||||||
get_info_for_pid(entry->d_name);
|
get_info_for_pid(entry->d_name);
|
||||||
}
|
}
|
||||||
closedir(proc);
|
closedir(proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct prg_node * findPID (unsigned long inode)
|
struct prg_node *findPID(unsigned long inode) {
|
||||||
{
|
/* we first look in inodeproc */
|
||||||
/* we first look in inodeproc */
|
struct prg_node *node = inodeproc[inode];
|
||||||
struct prg_node * node = inodeproc[inode];
|
|
||||||
|
|
||||||
if (node != NULL)
|
if (node != NULL) {
|
||||||
{
|
if (bughuntmode) {
|
||||||
if (bughuntmode)
|
std::cout << ":) Found pid in inodeproc table" << std::endl;
|
||||||
{
|
}
|
||||||
std::cout << ":) Found pid in inodeproc table" << std::endl;
|
return node;
|
||||||
}
|
}
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef __APPLE__
|
#ifndef __APPLE__
|
||||||
reread_mapping();
|
reread_mapping();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct prg_node * retval = inodeproc[inode];
|
struct prg_node *retval = inodeproc[inode];
|
||||||
if (bughuntmode)
|
if (bughuntmode) {
|
||||||
{
|
if (retval == NULL) {
|
||||||
if (retval == NULL)
|
std::cout << ":( No pid after inodeproc refresh" << std::endl;
|
||||||
{
|
} else {
|
||||||
std::cout << ":( No pid after inodeproc refresh" << std::endl;
|
std::cout << ":) Found pid after inodeproc refresh" << std::endl;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
return retval;
|
||||||
std::cout << ":) Found pid after inodeproc refresh" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void prg_cache_clear() {};
|
void prg_cache_clear(){};
|
||||||
|
|
||||||
/*void main () {
|
/*void main () {
|
||||||
std::cout << "Fooo\n";
|
std::cout << "Fooo\n";
|
||||||
reread_mapping();
|
reread_mapping();
|
||||||
std::cout << "Haihai\n";
|
std::cout << "Haihai\n";
|
||||||
}*/
|
}*/
|
||||||
|
|||||||
13
inode2prog.h
13
inode2prog.h
@@ -15,7 +15,8 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#ifndef __INODE2PROG_h
|
#ifndef __INODE2PROG_h
|
||||||
@@ -28,16 +29,16 @@
|
|||||||
#include "nethogs.h"
|
#include "nethogs.h"
|
||||||
|
|
||||||
struct prg_node {
|
struct prg_node {
|
||||||
long inode;
|
long inode;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct prg_node * findPID (unsigned long inode);
|
struct prg_node *findPID(unsigned long inode);
|
||||||
|
|
||||||
void prg_cache_clear();
|
void prg_cache_clear();
|
||||||
|
|
||||||
// reread the inode-to-prg_node-mapping
|
// reread the inode-to-prg_node-mapping
|
||||||
void reread_mapping ();
|
void reread_mapping();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
542
libnethogs.cpp
542
libnethogs.cpp
@@ -1,6 +1,5 @@
|
|||||||
extern "C"
|
extern "C" {
|
||||||
{
|
#include "libnethogs.h"
|
||||||
#include "libnethogs.h"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "nethogs.cpp"
|
#include "nethogs.cpp"
|
||||||
@@ -13,359 +12,318 @@ extern "C"
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
extern ProcList * processes;
|
extern ProcList *processes;
|
||||||
extern Process * unknowntcp;
|
extern Process *unknowntcp;
|
||||||
extern Process * unknownudp;
|
extern Process *unknownudp;
|
||||||
extern Process * unknownip;
|
extern Process *unknownip;
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|
||||||
//The self_pipe is used to interrupt the select() in the main loop
|
// The self_pipe is used to interrupt the select() in the main loop
|
||||||
static std::pair<int,int> self_pipe = std::make_pair(-1, -1);
|
static std::pair<int, int> self_pipe = std::make_pair(-1, -1);
|
||||||
|
|
||||||
static bool monitor_run_flag = false;
|
static bool monitor_run_flag = false;
|
||||||
typedef std::map<void*, NethogsMonitorRecord> NethogsRecordMap;
|
typedef std::map<void *, NethogsMonitorRecord> NethogsRecordMap;
|
||||||
static NethogsRecordMap monitor_record_map;
|
static NethogsRecordMap monitor_record_map;
|
||||||
|
|
||||||
static int monitor_refresh_delay = 1;
|
static int monitor_refresh_delay = 1;
|
||||||
static time_t monitor_last_refresh_time = 0;
|
static time_t monitor_last_refresh_time = 0;
|
||||||
|
|
||||||
//selectable file descriptors for the main loop
|
// selectable file descriptors for the main loop
|
||||||
static fd_set pc_loop_fd_set;
|
static fd_set pc_loop_fd_set;
|
||||||
static std::vector<int> pc_loop_fd_list;
|
static std::vector<int> pc_loop_fd_list;
|
||||||
static bool pc_loop_use_select = true;
|
static bool pc_loop_use_select = true;
|
||||||
|
|
||||||
static handle * handles = NULL;
|
static handle *handles = NULL;
|
||||||
|
|
||||||
static std::pair<int, int> create_self_pipe()
|
static std::pair<int, int> create_self_pipe() {
|
||||||
{
|
int pfd[2];
|
||||||
int pfd[2];
|
if (pipe(pfd) == -1)
|
||||||
if (pipe(pfd) == -1)
|
return std::make_pair(-1, -1);
|
||||||
return std::make_pair(-1, -1);
|
|
||||||
|
|
||||||
if (fcntl(pfd[0], F_SETFL, fcntl(pfd[0], F_GETFL) | O_NONBLOCK) == -1)
|
if (fcntl(pfd[0], F_SETFL, fcntl(pfd[0], F_GETFL) | O_NONBLOCK) == -1)
|
||||||
return std::make_pair(-1, -1);
|
return std::make_pair(-1, -1);
|
||||||
|
|
||||||
if (fcntl(pfd[1], F_SETFL, fcntl(pfd[1], F_GETFL) | O_NONBLOCK) == -1)
|
if (fcntl(pfd[1], F_SETFL, fcntl(pfd[1], F_GETFL) | O_NONBLOCK) == -1)
|
||||||
return std::make_pair(-1, -1);
|
return std::make_pair(-1, -1);
|
||||||
|
|
||||||
return std::make_pair(pfd[0], pfd[1]);
|
return std::make_pair(pfd[0], pfd[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool wait_for_next_trigger()
|
static bool wait_for_next_trigger() {
|
||||||
{
|
if (pc_loop_use_select) {
|
||||||
if( pc_loop_use_select )
|
FD_ZERO(&pc_loop_fd_set);
|
||||||
{
|
int nfds = 0;
|
||||||
FD_ZERO(&pc_loop_fd_set);
|
for (std::vector<int>::const_iterator it = pc_loop_fd_list.begin();
|
||||||
int nfds = 0;
|
it != pc_loop_fd_list.end(); ++it) {
|
||||||
for(std::vector<int>::const_iterator it=pc_loop_fd_list.begin();
|
int const fd = *it;
|
||||||
it != pc_loop_fd_list.end(); ++it)
|
nfds = std::max(nfds, *it + 1);
|
||||||
{
|
FD_SET(fd, &pc_loop_fd_set);
|
||||||
int const fd = *it;
|
}
|
||||||
nfds = std::max(nfds, *it + 1);
|
timeval timeout = {monitor_refresh_delay, 0};
|
||||||
FD_SET(fd, &pc_loop_fd_set);
|
if (select(nfds, &pc_loop_fd_set, 0, 0, &timeout) != -1) {
|
||||||
}
|
if (FD_ISSET(self_pipe.first, &pc_loop_fd_set)) {
|
||||||
timeval timeout = {monitor_refresh_delay, 0};
|
return false;
|
||||||
if( select(nfds, &pc_loop_fd_set, 0, 0, &timeout) != -1 )
|
}
|
||||||
{
|
}
|
||||||
if( FD_ISSET(self_pipe.first, &pc_loop_fd_set) )
|
} else {
|
||||||
{
|
// If select() not possible, pause to prevent 100%
|
||||||
return false;
|
usleep(1000);
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If select() not possible, pause to prevent 100%
|
|
||||||
usleep(1000);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nethogsmonitor_init()
|
static int nethogsmonitor_init() {
|
||||||
{
|
process_init();
|
||||||
process_init();
|
|
||||||
|
|
||||||
device * devices = get_default_devices();
|
device *devices = get_default_devices();
|
||||||
if ( devices == NULL )
|
if (devices == NULL) {
|
||||||
{
|
std::cerr << "No devices to monitor" << std::endl;
|
||||||
std::cerr << "No devices to monitor" << std::endl;
|
return NETHOGS_STATUS_NO_DEVICE;
|
||||||
return NETHOGS_STATUS_NO_DEVICE;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
device * current_dev = devices;
|
device *current_dev = devices;
|
||||||
|
|
||||||
bool promiscuous = false;
|
bool promiscuous = false;
|
||||||
|
|
||||||
int nb_devices = 0;
|
int nb_devices = 0;
|
||||||
int nb_failed_devices = 0;
|
int nb_failed_devices = 0;
|
||||||
|
|
||||||
while (current_dev != NULL)
|
while (current_dev != NULL) {
|
||||||
{
|
++nb_devices;
|
||||||
++nb_devices;
|
|
||||||
|
|
||||||
if( !getLocal(current_dev->name, false) )
|
if (!getLocal(current_dev->name, false)) {
|
||||||
{
|
std::cerr << "getifaddrs failed while establishing local IP."
|
||||||
std::cerr << "getifaddrs failed while establishing local IP." << std::endl;
|
<< std::endl;
|
||||||
++nb_failed_devices;
|
++nb_failed_devices;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
char errbuf[PCAP_ERRBUF_SIZE];
|
char errbuf[PCAP_ERRBUF_SIZE];
|
||||||
dp_handle * newhandle = dp_open_live(current_dev->name, BUFSIZ, promiscuous, 100, errbuf);
|
dp_handle *newhandle =
|
||||||
if (newhandle != NULL)
|
dp_open_live(current_dev->name, BUFSIZ, promiscuous, 100, errbuf);
|
||||||
{
|
if (newhandle != NULL) {
|
||||||
dp_addcb (newhandle, dp_packet_ip, process_ip);
|
dp_addcb(newhandle, dp_packet_ip, process_ip);
|
||||||
dp_addcb (newhandle, dp_packet_ip6, process_ip6);
|
dp_addcb(newhandle, dp_packet_ip6, process_ip6);
|
||||||
dp_addcb (newhandle, dp_packet_tcp, process_tcp);
|
dp_addcb(newhandle, dp_packet_tcp, process_tcp);
|
||||||
dp_addcb (newhandle, dp_packet_udp, process_udp);
|
dp_addcb(newhandle, dp_packet_udp, process_udp);
|
||||||
|
|
||||||
/* The following code solves sf.net bug 1019381, but is only available
|
/* The following code solves sf.net bug 1019381, but is only available
|
||||||
* in newer versions (from 0.8 it seems) of libpcap
|
* in newer versions (from 0.8 it seems) of libpcap
|
||||||
*
|
*
|
||||||
* update: version 0.7.2, which is in debian stable now, should be ok
|
* update: version 0.7.2, which is in debian stable now, should be ok
|
||||||
* also.
|
* also.
|
||||||
*/
|
*/
|
||||||
if (dp_setnonblock (newhandle, 1, errbuf) == -1)
|
if (dp_setnonblock(newhandle, 1, errbuf) == -1) {
|
||||||
{
|
fprintf(stderr, "Error putting libpcap in nonblocking mode\n");
|
||||||
fprintf(stderr, "Error putting libpcap in nonblocking mode\n");
|
}
|
||||||
}
|
handles = new handle(newhandle, current_dev->name, handles);
|
||||||
handles = new handle (newhandle, current_dev->name, handles);
|
|
||||||
|
|
||||||
if( pc_loop_use_select )
|
if (pc_loop_use_select) {
|
||||||
{
|
// some devices may not support pcap_get_selectable_fd
|
||||||
//some devices may not support pcap_get_selectable_fd
|
int const fd = pcap_get_selectable_fd(newhandle->pcap_handle);
|
||||||
int const fd = pcap_get_selectable_fd(newhandle->pcap_handle);
|
if (fd != -1) {
|
||||||
if( fd != -1 )
|
pc_loop_fd_list.push_back(fd);
|
||||||
{
|
} else {
|
||||||
pc_loop_fd_list.push_back(fd);
|
pc_loop_use_select = false;
|
||||||
}
|
pc_loop_fd_list.clear();
|
||||||
else
|
fprintf(stderr, "failed to get selectable_fd for %s\n",
|
||||||
{
|
current_dev->name);
|
||||||
pc_loop_use_select = false;
|
}
|
||||||
pc_loop_fd_list.clear();
|
}
|
||||||
fprintf(stderr, "failed to get selectable_fd for %s\n", current_dev->name);
|
} else {
|
||||||
}
|
fprintf(stderr, "ERROR: opening handler for device %s: %s\n",
|
||||||
}
|
current_dev->name, strerror(errno));
|
||||||
}
|
++nb_failed_devices;
|
||||||
else
|
}
|
||||||
{
|
|
||||||
fprintf(stderr, "ERROR: opening handler for device %s: %s\n", current_dev->name, strerror(errno));
|
|
||||||
++nb_failed_devices;
|
|
||||||
}
|
|
||||||
|
|
||||||
current_dev = current_dev->next;
|
current_dev = current_dev->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nb_devices == nb_failed_devices)
|
if (nb_devices == nb_failed_devices) {
|
||||||
{
|
return NETHOGS_STATUS_FAILURE;
|
||||||
return NETHOGS_STATUS_FAILURE;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//use the Self-Pipe trick to interrupt the select() in the main loop
|
// use the Self-Pipe trick to interrupt the select() in the main loop
|
||||||
if( pc_loop_use_select )
|
if (pc_loop_use_select) {
|
||||||
{
|
self_pipe = create_self_pipe();
|
||||||
self_pipe = create_self_pipe();
|
if (self_pipe.first == -1 || self_pipe.second == -1) {
|
||||||
if( self_pipe.first == -1 || self_pipe.second == -1 )
|
std::cerr << "Error creating pipe file descriptors\n";
|
||||||
{
|
pc_loop_use_select = false;
|
||||||
std::cerr << "Error creating pipe file descriptors\n";
|
} else {
|
||||||
pc_loop_use_select = false;
|
pc_loop_fd_list.push_back(self_pipe.first);
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
|
||||||
pc_loop_fd_list.push_back(self_pipe.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NETHOGS_STATUS_OK;
|
return NETHOGS_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nethogsmonitor_handle_update(NethogsMonitorCallback cb)
|
static void nethogsmonitor_handle_update(NethogsMonitorCallback cb) {
|
||||||
{
|
refreshconninode();
|
||||||
refreshconninode();
|
refreshcount++;
|
||||||
refreshcount++;
|
|
||||||
|
|
||||||
ProcList * curproc = processes;
|
ProcList *curproc = processes;
|
||||||
ProcList * previousproc = NULL;
|
ProcList *previousproc = NULL;
|
||||||
int nproc = processes->size();
|
int nproc = processes->size();
|
||||||
|
|
||||||
while (curproc != NULL)
|
while (curproc != NULL) {
|
||||||
{
|
// walk though its connections, summing up their data, and
|
||||||
// walk though its connections, summing up their data, and
|
// throwing away connections that haven't received a package
|
||||||
// throwing away connections that haven't received a package
|
// in the last PROCESSTIMEOUT seconds.
|
||||||
// in the last PROCESSTIMEOUT seconds.
|
assert(curproc != NULL);
|
||||||
assert (curproc != NULL);
|
assert(curproc->getVal() != NULL);
|
||||||
assert (curproc->getVal() != NULL);
|
assert(nproc == processes->size());
|
||||||
assert (nproc == processes->size());
|
|
||||||
|
|
||||||
/* remove timed-out processes (unless it's one of the the unknown process) */
|
/* remove timed-out processes (unless it's one of the the unknown process)
|
||||||
if ((curproc->getVal()->getLastPacket() + PROCESSTIMEOUT <= curtime.tv_sec)
|
*/
|
||||||
&& (curproc->getVal() != unknowntcp)
|
if ((curproc->getVal()->getLastPacket() + PROCESSTIMEOUT <=
|
||||||
&& (curproc->getVal() != unknownudp)
|
curtime.tv_sec) &&
|
||||||
&& (curproc->getVal() != unknownip))
|
(curproc->getVal() != unknowntcp) &&
|
||||||
{
|
(curproc->getVal() != unknownudp) && (curproc->getVal() != unknownip)) {
|
||||||
if (DEBUG)
|
if (DEBUG)
|
||||||
std::cout << "PROC: Deleting process\n";
|
std::cout << "PROC: Deleting process\n";
|
||||||
|
|
||||||
NethogsRecordMap::iterator it = monitor_record_map.find(curproc);
|
NethogsRecordMap::iterator it = monitor_record_map.find(curproc);
|
||||||
if( it != monitor_record_map.end() )
|
if (it != monitor_record_map.end()) {
|
||||||
{
|
NethogsMonitorRecord &data = it->second;
|
||||||
NethogsMonitorRecord& data = it->second;
|
(*cb)(NETHOGS_APP_ACTION_REMOVE, &data);
|
||||||
(*cb)(NETHOGS_APP_ACTION_REMOVE, &data);
|
monitor_record_map.erase(curproc);
|
||||||
monitor_record_map.erase(curproc);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ProcList * todelete = curproc;
|
ProcList *todelete = curproc;
|
||||||
Process * p_todelete = curproc->getVal();
|
Process *p_todelete = curproc->getVal();
|
||||||
if (previousproc)
|
if (previousproc) {
|
||||||
{
|
previousproc->next = curproc->next;
|
||||||
previousproc->next = curproc->next;
|
curproc = curproc->next;
|
||||||
curproc = curproc->next;
|
} else {
|
||||||
} else
|
processes = curproc->getNext();
|
||||||
{
|
curproc = processes;
|
||||||
processes = curproc->getNext();
|
}
|
||||||
curproc = processes;
|
delete todelete;
|
||||||
}
|
delete p_todelete;
|
||||||
delete todelete;
|
nproc--;
|
||||||
delete p_todelete;
|
// continue;
|
||||||
nproc--;
|
} else {
|
||||||
//continue;
|
const u_int32_t uid = curproc->getVal()->getUid();
|
||||||
}
|
u_int32_t sent_bytes;
|
||||||
else
|
u_int32_t recv_bytes;
|
||||||
{
|
float sent_kbs;
|
||||||
const u_int32_t uid = curproc->getVal()->getUid();
|
float recv_kbs;
|
||||||
u_int32_t sent_bytes;
|
curproc->getVal()->getkbps(&recv_kbs, &sent_kbs);
|
||||||
u_int32_t recv_bytes;
|
curproc->getVal()->gettotal(&recv_bytes, &sent_bytes);
|
||||||
float sent_kbs;
|
|
||||||
float recv_kbs;
|
|
||||||
curproc->getVal()->getkbps (&recv_kbs, &sent_kbs);
|
|
||||||
curproc->getVal()->gettotal (&recv_bytes, &sent_bytes);
|
|
||||||
|
|
||||||
//notify update
|
// notify update
|
||||||
bool const new_data = (monitor_record_map.find(curproc) == monitor_record_map.end());
|
bool const new_data =
|
||||||
NethogsMonitorRecord &data = monitor_record_map[curproc];
|
(monitor_record_map.find(curproc) == monitor_record_map.end());
|
||||||
|
NethogsMonitorRecord &data = monitor_record_map[curproc];
|
||||||
|
|
||||||
bool data_change = false;
|
bool data_change = false;
|
||||||
if( new_data )
|
if (new_data) {
|
||||||
{
|
data_change = true;
|
||||||
data_change = true;
|
static int record_id = 0;
|
||||||
static int record_id = 0;
|
++record_id;
|
||||||
++record_id;
|
memset(&data, 0, sizeof(data));
|
||||||
memset(&data, 0, sizeof(data));
|
data.record_id = record_id;
|
||||||
data.record_id = record_id;
|
data.name = curproc->getVal()->name;
|
||||||
data.name = curproc->getVal()->name;
|
data.pid = curproc->getVal()->pid;
|
||||||
data.pid = curproc->getVal()->pid;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
data.device_name = curproc->getVal()->devicename;
|
data.device_name = curproc->getVal()->devicename;
|
||||||
|
|
||||||
#define NHM_UPDATE_ONE_FIELD(TO,FROM) if((TO)!=(FROM)) { TO = FROM; data_change = true; }
|
#define NHM_UPDATE_ONE_FIELD(TO, FROM) \
|
||||||
|
if ((TO) != (FROM)) { \
|
||||||
|
TO = FROM; \
|
||||||
|
data_change = true; \
|
||||||
|
}
|
||||||
|
|
||||||
NHM_UPDATE_ONE_FIELD( data.uid, uid )
|
NHM_UPDATE_ONE_FIELD(data.uid, uid)
|
||||||
NHM_UPDATE_ONE_FIELD( data.sent_bytes, sent_bytes )
|
NHM_UPDATE_ONE_FIELD(data.sent_bytes, sent_bytes)
|
||||||
NHM_UPDATE_ONE_FIELD( data.recv_bytes, recv_bytes )
|
NHM_UPDATE_ONE_FIELD(data.recv_bytes, recv_bytes)
|
||||||
NHM_UPDATE_ONE_FIELD( data.sent_kbs, sent_kbs )
|
NHM_UPDATE_ONE_FIELD(data.sent_kbs, sent_kbs)
|
||||||
NHM_UPDATE_ONE_FIELD( data.recv_kbs, recv_kbs )
|
NHM_UPDATE_ONE_FIELD(data.recv_kbs, recv_kbs)
|
||||||
|
|
||||||
#undef NHM_UPDATE_ONE_FIELD
|
#undef NHM_UPDATE_ONE_FIELD
|
||||||
|
|
||||||
if( data_change )
|
if (data_change) {
|
||||||
{
|
(*cb)(NETHOGS_APP_ACTION_SET, &data);
|
||||||
(*cb)(NETHOGS_APP_ACTION_SET, &data);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//next
|
// next
|
||||||
previousproc = curproc;
|
previousproc = curproc;
|
||||||
curproc = curproc->next;
|
curproc = curproc->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nethogsmonitor_clean_up()
|
static void nethogsmonitor_clean_up() {
|
||||||
{
|
// clean up
|
||||||
//clean up
|
handle *current_handle = handles;
|
||||||
handle * current_handle = handles;
|
while (current_handle != NULL) {
|
||||||
while (current_handle != NULL)
|
pcap_close(current_handle->content->pcap_handle);
|
||||||
{
|
current_handle = current_handle->next;
|
||||||
pcap_close(current_handle->content->pcap_handle);
|
}
|
||||||
current_handle = current_handle->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
//close file descriptors
|
// close file descriptors
|
||||||
for(std::vector<int>::const_iterator it=pc_loop_fd_list.begin();
|
for (std::vector<int>::const_iterator it = pc_loop_fd_list.begin();
|
||||||
it != pc_loop_fd_list.end(); ++it)
|
it != pc_loop_fd_list.end(); ++it) {
|
||||||
{
|
close(*it);
|
||||||
close(*it);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
procclean();
|
procclean();
|
||||||
}
|
}
|
||||||
|
|
||||||
int nethogsmonitor_loop(NethogsMonitorCallback cb)
|
int nethogsmonitor_loop(NethogsMonitorCallback cb) {
|
||||||
{
|
if (monitor_run_flag) {
|
||||||
if( monitor_run_flag )
|
return NETHOGS_STATUS_FAILURE;
|
||||||
{
|
}
|
||||||
return NETHOGS_STATUS_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int return_value = nethogsmonitor_init();
|
int return_value = nethogsmonitor_init();
|
||||||
if( return_value != NETHOGS_STATUS_OK )
|
if (return_value != NETHOGS_STATUS_OK) {
|
||||||
{
|
return return_value;
|
||||||
return return_value;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
monitor_run_flag = true;
|
monitor_run_flag = true;
|
||||||
|
|
||||||
struct dpargs * userdata = (dpargs *) malloc (sizeof (struct dpargs));
|
struct dpargs *userdata = (dpargs *)malloc(sizeof(struct dpargs));
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
while (monitor_run_flag)
|
while (monitor_run_flag) {
|
||||||
{
|
bool packets_read = false;
|
||||||
bool packets_read = false;
|
|
||||||
|
|
||||||
handle * current_handle = handles;
|
handle *current_handle = handles;
|
||||||
while (current_handle != NULL)
|
while (current_handle != NULL) {
|
||||||
{
|
userdata->device = current_handle->devicename;
|
||||||
userdata->device = current_handle->devicename;
|
userdata->sa_family = AF_UNSPEC;
|
||||||
userdata->sa_family = AF_UNSPEC;
|
int retval = dp_dispatch(current_handle->content, -1, (u_char *)userdata,
|
||||||
int retval = dp_dispatch (current_handle->content, -1, (u_char *)userdata, sizeof (struct dpargs));
|
sizeof(struct dpargs));
|
||||||
if (retval < 0)
|
if (retval < 0) {
|
||||||
{
|
std::cerr << "Error dispatching: " << retval << std::endl;
|
||||||
std::cerr << "Error dispatching: " << retval << std::endl;
|
} else if (retval != 0) {
|
||||||
}
|
packets_read = true;
|
||||||
else if (retval != 0)
|
} else {
|
||||||
{
|
gettimeofday(&curtime, NULL);
|
||||||
packets_read = true;
|
}
|
||||||
}
|
current_handle = current_handle->next;
|
||||||
else
|
}
|
||||||
{
|
|
||||||
gettimeofday(&curtime, NULL);
|
|
||||||
}
|
|
||||||
current_handle = current_handle->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t const now = ::time(NULL);
|
time_t const now = ::time(NULL);
|
||||||
if( monitor_last_refresh_time + monitor_refresh_delay <= now )
|
if (monitor_last_refresh_time + monitor_refresh_delay <= now) {
|
||||||
{
|
monitor_last_refresh_time = now;
|
||||||
monitor_last_refresh_time = now;
|
nethogsmonitor_handle_update(cb);
|
||||||
nethogsmonitor_handle_update(cb);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!packets_read)
|
if (!packets_read) {
|
||||||
{
|
if (!wait_for_next_trigger()) {
|
||||||
if( !wait_for_next_trigger() )
|
break;
|
||||||
{
|
}
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nethogsmonitor_clean_up();
|
nethogsmonitor_clean_up();
|
||||||
|
|
||||||
return NETHOGS_STATUS_OK;
|
return NETHOGS_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nethogsmonitor_breakloop()
|
void nethogsmonitor_breakloop() {
|
||||||
{
|
monitor_run_flag = false;
|
||||||
monitor_run_flag = false;
|
write(self_pipe.second, "x", 1);
|
||||||
write(self_pipe.second, "x", 1);
|
|
||||||
}
|
}
|
||||||
|
|||||||
59
libnethogs.h
59
libnethogs.h
@@ -8,46 +8,51 @@ extern "C" {
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define NETHOGS_DSO_VISIBLE __attribute__ ((visibility ("default")))
|
#define NETHOGS_DSO_VISIBLE __attribute__((visibility("default")))
|
||||||
#define NETHOGS_DSO_HIDDEN __attribute__ ((visibility ("hidden")))
|
#define NETHOGS_DSO_HIDDEN __attribute__((visibility("hidden")))
|
||||||
|
|
||||||
#define NETHOGS_APP_ACTION_SET 1
|
#define NETHOGS_APP_ACTION_SET 1
|
||||||
#define NETHOGS_APP_ACTION_REMOVE 2
|
#define NETHOGS_APP_ACTION_REMOVE 2
|
||||||
|
|
||||||
#define NETHOGS_STATUS_OK 0
|
#define NETHOGS_STATUS_OK 0
|
||||||
#define NETHOGS_STATUS_FAILURE 1 //generic error
|
#define NETHOGS_STATUS_FAILURE 1 // generic error
|
||||||
#define NETHOGS_STATUS_NO_DEVICE 2 //no device foundr
|
#define NETHOGS_STATUS_NO_DEVICE 2 // no device foundr
|
||||||
|
|
||||||
typedef struct NethogsMonitorRecord
|
typedef struct NethogsMonitorRecord {
|
||||||
{
|
int record_id;
|
||||||
int record_id;
|
const char *name;
|
||||||
const char* name;
|
int pid;
|
||||||
int pid;
|
uint32_t uid;
|
||||||
uint32_t uid;
|
const char *device_name;
|
||||||
const char* device_name;
|
uint32_t sent_bytes;
|
||||||
uint32_t sent_bytes;
|
uint32_t recv_bytes;
|
||||||
uint32_t recv_bytes;
|
float sent_kbs;
|
||||||
float sent_kbs;
|
float recv_kbs;
|
||||||
float recv_kbs;
|
|
||||||
} NethogsMonitorRecord;
|
} NethogsMonitorRecord;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Defines a callback to handle updates about applications
|
* @brief Defines a callback to handle updates about applications
|
||||||
* @param action NETHOGS_APP_ACTION_SET if data is beeing added or updated,
|
* @param action NETHOGS_APP_ACTION_SET if data is beeing added or updated,
|
||||||
* NETHOGS_APP_ACTION_REMOVE if data is beeing removed.
|
* NETHOGS_APP_ACTION_REMOVE if data is beeing removed.
|
||||||
* the record_id member is used to uniquely identify the data beeing update or removed.
|
* the record_id member is used to uniquely identify the data beeing
|
||||||
* @param data a pointer to an application usage data. the pointer remains valid until
|
* update or removed.
|
||||||
* the callback is called with NETHOGS_APP_ACTION_REMOVE for the same pointer.
|
* @param data a pointer to an application usage data. the pointer remains valid
|
||||||
* the user should not modify the content of the structure pointed by data.
|
* until
|
||||||
|
* the callback is called with NETHOGS_APP_ACTION_REMOVE for the same
|
||||||
|
* pointer.
|
||||||
|
* the user should not modify the content of the structure pointed by
|
||||||
|
* data.
|
||||||
*/
|
*/
|
||||||
typedef void(*NethogsMonitorCallback)(int action, NethogsMonitorRecord const* data);
|
typedef void (*NethogsMonitorCallback)(int action,
|
||||||
|
NethogsMonitorRecord const *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enter the process monitoring loop and reports updates using the
|
* @brief Enter the process monitoring loop and reports updates using the
|
||||||
* callback provided as parameter.
|
* callback provided as parameter.
|
||||||
* This call will block until nethogsmonitor_breakloop() is called or a failure occurs.
|
* This call will block until nethogsmonitor_breakloop() is called or a failure
|
||||||
* @param cb A pointer to a callback function following the NethogsMonitorCallback definition
|
* occurs.
|
||||||
|
* @param cb A pointer to a callback function following the
|
||||||
|
* NethogsMonitorCallback definition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
NETHOGS_DSO_VISIBLE int nethogsmonitor_loop(NethogsMonitorCallback cb);
|
NETHOGS_DSO_VISIBLE int nethogsmonitor_loop(NethogsMonitorCallback cb);
|
||||||
|
|||||||
477
main.cpp
477
main.cpp
@@ -2,302 +2,277 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
//The self_pipe is used to interrupt the select() in the main loop
|
// The self_pipe is used to interrupt the select() in the main loop
|
||||||
static std::pair<int,int> self_pipe = std::make_pair(-1, -1);
|
static std::pair<int, int> self_pipe = std::make_pair(-1, -1);
|
||||||
static time_t last_refresh_time = 0;
|
static time_t last_refresh_time = 0;
|
||||||
|
|
||||||
//selectable file descriptors for the main loop
|
// selectable file descriptors for the main loop
|
||||||
static fd_set pc_loop_fd_set;
|
static fd_set pc_loop_fd_set;
|
||||||
static std::vector<int> pc_loop_fd_list;
|
static std::vector<int> pc_loop_fd_list;
|
||||||
static bool pc_loop_use_select = true;
|
static bool pc_loop_use_select = true;
|
||||||
|
|
||||||
|
static void versiondisplay(void) { std::cout << version << "\n"; }
|
||||||
|
|
||||||
static void versiondisplay(void)
|
static void help(bool iserror) {
|
||||||
{
|
std::ostream &output = (iserror ? std::cerr : std::cout);
|
||||||
std::cout << version << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
static void help(bool iserror)
|
// output << "usage: nethogs [-V] [-b] [-d seconds] [-t] [-p] [-f (eth|ppp))]
|
||||||
{
|
// [device [device [device ...]]]\n";
|
||||||
std::ostream & output = (iserror ? std::cerr : std::cout);
|
output << "usage: nethogs [-V] [-h] [-b] [-d seconds] [-v mode] [-c count] "
|
||||||
|
"[-t] [-p] [-s] [device [device [device ...]]]\n";
|
||||||
//output << "usage: nethogs [-V] [-b] [-d seconds] [-t] [-p] [-f (eth|ppp))] [device [device [device ...]]]\n";
|
output << " -V : prints version.\n";
|
||||||
output << "usage: nethogs [-V] [-h] [-b] [-d seconds] [-v mode] [-c count] [-t] [-p] [-s] [device [device [device ...]]]\n";
|
output << " -h : prints this help.\n";
|
||||||
output << " -V : prints version.\n";
|
output << " -b : bughunt mode - implies tracemode.\n";
|
||||||
output << " -h : prints this help.\n";
|
output << " -d : delay for update refresh rate in seconds. default "
|
||||||
output << " -b : bughunt mode - implies tracemode.\n";
|
"is 1.\n";
|
||||||
output << " -d : delay for update refresh rate in seconds. default is 1.\n";
|
output << " -v : view mode (0 = KB/s, 1 = total KB, 2 = total B, 3 "
|
||||||
output << " -v : view mode (0 = KB/s, 1 = total KB, 2 = total B, 3 = total MB). default is 0.\n";
|
"= total MB). default is 0.\n";
|
||||||
output << " -c : number of updates. default is 0 (unlimited).\n";
|
output << " -c : number of updates. default is 0 (unlimited).\n";
|
||||||
output << " -t : tracemode.\n";
|
output << " -t : tracemode.\n";
|
||||||
//output << " -f : format of packets on interface, default is eth.\n";
|
// output << " -f : format of packets on interface, default is
|
||||||
output << " -p : sniff in promiscious mode (not recommended).\n";
|
// eth.\n";
|
||||||
output << " -s : sort output by sent column.\n";
|
output << " -p : sniff in promiscious mode (not recommended).\n";
|
||||||
|
output << " -s : sort output by sent column.\n";
|
||||||
output << " -a : monitor all devices, even loopback/stopped ones.\n";
|
output << " -a : monitor all devices, even loopback/stopped ones.\n";
|
||||||
output << " device : device(s) to monitor. default is all interfaces up and running excluding loopback\n";
|
output << " device : device(s) to monitor. default is all "
|
||||||
output << std::endl;
|
"interfaces up and running excluding loopback\n";
|
||||||
output << "When nethogs is running, press:\n";
|
output << std::endl;
|
||||||
output << " q: quit\n";
|
output << "When nethogs is running, press:\n";
|
||||||
output << " s: sort by SENT traffic\n";
|
output << " q: quit\n";
|
||||||
output << " r: sort by RECEIVE traffic\n";
|
output << " s: sort by SENT traffic\n";
|
||||||
output << " m: switch between total (KB, B, MB) and KB/s mode\n";
|
output << " r: sort by RECEIVE traffic\n";
|
||||||
|
output << " m: switch between total (KB, B, MB) and KB/s mode\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void quit_cb(int /* i */) {
|
||||||
void quit_cb (int /* i */)
|
if (self_pipe.second != -1) {
|
||||||
{
|
write(self_pipe.second, "x", 1);
|
||||||
if( self_pipe.second != -1 )
|
} else {
|
||||||
{
|
exit(0);
|
||||||
write(self_pipe.second, "x", 1);
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void forceExit(bool success, const char *msg, ...)
|
void forceExit(bool success, const char *msg, ...) {
|
||||||
{
|
if ((!tracemode) && (!DEBUG)) {
|
||||||
if ((!tracemode)&&(!DEBUG)){
|
exit_ui();
|
||||||
exit_ui();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
va_list argp;
|
va_list argp;
|
||||||
va_start(argp, msg);
|
va_start(argp, msg);
|
||||||
vfprintf(stderr, msg, argp);
|
vfprintf(stderr, msg, argp);
|
||||||
va_end(argp);
|
va_end(argp);
|
||||||
std::cerr << std::endl;
|
std::cerr << std::endl;
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
else
|
else
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<int, int> create_self_pipe()
|
std::pair<int, int> create_self_pipe() {
|
||||||
{
|
int pfd[2];
|
||||||
int pfd[2];
|
if (pipe(pfd) == -1)
|
||||||
if (pipe(pfd) == -1)
|
return std::make_pair(-1, -1);
|
||||||
return std::make_pair(-1, -1);
|
|
||||||
|
|
||||||
if (fcntl(pfd[0], F_SETFL, fcntl(pfd[0], F_GETFL) | O_NONBLOCK) == -1)
|
if (fcntl(pfd[0], F_SETFL, fcntl(pfd[0], F_GETFL) | O_NONBLOCK) == -1)
|
||||||
return std::make_pair(-1, -1);
|
return std::make_pair(-1, -1);
|
||||||
|
|
||||||
if (fcntl(pfd[1], F_SETFL, fcntl(pfd[1], F_GETFL) | O_NONBLOCK) == -1)
|
if (fcntl(pfd[1], F_SETFL, fcntl(pfd[1], F_GETFL) | O_NONBLOCK) == -1)
|
||||||
return std::make_pair(-1, -1);
|
return std::make_pair(-1, -1);
|
||||||
|
|
||||||
return std::make_pair(pfd[0], pfd[1]);
|
return std::make_pair(pfd[0], pfd[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wait_for_next_trigger()
|
bool wait_for_next_trigger() {
|
||||||
{
|
if (pc_loop_use_select) {
|
||||||
if( pc_loop_use_select )
|
FD_ZERO(&pc_loop_fd_set);
|
||||||
{
|
int nfds = 0;
|
||||||
FD_ZERO(&pc_loop_fd_set);
|
for (std::vector<int>::const_iterator it = pc_loop_fd_list.begin();
|
||||||
int nfds = 0;
|
it != pc_loop_fd_list.end(); ++it) {
|
||||||
for(std::vector<int>::const_iterator it=pc_loop_fd_list.begin();
|
int const fd = *it;
|
||||||
it != pc_loop_fd_list.end(); ++it)
|
nfds = std::max(nfds, *it + 1);
|
||||||
{
|
FD_SET(fd, &pc_loop_fd_set);
|
||||||
int const fd = *it;
|
}
|
||||||
nfds = std::max(nfds, *it + 1);
|
timeval timeout = {refreshdelay, 0};
|
||||||
FD_SET(fd, &pc_loop_fd_set);
|
if (select(nfds, &pc_loop_fd_set, 0, 0, &timeout) != -1) {
|
||||||
}
|
if (FD_ISSET(self_pipe.first, &pc_loop_fd_set)) {
|
||||||
timeval timeout = {refreshdelay, 0};
|
return false;
|
||||||
if( select(nfds, &pc_loop_fd_set, 0, 0, &timeout) != -1 )
|
}
|
||||||
{
|
}
|
||||||
if( FD_ISSET(self_pipe.first, &pc_loop_fd_set) )
|
} else {
|
||||||
{
|
// If select() not possible, pause to prevent 100%
|
||||||
return false;
|
usleep(1000);
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If select() not possible, pause to prevent 100%
|
|
||||||
usleep(1000);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clean_up() {
|
||||||
|
// close file descriptors
|
||||||
|
for (std::vector<int>::const_iterator it = pc_loop_fd_list.begin();
|
||||||
|
it != pc_loop_fd_list.end(); ++it) {
|
||||||
|
close(*it);
|
||||||
|
}
|
||||||
|
|
||||||
void clean_up()
|
procclean();
|
||||||
{
|
if ((!tracemode) && (!DEBUG))
|
||||||
//close file descriptors
|
exit_ui();
|
||||||
for(std::vector<int>::const_iterator it=pc_loop_fd_list.begin();
|
|
||||||
it != pc_loop_fd_list.end(); ++it)
|
|
||||||
{
|
|
||||||
close(*it);
|
|
||||||
}
|
|
||||||
|
|
||||||
procclean();
|
|
||||||
if ((!tracemode) && (!DEBUG))
|
|
||||||
exit_ui();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main (int argc, char** argv)
|
int main(int argc, char **argv) {
|
||||||
{
|
process_init();
|
||||||
process_init();
|
|
||||||
|
|
||||||
int promisc = 0;
|
int promisc = 0;
|
||||||
bool all = false;
|
bool all = false;
|
||||||
|
|
||||||
int opt;
|
int opt;
|
||||||
while ((opt = getopt(argc, argv, "Vahbtpd:v:c:sa")) != -1) {
|
while ((opt = getopt(argc, argv, "Vahbtpd:v:c:sa")) != -1) {
|
||||||
switch(opt) {
|
switch (opt) {
|
||||||
case 'V':
|
case 'V':
|
||||||
versiondisplay();
|
versiondisplay();
|
||||||
exit(0);
|
exit(0);
|
||||||
case 'h':
|
case 'h':
|
||||||
help(false);
|
help(false);
|
||||||
exit(0);
|
exit(0);
|
||||||
case 'b':
|
case 'b':
|
||||||
bughuntmode = true;
|
bughuntmode = true;
|
||||||
tracemode = true;
|
tracemode = true;
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
tracemode = true;
|
tracemode = true;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
promisc = 1;
|
promisc = 1;
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
sortRecv = false;
|
sortRecv = false;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
refreshdelay = atoi(optarg);
|
refreshdelay = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
viewMode = atoi(optarg) % VIEWMODE_COUNT;
|
viewMode = atoi(optarg) % VIEWMODE_COUNT;
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
refreshlimit = atoi(optarg);
|
refreshlimit = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
all = true;
|
all = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
help(true);
|
help(true);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
device * devices = get_devices(argc - optind, argv + optind, all);
|
device *devices = get_devices(argc - optind, argv + optind, all);
|
||||||
if (devices == NULL)
|
if (devices == NULL)
|
||||||
forceExit(false, "No devices to monitor. Use '-a' to allow monitoring loopback interfaces or devices that are not up/running");
|
forceExit(false, "No devices to monitor. Use '-a' to allow monitoring "
|
||||||
|
"loopback interfaces or devices that are not up/running");
|
||||||
|
|
||||||
if ((!tracemode) && (!DEBUG)){
|
if ((!tracemode) && (!DEBUG)) {
|
||||||
init_ui();
|
init_ui();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NEEDROOT && (geteuid() != 0))
|
if (NEEDROOT && (geteuid() != 0))
|
||||||
forceExit(false, "You need to be root to run NetHogs!");
|
forceExit(false, "You need to be root to run NetHogs!");
|
||||||
|
|
||||||
//use the Self-Pipe trick to interrupt the select() in the main loop
|
// use the Self-Pipe trick to interrupt the select() in the main loop
|
||||||
self_pipe = create_self_pipe();
|
self_pipe = create_self_pipe();
|
||||||
if( self_pipe.first == -1 || self_pipe.second == -1 )
|
if (self_pipe.first == -1 || self_pipe.second == -1) {
|
||||||
{
|
forceExit(false, "Error creating pipe file descriptors\n");
|
||||||
forceExit(false, "Error creating pipe file descriptors\n");
|
} else {
|
||||||
}
|
// add the self-pipe to allow interrupting select()
|
||||||
else
|
pc_loop_fd_list.push_back(self_pipe.first);
|
||||||
{
|
}
|
||||||
//add the self-pipe to allow interrupting select()
|
|
||||||
pc_loop_fd_list.push_back(self_pipe.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
char errbuf[PCAP_ERRBUF_SIZE];
|
char errbuf[PCAP_ERRBUF_SIZE];
|
||||||
|
|
||||||
handle * handles = NULL;
|
handle *handles = NULL;
|
||||||
device * current_dev = devices;
|
device *current_dev = devices;
|
||||||
while (current_dev != NULL) {
|
while (current_dev != NULL) {
|
||||||
|
|
||||||
if( !getLocal(current_dev->name, tracemode) )
|
if (!getLocal(current_dev->name, tracemode)) {
|
||||||
{
|
forceExit(false, "getifaddrs failed while establishing local IP.");
|
||||||
forceExit(false, "getifaddrs failed while establishing local IP.");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
dp_handle * newhandle = dp_open_live(current_dev->name, BUFSIZ, promisc, 100, errbuf);
|
dp_handle *newhandle =
|
||||||
if (newhandle != NULL)
|
dp_open_live(current_dev->name, BUFSIZ, promisc, 100, errbuf);
|
||||||
{
|
if (newhandle != NULL) {
|
||||||
dp_addcb (newhandle, dp_packet_ip, process_ip);
|
dp_addcb(newhandle, dp_packet_ip, process_ip);
|
||||||
dp_addcb (newhandle, dp_packet_ip6, process_ip6);
|
dp_addcb(newhandle, dp_packet_ip6, process_ip6);
|
||||||
dp_addcb (newhandle, dp_packet_tcp, process_tcp);
|
dp_addcb(newhandle, dp_packet_tcp, process_tcp);
|
||||||
dp_addcb (newhandle, dp_packet_udp, process_udp);
|
dp_addcb(newhandle, dp_packet_udp, process_udp);
|
||||||
|
|
||||||
/* The following code solves sf.net bug 1019381, but is only available
|
/* The following code solves sf.net bug 1019381, but is only available
|
||||||
* in newer versions (from 0.8 it seems) of libpcap
|
* in newer versions (from 0.8 it seems) of libpcap
|
||||||
*
|
*
|
||||||
* update: version 0.7.2, which is in debian stable now, should be ok
|
* update: version 0.7.2, which is in debian stable now, should be ok
|
||||||
* also.
|
* also.
|
||||||
*/
|
*/
|
||||||
if (dp_setnonblock (newhandle, 1, errbuf) == -1)
|
if (dp_setnonblock(newhandle, 1, errbuf) == -1) {
|
||||||
{
|
fprintf(stderr, "Error putting libpcap in nonblocking mode\n");
|
||||||
fprintf(stderr, "Error putting libpcap in nonblocking mode\n");
|
}
|
||||||
}
|
handles = new handle(newhandle, current_dev->name, handles);
|
||||||
handles = new handle (newhandle, current_dev->name, handles);
|
|
||||||
|
|
||||||
if( pc_loop_use_select )
|
if (pc_loop_use_select) {
|
||||||
{
|
// some devices may not support pcap_get_selectable_fd
|
||||||
//some devices may not support pcap_get_selectable_fd
|
int const fd = pcap_get_selectable_fd(newhandle->pcap_handle);
|
||||||
int const fd = pcap_get_selectable_fd(newhandle->pcap_handle);
|
if (fd != -1) {
|
||||||
if( fd != -1 )
|
pc_loop_fd_list.push_back(fd);
|
||||||
{
|
} else {
|
||||||
pc_loop_fd_list.push_back(fd);
|
pc_loop_use_select = false;
|
||||||
}
|
pc_loop_fd_list.clear();
|
||||||
else
|
fprintf(stderr, "failed to get selectable_fd for %s\n",
|
||||||
{
|
current_dev->name);
|
||||||
pc_loop_use_select = false;
|
}
|
||||||
pc_loop_fd_list.clear();
|
}
|
||||||
fprintf(stderr, "failed to get selectable_fd for %s\n", current_dev->name);
|
} else {
|
||||||
}
|
fprintf(stderr, "Error opening handler for device %s\n",
|
||||||
}
|
current_dev->name);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Error opening handler for device %s\n", current_dev->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
current_dev = current_dev->next;
|
current_dev = current_dev->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
signal (SIGINT, &quit_cb);
|
signal(SIGINT, &quit_cb);
|
||||||
|
|
||||||
fprintf(stderr, "Waiting for first packet to arrive (see sourceforge.net bug 1019381)\n");
|
fprintf(
|
||||||
struct dpargs * userdata = (dpargs *) malloc (sizeof (struct dpargs));
|
stderr,
|
||||||
|
"Waiting for first packet to arrive (see sourceforge.net bug 1019381)\n");
|
||||||
|
struct dpargs *userdata = (dpargs *)malloc(sizeof(struct dpargs));
|
||||||
|
|
||||||
// Main loop:
|
// Main loop:
|
||||||
while (1)
|
while (1) {
|
||||||
{
|
bool packets_read = false;
|
||||||
bool packets_read = false;
|
|
||||||
|
|
||||||
for (handle * current_handle = handles; current_handle != NULL; current_handle = current_handle->next)
|
for (handle *current_handle = handles; current_handle != NULL;
|
||||||
{
|
current_handle = current_handle->next) {
|
||||||
userdata->device = current_handle->devicename;
|
userdata->device = current_handle->devicename;
|
||||||
userdata->sa_family = AF_UNSPEC;
|
userdata->sa_family = AF_UNSPEC;
|
||||||
int retval = dp_dispatch (current_handle->content, -1, (u_char *)userdata, sizeof (struct dpargs));
|
int retval = dp_dispatch(current_handle->content, -1, (u_char *)userdata,
|
||||||
if (retval < 0)
|
sizeof(struct dpargs));
|
||||||
std::cerr << "Error dispatching: " << retval << std::endl;
|
if (retval < 0)
|
||||||
else if (retval != 0)
|
std::cerr << "Error dispatching: " << retval << std::endl;
|
||||||
packets_read = true;
|
else if (retval != 0)
|
||||||
}
|
packets_read = true;
|
||||||
|
}
|
||||||
|
|
||||||
time_t const now = ::time(NULL);
|
time_t const now = ::time(NULL);
|
||||||
if( last_refresh_time + refreshdelay <= now )
|
if (last_refresh_time + refreshdelay <= now) {
|
||||||
{
|
last_refresh_time = now;
|
||||||
last_refresh_time = now;
|
if ((!DEBUG) && (!tracemode)) {
|
||||||
if ((!DEBUG)&&(!tracemode))
|
// handle user input
|
||||||
{
|
ui_tick();
|
||||||
// handle user input
|
}
|
||||||
ui_tick();
|
do_refresh();
|
||||||
}
|
}
|
||||||
do_refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
// if not packets, do a select() until next packet
|
// if not packets, do a select() until next packet
|
||||||
if (!packets_read)
|
if (!packets_read)
|
||||||
if( !wait_for_next_trigger() )
|
if (!wait_for_next_trigger())
|
||||||
// Shutdown requested - exit the loop
|
// Shutdown requested - exit the loop
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
clean_up();
|
clean_up();
|
||||||
}
|
}
|
||||||
|
|||||||
313
nethogs.cpp
313
nethogs.cpp
@@ -15,7 +15,8 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@
|
|||||||
#include "cui.h"
|
#include "cui.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "decpcap.h"
|
#include "decpcap.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
@@ -48,7 +49,7 @@ extern "C" {
|
|||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "devices.h"
|
#include "devices.h"
|
||||||
|
|
||||||
extern Process * unknownudp;
|
extern Process *unknownudp;
|
||||||
|
|
||||||
unsigned refreshdelay = 1;
|
unsigned refreshdelay = 1;
|
||||||
unsigned refreshlimit = 0;
|
unsigned refreshlimit = 0;
|
||||||
@@ -64,178 +65,184 @@ const char version[] = " version " VERSION "." SUBVERSION "." MINORVERSION;
|
|||||||
|
|
||||||
timeval curtime;
|
timeval curtime;
|
||||||
|
|
||||||
bool local_addr::contains (const in_addr_t & n_addr) {
|
bool local_addr::contains(const in_addr_t &n_addr) {
|
||||||
if ((sa_family == AF_INET)
|
if ((sa_family == AF_INET) && (n_addr == addr))
|
||||||
&& (n_addr == addr))
|
return true;
|
||||||
return true;
|
if (next == NULL)
|
||||||
if (next == NULL)
|
return false;
|
||||||
return false;
|
return next->contains(n_addr);
|
||||||
return next->contains(n_addr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool local_addr::contains(const struct in6_addr & n_addr) {
|
bool local_addr::contains(const struct in6_addr &n_addr) {
|
||||||
if (sa_family == AF_INET6)
|
if (sa_family == AF_INET6) {
|
||||||
{
|
/*
|
||||||
/*
|
if (DEBUG) {
|
||||||
if (DEBUG) {
|
char addy [50];
|
||||||
char addy [50];
|
std::cerr << "Comparing: ";
|
||||||
std::cerr << "Comparing: ";
|
inet_ntop (AF_INET6, &n_addr, addy, 49);
|
||||||
inet_ntop (AF_INET6, &n_addr, addy, 49);
|
std::cerr << addy << " and ";
|
||||||
std::cerr << addy << " and ";
|
inet_ntop (AF_INET6, &addr6, addy, 49);
|
||||||
inet_ntop (AF_INET6, &addr6, addy, 49);
|
std::cerr << addy << std::endl;
|
||||||
std::cerr << addy << std::endl;
|
}
|
||||||
}
|
*/
|
||||||
*/
|
// if (addr6.s6_addr == n_addr.s6_addr)
|
||||||
//if (addr6.s6_addr == n_addr.s6_addr)
|
if (memcmp(&addr6, &n_addr, sizeof(struct in6_addr)) == 0) {
|
||||||
if (memcmp (&addr6, &n_addr, sizeof(struct in6_addr)) == 0)
|
if (DEBUG)
|
||||||
{
|
std::cerr << "Match!" << std::endl;
|
||||||
if (DEBUG)
|
return true;
|
||||||
std::cerr << "Match!" << std::endl;
|
}
|
||||||
return true;
|
}
|
||||||
}
|
if (next == NULL)
|
||||||
}
|
return false;
|
||||||
if (next == NULL)
|
return next->contains(n_addr);
|
||||||
return false;
|
|
||||||
return next->contains(n_addr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dpargs {
|
struct dpargs {
|
||||||
const char * device;
|
const char *device;
|
||||||
int sa_family;
|
int sa_family;
|
||||||
in_addr ip_src;
|
in_addr ip_src;
|
||||||
in_addr ip_dst;
|
in_addr ip_dst;
|
||||||
in6_addr ip6_src;
|
in6_addr ip6_src;
|
||||||
in6_addr ip6_dst;
|
in6_addr ip6_dst;
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* getVersion()
|
const char *getVersion() { return version; }
|
||||||
{
|
|
||||||
return version;
|
int process_tcp(u_char *userdata, const dp_header *header,
|
||||||
|
const u_char *m_packet) {
|
||||||
|
struct dpargs *args = (struct dpargs *)userdata;
|
||||||
|
struct tcphdr *tcp = (struct tcphdr *)m_packet;
|
||||||
|
|
||||||
|
curtime = header->ts;
|
||||||
|
|
||||||
|
/* get info from userdata, then call getPacket */
|
||||||
|
Packet *packet;
|
||||||
|
switch (args->sa_family) {
|
||||||
|
case AF_INET:
|
||||||
|
#ifdef __APPLE__
|
||||||
|
packet = new Packet(args->ip_src, ntohs(tcp->th_sport), args->ip_dst,
|
||||||
|
ntohs(tcp->th_dport), header->len, header->ts);
|
||||||
|
#else
|
||||||
|
packet = new Packet(args->ip_src, ntohs(tcp->source), args->ip_dst,
|
||||||
|
ntohs(tcp->dest), header->len, header->ts);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
#ifdef __APPLE__
|
||||||
|
packet = new Packet(args->ip6_src, ntohs(tcp->th_sport), args->ip6_dst,
|
||||||
|
ntohs(tcp->th_dport), header->len, header->ts);
|
||||||
|
#else
|
||||||
|
packet = new Packet(args->ip6_src, ntohs(tcp->source), args->ip6_dst,
|
||||||
|
ntohs(tcp->dest), header->len, header->ts);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
std::cerr << "Invalid address family for TCP packet: " << args->sa_family
|
||||||
|
<< std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection *connection = findConnection(packet);
|
||||||
|
|
||||||
|
if (connection != NULL) {
|
||||||
|
/* add packet to the connection */
|
||||||
|
connection->add(packet);
|
||||||
|
} else {
|
||||||
|
/* else: unknown connection, create new */
|
||||||
|
connection = new Connection(packet);
|
||||||
|
getProcess(connection, args->device);
|
||||||
|
}
|
||||||
|
delete packet;
|
||||||
|
|
||||||
|
/* we're done now. */
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int process_tcp (u_char * userdata, const dp_header * header, const u_char * m_packet) {
|
int process_udp(u_char *userdata, const dp_header *header,
|
||||||
struct dpargs * args = (struct dpargs *) userdata;
|
const u_char *m_packet) {
|
||||||
struct tcphdr * tcp = (struct tcphdr *) m_packet;
|
struct dpargs *args = (struct dpargs *)userdata;
|
||||||
|
struct udphdr *udp = (struct udphdr *)m_packet;
|
||||||
|
|
||||||
curtime = header->ts;
|
curtime = header->ts;
|
||||||
|
|
||||||
/* get info from userdata, then call getPacket */
|
Packet *packet;
|
||||||
Packet * packet;
|
switch (args->sa_family) {
|
||||||
switch (args->sa_family)
|
case AF_INET:
|
||||||
{
|
#ifdef __APPLE__
|
||||||
case AF_INET:
|
packet = new Packet(args->ip_src, ntohs(udp->uh_sport), args->ip_dst,
|
||||||
#ifdef __APPLE__
|
ntohs(udp->uh_dport), header->len, header->ts);
|
||||||
packet = new Packet (args->ip_src, ntohs(tcp->th_sport), args->ip_dst, ntohs(tcp->th_dport), header->len, header->ts);
|
#else
|
||||||
#else
|
packet = new Packet(args->ip_src, ntohs(udp->source), args->ip_dst,
|
||||||
packet = new Packet (args->ip_src, ntohs(tcp->source), args->ip_dst, ntohs(tcp->dest), header->len, header->ts);
|
ntohs(udp->dest), header->len, header->ts);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
packet = new Packet (args->ip6_src, ntohs(tcp->th_sport), args->ip6_dst, ntohs(tcp->th_dport), header->len, header->ts);
|
packet = new Packet(args->ip6_src, ntohs(udp->uh_sport), args->ip6_dst,
|
||||||
#else
|
ntohs(udp->uh_dport), header->len, header->ts);
|
||||||
packet = new Packet (args->ip6_src, ntohs(tcp->source), args->ip6_dst, ntohs(tcp->dest), header->len, header->ts);
|
#else
|
||||||
#endif
|
packet = new Packet(args->ip6_src, ntohs(udp->source), args->ip6_dst,
|
||||||
break;
|
ntohs(udp->dest), header->len, header->ts);
|
||||||
default:
|
#endif
|
||||||
std::cerr << "Invalid address family for TCP packet: " << args->sa_family << std::endl;
|
break;
|
||||||
return true;
|
default:
|
||||||
}
|
std::cerr << "Invalid address family for UDP packet: " << args->sa_family
|
||||||
|
<< std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Connection * connection = findConnection(packet);
|
// if (DEBUG)
|
||||||
|
// std::cout << "Got packet from " << packet->gethashstring() << std::endl;
|
||||||
|
|
||||||
if (connection != NULL)
|
Connection *connection = findConnection(packet);
|
||||||
{
|
|
||||||
/* add packet to the connection */
|
|
||||||
connection->add(packet);
|
|
||||||
} else {
|
|
||||||
/* else: unknown connection, create new */
|
|
||||||
connection = new Connection (packet);
|
|
||||||
getProcess(connection, args->device);
|
|
||||||
}
|
|
||||||
delete packet;
|
|
||||||
|
|
||||||
/* we're done now. */
|
if (connection != NULL) {
|
||||||
return true;
|
/* add packet to the connection */
|
||||||
|
connection->add(packet);
|
||||||
|
} else {
|
||||||
|
/* else: unknown connection, create new */
|
||||||
|
connection = new Connection(packet);
|
||||||
|
getProcess(connection, args->device);
|
||||||
|
}
|
||||||
|
delete packet;
|
||||||
|
|
||||||
|
/* we're done now. */
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int process_udp (u_char * userdata, const dp_header * header, const u_char * m_packet) {
|
int process_ip(u_char *userdata, const dp_header * /* header */,
|
||||||
struct dpargs * args = (struct dpargs *) userdata;
|
const u_char *m_packet) {
|
||||||
struct udphdr * udp = (struct udphdr *) m_packet;
|
struct dpargs *args = (struct dpargs *)userdata;
|
||||||
|
struct ip *ip = (struct ip *)m_packet;
|
||||||
|
args->sa_family = AF_INET;
|
||||||
|
args->ip_src = ip->ip_src;
|
||||||
|
args->ip_dst = ip->ip_dst;
|
||||||
|
|
||||||
curtime = header->ts;
|
/* we're not done yet - also parse tcp :) */
|
||||||
|
return false;
|
||||||
Packet * packet;
|
|
||||||
switch (args->sa_family)
|
|
||||||
{
|
|
||||||
case AF_INET:
|
|
||||||
#ifdef __APPLE__
|
|
||||||
packet = new Packet (args->ip_src, ntohs(udp->uh_sport), args->ip_dst, ntohs(udp->uh_dport), header->len, header->ts);
|
|
||||||
#else
|
|
||||||
packet = new Packet (args->ip_src, ntohs(udp->source), args->ip_dst, ntohs(udp->dest), header->len, header->ts);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case AF_INET6:
|
|
||||||
#ifdef __APPLE__
|
|
||||||
packet = new Packet (args->ip6_src, ntohs(udp->uh_sport), args->ip6_dst, ntohs(udp->uh_dport), header->len, header->ts);
|
|
||||||
#else
|
|
||||||
packet = new Packet (args->ip6_src, ntohs(udp->source), args->ip6_dst, ntohs(udp->dest), header->len, header->ts);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
std::cerr << "Invalid address family for UDP packet: " << args->sa_family << std::endl;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if (DEBUG)
|
|
||||||
// std::cout << "Got packet from " << packet->gethashstring() << std::endl;
|
|
||||||
|
|
||||||
Connection * connection = findConnection(packet);
|
|
||||||
|
|
||||||
if (connection != NULL)
|
|
||||||
{
|
|
||||||
/* add packet to the connection */
|
|
||||||
connection->add(packet);
|
|
||||||
} else {
|
|
||||||
/* else: unknown connection, create new */
|
|
||||||
connection = new Connection (packet);
|
|
||||||
getProcess(connection, args->device);
|
|
||||||
}
|
|
||||||
delete packet;
|
|
||||||
|
|
||||||
/* we're done now. */
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int process_ip (u_char * userdata, const dp_header * /* header */, const u_char * m_packet) {
|
int process_ip6(u_char *userdata, const dp_header * /* header */,
|
||||||
struct dpargs * args = (struct dpargs *) userdata;
|
const u_char *m_packet) {
|
||||||
struct ip * ip = (struct ip *) m_packet;
|
struct dpargs *args = (struct dpargs *)userdata;
|
||||||
args->sa_family = AF_INET;
|
const struct ip6_hdr *ip6 = (struct ip6_hdr *)m_packet;
|
||||||
args->ip_src = ip->ip_src;
|
args->sa_family = AF_INET6;
|
||||||
args->ip_dst = ip->ip_dst;
|
args->ip6_src = ip6->ip6_src;
|
||||||
|
args->ip6_dst = ip6->ip6_dst;
|
||||||
|
|
||||||
/* we're not done yet - also parse tcp :) */
|
/* we're not done yet - also parse tcp :) */
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
int process_ip6 (u_char * userdata, const dp_header * /* header */, const u_char * m_packet) {
|
|
||||||
struct dpargs * args = (struct dpargs *) userdata;
|
|
||||||
const struct ip6_hdr * ip6 = (struct ip6_hdr *) m_packet;
|
|
||||||
args->sa_family = AF_INET6;
|
|
||||||
args->ip6_src = ip6->ip6_src;
|
|
||||||
args->ip6_dst = ip6->ip6_dst;
|
|
||||||
|
|
||||||
/* we're not done yet - also parse tcp :) */
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class handle {
|
class handle {
|
||||||
public:
|
public:
|
||||||
handle (dp_handle * m_handle, const char * m_devicename = NULL,
|
handle(dp_handle *m_handle, const char *m_devicename = NULL,
|
||||||
handle * m_next = NULL) {
|
handle *m_next = NULL) {
|
||||||
content = m_handle; next = m_next; devicename = m_devicename;
|
content = m_handle;
|
||||||
}
|
next = m_next;
|
||||||
dp_handle * content;
|
devicename = m_devicename;
|
||||||
const char * devicename;
|
}
|
||||||
handle * next;
|
dp_handle *content;
|
||||||
|
const char *devicename;
|
||||||
|
handle *next;
|
||||||
};
|
};
|
||||||
|
|||||||
70
nethogs.h
70
nethogs.h
@@ -15,11 +15,11 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef __NETHOGS_H
|
#ifndef __NETHOGS_H
|
||||||
#define __NETHOGS_H
|
#define __NETHOGS_H
|
||||||
|
|
||||||
@@ -30,9 +30,9 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <sys/malloc.h>
|
#include <sys/malloc.h>
|
||||||
#else
|
#else
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#endif
|
#endif
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@@ -68,50 +68,48 @@
|
|||||||
#define PROGNAME_WIDTH 512
|
#define PROGNAME_WIDTH 512
|
||||||
|
|
||||||
// viewMode: how to represent numbers
|
// viewMode: how to represent numbers
|
||||||
#define VIEWMODE_KBPS 0
|
#define VIEWMODE_KBPS 0
|
||||||
#define VIEWMODE_TOTAL_KB 1
|
#define VIEWMODE_TOTAL_KB 1
|
||||||
#define VIEWMODE_TOTAL_B 2
|
#define VIEWMODE_TOTAL_B 2
|
||||||
#define VIEWMODE_TOTAL_MB 3
|
#define VIEWMODE_TOTAL_MB 3
|
||||||
#define VIEWMODE_COUNT 4
|
#define VIEWMODE_COUNT 4
|
||||||
|
|
||||||
#define NORETURN __attribute__ ((__noreturn__))
|
#define NORETURN __attribute__((__noreturn__))
|
||||||
|
|
||||||
void forceExit(bool success, const char *msg, ...) NORETURN;
|
void forceExit(bool success, const char *msg, ...) NORETURN;
|
||||||
|
|
||||||
class local_addr {
|
class local_addr {
|
||||||
public:
|
public:
|
||||||
/* ipv4 constructor takes an in_addr_t */
|
/* ipv4 constructor takes an in_addr_t */
|
||||||
local_addr (in_addr_t m_addr, local_addr * m_next = NULL)
|
local_addr(in_addr_t m_addr, local_addr *m_next = NULL) {
|
||||||
{
|
addr = m_addr;
|
||||||
addr = m_addr;
|
next = m_next;
|
||||||
next = m_next;
|
sa_family = AF_INET;
|
||||||
sa_family = AF_INET;
|
string = (char *)malloc(16);
|
||||||
string = (char*) malloc (16);
|
inet_ntop(AF_INET, &m_addr, string, 15);
|
||||||
inet_ntop (AF_INET, &m_addr, string, 15);
|
}
|
||||||
}
|
/* this constructor takes an char address[33] */
|
||||||
/* this constructor takes an char address[33] */
|
local_addr(struct in6_addr *m_addr, local_addr *m_next = NULL) {
|
||||||
local_addr (struct in6_addr *m_addr, local_addr * m_next = NULL)
|
addr6 = *m_addr;
|
||||||
{
|
next = m_next;
|
||||||
addr6 = *m_addr;
|
sa_family = AF_INET6;
|
||||||
next = m_next;
|
string = (char *)malloc(64);
|
||||||
sa_family = AF_INET6;
|
inet_ntop(AF_INET6, &m_addr, string, 63);
|
||||||
string = (char*) malloc (64);
|
}
|
||||||
inet_ntop (AF_INET6, &m_addr, string, 63);
|
|
||||||
}
|
bool contains(const in_addr_t &n_addr);
|
||||||
|
bool contains(const struct in6_addr &n_addr);
|
||||||
|
char *string;
|
||||||
|
local_addr *next;
|
||||||
|
|
||||||
bool contains (const in_addr_t & n_addr);
|
|
||||||
bool contains (const struct in6_addr & n_addr);
|
|
||||||
char * string;
|
|
||||||
local_addr * next;
|
|
||||||
private:
|
private:
|
||||||
|
in_addr_t addr;
|
||||||
in_addr_t addr;
|
struct in6_addr addr6;
|
||||||
struct in6_addr addr6;
|
short int sa_family;
|
||||||
short int sa_family;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void quit_cb (int i);
|
void quit_cb(int i);
|
||||||
|
|
||||||
const char* getVersion();
|
const char *getVersion();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
356
packet.cpp
356
packet.cpp
@@ -15,20 +15,20 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "nethogs.h"
|
#include "nethogs.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <sys/malloc.h>
|
#include <sys/malloc.h>
|
||||||
#else
|
#else
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#endif
|
#endif
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
#include <ifaddrs.h>
|
#include <ifaddrs.h>
|
||||||
// #include "inet6.c"
|
// #include "inet6.c"
|
||||||
|
|
||||||
local_addr * local_addrs = NULL;
|
local_addr *local_addrs = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* getLocal
|
* getLocal
|
||||||
@@ -48,40 +48,39 @@ local_addr * local_addrs = NULL;
|
|||||||
* uses getifaddrs to get addresses of this device, and adds them to the
|
* uses getifaddrs to get addresses of this device, and adds them to the
|
||||||
* local_addrs-list.
|
* local_addrs-list.
|
||||||
*/
|
*/
|
||||||
bool getLocal (const char *device, bool tracemode)
|
bool getLocal(const char *device, bool tracemode) {
|
||||||
{
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
struct ifaddrs *ifaddr, *ifa;
|
if (getifaddrs(&ifaddr) == -1) {
|
||||||
if(getifaddrs(&ifaddr) == -1) {
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
|
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
|
||||||
if(ifa->ifa_addr == NULL)
|
if (ifa->ifa_addr == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(strcmp(ifa->ifa_name, device) != 0)
|
if (strcmp(ifa->ifa_name, device) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int family = ifa->ifa_addr->sa_family;
|
int family = ifa->ifa_addr->sa_family;
|
||||||
|
|
||||||
if(family == AF_INET){
|
if (family == AF_INET) {
|
||||||
struct sockaddr_in *addr = (struct sockaddr_in*)ifa->ifa_addr;
|
struct sockaddr_in *addr = (struct sockaddr_in *)ifa->ifa_addr;
|
||||||
local_addrs = new local_addr(addr->sin_addr.s_addr, local_addrs);
|
local_addrs = new local_addr(addr->sin_addr.s_addr, local_addrs);
|
||||||
|
|
||||||
if (tracemode || DEBUG) {
|
if (tracemode || DEBUG) {
|
||||||
printf("Adding local address: %s\n", inet_ntoa(addr->sin_addr));
|
printf("Adding local address: %s\n", inet_ntoa(addr->sin_addr));
|
||||||
}
|
}
|
||||||
}else if(family == AF_INET6){
|
} else if (family == AF_INET6) {
|
||||||
struct sockaddr_in6 *addr = (struct sockaddr_in6*)ifa->ifa_addr;
|
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)ifa->ifa_addr;
|
||||||
local_addrs = new local_addr(&addr->sin6_addr, local_addrs);
|
local_addrs = new local_addr(&addr->sin6_addr, local_addrs);
|
||||||
if (tracemode || DEBUG) {
|
if (tracemode || DEBUG) {
|
||||||
char host[512];
|
char host[512];
|
||||||
printf("Adding local address: %s\n",
|
printf("Adding local address: %s\n",
|
||||||
inet_ntop(AF_INET6, &addr->sin6_addr, host, sizeof(host)));
|
inet_ntop(AF_INET6, &addr->sin6_addr, host, sizeof(host)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef u_int32_t tcp_seq;
|
typedef u_int32_t tcp_seq;
|
||||||
@@ -90,33 +89,33 @@ typedef u_int32_t tcp_seq;
|
|||||||
/* glanced from ethereal, it's 16 bytes, and the payload packet type is
|
/* glanced from ethereal, it's 16 bytes, and the payload packet type is
|
||||||
* in the last 2 bytes... */
|
* in the last 2 bytes... */
|
||||||
struct ppp_header {
|
struct ppp_header {
|
||||||
u_int16_t dummy1;
|
u_int16_t dummy1;
|
||||||
u_int16_t dummy2;
|
u_int16_t dummy2;
|
||||||
u_int16_t dummy3;
|
u_int16_t dummy3;
|
||||||
u_int16_t dummy4;
|
u_int16_t dummy4;
|
||||||
u_int16_t dummy5;
|
u_int16_t dummy5;
|
||||||
u_int16_t dummy6;
|
u_int16_t dummy6;
|
||||||
u_int16_t dummy7;
|
u_int16_t dummy7;
|
||||||
|
|
||||||
u_int16_t packettype;
|
u_int16_t packettype;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TCP header */
|
/* TCP header */
|
||||||
// TODO take from elsewhere.
|
// TODO take from elsewhere.
|
||||||
struct tcp_hdr {
|
struct tcp_hdr {
|
||||||
u_short th_sport; /* source port */
|
u_short th_sport; /* source port */
|
||||||
u_short th_dport; /* destination port */
|
u_short th_dport; /* destination port */
|
||||||
tcp_seq th_seq; /* sequence number */
|
tcp_seq th_seq; /* sequence number */
|
||||||
tcp_seq th_ack; /* acknowledgement number */
|
tcp_seq th_ack; /* acknowledgement number */
|
||||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
u_int th_x2:4, /* (unused) */
|
u_int th_x2 : 4, /* (unused) */
|
||||||
th_off:4; /* data offset */
|
th_off : 4; /* data offset */
|
||||||
#endif
|
#endif
|
||||||
#if BYTE_ORDER == BIG_ENDIAN
|
#if BYTE_ORDER == BIG_ENDIAN
|
||||||
u_int th_off:4, /* data offset */
|
u_int th_off : 4, /* data offset */
|
||||||
th_x2:4; /* (unused) */
|
th_x2 : 4; /* (unused) */
|
||||||
#endif
|
#endif
|
||||||
u_char th_flags;
|
u_char th_flags;
|
||||||
#define TH_FIN 0x01
|
#define TH_FIN 0x01
|
||||||
#define TH_SYN 0x02
|
#define TH_SYN 0x02
|
||||||
#define TH_RST 0x04
|
#define TH_RST 0x04
|
||||||
@@ -125,157 +124,170 @@ struct tcp_hdr {
|
|||||||
#define TH_URG 0x20
|
#define TH_URG 0x20
|
||||||
#define TH_ECE 0x40
|
#define TH_ECE 0x40
|
||||||
#define TH_CWR 0x80
|
#define TH_CWR 0x80
|
||||||
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
|
#define TH_FLAGS (TH_FIN | TH_SYN | TH_RST | TH_ACK | TH_URG | TH_ECE | TH_CWR)
|
||||||
u_short th_win; /* window */
|
u_short th_win; /* window */
|
||||||
u_short th_sum; /* checksum */
|
u_short th_sum; /* checksum */
|
||||||
u_short th_urp; /* urgent pointer */
|
u_short th_urp; /* urgent pointer */
|
||||||
};
|
};
|
||||||
Packet::Packet (in_addr m_sip, unsigned short m_sport, in_addr m_dip, unsigned short m_dport, u_int32_t m_len, timeval m_time, direction m_dir)
|
Packet::Packet(in_addr m_sip, unsigned short m_sport, in_addr m_dip,
|
||||||
{
|
unsigned short m_dport, u_int32_t m_len, timeval m_time,
|
||||||
sip = m_sip; sport = m_sport;
|
direction m_dir) {
|
||||||
dip = m_dip; dport = m_dport;
|
sip = m_sip;
|
||||||
len = m_len; time = m_time;
|
sport = m_sport;
|
||||||
dir = m_dir; sa_family = AF_INET;
|
dip = m_dip;
|
||||||
hashstring = NULL;
|
dport = m_dport;
|
||||||
|
len = m_len;
|
||||||
|
time = m_time;
|
||||||
|
dir = m_dir;
|
||||||
|
sa_family = AF_INET;
|
||||||
|
hashstring = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Packet::Packet (in6_addr m_sip, unsigned short m_sport, in6_addr m_dip, unsigned short m_dport, u_int32_t m_len, timeval m_time, direction m_dir)
|
Packet::Packet(in6_addr m_sip, unsigned short m_sport, in6_addr m_dip,
|
||||||
{
|
unsigned short m_dport, u_int32_t m_len, timeval m_time,
|
||||||
sip6 = m_sip; sport = m_sport;
|
direction m_dir) {
|
||||||
dip6 = m_dip; dport = m_dport;
|
sip6 = m_sip;
|
||||||
len = m_len; time = m_time;
|
sport = m_sport;
|
||||||
dir = m_dir; sa_family = AF_INET6;
|
dip6 = m_dip;
|
||||||
hashstring = NULL;
|
dport = m_dport;
|
||||||
|
len = m_len;
|
||||||
|
time = m_time;
|
||||||
|
dir = m_dir;
|
||||||
|
sa_family = AF_INET6;
|
||||||
|
hashstring = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
direction invert(direction dir) {
|
direction invert(direction dir) {
|
||||||
if (dir == dir_incoming)
|
if (dir == dir_incoming)
|
||||||
return dir_outgoing;
|
return dir_outgoing;
|
||||||
else if (dir == dir_outgoing)
|
else if (dir == dir_outgoing)
|
||||||
return dir_incoming;
|
return dir_incoming;
|
||||||
else
|
else
|
||||||
return dir_unknown;
|
return dir_unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
Packet * Packet::newInverted () {
|
Packet *Packet::newInverted() {
|
||||||
direction new_direction = invert(dir);
|
direction new_direction = invert(dir);
|
||||||
|
|
||||||
if (sa_family == AF_INET)
|
if (sa_family == AF_INET)
|
||||||
return new Packet (dip, dport, sip, sport, len, time, new_direction);
|
return new Packet(dip, dport, sip, sport, len, time, new_direction);
|
||||||
else
|
else
|
||||||
return new Packet (dip6, dport, sip6, sport, len, time, new_direction);
|
return new Packet(dip6, dport, sip6, sport, len, time, new_direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* constructs returns a new Packet() structure with the same contents as this one */
|
/* constructs returns a new Packet() structure with the same contents as this
|
||||||
Packet::Packet (const Packet &old_packet) {
|
* one */
|
||||||
sip = old_packet.sip; sport = old_packet.sport;
|
Packet::Packet(const Packet &old_packet) {
|
||||||
sip6 = old_packet.sip6;
|
sip = old_packet.sip;
|
||||||
dip6 = old_packet.dip6;
|
sport = old_packet.sport;
|
||||||
dip = old_packet.dip; dport = old_packet.dport;
|
sip6 = old_packet.sip6;
|
||||||
len = old_packet.len; time = old_packet.time;
|
dip6 = old_packet.dip6;
|
||||||
sa_family = old_packet.sa_family;
|
dip = old_packet.dip;
|
||||||
if (old_packet.hashstring == NULL)
|
dport = old_packet.dport;
|
||||||
hashstring = NULL;
|
len = old_packet.len;
|
||||||
else
|
time = old_packet.time;
|
||||||
hashstring = strdup(old_packet.hashstring);
|
sa_family = old_packet.sa_family;
|
||||||
dir = old_packet.dir;
|
if (old_packet.hashstring == NULL)
|
||||||
|
hashstring = NULL;
|
||||||
|
else
|
||||||
|
hashstring = strdup(old_packet.hashstring);
|
||||||
|
dir = old_packet.dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sameinaddr(in_addr one, in_addr other)
|
bool sameinaddr(in_addr one, in_addr other) {
|
||||||
{
|
return one.s_addr == other.s_addr;
|
||||||
return one.s_addr == other.s_addr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Packet::isOlderThan (timeval t) {
|
bool Packet::isOlderThan(timeval t) {
|
||||||
std::cout << "Comparing " << time.tv_sec << " <= " << t.tv_sec << std::endl;
|
std::cout << "Comparing " << time.tv_sec << " <= " << t.tv_sec << std::endl;
|
||||||
return (time.tv_sec <= t.tv_sec);
|
return (time.tv_sec <= t.tv_sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Packet::Outgoing () {
|
bool Packet::Outgoing() {
|
||||||
/* must be initialised with getLocal("eth0:1");) */
|
/* must be initialised with getLocal("eth0:1");) */
|
||||||
assert (local_addrs != NULL);
|
assert(local_addrs != NULL);
|
||||||
|
|
||||||
switch (dir) {
|
switch (dir) {
|
||||||
case dir_outgoing:
|
case dir_outgoing:
|
||||||
return true;
|
return true;
|
||||||
case dir_incoming:
|
case dir_incoming:
|
||||||
return false;
|
return false;
|
||||||
case dir_unknown:
|
case dir_unknown:
|
||||||
bool islocal;
|
bool islocal;
|
||||||
if (sa_family == AF_INET)
|
if (sa_family == AF_INET)
|
||||||
islocal = local_addrs->contains(sip.s_addr);
|
islocal = local_addrs->contains(sip.s_addr);
|
||||||
else
|
else
|
||||||
islocal = local_addrs->contains(sip6);
|
islocal = local_addrs->contains(sip6);
|
||||||
if (islocal) {
|
if (islocal) {
|
||||||
dir = dir_outgoing;
|
dir = dir_outgoing;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
if (sa_family == AF_INET)
|
if (sa_family == AF_INET)
|
||||||
islocal = local_addrs->contains(dip.s_addr);
|
islocal = local_addrs->contains(dip.s_addr);
|
||||||
else
|
else
|
||||||
islocal = local_addrs->contains(dip6);
|
islocal = local_addrs->contains(dip6);
|
||||||
|
|
||||||
if (!islocal) {
|
if (!islocal) {
|
||||||
std::cerr << "Neither dip nor sip are local: ";
|
std::cerr << "Neither dip nor sip are local: ";
|
||||||
char addy [50];
|
char addy[50];
|
||||||
inet_ntop (AF_INET6, &sip6, addy, 49);
|
inet_ntop(AF_INET6, &sip6, addy, 49);
|
||||||
std::cerr << addy << std::endl;
|
std::cerr << addy << std::endl;
|
||||||
inet_ntop (AF_INET6, &dip6, addy, 49);
|
inet_ntop(AF_INET6, &dip6, addy, 49);
|
||||||
std::cerr << addy << std::endl;
|
std::cerr << addy << std::endl;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dir = dir_incoming;
|
dir = dir_incoming;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns the packet in '1.2.3.4:5-1.2.3.4:5'-form, for use in the 'conninode' table */
|
/* returns the packet in '1.2.3.4:5-1.2.3.4:5'-form, for use in the 'conninode'
|
||||||
|
* table */
|
||||||
/* '1.2.3.4' should be the local address. */
|
/* '1.2.3.4' should be the local address. */
|
||||||
/* the calling code should take care of deletion of the hash string */
|
/* the calling code should take care of deletion of the hash string */
|
||||||
char * Packet::gethashstring ()
|
char *Packet::gethashstring() {
|
||||||
{
|
if (hashstring != NULL) {
|
||||||
if (hashstring != NULL)
|
return hashstring;
|
||||||
{
|
}
|
||||||
return hashstring;
|
|
||||||
}
|
|
||||||
|
|
||||||
hashstring = (char *) malloc (HASHKEYSIZE * sizeof(char));
|
hashstring = (char *)malloc(HASHKEYSIZE * sizeof(char));
|
||||||
|
|
||||||
char * local_string = (char *) malloc (50);
|
char *local_string = (char *)malloc(50);
|
||||||
char * remote_string = (char *) malloc (50);
|
char *remote_string = (char *)malloc(50);
|
||||||
if (sa_family == AF_INET) {
|
if (sa_family == AF_INET) {
|
||||||
inet_ntop(sa_family, &sip, local_string, 49);
|
inet_ntop(sa_family, &sip, local_string, 49);
|
||||||
inet_ntop(sa_family, &dip, remote_string, 49);
|
inet_ntop(sa_family, &dip, remote_string, 49);
|
||||||
} else {
|
} else {
|
||||||
inet_ntop(sa_family, &sip6, local_string, 49);
|
inet_ntop(sa_family, &sip6, local_string, 49);
|
||||||
inet_ntop(sa_family, &dip6, remote_string, 49);
|
inet_ntop(sa_family, &dip6, remote_string, 49);
|
||||||
}
|
}
|
||||||
if (Outgoing()) {
|
if (Outgoing()) {
|
||||||
snprintf(hashstring, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d", local_string, sport, remote_string, dport);
|
snprintf(hashstring, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d",
|
||||||
} else {
|
local_string, sport, remote_string, dport);
|
||||||
snprintf(hashstring, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d", remote_string, dport, local_string, sport);
|
} else {
|
||||||
}
|
snprintf(hashstring, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d",
|
||||||
free (local_string);
|
remote_string, dport, local_string, sport);
|
||||||
free (remote_string);
|
}
|
||||||
//if (DEBUG)
|
free(local_string);
|
||||||
// std::cout << "Returning newly created hash string: " << hashstring << std::endl;
|
free(remote_string);
|
||||||
return hashstring;
|
// if (DEBUG)
|
||||||
|
// std::cout << "Returning newly created hash string: " << hashstring <<
|
||||||
|
//std::endl;
|
||||||
|
return hashstring;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 2 packets match if they have the same
|
/* 2 packets match if they have the same
|
||||||
* source and destination ports and IP's. */
|
* source and destination ports and IP's. */
|
||||||
bool Packet::match (Packet * other)
|
bool Packet::match(Packet *other) {
|
||||||
{
|
return (sport == other->sport) && (dport == other->dport) &&
|
||||||
return (sport == other->sport) && (dport == other->dport)
|
(sameinaddr(sip, other->sip)) && (sameinaddr(dip, other->dip));
|
||||||
&& (sameinaddr(sip, other->sip)) && (sameinaddr(dip, other->dip));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Packet::matchSource (Packet * other)
|
bool Packet::matchSource(Packet *other) {
|
||||||
{
|
return (sport == other->sport) && (sameinaddr(sip, other->sip));
|
||||||
return (sport == other->sport) && (sameinaddr(sip, other->sip));
|
|
||||||
}
|
}
|
||||||
|
|||||||
86
packet.h
86
packet.h
@@ -1,4 +1,4 @@
|
|||||||
/*
|
/*
|
||||||
* packet.h
|
* packet.h
|
||||||
*
|
*
|
||||||
* Copyright (c) 2004,2006 Arnout Engelen
|
* Copyright (c) 2004,2006 Arnout Engelen
|
||||||
@@ -15,11 +15,11 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef __PACKET_H
|
#ifndef __PACKET_H
|
||||||
#define __PACKET_H
|
#define __PACKET_H
|
||||||
|
|
||||||
@@ -31,56 +31,54 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include "nethogs.h"
|
#include "nethogs.h"
|
||||||
|
|
||||||
enum direction {
|
enum direction { dir_unknown, dir_incoming, dir_outgoing };
|
||||||
dir_unknown,
|
|
||||||
dir_incoming,
|
|
||||||
dir_outgoing
|
|
||||||
};
|
|
||||||
|
|
||||||
/* To initialise this module, call getLocal with the currently
|
/* To initialise this module, call getLocal with the currently
|
||||||
* monitored device (e.g. "eth0:1") */
|
* monitored device (e.g. "eth0:1") */
|
||||||
bool getLocal (const char *device, bool tracemode);
|
bool getLocal(const char *device, bool tracemode);
|
||||||
|
|
||||||
class Packet
|
class Packet {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
in6_addr sip6;
|
in6_addr sip6;
|
||||||
in6_addr dip6;
|
in6_addr dip6;
|
||||||
in_addr sip;
|
in_addr sip;
|
||||||
in_addr dip;
|
in_addr dip;
|
||||||
unsigned short sport;
|
unsigned short sport;
|
||||||
unsigned short dport;
|
unsigned short dport;
|
||||||
u_int32_t len;
|
u_int32_t len;
|
||||||
timeval time;
|
timeval time;
|
||||||
|
|
||||||
Packet (in_addr m_sip, unsigned short m_sport, in_addr m_dip, unsigned short m_dport, u_int32_t m_len, timeval m_time, direction dir = dir_unknown);
|
Packet(in_addr m_sip, unsigned short m_sport, in_addr m_dip,
|
||||||
Packet (in6_addr m_sip, unsigned short m_sport, in6_addr m_dip, unsigned short m_dport, u_int32_t m_len, timeval m_time, direction dir = dir_unknown);
|
unsigned short m_dport, u_int32_t m_len, timeval m_time,
|
||||||
/* copy constructor */
|
direction dir = dir_unknown);
|
||||||
Packet (const Packet &old);
|
Packet(in6_addr m_sip, unsigned short m_sport, in6_addr m_dip,
|
||||||
~Packet ()
|
unsigned short m_dport, u_int32_t m_len, timeval m_time,
|
||||||
{
|
direction dir = dir_unknown);
|
||||||
if (hashstring != NULL)
|
/* copy constructor */
|
||||||
{
|
Packet(const Packet &old);
|
||||||
free (hashstring);
|
~Packet() {
|
||||||
hashstring = NULL;
|
if (hashstring != NULL) {
|
||||||
}
|
free(hashstring);
|
||||||
}
|
hashstring = NULL;
|
||||||
/* Packet (const Packet &old_packet); */
|
}
|
||||||
/* copy constructor that turns the packet around */
|
}
|
||||||
Packet * newInverted ();
|
/* Packet (const Packet &old_packet); */
|
||||||
|
/* copy constructor that turns the packet around */
|
||||||
|
Packet *newInverted();
|
||||||
|
|
||||||
bool isOlderThan(timeval t);
|
bool isOlderThan(timeval t);
|
||||||
/* is this packet coming from the local host? */
|
/* is this packet coming from the local host? */
|
||||||
bool Outgoing ();
|
bool Outgoing();
|
||||||
|
|
||||||
|
bool match(Packet *other);
|
||||||
|
bool matchSource(Packet *other);
|
||||||
|
/* returns '1.2.3.4:5-1.2.3.4:6'-style string */
|
||||||
|
char *gethashstring();
|
||||||
|
|
||||||
bool match (Packet * other);
|
|
||||||
bool matchSource (Packet * other);
|
|
||||||
/* returns '1.2.3.4:5-1.2.3.4:6'-style string */
|
|
||||||
char * gethashstring();
|
|
||||||
private:
|
private:
|
||||||
direction dir;
|
direction dir;
|
||||||
short int sa_family;
|
short int sa_family;
|
||||||
char * hashstring;
|
char *hashstring;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
486
process.cpp
486
process.cpp
@@ -15,17 +15,17 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ncurses.h>
|
#include <ncurses.h>
|
||||||
#ifndef __APPLE__
|
#ifndef __APPLE__
|
||||||
#include <asm/types.h>
|
#include <asm/types.h>
|
||||||
#endif
|
#endif
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -47,8 +47,7 @@ extern timeval curtime;
|
|||||||
* key contains source ip, source port, destination ip, destination
|
* key contains source ip, source port, destination ip, destination
|
||||||
* port in format: '1.2.3.4:5-1.2.3.4:5'
|
* port in format: '1.2.3.4:5-1.2.3.4:5'
|
||||||
*/
|
*/
|
||||||
extern std::map <std::string, unsigned long> conninode;
|
extern std::map<std::string, unsigned long> conninode;
|
||||||
|
|
||||||
|
|
||||||
/* this file includes:
|
/* this file includes:
|
||||||
* - calls to inodeproc to get the pid that belongs to that inode
|
* - calls to inodeproc to get the pid that belongs to that inode
|
||||||
@@ -61,186 +60,155 @@ extern std::map <std::string, unsigned long> conninode;
|
|||||||
* * unknown IP traffic
|
* * unknown IP traffic
|
||||||
* We must take care these never get removed from the list.
|
* We must take care these never get removed from the list.
|
||||||
*/
|
*/
|
||||||
Process * unknowntcp;
|
Process *unknowntcp;
|
||||||
Process * unknownudp;
|
Process *unknownudp;
|
||||||
Process * unknownip;
|
Process *unknownip;
|
||||||
ProcList * processes;
|
ProcList *processes;
|
||||||
|
|
||||||
/* We're migrating to having several `unknown' processes that are added as
|
/* We're migrating to having several `unknown' processes that are added as
|
||||||
* normal processes, instead of hard-wired unknown processes.
|
* normal processes, instead of hard-wired unknown processes.
|
||||||
* This mapping maps from unknown processes descriptions to processes */
|
* This mapping maps from unknown processes descriptions to processes */
|
||||||
std::map <std::string, Process*> unknownprocs;
|
std::map<std::string, Process *> unknownprocs;
|
||||||
|
|
||||||
|
float tomb(u_int32_t bytes) { return ((double)bytes) / 1024 / 1024; }
|
||||||
|
float tokb(u_int32_t bytes) { return ((double)bytes) / 1024; }
|
||||||
|
|
||||||
float tomb (u_int32_t bytes)
|
float tokbps(u_int32_t bytes) { return (((double)bytes) / PERIOD) / 1024; }
|
||||||
{
|
|
||||||
return ((double)bytes) / 1024 / 1024;
|
void process_init() {
|
||||||
}
|
unknowntcp = new Process(0, "", "unknown TCP");
|
||||||
float tokb (u_int32_t bytes)
|
// unknownudp = new Process (0, "", "unknown UDP");
|
||||||
{
|
// unknownip = new Process (0, "", "unknown IP");
|
||||||
return ((double)bytes) / 1024;
|
processes = new ProcList(unknowntcp, NULL);
|
||||||
|
// processes = new ProcList (unknownudp, processes);
|
||||||
|
// processes = new ProcList (unknownip, processes);
|
||||||
}
|
}
|
||||||
|
|
||||||
float tokbps (u_int32_t bytes)
|
int Process::getLastPacket() {
|
||||||
{
|
int lastpacket = 0;
|
||||||
return (((double)bytes) / PERIOD) / 1024;
|
ConnList *curconn = connections;
|
||||||
}
|
while (curconn != NULL) {
|
||||||
|
assert(curconn != NULL);
|
||||||
|
assert(curconn->getVal() != NULL);
|
||||||
void process_init ()
|
if (curconn->getVal()->getLastPacket() > lastpacket)
|
||||||
{
|
lastpacket = curconn->getVal()->getLastPacket();
|
||||||
unknowntcp = new Process (0, "", "unknown TCP");
|
curconn = curconn->getNext();
|
||||||
//unknownudp = new Process (0, "", "unknown UDP");
|
}
|
||||||
//unknownip = new Process (0, "", "unknown IP");
|
return lastpacket;
|
||||||
processes = new ProcList (unknowntcp, NULL);
|
|
||||||
//processes = new ProcList (unknownudp, processes);
|
|
||||||
//processes = new ProcList (unknownip, processes);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Process::getLastPacket()
|
|
||||||
{
|
|
||||||
int lastpacket=0;
|
|
||||||
ConnList * curconn=connections;
|
|
||||||
while (curconn != NULL)
|
|
||||||
{
|
|
||||||
assert (curconn != NULL);
|
|
||||||
assert (curconn->getVal() != NULL);
|
|
||||||
if (curconn->getVal()->getLastPacket() > lastpacket)
|
|
||||||
lastpacket = curconn->getVal()->getLastPacket();
|
|
||||||
curconn = curconn->getNext();
|
|
||||||
}
|
|
||||||
return lastpacket;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the kb/s values for this process */
|
/** Get the kb/s values for this process */
|
||||||
void Process::getkbps (float * recvd, float * sent)
|
void Process::getkbps(float *recvd, float *sent) {
|
||||||
{
|
u_int32_t sum_sent = 0, sum_recv = 0;
|
||||||
u_int32_t sum_sent = 0, sum_recv = 0;
|
|
||||||
|
|
||||||
/* walk though all this process's connections, and sum
|
/* walk though all this process's connections, and sum
|
||||||
* them up */
|
* them up */
|
||||||
ConnList * curconn = this->connections;
|
ConnList *curconn = this->connections;
|
||||||
ConnList * previous = NULL;
|
ConnList *previous = NULL;
|
||||||
while (curconn != NULL)
|
while (curconn != NULL) {
|
||||||
{
|
if (curconn->getVal()->getLastPacket() <= curtime.tv_sec - CONNTIMEOUT) {
|
||||||
if (curconn->getVal()->getLastPacket() <= curtime.tv_sec - CONNTIMEOUT)
|
/* stalled connection, remove. */
|
||||||
{
|
ConnList *todelete = curconn;
|
||||||
/* stalled connection, remove. */
|
Connection *conn_todelete = curconn->getVal();
|
||||||
ConnList * todelete = curconn;
|
curconn = curconn->getNext();
|
||||||
Connection * conn_todelete = curconn->getVal();
|
if (todelete == this->connections)
|
||||||
curconn = curconn->getNext();
|
this->connections = curconn;
|
||||||
if (todelete == this->connections)
|
if (previous != NULL)
|
||||||
this->connections = curconn;
|
previous->setNext(curconn);
|
||||||
if (previous != NULL)
|
delete (todelete);
|
||||||
previous->setNext(curconn);
|
delete (conn_todelete);
|
||||||
delete (todelete);
|
} else {
|
||||||
delete (conn_todelete);
|
u_int32_t sent = 0, recv = 0;
|
||||||
}
|
curconn->getVal()->sumanddel(curtime, &recv, &sent);
|
||||||
else
|
sum_sent += sent;
|
||||||
{
|
sum_recv += recv;
|
||||||
u_int32_t sent = 0, recv = 0;
|
previous = curconn;
|
||||||
curconn->getVal()->sumanddel(curtime, &recv, &sent);
|
curconn = curconn->getNext();
|
||||||
sum_sent += sent;
|
}
|
||||||
sum_recv += recv;
|
}
|
||||||
previous = curconn;
|
*recvd = tokbps(sum_recv);
|
||||||
curconn = curconn->getNext();
|
*sent = tokbps(sum_sent);
|
||||||
}
|
|
||||||
}
|
|
||||||
*recvd = tokbps(sum_recv);
|
|
||||||
*sent = tokbps(sum_sent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** get total values for this process */
|
/** get total values for this process */
|
||||||
void Process::gettotal( u_int32_t * recvd, u_int32_t * sent)
|
void Process::gettotal(u_int32_t *recvd, u_int32_t *sent) {
|
||||||
{
|
u_int32_t sum_sent = 0, sum_recv = 0;
|
||||||
u_int32_t sum_sent = 0, sum_recv = 0;
|
ConnList *curconn = this->connections;
|
||||||
ConnList * curconn = this->connections;
|
while (curconn != NULL) {
|
||||||
while (curconn != NULL)
|
Connection *conn = curconn->getVal();
|
||||||
{
|
sum_sent += conn->sumSent;
|
||||||
Connection * conn = curconn->getVal();
|
sum_recv += conn->sumRecv;
|
||||||
sum_sent += conn->sumSent;
|
curconn = curconn->getNext();
|
||||||
sum_recv += conn->sumRecv;
|
}
|
||||||
curconn = curconn->getNext();
|
// std::cout << "Sum sent: " << sum_sent << std::endl;
|
||||||
}
|
// std::cout << "Sum recv: " << sum_recv << std::endl;
|
||||||
//std::cout << "Sum sent: " << sum_sent << std::endl;
|
*recvd = sum_recv;
|
||||||
//std::cout << "Sum recv: " << sum_recv << std::endl;
|
*sent = sum_sent;
|
||||||
*recvd = sum_recv;
|
|
||||||
*sent = sum_sent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::gettotalmb(float * recvd, float * sent)
|
void Process::gettotalmb(float *recvd, float *sent) {
|
||||||
{
|
u_int32_t sum_sent = 0, sum_recv = 0;
|
||||||
u_int32_t sum_sent = 0, sum_recv = 0;
|
gettotal(&sum_recv, &sum_sent);
|
||||||
gettotal(&sum_recv, &sum_sent);
|
*recvd = tomb(sum_recv);
|
||||||
*recvd = tomb(sum_recv);
|
*sent = tomb(sum_sent);
|
||||||
*sent = tomb(sum_sent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** get total values for this process */
|
/** get total values for this process */
|
||||||
void Process::gettotalkb(float * recvd, float * sent)
|
void Process::gettotalkb(float *recvd, float *sent) {
|
||||||
{
|
u_int32_t sum_sent = 0, sum_recv = 0;
|
||||||
u_int32_t sum_sent = 0, sum_recv = 0;
|
gettotal(&sum_recv, &sum_sent);
|
||||||
gettotal(&sum_recv, &sum_sent);
|
*recvd = tokb(sum_recv);
|
||||||
*recvd = tokb(sum_recv);
|
*sent = tokb(sum_sent);
|
||||||
*sent = tokb(sum_sent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::gettotalb(float * recvd, float * sent)
|
void Process::gettotalb(float *recvd, float *sent) {
|
||||||
{
|
u_int32_t sum_sent = 0, sum_recv = 0;
|
||||||
u_int32_t sum_sent = 0, sum_recv = 0;
|
gettotal(&sum_recv, &sum_sent);
|
||||||
gettotal(&sum_recv, &sum_sent);
|
// std::cout << "Total sent: " << sum_sent << std::endl;
|
||||||
//std::cout << "Total sent: " << sum_sent << std::endl;
|
*sent = sum_sent;
|
||||||
*sent = sum_sent;
|
*recvd = sum_recv;
|
||||||
*recvd = sum_recv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Process *findProcess(struct prg_node *node) {
|
||||||
|
ProcList *current = processes;
|
||||||
|
while (current != NULL) {
|
||||||
|
Process *currentproc = current->getVal();
|
||||||
|
assert(currentproc != NULL);
|
||||||
|
|
||||||
Process * findProcess (struct prg_node * node)
|
if (node->pid == currentproc->pid)
|
||||||
{
|
return current->getVal();
|
||||||
ProcList * current = processes;
|
current = current->next;
|
||||||
while (current != NULL)
|
}
|
||||||
{
|
return NULL;
|
||||||
Process * currentproc = current->getVal();
|
|
||||||
assert (currentproc != NULL);
|
|
||||||
|
|
||||||
if (node->pid == currentproc->pid)
|
|
||||||
return current->getVal();
|
|
||||||
current = current->next;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* finds process based on inode, if any */
|
/* finds process based on inode, if any */
|
||||||
/* should be done quickly after arrival of the packet,
|
/* should be done quickly after arrival of the packet,
|
||||||
* otherwise findPID will be outdated */
|
* otherwise findPID will be outdated */
|
||||||
Process * findProcess (unsigned long inode)
|
Process *findProcess(unsigned long inode) {
|
||||||
{
|
struct prg_node *node = findPID(inode);
|
||||||
struct prg_node * node = findPID(inode);
|
|
||||||
|
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return findProcess (node);
|
return findProcess(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ProcList::size ()
|
int ProcList::size() {
|
||||||
{
|
int i = 1;
|
||||||
int i=1;
|
|
||||||
|
|
||||||
if (next != NULL)
|
if (next != NULL)
|
||||||
i += next->size();
|
i += next->size();
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_all_procs ()
|
void check_all_procs() {
|
||||||
{
|
ProcList *curproc = processes;
|
||||||
ProcList * curproc = processes;
|
while (curproc != NULL) {
|
||||||
while (curproc != NULL)
|
curproc->getVal()->check();
|
||||||
{
|
curproc = curproc->getNext();
|
||||||
curproc->getVal()->check();
|
}
|
||||||
curproc = curproc->getNext();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -248,54 +216,52 @@ void check_all_procs ()
|
|||||||
* if the inode is not associated with any PID, return NULL
|
* if the inode is not associated with any PID, return NULL
|
||||||
* if the process is not yet in the proclist, add it
|
* if the process is not yet in the proclist, add it
|
||||||
*/
|
*/
|
||||||
Process * getProcess (unsigned long inode, const char * devicename)
|
Process *getProcess(unsigned long inode, const char *devicename) {
|
||||||
{
|
struct prg_node *node = findPID(inode);
|
||||||
struct prg_node * node = findPID(inode);
|
|
||||||
|
|
||||||
if (node == NULL)
|
if (node == NULL) {
|
||||||
{
|
if (DEBUG || bughuntmode)
|
||||||
if (DEBUG || bughuntmode)
|
std::cout << "No PID information for inode " << inode << std::endl;
|
||||||
std::cout << "No PID information for inode " << inode << std::endl;
|
return NULL;
|
||||||
return NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Process * proc = findProcess (node);
|
Process *proc = findProcess(node);
|
||||||
|
|
||||||
if (proc != NULL)
|
if (proc != NULL)
|
||||||
return proc;
|
return proc;
|
||||||
|
|
||||||
Process * newproc = new Process (inode, devicename, node->name.c_str());
|
Process *newproc = new Process(inode, devicename, node->name.c_str());
|
||||||
newproc->pid = node->pid;
|
newproc->pid = node->pid;
|
||||||
|
|
||||||
char procdir [100];
|
char procdir[100];
|
||||||
sprintf(procdir , "/proc/%d", node->pid);
|
sprintf(procdir, "/proc/%d", node->pid);
|
||||||
struct stat stats;
|
struct stat stats;
|
||||||
int retval = stat(procdir, &stats);
|
int retval = stat(procdir, &stats);
|
||||||
|
|
||||||
/* 0 seems a proper default.
|
/* 0 seems a proper default.
|
||||||
* used in case the PID disappeared while nethogs was running
|
* used in case the PID disappeared while nethogs was running
|
||||||
* TODO we can store node->uid this while info on the inodes,
|
* TODO we can store node->uid this while info on the inodes,
|
||||||
* right? */
|
* right? */
|
||||||
/*
|
/*
|
||||||
if (!ROBUST && (retval != 0))
|
if (!ROBUST && (retval != 0))
|
||||||
{
|
{
|
||||||
std::cerr << "Couldn't stat " << procdir << std::endl;
|
std::cerr << "Couldn't stat " << procdir << std::endl;
|
||||||
assert (false);
|
assert (false);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (retval != 0)
|
if (retval != 0)
|
||||||
newproc->setUid(0);
|
newproc->setUid(0);
|
||||||
else
|
else
|
||||||
newproc->setUid(stats.st_uid);
|
newproc->setUid(stats.st_uid);
|
||||||
|
|
||||||
/*if (getpwuid(stats.st_uid) == NULL) {
|
/*if (getpwuid(stats.st_uid) == NULL) {
|
||||||
std::stderr << "uid for inode
|
std::stderr << "uid for inode
|
||||||
if (!ROBUST)
|
if (!ROBUST)
|
||||||
assert(false);
|
assert(false);
|
||||||
}*/
|
}*/
|
||||||
processes = new ProcList (newproc, processes);
|
processes = new ProcList(newproc, processes);
|
||||||
return newproc;
|
return newproc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -305,88 +271,82 @@ Process * getProcess (unsigned long inode, const char * devicename)
|
|||||||
* is made. If no process can be found even then, it's added to the
|
* is made. If no process can be found even then, it's added to the
|
||||||
* 'unknown' process.
|
* 'unknown' process.
|
||||||
*/
|
*/
|
||||||
Process * getProcess (Connection * connection, const char * devicename)
|
Process *getProcess(Connection *connection, const char *devicename) {
|
||||||
{
|
unsigned long inode = conninode[connection->refpacket->gethashstring()];
|
||||||
unsigned long inode = conninode[connection->refpacket->gethashstring()];
|
|
||||||
|
|
||||||
if (inode == 0)
|
if (inode == 0) {
|
||||||
{
|
// no? refresh and check conn/inode table
|
||||||
// no? refresh and check conn/inode table
|
if (bughuntmode) {
|
||||||
if (bughuntmode)
|
std::cout << "? new connection not in connection-to-inode table before "
|
||||||
{
|
"refresh.\n";
|
||||||
std::cout << "? new connection not in connection-to-inode table before refresh.\n";
|
}
|
||||||
}
|
// refresh the inode->pid table first. Presumably processing the renewed
|
||||||
// refresh the inode->pid table first. Presumably processing the renewed connection->inode table
|
// connection->inode table
|
||||||
// is slow, making this worthwhile.
|
// is slow, making this worthwhile.
|
||||||
// We take the fact for granted that we might already know the inode->pid (unlikely anyway if we
|
// We take the fact for granted that we might already know the inode->pid
|
||||||
// haven't seen the connection->inode yet though).
|
// (unlikely anyway if we
|
||||||
#ifndef __APPLE__
|
// haven't seen the connection->inode yet though).
|
||||||
reread_mapping();
|
#ifndef __APPLE__
|
||||||
#endif
|
reread_mapping();
|
||||||
refreshconninode();
|
|
||||||
inode = conninode[connection->refpacket->gethashstring()];
|
|
||||||
if (bughuntmode)
|
|
||||||
{
|
|
||||||
if (inode == 0)
|
|
||||||
{
|
|
||||||
std::cout << ":( inode for connection not found after refresh.\n";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cout << ":) inode for connection found after refresh.\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if REVERSEHACK
|
|
||||||
if (inode == 0)
|
|
||||||
{
|
|
||||||
/* HACK: the following is a hack for cases where the
|
|
||||||
* 'local' addresses aren't properly recognised, as is
|
|
||||||
* currently the case for IPv6 */
|
|
||||||
|
|
||||||
/* we reverse the direction of the stream if
|
|
||||||
* successful. */
|
|
||||||
Packet * reversepacket = connection->refpacket->newInverted();
|
|
||||||
inode = conninode[reversepacket->gethashstring()];
|
|
||||||
|
|
||||||
if (inode == 0)
|
|
||||||
{
|
|
||||||
delete reversepacket;
|
|
||||||
if (bughuntmode || DEBUG)
|
|
||||||
std::cout << "LOC: " << connection->refpacket->gethashstring() << " STILL not in connection-to-inode table - adding to the unknown process\n";
|
|
||||||
unknowntcp->connections = new ConnList (connection, unknowntcp->connections);
|
|
||||||
return unknowntcp;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete connection->refpacket;
|
|
||||||
connection->refpacket = reversepacket;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
refreshconninode();
|
||||||
else if (bughuntmode)
|
inode = conninode[connection->refpacket->gethashstring()];
|
||||||
{
|
if (bughuntmode) {
|
||||||
std::cout << ";) new connection in connection-to-inode table before refresh.\n";
|
if (inode == 0) {
|
||||||
}
|
std::cout << ":( inode for connection not found after refresh.\n";
|
||||||
|
} else {
|
||||||
|
std::cout << ":) inode for connection found after refresh.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if REVERSEHACK
|
||||||
|
if (inode == 0) {
|
||||||
|
/* HACK: the following is a hack for cases where the
|
||||||
|
* 'local' addresses aren't properly recognised, as is
|
||||||
|
* currently the case for IPv6 */
|
||||||
|
|
||||||
if (bughuntmode)
|
/* we reverse the direction of the stream if
|
||||||
{
|
* successful. */
|
||||||
std::cout << " inode # " << inode << std::endl;
|
Packet *reversepacket = connection->refpacket->newInverted();
|
||||||
}
|
inode = conninode[reversepacket->gethashstring()];
|
||||||
|
|
||||||
Process * proc = NULL;
|
if (inode == 0) {
|
||||||
if (inode != 0)
|
delete reversepacket;
|
||||||
proc = getProcess(inode, devicename);
|
if (bughuntmode || DEBUG)
|
||||||
|
std::cout << "LOC: " << connection->refpacket->gethashstring()
|
||||||
|
<< " STILL not in connection-to-inode table - adding to "
|
||||||
|
"the unknown process\n";
|
||||||
|
unknowntcp->connections =
|
||||||
|
new ConnList(connection, unknowntcp->connections);
|
||||||
|
return unknowntcp;
|
||||||
|
}
|
||||||
|
|
||||||
if (proc == NULL) {
|
delete connection->refpacket;
|
||||||
proc = new Process (inode, "", connection->refpacket->gethashstring());
|
connection->refpacket = reversepacket;
|
||||||
processes = new ProcList (proc, processes);
|
}
|
||||||
}
|
#endif
|
||||||
|
} else if (bughuntmode) {
|
||||||
|
std::cout
|
||||||
|
<< ";) new connection in connection-to-inode table before refresh.\n";
|
||||||
|
}
|
||||||
|
|
||||||
proc->connections = new ConnList (connection, proc->connections);
|
if (bughuntmode) {
|
||||||
return proc;
|
std::cout << " inode # " << inode << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Process *proc = NULL;
|
||||||
|
if (inode != 0)
|
||||||
|
proc = getProcess(inode, devicename);
|
||||||
|
|
||||||
|
if (proc == NULL) {
|
||||||
|
proc = new Process(inode, "", connection->refpacket->gethashstring());
|
||||||
|
processes = new ProcList(proc, processes);
|
||||||
|
}
|
||||||
|
|
||||||
|
proc->connections = new ConnList(connection, proc->connections);
|
||||||
|
return proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void procclean ()
|
void procclean() {
|
||||||
{
|
// delete conninode;
|
||||||
//delete conninode;
|
prg_cache_clear();
|
||||||
prg_cache_clear();
|
|
||||||
}
|
}
|
||||||
|
|||||||
176
process.h
176
process.h
@@ -1,4 +1,4 @@
|
|||||||
/*
|
/*
|
||||||
* process.h
|
* process.h
|
||||||
*
|
*
|
||||||
* Copyright (c) 2004-2006,2008,2011 Arnout Engelen
|
* Copyright (c) 2004-2006,2008,2011 Arnout Engelen
|
||||||
@@ -15,11 +15,11 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
*USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef __PROCESS_H
|
#ifndef __PROCESS_H
|
||||||
#define __PROCESS_H
|
#define __PROCESS_H
|
||||||
|
|
||||||
@@ -30,123 +30,103 @@
|
|||||||
extern bool tracemode;
|
extern bool tracemode;
|
||||||
extern bool bughuntmode;
|
extern bool bughuntmode;
|
||||||
|
|
||||||
void check_all_procs ();
|
void check_all_procs();
|
||||||
|
|
||||||
class ConnList
|
class ConnList {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
ConnList (Connection * m_val, ConnList * m_next)
|
ConnList(Connection *m_val, ConnList *m_next) {
|
||||||
{
|
assert(m_val != NULL);
|
||||||
assert (m_val != NULL);
|
val = m_val;
|
||||||
val = m_val; next = m_next;
|
next = m_next;
|
||||||
}
|
}
|
||||||
~ConnList ()
|
~ConnList() {
|
||||||
{
|
/* does not delete its value, to allow a connection to
|
||||||
/* does not delete its value, to allow a connection to
|
* remove itself from the global connlist in its destructor */
|
||||||
* remove itself from the global connlist in its destructor */
|
}
|
||||||
}
|
Connection *getVal() { return val; }
|
||||||
Connection * getVal ()
|
void setNext(ConnList *m_next) { next = m_next; }
|
||||||
{
|
ConnList *getNext() { return next; }
|
||||||
return val;
|
|
||||||
}
|
|
||||||
void setNext (ConnList * m_next)
|
|
||||||
{
|
|
||||||
next = m_next;
|
|
||||||
}
|
|
||||||
ConnList * getNext ()
|
|
||||||
{
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
Connection * val;
|
Connection *val;
|
||||||
ConnList * next;
|
ConnList *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Process
|
class Process {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
/* the process makes a copy of the name. the device name needs to be stable. */
|
/* the process makes a copy of the name. the device name needs to be stable.
|
||||||
Process (const unsigned long m_inode, const char * m_devicename, const char * m_name = NULL)
|
*/
|
||||||
: inode (m_inode)
|
Process(const unsigned long m_inode, const char *m_devicename,
|
||||||
{
|
const char *m_name = NULL)
|
||||||
//std::cout << "ARN: Process created with dev " << m_devicename << std::endl;
|
: inode(m_inode) {
|
||||||
if (DEBUG)
|
// std::cout << "ARN: Process created with dev " << m_devicename <<
|
||||||
std::cout << "PROC: Process created at " << this << std::endl;
|
// std::endl;
|
||||||
|
if (DEBUG)
|
||||||
|
std::cout << "PROC: Process created at " << this << std::endl;
|
||||||
|
|
||||||
if (m_name == NULL)
|
if (m_name == NULL)
|
||||||
name = NULL;
|
name = NULL;
|
||||||
else
|
else
|
||||||
name = strdup(m_name);
|
name = strdup(m_name);
|
||||||
|
|
||||||
devicename = m_devicename;
|
devicename = m_devicename;
|
||||||
connections = NULL;
|
connections = NULL;
|
||||||
pid = 0;
|
pid = 0;
|
||||||
uid = 0;
|
uid = 0;
|
||||||
}
|
}
|
||||||
void check () {
|
void check() { assert(pid >= 0); }
|
||||||
assert (pid >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
~Process ()
|
|
||||||
{
|
|
||||||
free (name);
|
|
||||||
if (DEBUG)
|
|
||||||
std::cout << "PROC: Process deleted at " << this << std::endl;
|
|
||||||
}
|
|
||||||
int getLastPacket ();
|
|
||||||
|
|
||||||
void gettotal( u_int32_t * recvd, u_int32_t * sent);
|
~Process() {
|
||||||
void getkbps (float * recvd, float * sent);
|
free(name);
|
||||||
void gettotalmb(float * recvd, float * sent);
|
if (DEBUG)
|
||||||
void gettotalkb(float * recvd, float * sent);
|
std::cout << "PROC: Process deleted at " << this << std::endl;
|
||||||
void gettotalb (float * recvd, float * sent);
|
}
|
||||||
|
int getLastPacket();
|
||||||
|
|
||||||
char * name;
|
void gettotal(u_int32_t *recvd, u_int32_t *sent);
|
||||||
const char * devicename;
|
void getkbps(float *recvd, float *sent);
|
||||||
int pid;
|
void gettotalmb(float *recvd, float *sent);
|
||||||
|
void gettotalkb(float *recvd, float *sent);
|
||||||
|
void gettotalb(float *recvd, float *sent);
|
||||||
|
|
||||||
ConnList * connections;
|
char *name;
|
||||||
uid_t getUid()
|
const char *devicename;
|
||||||
{
|
int pid;
|
||||||
return uid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setUid(uid_t m_uid)
|
ConnList *connections;
|
||||||
{
|
uid_t getUid() { return uid; }
|
||||||
uid = m_uid;
|
|
||||||
}
|
void setUid(uid_t m_uid) { uid = m_uid; }
|
||||||
|
|
||||||
|
unsigned long getInode() { return inode; }
|
||||||
|
|
||||||
unsigned long getInode()
|
|
||||||
{
|
|
||||||
return inode;
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
const unsigned long inode;
|
const unsigned long inode;
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProcList
|
class ProcList {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
ProcList (Process * m_val, ProcList * m_next)
|
ProcList(Process *m_val, ProcList *m_next) {
|
||||||
{
|
assert(m_val != NULL);
|
||||||
assert (m_val != NULL);
|
val = m_val;
|
||||||
val = m_val; next = m_next;
|
next = m_next;
|
||||||
}
|
}
|
||||||
int size ();
|
int size();
|
||||||
Process * getVal () { return val; }
|
Process *getVal() { return val; }
|
||||||
ProcList * getNext () { return next; }
|
ProcList *getNext() { return next; }
|
||||||
ProcList * next;
|
ProcList *next;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Process * val;
|
Process *val;
|
||||||
};
|
};
|
||||||
|
|
||||||
Process * getProcess (Connection * connection, const char * devicename = NULL);
|
Process *getProcess(Connection *connection, const char *devicename = NULL);
|
||||||
|
|
||||||
void process_init ();
|
void process_init();
|
||||||
|
|
||||||
void refreshconninode ();
|
void refreshconninode();
|
||||||
|
|
||||||
void procclean ();
|
void procclean();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user