Blame view

pdw committed
1 2 3 4 5
/*
 * iftop.c:
 *
 */

chris committed
6 7
#include "integers.h"

pdw committed
8 9 10
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
11
#include <sys/types.h>
chris committed
12
#include <sys/ioctl.h>
13
#include <sys/socket.h>
chris committed
14
#include <net/if.h>
15 16
/* include <net/bpf.h> -- this was added by the PFLOG patch but seems
 * superfluous and breaks on Slackware */
17 18 19 20 21 22 23
#if defined(HAVE_PCAP_H)
#   include <pcap.h>
#elif defined(HAVE_PCAP_PCAP_H)
#   include <pcap/pcap.h>
#else
#   error No pcap.h
#endif
24

pdw committed
25 26 27 28
#include <pthread.h>
#include <curses.h>
#include <signal.h>
#include <string.h>
chris committed
29
#include <unistd.h>
30
#include <locale.h>
pdw committed
31 32 33 34

#include "iftop.h"
#include "addr_hash.h"
#include "resolver.h"
35
#include "ui_common.h"
pdw committed
36
#include "ui.h"
37
#include "tui.h"
pdw committed
38
#include "options.h"
chris committed
39
#ifdef DLT_LINUX_SLL
40
#include "sll.h"
chris committed
41
#endif /* DLT_LINUX_SLL */
pdw committed
42
#include "threadprof.h"
43 44 45
#include "ether.h"
#include "ip.h"
#include "tcp.h"
pdw committed
46 47 48 49
#include "token.h"
#include "llc.h"
#include "extract.h"
#include "ethertype.h"
pdw committed
50
#include "cfgfile.h"
pdw committed
51
#include "ppp.h"
52
#include "addrs_ioctl.h"
pdw committed
53

54
#include <netinet/ip6.h>
pdw committed
55

56 57
/* ethernet address of interface. */
int have_hw_addr = 0;
Paul Warren committed
58
u_int8_t if_hw_addr[6];
59 60 61

/* IP address of interface */
int have_ip_addr = 0;
62
int have_ip6_addr = 0;
63
struct in_addr if_ip_addr;
64
struct in6_addr if_ip6_addr;
pdw committed
65

pdw committed
66 67
extern options_t options;

pdw committed
68
hash_type* history;
pdw committed
69
history_type history_totals;
pdw committed
70
time_t last_timestamp;
71
time_t first_timestamp;
pdw committed
72 73 74 75
int history_pos = 0;
int history_len = 1;
pthread_mutex_t tick_mutex;

76
pcap_t* pd; /* pcap descriptor */
chris committed
77
struct bpf_program pcap_filter;
78 79
pcap_handler packet_handler;

chris committed
80 81 82 83 84 85
sig_atomic_t foad;

static void finish(int sig) {
    foad = sig;
}

pdw committed
86 87


pdw committed
88

pdw committed
89 90
/* Only need ethernet (plus optional 4 byte VLAN) and IP headers (48) + first 2
 * bytes of tcp/udp header */
91
/* Increase with a further 20 to account for IPv6 header length.  */
pdw committed
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
pdw committed
94
 * the radiotap payload */
95 96
/*#define CAPTURE_LENGTH 92 */
#define CAPTURE_LENGTH 256
pdw committed
97 98 99 100

void init_history() {
    history = addr_hash_create();
    last_timestamp = time(NULL);
pdw committed
101
    memset(&history_totals, 0, sizeof history_totals);
pdw committed
102 103 104 105
}

history_type* history_create() {
    history_type* h;
chris committed
106
    h = xcalloc(1, sizeof *h);
pdw committed
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
    return h;
}

void history_rotate() {
    hash_node_type* n = NULL;
    history_pos = (history_pos + 1) % HISTORY_LENGTH;
    hash_next_item(history, &n);
    while(n != NULL) {
        hash_node_type* next = n;
        history_type* d = (history_type*)n->rec;
        hash_next_item(history, &next);

        if(d->last_write == history_pos) {
            addr_pair key = *(addr_pair*)(n->key);
            hash_delete(history, &key);
pdw committed
122
            free(d);
pdw committed
123 124 125 126 127 128 129
        }
        else {
            d->recv[history_pos] = 0;
            d->sent[history_pos] = 0;
        }
        n = next; 
    }
pdw committed
130 131 132 133

    history_totals.sent[history_pos] = 0;
    history_totals.recv[history_pos] = 0;

pdw committed
134 135 136 137 138 139
    if(history_len < HISTORY_LENGTH) {
        history_len++;
    }
}


