1 /*
2     rate  --  statistic traffic analyzer
3     Copyright (C) 2003 Mateusz 'mteg' Golicz
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 #ifdef STREAM_ANALYZER
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #ifdef OPEN_BSD
27 #include <netinet/in_systm.h>
28 #endif
29 #include <netinet/in.h>
30 #include <netinet/ip.h>
31 #include <netinet/tcp.h>
32 #include <sys/timeb.h>
33 #include <signal.h>
34 #include <time.h>
35 #include <pcap.h>
36 #include "lib.h"
37 #include "dns.h"
38 #ifdef HAVE_REGEX
39 #include <regex.h>
40 #endif
41 #include "iphash.h"
42 #include "protos.h"
43 #include "sta.h"
44 #include "streams.h"
45 #include "streamstat.h"
46 #include "colors.h"
47 #include "process.h"
48 
49 extern int opt_caplen;
50 extern int opt_cls;
51 extern int opt_human;
52 extern int opt_cols;
53 extern int opt_dns;
54 
55 static int opt_memlimit = 0;
56 static int opt_memfree = 4000;
57 static int opt_verbose = 0;
58 
59 static int opt_top = 5;
60 static int opt_brief = 0;
61 static int opt_mode = COUNTER_BYTE;
62 static int opt_counter = LRECV;
63 static int opt_sort = ORDER_ASC;
64 extern int opt_color;
65 static int opt_spaces = 0;
66 static int opt_overall = 0;
67 static int opt_resources = 0;
68 static char opt_opmode = 0;
69 
output(struct timeb * now,int miliFromStart,int miliFromLast,unsigned long long totalbytes,unsigned long long totalpackets,unsigned long nowbytes,unsigned long nowpackets)70 static void output(struct timeb * now, int miliFromStart, int miliFromLast,
71 					unsigned long long totalbytes, unsigned long long totalpackets,
72 					unsigned long nowbytes, unsigned long nowpackets)
73 {
74 	struct itimerval itv;
75 	static double time_real = 0, time_this = 0; /* in 1/1000 s */
76 
77 	int mem, sc, ssc, hc;
78 
79 	getitimer(ITIMER_PROF, &itv);
80 
81 	time_real = miliFromStart;
82 	time_this = (PROFILER_STARTUP - itv.it_value.tv_sec) * 1000 + ((0 - itv.it_value.tv_usec) / 1000);
83 
84 	if(time_real)
85 		time_this /= time_real / 100;
86 	else
87 		time_this = 0;
88 
89 	mem = stastream_streamcount() * sizeof(sta_stream) + stastream_hostcount() * sizeof(sta_host);
90 	mem /= 1024;
91 
92 	if(opt_memlimit)
93 	{
94 		if(mem > opt_memlimit)
95 			stastream_cleanstreams(now, opt_memfree);
96 	}
97 
98 
99 	stastream_expire(now);
100 
101 	sc = stastream_streamcount();
102 	ssc = stastream_stalestreamcount();
103 	hc = stastream_hostcount();
104 
105 	if(opt_resources)
106 	{
107 		printf(opt_color ?
108 		(COLOR_RESOURCEREPORT "### %d streams (%d stale) %d hosts, hash tables: %d kB, CPU usage %.0f %%\033[0m  \n") :
109 		("### %d streams (%d stale) %d hosts, hash tables: %d kB, CPU usage %.0f %%  \n"), sc, ssc, hc, mem, time_this);
110 	}
111 
112 	switch(opt_opmode)
113 	{
114 		case 'n':
115 		{
116 			sta_host ** list;
117 			int n, i;
118 
119 
120 			list = stastat_gethostlist(opt_top, &n, opt_mode, opt_counter, opt_sort, 0);
121 			if((!opt_brief) && n)
122 				printf("%s\n", stastat_streamheader("  ", opt_cols, opt_verbose, opt_color));
123 
124 			for(i = 0; i<n; i++)
125 			{
126 				struct in_addr in;
127 				sta_stream ** streams;
128 				sta_host * h = list[i];
129 				int n, j;
130 				char overall_bytes[20];
131 				char overall_packets[20];
132 				char overall_bps[20];
133 				char overall_pps[20];
134 				char host[50];
135 
136 
137 				if(opt_dns)
138 					snprintf(host, 50, "%s", dns_lookup(ntohl(h->ip)));
139 				else
140 				{
141 					in.s_addr = h->ip;
142 					snprintf(host, 50, "%s", inet_ntoa(in));
143 				}
144 
145 				if(opt_counter == LRECV || opt_counter == RECV)
146 				{
147 					mkhuman(h->bytes[RECV], 20, overall_bytes, "B", 1024, opt_human);
148 					mkhuman(h->packets[RECV], 20, overall_packets, "p", 1000, opt_human);
149 					mkhuman(h->bytes[LRECV] * 1000.0 / miliFromLast, 20, overall_bps, "Bps", 1024, opt_human);
150 					mkhuman(h->packets[LRECV] * 1000.0 / miliFromLast, 20, overall_pps, "pps", 1000, opt_human);
151 				}
152 				else
153 				{
154 					mkhuman(h->bytes[SENT], 20, overall_bytes, "B", 1024, opt_human);
155 					mkhuman(h->packets[SENT], 20, overall_packets, "p", 1000, opt_human);
156 					mkhuman(h->bytes[SENT] * 1000.0 / miliFromLast, 20, overall_bps, "Bps", 1024, opt_human);
157 					mkhuman(h->packets[SENT] * 1000.0 / miliFromLast, 20, overall_pps, "pps", 1000, opt_human);
158 				}
159 
160 // ### 01.  123 123.45k/123.45k 123.45k/123.45k
161 // ### 02.  6s  7.67 kB/115.00  p 683.00  Bps/10.00  pps
162 				printf(customize_format(opt_cols * 2, 54 * 2,
163 						"%%s### %%.2d.%%s %%s%%-%d.%ds%%s %%s%%3ds%%s %%s%%8s/%%8s%%s %%s%%8s/%%8s%%s%%s\n"),
164 						CM_POSITION(opt_color),
165 						i + 1,
166 						CM_PLAIN(0, opt_color),
167 						CM_HOST(0, opt_color),
168 						host,
169 						CM_PLAIN(0, opt_color),
170 						CM_STREAMCOUNT(opt_color),
171 						list[i]->streamcount,
172 						CM_PLAIN(0, opt_color),
173 						CM_DATA(0, opt_color),
174 						overall_bytes,
175 						overall_packets,
176 						CM_PLAIN(0, opt_color),
177 						CM_RATE(0, opt_color),
178 						overall_bps,
179 						overall_pps,
180 						CM_PLAIN(0, opt_color),
181 						opt_cls ? "\033[K" : "");
182 
183 				if(!opt_brief)
184 				{
185 					streams = stastat_getstreams(list[i], &n);
186 					stastat_sortstreams(streams, n);
187 
188 					for(j = 0; j<n; j++)
189 					{
190 						char * sd;
191 						if(streams[j]->properties & SPROP_CLOSED) continue;
192 						sd = stastat_stream2a("  ", streams[j], opt_cols, opt_verbose, opt_human, opt_color, opt_spaces, miliFromLast);
193 						printf("  %s%s\n", sd, opt_cls ? "\033[K" : "");
194 						free(sd);
195 					}
196 					free(streams);
197 					printf("%s\n", opt_cls ? "\033[K" : "");
198 				}
199 			}
200 			free(list);
201 			break;
202 		}
203 		case 's':
204 		{
205 			sta_stream ** list;
206 			int n, i;
207 
208 			list = stastat_getstreamlist(opt_top, &n, opt_mode, opt_overall, opt_sort, 0);
209 			if(n)
210 				printf("%s\n", stastat_streamheader("   ", opt_cols, opt_verbose, opt_color));
211 			for(i = 0; i<n; i++)
212 			{
213 				char * sd;
214 				sd = stastat_stream2a("   ", list[i], opt_cols, opt_verbose, opt_human, opt_color, opt_spaces, miliFromLast);
215 				printf((opt_color) ? (COLOR_POSITION "%2d \033[0m%s\n") :
216 									 "%2d %s%s\n", i + 1, sd, opt_cls ? "\033[K" : "");
217 				free(sd);
218 			}
219 			free(list);
220 			break;
221 		}
222 		case 'p':
223 		{
224 			struct protoinfo ** list;
225 			int n, i;
226 
227 			list = stastat_getprotolist(opt_top, &n, opt_mode, opt_overall, opt_sort);
228 			if((!opt_brief) && n)
229 				printf("%s\n", stastat_streamheader("  ", opt_cols, opt_verbose, opt_color));
230 			for(i = 0; i<n; i++)
231 			{
232 				char overall_bytes[20];
233 				char overall_packets[20];
234 				char overall_bps[20];
235 				char overall_pps[20];
236 				struct protoinfo * pi = list[i];
237 
238 				mkhuman(pi->counters[PC_OVERALL_BYTES], 20, overall_bytes, "B", 1024, opt_human);
239 				mkhuman(pi->counters[PC_OVERALL_PACKETS], 20, overall_packets, "p", 1000, opt_human);
240 				mkhuman(pi->counters[PC_LAST_BYTES] * 1000.0 / miliFromLast, 20, overall_bps, "Bps", 1024, opt_human);
241 				mkhuman(pi->counters[PC_LAST_PACKETS] * 1000.0 / miliFromLast, 20, overall_pps, "pps", 1000, opt_human);
242 
243 				printf(opt_color ?
244 					(COLOR_POSITION "### %2d. \033[0m" COLOR_PROTOCOL "%s \033[0m" COLOR_DATA "%s/%s\033[0m " COLOR_RATE "%s/%s\033[0m%s\n") :
245 					("### %.2d. %s %s/%s %s/%s%s\n"),
246 					i + 1, sta_getprotoname(pi->protoid),
247 					overall_bytes, overall_packets, overall_bps, overall_pps, opt_cls ? "\033[K" : "");
248 
249 				if(!opt_brief)
250 				{
251 					sta_stream ** streams;
252 					sta_stream * streamlist;
253 					sta_stream * current;
254 					int n;
255 
256 					streamlist = stastream_getprotolist(pi->protoid);
257 					for(n = 0, current = streamlist; current; current = current->proto_next) n++;
258 
259 					if(n)
260 					{
261 						int j;
262 
263 						streams = (sta_stream**) sta_malloc(sizeof(sta_stream*) * n);
264 						for(n = 0, current = streamlist; current; current = current->proto_next)
265 							streams[n++] = current;
266 
267 						stastat_sortstreams(streams, n);
268 
269 						for(j = 0; j<n; j++)
270 						{
271 							char * sd;
272 							if(streams[j]->properties & SPROP_CLOSED) continue;
273 							sd = stastat_stream2a("  ", streams[j], opt_cols, opt_verbose, opt_human, opt_color, opt_spaces, miliFromLast);
274 							printf("  %s%s\n", sd, opt_cls ? "\033[K" : "");
275 							free(sd);
276 						}
277 						free(streams);
278 						printf("%s\n", opt_cls ? "\033[K" : "");
279 					}
280 				}
281 // 00 U xxx.yyy.zzz.ttt:ppppp xxx.yyy.zzz.ttt:ppppp kkk.kkK ppp.ppK kps.kkK bps.ppK
282 
283 //				char * sd;
284 //
285 //				sd = stastat_stream2a("     ", list[i], opt_verbose, opt_human, opt_color, opt_tab, miliFromLast);
286 //				printf((opt_color) ? (COLOR_POSITION "## %2d. \033[0m%s\n") :
287 //									 "## %2d. %s\n", i + 1, sd);
288 //				free(sd);
289 			}
290 			free(list);
291 			break;
292 		}
293 
294 	}
295 	stastream_clear();
296 
297 }
298 
help2(void)299 static void help2(void)
300 {
301 	printf("\n\nSTREAM TRAFFIC ANALYZER USAGE: ... -T [-uvrct] [-m <ml> [-f <f>]] (-n | -s | -p) <n> [-R | -S] [-M | -O] [-B | -P] [-A | -D] [-b]\n");
302 	printf("  -v     Increase verbosity level.\n");
303 	printf("  -r     Output resource statistics (CPU usage, memory used by hash tables).\n");
304 	printf("  -t     Separate output columns by tabs.\n");
305 	printf("  -m <m> Limit memory used by stream and host data to m kilobytes.\n");
306 	printf("  -d <f> After a memory overlimit, dispose f stream entries (default: 4000).\n");
307 	printf("  -f     Print spaces instead of standard column separators (|).\n");
308 	printf("  -n <n> Node-driven reports - report n top nodes:\n");
309 	printf("      -R On received data (default).\n");
310 	printf("      -S On sent data.\n");
311 	printf("      -M On momentary rates (default).\n");
312 	printf("      -O On overall rates.\n");
313 	printf("      -B Counting bytes (default).\n");
314 	printf("      -P Counting packets.\n");
315 	printf("      -A Ascending sort.\n");
316 	printf("      -D Descending sort (default).\n");
317 	printf("      -b Brief output - do not print stream list for each host.\n");
318 	printf("  -s <n> Stream-driven reports - report n top streams:\n");
319 	printf("      -B On bytes transferred within a stream (default).\n");
320 	printf("      -P On packets transferred within a stream.\n");
321 	printf("      -M On momentary rates (default).\n");
322 	printf("      -O On overall rates.\n");
323 	printf("      -A Ascending sort.\n");
324 	printf("      -D Descending sort (default).\n");
325 	printf("  -p <n> Protocol-driven reports - report n top protocols:\n");
326 	printf("      -B On bytes transferred using a protocol (default).\n");
327 	printf("      -P On packets transferred using a protocol.\n");
328 	printf("      -M On momentary rates (default).\n");
329 	printf("      -O On overall rates.\n");
330 	printf("      -A Ascending sort.\n");
331 	printf("      -D Descending sort (default).\n");
332 	printf("      -b Brief output - do not print stream list for each protocol.\n");
333 }
334 
counter(const unsigned char * data,int caplen,int len)335 static void counter(const unsigned char * data, int caplen, int len)
336 {
337 	struct timeval tv;
338 	struct timezone tz;
339 
340 	gettimeofday(&tv, &tz);
341 	stastream_classify(data, caplen, len, &tv);
342 }
343 
r_stream_setup(int argc,char ** argv,void (** custom_output)(struct timeb *,int,int,unsigned long long,unsigned long long,unsigned long,unsigned long),void (** custom_counter)(const unsigned char *,int,int))344 void r_stream_setup(int argc, char ** argv,
345 						void (**custom_output)(struct timeb*, int, int, unsigned long long,
346 							  unsigned long long, unsigned long, unsigned long),
347 						void (**custom_counter)(const unsigned char *, int, int))
348 {
349 	int c, dir = 0, mom = 0;
350 
351 	*custom_output = output;
352 	*custom_counter = counter;
353 	while((c = getopt(argc, argv, "?hvd:m:fn:s:p:RSMOBPADbrt")) != EOF)
354 	{
355 		switch(c)
356 		{
357 			case '?':
358 			case 'h':
359 				help(argv[0]);
360 				help2();
361 				exit(0);
362 			case 'v': opt_verbose++; break;
363 			case 'm':
364 				opt_memlimit = atoi(optarg);
365 				break;
366 			case 'd':
367 				opt_memfree = atoi(optarg);
368 				break;
369 			case 'n':
370 			case 's':
371 			case 'p':
372 				if(opt_opmode)
373 				{
374 					fprintf(stderr, "You have to select only one of: -n, -s or -p. Consult %s -T -h\n", argv[0]);
375 					exit(1);
376 				}
377 				opt_opmode = c;
378 				opt_top = atoi(optarg);
379 				if(opt_top < 1) opt_top = 1;
380 				break;
381 			case 'A': opt_sort = ORDER_DESC; break;
382 			case 'D': opt_sort = ORDER_ASC; break;
383 			case 'B': opt_mode = COUNTER_BYTE; break;
384 			case 'P': opt_mode = COUNTER_PACKET; break;
385 			case 'R': dir = 1; break;
386 			case 'S': dir = 2; break;
387 			case 'M': mom = 1; break;
388 			case 'O': mom = 2; break;
389 			case 'f': opt_spaces = 1; break;
390 			case 'r': opt_resources = 1; break;
391 			case 'b': opt_brief = 1; break;
392 		}
393 	}
394 
395 	if(!opt_opmode)
396 	{
397 		opt_opmode = 'n';
398 		opt_top = 10;
399 	}
400 
401 	if(opt_opmode != 'n' && dir)
402 	{
403 		fprintf(stderr, "The -R and -S options do not make sense in this mode. Consult %s -T -h.\n", argv[0]);
404 		exit(1);
405 	}
406 
407 	if(opt_opmode == 'n')
408 	{
409 		if(dir && (!mom)) mom = 1;
410 		if(mom && (!dir)) dir = 1;
411 
412 		if(dir == 1 && mom == 1) opt_counter = LRECV;
413 		if(dir == 2 && mom == 1) opt_counter = LSENT;
414 		if(dir == 1 && mom == 2) opt_counter = RECV;
415 		if(dir == 2 && mom == 2) opt_counter = SENT;
416 	}
417 	else
418 		if(mom == 2) opt_overall = 1;
419 
420 	if(opt_caplen < 1500) opt_caplen = 1500;
421 }
422 #endif
423