aboutsummaryrefslogtreecommitdiffstats
path: root/src/firemon/netstats.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firemon/netstats.c')
-rw-r--r--src/firemon/netstats.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/firemon/netstats.c b/src/firemon/netstats.c
new file mode 100644
index 000000000..6c4a767f1
--- /dev/null
+++ b/src/firemon/netstats.c
@@ -0,0 +1,214 @@
1/*
2 * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com)
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#include "firemon.h"
21#include <termios.h>
22#include <sys/ioctl.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <unistd.h>
26
27#define MAXBUF 4096
28
29static char *get_header(void) {
30 char *rv;
31 if (asprintf(&rv, "%-5.5s %-9.9s %-10.10s %-10.10s %s",
32 "PID", "User", "RX(KB/s)", "TX(KB/s)", "Command") == -1)
33 errExit("asprintf");
34
35 return rv;
36}
37
38void get_stats(int parent) {
39 // find the first child
40 int child = -1;
41 for (child = parent + 1; child < max_pids; child++) {
42 if (pids[child].parent == parent)
43 break;
44 }
45
46 if (child == -1)
47 goto errexit;
48
49 // open /proc/child/net/dev file and read rx and tx
50 char *fname;
51 if (asprintf(&fname, "/proc/%d/net/dev", child) == -1)
52 errExit("asprintf");
53 FILE *fp = fopen(fname, "r");
54 if (!fp) {
55 free(fname);
56 goto errexit;
57 }
58
59 char buf[MAXBUF];
60 long long unsigned rx = 0;
61 long long unsigned tx = 0;
62 while (fgets(buf, MAXBUF, fp)) {
63 if (strncmp(buf, "Inter", 5) == 0)
64 continue;
65 if (strncmp(buf, " face", 5) == 0)
66 continue;
67
68 char *ptr = buf;
69 while (*ptr != '\0' && *ptr != ':') {
70 ptr++;
71 }
72
73 if (*ptr == '\0') {
74 fclose(fp);
75 free(fname);
76 goto errexit;
77 }
78 ptr++;
79
80 long long unsigned rxval;
81 long long unsigned txval;
82 unsigned a, b, c, d, e, f, g;
83 sscanf(ptr, "%llu %u %u %u %u %u %u %u %llu",
84 &rxval, &a, &b, &c, &d, &e, &f, &g, &txval);
85 rx += rxval;
86 tx += txval;
87 }
88
89 // store data
90 pids[parent].rx_delta = rx - pids[parent].rx;
91 pids[parent].rx = rx;
92 pids[parent].tx_delta = tx - pids[parent].tx;
93 pids[parent].tx = tx;
94
95
96 free(fname);
97 fclose(fp);
98 return;
99
100errexit:
101 pids[parent].rx = 0;
102 pids[parent].tx = 0;
103 pids[parent].rx_delta = 0;
104 pids[parent].tx_delta = 0;
105}
106
107
108static void print_proc(int index, int itv, int col) {
109 // command
110 char *cmd = pid_proc_cmdline(index);
111 char *ptrcmd;
112 if (cmd == NULL) {
113 if (pids[index].zombie)
114 ptrcmd = "(zombie)";
115 else
116 ptrcmd = "";
117 }
118 else
119 ptrcmd = cmd;
120 // if the command doesn't have a --net= option, don't print
121 if (strstr(ptrcmd, "--net=") == NULL) {
122 if (cmd)
123 free(cmd);
124 return;
125 }
126
127 // pid
128 char pidstr[10];
129 snprintf(pidstr, 10, "%u", index);
130
131 // user
132 char *user = pid_get_user_name(pids[index].uid);
133 char *ptruser;
134 if (user)
135 ptruser = user;
136 else
137 ptruser = "";
138
139
140 float rx_kbps = ((float) pids[index].rx_delta / 1000) / itv;
141 char ptrrx[15];
142 sprintf(ptrrx, "%.03f", rx_kbps);
143
144 float tx_kbps = ((float) pids[index].tx_delta / 1000) / itv;
145 char ptrtx[15];
146 sprintf(ptrtx, "%.03f", tx_kbps);
147
148 char buf[1024 + 1];
149 snprintf(buf, 1024, "%-5.5s %-9.9s %-10.10s %-10.10s %s",
150 pidstr, ptruser, ptrrx, ptrtx, ptrcmd);
151 if (col < 1024)
152 buf[col] = '\0';
153 printf("%s\n", buf);
154
155 if (cmd)
156 free(cmd);
157 if (user)
158 free(user);
159
160}
161
162void netstats(void) {
163 if (getuid() == 0)
164 firemon_drop_privs();
165
166 pid_read(0); // include all processes
167
168 printf("Displaying network statistics only for sandboxes using a new network namespace.\n");
169
170 // print processes
171 while (1) {
172 // set pid table
173 int i;
174 int itv = 5; // 5 second interval
175 pid_read(0); // todo: preserve the last calculation if any, so we don't have to do get_stats()
176
177 // start rx/tx measurements
178 for (i = 0; i < max_pids; i++) {
179 if (pids[i].level == 1)
180 get_stats(i);
181 }
182
183 // wait 5 seconds
184 firemon_sleep(itv);
185
186 // grab screen size
187 struct winsize sz;
188 int row = 24;
189 int col = 80;
190 if (!ioctl(0, TIOCGWINSZ, &sz)) {
191 col = sz.ws_col;
192 row = sz.ws_row;
193 }
194
195 // start printing
196 firemon_clrscr();
197 char *header = get_header();
198 if (strlen(header) > col)
199 header[col] = '\0';
200 printf("%s\n", header);
201 if (row > 0)
202 row--;
203 free(header);
204
205 // start rx/tx measurements
206 for (i = 0; i < max_pids; i++) {
207 if (pids[i].level == 1) {
208 get_stats(i);
209 print_proc(i, itv, col);
210 }
211 }
212 }
213}
214