140
void tick(int print) {
pdw committed
141 142 143 144 145 146
    time_t t;

    pthread_mutex_lock(&tick_mutex);
   
    t = time(NULL);
    if(t - last_timestamp >= RESOLUTION) {
pdw committed
147
        analyse_data();
148
        if (options.no_curses) {
149
          if (!options.timed_output || (t - first_timestamp >= options.timed_output)) {
150 151 152 153 154 155 156 157 158
            tui_print();
            if (options.timed_output) {
              finish(SIGINT);
            }
          }
        }
        else {
          ui_print();
        }
pdw committed
159 160 161
        history_rotate();
        last_timestamp = t;
    }
pdw committed
162
    else {
163 164 165 166 167 168
      if (options.no_curses) {
        tui_tick(print);
      }
      else {
        ui_tick(print);
      }
169
    }
pdw committed
170 171 172 173

    pthread_mutex_unlock(&tick_mutex);
}

pdw committed
174 175 176 177 178 179
int in_filter_net(struct in_addr addr) {
    int ret;
    ret = ((addr.s_addr & options.netfiltermask.s_addr) == options.netfilternet.s_addr);
    return ret;
}

pdw committed
180
static int __inline__ ip_addr_match(struct in_addr addr) {
181 182 183
    return addr.s_addr == if_ip_addr.s_addr;
}

pdw committed
184
static int __inline__ ip6_addr_match(struct in6_addr *addr) {
185 186 187
    return IN6_ARE_ADDR_EQUAL(addr, &if_ip6_addr);
}

188 189 190 191 192 193 194 195
/**
 * Creates an addr_pair from an ip (and tcp/udp) header, swapping src and dst
 * if required
 */
void assign_addr_pair(addr_pair* ap, struct ip* iptr, int flip) {
  unsigned short int src_port = 0;
  unsigned short int dst_port = 0;

196 197 198 199 200
  /* Arrange for predictable values. */
  memset(ap, '\0', sizeof(*ap));

  if(IP_V(iptr) == 4) {
    ap->af = AF_INET;
201
  /* Does this protocol use ports? */
pdw committed
202
  if(iptr->ip_p == IPPROTO_TCP || iptr->ip_p == IPPROTO_UDP) {
203 204 205
    /* We take a slight liberty here by treating UDP the same as TCP */

    /* Find the TCP/UDP header */
206 207 208
    struct tcphdr* thdr = ((void*)iptr) + IP_HL(iptr) * 4;
    src_port = ntohs(thdr->th_sport);
    dst_port = ntohs(thdr->th_dport);
209 210 211 212 213 214 215 216 217 218 219 220 221 222
  }

  if(flip == 0) {
    ap->src = iptr->ip_src;
    ap->src_port = src_port;
    ap->dst = iptr->ip_dst;
    ap->dst_port = dst_port;
  }
  else {
    ap->src = iptr->ip_dst;
    ap->src_port = dst_port;
    ap->dst = iptr->ip_src;
    ap->dst_port = src_port;
  }
223 224 225 226 227 228 229 230 231 232 233 234 235
  } /* IPv4 */
  else if (IP_V(iptr) == 6) {
    /* IPv6 packet seen. */
    struct ip6_hdr *ip6tr = (struct ip6_hdr *) iptr;

    ap->af = AF_INET6;

    if( (ip6tr->ip6_nxt == IPPROTO_TCP) || (ip6tr->ip6_nxt == IPPROTO_UDP) ) {
      struct tcphdr *thdr = ((void *) ip6tr) + 40;

      src_port = ntohs(thdr->th_sport);
      dst_port = ntohs(thdr->th_dport);
    }
236

237 238 239 240 241 242 243 244 245 246 247 248 249
    if(flip == 0) {
      memcpy(&ap->src6, &ip6tr->ip6_src, sizeof(ap->src6));
      ap->src_port = src_port;
      memcpy(&ap->dst6, &ip6tr->ip6_dst, sizeof(ap->dst6));
      ap->dst_port = dst_port;
    }
    else {
      memcpy(&ap->src6, &ip6tr->ip6_dst, sizeof(ap->src6));
      ap->src_port = dst_port;
      memcpy(&ap->dst6, &ip6tr->ip6_src, sizeof(ap->dst6));
      ap->dst_port = src_port;
    }
  }
250 251
}

