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