From cabc2a1ea356b5acbfa120846a279c4b5646cec1 Mon Sep 17 00:00:00 2001 From: Matheus Rambo Date: Mon, 28 Feb 2022 20:53:51 -0300 Subject: [PATCH] feat: Filter by process #217 It is possible to filter by process id! Add the -P flag. Example: `nethogs -P 123 -P 333` to filter the processes: 123 and 333 --- doc/nethogs.8 | 8 +++++++- src/main.cpp | 12 ++++++++++-- src/process.cpp | 15 +++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/doc/nethogs.8 b/doc/nethogs.8 index 398e26b..c3a9953 100644 --- a/doc/nethogs.8 +++ b/doc/nethogs.8 @@ -21,6 +21,7 @@ nethogs \- Net top tool grouping bandwidth per process .RB [ "\-C" ] .RB [ "\-b" ] .RB [ "\-g period" ] +.RB [ "\-P pid" ] .RI [device(s)] .SH DESCRIPTION NetHogs is a small 'net top' tool. Instead of breaking the traffic down per protocol or per subnet, like most such tools do, it groups bandwidth by process - and does not rely on a special kernel module to be loaded. So if there's suddenly a lot of network traffic, you can fire up NetHogs and immediately see which PID is causing this, and if it's some kind of spinning process, kill it. @@ -69,6 +70,9 @@ Display the program basename. \fB-g\fP garbage collection period in number of refresh. default is 50. .TP +\fB-P\fP +Show only processes with the specified pid(s). +.TP \fB-f\fP EXPERIMENTAL: specify string pcap filter (like tcpdump). This may be removed or changed in a future version. .TP @@ -113,7 +117,9 @@ command, as follows: sudo setcap "cap_net_admin,cap_net_raw+pe" /usr/local/sbin/nethogs .EE .in - +.SH "Notes" +1. When using the -P option, in a case where a process exited (normally or abruptly), Nethogs does not track that it exited. So, the operating system might create +a new process (for another program) with the same pid. In this case, this new process will be shown by Nethogs. .SH "SEE ALSO" .I netstat(8) tcpdump(1) pcap(3) .SH AUTHOR diff --git a/src/main.cpp b/src/main.cpp index a48d41b..efaa2ce 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #include "nethogs.cpp" #include +#include #include #ifdef __linux__ @@ -14,6 +15,8 @@ static std::pair self_pipe = std::make_pair(-1, -1); static time_t last_refresh_time = 0; +std::set pidsToWatch; + // selectable file descriptors for the main loop static fd_set pc_loop_fd_set; static std::vector pc_loop_fd_list; @@ -27,7 +30,7 @@ static void help(bool iserror) { // output << "usage: nethogs [-V] [-b] [-d seconds] [-t] [-p] [-f (eth|ppp))] // [device [device [device ...]]]\n"; output << "usage: nethogs [-V] [-h] [-x] [-d seconds] [-v mode] [-c count] " - "[-t] [-p] [-s] [-a] [-l] [-f filter] [-C] [-b]" + "[-t] [-p] [-s] [-a] [-l] [-f filter] [-C] [-b] [-P pid] " "[device [device [device ...]]]\n"; output << " -V : prints version.\n"; output << " -h : prints this help.\n"; @@ -54,6 +57,7 @@ static void help(bool iserror) { " This may be removed or changed in a future version.\n"; output << " device : device(s) to monitor. default is all " "interfaces up and running excluding loopback\n"; + output << " -P : Show only processes.\n"; output << std::endl; output << "When nethogs is running, press:\n"; output << " q: quit\n"; @@ -146,8 +150,9 @@ int main(int argc, char **argv) { char *filter = NULL; int garbage_collection_period = 50; + int opt; - while ((opt = getopt(argc, argv, "Vhxtpsd:v:c:laf:Cbg:")) != -1) { + while ((opt = getopt(argc, argv, "Vhxtpsd:v:c:laf:Cbg:P:")) != -1) { switch (opt) { case 'V': versiondisplay(); @@ -195,6 +200,9 @@ int main(int argc, char **argv) { case 'g': garbage_collection_period = (time_t)atoi(optarg); break; + case 'P': + pidsToWatch.insert((pid_t) atoi(optarg)); + break; default: help(true); exit(EXIT_FAILURE); diff --git a/src/process.cpp b/src/process.cpp index 0c8f03e..fcfb1f9 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #if !defined(__APPLE__) && !defined(__FreeBSD__) @@ -34,6 +35,7 @@ #include #include #include +#include #include "conninode.h" #include "inode2prog.h" @@ -66,6 +68,8 @@ Process *unknownudp; Process *unknownip; ProcList *processes; +extern std::set pidsToWatch; + #define KB (1UL << 10) #define MB (1UL << 20) #define GB (1UL << 30) @@ -77,6 +81,7 @@ float tokbps(u_int64_t bytes) { return (((double)bytes) / PERIOD) / KB; } float tombps(u_int64_t bytes) { return (((double)bytes) / PERIOD) / MB; } float togbps(u_int64_t bytes) { return (((double)bytes) / PERIOD) / GB; } + void process_init() { unknowntcp = new Process(0, "", "unknown TCP"); processes = new ProcList(unknowntcp, NULL); @@ -87,6 +92,7 @@ void process_init() { // unknownip = new Process (0, "", "unknown IP"); // processes = new ProcList (unknownip, processes); } + } int Process::getLastPacket() { @@ -262,6 +268,10 @@ Process *getProcess(unsigned long inode, const char *devicename) { if (proc != NULL) return proc; + if ( !(pidsToWatch.empty()) && pidsToWatch.find(node->pid) == pidsToWatch.end() ) { + return NULL; + } + // extract program name and command line from data read from cmdline file const char *prgname = node->cmdline.c_str(); const char *cmdline = prgname + strlen(prgname) + 1; @@ -384,6 +394,10 @@ Process *getProcess(Connection *connection, const char *devicename, } } + if (!(pidsToWatch.empty()) && proc == NULL) { + proc = (packettype == IPPROTO_TCP) ? unknowntcp : unknownudp; + } + if (proc == NULL) { proc = new Process(inode, "", connection->refpacket->gethashstring()); processes = new ProcList(proc, processes); @@ -426,3 +440,4 @@ void remove_timed_out_processes() { } void garbage_collect_processes() { garbage_collect_inodeproc(); } +