252
static void handle_ip_packet(struct ip* iptr, int hw_dir, int pld_len)
pdw committed
253
{
pdw committed
254
    int direction = 0; /* incoming */
255
    int len;
256
    history_type* ht;
257
    union {
pdw committed
258 259
      history_type **ht_pp;
      void **void_pp;
260
    } u_ht = { &ht };
261
    addr_pair ap;
262 263 264 265 266 267
    struct in6_addr scribdst;   /* Scratch pad. */
    struct in6_addr scribsrc;   /* Scratch pad. */
    /* Reinterpret packet type. */
    struct ip6_hdr* ip6tr = (struct ip6_hdr *) iptr;

    memset(&ap, '\0', sizeof(ap));
268

269 270
    tick(0);

271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
    /*
     * Sanity check: drop obviously short packets.
     * pld_len comes from pcaphdr->len - sizeof(struct l2_header).
     *
     * It is assumed that the snaplen (currently hard-coded to 1000) is
     * big enough to always capture the IP header past the L2 encap, and
     * that pcap never truncates the packet to less than snaplen; in
     * other words, that pcaphdr->caplen = MIN(pcaphdr->len, snaplen).
     */
    if (pld_len < sizeof (struct ip))
	return;
    if (IP_V(iptr) == 6 && pld_len < sizeof (struct ip6_hdr))
	return;

    if( (IP_V(iptr) == 4 && options.netfilter == 0)
286
            || (IP_V(iptr) == 6 && options.netfilter6 == 0) ) { 
287 288 289 290 291
        /*
         * Net filter is off, so assign direction based on MAC address
         */
        if(hw_dir == 1) {
            /* Packet leaving this interface. */
292
            assign_addr_pair(&ap, iptr, 0);
293
            direction = 1;
pdw committed
294
        }
295 296
        else if(hw_dir == 0) {
            /* Packet incoming */
297 298
            assign_addr_pair(&ap, iptr, 1);
            direction = 0;
pdw committed
299
        }
300 301 302
        /* Packet direction is not given away by h/ware layer.  Try IP
         * layer
         */
303
        else if((IP_V(iptr) == 4) && have_ip_addr && ip_addr_match(iptr->ip_src)) {
304 305 306 307
            /* outgoing */
            assign_addr_pair(&ap, iptr, 0);
            direction = 1;
        }
308 309 310 311 312 313 314 315 316 317 318
        else if((IP_V(iptr) == 4) && have_ip_addr && ip_addr_match(iptr->ip_dst)) {
            /* incoming */
            assign_addr_pair(&ap, iptr, 1);
            direction = 0;
        }
        else if((IP_V(iptr) == 6) && have_ip6_addr && ip6_addr_match(&ip6tr->ip6_src)) {
            /* outgoing */
            assign_addr_pair(&ap, iptr, 0);
            direction = 1;
        }
        else if((IP_V(iptr) == 6) && have_ip6_addr && ip6_addr_match(&ip6tr->ip6_dst)) {
319 320 321 322
            /* incoming */
            assign_addr_pair(&ap, iptr, 1);
            direction = 0;
        }
323 324 325 326 327 328 329 330
        else if (IP_V(iptr) == 4 && IN_MULTICAST(iptr->ip_dst.s_addr)) {
            assign_addr_pair(&ap, iptr, 1);
            direction = 0;
        }
        else if (IP_V(iptr) == 6 && IN6_IS_ADDR_MULTICAST(&ip6tr->ip6_dst)) {
            assign_addr_pair(&ap, iptr, 1);
            direction = 0;
        }
331
        /*
332 333 334 335
         * Cannot determine direction from hardware or IP levels.  Therefore 
         * assume that it was a packet between two other machines, assign
         * source and dest arbitrarily (by numerical value) and account as 
         * incoming.
336
         */
337 338 339
	else if (options.promiscuous_but_choosy) {
	    return;		/* junk it */
	}
340
        else if((IP_V(iptr) == 4) && (iptr->ip_src.s_addr < iptr->ip_dst.s_addr)) {
pdw committed
341
            assign_addr_pair(&ap, iptr, 1);
342
            direction = 0;
pdw committed
343
        }
344
        else if(IP_V(iptr) == 4) {
345 346
            assign_addr_pair(&ap, iptr, 0);
            direction = 0;
pdw committed
347
        }
348
        /* Drop other uncertain packages. */
349 350
        else
            return;
351
    }
352 353

    if(IP_V(iptr) == 4 && options.netfilter != 0) {
354 355 356
        /* 
         * Net filter on, assign direction according to netmask 
         */ 
357
        if(in_filter_net(iptr->ip_src) && !in_filter_net(iptr->ip_dst)) {
358
            /* out of network */
359
            assign_addr_pair(&ap, iptr, 0);
360 361
            direction = 1;
        }
362
        else if(in_filter_net(iptr->ip_dst) && !in_filter_net(iptr->ip_src)) {
363
            /* into network */
364 365
            assign_addr_pair(&ap, iptr, 1);
            direction = 0;
pdw committed
366 367
        }
        else {
368 369
            /* drop packet */
            return ;
pdw committed
370
        }
371 372
    }

373 374 375 376 377 378 379 380 381
    if(IP_V(iptr) == 6 && options.netfilter6 != 0) {
        /*
         * Net filter IPv6 active.
         */
        int j;
        //else if((IP_V(iptr) == 6) && have_ip6_addr && ip6_addr_match(&ip6tr->ip6_dst)) {
        /* First reduce the participating addresses using the netfilter prefix.
         * We need scratch pads to do this.
         */
382 383 384 385 386
        for (j=0; j < 16; ++j) {
            scribdst.s6_addr[j] = ip6tr->ip6_dst.s6_addr[j]
                                        & options.netfilter6mask.s6_addr[j];
            scribsrc.s6_addr[j] = ip6tr->ip6_src.s6_addr[j]
                                        & options.netfilter6mask.s6_addr[j];
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
        }

        /* Now look for any hits. */
        //if(in_filter_net(iptr->ip_src) && !in_filter_net(iptr->ip_dst)) {
        if (IN6_ARE_ADDR_EQUAL(&scribsrc, &options.netfilter6net)
                && ! IN6_ARE_ADDR_EQUAL(&scribdst, &options.netfilter6net)) {
            /* out of network */
            assign_addr_pair(&ap, iptr, 0);
            direction = 1;
        }
        //else if(in_filter_net(iptr->ip_dst) && !in_filter_net(iptr->ip_src)) {
        else if (! IN6_ARE_ADDR_EQUAL(&scribsrc, &options.netfilter6net)
                    && IN6_ARE_ADDR_EQUAL(&scribdst, &options.netfilter6net)) {
            /* into network */
            assign_addr_pair(&ap, iptr, 1);
            direction = 0;
        }
        else {
            /* drop packet */
            return ;
        }
    }

#if 1
    /* Test if link-local IPv6 packets should be dropped. */
    if( IP_V(iptr) == 6 && !options.link_local
            && (IN6_IS_ADDR_LINKLOCAL(&ip6tr->ip6_dst)
                || IN6_IS_ADDR_LINKLOCAL(&ip6tr->ip6_src)) )
        return;
#endif

    /* Do address resolving. */
    switch (IP_V(iptr)) {
      case 4:
          ap.protocol = iptr->ip_p;
          /* Add the addresses to be resolved */
          /* The IPv4 address is embedded in a in6_addr structure,
           * so it need be copied, and delivered to resolve(). */
          memset(&scribdst, '\0', sizeof(scribdst));
          memcpy(&scribdst, &iptr->ip_dst, sizeof(struct in_addr));
          resolve(ap.af, &scribdst, NULL, 0);
          memset(&scribsrc, '\0', sizeof(scribsrc));
          memcpy(&scribsrc, &iptr->ip_src, sizeof(struct in_addr));
          resolve(ap.af, &scribsrc, NULL, 0);
          break;
      case 6:
          ap.protocol = ip6tr->ip6_nxt;
          /* Add the addresses to be resolved */
          resolve(ap.af, &ip6tr->ip6_dst, NULL, 0);
          resolve(ap.af, &ip6tr->ip6_src, NULL, 0);
      default:
          break;
    }
440

441
    if(hash_find(history, &ap, u_ht.void_pp) == HASH_STATUS_KEY_NOT_FOUND) {
442 443 444 445
        ht = history_create();
        hash_insert(history, &ap, ht);
    }

446
    /* Do accounting. */
447 448 449
    switch (options.bandwidth_unit) {
      case OPTION_BW_BITS:
      case OPTION_BW_BYTES:
450
	  len = pld_len;
451 452 453 454
	  break;
      case OPTION_BW_PKTS:
	  len = 1;
	  break;
455 456
      default:
	  return;
457
    }
458 459 460

    /* Update record */
    ht->last_write = history_pos;
461 462 463
    if( ((IP_V(iptr) == 4) && (iptr->ip_src.s_addr == ap.src.s_addr))
       || ((IP_V(iptr) == 6) && !memcmp(&ip6tr->ip6_src, &ap.src6, sizeof(ap.src6))) )
    {
464
        ht->sent[history_pos] += len;
pdw committed
465
        ht->total_sent += len;
466 467 468
    }
    else {
        ht->recv[history_pos] += len;
pdw committed
469
        ht->total_recv += len;
470
    }
pdw committed
471

472 473
    if(direction == 0) {
        /* incoming */
pdw committed
474
        history_totals.recv[history_pos] += len;
pdw committed
475
        history_totals.total_recv += len;
pdw committed
476
    }
477
    else {
pdw committed
478
        history_totals.sent[history_pos] += len;
pdw committed
479
        history_totals.total_sent += len;
480 481
    }
    
pdw committed
482 483
}

