Annotation of embedaddon/iftop/iftop.c, revision 1.1.1.2
1.1 misho 1: /*
2: * iftop.c:
3: *
4: */
5:
6: #include "integers.h"
7:
8: #include <stdio.h>
9: #include <stdlib.h>
10: #include <time.h>
11: #include <sys/types.h>
12: #include <sys/ioctl.h>
13: #include <sys/socket.h>
14: #include <net/if.h>
1.1.1.2 ! misho 15: /* include <net/bpf.h> -- this was added by the PFLOG patch but seems
! 16: * superfluous and breaks on Slackware */
! 17: #if defined(HAVE_PCAP_H)
! 18: # include <pcap.h>
! 19: #elif defined(HAVE_PCAP_PCAP_H)
! 20: # include <pcap/pcap.h>
! 21: #else
! 22: # error No pcap.h
! 23: #endif
1.1 misho 24:
25: #include <pthread.h>
26: #include <curses.h>
27: #include <signal.h>
28: #include <string.h>
29: #include <unistd.h>
1.1.1.2 ! misho 30: #include <locale.h>
1.1 misho 31:
32: #include "iftop.h"
33: #include "addr_hash.h"
34: #include "resolver.h"
1.1.1.2 ! misho 35: #include "ui_common.h"
1.1 misho 36: #include "ui.h"
1.1.1.2 ! misho 37: #include "tui.h"
1.1 misho 38: #include "options.h"
39: #ifdef DLT_LINUX_SLL
40: #include "sll.h"
41: #endif /* DLT_LINUX_SLL */
42: #include "threadprof.h"
43: #include "ether.h"
44: #include "ip.h"
45: #include "tcp.h"
46: #include "token.h"
47: #include "llc.h"
48: #include "extract.h"
49: #include "ethertype.h"
50: #include "cfgfile.h"
51: #include "ppp.h"
1.1.1.2 ! misho 52: #include "addrs_ioctl.h"
1.1 misho 53:
1.1.1.2 ! misho 54: #include <netinet/ip6.h>
1.1 misho 55:
56: /* ethernet address of interface. */
57: int have_hw_addr = 0;
1.1.1.2 ! misho 58: char if_hw_addr[6];
1.1 misho 59:
60: /* IP address of interface */
61: int have_ip_addr = 0;
1.1.1.2 ! misho 62: int have_ip6_addr = 0;
1.1 misho 63: struct in_addr if_ip_addr;
1.1.1.2 ! misho 64: struct in6_addr if_ip6_addr;
1.1 misho 65:
66: extern options_t options;
67:
68: hash_type* history;
69: history_type history_totals;
70: time_t last_timestamp;
1.1.1.2 ! misho 71: time_t first_timestamp;
1.1 misho 72: int history_pos = 0;
73: int history_len = 1;
74: pthread_mutex_t tick_mutex;
75:
76: pcap_t* pd; /* pcap descriptor */
77: struct bpf_program pcap_filter;
78: pcap_handler packet_handler;
79:
80: sig_atomic_t foad;
81:
82: static void finish(int sig) {
83: foad = sig;
84: }
85:
86:
87:
88:
1.1.1.2 ! misho 89: /* Only need ethernet (plus optional 4 byte VLAN) and IP headers (48) + first 2
! 90: * bytes of tcp/udp header */
! 91: /* Increase with a further 20 to account for IPv6 header length. */
! 92: /* IEEE 802.11 radiotap throws in a variable length header plus 8 (radiotap
! 93: * header header) plus 34 (802.11 MAC) plus 40 (IPv6) = 78, plus whatever's in
! 94: * the radiotap payload */
! 95: /*#define CAPTURE_LENGTH 92 */
! 96: #define CAPTURE_LENGTH 256
1.1 misho 97:
98: void init_history() {
99: history = addr_hash_create();
100: last_timestamp = time(NULL);
101: memset(&history_totals, 0, sizeof history_totals);
102: }
103:
104: history_type* history_create() {
105: history_type* h;
106: h = xcalloc(1, sizeof *h);
107: return h;
108: }
109:
110: void history_rotate() {
111: hash_node_type* n = NULL;
112: history_pos = (history_pos + 1) % HISTORY_LENGTH;
113: hash_next_item(history, &n);
114: while(n != NULL) {
115: hash_node_type* next = n;
116: history_type* d = (history_type*)n->rec;
117: hash_next_item(history, &next);
118:
119: if(d->last_write == history_pos) {
120: addr_pair key = *(addr_pair*)(n->key);
121: hash_delete(history, &key);
122: free(d);
123: }
124: else {
125: d->recv[history_pos] = 0;
126: d->sent[history_pos] = 0;
127: }
128: n = next;
129: }
130:
131: history_totals.sent[history_pos] = 0;
132: history_totals.recv[history_pos] = 0;
133:
134: if(history_len < HISTORY_LENGTH) {
135: history_len++;
136: }
137: }
138:
139:
140: void tick(int print) {
141: time_t t;
142:
143: pthread_mutex_lock(&tick_mutex);
144:
145: t = time(NULL);
146: if(t - last_timestamp >= RESOLUTION) {
147: analyse_data();
1.1.1.2 ! misho 148: if (options.no_curses) {
! 149: if (!options.timed_output || (options.timed_output && t - first_timestamp >= options.timed_output)) {
! 150: tui_print();
! 151: if (options.timed_output) {
! 152: finish(SIGINT);
! 153: }
! 154: }
! 155: }
! 156: else {
! 157: ui_print();
! 158: }
1.1 misho 159: history_rotate();
160: last_timestamp = t;
161: }
162: else {
1.1.1.2 ! misho 163: if (options.no_curses) {
! 164: tui_tick(print);
! 165: }
! 166: else {
! 167: ui_tick(print);
! 168: }
1.1 misho 169: }
170:
171: pthread_mutex_unlock(&tick_mutex);
172: }
173:
174: int in_filter_net(struct in_addr addr) {
175: int ret;
176: ret = ((addr.s_addr & options.netfiltermask.s_addr) == options.netfilternet.s_addr);
177: return ret;
178: }
179:
1.1.1.2 ! misho 180: static int __inline__ ip_addr_match(struct in_addr addr) {
1.1 misho 181: return addr.s_addr == if_ip_addr.s_addr;
182: }
183:
1.1.1.2 ! misho 184: static int __inline__ ip6_addr_match(struct in6_addr *addr) {
! 185: return IN6_ARE_ADDR_EQUAL(addr, &if_ip6_addr);
! 186: }
! 187:
1.1 misho 188: /**
189: * Creates an addr_pair from an ip (and tcp/udp) header, swapping src and dst
190: * if required
191: */
192: void assign_addr_pair(addr_pair* ap, struct ip* iptr, int flip) {
193: unsigned short int src_port = 0;
194: unsigned short int dst_port = 0;
195:
1.1.1.2 ! misho 196: /* Arrange for predictable values. */
! 197: memset(ap, '\0', sizeof(*ap));
! 198:
! 199: if(IP_V(iptr) == 4) {
! 200: ap->af = AF_INET;
1.1 misho 201: /* Does this protocol use ports? */
202: if(iptr->ip_p == IPPROTO_TCP || iptr->ip_p == IPPROTO_UDP) {
203: /* We take a slight liberty here by treating UDP the same as TCP */
204:
205: /* Find the TCP/UDP header */
206: struct tcphdr* thdr = ((void*)iptr) + IP_HL(iptr) * 4;
207: src_port = ntohs(thdr->th_sport);
208: dst_port = ntohs(thdr->th_dport);
209: }
210:
211: if(flip == 0) {
212: ap->src = iptr->ip_src;
213: ap->src_port = src_port;
214: ap->dst = iptr->ip_dst;
215: ap->dst_port = dst_port;
216: }
217: else {
218: ap->src = iptr->ip_dst;
219: ap->src_port = dst_port;
220: ap->dst = iptr->ip_src;
221: ap->dst_port = src_port;
222: }
1.1.1.2 ! misho 223: } /* IPv4 */
! 224: else if (IP_V(iptr) == 6) {
! 225: /* IPv6 packet seen. */
! 226: struct ip6_hdr *ip6tr = (struct ip6_hdr *) iptr;
1.1 misho 227:
1.1.1.2 ! misho 228: ap->af = AF_INET6;
! 229:
! 230: if( (ip6tr->ip6_nxt == IPPROTO_TCP) || (ip6tr->ip6_nxt == IPPROTO_UDP) ) {
! 231: struct tcphdr *thdr = ((void *) ip6tr) + 40;
! 232:
! 233: src_port = ntohs(thdr->th_sport);
! 234: dst_port = ntohs(thdr->th_dport);
! 235: }
! 236:
! 237: if(flip == 0) {
! 238: memcpy(&ap->src6, &ip6tr->ip6_src, sizeof(ap->src6));
! 239: ap->src_port = src_port;
! 240: memcpy(&ap->dst6, &ip6tr->ip6_dst, sizeof(ap->dst6));
! 241: ap->dst_port = dst_port;
! 242: }
! 243: else {
! 244: memcpy(&ap->src6, &ip6tr->ip6_dst, sizeof(ap->src6));
! 245: ap->src_port = dst_port;
! 246: memcpy(&ap->dst6, &ip6tr->ip6_src, sizeof(ap->dst6));
! 247: ap->dst_port = src_port;
! 248: }
! 249: }
1.1 misho 250: }
251:
252: static void handle_ip_packet(struct ip* iptr, int hw_dir)
253: {
254: int direction = 0; /* incoming */
255: history_type* ht;
256: union {
1.1.1.2 ! misho 257: history_type **ht_pp;
! 258: void **void_pp;
1.1 misho 259: } u_ht = { &ht };
260: addr_pair ap;
1.1.1.2 ! misho 261: unsigned int len = 0;
! 262: struct in6_addr scribdst; /* Scratch pad. */
! 263: struct in6_addr scribsrc; /* Scratch pad. */
! 264: /* Reinterpret packet type. */
! 265: struct ip6_hdr* ip6tr = (struct ip6_hdr *) iptr;
! 266:
! 267: memset(&ap, '\0', sizeof(ap));
! 268:
! 269: tick(0);
1.1 misho 270:
1.1.1.2 ! misho 271: if( (IP_V(iptr) ==4 && options.netfilter == 0)
! 272: || (IP_V(iptr) == 6 && options.netfilter6 == 0) ) {
1.1 misho 273: /*
274: * Net filter is off, so assign direction based on MAC address
275: */
276: if(hw_dir == 1) {
277: /* Packet leaving this interface. */
278: assign_addr_pair(&ap, iptr, 0);
279: direction = 1;
280: }
281: else if(hw_dir == 0) {
282: /* Packet incoming */
283: assign_addr_pair(&ap, iptr, 1);
284: direction = 0;
285: }
286: /* Packet direction is not given away by h/ware layer. Try IP
287: * layer
288: */
1.1.1.2 ! misho 289: else if((IP_V(iptr) == 4) && have_ip_addr && ip_addr_match(iptr->ip_src)) {
! 290: /* outgoing */
! 291: assign_addr_pair(&ap, iptr, 0);
! 292: direction = 1;
! 293: }
! 294: else if((IP_V(iptr) == 4) && have_ip_addr && ip_addr_match(iptr->ip_dst)) {
! 295: /* incoming */
! 296: assign_addr_pair(&ap, iptr, 1);
! 297: direction = 0;
! 298: }
! 299: else if((IP_V(iptr) == 6) && have_ip6_addr && ip6_addr_match(&ip6tr->ip6_src)) {
1.1 misho 300: /* outgoing */
301: assign_addr_pair(&ap, iptr, 0);
302: direction = 1;
303: }
1.1.1.2 ! misho 304: else if((IP_V(iptr) == 6) && have_ip6_addr && ip6_addr_match(&ip6tr->ip6_dst)) {
1.1 misho 305: /* incoming */
306: assign_addr_pair(&ap, iptr, 1);
307: direction = 0;
308: }
1.1.1.2 ! misho 309: else if (IP_V(iptr) == 4 && IN_MULTICAST(iptr->ip_dst.s_addr)) {
! 310: assign_addr_pair(&ap, iptr, 1);
! 311: direction = 0;
! 312: }
! 313: else if (IP_V(iptr) == 6 && IN6_IS_ADDR_MULTICAST(&ip6tr->ip6_dst)) {
! 314: assign_addr_pair(&ap, iptr, 1);
! 315: direction = 0;
! 316: }
1.1 misho 317: /*
318: * Cannot determine direction from hardware or IP levels. Therefore
319: * assume that it was a packet between two other machines, assign
320: * source and dest arbitrarily (by numerical value) and account as
321: * incoming.
322: */
323: else if (options.promiscuous_but_choosy) {
324: return; /* junk it */
325: }
1.1.1.2 ! misho 326: else if((IP_V(iptr) == 4) && (iptr->ip_src.s_addr < iptr->ip_dst.s_addr)) {
1.1 misho 327: assign_addr_pair(&ap, iptr, 1);
328: direction = 0;
329: }
1.1.1.2 ! misho 330: else if(IP_V(iptr) == 4) {
1.1 misho 331: assign_addr_pair(&ap, iptr, 0);
332: direction = 0;
333: }
1.1.1.2 ! misho 334: /* Drop other uncertain packages. */
! 335: else
! 336: return;
1.1 misho 337: }
1.1.1.2 ! misho 338:
! 339: if(IP_V(iptr) == 4 && options.netfilter != 0) {
1.1 misho 340: /*
341: * Net filter on, assign direction according to netmask
342: */
343: if(in_filter_net(iptr->ip_src) && !in_filter_net(iptr->ip_dst)) {
344: /* out of network */
345: assign_addr_pair(&ap, iptr, 0);
346: direction = 1;
347: }
348: else if(in_filter_net(iptr->ip_dst) && !in_filter_net(iptr->ip_src)) {
349: /* into network */
350: assign_addr_pair(&ap, iptr, 1);
351: direction = 0;
352: }
353: else {
354: /* drop packet */
355: return ;
356: }
357: }
358:
1.1.1.2 ! misho 359: if(IP_V(iptr) == 6 && options.netfilter6 != 0) {
! 360: /*
! 361: * Net filter IPv6 active.
! 362: */
! 363: int j;
! 364: //else if((IP_V(iptr) == 6) && have_ip6_addr && ip6_addr_match(&ip6tr->ip6_dst)) {
! 365: /* First reduce the participating addresses using the netfilter prefix.
! 366: * We need scratch pads to do this.
! 367: */
! 368: for (j=0; j < 16; ++j) {
! 369: scribdst.s6_addr[j] = ip6tr->ip6_dst.s6_addr[j]
! 370: & options.netfilter6mask.s6_addr[j];
! 371: scribsrc.s6_addr[j] = ip6tr->ip6_src.s6_addr[j]
! 372: & options.netfilter6mask.s6_addr[j];
! 373: }
! 374:
! 375: /* Now look for any hits. */
! 376: //if(in_filter_net(iptr->ip_src) && !in_filter_net(iptr->ip_dst)) {
! 377: if (IN6_ARE_ADDR_EQUAL(&scribsrc, &options.netfilter6net)
! 378: && ! IN6_ARE_ADDR_EQUAL(&scribdst, &options.netfilter6net)) {
! 379: /* out of network */
! 380: assign_addr_pair(&ap, iptr, 0);
! 381: direction = 1;
! 382: }
! 383: //else if(in_filter_net(iptr->ip_dst) && !in_filter_net(iptr->ip_src)) {
! 384: else if (! IN6_ARE_ADDR_EQUAL(&scribsrc, &options.netfilter6net)
! 385: && IN6_ARE_ADDR_EQUAL(&scribdst, &options.netfilter6net)) {
! 386: /* into network */
! 387: assign_addr_pair(&ap, iptr, 1);
! 388: direction = 0;
! 389: }
! 390: else {
! 391: /* drop packet */
! 392: return ;
! 393: }
! 394: }
! 395:
! 396: #if 1
! 397: /* Test if link-local IPv6 packets should be dropped. */
! 398: if( IP_V(iptr) == 6 && !options.link_local
! 399: && (IN6_IS_ADDR_LINKLOCAL(&ip6tr->ip6_dst)
! 400: || IN6_IS_ADDR_LINKLOCAL(&ip6tr->ip6_src)) )
! 401: return;
! 402: #endif
! 403:
! 404: /* Do address resolving. */
! 405: switch (IP_V(iptr)) {
! 406: case 4:
! 407: ap.protocol = iptr->ip_p;
! 408: /* Add the addresses to be resolved */
! 409: /* The IPv4 address is embedded in a in6_addr structure,
! 410: * so it need be copied, and delivered to resolve(). */
! 411: memset(&scribdst, '\0', sizeof(scribdst));
! 412: memcpy(&scribdst, &iptr->ip_dst, sizeof(struct in_addr));
! 413: resolve(ap.af, &scribdst, NULL, 0);
! 414: memset(&scribsrc, '\0', sizeof(scribsrc));
! 415: memcpy(&scribsrc, &iptr->ip_src, sizeof(struct in_addr));
! 416: resolve(ap.af, &scribsrc, NULL, 0);
! 417: break;
! 418: case 6:
! 419: ap.protocol = ip6tr->ip6_nxt;
! 420: /* Add the addresses to be resolved */
! 421: resolve(ap.af, &ip6tr->ip6_dst, NULL, 0);
! 422: resolve(ap.af, &ip6tr->ip6_src, NULL, 0);
! 423: default:
! 424: break;
! 425: }
1.1 misho 426:
427:
428: if(hash_find(history, &ap, u_ht.void_pp) == HASH_STATUS_KEY_NOT_FOUND) {
429: ht = history_create();
430: hash_insert(history, &ap, ht);
431: }
432:
1.1.1.2 ! misho 433: /* Do accounting. */
! 434: switch (IP_V(iptr)) {
! 435: case 4:
! 436: len = ntohs(iptr->ip_len);
! 437: break;
! 438: case 6:
! 439: len = ntohs(ip6tr->ip6_plen) + 40;
! 440: default:
! 441: break;
! 442: }
1.1 misho 443:
444: /* Update record */
445: ht->last_write = history_pos;
1.1.1.2 ! misho 446: if( ((IP_V(iptr) == 4) && (iptr->ip_src.s_addr == ap.src.s_addr))
! 447: || ((IP_V(iptr) == 6) && !memcmp(&ip6tr->ip6_src, &ap.src6, sizeof(ap.src6))) )
! 448: {
1.1 misho 449: ht->sent[history_pos] += len;
450: ht->total_sent += len;
451: }
452: else {
453: ht->recv[history_pos] += len;
454: ht->total_recv += len;
455: }
456:
457: if(direction == 0) {
458: /* incoming */
459: history_totals.recv[history_pos] += len;
460: history_totals.total_recv += len;
461: }
462: else {
463: history_totals.sent[history_pos] += len;
464: history_totals.total_sent += len;
465: }
466:
467: }
468:
469: static void handle_raw_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
470: {
471: handle_ip_packet((struct ip*)packet, -1);
472: }
473:
1.1.1.2 ! misho 474: #ifdef DLT_PFLOG
! 475: static void handle_pflog_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
! 476: {
! 477: register u_int length = pkthdr->len;
! 478: u_int hdrlen;
! 479: const struct pfloghdr *hdr;
! 480:
! 481: hdr = (struct pfloghdr *)packet;
! 482: hdrlen = BPF_WORDALIGN(hdr->length);
! 483: length -= hdrlen;
! 484: packet += hdrlen;
! 485: handle_ip_packet((struct ip*)packet, -1);
! 486: }
! 487: #endif
! 488:
! 489: static void handle_null_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
! 490: {
! 491: handle_ip_packet((struct ip*)(packet + 4), -1);
! 492: }
! 493:
1.1 misho 494: static void handle_llc_packet(const struct llc* llc, int dir) {
495:
496: struct ip* ip = (struct ip*)((void*)llc + sizeof(struct llc));
497:
498: /* Taken from tcpdump/print-llc.c */
499: if(llc->ssap == LLCSAP_SNAP && llc->dsap == LLCSAP_SNAP
500: && llc->llcui == LLC_UI) {
501: u_int32_t orgcode;
1.1.1.2 ! misho 502: u_int16_t et;
1.1 misho 503: orgcode = EXTRACT_24BITS(&llc->llc_orgcode[0]);
1.1.1.2 ! misho 504: et = (llc->llc_ethertype[0] << 8) + llc->llc_ethertype[1];
1.1 misho 505: switch(orgcode) {
506: case OUI_ENCAP_ETHER:
507: case OUI_CISCO_90:
508: handle_ip_packet(ip, dir);
509: break;
510: case OUI_APPLETALK:
511: if(et == ETHERTYPE_ATALK) {
512: handle_ip_packet(ip, dir);
513: }
514: break;
515: default:;
516: /* Not a lot we can do */
517: }
518: }
519: }
520:
521: static void handle_tokenring_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
522: {
523: struct token_header *trp;
524: int dir = -1;
525: trp = (struct token_header *)packet;
526:
527: if(IS_SOURCE_ROUTED(trp)) {
528: packet += RIF_LENGTH(trp);
529: }
530: packet += TOKEN_HDRLEN;
531:
532: if(memcmp(trp->token_shost, if_hw_addr, 6) == 0 ) {
533: /* packet leaving this i/f */
534: dir = 1;
535: }
536: else if(memcmp(trp->token_dhost, if_hw_addr, 6) == 0 || memcmp("\xFF\xFF\xFF\xFF\xFF\xFF", trp->token_dhost, 6) == 0) {
537: /* packet entering this i/f */
538: dir = 0;
539: }
540:
541: /* Only know how to deal with LLC encapsulated packets */
542: if(FRAME_TYPE(trp) == TOKEN_FC_LLC) {
543: handle_llc_packet((struct llc*)packet, dir);
544: }
545: }
546:
547: static void handle_ppp_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
548: {
549: register u_int length = pkthdr->len;
550: register u_int caplen = pkthdr->caplen;
551: u_int proto;
552:
553: if (caplen < 2)
554: return;
555:
556: if(packet[0] == PPP_ADDRESS) {
557: if (caplen < 4)
558: return;
559:
560: packet += 2;
561: length -= 2;
562:
563: proto = EXTRACT_16BITS(packet);
564: packet += 2;
565: length -= 2;
566:
1.1.1.2 ! misho 567: if(proto == PPP_IP || proto == ETHERTYPE_IP || proto == ETHERTYPE_IPV6) {
1.1 misho 568: handle_ip_packet((struct ip*)packet, -1);
569: }
570: }
571: }
572:
573: #ifdef DLT_LINUX_SLL
574: static void handle_cooked_packet(unsigned char *args, const struct pcap_pkthdr * thdr, const unsigned char * packet)
575: {
576: struct sll_header *sptr;
577: int dir = -1;
578: sptr = (struct sll_header *) packet;
579:
580: switch (ntohs(sptr->sll_pkttype))
581: {
582: case LINUX_SLL_HOST:
583: /*entering this interface*/
584: dir = 0;
585: break;
586: case LINUX_SLL_OUTGOING:
587: /*leaving this interface */
588: dir=1;
589: break;
590: }
591: handle_ip_packet((struct ip*)(packet+SLL_HDR_LEN), dir);
592: }
593: #endif /* DLT_LINUX_SLL */
594:
595: static void handle_eth_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
596: {
597: struct ether_header *eptr;
598: int ether_type;
599: const unsigned char *payload;
600: eptr = (struct ether_header*)packet;
601: ether_type = ntohs(eptr->ether_type);
602: payload = packet + sizeof(struct ether_header);
603:
604: if(ether_type == ETHERTYPE_8021Q) {
1.1.1.2 ! misho 605: struct vlan_8021q_header* vptr;
! 606: vptr = (struct vlan_8021q_header*)payload;
! 607: ether_type = ntohs(vptr->ether_type);
1.1 misho 608: payload += sizeof(struct vlan_8021q_header);
609: }
610:
1.1.1.2 ! misho 611: if(ether_type == ETHERTYPE_IP || ether_type == ETHERTYPE_IPV6) {
1.1 misho 612: struct ip* iptr;
613: int dir = -1;
614:
615: /*
616: * Is a direction implied by the MAC addresses?
617: */
618: if(have_hw_addr && memcmp(eptr->ether_shost, if_hw_addr, 6) == 0 ) {
619: /* packet leaving this i/f */
620: dir = 1;
621: }
622: else if(have_hw_addr && memcmp(eptr->ether_dhost, if_hw_addr, 6) == 0 ) {
1.1.1.2 ! misho 623: /* packet entering this i/f */
! 624: dir = 0;
! 625: }
! 626: else if (memcmp("\xFF\xFF\xFF\xFF\xFF\xFF", eptr->ether_dhost, 6) == 0) {
! 627: /* broadcast packet, count as incoming */
1.1 misho 628: dir = 0;
629: }
630:
1.1.1.2 ! misho 631: /* Distinguishing ip_hdr and ip6_hdr will be done later. */
1.1 misho 632: iptr = (struct ip*)(payload); /* alignment? */
633: handle_ip_packet(iptr, dir);
634: }
635: }
636:
1.1.1.2 ! misho 637: #ifdef DLT_IEEE802_11_RADIO
! 638: /*
! 639: * Packets with a bonus radiotap header.
! 640: * See http://www.gsp.com/cgi-bin/man.cgi?section=9&topic=ieee80211_radiotap
! 641: */
! 642: static void handle_radiotap_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
! 643: {
! 644: /* 802.11 MAC header is = 34 bytes (not sure if that's universally true) */
! 645: /* We could try harder to figure out hardware direction from the MAC header */
! 646: handle_ip_packet((struct ip*)(packet + ((struct radiotap_header *)packet)->it_len + 34),-1);
! 647: }
! 648:
! 649:
! 650: #endif
1.1 misho 651:
652: /* set_filter_code:
653: * Install some filter code. Returns NULL on success or an error message on
654: * failure. */
655: char *set_filter_code(const char *filter) {
656: char *x;
657: if (filter) {
1.1.1.2 ! misho 658: x = xmalloc(strlen(filter) + sizeof "() and (ip or ip6)");
! 659: sprintf(x, "(%s) and (ip or ip6)", filter);
1.1 misho 660: } else
1.1.1.2 ! misho 661: x = xstrdup("ip or ip6");
1.1 misho 662: if (pcap_compile(pd, &pcap_filter, x, 1, 0) == -1) {
663: xfree(x);
664: return pcap_geterr(pd);
665: }
666: xfree(x);
667: if (pcap_setfilter(pd, &pcap_filter) == -1)
668: return pcap_geterr(pd);
669: else
670: return NULL;
671: }
672:
673:
674:
675: /*
676: * packet_init:
677: *
678: * performs pcap initialisation, called before ui is initialised
679: */
680: void packet_init() {
681: char errbuf[PCAP_ERRBUF_SIZE];
682: char *m;
683: int i;
684: int dlt;
685: int result;
686:
687: #ifdef HAVE_DLPI
688: result = get_addrs_dlpi(options.interface, if_hw_addr, &if_ip_addr);
689: #else
1.1.1.2 ! misho 690: result = get_addrs_ioctl(options.interface, if_hw_addr,
! 691: &if_ip_addr, &if_ip6_addr);
1.1 misho 692: #endif
693:
694: if (result < 0) {
695: exit(1);
696: }
697:
1.1.1.2 ! misho 698: have_hw_addr = result & 0x01;
! 699: have_ip_addr = result & 0x02;
! 700: have_ip6_addr = result & 0x04;
1.1 misho 701:
702: if(have_ip_addr) {
703: fprintf(stderr, "IP address is: %s\n", inet_ntoa(if_ip_addr));
704: }
1.1.1.2 ! misho 705: if(have_ip6_addr) {
! 706: char ip6str[INET6_ADDRSTRLEN];
! 707:
! 708: ip6str[0] = '\0';
! 709: inet_ntop(AF_INET6, &if_ip6_addr, ip6str, sizeof(ip6str));
! 710: fprintf(stderr, "IPv6 address is: %s\n", ip6str);
! 711: }
1.1 misho 712:
713: if(have_hw_addr) {
714: fprintf(stderr, "MAC address is:");
715: for (i = 0; i < 6; ++i)
716: fprintf(stderr, "%c%02x", i ? ':' : ' ', (unsigned int)if_hw_addr[i]);
717: fprintf(stderr, "\n");
718: }
719:
720: // exit(0);
721: resolver_initialise();
722:
723: pd = pcap_open_live(options.interface, CAPTURE_LENGTH, options.promiscuous, 1000, errbuf);
724: // DEBUG: pd = pcap_open_offline("tcpdump.out", errbuf);
725: if(pd == NULL) {
726: fprintf(stderr, "pcap_open_live(%s): %s\n", options.interface, errbuf);
727: exit(1);
728: }
729: dlt = pcap_datalink(pd);
730: if(dlt == DLT_EN10MB) {
731: packet_handler = handle_eth_packet;
732: }
1.1.1.2 ! misho 733: #ifdef DLT_PFLOG
! 734: else if (dlt == DLT_PFLOG) {
! 735: packet_handler = handle_pflog_packet;
! 736: }
! 737: #endif
! 738: else if(dlt == DLT_RAW) {
1.1 misho 739: packet_handler = handle_raw_packet;
740: }
1.1.1.2 ! misho 741: else if(dlt == DLT_NULL) {
! 742: packet_handler = handle_null_packet;
! 743: }
! 744: #ifdef DLT_LOOP
! 745: else if(dlt == DLT_LOOP) {
! 746: packet_handler = handle_null_packet;
! 747: }
! 748: #endif
! 749: #ifdef DLT_IEEE802_11_RADIO
! 750: else if(dlt == DLT_IEEE802_11_RADIO) {
! 751: packet_handler = handle_radiotap_packet;
! 752: }
! 753: #endif
1.1 misho 754: else if(dlt == DLT_IEEE802) {
755: packet_handler = handle_tokenring_packet;
756: }
757: else if(dlt == DLT_PPP) {
758: packet_handler = handle_ppp_packet;
759: }
760: /*
761: * SLL support not available in older libpcaps
762: */
763: #ifdef DLT_LINUX_SLL
764: else if(dlt == DLT_LINUX_SLL) {
765: packet_handler = handle_cooked_packet;
766: }
767: #endif
768: else {
769: fprintf(stderr, "Unsupported datalink type: %d\n"
770: "Please email pdw@ex-parrot.com, quoting the datalink type and what you were\n"
771: "trying to do at the time\n.", dlt);
772: exit(1);
773: }
774:
775: if ((m = set_filter_code(options.filtercode))) {
776: fprintf(stderr, "set_filter_code: %s\n", m);
777: exit(1);
778: return;
779: }
780: }
781:
782: /* packet_loop:
783: * Worker function for packet capture thread. */
784: void packet_loop(void* ptr) {
785: pcap_loop(pd,-1,(pcap_handler)packet_handler,NULL);
786: }
787:
788:
789: /* main:
790: * Entry point. See usage(). */
791: int main(int argc, char **argv) {
792: pthread_t thread;
793: struct sigaction sa = {};
794:
1.1.1.2 ! misho 795: setlocale(LC_ALL, "");
! 796:
1.1 misho 797: /* TODO: tidy this up */
798: /* read command line options and config file */
799: config_init();
800: options_set_defaults();
801: options_read_args(argc, argv);
802: /* If a config was explicitly specified, whinge if it can't be found */
803: read_config(options.config_file, options.config_file_specified);
804: options_make();
805:
806: sa.sa_handler = finish;
807: sigaction(SIGINT, &sa, NULL);
808:
809: pthread_mutex_init(&tick_mutex, NULL);
810:
811: packet_init();
812:
813: init_history();
814:
1.1.1.2 ! misho 815: if (options.no_curses) {
! 816: tui_init();
! 817: }
! 818: else {
! 819: ui_init();
! 820: }
1.1 misho 821:
822: pthread_create(&thread, NULL, (void*)&packet_loop, NULL);
823:
1.1.1.2 ! misho 824: /* Keep the starting time (used for timed termination) */
! 825: first_timestamp = time(NULL);
! 826:
! 827: if (options.no_curses) {
! 828: if (options.timed_output) {
! 829: while(!foad) {
! 830: sleep(1);
! 831: }
! 832: }
! 833: else {
! 834: tui_loop();
! 835: }
! 836: }
! 837: else {
! 838: ui_loop();
! 839: }
1.1 misho 840:
841: pthread_cancel(thread);
842:
843: ui_finish();
844:
845: return 0;
846: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>