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