chris committed
484
static void handle_raw_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
485
{
486
    handle_ip_packet((struct ip*)packet, -1, pkthdr->len);
487 488
}

489
#ifdef DLT_PFLOG
490 491 492 493 494 495 496 497 498 499
static void handle_pflog_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
{
	register u_int length = pkthdr->len;
	u_int hdrlen;
	const struct pfloghdr *hdr;
	
	hdr = (struct pfloghdr *)packet;
	hdrlen = BPF_WORDALIGN(hdr->length);
	length -= hdrlen;
	packet += hdrlen;
500
	handle_ip_packet((struct ip*)packet, -1, length);
501
}
502
#endif
503

504
static void handle_null_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
pdw committed
505
{
506
    handle_ip_packet((struct ip*)(packet + 4), -1, pkthdr->len);
pdw committed
507 508
}

509 510 511 512
static void handle_llc_packet(const struct llc* llc, int dir, int llclen) {
    int hdrlen = sizeof(struct llc);
    int pldlen = llclen - hdrlen;
    struct ip* ip = (struct ip*)((void*)llc + hdrlen);
pdw committed
513 514 515 516 517

    /* Taken from tcpdump/print-llc.c */
    if(llc->ssap == LLCSAP_SNAP && llc->dsap == LLCSAP_SNAP
       && llc->llcui == LLC_UI) {
        u_int32_t orgcode;
518
        u_int16_t et;
pdw committed
519
        orgcode = EXTRACT_24BITS(&llc->llc_orgcode[0]);
520
        et = (llc->llc_ethertype[0] << 8) + llc->llc_ethertype[1];
pdw committed
521 522 523
        switch(orgcode) {
          case OUI_ENCAP_ETHER:
          case OUI_CISCO_90:
524
	      handle_ip_packet(ip, dir, pldlen);
pdw committed
525 526 527
            break;
          case OUI_APPLETALK:
            if(et == ETHERTYPE_ATALK) {
528
		handle_ip_packet(ip, dir, pldlen);
pdw committed
529 530
            }
            break;
chris committed
531
          default:;
pdw committed
532 533 534 535 536 537 538 539
            /* Not a lot we can do */
        }
    }
}

