Annotation of embedaddon/trafshow/netstat.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 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 <sys/time.h>
! 18: #include <netinet/in.h>
! 19: #include <netdb.h>
! 20: #include <stdio.h>
! 21: #include <stdlib.h>
! 22: #include <string.h>
! 23: #include <errno.h>
! 24: #include <pthread.h>
! 25:
! 26: #include "netstat.h"
! 27: #include "hashtab.h"
! 28: #include "trafshow.h"
! 29: #include "events.h" /* just for tv_diff() */
! 30: #include "colormask.h"
! 31: #include "addrtoname.h"
! 32:
! 33: int
! 34: netstat_count(ph)
! 35: const PCAP_HANDLER *ph;
! 36: {
! 37: /* sanity check */
! 38: if (!ph || !ph->ns_hash)
! 39: return 0;
! 40:
! 41: return hcount(ph->ns_hash);
! 42: }
! 43:
! 44: static void
! 45: maskit(bp, len, bits)
! 46: u_int8_t *bp;
! 47: int len, bits;
! 48: {
! 49: register u_int8_t mask;
! 50: register int i, j;
! 51:
! 52: for (i = 0; i < len; i++) {
! 53: mask = 0;
! 54: for (j = 0; j < 8 && bits > 0; j++, bits--) {
! 55: mask >>= 1;
! 56: mask |= 0x80;
! 57: }
! 58: bp[i] &= mask;
! 59: }
! 60: }
! 61:
! 62: void
! 63: netstat_aggregate(nh, bits)
! 64: struct netstat_header *nh;
! 65: int bits;
! 66: {
! 67: /* sanity check */
! 68: if (!nh || bits < 0)
! 69: return;
! 70:
! 71: memset(&nh->en_hdr.src, 0, sizeof(nh->en_hdr.src));
! 72: memset(&nh->en_hdr.dst, 0, sizeof(nh->en_hdr.dst));
! 73:
! 74: if (nh->in_hdr.ver) {
! 75: struct ip_address *src = &nh->in_hdr.src;
! 76: struct ip_address *dst = &nh->in_hdr.dst;
! 77:
! 78: maskit((u_int8_t *)&src->ipaddr, sizeof(src->ipaddr), bits);
! 79: maskit((u_int8_t *)&dst->ipaddr, sizeof(dst->ipaddr), bits);
! 80:
! 81: /* guess server port */
! 82: if (src->ip_port && dst->ip_port) {
! 83: u_int16_t sport = ntohs(src->ip_port);
! 84: u_int16_t dport = ntohs(dst->ip_port);
! 85:
! 86: if (isservport(sport))
! 87: dst->ip_port = 0;
! 88: else if (isservport(dport))
! 89: src->ip_port = 0;
! 90: else if (sport < IPPORT_RESERVED)
! 91: dst->ip_port = 0;
! 92: else if (dport < IPPORT_RESERVED)
! 93: src->ip_port = 0;
! 94: else if (sport >= IPPORT_DYNAMIC)
! 95: src->ip_port = 0;
! 96: else if (dport >= IPPORT_DYNAMIC)
! 97: dst->ip_port = 0;
! 98: else if (sport > dport)
! 99: src->ip_port = 0;
! 100: else dst->ip_port = 0;
! 101: }
! 102: }
! 103: }
! 104:
! 105: static int
! 106: htab_insert(ht, ns)
! 107: struct htab *ht;
! 108: const NETSTAT *ns;
! 109: {
! 110: ub1 *key;
! 111: ub4 keyl;
! 112: int op;
! 113: NETSTAT *dp;
! 114:
! 115: key = (ub1 *)&ns->ns_hdr;
! 116: keyl = sizeof(ns->ns_hdr);
! 117: if ((op = hadd(ht, key, keyl, 0)) < 0)
! 118: return -1;
! 119:
! 120: if (op) { /* OK, new item inserted */
! 121: if ((dp = (NETSTAT *)malloc(sizeof(NETSTAT))) == 0) {
! 122: hdel(ht);
! 123: return -1;
! 124: }
! 125: memcpy(dp, ns, sizeof(NETSTAT));
! 126: dp->gain_pkt_cnt = ns->pkt_cnt;
! 127: dp->gain_pkt_len = ns->pkt_len;
! 128: dp->gain_data_len = ns->data_len;
! 129: dp->attr = colormask(&dp->ns_hdr);
! 130:
! 131: hkey(ht) = (ub1 *)&dp->ns_hdr;
! 132: hstuff(ht) = dp;
! 133: return 1;
! 134: }
! 135: /* Failed because already in cache -- update it */
! 136:
! 137: if ((dp = (NETSTAT *)hstuff(ht)) == 0)
! 138: return 0; /* should not happen */
! 139:
! 140: dp->pkt_cnt += ns->pkt_cnt;
! 141: dp->pkt_len += ns->pkt_len;
! 142: dp->data_len += ns->data_len;
! 143:
! 144: dp->gain_pkt_cnt += ns->pkt_cnt;
! 145: dp->gain_pkt_len += ns->pkt_len;
! 146: dp->gain_data_len += ns->data_len;
! 147:
! 148: if (ns->pkt_cnt_rate || ns->pkt_len_rate || ns->data_len_rate) {
! 149: dp->mtime = ns->mtime;
! 150:
! 151: dp->pkt_cnt_rate = ns->pkt_cnt_rate;
! 152: dp->pkt_len_rate = ns->pkt_len_rate;
! 153: dp->data_len_rate = ns->data_len_rate;
! 154:
! 155: } else if ((op = tv_diff(&dp->mtime, &ns->mtime)) >= 1000) {
! 156: dp->mtime = ns->mtime;
! 157:
! 158: dp->gain_pkt_cnt = dp->gain_pkt_cnt * 1000 / op;
! 159: if (dp->gain_pkt_cnt) {
! 160: dp->pkt_cnt_rate = dp->gain_pkt_cnt;
! 161: dp->gain_pkt_cnt = 0;
! 162: }
! 163: dp->gain_pkt_len = dp->gain_pkt_len * 1000 / op;
! 164: if (dp->gain_pkt_len) {
! 165: dp->pkt_len_rate = dp->gain_pkt_len;
! 166: dp->gain_pkt_len = 0;
! 167: }
! 168: dp->gain_data_len = dp->gain_data_len * 1000 / op;
! 169: if (dp->gain_data_len) {
! 170: dp->data_len_rate = dp->gain_data_len;
! 171: dp->gain_data_len = 0;
! 172: }
! 173: }
! 174: return 0;
! 175: }
! 176:
! 177: int
! 178: netstat_insert(ph, ns)
! 179: PCAP_HANDLER *ph;
! 180: const NETSTAT *ns;
! 181: {
! 182: int op;
! 183: NETSTAT ns_buf;
! 184:
! 185: /* sanity check */
! 186: if (!ph || !ns) {
! 187: errno = EINVAL;
! 188: return -1;
! 189: }
! 190: if (!ph->ns_hash && (ph->ns_hash = hcreate(65536)) == 0)
! 191: return -1;
! 192:
! 193: if (ph->masklen >= 0) {
! 194: memcpy(&ns_buf, ns, sizeof(NETSTAT));
! 195: netstat_aggregate(&ns_buf.ns_hdr, ph->masklen);
! 196: ns = &ns_buf;
! 197: }
! 198: if (ph->ns_mutex) pthread_mutex_lock(ph->ns_mutex);
! 199:
! 200: op = htab_insert(ph->ns_hash, ns);
! 201:
! 202: if (ph->ns_mutex) pthread_mutex_unlock(ph->ns_mutex);
! 203: return op;
! 204: }
! 205:
! 206: int
! 207: netstat_find(ph, ns)
! 208: PCAP_HANDLER *ph;
! 209: NETSTAT *ns; /* IN/OUT */
! 210: {
! 211: struct htab *ht;
! 212: ub1 *key;
! 213: ub4 keyl;
! 214: NETSTAT *found;
! 215: int ok = 0;
! 216:
! 217: /* sanity check */
! 218: if (!ph || !ns || netstat_count(ph) < 1)
! 219: return 0;
! 220:
! 221: if (ph->ns_mutex) pthread_mutex_lock(ph->ns_mutex);
! 222: ht = ph->ns_hash;
! 223:
! 224: key = (ub1 *)&ns->ns_hdr;
! 225: keyl = sizeof(ns->ns_hdr);
! 226: if (hfind(ht, key, keyl) && (found = hstuff(ht)) != 0) {
! 227: ok = 1;
! 228: *ns = *found;
! 229: }
! 230:
! 231: if (ph->ns_mutex) pthread_mutex_unlock(ph->ns_mutex);
! 232: return ok;
! 233: }
! 234:
! 235: int
! 236: netstat_purge(ph, at)
! 237: PCAP_HANDLER *ph;
! 238: const struct timeval *at;
! 239: {
! 240: struct htab *ht;
! 241: int op, cnt = 0;
! 242: NETSTAT *ns;
! 243:
! 244: /* sanity check */
! 245: if (!ph) {
! 246: errno = EINVAL;
! 247: return -1;
! 248: }
! 249: if (netstat_count(ph) < 1)
! 250: return 0;
! 251:
! 252: if (ph->ns_mutex) pthread_mutex_lock(ph->ns_mutex);
! 253: ht = ph->ns_hash;
! 254:
! 255: op = hfirst(ht);
! 256: while (op && hcount(ht) > 0) {
! 257: ns = hstuff(ht);
! 258: if (!ns) { /* should not happen */
! 259: op = hdel(ht);
! 260: } else if (!at || timercmp(&ns->mtime, at, <)) {
! 261: free(ns);
! 262: op = hdel(ht);
! 263: cnt++;
! 264: } else {
! 265: op = hnext(ht);
! 266: }
! 267: }
! 268: if (ph->ns_mutex) pthread_mutex_unlock(ph->ns_mutex);
! 269: return cnt;
! 270: }
! 271:
! 272: void
! 273: netstat_free(ph)
! 274: PCAP_HANDLER *ph;
! 275: {
! 276: struct htab *ht;
! 277:
! 278: /* sanity check */
! 279: if (!ph) return;
! 280:
! 281: netstat_purge(ph, 0);
! 282:
! 283: if (ph->ns_mutex) pthread_mutex_lock(ph->ns_mutex);
! 284: ht = ph->ns_hash;
! 285: ph->ns_hash = 0;
! 286: if (ht) hdestroy(ht);
! 287: if (ph->ns_mutex) pthread_mutex_unlock(ph->ns_mutex);
! 288: }
! 289:
! 290: int
! 291: netstat_match(p1, p2)
! 292: register const NETSTAT *p1, *p2;
! 293: {
! 294: /* sanity check */
! 295: if (!p1 || !p2) return 0;
! 296:
! 297: return !memcmp(&p1->ns_hdr, &p2->ns_hdr, sizeof(struct netstat_header));
! 298: }
! 299:
! 300: int
! 301: netstat_bidir(p1, p2)
! 302: register const NETSTAT *p1, *p2;
! 303: {
! 304: /* sanity check */
! 305: if (!p1 || !p2) return 0;
! 306:
! 307: if (p1->ip_ver) {
! 308: if (p1->ip_ver == p2->ip_ver &&
! 309: p1->ip_proto == p2->ip_proto &&
! 310: !memcmp(&p1->ip_src_addr, &p2->ip_dst_addr,
! 311: sizeof(struct ip_address)) &&
! 312: !memcmp(&p2->ip_src_addr, &p1->ip_dst_addr,
! 313: sizeof(struct ip_address)))
! 314: return 1;
! 315: } else if (!p2->ip_ver) {
! 316: if (p1->eth_type == p2->eth_type &&
! 317: !memcmp(p1->eth_src_addr, p2->eth_dst_addr,
! 318: ETHER_ADDR_LEN) &&
! 319: !memcmp(p2->eth_src_addr, p1->eth_dst_addr,
! 320: ETHER_ADDR_LEN))
! 321: return 1;
! 322: }
! 323: return 0;
! 324: }
! 325:
! 326: int
! 327: netstat_fetch(list, ph)
! 328: NETSTAT **list[];
! 329: PCAP_HANDLER *ph;
! 330: {
! 331: struct htab *ht;
! 332: int op, cnt, i;
! 333: NETSTAT *ns, **array;
! 334:
! 335: /* sanity check */
! 336: if (!list || !ph) {
! 337: errno = EINVAL;
! 338: return -1;
! 339: }
! 340:
! 341: if ((cnt = netstat_count(ph)) < 1) {
! 342: /* free previous */
! 343: if (*list) free(*list);
! 344: *list = 0;
! 345: return 0;
! 346: }
! 347: if ((array = (NETSTAT **)malloc(cnt * sizeof(NETSTAT *))) == 0)
! 348: return -1;
! 349:
! 350: if (ph->ns_mutex) pthread_mutex_lock(ph->ns_mutex);
! 351: ht = ph->ns_hash;
! 352:
! 353: /* reset total statistics */
! 354: ph->pkt_cnt = 0;
! 355: ph->pkt_len = 0;
! 356: ph->data_len = 0;
! 357:
! 358: ph->pkt_cnt_rate = 0;
! 359: ph->pkt_len_rate = 0;
! 360: ph->data_len_rate = 0;
! 361:
! 362: op = hfirst(ht);
! 363: i = 0;
! 364: while (op && i < cnt) {
! 365: ns = hstuff(ht);
! 366: if (ns) {
! 367: array[i++] = ns;
! 368:
! 369: /* collect total statistics */
! 370: ph->pkt_cnt += ns->pkt_cnt;
! 371: ph->pkt_len += ns->pkt_len;
! 372: ph->data_len += ns->data_len;
! 373:
! 374: ph->pkt_cnt_rate += ns->pkt_cnt_rate;
! 375: ph->pkt_len_rate += ns->pkt_len_rate;
! 376: ph->data_len_rate += ns->data_len_rate;
! 377: }
! 378: op = hnext(ht);
! 379: }
! 380: /* free previous */
! 381: if (*list) free(*list);
! 382: *list = array;
! 383:
! 384: if (ph->ns_mutex) pthread_mutex_unlock(ph->ns_mutex);
! 385: return i;
! 386: }
! 387:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>