From cb6ad14afc45df1059e37234bb3447cb578040cb Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Mon, 21 Mar 2016 00:09:27 +0100 Subject: [PATCH] Warn when no devices are up/running (fixes #45) --- devices.cpp | 78 +++++++++++++++++++++++++++++++------------------- devices.h | 18 ++++++++---- libnethogs.cpp | 66 +++++++++++++++++++++--------------------- main.cpp | 22 ++++++-------- process.cpp | 37 +++++++++++------------- 5 files changed, 119 insertions(+), 102 deletions(-) diff --git a/devices.cpp b/devices.cpp index 09b76bd..a314c34 100644 --- a/devices.cpp +++ b/devices.cpp @@ -1,4 +1,4 @@ -/* +/* * devices.cpp * * Copyright (c) 2011 Arnout Engelen @@ -28,11 +28,44 @@ #include #include -device * get_default_devices() +bool selected(int devc, char** devicenames, char* devicename) { + if (devc == 0) + return true; + + for (int i = 0; i < devc; i++) + if (strcmp(devicenames[i], devicename) == 0) + return true; + + return false; +} + +bool already_seen(device* devices, char* devicename) { + for (class device* current_device = devices; + current_device != NULL; + current_device = current_device->next) { + if (strcmp(current_device->name, devicename) == 0) + return true; + } + return false; +} + +// The interface is up, not a loopback and running? +bool up_running(int ifa_flags) { + std::cout << "up: " << (ifa_flags & IFF_UP) << std::endl; + return !(ifa_flags & IFF_LOOPBACK) && + (ifa_flags & IFF_UP) && + (ifa_flags & IFF_RUNNING); +} + +/** + * This function can return null, if no good interface is found + * When 'all' is set to 'false', the function avoids loopback interface and down/not running interfaces + */ +device * get_devices(int devc, char** devicenames, bool all) { struct ifaddrs *ifaddr, *ifa; - if (getifaddrs(&ifaddr) == -1) + if (getifaddrs(&ifaddr) == -1) { std::cerr << "Fail to get interface addresses" << std::endl; // perror("getifaddrs"); @@ -40,37 +73,24 @@ device * get_default_devices() } 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) - continue; + if (ifa->ifa_addr == NULL) + continue; + if (!selected(devc, devicenames, ifa->ifa_name)) + continue; + if (already_seen(devices, ifa->ifa_name)) + continue; + if (!all && !up_running(ifa->ifa_flags)) + continue; - // The interface is up, not a loopback and running ? - if ( !(ifa->ifa_flags & IFF_LOOPBACK) && - (ifa->ifa_flags & IFF_UP) && - (ifa->ifa_flags & IFF_RUNNING) ) - { - // Check if the interface is already known by going through all the devices - bool found = false; - device* pIter = devices; - while(pIter != NULL) - { - if ( strcmp(ifa->ifa_name,pIter->name) == 0 ) - { - found = true; - } - pIter = pIter->next; - } - - // We found a new interface, let's add it - if ( found == false ) - { - devices = new device(strdup(ifa->ifa_name),devices); - } - } + devices = new device(strdup(ifa->ifa_name),devices); } freeifaddrs(ifaddr); return devices; } +device * get_default_devices() { + return get_devices(0, NULL, false); +} diff --git a/devices.h b/devices.h index 5642ede..27a6ffc 100644 --- a/devices.h +++ b/devices.h @@ -1,4 +1,4 @@ -/* +/* * devices.h * * Copyright (c) 2011 Arnout Engelen @@ -26,7 +26,7 @@ class device { public: - device (const char * m_name, device * m_next = NULL) + device (const char * m_name, device * m_next = NULL) { name = m_name; next = m_next; } @@ -34,10 +34,16 @@ public: device * next; }; -/** - * This function can return null, if no good interface is found - * The function avoids loopback interface and down/not running interfaces - */ +/** get all devices that are up, running and not loopback */ device * get_default_devices(); +/** + * Get all specified devices. + * If no devices are specified, get all devices. + * + * when 'all' is set, also return loopback interfaces and interfaces + * that are down or not running + */ +device * get_devices(int devc, char** devv, bool all); + #endif diff --git a/libnethogs.cpp b/libnethogs.cpp index 4fd826e..4f6bc9d 100644 --- a/libnethogs.cpp +++ b/libnethogs.cpp @@ -32,14 +32,14 @@ static time_t monitor_last_refresh_time = 0; //selectable file descriptors for the main loop static fd_set pc_loop_fd_set; static std::vector pc_loop_fd_list; -static bool pc_loop_use_select = true; +static bool pc_loop_use_select = true; static handle * handles = NULL; static std::pair create_self_pipe() { int pfd[2]; - if (pipe(pfd) == -1) + if (pipe(pfd) == -1) return std::make_pair(-1, -1); if (fcntl(pfd[0], F_SETFL, fcntl(pfd[0], F_GETFL) | O_NONBLOCK) == -1) @@ -71,7 +71,7 @@ static bool wait_for_next_trigger() { return false; } - } + } } else { @@ -84,32 +84,32 @@ static bool wait_for_next_trigger() static int nethogsmonitor_init() { process_init(); - + device * devices = get_default_devices(); if ( devices == NULL ) { - std::cerr << "Not devices to monitor" << std::endl; + std::cerr << "No devices to monitor" << std::endl; return NETHOGS_STATUS_NO_DEVICE; } - + device * current_dev = devices; - + bool promiscuous = false; - + int nb_devices = 0; int nb_failed_devices = 0; - - while (current_dev != NULL) + + while (current_dev != NULL) { ++nb_devices; - + if( !getLocal(current_dev->name, false) ) { std::cerr << "getifaddrs failed while establishing local IP." << std::endl; ++nb_failed_devices; continue; } - + char errbuf[PCAP_ERRBUF_SIZE]; dp_handle * newhandle = dp_open_live(current_dev->name, BUFSIZ, promiscuous, 100, errbuf); if (newhandle != NULL) @@ -130,7 +130,7 @@ static int nethogsmonitor_init() fprintf(stderr, "Error putting libpcap in nonblocking mode\n"); } handles = new handle (newhandle, current_dev->name, handles); - + if( pc_loop_use_select ) { //some devices may not support pcap_get_selectable_fd @@ -145,7 +145,7 @@ static int nethogsmonitor_init() pc_loop_fd_list.clear(); fprintf(stderr, "failed to get selectable_fd for %s\n", current_dev->name); } - } + } } else { @@ -159,8 +159,8 @@ static int nethogsmonitor_init() if(nb_devices == nb_failed_devices) { return NETHOGS_STATUS_FAILURE; - } - + } + //use the Self-Pipe trick to interrupt the select() in the main loop if( pc_loop_use_select ) { @@ -175,7 +175,7 @@ static int nethogsmonitor_init() pc_loop_fd_list.push_back(self_pipe.first); } } - + return NETHOGS_STATUS_OK; } @@ -220,7 +220,7 @@ static void nethogsmonitor_handle_update(NethogsMonitorCallback cb) { previousproc->next = curproc->next; curproc = curproc->next; - } else + } else { processes = curproc->getNext(); curproc = processes; @@ -239,12 +239,12 @@ static void nethogsmonitor_handle_update(NethogsMonitorCallback cb) float recv_kbs; curproc->getVal()->getkbps (&recv_kbs, &sent_kbs); curproc->getVal()->gettotal (&recv_bytes, &sent_bytes); - + //notify update bool const new_data = (monitor_record_map.find(curproc) == monitor_record_map.end()); NethogsMonitorRecord &data = monitor_record_map[curproc]; - bool data_change = false; + bool data_change = false; if( new_data ) { data_change = true; @@ -255,24 +255,24 @@ static void nethogsmonitor_handle_update(NethogsMonitorCallback cb) data.name = curproc->getVal()->name; data.pid = curproc->getVal()->pid; } - + data.device_name = curproc->getVal()->devicename; #define NHM_UPDATE_ONE_FIELD(TO,FROM) if((TO)!=(FROM)) { TO = FROM; data_change = true; } - + NHM_UPDATE_ONE_FIELD( data.uid, uid ) NHM_UPDATE_ONE_FIELD( data.sent_bytes, sent_bytes ) NHM_UPDATE_ONE_FIELD( data.recv_bytes, recv_bytes ) NHM_UPDATE_ONE_FIELD( data.sent_kbs, sent_kbs ) NHM_UPDATE_ONE_FIELD( data.recv_kbs, recv_kbs ) - - #undef NHM_UPDATE_ONE_FIELD - + + #undef NHM_UPDATE_ONE_FIELD + if( data_change ) { (*cb)(NETHOGS_APP_ACTION_SET, &data); } - + //next previousproc = curproc; curproc = curproc->next; @@ -289,14 +289,14 @@ static void nethogsmonitor_clean_up() pcap_close(current_handle->content->pcap_handle); current_handle = current_handle->next; } - + //close file descriptors for(std::vector::const_iterator it=pc_loop_fd_list.begin(); it != pc_loop_fd_list.end(); ++it) { close(*it); } - + procclean(); } @@ -306,15 +306,15 @@ int nethogsmonitor_loop(NethogsMonitorCallback cb) { return NETHOGS_STATUS_FAILURE; } - + int return_value = nethogsmonitor_init(); if( return_value != NETHOGS_STATUS_OK ) { return return_value; } - + monitor_run_flag = true; - + struct dpargs * userdata = (dpargs *) malloc (sizeof (struct dpargs)); // Main loop @@ -358,9 +358,9 @@ int nethogsmonitor_loop(NethogsMonitorCallback cb) } } } - + nethogsmonitor_clean_up(); - + return NETHOGS_STATUS_OK; } diff --git a/main.cpp b/main.cpp index 2f9e431..940b819 100644 --- a/main.cpp +++ b/main.cpp @@ -33,6 +33,7 @@ static void help(bool iserror) //output << " -f : format of packets on interface, default is eth.\n"; output << " -p : sniff in promiscious mode (not recommended).\n"; output << " -s : sort output by sent column.\n"; + output << " -a : monitor all devices, even loopback/stopped ones.\n"; output << " device : device(s) to monitor. default is all interfaces up and running excluding loopback\n"; output << std::endl; output << "When nethogs is running, press:\n"; @@ -137,11 +138,11 @@ int main (int argc, char** argv) { process_init(); - device * devices = NULL; int promisc = 0; + bool all = false; int opt; - while ((opt = getopt(argc, argv, "Vhbtpd:v:c:s")) != -1) { + while ((opt = getopt(argc, argv, "Vahbtpd:v:c:sa")) != -1) { switch(opt) { case 'V': versiondisplay(); @@ -171,25 +172,18 @@ int main (int argc, char** argv) case 'c': refreshlimit = atoi(optarg); break; + case 'a': + all = true; + break; default: help(true); exit(EXIT_FAILURE); } } - while (optind < argc) { - devices = new device (strdup(argv[optind++]), devices); - } - + device * devices = get_devices(argc - optind, argv + optind, all); if (devices == NULL) - { - devices = get_default_devices(); - if ( devices == NULL ) - { - std::cerr << "Not devices to monitor" << std::endl; - return 0; - } - } + forceExit(false, "No devices to monitor. Use '-a' to allow monitoring loopback interfaces or devices that are not up/running"); if ((!tracemode) && (!DEBUG)){ init_ui(); diff --git a/process.cpp b/process.cpp index 0e92ca9..196f803 100644 --- a/process.cpp +++ b/process.cpp @@ -1,4 +1,4 @@ -/* +/* * process.cpp * * Copyright (c) 2004,2005,2008,2011 Arnout Engelen @@ -37,17 +37,14 @@ #include "process.h" #include "nethogs.h" -/* #include "inodeproc.cpp" */ -#include "inode2prog.h" +#include "inode2prog.h" #include "conninode.h" -extern local_addr * local_addrs; - extern timeval curtime; -/* +/* * 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' */ extern std::map conninode; @@ -64,12 +61,12 @@ extern std::map conninode; * * unknown IP traffic * We must take care these never get removed from the list. */ -Process * unknowntcp; -Process * unknownudp; -Process * unknownip; +Process * unknowntcp; +Process * unknownudp; +Process * unknownip; 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. * This mapping maps from unknown processes descriptions to processes */ std::map unknownprocs; @@ -90,7 +87,7 @@ float tokbps (u_int32_t bytes) } -void process_init () +void process_init () { unknowntcp = new Process (0, "", "unknown TCP"); //unknownudp = new Process (0, "", "unknown UDP"); @@ -205,7 +202,7 @@ Process * findProcess (struct prg_node * node) { Process * currentproc = current->getVal(); assert (currentproc != NULL); - + if (node->pid == currentproc->pid) return current->getVal(); current = current->next; @@ -214,7 +211,7 @@ Process * findProcess (struct prg_node * node) } /* 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 */ Process * findProcess (unsigned long inode) { @@ -246,7 +243,7 @@ void check_all_procs () } } -/* +/* * returns the process from proclist with matching pid * if the inode is not associated with any PID, return NULL * if the process is not yet in the proclist, add it @@ -254,7 +251,7 @@ void check_all_procs () Process * getProcess (unsigned long inode, const char * devicename) { struct prg_node * node = findPID(inode); - + if (node == NULL) { if (DEBUG || bughuntmode) @@ -275,7 +272,7 @@ Process * getProcess (unsigned long inode, const char * devicename) struct stat 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 * TODO we can store node->uid this while info on the inodes, * right? */ @@ -293,7 +290,7 @@ Process * getProcess (unsigned long inode, const char * devicename) newproc->setUid(stats.st_uid); /*if (getpwuid(stats.st_uid) == NULL) { - std::stderr << "uid for inode + std::stderr << "uid for inode if (!ROBUST) assert(false); }*/ @@ -301,11 +298,11 @@ Process * getProcess (unsigned long inode, const char * devicename) return newproc; } -/* +/* * Used when a new connection is encountered. Finds corresponding * process and adds the connection. If the connection doesn't belong * to any known process, the process list is updated and a new process - * 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. */ Process * getProcess (Connection * connection, const char * devicename)