static void handle_tokenring_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
{
    struct token_header *trp;
540
    int hdrlen = 0;
pdw committed
541 542 543 544
    int dir = -1;
    trp = (struct token_header *)packet;

    if(IS_SOURCE_ROUTED(trp)) {
545
      hdrlen += RIF_LENGTH(trp);
pdw committed
546
    }
547 548
    hdrlen += TOKEN_HDRLEN;
    packet += hdrlen;
pdw committed
549 550 551 552

    if(memcmp(trp->token_shost, if_hw_addr, 6) == 0 ) {
      /* packet leaving this i/f */
      dir = 1;
553 554
    }
    else if(memcmp(trp->token_dhost, if_hw_addr, 6) == 0 || memcmp("\xFF\xFF\xFF\xFF\xFF\xFF", trp->token_dhost, 6) == 0) {
pdw committed
555 556 557 558 559 560
      /* packet entering this i/f */
      dir = 0;
    }

    /* Only know how to deal with LLC encapsulated packets */
    if(FRAME_TYPE(trp) == TOKEN_FC_LLC) {
561
        handle_llc_packet((struct llc*)packet, dir, pkthdr->len - hdrlen);
pdw committed
562 563 564
    }
}

pdw committed
565 566
static void handle_ppp_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
{
567 568 569
    register u_int length = pkthdr->len;
    register u_int caplen = pkthdr->caplen;
    u_int proto;
pdw committed
570 571 572 573 574 575 576 577 578

	if (caplen < 2) 
        return;

	if(packet[0] == PPP_ADDRESS) {
		if (caplen < 4) 
            return;

		packet += 2;
579
        length -= 2;
pdw committed
580 581 582

		proto = EXTRACT_16BITS(packet);
		packet += 2;
583
		length -= 2;
pdw committed
584

585
        if(proto == PPP_IP || proto == ETHERTYPE_IP || proto == ETHERTYPE_IPV6) {
586
            handle_ip_packet((struct ip*)packet, -1, length);
pdw committed
587 588 589 590
        }
    }
}

