Annotation of embedaddon/trafshow/show_stat.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 1998,2004 Rinet Corp., Novosibirsk, Russia
3: *
4: * Redistribution and use in source forms, with and without modification,
5: * are permitted provided that this entire comment appears intact.
6: *
7: * THIS SOURCE CODE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
8: */
9:
10: #ifdef HAVE_CONFIG_H
11: #include <config.h>
12: #endif
13:
14: #include <sys/param.h>
15: #include <sys/types.h>
16: #include <sys/socket.h>
17: #include <netinet/in.h>
18: #include <arpa/inet.h>
19: #include <stdio.h>
20: #include <stdlib.h>
21: #include <string.h>
22:
23: #include "show_stat.h"
24: #include "trafshow.h"
25: #include "screen.h"
26: #include "selector.h"
27: #include "netstat.h"
28: #include "getkey.h"
29: #include "addrtoname.h"
30:
31: ShowStatMode show_stat_mode = Size;
32: static int find_backflow(NETSTAT **list, int items, NETSTAT *at);
33: static void sort_backflow(NETSTAT **list, int items);
34:
35: static void
36: scale_size(addr, prot, data, rate)
37: int *addr, *prot, *data, *rate;
38: {
39: *addr = line_factor * (double)SHOW_STAT_ADDR;
40: *prot = line_factor * (double)SHOW_STAT_PROT;
41: *data = line_factor * (double)SHOW_STAT_DATA;
42: *rate = line_factor * (double)SHOW_STAT_RATE;
43: }
44:
45: static int
46: compare_pkt_len(p1, p2)
47: register const NETSTAT **p1, **p2;
48: {
49: if ((*p1)->pkt_len > (*p2)->pkt_len) return -1;
50: if ((*p1)->pkt_len < (*p2)->pkt_len) return 1;
51: return 0;
52: }
53:
54: static int
55: compare_data_len(p1, p2)
56: register const NETSTAT **p1, **p2;
57: {
58: if ((*p1)->data_len > (*p2)->data_len) return -1;
59: if ((*p1)->data_len < (*p2)->data_len) return 1;
60: return 0;
61: }
62:
63: static int
64: compare_pkt_cnt(p1, p2)
65: register const NETSTAT **p1, **p2;
66: {
67: if ((*p1)->pkt_cnt > (*p2)->pkt_cnt) return -1;
68: if ((*p1)->pkt_cnt < (*p2)->pkt_cnt) return 1;
69: return 0;
70: }
71:
72: static int
73: find_backflow(list, items, at)
74: NETSTAT **list;
75: int items;
76: NETSTAT *at;
77: {
78: int i;
79:
80: /* sanity check */
81: if (!list || items < 1 || !at)
82: return -1;
83:
84: for (i = 0; i < items; i++) {
85: if (netstat_bidir(at, list[i]))
86: return i;
87: }
88: return -1;
89: }
90:
91: /* too bad implementation -- it take alot of CPU cycles like deadloop. XXX */
92: static void
93: sort_backflow(list, items)
94: NETSTAT **list;
95: int items;
96: {
97: int i = 0, at;
98: NETSTAT *ns;
99:
100: while (i < items-1) {
101: ns = list[i++];
102: if ((at = find_backflow(&list[i], items - i, ns)) < 0)
103: continue;
104: if (at) {
105: ns = list[i + at];
106: memmove(&list[i + 1], &list[i], at * sizeof(NETSTAT *));
107: list[i] = ns;
108: }
109: i++;
110: }
111: }
112:
113: /*
114: * Pretty print an Internet address (net address + port).
115: */
116: static char *
117: ip_print(ver, proto, addr, dst, size)
118: int ver;
119: int proto;
120: const struct ip_address *addr;
121: char *dst;
122: int size;
123: {
124: const char *cp = 0;
125: char buf[100];
126:
127: if (ver == 4 && addr->ip_addr.s_addr) {
128: /*cp = intoa(addr->ip_addr.s_addr);*/
129: cp = ipaddr_string(&addr->ip_addr);
130: }
131: #ifdef INET6
132: else if (ver == 6 && !IN6_IS_ADDR_UNSPECIFIED(&addr->ip6_addr)) {
133: /*cp = inet_ntop(AF_INET6, &addr->ip6_addr, buf, sizeof(buf));*/
134: cp = ip6addr_string(&addr->ip6_addr);
135: }
136: #endif
137:
138: if (cp) {
139: (void)strncpy(dst, cp, size);
140: dst[size-1] = '\0';
141: } else snprintf(dst, size, "IPv%d", ver);
142:
143: if (addr->ip_port) {
144: char pb[20];
145: int len;
146: switch (proto) {
147: case IPPROTO_TCP:
148: if (nflag) {
149: sprintf(pb, "%d", ntohs(addr->ip_port));
150: cp = pb;
151: } else cp = tcpport_string(ntohs(addr->ip_port));
152: break;
153: case IPPROTO_UDP:
154: if (nflag) {
155: sprintf(pb, "%d", ntohs(addr->ip_port));
156: cp = pb;
157: } else cp = udpport_string(ntohs(addr->ip_port));
158: break;
159: case IPPROTO_ICMP:
160: if (nflag) {
161: sprintf(pb, "%04x", addr->ip_port - 1);
162: cp = pb;
163: } else cp = icmp_string(addr->ip_port - 1);
164: break;
165: #ifdef INET6
166: case IPPROTO_ICMPV6:
167: if (nflag) {
168: sprintf(pb, "%04x", addr->ip_port - 1);
169: cp = pb;
170: } else cp = icmpv6_string(addr->ip_port - 1);
171: break;
172: #endif
173: default: /* nonsense, but be strong */
174: sprintf(pb, "%d", ntohs(addr->ip_port));
175: cp = pb;
176: }
177: buf[0] = ',';
178: (void)strncpy(&buf[1], cp, 10);
179: buf[11] = '\0';
180: len = strlen(buf);
181: if (strlen(dst) + len < size)
182: (void)strcat(dst, buf);
183: else (void)strcpy(&dst[size - len - 1], buf);
184: }
185: return dst;
186: }
187:
188: static char *
189: sap_print(addr, sap, dst, size)
190: const u_char *addr;
191: u_char sap;
192: char *dst;
193: int size;
194: {
195: char buf[20];
196: int len;
197:
198: (void)strncpy(dst, etheraddr_string(addr), size);
199: dst[size-1] = '\0';
200:
201: buf[0] = '/';
202: if (nflag)
203: sprintf(&buf[1], "sap-%02x", sap & 0xff);
204: else (void)strncpy(&buf[1], llcsap_string(sap), 10);
205: buf[11] = '\0';
206: len = strlen(buf);
207: if (strlen(dst) + len < size)
208: (void)strcat(dst, buf);
209: else (void)strcpy(&dst[size - len - 1], buf);
210: return dst;
211: }
212:
213: void
214: hdr2str(nh, src_buf, src_len, dst_buf, dst_len, proto_buf, proto_len)
215: const struct netstat_header *nh;
216: char *src_buf, *dst_buf, *proto_buf;
217: int src_len, dst_len, proto_len;
218: {
219: const NETSTAT *ns;
220:
221: if (src_buf) *src_buf = '\0';
222: if (dst_buf) *dst_buf = '\0';
223: if (proto_buf) *proto_buf = '\0';
224:
225: /* sanity check */
226: if (!nh) return;
227:
228: ns = (NETSTAT *)nh;
229:
230: if (ns->ip_ver) {
231: if (src_buf && src_len > 1) {
232: ip_print(ns->ip_ver, ns->ip_proto, &ns->ip_src_addr,
233: src_buf, src_len);
234: }
235: if (dst_buf && dst_len > 1) {
236: ip_print(ns->ip_ver, ns->ip_proto, &ns->ip_dst_addr,
237: dst_buf, dst_len);
238: }
239: if (proto_buf && proto_len > 1) {
240: if (nflag)
241: snprintf(proto_buf, proto_len, "%d", (int)ns->ip_proto);
242: else (void)strncpy(proto_buf, ipproto_string(ns->ip_proto),
243: proto_len);
244: proto_buf[proto_len-1] = '\0';
245: }
246: } else if (ntohs(ns->eth_type) > 1500) { /* Ethernet II (DIX) */
247: if (src_buf && src_len > 1) {
248: (void)strncpy(src_buf, etheraddr_string(ns->eth_src_addr),
249: src_len);
250: src_buf[src_len-1] = '\0';
251: }
252: if (dst_buf && dst_len > 1) {
253: (void)strncpy(dst_buf, etheraddr_string(ns->eth_dst_addr),
254: dst_len);
255: dst_buf[dst_len-1] = '\0';
256: }
257: if (proto_buf && proto_len > 1) {
258: if (nflag)
259: snprintf(proto_buf, proto_len, "%04x", ntohs(ns->eth_type));
260: else (void)strncpy(proto_buf, ethertype_string(ns->eth_type),
261: proto_len);
262: proto_buf[proto_len-1] = '\0';
263: }
264: } else if (ns->eth_ssap == ns->eth_dsap) {
265: if (src_buf && src_len > 1) {
266: (void)strncpy(src_buf, etheraddr_string(ns->eth_src_addr),
267: src_len);
268: src_buf[src_len-1] = '\0';
269: }
270: if (dst_buf && dst_len > 1) {
271: (void)strncpy(dst_buf, etheraddr_string(ns->eth_dst_addr),
272: dst_len);
273: dst_buf[dst_len-1] = '\0';
274: }
275: if (proto_buf && proto_len > 1) {
276: if (nflag)
277: snprintf(proto_buf, proto_len, "sap-%02x",
278: (int)(ns->eth_ssap & 0xff));
279: else (void)strncpy(proto_buf, llcsap_string(ns->eth_ssap),
280: proto_len);
281: proto_buf[proto_len-1] = '\0';
282: }
283: } else {
284: if (src_buf && src_len > 1) {
285: sap_print(ns->eth_src_addr, ns->eth_ssap,
286: src_buf, src_len);
287: }
288: if (dst_buf && dst_len > 1) {
289: sap_print(ns->eth_dst_addr, ns->eth_dsap,
290: dst_buf, dst_len);
291: }
292: if (proto_buf && proto_len > 1) {
293: (void)strncpy(proto_buf, "802.3", proto_len);
294: proto_buf[proto_len-1] = '\0';
295: }
296: }
297: }
298:
299: static int
300: show_stat_header(dst, size, ph)
301: char *dst;
302: int size;
303: const PCAP_HANDLER *ph;
304: {
305: int addr_sz, prot_sz, data_sz, rate_sz;
306: char src_buf[100], dst_buf[100];
307: const char *data_ptr, *rate_ptr;
308:
309: /* sanity check */
310: if (!dst || size < 1 || !ph)
311: return 0;
312:
313: scale_size(&addr_sz, &prot_sz, &data_sz, &rate_sz);
314:
315: (void)strcpy(src_buf, "Source");
316: (void)strcpy(dst_buf, "Destination");
317: if (ph->masklen >= 0) {
318: sprintf(src_buf + strlen(src_buf), "/%d", ph->masklen);
319: sprintf(dst_buf + strlen(dst_buf), "/%d", ph->masklen);
320: }
321:
322: data_ptr = rate_ptr = "?";
323: switch (show_stat_mode) {
324: case Size:
325: data_ptr = "Size";
326: rate_ptr = "CPS";
327: break;
328: case Data:
329: data_ptr = "Data";
330: rate_ptr = "CPS";
331: break;
332: case Packets:
333: data_ptr = "Packets";
334: rate_ptr = "PPS";
335: break;
336: }
337: snprintf(dst, size,
338: "%-*.*s %-*.*s %-*.*s %-*.*s %-*.*s",
339: addr_sz, addr_sz, src_buf,
340: addr_sz, addr_sz, dst_buf,
341: prot_sz, prot_sz, "Protocol",
342: data_sz, data_sz, data_ptr,
343: rate_sz, rate_sz, rate_ptr);
344: return 0;
345: }
346:
347: static int
348: show_stat_line(dst, size, ns_list, idx)
349: char *dst;
350: int size;
351: const NETSTAT **ns_list;
352: int idx;
353: {
354: int addr_sz, prot_sz, data_sz, rate_sz;
355: const NETSTAT *ns;
356: char src_buf[100], dst_buf[100], proto_buf[20], data_buf[20], rate_buf[20];
357:
358: /* sanity check */
359: if (!dst || size < 1 || !ns_list)
360: return 0;
361:
362: ns = ns_list[idx];
363:
364: scale_size(&addr_sz, &prot_sz, &data_sz, &rate_sz);
365:
366: hdr2str(&ns->ns_hdr,
367: src_buf, MIN(sizeof(src_buf), addr_sz + 1),
368: dst_buf, MIN(sizeof(dst_buf), addr_sz + 1),
369: proto_buf, MIN(sizeof(proto_buf), prot_sz + 1));
370:
371: data_buf[0] = '\0';
372: rate_buf[0] = '\0';
373: switch (show_stat_mode) {
374: case Size:
375: if (ns->pkt_len >= 10000)
376: snprintf(data_buf, sizeof(data_buf), "%uK", ns->pkt_len / 1024);
377: else snprintf(data_buf, sizeof(data_buf), "%u", ns->pkt_len);
378:
379: if (ns->pkt_len_rate >= 10000)
380: snprintf(rate_buf, sizeof(rate_buf), "%uK", ns->pkt_len_rate / 1024);
381: else if (ns->pkt_len_rate > 0)
382: snprintf(rate_buf, sizeof(rate_buf), "%u", ns->pkt_len_rate);
383: break;
384: case Data:
385: if (ns->data_len >= 10000)
386: snprintf(data_buf, sizeof(data_buf), "%uK", ns->data_len / 1024);
387: else snprintf(data_buf, sizeof(data_buf), "%u", ns->data_len);
388:
389: if (ns->data_len_rate >= 10000)
390: snprintf(rate_buf, sizeof(rate_buf), "%uK", ns->data_len_rate / 1024);
391: else if (ns->data_len_rate > 0)
392: snprintf(rate_buf, sizeof(rate_buf), "%u", ns->data_len_rate);
393: break;
394: case Packets:
395: snprintf(data_buf, sizeof(data_buf), "%u", ns->pkt_cnt);
396:
397: if (ns->pkt_cnt_rate > 0)
398: snprintf(rate_buf, sizeof(rate_buf), "%u", ns->pkt_cnt_rate);
399: break;
400: }
401:
402: snprintf(dst, size,
403: "%-*.*s %-*.*s %-*.*s %-*.*s %-*.*s",
404: addr_sz, addr_sz, src_buf,
405: addr_sz, addr_sz, dst_buf,
406: prot_sz, prot_sz, proto_buf,
407: data_sz, data_sz, data_buf,
408: rate_sz, rate_sz, rate_buf);
409:
410: return ns->attr;
411: }
412:
413: static int
414: show_stat_footer(dst, size, ph)
415: char *dst;
416: int size;
417: const PCAP_HANDLER *ph;
418: {
419: const PCAP_HANDLER *top;
420: int addr_sz, prot_sz, data_sz, rate_sz, depth;
421: u_int64_t total = 0, rate = 0;
422: char stat_buf[50], data_buf[20], rate_buf[20];
423:
424: /* sanity check */
425: if (!dst || size < 1 || !ph)
426: return 0;
427:
428: scale_size(&addr_sz, &prot_sz, &data_sz, &rate_sz);
429:
430: depth = 0;
431: for (top = ph->top; top; top = top->top) depth++;
432: if (depth) {
433: snprintf(stat_buf, sizeof(stat_buf), "%d Flows (depth %d)",
434: netstat_count(ph), depth);
435: } else {
436: snprintf(stat_buf, sizeof(stat_buf), "%d Flows",
437: netstat_count(ph));
438: }
439:
440: switch (show_stat_mode) {
441: case Size:
442: total = ph->pkt_len;
443: rate = ph->pkt_len_rate;
444: break;
445: case Data:
446: total = ph->data_len;
447: rate = ph->data_len_rate;
448: break;
449: case Packets:
450: total = ph->pkt_cnt;
451: rate = ph->pkt_cnt_rate;
452: break;
453: }
454:
455: if (total >= 10000000)
456: snprintf(data_buf, sizeof(data_buf), "%uM",
457: (unsigned int)(total / (1024 * 1024)));
458: else if (total >= 10000)
459: snprintf(data_buf, sizeof(data_buf), "%uK",
460: (unsigned int)(total / 1024));
461: else snprintf(data_buf, sizeof(data_buf), "%u",
462: (unsigned int)total);
463:
464: if (rate >= 10000000)
465: snprintf(rate_buf, sizeof(rate_buf), "%uM",
466: (unsigned int)(rate / (1024 * 1024)));
467: else if (rate >= 10000)
468: snprintf(rate_buf, sizeof(rate_buf), "%uK",
469: (unsigned int)(rate / 1024));
470: else snprintf(rate_buf, sizeof(rate_buf), "%u",
471: (unsigned int)rate);
472:
473: snprintf(dst, size,
474: "%-*.*s %-*.*s %-*.*s %-*.*s %-*.*s",
475: addr_sz, addr_sz, ph->name,
476: addr_sz, addr_sz, stat_buf,
477: prot_sz, prot_sz, "Total:",
478: data_sz, data_sz, data_buf,
479: rate_sz, rate_sz, rate_buf);
480: return 0;
481: }
482:
483: int
484: show_stat_input(ph, ch)
485: PCAP_HANDLER *ph;
486: int ch;
487: {
488: switch (ch) {
489: case '[': /* rotate list mode left */
490: case K_LEFT:
491: if (show_stat_mode == Size)
492: show_stat_mode = Packets;
493: else show_stat_mode--;
494: return 1;
495: case ']': /* rotate list mode right */
496: case K_RIGHT:
497: if (show_stat_mode == Packets)
498: show_stat_mode = Size;
499: else show_stat_mode++;
500: return 1;
501: case K_CTRL('R'): /* reset current netstat hash */
502: if (ph) {
503: netstat_purge(ph, 0);
504: show_stat_list(ph);
505: return 1;
506: }
507: break;
508: case K_TAB: /* follow to backflow */
509: if (ph) {
510: SELECTOR *sp = show_stat_selector(ph);
511: int idx = selector_get(sp);
512:
513: if (idx >= 0) {
514: NETSTAT **ns_list = (NETSTAT **)sp->list;
515: const NETSTAT *ns = ns_list[idx];
516:
517: for (idx = 0; idx < sp->items; idx++) {
518: if (netstat_bidir(ns, ns_list[idx])) {
519: selector_set(idx, sp);
520: return 1;
521: }
522: }
523: }
524: }
525: break;
526: }
527: return 0;
528: }
529:
530: SELECTOR *
531: show_stat_selector(ph)
532: PCAP_HANDLER *ph;
533: {
534: if (!ph) return 0;
535: if (!ph->selector && (ph->selector = selector_init()) != 0) {
536: ph->selector->get_header = show_stat_header;
537: ph->selector->get_line = show_stat_line;
538: ph->selector->get_footer = show_stat_footer;
539: }
540: return ph->selector;
541: }
542:
543: NETSTAT *
544: show_stat_get(ph, idx)
545: PCAP_HANDLER *ph;
546: int idx;
547: {
548: SELECTOR *sp;
549: NETSTAT **ns_list;
550:
551: /* sanity check */
552: if (!ph || idx < 0 || (sp = show_stat_selector(ph)) == 0 || idx >= sp->items)
553: return 0;
554:
555: ns_list = (NETSTAT **)sp->list;
556: return ns_list[idx];
557: }
558:
559: int
560: show_stat_search(ph, str)
561: PCAP_HANDLER *ph;
562: const char *str;
563: {
564: SELECTOR *sp;
565: NETSTAT **ns_list;
566: const NETSTAT *ns;
567: int idx;
568: char src_buf[100], dst_buf[100], proto_buf[20];
569:
570: /* sanity check */
571: if (!ph || !str || *str == '\0' || (sp = show_stat_selector(ph)) == 0)
572: return -1;
573:
574: ns_list = (NETSTAT **)sp->list;
575: for (idx = 0; idx < sp->items; idx++) {
576: ns = ns_list[idx];
577: hdr2str(&ns->ns_hdr,
578: src_buf, sizeof(src_buf),
579: dst_buf, sizeof(dst_buf),
580: proto_buf, sizeof(proto_buf));
581: if (strstr(src_buf, str) ||
582: strstr(dst_buf, str) ||
583: strstr(proto_buf, str))
584: return idx;
585: }
586: return -1;
587: }
588:
589: SELECTOR *
590: show_stat_list(ph)
591: PCAP_HANDLER *ph;
592: {
593: SELECTOR *sp;
594: int cnt;
595:
596: /* sanity check */
597: if (!ph || (sp = show_stat_selector(ph)) == 0)
598: return 0;
599:
600: sp->header = ph;
601: sp->footer = ph;
602:
603: if ((cnt = netstat_fetch((NETSTAT ***)&sp->list, ph)) < 0)
604: return sp;
605:
606: sp->items = cnt;
607: if (cnt < 2) /* no sorting required */
608: return sp;
609:
610: /* sort it accroding to current mode */
611: switch (show_stat_mode) {
612: case Size:
613: qsort(sp->list, sp->items, sizeof(NETSTAT *), compare_pkt_len);
614: break;
615: case Data:
616: qsort(sp->list, sp->items, sizeof(NETSTAT *), compare_data_len);
617: break;
618: case Packets:
619: qsort(sp->list, sp->items, sizeof(NETSTAT *), compare_pkt_cnt);
620: break;
621: }
622: if (popbackflow)
623: sort_backflow(sp->list, sp->items);
624:
625: return sp;
626: }
627:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>