1 /*
2 KSysGuard, the KDE System Guard
3
4 Copyright (c) 2001 Tobias Koenig <tokoe@kde.org>
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of version 2 of the GNU General Public
8 License as published by the Free Software Foundation.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
19 */
20
21 #include <config-workspace.h>
22
23 #define _POSIX_SOURCE /* expose old gethostbyaddr(3) call */
24 #include <arpa/inet.h>
25 #include <netdb.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32
33 #include "ksysguardd.h"
34 #include "Command.h"
35 #include "ccont.h"
36 #include "netstat.h"
37
38 static CONTAINER TcpSocketList = 0;
39 static CONTAINER UdpSocketList = 0;
40 static CONTAINER UnixSocketList = 0;
41 static CONTAINER RawSocketList = 0;
42
43 static int num_tcp = 0;
44 static int num_udp = 0;
45 static int num_unix = 0;
46 static int num_raw = 0;
47
48 typedef struct {
49 char local_addr[128];
50 char local_port[128];
51 char remote_addr[128];
52 char remote_port[128];
53 char state[128];
54 int uid;
55 } SocketInfo;
56
57 typedef struct {
58 int refcount;
59 char type[128];
60 char state[128];
61 int inode;
62 char path[256];
63 } UnixInfo;
64
65 char *get_serv_name(int port, const char *proto);
66 char *get_host_name(int addr);
67 char *get_proto_name(int number);
68 int get_num_sockets(FILE *netstat);
69 void printSocketInfo(SocketInfo* socket_info);
70
71 static time_t TcpUdpRaw_timeStamp = 0;
72 static time_t Unix_timeStamp = 0;
73 static time_t NetStat_timeStamp = 0;
74
75 static const char * const raw_type[] =
76 {
77 "",
78 "stream",
79 "dgram",
80 "raw",
81 "rdm",
82 "seqpacket",
83 "packet"
84 };
85
86 static const char * const raw_state[] =
87 {
88 "free",
89 "unconnected",
90 "connecting",
91 "connected",
92 "disconnecting"
93 };
94
95 static const char * const conn_state[] =
96 {
97 "",
98 "established",
99 "syn_sent",
100 "syn_recv",
101 "fin_wait1",
102 "fin_wait2",
103 "time_wait",
104 "close",
105 "close_wait",
106 "last_ack",
107 "listen",
108 "closing"
109 };
110
get_serv_name(int port,const char * proto)111 char *get_serv_name(int port, const char *proto)
112 {
113 static char buffer[1024];
114 struct servent *service;
115
116 if (port == 0) {
117 return (char *)"*";
118 }
119
120 if ((service = getservbyport(ntohs(port), proto)) == NULL)
121 snprintf(buffer, sizeof(buffer)-1, "%d", port);
122 else
123 strncpy(buffer, service->s_name, sizeof(buffer)-1);
124 buffer[sizeof(buffer) -1] = 0;
125
126 return (char *)buffer;
127 }
128
get_host_name(int addr)129 char *get_host_name(int addr)
130 {
131 static char buffer[1024];
132 struct hostent *host;
133 struct in_addr a_addr;
134
135 if (addr == 0) {
136 return (char *)"*";
137 }
138
139 memset(buffer, 0, sizeof(buffer));
140
141 if ((host = gethostbyaddr((char *)&addr, 4, AF_INET)) == NULL) {
142 a_addr.s_addr = addr;
143 return inet_ntoa(a_addr);
144 } else {
145 strncpy(buffer, host->h_name, sizeof(buffer)-1);
146 buffer[sizeof(buffer) -1] = 0;
147 return (char *)buffer;
148 }
149 }
150
get_proto_name(int number)151 char *get_proto_name(int number)
152 {
153 static char buffer[1024];
154 struct protoent *protocol;
155
156 if (number == 0) {
157 return (char *)"*";
158 }
159
160 if ((protocol = getprotobynumber(number)) == NULL)
161 snprintf(buffer, sizeof(buffer)-1, "%d", number);
162 else
163 strncpy(buffer, protocol->p_name, sizeof(buffer)-1);
164 buffer[sizeof(buffer) -1] = 0;
165
166 return (char *)buffer;
167 }
168
get_num_sockets(FILE * netstat)169 int get_num_sockets(FILE *netstat)
170 {
171 char line[1024];
172 int line_count = 0;
173 while (fgets(line, 1024, netstat) != NULL)
174 line_count++;
175
176 return line_count - 1;
177 }
178
printSocketInfo(SocketInfo * socket_info)179 void printSocketInfo(SocketInfo* socket_info)
180 {
181 output( "%s\t%s\t%s\t%s\t%s\t%d\n",
182 socket_info->local_addr,
183 socket_info->local_port,
184 socket_info->remote_addr,
185 socket_info->remote_port,
186 socket_info->state,
187 socket_info->uid);
188 }
189
190 /*
191 ================================ public part =================================
192 */
193
194 void
initNetStat(struct SensorModul * sm)195 initNetStat(struct SensorModul* sm)
196 {
197 FILE *netstat;
198
199 if ((netstat = fopen("/proc/net/tcp", "r")) != NULL) {
200 registerMonitor("network/sockets/tcp/count", "integer", printNetStat, printNetStatInfo, sm);
201 /* This monitor takes _way_ too much time (up to a minute, or more) since it does DNS lookups
202 Hide the monitor, leaving it there for backwards compatibility */
203 registerLegacyMonitor("network/sockets/tcp/list", "listview", printNetStatTcpUdpRaw, printNetStatTcpUdpRawInfo, sm);
204 fclose(netstat);
205 }
206 if ((netstat = fopen("/proc/net/udp", "r")) != NULL) {
207 registerMonitor("network/sockets/udp/count", "integer", printNetStat, printNetStatInfo, sm);
208 registerMonitor("network/sockets/udp/list", "listview", printNetStatTcpUdpRaw, printNetStatTcpUdpRawInfo, sm);
209 fclose(netstat);
210 }
211 if ((netstat = fopen("/proc/net/unix", "r")) != NULL) {
212 registerMonitor("network/sockets/unix/count", "integer", printNetStat, printNetStatInfo, sm);
213 registerMonitor("network/sockets/unix/list", "listview", printNetStatUnix, printNetStatUnixInfo, sm);
214 fclose(netstat);
215 }
216 if ((netstat = fopen("/proc/net/raw", "r")) != NULL) {
217 registerMonitor("network/sockets/raw/count", "integer", printNetStat, printNetStatInfo, sm);
218 registerMonitor("network/sockets/raw/list", "listview", printNetStatTcpUdpRaw, printNetStatTcpUdpRawInfo, sm);
219 fclose(netstat);
220 }
221
222 TcpSocketList = new_ctnr();
223 UdpSocketList = new_ctnr();
224 RawSocketList = new_ctnr();
225 UnixSocketList = new_ctnr();
226 }
227
228 void
exitNetStat(void)229 exitNetStat(void)
230 {
231 destr_ctnr(TcpSocketList, free);
232 destr_ctnr(UdpSocketList, free);
233 destr_ctnr(RawSocketList, free);
234 destr_ctnr(UnixSocketList, free);
235 }
236
237 int
updateNetStat(void)238 updateNetStat(void)
239 {
240 FILE *netstat;
241
242 if ((netstat = fopen("/proc/net/tcp", "r")) != NULL) {
243 num_tcp = get_num_sockets(netstat);
244 fclose(netstat);
245 }
246
247 if ((netstat = fopen("/proc/net/udp", "r")) != NULL) {
248 num_udp = get_num_sockets(netstat);
249 fclose(netstat);
250 }
251
252 if ((netstat = fopen("/proc/net/unix", "r")) != NULL) {
253 num_unix = get_num_sockets(netstat);
254 fclose(netstat);
255 }
256 if ((netstat = fopen("/proc/net/raw", "r")) != NULL) {
257 num_raw = get_num_sockets(netstat);
258 fclose(netstat);
259 }
260
261 NetStat_timeStamp = time(0);
262 return 0;
263 }
264
265 int
updateNetStatTcpUdpRaw(const char * cmd)266 updateNetStatTcpUdpRaw(const char *cmd)
267 {
268 FILE *netstat;
269 char buffer[1024];
270 unsigned local_addr, local_port;
271 unsigned remote_addr, remote_port;
272 int uid;
273 unsigned state;
274 SocketInfo *socket_info;
275
276 if (strstr(cmd, "tcp")) {
277 snprintf(buffer, sizeof(buffer), "/proc/net/tcp");
278 empty_ctnr(TcpSocketList);
279 }
280 else if (strstr(cmd, "udp")) {
281 snprintf(buffer, sizeof(buffer), "/proc/net/udp");
282 empty_ctnr(UdpSocketList);
283 }
284 else if (strstr(cmd, "raw")) {
285 snprintf(buffer, sizeof(buffer), "/proc/net/raw");
286 empty_ctnr(RawSocketList);
287 }
288 else {
289 print_error("cmd needs to be [tcp|udp|raw], is %s\n", cmd);
290 return -1;
291 }
292
293 if ((netstat = fopen(buffer, "r")) == NULL) {
294 print_error("Cannot open \'%s\'!\n"
295 "The kernel needs to be compiled with support\n"
296 "for /proc file system enabled!\n", buffer);
297 return -1;
298 }
299
300 while (fgets(buffer, sizeof(buffer), netstat) != NULL) {
301 if (buffer[0] != 0) {
302 int matches = sscanf(buffer, "%*d: %x:%x %x:%x %x %*x:%*x %*x:%*x %d",
303 &local_addr, &local_port,
304 &remote_addr, &remote_port,
305 &state,
306 &uid);
307 if(matches != 6)
308 continue;
309
310 if ((socket_info = (SocketInfo *)malloc(sizeof(SocketInfo))) == NULL) {
311 continue;
312 }
313 strncpy(socket_info->local_addr, get_host_name(local_addr), sizeof(socket_info->local_addr)-1);
314 socket_info->local_addr[ sizeof(socket_info->local_addr)-1] = 0;
315 strncpy(socket_info->remote_addr, get_host_name(remote_addr), sizeof(socket_info->remote_addr)-1);
316 socket_info->remote_addr[ sizeof(socket_info->remote_addr)-1] = 0;
317
318 if (strstr(cmd, "tcp")) {
319 strncpy(socket_info->local_port, get_serv_name(local_port, "tcp"), sizeof(socket_info->local_port)-1);
320 socket_info->local_port[sizeof(socket_info->local_port)-1] = 0;
321 strncpy(socket_info->remote_port, get_serv_name(remote_port, "tcp"), sizeof(socket_info->remote_port)-1);
322 socket_info->remote_port[sizeof(socket_info->remote_port)-1] = 0;
323
324 strncpy(socket_info->state, conn_state[state], sizeof(socket_info->state));
325 socket_info->state[sizeof(socket_info->state)-1] = 0;
326 socket_info->uid = uid;
327
328 push_ctnr(TcpSocketList, socket_info);
329 }
330
331 if (strstr(cmd, "udp")) {
332 strncpy(socket_info->local_port, get_serv_name(local_port, "udp"), sizeof(socket_info->local_port)-1);
333 socket_info->local_port[sizeof(socket_info->local_port)-1] = 0;
334 strncpy(socket_info->remote_port, get_serv_name(remote_port, "udp"), sizeof(socket_info->remote_port)-1);
335 socket_info->remote_port[sizeof(socket_info->remote_port)-1] = 0;
336
337 strncpy(socket_info->state, conn_state[state], sizeof(socket_info->state)-1);
338 socket_info->state[sizeof(socket_info->state)-1] = 0;
339
340 socket_info->uid = uid;
341
342 push_ctnr(UdpSocketList, socket_info);
343 }
344
345 if (strstr(cmd, "raw")) {
346 strncpy(socket_info->local_port, get_proto_name(local_port), sizeof(socket_info->local_port)-1);
347 socket_info->local_port[sizeof(socket_info->local_port)-1] = 0;
348 strncpy(socket_info->remote_port, get_proto_name(remote_port), sizeof(socket_info->remote_port)-1);
349 socket_info->remote_port[sizeof(socket_info->remote_port)-1] = 0;
350 snprintf(socket_info->state, sizeof(socket_info->state)-1, "%d", state);
351 socket_info->state[sizeof(socket_info->state)-1] = 0;
352 socket_info->uid = uid;
353
354 push_ctnr(RawSocketList, socket_info);
355 }
356 }
357 }
358 fclose(netstat);
359 TcpUdpRaw_timeStamp = time(0);
360
361 return 0;
362 }
363
364 int
updateNetStatUnix(void)365 updateNetStatUnix(void)
366 {
367 FILE *file;
368 char buffer[1024];
369 char path[256];
370 int ref_count, type, state, inode;
371 UnixInfo *unix_info;
372
373 if ((file = fopen("/proc/net/unix", "r")) == NULL) {
374 print_error("Cannot open \'/proc/net/unix\'!\n"
375 "The kernel needs to be compiled with support\n"
376 "for /proc file system enabled!\n");
377 return -1;
378 }
379
380 empty_ctnr(UnixSocketList);
381
382 while (fgets(buffer, sizeof(buffer), file) != NULL) {
383 if(buffer[0] != 0) {
384 buffer[1023] = 0;
385 int matches = sscanf(buffer, "%*x: %d %*d %*d %d %d %d %255s",
386 &ref_count, &type, &state, &inode, path);
387 path[255] = 0;
388 if(matches <= 3)
389 continue;
390
391 if ((unix_info = (UnixInfo *)malloc(sizeof(UnixInfo))) == NULL) {
392 continue;
393 }
394
395 unix_info->refcount = ref_count;
396 strncpy(unix_info->type, raw_type[type], sizeof(unix_info->type)-1);
397 unix_info->type[ sizeof(unix_info->type)-1] = 0;
398 strncpy(unix_info->state, raw_state[state], sizeof(unix_info->state)-1);
399 unix_info->state[ sizeof(unix_info->state)-1] = 0;
400 unix_info->inode = inode;
401 strncpy(unix_info->path, path, sizeof(unix_info->path)-1);
402 unix_info->path[ sizeof(unix_info->path)-1] = 0;
403
404 push_ctnr(UnixSocketList, unix_info);
405 }
406 }
407 fclose(file);
408 Unix_timeStamp = time(0);
409
410 return 0;
411 }
412
413 void
printNetStat(const char * cmd)414 printNetStat(const char* cmd)
415 {
416 updateNetStat();
417
418 if (strstr(cmd, "tcp") != NULL)
419 output( "%d\n", num_tcp);
420 if (strstr(cmd, "udp") != NULL)
421 output( "%d\n", num_udp);
422 if (strstr(cmd, "unix") != NULL)
423 output( "%d\n", num_unix);
424 if (strstr(cmd, "raw") != NULL)
425 output( "%d\n", num_raw);
426 }
427
428 void
printNetStatInfo(const char * cmd)429 printNetStatInfo(const char* cmd)
430 {
431 if (strstr(cmd, "tcp") != NULL)
432 output( "Number of TCP-Sockets\t0\t0\tSockets\n");
433 if (strstr(cmd, "udp") != NULL)
434 output( "Number of UDP-Sockets\t0\t0\tSockets\n");
435 if (strstr(cmd, "unix") != NULL)
436 output( "Number of UnixDomain-Sockets\t0\t0\tSockets\n");
437 if (strstr(cmd, "raw") != NULL)
438 output( "Number of Raw-Sockets\t0\t0\tSockets\n");
439 }
440
441 void
printNetStatTcpUdpRaw(const char * cmd)442 printNetStatTcpUdpRaw(const char *cmd)
443 {
444 SocketInfo* socket_info;
445
446 if (strstr(cmd, "tcp")) {
447 updateNetStatTcpUdpRaw("tcp");
448
449 for (socket_info = first_ctnr(TcpSocketList); socket_info; socket_info = next_ctnr(TcpSocketList))
450 printSocketInfo(socket_info);
451
452 if (level_ctnr(TcpSocketList) == 0)
453 output( "\n");
454 }
455
456 if (strstr(cmd, "udp")) {
457 updateNetStatTcpUdpRaw("udp");
458
459 for (socket_info = first_ctnr(UdpSocketList); socket_info; socket_info = next_ctnr(UdpSocketList))
460 printSocketInfo(socket_info);
461
462 if (level_ctnr(UdpSocketList) == 0)
463 output( "\n");
464 }
465
466 if (strstr(cmd, "raw")) {
467 updateNetStatTcpUdpRaw("raw");
468
469 for (socket_info = first_ctnr(RawSocketList); socket_info; socket_info = next_ctnr(RawSocketList))
470 printSocketInfo(socket_info);
471
472 if (level_ctnr(RawSocketList) == 0)
473 output( "\n");
474 }
475 }
476
477 void
printNetStatTcpUdpRawInfo(const char * cmd)478 printNetStatTcpUdpRawInfo(const char *cmd)
479 {
480 (void) cmd;
481 output( "Local Address\tPort\tForeign Address\tPort\tState\tUID\ns\ts\ts\ts\ts\td\n");
482 }
483
printNetStatUnix(const char * cmd)484 void printNetStatUnix(const char *cmd)
485 {
486 UnixInfo* unix_info;
487
488 (void) cmd;
489 updateNetStatUnix();
490
491 for (unix_info = first_ctnr(UnixSocketList); unix_info; unix_info = next_ctnr(UnixSocketList)) {
492 output( "%d\t%s\t%s\t%d\t%s\n",
493 unix_info->refcount,
494 unix_info->type,
495 unix_info->state,
496 unix_info->inode,
497 unix_info->path);
498 }
499
500 if (level_ctnr(UnixSocketList) == 0)
501 output( "\n");
502 }
503
printNetStatUnixInfo(const char * cmd)504 void printNetStatUnixInfo(const char *cmd)
505 {
506 (void) cmd;
507 output( "RefCount\tType\tState\tInode\tPath\nd\ts\ts\td\ts\n");
508 }
509