chris committed
591
#ifdef DLT_LINUX_SLL
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
static void handle_cooked_packet(unsigned char *args, const struct pcap_pkthdr * thdr, const unsigned char * packet)
{
    struct sll_header *sptr;
    int dir = -1;
    sptr = (struct sll_header *) packet;

    switch (ntohs(sptr->sll_pkttype))
    {
    case LINUX_SLL_HOST:
        /*entering this interface*/
	dir = 0;
	break;
    case LINUX_SLL_OUTGOING:
	/*leaving this interface */
	dir=1;
	break;
    }
609 610
    handle_ip_packet((struct ip*)(packet+SLL_HDR_LEN), dir,
		     thdr->len - SLL_HDR_LEN);
611
}
chris committed
612
#endif /* DLT_LINUX_SLL */
613

chris committed
614
static void handle_eth_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
615 616
{
    struct ether_header *eptr;
617 618
    int ether_type, hdrlen;

619
    eptr = (struct ether_header*)packet;
620
    ether_type = ntohs(eptr->ether_type);
621
    hdrlen = sizeof(struct ether_header);
chris committed
622

623
    if(ether_type == ETHERTYPE_8021Q) {
pdw committed
624
        struct vlan_8021q_header* vptr;
625
        vptr = (struct vlan_8021q_header*) (packet + hdrlen);
pdw committed
626
        ether_type = ntohs(vptr->ether_type);
627
        hdrlen += sizeof(struct vlan_8021q_header);
628 629
    }

630
    if(ether_type == ETHERTYPE_IP || ether_type == ETHERTYPE_IPV6) {
631 632 633 634 635 636
        struct ip* iptr;
        int dir = -1;
        
        /*
         * Is a direction implied by the MAC addresses?
         */
637
        if(have_hw_addr && memcmp(eptr->ether_shost, if_hw_addr, 6) == 0 ) {
638 639
            /* packet leaving this i/f */
            dir = 1;
640 641
        }
        else if(have_hw_addr && memcmp(eptr->ether_dhost, if_hw_addr, 6) == 0 ) {
pdw committed
642 643 644 645 646
            /* packet entering this i/f */
            dir = 0;
        }
        else if (memcmp("\xFF\xFF\xFF\xFF\xFF\xFF", eptr->ether_dhost, 6) == 0) {
            /* broadcast packet, count as incoming */
647 648 649
            dir = 0;
        }

650
        /* Distinguishing ip_hdr and ip6_hdr will be done later. */
651 652
        iptr = (struct ip*) (packet + hdrlen); /* alignment? */
        handle_ip_packet(iptr, dir, pkthdr->len - hdrlen);
653 654 655
    }
}

