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