aboutsummaryrefslogtreecommitdiffstats
path: root/src/firemon
diff options
context:
space:
mode:
Diffstat (limited to 'src/firemon')
-rw-r--r--src/firemon/Makefile.in24
-rw-r--r--src/firemon/arp.c99
-rw-r--r--src/firemon/caps.c69
-rw-r--r--src/firemon/cgroup.c64
-rw-r--r--src/firemon/cpu.c68
-rw-r--r--src/firemon/firemon.c222
-rw-r--r--src/firemon/firemon.h84
-rw-r--r--src/firemon/interface.c176
-rw-r--r--src/firemon/list.c35
-rw-r--r--src/firemon/netstats.c214
-rw-r--r--src/firemon/procevent.c377
-rw-r--r--src/firemon/route.c213
-rw-r--r--src/firemon/seccomp.c69
-rw-r--r--src/firemon/top.c297
-rw-r--r--src/firemon/tree.c36
-rw-r--r--src/firemon/usage.c77
16 files changed, 2124 insertions, 0 deletions
diff --git a/src/firemon/Makefile.in b/src/firemon/Makefile.in
new file mode 100644
index 000000000..425289695
--- /dev/null
+++ b/src/firemon/Makefile.in
@@ -0,0 +1,24 @@
1all: firemon
2
3PREFIX=@prefix@
4VERSION=@PACKAGE_VERSION@
5NAME=@PACKAGE_NAME@
6
7H_FILE_LIST = $(wildcard *.[h])
8C_FILE_LIST = $(wildcard *.c)
9OBJS = $(C_FILE_LIST:.c=.o)
10BINOBJS = $(foreach file, $(OBJS), $file)
11CFLAGS += -ggdb -O2 -DVERSION='"$(VERSION)"' -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security
12LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now
13
14%.o : %.c $(H_FILE_LIST)
15 $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
16
17firemon: $(OBJS) ../lib/common.o ../lib/pid.o
18 $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/common.o ../lib/pid.o $(LIBS)
19
20clean:; rm -f *.o firemon
21
22distclean: clean
23 rm -fr Makefile
24
diff --git a/src/firemon/arp.c b/src/firemon/arp.c
new file mode 100644
index 000000000..71beb0630
--- /dev/null
+++ b/src/firemon/arp.c
@@ -0,0 +1,99 @@
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#define MAXBUF 4096
22
23static void print_arp(const char *fname) {
24 FILE *fp = fopen(fname, "r");
25 if (!fp)
26 return;
27
28 printf(" ARP Table:\n");
29 char buf[MAXBUF];
30 while (fgets(buf, MAXBUF, fp)) {
31 // remove blanks, \n
32 char *ptr = buf;
33 while (*ptr == ' ' || *ptr == '\t')
34 ptr++;
35 char *start = ptr;
36 if (*start == '\0')
37 continue;
38 ptr = strchr(ptr, '\n');
39 if (ptr)
40 *ptr = '\0';
41
42 // remove table header
43 //IP address HW type Flags HW address Mask Device
44 if (strncmp(start, "IP address", 10) == 0)
45 continue;
46
47 // extract data
48 char ip[64];
49 char type[64];
50 char flags[64];
51 char mac[64];
52 char mask[64];
53 char device[64];
54 int rv = sscanf(start, "%s %s %s %s %s %s\n", ip, type, flags, mac, mask, device);
55 if (rv != 6)
56 continue;
57
58 // destination ip
59 unsigned a, b, c, d;
60 if (sscanf(ip, "%u.%u.%u.%u", &a, &b, &c, &d) != 4 || a > 255 || b > 255 || c > 255 || d > 255)
61 continue;
62 uint32_t destip = a * 0x1000000 + b * 0x10000 + c * 0x100 + d;
63 if (strcmp(flags, "0x0") == 0)
64 printf(" %d.%d.%d.%d dev %s FAILED\n",
65 PRINT_IP(destip), device);
66 else
67 printf(" %d.%d.%d.%d dev %s lladdr %s REACHABLE\n",
68 PRINT_IP(destip), device, mac);
69 }
70
71 fclose(fp);
72
73}
74
75void arp(pid_t pid) {
76 if (getuid() == 0)
77 firemon_drop_privs();
78
79 pid_read(pid);
80
81 // print processes
82 int i;
83 for (i = 0; i < max_pids; i++) {
84 if (pids[i].level == 1) {
85 pid_print_list(i, 0);
86 int child = find_child(i);
87 if (child != -1) {
88 char *fname;
89 if (asprintf(&fname, "/proc/%d/net/arp", child) == -1)
90 errExit("asprintf");
91 print_arp(fname);
92 free(fname);
93 printf("\n");
94 }
95 }
96 }
97}
98
99
diff --git a/src/firemon/caps.c b/src/firemon/caps.c
new file mode 100644
index 000000000..4ae9ab28d
--- /dev/null
+++ b/src/firemon/caps.c
@@ -0,0 +1,69 @@
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#define MAXBUF 4098
22
23static void print_caps(int pid) {
24 char *file;
25 if (asprintf(&file, "/proc/%d/status", pid) == -1) {
26 errExit("asprintf");
27 exit(1);
28 }
29
30 FILE *fp = fopen(file, "r");
31 if (!fp) {
32 printf(" Error: cannot open %s\n", file);
33 free(file);
34 return;
35 }
36
37 char buf[MAXBUF];
38 while (fgets(buf, MAXBUF, fp)) {
39 if (strncmp(buf, "CapBnd:", 7) == 0) {
40 printf(" %s", buf);
41 fflush(0);
42 free(file);
43 fclose(fp);
44 return;
45 }
46 }
47 fclose(fp);
48 free(file);
49}
50
51void caps(pid_t pid) {
52 if (getuid() == 0)
53 firemon_drop_privs();
54
55 pid_read(pid); // include all processes
56
57 // print processes
58 int i;
59 for (i = 0; i < max_pids; i++) {
60 if (pids[i].level == 1) {
61 pid_print_list(i, 0);
62 int child = find_child(i);
63 if (child != -1)
64 print_caps(child);
65 }
66 }
67 printf("\n");
68}
69
diff --git a/src/firemon/cgroup.c b/src/firemon/cgroup.c
new file mode 100644
index 000000000..214aefaf9
--- /dev/null
+++ b/src/firemon/cgroup.c
@@ -0,0 +1,64 @@
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#define MAXBUF 4098
22
23static void print_cgroup(int pid) {
24 char *file;
25 if (asprintf(&file, "/proc/%d/cgroup", pid) == -1) {
26 errExit("asprintf");
27 exit(1);
28 }
29
30 FILE *fp = fopen(file, "r");
31 if (!fp) {
32 printf(" Error: cannot open %s\n", file);
33 free(file);
34 return;
35 }
36
37 char buf[MAXBUF];
38 if (fgets(buf, MAXBUF, fp)) {
39 printf(" %s", buf);
40 fflush(0);
41 }
42
43 fclose(fp);
44 free(file);
45}
46
47void cgroup(pid_t pid) {
48 if (getuid() == 0)
49 firemon_drop_privs();
50
51 pid_read(pid);
52
53 // print processes
54 int i;
55 for (i = 0; i < max_pids; i++) {
56 if (pids[i].level == 1) {
57 pid_print_list(i, 0);
58 int child = find_child(i);
59 if (child != -1)
60 print_cgroup(child);
61 }
62 }
63}
64
diff --git a/src/firemon/cpu.c b/src/firemon/cpu.c
new file mode 100644
index 000000000..d5d20d1b8
--- /dev/null
+++ b/src/firemon/cpu.c
@@ -0,0 +1,68 @@
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#define MAXBUF 4098
22
23static void print_cpu(int pid) {
24 char *file;
25 if (asprintf(&file, "/proc/%d/status", pid) == -1) {
26 errExit("asprintf");
27 exit(1);
28 }
29
30 FILE *fp = fopen(file, "r");
31 if (!fp) {
32 printf(" Error: cannot open %s\n", file);
33 free(file);
34 return;
35 }
36
37 char buf[MAXBUF];
38 while (fgets(buf, MAXBUF, fp)) {
39 if (strncmp(buf, "Cpus_allowed_list:", 18) == 0) {
40 printf(" %s", buf);
41 fflush(0);
42 free(file);
43 fclose(fp);
44 return;
45 }
46 }
47 fclose(fp);
48 free(file);
49}
50
51void cpu(pid_t pid) {
52 if (getuid() == 0)
53 firemon_drop_privs();
54
55 pid_read(pid);
56
57 // print processes
58 int i;
59 for (i = 0; i < max_pids; i++) {
60 if (pids[i].level == 1) {
61 pid_print_list(i, 0);
62 int child = find_child(i);
63 if (child != -1)
64 print_cpu(child);
65 }
66 }
67}
68
diff --git a/src/firemon/firemon.c b/src/firemon/firemon.c
new file mode 100644
index 000000000..d77d11a7a
--- /dev/null
+++ b/src/firemon/firemon.c
@@ -0,0 +1,222 @@
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 <signal.h>
22#include <termios.h>
23#include <sys/ioctl.h>
24#include <sys/prctl.h>
25#include <grp.h>
26
27
28static int arg_route = 0;
29static int arg_arp = 0;
30static int arg_tree = 0;
31static int arg_interface = 0;
32static int arg_seccomp = 0;
33static int arg_caps = 0;
34static int arg_cpu = 0;
35static int arg_cgroup = 0;
36int arg_nowrap = 0;
37
38static struct termios tlocal; // startup terminal setting
39static struct termios twait; // no wait on key press
40static int terminal_set = 0;
41
42static void my_handler(int s){
43 if (terminal_set)
44 tcsetattr(0, TCSANOW, &tlocal);
45 exit(0);
46}
47
48// find the first child process for the specified pid
49// return -1 if not found
50int find_child(int id) {
51 int i;
52 for (i = 0; i < max_pids; i++) {
53 if (pids[i].level == 2 && pids[i].parent == id)
54 return i;
55 }
56
57 return -1;
58}
59
60// drop privileges
61void firemon_drop_privs(void) {
62 // drop privileges
63 if (setgroups(0, NULL) < 0)
64 errExit("setgroups");
65 if (setgid(getgid()) < 0)
66 errExit("setgid/getgid");
67 if (setuid(getuid()) < 0)
68 errExit("setuid/getuid");
69}
70
71// sleep and wait for a key to be pressed
72void firemon_sleep(int st) {
73 if (terminal_set == 0) {
74 tcgetattr(0, &twait); // get current terminal attirbutes; 0 is the file descriptor for stdin
75 memcpy(&tlocal, &twait, sizeof(tlocal));
76 twait.c_lflag &= ~ICANON; // disable canonical mode
77 twait.c_lflag &= ~ECHO; // no echo
78 twait.c_cc[VMIN] = 1; // wait until at least one keystroke available
79 twait.c_cc[VTIME] = 0; // no timeout
80 terminal_set = 1;
81 }
82 tcsetattr(0, TCSANOW, &twait);
83
84
85 fd_set fds;
86 FD_ZERO(&fds);
87 FD_SET(0,&fds);
88 int maxfd = 1;
89
90 struct timeval ts;
91 ts.tv_sec = st;
92 ts.tv_usec = 0;
93
94 int ready = select(maxfd, &fds, (fd_set *) 0, (fd_set *) 0, &ts);
95 (void) ready;
96 if( FD_ISSET(0, &fds)) {
97 getchar();
98 tcsetattr(0, TCSANOW, &tlocal);
99 printf("\n");
100 exit(0);
101 }
102 tcsetattr(0, TCSANOW, &tlocal);
103}
104
105
106int main(int argc, char **argv) {
107 unsigned pid = 0;
108 int i;
109
110 // handle CTRL-C
111 signal (SIGINT, my_handler);
112 signal (SIGTERM, my_handler);
113
114 for (i = 1; i < argc; i++) {
115 // default options
116 if (strcmp(argv[i], "--help") == 0 ||
117 strcmp(argv[i], "-?") == 0) {
118 usage();
119 return 0;
120 }
121 else if (strcmp(argv[i], "--version") == 0) {
122 printf("firemon version %s\n\n", VERSION);
123 return 0;
124 }
125
126 // options without a pid argument
127 else if (strcmp(argv[i], "--top") == 0) {
128 top(); // never to return
129 }
130 else if (strcmp(argv[i], "--list") == 0) {
131 list();
132 return 0;
133 }
134 else if (strcmp(argv[i], "--netstats") == 0) {
135 netstats();
136 return 0;
137 }
138
139
140 // cumulative options with or without a pid argument
141 else if (strcmp(argv[i], "--cgroup") == 0) {
142 arg_cgroup = 1;
143 }
144 else if (strcmp(argv[i], "--cpu") == 0) {
145 arg_cpu = 1;
146 }
147 else if (strcmp(argv[i], "--seccomp") == 0) {
148 arg_seccomp = 1;
149 }
150 else if (strcmp(argv[i], "--caps") == 0) {
151 arg_caps = 1;
152 }
153 else if (strcmp(argv[i], "--tree") == 0) {
154 arg_tree = 1;
155 }
156 else if (strcmp(argv[i], "--interface") == 0) {
157 arg_interface = 1;
158 }
159 else if (strcmp(argv[i], "--route") == 0) {
160 arg_route = 1;
161 }
162 else if (strcmp(argv[i], "--arp") == 0) {
163 arg_arp = 1;
164 }
165
166 else if (strncmp(argv[i], "--name=", 7) == 0) {
167 char *name = argv[i] + 7;
168 if (name2pid(name, (pid_t *) &pid)) {
169 fprintf(stderr, "Error: cannot find sandbox %s\n", name);
170 return 1;
171 }
172 }
173
174 // etc
175 else if (strcmp(argv[i], "--nowrap") == 0)
176 arg_nowrap = 1;
177
178 // invalid option
179 else if (*argv[i] == '-') {
180 fprintf(stderr, "Error: invalid option\n");
181 return 1;
182 }
183
184 // PID argument
185 else {
186 // this should be a pid number
187 char *ptr = argv[i];
188 while (*ptr != '\0') {
189 if (!isdigit(*ptr)) {
190 fprintf(stderr, "Error: not a valid PID number\n");
191 exit(1);
192 }
193 ptr++;
194 }
195
196 sscanf(argv[i], "%u", &pid);
197 break;
198 }
199 }
200
201 if (arg_tree)
202 tree((pid_t) pid);
203 if (arg_interface)
204 interface((pid_t) pid);
205 if (arg_route)
206 route((pid_t) pid);
207 if (arg_arp)
208 arp((pid_t) pid);
209 if (arg_seccomp)
210 seccomp((pid_t) pid);
211 if (arg_caps)
212 caps((pid_t) pid);
213 if (arg_cpu)
214 cpu((pid_t) pid);
215 if (arg_cgroup)
216 cgroup((pid_t) pid);
217
218 if (!arg_route && !arg_arp && !arg_interface && !arg_tree && !arg_caps && !arg_seccomp)
219 procevent((pid_t) pid); // never to return
220
221 return 0;
222}
diff --git a/src/firemon/firemon.h b/src/firemon/firemon.h
new file mode 100644
index 000000000..59b1f352c
--- /dev/null
+++ b/src/firemon/firemon.h
@@ -0,0 +1,84 @@
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#ifndef FIREMON_H
21#define FIREMON_H
22#define _GNU_SOURCE
23#include <stdlib.h>
24#include <stdio.h>
25#include <ctype.h>
26#include <string.h>
27#include <errno.h>
28#include <stdint.h>
29#include "../include/pid.h"
30#include "../include/common.h"
31
32// clear screen
33static inline void firemon_clrscr(void) {
34 printf("\033[2J\033[1;1H");
35 fflush(0);
36}
37
38// firemon.c
39extern int arg_nowrap;
40int find_child(int id);
41void firemon_drop_privs(void);
42void firemon_sleep(int st);
43
44
45// procevent.c
46void procevent(pid_t pid);
47
48// usage.c
49void usage(void);
50
51// top.c
52void top(void);
53
54// list.c
55void list(void);
56
57// interface.c
58void interface(pid_t pid);
59
60// arp.c
61void arp(pid_t pid);
62
63// route.c
64void route(pid_t pid);
65
66// caps.c
67void caps(pid_t pid);
68
69// seccomp.c
70void seccomp(pid_t pid);
71
72// cpu.c
73void cpu(pid_t pid);
74
75// cgroup.c
76void cgroup(pid_t pid);
77
78// tree.c
79void tree(pid_t pid);
80
81// netstats.c
82void netstats(void);
83
84#endif
diff --git a/src/firemon/interface.c b/src/firemon/interface.c
new file mode 100644
index 000000000..52a9c33cd
--- /dev/null
+++ b/src/firemon/interface.c
@@ -0,0 +1,176 @@
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 <sys/types.h>
22#include <sys/wait.h>
23#include <netdb.h>
24#include <arpa/inet.h>
25#include <ifaddrs.h>
26#include <net/if.h>
27#include <linux/connector.h>
28#include <linux/netlink.h>
29#include <linux/if_link.h>
30#include <linux/sockios.h>
31#include <sys/ioctl.h>
32
33//#include <net/route.h>
34//#include <linux/if_bridge.h>
35
36// print IP addresses for all interfaces
37static void net_ifprint(void) {
38 uint32_t ip;
39 uint32_t mask;
40 struct ifaddrs *ifaddr, *ifa;
41
42 int fd;
43 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
44 fprintf(stderr, "Error: cannot open AF_INET socket\n");
45 exit(1);
46 }
47
48 if (getifaddrs(&ifaddr) == -1)
49 errExit("getifaddrs");
50
51 // walk through the linked list
52 printf(" Link status:\n");
53 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
54 if (ifa->ifa_addr == NULL)
55 continue;
56
57 if (ifa->ifa_addr->sa_family == AF_PACKET) {
58 if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP) {
59 if (ifa->ifa_data != NULL) {
60 struct rtnl_link_stats *stats = ifa->ifa_data;
61
62 // extract mac address
63 struct ifreq ifr;
64 memset(&ifr, 0, sizeof(ifr));
65 strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ);
66 int rv = ioctl (fd, SIOCGIFHWADDR, &ifr);
67
68 if (rv == 0)
69 printf(" %s UP, %02x:%02x:%02x:%02x:%02x:%02x\n",
70 ifa->ifa_name, PRINT_MAC((unsigned char *) &ifr.ifr_hwaddr.sa_data));
71 else
72 printf(" %s UP\n", ifa->ifa_name);
73
74 printf(" tx/rx: %u/%u packets, %u/%u bytes\n",
75 stats->tx_packets, stats->rx_packets,
76 stats->tx_bytes, stats->rx_bytes);
77 }
78 }
79 else
80 printf(" %s DOWN\n", ifa->ifa_name);
81 }
82 }
83
84
85 // walk through the linked list
86 printf(" IPv4 status:\n");
87 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
88 if (ifa->ifa_addr == NULL)
89 continue;
90
91 if (ifa->ifa_addr->sa_family == AF_INET) {
92 struct sockaddr_in *si = (struct sockaddr_in *) ifa->ifa_netmask;
93 mask = ntohl(si->sin_addr.s_addr);
94 si = (struct sockaddr_in *) ifa->ifa_addr;
95 ip = ntohl(si->sin_addr.s_addr);
96
97 char *status;
98 if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP)
99 status = "UP";
100 else
101 status = "DOWN";
102
103 printf(" %s %s, %d.%d.%d.%d/%u\n",
104 ifa->ifa_name, status, PRINT_IP(ip), mask2bits(mask));
105 }
106 }
107
108
109 // walk through the linked list
110 printf(" IPv6 status:\n");
111 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
112 if (ifa->ifa_addr == NULL)
113 continue;
114
115 if (ifa->ifa_addr->sa_family == AF_INET6) {
116 char host[NI_MAXHOST];
117 int s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6),
118 host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
119 if (s == 0) {
120 char *ptr;
121 if ((ptr = strchr(host, '%')) != NULL)
122 *ptr = '\0';
123 char *status;
124 if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP)
125 status = "UP";
126 else
127 status = "DOWN";
128
129 printf(" %s %s, %s\n", ifa->ifa_name, status, host);
130 }
131 }
132 }
133
134 freeifaddrs(ifaddr);
135 close(fd);
136}
137
138static void print_sandbox(pid_t pid) {
139 pid_t child = fork();
140 if (child == -1)
141 return;
142
143 if (child == 0) {
144 int rv = join_namespace(pid, "net");
145 if (rv)
146 return;
147 net_ifprint();
148 printf("\n");
149 exit(0);
150 }
151
152 // wait for the child to finish
153 waitpid(child, NULL, 0);
154}
155
156void interface(pid_t pid) {
157 if (getuid() != 0) {
158 fprintf(stderr, "Error: you need to be root to run this command\n");
159 exit(1);
160 }
161
162 pid_read(pid); // a pid of 0 will include all processes
163
164 // print processes
165 int i;
166 for (i = 0; i < max_pids; i++) {
167 if (pids[i].level == 1) {
168 pid_print_list(i, 0);
169 int child = find_child(i);
170 if (child != -1) {
171 print_sandbox(child);
172 }
173 }
174 }
175}
176
diff --git a/src/firemon/list.c b/src/firemon/list.c
new file mode 100644
index 000000000..6a997bde1
--- /dev/null
+++ b/src/firemon/list.c
@@ -0,0 +1,35 @@
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
22void list(void) {
23 if (getuid() == 0)
24 firemon_drop_privs();
25
26 pid_read(0); // include all processes
27
28 // print processes
29 int i;
30 for (i = 0; i < max_pids; i++) {
31 if (pids[i].level == 1)
32 pid_print_list(i, 0);
33 }
34}
35
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
diff --git a/src/firemon/procevent.c b/src/firemon/procevent.c
new file mode 100644
index 000000000..d2b5f7bbf
--- /dev/null
+++ b/src/firemon/procevent.c
@@ -0,0 +1,377 @@
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 <sys/socket.h>
22#include <linux/connector.h>
23#include <linux/netlink.h>
24#include <linux/cn_proc.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <unistd.h>
28#include <arpa/inet.h>
29#include <time.h>
30#define PIDS_BUFLEN 4096
31#define SERVER_PORT 889 // 889-899 is left unassigned by IANA
32
33static int pid_is_firejail(pid_t pid) {
34 uid_t rv = 0;
35
36 // open stat file
37 char *file;
38 if (asprintf(&file, "/proc/%u/status", pid) == -1) {
39 perror("asprintf");
40 exit(1);
41 }
42 FILE *fp = fopen(file, "r");
43 if (!fp) {
44 free(file);
45 return 0;
46 }
47
48 // look for firejail executable name
49 char buf[PIDS_BUFLEN];
50 while (fgets(buf, PIDS_BUFLEN - 1, fp)) {
51 if (strncmp(buf, "Name:", 5) == 0) {
52 char *ptr = buf + 5;
53 while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) {
54 ptr++;
55 }
56 if (*ptr == '\0')
57 goto doexit;
58 if (strncmp(ptr, "firejail", 8) == 0)
59 rv = 1;
60// if (strncmp(ptr, "lxc-execute", 11) == 0)
61// rv = 1;
62 break;
63 }
64 }
65doexit:
66 fclose(fp);
67 free(file);
68 return rv;
69}
70
71
72static int procevent_netlink_setup(void) {
73 // open socket for process event connector
74 int sock;
75 if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR)) < 0) {
76 fprintf(stderr, "Error: cannot open netlink socket\n");
77 exit(1);
78 }
79
80 // bind socket
81 struct sockaddr_nl addr;
82 memset(&addr, 0, sizeof(addr));
83 addr.nl_pid = getpid();
84 addr.nl_family = AF_NETLINK;
85 addr.nl_groups = CN_IDX_PROC;
86 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
87 fprintf(stderr, "Error: cannot bind to netlink socket\n");
88 exit(1);
89 }
90
91 // send monitoring message
92 struct nlmsghdr nlmsghdr;
93 memset(&nlmsghdr, 0, sizeof(nlmsghdr));
94 nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct cn_msg) + sizeof(enum proc_cn_mcast_op));
95 nlmsghdr.nlmsg_pid = getpid();
96 nlmsghdr.nlmsg_type = NLMSG_DONE;
97
98 struct cn_msg cn_msg;
99 memset(&cn_msg, 0, sizeof(cn_msg));
100 cn_msg.id.idx = CN_IDX_PROC;
101 cn_msg.id.val = CN_VAL_PROC;
102 cn_msg.len = sizeof(enum proc_cn_mcast_op);
103
104 struct iovec iov[3];
105 iov[0].iov_base = &nlmsghdr;
106 iov[0].iov_len = sizeof(nlmsghdr);
107 iov[1].iov_base = &cn_msg;
108 iov[1].iov_len = sizeof(cn_msg);
109
110 enum proc_cn_mcast_op op = PROC_CN_MCAST_LISTEN;
111 iov[2].iov_base = &op;
112 iov[2].iov_len = sizeof(op);
113
114 if (writev(sock, iov, 3) == -1) {
115 fprintf(stderr, "Error: cannot write to netlink socket\n");
116 exit(1);
117 }
118
119 return sock;
120}
121
122
123static int procevent_monitor(const int sock, pid_t mypid) {
124 ssize_t len;
125 struct nlmsghdr *nlmsghdr;
126
127 // timeout in order to re-enable firejail module trace
128 struct timeval tv;
129 tv.tv_sec = 30;
130 tv.tv_usec = 0;
131
132 while (1) {
133#define BUFFSIZE 4096
134 char __attribute__ ((aligned(NLMSG_ALIGNTO)))buf[BUFFSIZE];
135
136 fd_set readfds;
137 int max;
138 FD_ZERO(&readfds);
139 FD_SET(sock, &readfds);
140 max = sock;
141 max++;
142
143 int rv = select(max, &readfds, NULL, NULL, &tv);
144 if (rv == -1) {
145 fprintf(stderr, "recv: %s\n", strerror(errno));
146 return -1;
147 }
148
149 // timeout
150 if (rv == 0) {
151 tv.tv_sec = 30;
152 tv.tv_usec = 0;
153 continue;
154 }
155
156
157 if ((len = recv(sock, buf, sizeof(buf), 0)) == 0) {
158 return 0;
159 }
160 if (len == -1) {
161 if (errno == EINTR) {
162 return 0;
163 } else {
164 fprintf(stderr,"recv: %s\n", strerror(errno));
165 return -1;
166 }
167 }
168
169 for (nlmsghdr = (struct nlmsghdr *)buf;
170 NLMSG_OK (nlmsghdr, len);
171 nlmsghdr = NLMSG_NEXT (nlmsghdr, len)) {
172
173 struct cn_msg *cn_msg;
174 struct proc_event *proc_ev;
175 struct tm tm;
176 time_t now;
177
178 if ((nlmsghdr->nlmsg_type == NLMSG_ERROR) ||
179 (nlmsghdr->nlmsg_type == NLMSG_NOOP))
180 continue;
181
182 cn_msg = NLMSG_DATA(nlmsghdr);
183 if ((cn_msg->id.idx != CN_IDX_PROC) ||
184 (cn_msg->id.val != CN_VAL_PROC))
185 continue;
186
187 (void)time(&now);
188 (void)localtime_r(&now, &tm);
189 char line[PIDS_BUFLEN];
190 char *lineptr = line;
191 sprintf(lineptr, "%2.2d:%2.2d:%2.2d", tm.tm_hour, tm.tm_min, tm.tm_sec);
192 lineptr += strlen(lineptr);
193
194 proc_ev = (struct proc_event *)cn_msg->data;
195 pid_t pid = 0;
196 pid_t child = 0;
197 int remove_pid = 0;
198 switch (proc_ev->what) {
199 case PROC_EVENT_FORK:
200 if (proc_ev->event_data.fork.child_pid !=
201 proc_ev->event_data.fork.child_tgid)
202 continue; // this is a thread, not a process
203 pid = proc_ev->event_data.fork.parent_tgid;
204 if (pids[pid].level > 0) {
205 child = proc_ev->event_data.fork.child_tgid;
206 child %= max_pids;
207 pids[child].level = pids[pid].level + 1;
208 pids[child].uid = pid_get_uid(child);
209 }
210 sprintf(lineptr, " fork");
211 break;
212 case PROC_EVENT_EXEC:
213 pid = proc_ev->event_data.exec.process_tgid;
214 sprintf(lineptr, " exec");
215 break;
216
217 case PROC_EVENT_EXIT:
218 if (proc_ev->event_data.exit.process_pid !=
219 proc_ev->event_data.exit.process_tgid)
220 continue; // this is a thread, not a process
221
222 pid = proc_ev->event_data.exit.process_tgid;
223 remove_pid = 1;
224 sprintf(lineptr, " exit");
225 break;
226
227 case PROC_EVENT_UID:
228 pid = proc_ev->event_data.id.process_tgid;
229 sprintf(lineptr, " uid ");
230 break;
231
232 case PROC_EVENT_GID:
233 pid = proc_ev->event_data.id.process_tgid;
234 sprintf(lineptr, " gid ");
235 break;
236
237 case PROC_EVENT_SID:
238 pid = proc_ev->event_data.sid.process_tgid;
239 sprintf(lineptr, " sid ");
240 break;
241
242 default:
243 sprintf(lineptr, "\n");
244 continue;
245 }
246
247 int add_new = 0;
248 if (pids[pid].level < 0) // not a firejail process
249 continue;
250 else if (pids[pid].level == 0) { // new porcess, do we track it?
251 if (pid_is_firejail(pid) && mypid == 0) {
252 pids[pid].level = 1;
253 add_new = 1;
254 }
255 else {
256 pids[pid].level = -1;
257 continue;
258 }
259 }
260
261 lineptr += strlen(lineptr);
262 sprintf(lineptr, " %u", pid);
263 lineptr += strlen(lineptr);
264
265 char *user = pids[pid].user;
266 if (!user)
267 user = pid_get_user_name(pids[pid].uid);
268 if (user) {
269 pids[pid].user = user;
270 sprintf(lineptr, " (%s)", user);
271 lineptr += strlen(lineptr);
272 }
273
274
275 int sandbox_closed = 0; // exit sandbox flag
276 char *cmd = pids[pid].cmd;
277 if (!cmd) {
278 cmd = pid_proc_cmdline(pid);
279 }
280 if (add_new) {
281 if (!cmd)
282 sprintf(lineptr, " NEW SANDBOX\n");
283 else
284 sprintf(lineptr, " NEW SANDBOX: %s\n", cmd);
285 lineptr += strlen(lineptr);
286 }
287 else if (proc_ev->what == PROC_EVENT_EXIT && pids[pid].level == 1) {
288 sprintf(lineptr, " EXIT SANDBOX\n");
289 lineptr += strlen(lineptr);
290 if (mypid == pid)
291 sandbox_closed = 1;
292 }
293 else {
294 if (!cmd) {
295 cmd = pid_proc_cmdline(pid);
296 }
297 if (cmd == NULL)
298 sprintf(lineptr, "\n");
299 else {
300 sprintf(lineptr, " %s\n", cmd);
301 free(cmd);
302 }
303 lineptr += strlen(lineptr);
304 }
305 (void) lineptr;
306
307 // print the event
308 printf("%s", line);
309 fflush(0);
310
311 // unflag pid for exit events
312 if (remove_pid) {
313 if (pids[pid].user)
314 free(pids[pid].user);
315 if (pids[pid].cmd)
316 free(pids[pid].cmd);
317 memset(&pids[pid], 0, sizeof(Process));
318 }
319
320 // print forked child
321 if (child) {
322 cmd = pid_proc_cmdline(child);
323 if (cmd) {
324 printf("\tchild %u %s\n", child, cmd);
325 free(cmd);
326 }
327 else
328 printf("\tchild %u\n", child);
329 }
330
331 // on uid events the uid is changing
332 if (proc_ev->what == PROC_EVENT_UID) {
333 if (pids[pid].user)
334 free(pids[pid].user);
335 pids[pid].user = 0;
336 pids[pid].uid = pid_get_uid(pid);
337 }
338
339 if (sandbox_closed)
340 exit(0);
341 }
342 }
343 return 0;
344}
345
346static void procevent_print_pids(void) {
347 // print files
348 int i;
349 for (i = 0; i < max_pids; i++) {
350 if (pids[i].level == 1)
351 pid_print_tree(i, 0, 1);
352 }
353 printf("\n");
354}
355
356void procevent(pid_t pid) {
357 // need to be root for this
358 if (getuid() != 0) {
359 fprintf(stderr, "Error: you need to be root to get process events\n");
360 exit(1);
361 }
362
363 // read and print sandboxed processes
364 pid_read(pid);
365 procevent_print_pids();
366
367 // monitor using netlink
368 int sock = procevent_netlink_setup();
369 if (sock < 0) {
370 fprintf(stderr, "Error: cannot open netlink socket\n");
371 exit(1);
372 }
373
374 procevent_monitor(sock, pid); // it will never return from here
375 assert(0);
376 close(sock); // quiet static analyzers
377}
diff --git a/src/firemon/route.c b/src/firemon/route.c
new file mode 100644
index 000000000..7f559c7b5
--- /dev/null
+++ b/src/firemon/route.c
@@ -0,0 +1,213 @@
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 <assert.h>
22#include <arpa/inet.h>
23#define MAXBUF 4096
24
25typedef struct iflist_t {
26 struct iflist_t *next;
27 uint32_t ip;
28} IfList;
29static IfList *ifs = NULL;
30static char last_start[MAXBUF + 1];
31
32static IfList *list_find(uint32_t ip, uint32_t mask) {
33 IfList *ptr = ifs;
34 while (ptr) {
35 if ((ptr->ip & mask) == (ip & mask))
36 return ptr;
37 ptr = ptr->next;
38 }
39
40 return NULL;
41}
42
43static void extract_if(const char *fname) {
44 // clear interface list
45 while (ifs) {
46 IfList *tmp = ifs->next;
47 free(ifs);
48 ifs = tmp;
49 }
50 assert(ifs == NULL);
51
52 FILE *fp = fopen(fname, "r");
53 if (!fp)
54 return;
55
56 char buf[MAXBUF];
57 int state = 0; // 0 -wait for Local
58 //
59 while (fgets(buf, MAXBUF, fp)) {
60 // remove blanks, \n
61 char *ptr = buf;
62 while (*ptr == ' ' || *ptr == '\t')
63 ptr++;
64 char *start = ptr;
65 if (*start == '\0')
66 continue;
67 ptr = strchr(ptr, '\n');
68 if (ptr)
69 *ptr = '\0';
70
71 if (state == 0) {
72 if (strncmp(buf, "Local:", 6) == 0) {
73 state = 1;
74 continue;
75 }
76 }
77 else if (state == 1) {
78 // remove broadcast addresses
79 if (strstr(start,"BROADCAST"))
80 continue;
81 else if (*start == '+')
82 continue;
83 else if (*start == '|') {
84 memset(last_start, 0, MAXBUF + 1);
85 strncpy(last_start, start, MAXBUF);
86 continue;
87 }
88 else if (strstr(buf, "LOCAL")) {
89// printf("%s %s\n", last_start, start);
90 unsigned mbits;
91 sscanf(start, "/%u", &mbits);
92 if (mbits != 32)
93 continue;
94
95 unsigned a, b, c, d;
96 if (sscanf(last_start, "|-- %u.%u.%u.%u", &a, &b, &c, &d) != 4 || a > 255 || b > 255 || c > 255 || d > 255)
97 continue;
98
99 IfList *newif = malloc(sizeof(IfList));
100 if (!newif)
101 errExit("malloc");
102 newif->ip = a * 0x1000000 + b * 0x10000 + c * 0x100 + d;
103 newif->next = ifs;
104 ifs = newif;
105 }
106 }
107 }
108
109 fclose(fp);
110
111
112}
113
114static void print_route(const char *fname) {
115 FILE *fp = fopen(fname, "r");
116 if (!fp)
117 return;
118
119 printf(" Route table:\n");
120 char buf[MAXBUF];
121 while (fgets(buf, MAXBUF, fp)) {
122 // remove blanks, \n
123 char *ptr = buf;
124 while (*ptr == ' ' || *ptr == '\t')
125 ptr++;
126 char *start = ptr;
127 if (*start == '\0')
128 continue;
129 ptr = strchr(ptr, '\n');
130 if (ptr)
131 *ptr = '\0';
132
133 // remove table header
134 //Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
135 if (strncmp(start, "Iface", 5) == 0)
136 continue;
137
138 // extract data
139 char ifname[64];
140 char destination[64];
141 char gateway[64];
142 char flags[64];
143 char refcnt[64];
144 char use[64];
145 char metric[64];
146 char mask[64];
147 int rv = sscanf(start, "%s %s %s %s %s %s %s %s\n", ifname, destination, gateway, flags, refcnt, use, metric, mask);
148 if (rv != 8)
149 continue;
150
151 // destination ip
152 uint32_t destip;
153 sscanf(destination, "%x", &destip);
154 destip = ntohl(destip);
155 uint32_t destmask;
156 sscanf(mask, "%x", &destmask);
157 destmask = ntohl(destmask);
158 uint32_t gw;
159 sscanf(gateway, "%x", &gw);
160 gw = ntohl(gw);
161
162// printf("#%s# #%s# #%s# #%s# #%s# #%s# #%s# #%s#\n", ifname, destination, gateway, flags, refcnt, use, metric, mask);
163 if (gw != 0)
164 printf(" %u.%u.%u.%u/%u via %u.%u.%u.%u, dev %s, metric %s\n",
165 PRINT_IP(destip), mask2bits(destmask),
166 PRINT_IP(gw),
167 ifname,
168 metric);
169 else { // this is an interface
170 IfList *ifentry = list_find(destip, destmask);
171 if (ifentry) {
172 printf(" %u.%u.%u.%u/%u, dev %s, scope link src %d.%d.%d.%d\n",
173 PRINT_IP(destip), mask2bits(destmask),
174 ifname,
175 PRINT_IP(ifentry->ip));
176 }
177 }
178 }
179
180 fclose(fp);
181
182}
183
184void route(pid_t pid) {
185 if (getuid() == 0)
186 firemon_drop_privs();
187
188 pid_read(pid);
189
190 // print processes
191 int i;
192 for (i = 0; i < max_pids; i++) {
193 if (pids[i].level == 1) {
194 pid_print_list(i, 0);
195 int child = find_child(i);
196 if (child != -1) {
197 char *fname;
198 if (asprintf(&fname, "/proc/%d/net/fib_trie", child) == -1)
199 errExit("asprintf");
200 extract_if(fname);
201 free(fname);
202
203 if (asprintf(&fname, "/proc/%d/net/route", child) == -1)
204 errExit("asprintf");
205 print_route(fname);
206 free(fname);
207 printf("\n");
208 }
209 }
210 }
211}
212
213
diff --git a/src/firemon/seccomp.c b/src/firemon/seccomp.c
new file mode 100644
index 000000000..4ffc93f2e
--- /dev/null
+++ b/src/firemon/seccomp.c
@@ -0,0 +1,69 @@
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
22#define MAXBUF 4098
23static void print_seccomp(int pid) {
24 char *file;
25 if (asprintf(&file, "/proc/%d/status", pid) == -1) {
26 errExit("asprintf");
27 exit(1);
28 }
29
30 FILE *fp = fopen(file, "r");
31 if (!fp) {
32 printf(" Error: cannot open %s\n", file);
33 free(file);
34 return;
35 }
36
37 char buf[MAXBUF];
38 while (fgets(buf, MAXBUF, fp)) {
39 if (strncmp(buf, "Seccomp:", 8) == 0) {
40 printf(" %s", buf);
41 fflush(0);
42 fclose(fp);
43 free(file);
44 return;
45 }
46 }
47 fclose(fp);
48 free(file);
49}
50
51void seccomp(pid_t pid) {
52 if (getuid() == 0)
53 firemon_drop_privs();
54
55 pid_read(pid); // include all processes
56
57 // print processes
58 int i;
59 for (i = 0; i < max_pids; i++) {
60 if (pids[i].level == 1) {
61 pid_print_list(i, 0);
62 int child = find_child(i);
63 if (child != -1)
64 print_seccomp(child);
65 }
66 }
67 printf("\n");
68}
69
diff --git a/src/firemon/top.c b/src/firemon/top.c
new file mode 100644
index 000000000..1eb753694
--- /dev/null
+++ b/src/firemon/top.c
@@ -0,0 +1,297 @@
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
27static unsigned pgs_rss = 0;
28static unsigned pgs_shared = 0;
29static unsigned clocktick = 0;
30static unsigned long long sysuptime = 0;
31
32static char *get_header(void) {
33 char *rv;
34 if (asprintf(&rv, "%-5.5s %-9.9s %-8.8s %-8.8s %-5.5s %-4.4s %-9.9s %s",
35 "PID", "User", "RES(KiB)", "SHR(KiB)", "CPU%", "Prcs", "Uptime", "Command") == -1)
36 errExit("asprintf");
37
38 return rv;
39}
40
41
42// recursivity!!!
43static char *print_top(unsigned index, unsigned parent, unsigned *utime, unsigned *stime, unsigned itv, float *cpu, int *cnt) {
44 char *rv = NULL;
45
46 char procdir[20];
47 snprintf(procdir, 20, "/proc/%u", index);
48 struct stat s;
49 if (stat(procdir, &s) == -1)
50 return NULL;
51
52 if (pids[index].level == 1) {
53 pgs_rss = 0;
54 pgs_shared = 0;
55 *utime = 0;
56 *stime = 0;
57 *cnt = 0;
58 }
59
60 (*cnt)++;
61 pid_getmem(index, &pgs_rss, &pgs_shared);
62 unsigned utmp;
63 unsigned stmp;
64 pid_get_cpu_time(index, &utmp, &stmp);
65 *utime += utmp;
66 *stime += stmp;
67
68
69 int i;
70 for (i = index + 1; i < max_pids; i++) {
71 if (pids[i].parent == index)
72 print_top(i, index, utime, stime, itv, cpu, cnt);
73 }
74
75 if (pids[index].level == 1) {
76 // pid
77 char pidstr[10];
78 snprintf(pidstr, 10, "%u", index);
79
80 // command
81 char *cmd = pid_proc_cmdline(index);
82 char *ptrcmd;
83 if (cmd == NULL) {
84 if (pids[index].zombie)
85 ptrcmd = "(zombie)";
86 else
87 ptrcmd = "";
88 }
89 else
90 ptrcmd = cmd;
91
92 // user
93 char *user = pid_get_user_name(pids[index].uid);
94 char *ptruser;
95 if (user)
96 ptruser = user;
97 else
98 ptruser = "";
99
100 // memory
101 int pgsz = getpagesize();
102 char rss[10];
103 snprintf(rss, 10, "%u", pgs_rss * pgsz / 1024);
104 char shared[10];
105 snprintf(shared, 10, "%u", pgs_shared * pgsz / 1024);
106
107 // uptime
108 unsigned long long uptime = pid_get_start_time(index);
109 if (clocktick == 0)
110 clocktick = sysconf(_SC_CLK_TCK);
111 uptime /= clocktick;
112 uptime = sysuptime - uptime;
113 unsigned sec = uptime % 60;
114 uptime -= sec;
115 uptime /= 60;
116 unsigned min = uptime % 60;
117 uptime -= min;
118 uptime /= 60;
119 unsigned hour = uptime;
120 char uptime_str[50];
121 snprintf(uptime_str, 50, "%02u:%02u:%02u", hour, min, sec);
122
123 // cpu
124 itv *= clocktick;
125 float ud = (float) (*utime - pids[index].utime) / itv * 100;
126 float sd = (float) (*stime - pids[index].stime) / itv * 100;
127 float cd = ud + sd;
128 *cpu = cd;
129 char cpu_str[10];
130 snprintf(cpu_str, 10, "%2.1f", cd);
131
132 // process count
133 char prcs_str[10];
134 snprintf(prcs_str, 10, "%d", *cnt);
135
136 if (asprintf(&rv, "%-5.5s %-9.9s %-8.8s %-8.8s %-5.5s %-4.4s %-9.9s %s",
137 pidstr, ptruser, rss, shared, cpu_str, prcs_str, uptime_str, ptrcmd) == -1)
138 errExit("asprintf");
139
140 if (cmd)
141 free(cmd);
142 if (user)
143 free(user);
144
145 }
146
147 return rv;
148}
149
150
151typedef struct node_t {
152 struct node_t *next;
153 char *line;
154 float cpu;
155} Node;
156
157static Node *head = NULL;
158
159static void head_clear(void) {
160 Node *ptr = head;
161 while (ptr) {
162 if (ptr->line)
163 free(ptr->line);
164 Node *next = ptr->next;
165 free(ptr);
166 ptr = next;
167 }
168
169 head = NULL;
170}
171
172static void head_add(float cpu, char *line) {
173 // allocate a new node structure
174 Node *node = malloc(sizeof(Node));
175 if (!node)
176 errExit("malloc");
177 node->line = line;
178 node->cpu = cpu;
179 node->next = NULL;
180
181 // insert in first list position
182 if (head == NULL || head->cpu < cpu) {
183 node->next = head;
184 head = node;
185 return;
186 }
187
188 // insert in the right place
189 Node *ptr = head;
190 while (1) {
191 // last position
192 Node *current = ptr->next;
193 if (current == NULL) {
194 ptr->next = node;
195 return;
196 }
197
198 // current position
199 if (current->cpu < cpu) {
200 ptr->next = node;
201 node->next = current;
202 return;
203 }
204
205 ptr = current;
206 }
207}
208
209void head_print(int col, int row) {
210 Node *ptr = head;
211 int current = 0;
212 while (ptr) {
213 if (current >= row)
214 break;
215
216 if (strlen(ptr->line) > col)
217 ptr->line[col] = '\0';
218
219 if (ptr->next == NULL || current == (row - 1)) {
220 printf("%s", ptr->line);
221 fflush(0);
222 }
223 else
224 printf("%s\n", ptr->line);
225
226 ptr = ptr->next;
227 current++;
228 }
229}
230
231void top(void) {
232 if (getuid() == 0)
233 firemon_drop_privs();
234
235 while (1) {
236 // clear linked list
237 head_clear();
238
239 // set pid table
240 int i;
241 int itv = 5; // 5 second interval
242 pid_read(0);
243
244 // start cpu measurements
245 unsigned utime = 0;
246 unsigned stime = 0;
247 for (i = 0; i < max_pids; i++) {
248 if (pids[i].level == 1)
249 pid_store_cpu(i, 0, &utime, &stime);
250 }
251
252 // wait 5 seconds
253 firemon_sleep(itv);
254
255 // grab screen size
256 struct winsize sz;
257 int row = 24;
258 int col = 80;
259 if (!ioctl(0, TIOCGWINSZ, &sz)) {
260 col = sz.ws_col;
261 row = sz.ws_row;
262 }
263
264 // start printing
265 firemon_clrscr();
266 char *header = get_header();
267 if (strlen(header) > col)
268 header[col] = '\0';
269 printf("%s\n", header);
270 if (row > 0)
271 row--;
272 free(header);
273
274 // find system uptime
275 FILE *fp = fopen("/proc/uptime", "r");
276 if (fp) {
277 float f;
278 int rv = fscanf(fp, "%f", &f);
279 (void) rv;
280 sysuptime = (unsigned long long) f;
281 fclose(fp);
282 }
283
284 // print processes
285 for (i = 0; i < max_pids; i++) {
286 if (pids[i].level == 1) {
287 float cpu = 0;
288 int cnt = 0; // process count
289 char *line = print_top(i, 0, &utime, &stime, itv, &cpu, &cnt);
290 if (line)
291 head_add(cpu, line);
292 }
293 }
294 head_print(col, row);
295 }
296}
297
diff --git a/src/firemon/tree.c b/src/firemon/tree.c
new file mode 100644
index 000000000..97e0e1f13
--- /dev/null
+++ b/src/firemon/tree.c
@@ -0,0 +1,36 @@
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
22void tree(pid_t pid) {
23 if (getuid() == 0)
24 firemon_drop_privs();
25
26 pid_read(pid); // include all processes
27
28 // print processes
29 int i;
30 for (i = 0; i < max_pids; i++) {
31 if (pids[i].level == 1)
32 pid_print_tree(i, 0, arg_nowrap);
33 }
34 printf("\n");
35}
36
diff --git a/src/firemon/usage.c b/src/firemon/usage.c
new file mode 100644
index 000000000..52788807a
--- /dev/null
+++ b/src/firemon/usage.c
@@ -0,0 +1,77 @@
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
22void usage(void) {
23 printf("firemon - version %s\n", VERSION);
24 printf("Usage: firemon [OPTIONS] [PID]\n\n");
25 printf("Monitor processes started in a Firejail sandbox. Without any PID specified,\n");
26 printf("all processes started by Firejail are monitored. Descendants of these processes\n");
27 printf("are also being monitored.\n\n");
28 printf("Options:\n");
29 printf("\t--arp - print ARP table for each sandbox.\n\n");
30 printf("\t--caps - print capabilities configuration for each sandbox.\n\n");
31 printf("\t--cgroup - print control group information for each sandbox.\n\n");
32 printf("\t--cpu - print CPU affinity for each sandbox.\n\n");
33 printf("\t--help, -? - this help screen.\n\n");
34 printf("\t--interface - print network interface information for each sandbox.\n\n");
35 printf("\t--list - list all sandboxes.\n\n");
36 printf("\t--name=name - print information only about named sandbox.\n\n");
37 printf("\t--netstats - monitor network statistics for sandboxes creating a new\n");
38 printf("\t\tnetwork namespace.\n\n");
39 printf("\t--route - print route table for each sandbox.\n\n");
40 printf("\t--seccomp - print seccomp configuration for each sandbox.\n\n");
41 printf("\t--tree - print a tree of all sandboxed processes.\n\n");
42 printf("\t--top - monitor the most CPU-intensive sandboxes.\n\n");
43 printf("\t--version - print program version and exit.\n\n");
44
45 printf("Without any options, firemon monitors all fork, exec, id change, and exit events\n");
46 printf("in the sandbox. Monitoring a specific PID is also supported.\n\n");
47
48 printf("Option --list prints a list of all sandboxes. The format for each entry is as\n");
49 printf("follows:\n\n");
50 printf("\tPID:USER:Command\n\n");
51
52 printf("Option --tree prints the tree of processes running in the sandbox. The format\n");
53 printf("for each process entry is as follows:\n\n");
54 printf("\tPID:USER:Command\n\n");
55
56 printf("Option --top is similar to the UNIX top command, however it applies only to\n");
57 printf("sandboxes. Listed below are the available fields (columns) in alphabetical\n");
58 printf("order:\n\n");
59 printf("\tCommand - command used to start the sandbox.\n");
60 printf("\tCPU%% - CPU usage, the sandbox share of the elapsed CPU time since the\n");
61 printf("\t last screen update\n");
62 printf("\tPID - Unique process ID for the task controlling the sandbox.\n");
63 printf("\tPrcs - number of processes running in sandbox, including the controlling\n");
64 printf("\t process.\n");
65 printf("\tRES - Resident Memory Size (KiB), sandbox non-swapped physical memory.\n");
66 printf("\t It is a sum of the RES values for all processes running in the\n");
67 printf("\t sandbox.\n");
68 printf("\tSHR - Shared Memory Size (KiB), it reflects memory shared with other\n");
69 printf("\t processes. It is a sum of the SHR values for all processes running\n");
70 printf("\t in the sandbox, including the controlling process.\n");
71 printf("\tUptime - sandbox running time in hours:minutes:seconds format.\n");
72 printf("\tUser - The owner of the sandbox.\n");
73 printf("\n");
74 printf("License GPL version 2 or later\n");
75 printf("Homepage: http://firejail.sourceforge.net\n");
76 printf("\n");
77}