pdw committed
656 657 658 659 660 661 662
#ifdef DLT_IEEE802_11_RADIO
/*
 * Packets with a bonus radiotap header.
 * See http://www.gsp.com/cgi-bin/man.cgi?section=9&topic=ieee80211_radiotap
 */
static void handle_radiotap_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
{
663
    /* 802.11 MAC header is = 34 bytes (not sure if that's universally true) */
pdw committed
664
    /* We could try harder to figure out hardware direction from the MAC header */
665 666
    int hdrlen = ((struct radiotap_header *)packet)->it_len + 34;
    handle_ip_packet((struct ip*)(packet + hdrlen), -1, pkthdr->len - hdrlen);
pdw committed
667 668 669 670
}


#endif
671

chris committed
672 673 674 675 676 677
/* set_filter_code:
 * Install some filter code. Returns NULL on success or an error message on
 * failure. */
char *set_filter_code(const char *filter) {
    char *x;
    if (filter) {
678 679
        x = xmalloc(strlen(filter) + sizeof "() and (ip or ip6)");
        sprintf(x, "(%s) and (ip or ip6)", filter);
chris committed
680
    } else
681
        x = xstrdup("ip or ip6");
chris committed
682 683 684 685 686 687 688 689 690 691 692 693 694
    if (pcap_compile(pd, &pcap_filter, x, 1, 0) == -1) {
        xfree(x);
        return pcap_geterr(pd);
    }
    xfree(x);
    if (pcap_setfilter(pd, &pcap_filter) == -1)
        return pcap_geterr(pd);
    else
        return NULL;
}



695 696 697 698 699 700
/*
 * packet_init:
 *
 * performs pcap initialisation, called before ui is initialised
 */
