Compare commits
10 Commits
02c1811f9e
...
e13522ea35
| Author | SHA1 | Date | |
|---|---|---|---|
| e13522ea35 | |||
| 5b92953241 | |||
| 23289acabd | |||
| 59cfb62336 | |||
| 5bb454cb03 | |||
| 468b055918 | |||
| 1d8d69bf06 | |||
| 7ea25e917f | |||
| 8b6c7c7bc8 | |||
|
|
08daf76d81 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -10,3 +10,7 @@ libnethogs.a
|
||||
results/
|
||||
build/
|
||||
nethogs.egg-info
|
||||
|
||||
# IDE configurations
|
||||
.vscode
|
||||
.idea
|
||||
12
README.md
12
README.md
@@ -81,7 +81,17 @@ If you want to remove Nethogs from your system, you can:
|
||||
|
||||
sudo make uninstall
|
||||
|
||||
### Running without root
|
||||
### Running
|
||||
|
||||
See the manpage for the options.
|
||||
|
||||
You will see a line called 'unknown TCP' - this bucket is used for traffic
|
||||
that cannot be associated with any process, for example because the process
|
||||
has terminated before its traffic could be counted. As long as there's not
|
||||
a significant amount of traffic in this bucket it can likely be safely
|
||||
ignored.
|
||||
|
||||
#### Running without root
|
||||
|
||||
In order to be run by a non-root user, nethogs needs the `cap_net_admin` and `cap_net_raw` capabilities; additionally, to read and display process names, `cap_dac_read_search` and `cap_sys_ptrace` capabilities are required. These can be set on the executable by using the `setcap` command, as follows:
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ bughunt mode - implies tracemode.
|
||||
delay for update refresh rate in seconds. default is 1.
|
||||
.TP
|
||||
\fB-v\fP
|
||||
view mode (0 = kB/s, 1 = total kB, 2 = total bytes, 3 = total MB, 4 = MB/s, 5 = GB/s). default is 0.
|
||||
view mode (0 = kB/s, 1 = total kB, 2 = total bytes, 3 = total MB, 4 = MB/s, 5 = GB/s, 6 = B/s). default is 0.
|
||||
|
||||
kB: 2e10 bytes, MB: 2e20 bytes, GB: 2e30 bytes
|
||||
.TP
|
||||
@@ -75,6 +75,12 @@ garbage collection period in number of refresh. default is 50.
|
||||
\fB-P\fP
|
||||
Show only processes with the specified pid(s).
|
||||
.TP
|
||||
\fB-j\fP
|
||||
Output in JSON format.
|
||||
.TP
|
||||
\fB-z\fP
|
||||
Sort by PID.
|
||||
.TP
|
||||
\fB-f\fP
|
||||
EXPERIMENTAL: specify string pcap filter (like tcpdump). This may be removed or changed in a future version.
|
||||
.TP
|
||||
|
||||
28
monitor-service/README.md
Normal file
28
monitor-service/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Nethogs monitor
|
||||
|
||||
Use nethogs as a background service to monitor network usage.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
sh nethogs-monitor-install.sh
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Enable service:
|
||||
```sh
|
||||
systemctl enable nethogs-monitor
|
||||
```
|
||||
|
||||
Start service:
|
||||
```sh
|
||||
systemctl start nethogs-monitor
|
||||
```
|
||||
|
||||
View report:
|
||||
```sh
|
||||
nethogs-monitor-report.sh
|
||||
```
|
||||
|
||||
|
||||
1000
monitor-service/nethogs-monitor-dashboard-template.html
Normal file
1000
monitor-service/nethogs-monitor-dashboard-template.html
Normal file
File diff suppressed because it is too large
Load Diff
22
monitor-service/nethogs-monitor-install.sh
Normal file
22
monitor-service/nethogs-monitor-install.sh
Normal file
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Create directories
|
||||
sudo mkdir -p /var/log/nethogs
|
||||
sudo mkdir -p /opt/nethogs-monitor
|
||||
|
||||
# Move files
|
||||
sudo cp ../src/nethogs /opt/nethogs-monitor/
|
||||
sudo cp nethogs-monitor.sh /opt/nethogs-monitor/
|
||||
sudo cp nethogs-monitor-dashboard-template.html /opt/nethogs-monitor/
|
||||
sudo cp nethogs-monitor.service /etc/systemd/system/
|
||||
sudo cp nethogs-monitor-report.sh /opt/nethogs-monitor/
|
||||
|
||||
# Set execution permissions
|
||||
sudo chmod +x /opt/nethogs-monitor/nethogs-monitor.sh
|
||||
sudo chmod +x /opt/nethogs-monitor/nethogs-monitor-report.sh
|
||||
|
||||
# Link in local bins
|
||||
sudo ln -sf /opt/nethogs-monitor/nethogs-monitor-report.sh /usr/local/bin/nethogs-monitor-report.sh
|
||||
|
||||
# Reload daemons
|
||||
sudo systemctl daemon-reload
|
||||
136
monitor-service/nethogs-monitor-report.sh
Normal file
136
monitor-service/nethogs-monitor-report.sh
Normal file
@@ -0,0 +1,136 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
NETHOGS_LOG="/var/log/nethogs/nethogs.jsonl"
|
||||
TEMPLATE_FILE="/opt/nethogs-monitor/nethogs-monitor-dashboard-template.html"
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
HOURS_BACK="${1:-24}"
|
||||
OUTPUT_FILE="${2:-${PWD}/nethogs-dashboard.html}"
|
||||
MAX_LINES=10000
|
||||
|
||||
log() {
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" >&2
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
rm -rf "$TEMP_DIR"
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
# Function to extract recent data from JSONL
|
||||
extract_recent_data() {
|
||||
local hours_back=$1
|
||||
local output_file="$TEMP_DIR/recent_data.jsonl"
|
||||
|
||||
if [ ! -f "$NETHOGS_LOG" ]; then
|
||||
log "Warning: File $NETHOGS_LOG not found"
|
||||
echo "[]" > "$output_file"
|
||||
return
|
||||
fi
|
||||
|
||||
# Calculate timestamp limit
|
||||
local time_limit=$(date -d "$hours_back hours ago" +%s)
|
||||
|
||||
# Extract last lines and filter by time
|
||||
echo "[" > "$output_file"
|
||||
tail -n $MAX_LINES "$NETHOGS_LOG" | while IFS= read -r line; do
|
||||
if [ -n "$line" ]; then
|
||||
# Extract timestamp and convert to epoch
|
||||
local timestamp_iso=$(echo "$line" | jq -r '.timestamp // empty' 2>/dev/null || echo "")
|
||||
if [ -n "$timestamp_iso" ]; then
|
||||
local timestamp_epoch=$(date -d "$timestamp_iso" +%s 2>/dev/null || echo "0")
|
||||
if [ "$timestamp_epoch" -ge "$time_limit" ]; then
|
||||
echo "${line},"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done >> "$output_file"
|
||||
echo "]" >> "$output_file"
|
||||
|
||||
# If no data, create valid empty file
|
||||
if [ ! -s "$output_file" ]; then
|
||||
echo "[]" > "$output_file"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to generate HTML with embedded data
|
||||
generate_html() {
|
||||
local data_file="$1"
|
||||
local output="$2"
|
||||
|
||||
# Verify template exists
|
||||
if [ ! -f "$TEMPLATE_FILE" ]; then
|
||||
log "Error: Template not found at $TEMPLATE_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Generate generation timestamp
|
||||
local generation_time=$(date -Iseconds)
|
||||
|
||||
# Copy template and replace placeholders
|
||||
cp "$TEMPLATE_FILE" "$output"
|
||||
|
||||
#sed -i "s|JSON_DATA_PLACEHOLDER|$json_data|g" "$output"
|
||||
sed -i "/JSON_DATA_PLACEHOLDER/{
|
||||
r $data_file
|
||||
d
|
||||
}" "$output"
|
||||
sed -i "s|GENERATION_TIME_PLACEHOLDER|$generation_time|g" "$output"
|
||||
sed -i "s|HOURS_BACK_PLACEHOLDER|$HOURS_BACK|g" "$output"
|
||||
|
||||
log "Dashboard HTML generated: $output"
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
log "Starting dashboard generation"
|
||||
log "Extracting data from last $HOURS_BACK hours..."
|
||||
|
||||
# Check dependencies
|
||||
if ! command -v jq &> /dev/null; then
|
||||
log "Error: jq is not installed. Install with: sudo apt install jq"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract recent data
|
||||
extract_recent_data "$HOURS_BACK"
|
||||
|
||||
# Verify data exists
|
||||
local data_file="$TEMP_DIR/recent_data.jsonl"
|
||||
local record_count=$(wc -l < "$data_file")
|
||||
log "Processing $record_count records"
|
||||
|
||||
# Generate HTML
|
||||
log "Generating dashboard HTML..."
|
||||
generate_html "$data_file" "$OUTPUT_FILE"
|
||||
|
||||
# Create output directory if it doesn't exist
|
||||
mkdir -p "$(dirname "$OUTPUT_FILE")"
|
||||
|
||||
log "Dashboard generated successfully: $OUTPUT_FILE"
|
||||
log "File size: $(du -h "$OUTPUT_FILE" | cut -f1)"
|
||||
|
||||
xdg-open "$OUTPUT_FILE"
|
||||
}
|
||||
|
||||
# Show help
|
||||
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
|
||||
echo "Usage: $0 [HOURS] [OUTPUT_FILE]"
|
||||
echo
|
||||
echo "HOURS: Number of hours to look back for data (default: 24)"
|
||||
echo "OUTPUT_FILE: Output HTML file (default: ${PWD}/nethogs-dashboard.html)"
|
||||
echo
|
||||
echo "Examples:"
|
||||
echo " $0 # Last 24 hours, default output"
|
||||
echo " $0 6 # Last 6 hours"
|
||||
echo " $0 168 /var/www/html/week.html # Last week"
|
||||
echo
|
||||
echo "Dependencies: jq"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Execute main function
|
||||
main "$@"
|
||||
31
monitor-service/nethogs-monitor.service
Normal file
31
monitor-service/nethogs-monitor.service
Normal file
@@ -0,0 +1,31 @@
|
||||
[Unit]
|
||||
Description=Nethogs Network Monitor Service
|
||||
Documentation=man:nethogs(8)
|
||||
After=network.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
Group=root
|
||||
ExecStart=/opt/nethogs-monitor/nethogs-monitor.sh
|
||||
ExecStop=/bin/kill -TERM $MAINPID
|
||||
PIDFile=/run/nethogs-monitor.pid
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
# Configuración de seguridad
|
||||
NoNewPrivileges=true
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=/var/log/nethogs /run
|
||||
ProtectHome=true
|
||||
PrivateTmp=true
|
||||
|
||||
# Límites de recursos
|
||||
LimitNOFILE=65536
|
||||
MemoryMax=512M
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
33
monitor-service/nethogs-monitor.sh
Normal file
33
monitor-service/nethogs-monitor.sh
Normal file
@@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Configuration
|
||||
LOGFILE="/var/log/nethogs/nethogs.jsonl"
|
||||
PIDFILE="/run/nethogs-monitor.pid"
|
||||
NETHOGS_BIN="/opt/nethogs-monitor/nethogs"
|
||||
|
||||
cleanup() {
|
||||
echo "Stopping nethogs monitor..."
|
||||
if [ -f "$PIDFILE" ]; then
|
||||
rm -f "$PIDFILE"
|
||||
fi
|
||||
exit 0
|
||||
}
|
||||
trap cleanup SIGTERM SIGINT
|
||||
|
||||
# Write PID
|
||||
echo $$ > "$PIDFILE"
|
||||
|
||||
# Ensure logfile directory
|
||||
mkdir -p "$(dirname "$LOGFILE")"
|
||||
|
||||
# Main loop
|
||||
while true; do
|
||||
# Execute nethogs
|
||||
"$NETHOGS_BIN" -j -v 6 -z -C -d 10 >> "$LOGFILE" 2>&1
|
||||
|
||||
# Si nethogs falla, esperar antes de reintentar
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$(date): Error executing nethogs, retrying in 10 seconds ..."
|
||||
sleep 10
|
||||
fi
|
||||
done
|
||||
@@ -58,6 +58,10 @@ u_int64_t PackList::sumanddel(timeval t) {
|
||||
PackListNode *previous = NULL;
|
||||
|
||||
while (current != NULL) {
|
||||
if(current->is_sum == false){
|
||||
retval += current->val->len;
|
||||
current->is_sum = true;
|
||||
}
|
||||
// std::cout << "Comparing " << current->val->time.tv_sec << " <= " <<
|
||||
// t.tv_sec - PERIOD << endl;
|
||||
if (current->val->time.tv_sec <= t.tv_sec - PERIOD) {
|
||||
@@ -68,7 +72,6 @@ u_int64_t PackList::sumanddel(timeval t) {
|
||||
delete current;
|
||||
return retval;
|
||||
}
|
||||
retval += current->val->len;
|
||||
previous = current;
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
PackListNode(Packet *m_val, PackListNode *m_next = NULL) {
|
||||
val = m_val;
|
||||
next = m_next;
|
||||
is_sum = false;
|
||||
}
|
||||
~PackListNode() {
|
||||
delete val;
|
||||
@@ -38,6 +39,7 @@ public:
|
||||
}
|
||||
PackListNode *next;
|
||||
Packet *val;
|
||||
bool is_sum;
|
||||
};
|
||||
|
||||
class PackList {
|
||||
|
||||
86
src/cui.cpp
86
src/cui.cpp
@@ -44,11 +44,14 @@ extern Process *unknownudp;
|
||||
extern Process *unknownip;
|
||||
|
||||
extern bool sortRecv;
|
||||
extern bool sortPID;
|
||||
|
||||
extern int viewMode;
|
||||
extern bool showcommandline;
|
||||
extern bool showBasename;
|
||||
|
||||
extern bool output_json;
|
||||
|
||||
extern unsigned refreshlimit;
|
||||
extern unsigned refreshcount;
|
||||
|
||||
@@ -68,7 +71,7 @@ const char *COLUMN_FORMAT_RECEIVED = "%11.3f";
|
||||
|
||||
// All descriptions are padded to 6 characters in length with spaces
|
||||
const char *const desc_view_mode[VIEWMODE_COUNT] = {
|
||||
"kB/s ", "kB ", "bytes ", "MB ", "MB/s ", "GB/s "};
|
||||
"kB/s ", "kB ", "bytes ", "MB ", "MB/s ", "GB/s ", "B/s "};
|
||||
|
||||
constexpr char FILE_SEPARATOR = '/';
|
||||
|
||||
@@ -90,12 +93,11 @@ public:
|
||||
|
||||
void show(int row, unsigned int proglen, unsigned int devlen);
|
||||
void log();
|
||||
void json();
|
||||
|
||||
double sent_value;
|
||||
double recv_value;
|
||||
const char *devicename;
|
||||
|
||||
private:
|
||||
const char *m_name;
|
||||
const char *m_cmdline;
|
||||
pid_t m_pid;
|
||||
@@ -232,6 +234,48 @@ void Line::log() {
|
||||
<< recv_value << std::endl;
|
||||
}
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
std::string escape_json(const std::string &s) {
|
||||
std::ostringstream o;
|
||||
for (auto c = s.cbegin(); c != s.cend(); c++) {
|
||||
switch (*c) {
|
||||
case '"': o << "\\\""; break;
|
||||
case '\\': o << "\\\\"; break;
|
||||
case '\b': o << "\\b"; break;
|
||||
case '\f': o << "\\f"; break;
|
||||
case '\n': o << "\\n"; break;
|
||||
case '\r': o << "\\r"; break;
|
||||
case '\t': o << "\\t"; break;
|
||||
default:
|
||||
if ('\x00' <= *c && *c <= '\x1f') {
|
||||
o << "\\u"
|
||||
<< std::hex << std::setw(4) << std::setfill('0') << static_cast<int>(*c);
|
||||
} else {
|
||||
o << *c;
|
||||
}
|
||||
}
|
||||
}
|
||||
return o.str();
|
||||
}
|
||||
|
||||
void Line::json() {
|
||||
std::cout << "{";
|
||||
std::cout << "\"name\": \"" << escape_json(m_name) << "\"";
|
||||
std::cout << ", ";
|
||||
std::cout << "\"pid\": \"" << m_pid << "\"";
|
||||
std::cout << ", ";
|
||||
std::cout << "\"uid\": \"" << m_uid << "\"";
|
||||
std::cout << ", ";
|
||||
std::cout << "\"devicename\": \"" << devicename << "\"";
|
||||
std::cout << ", ";
|
||||
std::cout << "\"sent\": " << sent_value;
|
||||
std::cout << ", ";
|
||||
std::cout << "\"recv\": " << recv_value;
|
||||
std::cout << "}";
|
||||
}
|
||||
|
||||
|
||||
int get_devlen(Line *lines[], int nproc, int rows) {
|
||||
int devlen = MIN_COLUMN_WIDTH_DEV;
|
||||
int curlen;
|
||||
@@ -255,14 +299,18 @@ int GreatestFirst(const void *ma, const void *mb) {
|
||||
Line *a = *pa;
|
||||
Line *b = *pb;
|
||||
double aValue;
|
||||
if (sortRecv) {
|
||||
if (sortPID) {
|
||||
aValue = a->m_pid;
|
||||
} else if (sortRecv) {
|
||||
aValue = a->recv_value;
|
||||
} else {
|
||||
aValue = a->sent_value;
|
||||
}
|
||||
|
||||
double bValue;
|
||||
if (sortRecv) {
|
||||
if (sortPID) {
|
||||
bValue = (double)b->m_pid;
|
||||
} else if (sortRecv) {
|
||||
bValue = b->recv_value;
|
||||
} else {
|
||||
bValue = b->sent_value;
|
||||
@@ -343,6 +391,28 @@ void show_trace(Line *lines[], int nproc) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char* get_iso8601_timestamp() {
|
||||
static char buffer[32];
|
||||
time_t now = time(NULL);
|
||||
struct tm *utc = gmtime(&now);
|
||||
strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%SZ", utc);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void show_json(Line *lines[], int nproc) {
|
||||
/* print them */
|
||||
std::cout << "{\"timestamp\": \""<< get_iso8601_timestamp() << "\", \"processes\": [";
|
||||
for (int i = 0; i < nproc; i++) {
|
||||
if(i>0){
|
||||
std::cout << ",";
|
||||
}
|
||||
lines[i]->json();
|
||||
delete lines[i];
|
||||
}
|
||||
std::cout << "]}"<< std::endl;
|
||||
}
|
||||
|
||||
void show_ncurses(Line *lines[], int nproc) {
|
||||
int rows; // number of terminal rows
|
||||
int cols; // number of terminal columns
|
||||
@@ -436,6 +506,8 @@ void do_refresh() {
|
||||
curproc->getVal()->gettotalmb(&value_recv, &value_sent);
|
||||
} else if (viewMode == VIEWMODE_TOTAL_B) {
|
||||
curproc->getVal()->gettotalb(&value_recv, &value_sent);
|
||||
} else if (viewMode == VIEWMODE_BPS) {
|
||||
curproc->getVal()->getbps(&value_recv, &value_sent);
|
||||
} else {
|
||||
forceExit(false, "Invalid viewMode: %d", viewMode);
|
||||
}
|
||||
@@ -453,7 +525,9 @@ void do_refresh() {
|
||||
/* sort the accumulated lines */
|
||||
qsort(lines, nproc, sizeof(Line *), GreatestFirst);
|
||||
|
||||
if (tracemode || DEBUG)
|
||||
if (output_json)
|
||||
show_json(lines, nproc);
|
||||
else if (tracemode || DEBUG)
|
||||
show_trace(lines, nproc);
|
||||
else
|
||||
show_ncurses(lines, nproc);
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
bool catchall = false;
|
||||
/* 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, bool quiet) {
|
||||
struct dp_handle *retval =
|
||||
(struct dp_handle *)malloc(sizeof(struct dp_handle));
|
||||
int i;
|
||||
@@ -47,37 +47,39 @@ struct dp_handle *dp_fillhandle(pcap_t *phandle) {
|
||||
|
||||
retval->linktype = pcap_datalink(retval->pcap_handle);
|
||||
|
||||
switch (retval->linktype) {
|
||||
case (DLT_EN10MB):
|
||||
fprintf(stdout, "Ethernet link detected\n");
|
||||
break;
|
||||
case (DLT_PPP):
|
||||
fprintf(stdout, "PPP link detected\n");
|
||||
break;
|
||||
case (DLT_LINUX_SLL):
|
||||
fprintf(stdout, "Linux Cooked Socket link detected\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stdout, "No PPP or Ethernet link: %d\n", retval->linktype);
|
||||
// TODO maybe error? or 'other' callback?
|
||||
break;
|
||||
if((!quiet)){
|
||||
switch (retval->linktype) {
|
||||
case (DLT_EN10MB):
|
||||
fprintf(stdout, "Ethernet link detected\n");
|
||||
break;
|
||||
case (DLT_PPP):
|
||||
fprintf(stdout, "PPP link detected\n");
|
||||
break;
|
||||
case (DLT_LINUX_SLL):
|
||||
fprintf(stdout, "Linux Cooked Socket link detected\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stdout, "No PPP or Ethernet link: %d\n", retval->linktype);
|
||||
// TODO maybe error? or 'other' callback?
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
struct dp_handle *dp_open_offline(char *fname, char *ebuf) {
|
||||
struct dp_handle *dp_open_offline(char *fname, char *ebuf, bool quiet) {
|
||||
pcap_t *temp = pcap_open_offline(fname, ebuf);
|
||||
|
||||
if (temp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dp_fillhandle(temp);
|
||||
return dp_fillhandle(temp, quiet);
|
||||
}
|
||||
|
||||
struct dp_handle *dp_open_live(const char *device, int snaplen, int promisc,
|
||||
int to_ms, char *filter, char *errbuf) {
|
||||
int to_ms, char *filter, char *errbuf, bool quiet) {
|
||||
struct bpf_program fp; // compiled filter program
|
||||
bpf_u_int32 maskp; // subnet mask
|
||||
bpf_u_int32 netp; // interface IP
|
||||
@@ -107,7 +109,7 @@ struct dp_handle *dp_open_live(const char *device, int snaplen, int promisc,
|
||||
}
|
||||
}
|
||||
|
||||
return dp_fillhandle(temp);
|
||||
return dp_fillhandle(temp, quiet);
|
||||
}
|
||||
|
||||
/* function to get packet statistics, e.g. dropped packets */
|
||||
|
||||
@@ -67,8 +67,8 @@ struct dp_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 *filter, char *errbuf);
|
||||
struct dp_handle *dp_open_offline(char *fname, char *ebuf);
|
||||
int to_ms, char *filter, char *errbuf, bool quiet);
|
||||
struct dp_handle *dp_open_offline(char *fname, char *ebuf, bool quiet);
|
||||
|
||||
/* function to get packet statistics, e.g. dropped packets */
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
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, false);
|
||||
dp_addcb(newhandle, dp_packet_tcp, process_tcp);
|
||||
int ret = dp_dispatch(newhandle, -1, NULL, 0);
|
||||
if (ret == -1) {
|
||||
|
||||
@@ -102,7 +102,7 @@ static int nethogsmonitor_init(int devc, char **devicenames, bool all,
|
||||
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
dp_handle *newhandle = dp_open_live(current_dev->name, BUFSIZ, promiscuous,
|
||||
to_ms, filter, errbuf);
|
||||
to_ms, filter, errbuf, false);
|
||||
if (newhandle != NULL) {
|
||||
dp_addcb(newhandle, dp_packet_ip, process_ip);
|
||||
dp_addcb(newhandle, dp_packet_ip6, process_ip6);
|
||||
|
||||
23
src/main.cpp
23
src/main.cpp
@@ -39,7 +39,7 @@ static void help(bool iserror) {
|
||||
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 bytes, 3 = total MB, 4 = MB/s, 5 = GB/s). default is 0.\n";
|
||||
"total bytes, 3 = total MB, 4 = MB/s, 5 = GB/s, 6 = B/s). default is 0.\n";
|
||||
output << " -c : number of updates. default is 0 (unlimited).\n";
|
||||
output << " -t : tracemode.\n";
|
||||
// output << " -f : format of packets on interface, default is
|
||||
@@ -69,6 +69,8 @@ static void help(bool iserror) {
|
||||
output << " b: display the program basename instead of the fullpath\n";
|
||||
output << " m: switch between total (kB, bytes, MB) and throughput (kB/s, "
|
||||
" MB/s, GB/s) mode\n";
|
||||
output << " j: json output\n";
|
||||
output << " z: sort by PIDn";
|
||||
}
|
||||
|
||||
void quit_cb(int /* i */) {
|
||||
@@ -80,7 +82,7 @@ void quit_cb(int /* i */) {
|
||||
}
|
||||
|
||||
void forceExit(bool success, const char *msg, ...) {
|
||||
if ((!tracemode) && (!DEBUG)) {
|
||||
if ((!tracemode) && (!DEBUG) && (!output_json)) {
|
||||
exit_ui();
|
||||
}
|
||||
|
||||
@@ -141,7 +143,7 @@ void clean_up() {
|
||||
}
|
||||
|
||||
procclean();
|
||||
if ((!tracemode) && (!DEBUG))
|
||||
if ((!tracemode) && (!DEBUG) && (!output_json))
|
||||
exit_ui();
|
||||
}
|
||||
|
||||
@@ -153,7 +155,7 @@ int main(int argc, char **argv) {
|
||||
int garbage_collection_period = 50;
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "Vhxtpsd:v:c:laf:Cbg:P:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "Vhxtpsd:v:c:laf:Cbg:P:jz")) != -1) {
|
||||
switch (opt) {
|
||||
case 'V':
|
||||
versiondisplay();
|
||||
@@ -204,6 +206,12 @@ int main(int argc, char **argv) {
|
||||
case 'P':
|
||||
pidsToWatch.insert((pid_t)atoi(optarg));
|
||||
break;
|
||||
case 'j':
|
||||
output_json = true;
|
||||
break;
|
||||
case 'z':
|
||||
sortPID = true;
|
||||
break;
|
||||
default:
|
||||
help(true);
|
||||
exit(EXIT_FAILURE);
|
||||
@@ -246,8 +254,9 @@ int main(int argc, char **argv) {
|
||||
forceExit(false, "getifaddrs failed while establishing local IP.");
|
||||
}
|
||||
|
||||
bool quiet = output_json;
|
||||
dp_handle *newhandle =
|
||||
dp_open_live(current_dev->name, BUFSIZ, promisc, 100, filter, errbuf);
|
||||
dp_open_live(current_dev->name, BUFSIZ, promisc, 100, filter, errbuf, quiet);
|
||||
if (newhandle != NULL) {
|
||||
dp_addcb(newhandle, dp_packet_ip, process_ip);
|
||||
dp_addcb(newhandle, dp_packet_ip6, process_ip6);
|
||||
@@ -300,7 +309,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
struct dpargs *userdata = (dpargs *)malloc(sizeof(struct dpargs));
|
||||
|
||||
if ((!tracemode) && (!DEBUG)) {
|
||||
if ((!tracemode) && (!DEBUG) && (!output_json)) {
|
||||
init_ui();
|
||||
}
|
||||
|
||||
@@ -328,7 +337,7 @@ int main(int argc, char **argv) {
|
||||
time_t const now = ::time(NULL);
|
||||
if (last_refresh_time + refreshdelay <= now) {
|
||||
last_refresh_time = now;
|
||||
if ((!DEBUG) && (!tracemode)) {
|
||||
if ((!DEBUG) && (!tracemode) && (!output_json)) {
|
||||
// handle user input
|
||||
ui_tick();
|
||||
}
|
||||
|
||||
@@ -59,10 +59,12 @@ bool tracemode = false;
|
||||
bool bughuntmode = false;
|
||||
// sort on sent or received?
|
||||
bool sortRecv = true;
|
||||
bool sortPID = false;
|
||||
bool showcommandline = false;
|
||||
bool showBasename = false;
|
||||
// viewMode: kb/s or total
|
||||
int viewMode = VIEWMODE_KBPS;
|
||||
bool output_json = false;
|
||||
const char version[] = " version " VERSION;
|
||||
timeval curtime;
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ enum {
|
||||
VIEWMODE_TOTAL_MB,
|
||||
VIEWMODE_MBPS,
|
||||
VIEWMODE_GBPS,
|
||||
VIEWMODE_BPS,
|
||||
VIEWMODE_COUNT
|
||||
};
|
||||
|
||||
|
||||
@@ -83,10 +83,12 @@ float togbps(u_int64_t bytes) { return (((double)bytes) / PERIOD) / GB; }
|
||||
|
||||
void process_init() {
|
||||
unknowntcp = new Process(0, "", "unknown TCP");
|
||||
unknowntcp->keep = true;
|
||||
processes = new ProcList(unknowntcp, NULL);
|
||||
|
||||
if (catchall) {
|
||||
unknownudp = new Process(0, "", "unknown UDP");
|
||||
unknownudp->keep = true;
|
||||
processes = new ProcList(unknownudp, processes);
|
||||
// unknownip = new Process (0, "", "unknown IP");
|
||||
// processes = new ProcList (unknownip, processes);
|
||||
@@ -127,6 +129,16 @@ static void sum_active_connections(Process *process_ptr, u_int64_t &sum_sent,
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the b/s values for this process */
|
||||
void Process::getbps(float *recvd, float *sent) {
|
||||
u_int64_t sum_sent = 0, sum_recv = 0;
|
||||
|
||||
sum_active_connections(this, sum_sent, sum_recv);
|
||||
*recvd = sum_recv;
|
||||
*sent = sum_sent;
|
||||
}
|
||||
|
||||
|
||||
/** Get the kb/s values for this process */
|
||||
void Process::getkbps(float *recvd, float *sent) {
|
||||
u_int64_t sum_sent = 0, sum_recv = 0;
|
||||
@@ -439,4 +451,29 @@ void remove_timed_out_processes() {
|
||||
}
|
||||
}
|
||||
|
||||
void garbage_collect_processes() { garbage_collect_inodeproc(); }
|
||||
void garbage_collect_processes()
|
||||
{
|
||||
garbage_collect_inodeproc();
|
||||
|
||||
ProcList *previousproc = NULL;
|
||||
ProcList *curProc = processes;
|
||||
while (curProc != NULL) {
|
||||
Process *curProcVal = curProc->getVal();
|
||||
if (curProcVal->connections.empty() && curProcVal->keep == false) {
|
||||
ProcList *toDelete = curProc;
|
||||
if (previousproc == NULL) {
|
||||
processes = curProc->next;
|
||||
}else
|
||||
{
|
||||
previousproc->next = curProc->next;
|
||||
}
|
||||
curProc = curProc->next;
|
||||
delete curProcVal;
|
||||
delete toDelete;
|
||||
} else {
|
||||
previousproc = curProc;
|
||||
curProc = curProc->next;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ public:
|
||||
rcvd_by_closed_bytes = 0;
|
||||
sent_last_reported = 0;
|
||||
rcvd_last_reported = 0;
|
||||
keep = false;
|
||||
}
|
||||
void check() { assert(pid >= 0); }
|
||||
|
||||
@@ -91,6 +92,7 @@ public:
|
||||
int getLastPacket();
|
||||
|
||||
void gettotal(u_int64_t *recvd, u_int64_t *sent);
|
||||
void getbps(float *recvd, float *sent);
|
||||
void getkbps(float *recvd, float *sent);
|
||||
void getmbps(float *recvd, float *sent);
|
||||
void getgbps(float *recvd, float *sent);
|
||||
@@ -116,6 +118,8 @@ public:
|
||||
|
||||
unsigned long getInode() { return inode; }
|
||||
|
||||
bool keep;
|
||||
|
||||
private:
|
||||
const unsigned long inode;
|
||||
uid_t uid;
|
||||
|
||||
Reference in New Issue
Block a user