void packet_init() {
pdw committed
701
    char errbuf[PCAP_ERRBUF_SIZE];
chris committed
702
    char *m;
703
    int i;
704
    int dlt;
705
    int result;
chris committed
706

707 708
#ifdef HAVE_DLPI
    result = get_addrs_dlpi(options.interface, if_hw_addr, &if_ip_addr);
709
#else
710 711
    result = get_addrs_ioctl(options.interface, if_hw_addr,
          &if_ip_addr, &if_ip6_addr);
712 713
#endif

714 715
    if (result < 0) {
      exit(1);
716 717
    }

718 719 720
    have_hw_addr = result & 0x01;
    have_ip_addr = result & 0x02;
    have_ip6_addr = result & 0x04;
721 722 723
    
    if(have_ip_addr) {
      fprintf(stderr, "IP address is: %s\n", inet_ntoa(if_ip_addr));
724
    }
725 726 727 728 729 730 731
    if(have_ip6_addr) {
       char ip6str[INET6_ADDRSTRLEN];

       ip6str[0] = '\0';
       inet_ntop(AF_INET6, &if_ip6_addr, ip6str, sizeof(ip6str));
       fprintf(stderr, "IPv6 address is: %s\n", ip6str);
    }
732

733 734 735 736 737 738
    if(have_hw_addr) {
      fprintf(stderr, "MAC address is:");
      for (i = 0; i < 6; ++i)
	fprintf(stderr, "%c%02x", i ? ':' : ' ', (unsigned int)if_hw_addr[i]);
      fprintf(stderr, "\n");
    }
chris committed
739
    
740
    //    exit(0);
pdw committed
741 742
    resolver_initialise();

pdw committed
743
    pd = pcap_open_live(options.interface, CAPTURE_LENGTH, options.promiscuous, 1000, errbuf);
pdw committed
744
    // DEBUG: pd = pcap_open_offline("tcpdump.out", errbuf);
pdw committed
745
    if(pd == NULL) { 
pdw committed
746
        fprintf(stderr, "pcap_open_live(%s): %s\n", options.interface, errbuf); 
chris committed
747
        exit(1);
748 749 750 751
    }
    dlt = pcap_datalink(pd);
    if(dlt == DLT_EN10MB) {
        packet_handler = handle_eth_packet;
pdw committed
752
    }
753
#ifdef DLT_PFLOG
754 755 756
    else if (dlt == DLT_PFLOG) {
		packet_handler = handle_pflog_packet;
    }
757
#endif
pdw committed
758
    else if(dlt == DLT_RAW) {
759 760
        packet_handler = handle_raw_packet;
    } 
pdw committed
761
    else if(dlt == DLT_NULL) {
762
        packet_handler = handle_null_packet;
pdw committed
763
    } 
764 765 766 767 768
#ifdef DLT_LOOP
    else if(dlt == DLT_LOOP) {
        packet_handler = handle_null_packet;
    }
#endif
pdw committed
769 770 771 772 773
#ifdef DLT_IEEE802_11_RADIO
    else if(dlt == DLT_IEEE802_11_RADIO) {
        packet_handler = handle_radiotap_packet;
    }
#endif
pdw committed
774 775 776
    else if(dlt == DLT_IEEE802) {
        packet_handler = handle_tokenring_packet;
    }
pdw committed
777 778 779
    else if(dlt == DLT_PPP) {
        packet_handler = handle_ppp_packet;
    }
pdw committed
780 781 782 783
/* 
 * SLL support not available in older libpcaps
 */
#ifdef DLT_LINUX_SLL
784
    else if(dlt == DLT_LINUX_SLL) {
pdw committed
785
      packet_handler = handle_cooked_packet;
786
    }
pdw committed
787
#endif
788 789 790 791
    else {
        fprintf(stderr, "Unsupported datalink type: %d\n"
                "Please email pdw@ex-parrot.com, quoting the datalink type and what you were\n"
                "trying to do at the time\n.", dlt);
chris committed
792
        exit(1);
793 794
    }

chris committed
795 796
    if ((m = set_filter_code(options.filtercode))) {
        fprintf(stderr, "set_filter_code: %s\n", m);
chris committed
797
        exit(1);
chris committed
798
        return;
chris committed
799
    }
800 801 802 803 804
}

/* packet_loop:
 * Worker function for packet capture thread. */
void packet_loop(void* ptr) {
chris committed
805
    pcap_loop(pd,-1,(pcap_handler)packet_handler,NULL);
pdw committed
806 807
}

chris committed
808 809 810

/* main:
 * Entry point. See usage(). */
pdw committed
811 812
int main(int argc, char **argv) {
    pthread_t thread;
pdw committed
813
    struct sigaction sa = {};
pdw committed
814

815 816
    setlocale(LC_ALL, "");

817
    /* TODO: tidy this up */
pdw committed
818 819 820 821
    /* read command line options and config file */   
    config_init();
    options_set_defaults();
    options_read_args(argc, argv);
822 823
    /* If a config was explicitly specified, whinge if it can't be found */
    read_config(options.config_file, options.config_file_specified);
pdw committed
824
    options_make();
chris committed
825
    
chris committed
826 827
    sa.sa_handler = finish;
    sigaction(SIGINT, &sa, NULL);
pdw committed
828 829 830

    pthread_mutex_init(&tick_mutex, NULL);

831 832
    packet_init();

pdw committed
833 834
    init_history();

835 836 837 838 839 840
    if (options.no_curses) {
      tui_init();
    }
    else {
      ui_init();
    }
841

pdw committed
842 843
    pthread_create(&thread, NULL, (void*)&packet_loop, NULL);

844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
    /* Keep the starting time (used for timed termination) */
    first_timestamp = time(NULL);

    if (options.no_curses) {
      if (options.timed_output) {
        while(!foad) {
          sleep(1);
        }
      }
      else {
        tui_loop();
      }
    }
    else {
      ui_loop();
    }
pdw committed
860

chris committed
861
    pthread_cancel(thread);
862 863
    pthread_join(thread, NULL);
    pcap_close(pd);
chris committed
864 865 866

    ui_finish();
    
pdw committed
867 868
    return 0;
}