iftop.c 22.5 KB
Newer Older
pdw's avatar
pdw committed
1 2 3 4 5
/*
 * iftop.c:
 *
 */

chris's avatar
chris committed
6 7
#include "integers.h"

pdw's avatar
pdw committed
8 9 10
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
11
#include <sys/types.h>
chris's avatar
chris committed
12
#include <sys/ioctl.h>
13
#include <sys/socket.h>
chris's avatar
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's avatar
pdw committed
25 26 27 28
#include <pthread.h>
#include <curses.h>
#include <signal.h>
#include <string.h>
chris's avatar
chris committed
29
#include <unistd.h>
30
#include <locale.h>
pdw's avatar
pdw committed
31 32 33 34

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

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

56 57
/* ethernet address of interface. */
int have_hw_addr = 0;
58
char 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's avatar
pdw committed
65

pdw's avatar
pdw committed
66 67
extern options_t options;

pdw's avatar
pdw committed
68
hash_type* history;
pdw's avatar
pdw committed
69
history_type history_totals;
pdw's avatar
pdw committed
70
time_t last_timestamp;
71
time_t first_timestamp;
pdw's avatar
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's avatar
chris committed
77
struct bpf_program pcap_filter;
78 79
pcap_handler packet_handler;

chris's avatar
chris committed
80 81 82 83 84 85
sig_atomic_t foad;

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

pdw's avatar
pdw committed
86 87


pdw's avatar
pdw committed
88

pdw's avatar
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's avatar
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's avatar
pdw committed
94
 * the radiotap payload */
95 96
/*#define CAPTURE_LENGTH 92 */
#define CAPTURE_LENGTH 256
pdw's avatar
pdw committed
97 98 99 100

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

history_type* history_create() {
    history_type* h;
chris's avatar
chris committed
106
    h = xcalloc(1, sizeof *h);
pdw's avatar
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's avatar
pdw committed
122
            free(d);
pdw's avatar
pdw committed
123 124 125 126 127 128 129
        }
        else {
            d->recv[history_pos] = 0;
            d->sent[history_pos] = 0;
        }
        n = next; 
    }
pdw's avatar
pdw committed
130 131 132 133

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

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


140
void tick(int print) {
pdw's avatar
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's avatar
pdw committed
147
        analyse_data();
148
        if (options.no_curses) {
pdw's avatar
pdw committed
149
          if (!options.timed_output || (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's avatar
pdw committed
159 160 161
        history_rotate();
        last_timestamp = t;
    }
pdw's avatar
pdw committed
162
    else {
163 164 165 166 167 168
      if (options.no_curses) {
        tui_tick(print);
      }
      else {
        ui_tick(print);
      }
169
    }
pdw's avatar
pdw committed
170 171 172 173

    pthread_mutex_unlock(&tick_mutex);
}

pdw's avatar
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's avatar
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's avatar
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's avatar
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)
pdw's avatar
pdw committed
253
{
pdw's avatar
pdw committed
254
    int direction = 0; /* incoming */
255
    history_type* ht;
256
    union {
pdw's avatar
pdw committed
257 258
      history_type **ht_pp;
      void **void_pp;
259
    } u_ht = { &ht };
260
    addr_pair ap;
261 262 263 264 265 266 267
    unsigned int len = 0;
    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
    if( (IP_V(iptr) ==4 && options.netfilter == 0)
            || (IP_V(iptr) == 6 && options.netfilter6 == 0) ) { 
273 274 275 276 277
        /*
         * Net filter is off, so assign direction based on MAC address
         */
        if(hw_dir == 1) {
            /* Packet leaving this interface. */
278
            assign_addr_pair(&ap, iptr, 0);
279
            direction = 1;
pdw's avatar
pdw committed
280
        }
281 282
        else if(hw_dir == 0) {
            /* Packet incoming */
283 284
            assign_addr_pair(&ap, iptr, 1);
            direction = 0;
pdw's avatar
pdw committed
285
        }
286 287 288
        /* Packet direction is not given away by h/ware layer.  Try IP
         * layer
         */
289
        else if((IP_V(iptr) == 4) && have_ip_addr && ip_addr_match(iptr->ip_src)) {
290 291 292 293
            /* outgoing */
            assign_addr_pair(&ap, iptr, 0);
            direction = 1;
        }
294 295 296 297 298 299 300 301 302 303 304
        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)) {
305 306 307 308
            /* incoming */
            assign_addr_pair(&ap, iptr, 1);
            direction = 0;
        }
309 310 311 312 313 314 315 316
        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;
        }
317
        /*
318 319 320 321
         * 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.
322
         */
323 324 325
	else if (options.promiscuous_but_choosy) {
	    return;		/* junk it */
	}
326
        else if((IP_V(iptr) == 4) && (iptr->ip_src.s_addr < iptr->ip_dst.s_addr)) {
pdw's avatar
pdw committed
327
            assign_addr_pair(&ap, iptr, 1);
328
            direction = 0;
pdw's avatar
pdw committed
329
        }
330
        else if(IP_V(iptr) == 4) {
331 332
            assign_addr_pair(&ap, iptr, 0);
            direction = 0;
pdw's avatar
pdw committed
333
        }
334
        /* Drop other uncertain packages. */
335 336
        else
            return;
337
    }
338 339

    if(IP_V(iptr) == 4 && options.netfilter != 0) {
340 341 342
        /* 
         * Net filter on, assign direction according to netmask 
         */ 
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 347
            direction = 1;
        }
348
        else if(in_filter_net(iptr->ip_dst) && !in_filter_net(iptr->ip_src)) {
349
            /* into network */
350 351
            assign_addr_pair(&ap, iptr, 1);
            direction = 0;
pdw's avatar
pdw committed
352 353
        }
        else {
354 355
            /* drop packet */
            return ;
pdw's avatar
pdw committed
356
        }
357 358
    }

359 360 361 362 363 364 365 366 367
    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.
         */
368 369 370 371 372
        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];
373 374 375 376 377 378 379 380 381 382 383 384 385 386 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
        }

        /* 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;
    }
426

427

428
    if(hash_find(history, &ap, u_ht.void_pp) == HASH_STATUS_KEY_NOT_FOUND) {
429 430 431 432
        ht = history_create();
        hash_insert(history, &ap, ht);
    }

433 434 435 436 437 438 439 440 441 442
    /* Do accounting. */
    switch (IP_V(iptr)) {
      case 4:
          len = ntohs(iptr->ip_len);
          break;
      case 6:
          len = ntohs(ip6tr->ip6_plen) + 40;
      default:
          break;
    }
443 444 445

    /* Update record */
    ht->last_write = history_pos;
446 447 448
    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))) )
    {
449
        ht->sent[history_pos] += len;
pdw's avatar
pdw committed
450
        ht->total_sent += len;
451 452 453
    }
    else {
        ht->recv[history_pos] += len;
pdw's avatar
pdw committed
454
        ht->total_recv += len;
455
    }
pdw's avatar
pdw committed
456

457 458
    if(direction == 0) {
        /* incoming */
pdw's avatar
pdw committed
459
        history_totals.recv[history_pos] += len;
pdw's avatar
pdw committed
460
        history_totals.total_recv += len;
pdw's avatar
pdw committed
461
    }
462
    else {
pdw's avatar
pdw committed
463
        history_totals.sent[history_pos] += len;
pdw's avatar
pdw committed
464
        history_totals.total_sent += len;
465 466
    }
    
pdw's avatar
pdw committed
467 468
}

chris's avatar
chris committed
469
static void handle_raw_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
470 471 472 473
{
    handle_ip_packet((struct ip*)packet, -1);
}

474
#ifdef DLT_PFLOG
475 476 477 478 479 480 481 482 483 484
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;
pdw's avatar
pdw committed
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 492 493
{
    handle_ip_packet((struct ip*)(packet + 4), -1);
}

pdw's avatar
pdw committed
494 495 496 497 498 499 500 501
static void handle_llc_packet(const struct llc* llc, int dir) {

    struct ip* ip = (struct ip*)((void*)llc + sizeof(struct llc));

    /* Taken from tcpdump/print-llc.c */
    if(llc->ssap == LLCSAP_SNAP && llc->dsap == LLCSAP_SNAP
       && llc->llcui == LLC_UI) {
        u_int32_t orgcode;
502
        u_int16_t et;
pdw's avatar
pdw committed
503
        orgcode = EXTRACT_24BITS(&llc->llc_orgcode[0]);
504
        et = (llc->llc_ethertype[0] << 8) + llc->llc_ethertype[1];
pdw's avatar
pdw committed
505 506 507 508 509 510 511 512 513 514
        switch(orgcode) {
          case OUI_ENCAP_ETHER:
          case OUI_CISCO_90:
            handle_ip_packet(ip, dir);
            break;
          case OUI_APPLETALK:
            if(et == ETHERTYPE_ATALK) {
              handle_ip_packet(ip, dir);
            }
            break;
chris's avatar
chris committed
515
          default:;
pdw's avatar
pdw committed
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
            /* 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;
    int dir = -1;
    trp = (struct token_header *)packet;

    if(IS_SOURCE_ROUTED(trp)) {
      packet += RIF_LENGTH(trp);
    }
    packet += TOKEN_HDRLEN;

    if(memcmp(trp->token_shost, if_hw_addr, 6) == 0 ) {
      /* packet leaving this i/f */
      dir = 1;
    } 
        else if(memcmp(trp->token_dhost, if_hw_addr, 6) == 0 || memcmp("\xFF\xFF\xFF\xFF\xFF\xFF", trp->token_dhost, 6) == 0) {
      /* packet entering this i/f */
      dir = 0;
    }

    /* Only know how to deal with LLC encapsulated packets */
    if(FRAME_TYPE(trp) == TOKEN_FC_LLC) {
      handle_llc_packet((struct llc*)packet, dir);
    }
}

pdw's avatar
pdw committed
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
static void handle_ppp_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
{
	register u_int length = pkthdr->len;
	register u_int caplen = pkthdr->caplen;
	u_int proto;

	if (caplen < 2) 
        return;

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

		packet += 2;
		length -= 2;

		proto = EXTRACT_16BITS(packet);
		packet += 2;
		length -= 2;

567
        if(proto == PPP_IP || proto == ETHERTYPE_IP || proto == ETHERTYPE_IPV6) {
pdw's avatar
pdw committed
568 569 570 571 572
            handle_ip_packet((struct ip*)packet, -1);
        }
    }
}

chris's avatar
chris committed
573
#ifdef DLT_LINUX_SLL
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
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;
    }
    handle_ip_packet((struct ip*)(packet+SLL_HDR_LEN), dir);
}
chris's avatar
chris committed
593
#endif /* DLT_LINUX_SLL */
594

chris's avatar
chris committed
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 599
    int ether_type;
    const unsigned char *payload;
600
    eptr = (struct ether_header*)packet;
601 602
    ether_type = ntohs(eptr->ether_type);
    payload = packet + sizeof(struct ether_header);
chris's avatar
chris committed
603

604
    if(ether_type == ETHERTYPE_8021Q) {
pdw's avatar
pdw committed
605 606 607
        struct vlan_8021q_header* vptr;
        vptr = (struct vlan_8021q_header*)payload;
        ether_type = ntohs(vptr->ether_type);
608 609 610
        payload += sizeof(struct vlan_8021q_header);
    }

611
    if(ether_type == ETHERTYPE_IP || ether_type == ETHERTYPE_IPV6) {
612 613 614 615 616 617
        struct ip* iptr;
        int dir = -1;
        
        /*
         * Is a direction implied by the MAC addresses?
         */
618
        if(have_hw_addr && memcmp(eptr->ether_shost, if_hw_addr, 6) == 0 ) {
619 620
            /* packet leaving this i/f */
            dir = 1;
621 622
        }
        else if(have_hw_addr && memcmp(eptr->ether_dhost, if_hw_addr, 6) == 0 ) {
pdw's avatar
pdw committed
623 624 625 626 627
            /* 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 */
628 629 630
            dir = 0;
        }

631
        /* Distinguishing ip_hdr and ip6_hdr will be done later. */
632
        iptr = (struct ip*)(payload); /* alignment? */
633 634 635 636
        handle_ip_packet(iptr, dir);
    }
}

pdw's avatar
pdw committed
637 638 639 640 641 642 643
#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)
{
644
    /* 802.11 MAC header is = 34 bytes (not sure if that's universally true) */
pdw's avatar
pdw committed
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);
pdw's avatar
pdw committed
647 648 649 650
}


#endif
651

chris's avatar
chris committed
652 653 654 655 656 657
/* 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) {
658 659
        x = xmalloc(strlen(filter) + sizeof "() and (ip or ip6)");
        sprintf(x, "(%s) and (ip or ip6)", filter);
chris's avatar
chris committed
660
    } else
661
        x = xstrdup("ip or ip6");
chris's avatar
chris committed
662 663 664 665 666 667 668 669 670 671 672 673 674
    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;
}



675 676 677 678 679 680
/*
 * packet_init:
 *
 * performs pcap initialisation, called before ui is initialised
 */
void packet_init() {
pdw's avatar
pdw committed
681
    char errbuf[PCAP_ERRBUF_SIZE];
chris's avatar
chris committed
682
    char *m;
683
    int i;
684
    int dlt;
685
    int result;
chris's avatar
chris committed
686

687 688
#ifdef HAVE_DLPI
    result = get_addrs_dlpi(options.interface, if_hw_addr, &if_ip_addr);
689
#else
690 691
    result = get_addrs_ioctl(options.interface, if_hw_addr,
          &if_ip_addr, &if_ip6_addr);
692 693
#endif

694 695
    if (result < 0) {
      exit(1);
696 697
    }

698 699 700
    have_hw_addr = result & 0x01;
    have_ip_addr = result & 0x02;
    have_ip6_addr = result & 0x04;
701 702 703
    
    if(have_ip_addr) {
      fprintf(stderr, "IP address is: %s\n", inet_ntoa(if_ip_addr));
704
    }
705 706 707 708 709 710 711
    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);
    }
712

713 714 715 716 717 718
    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's avatar
chris committed
719
    
720
    //    exit(0);
pdw's avatar
pdw committed
721 722
    resolver_initialise();

pdw's avatar
pdw committed
723
    pd = pcap_open_live(options.interface, CAPTURE_LENGTH, options.promiscuous, 1000, errbuf);
pdw's avatar
pdw committed
724
    // DEBUG: pd = pcap_open_offline("tcpdump.out", errbuf);
pdw's avatar
pdw committed
725
    if(pd == NULL) { 
pdw's avatar
pdw committed
726
        fprintf(stderr, "pcap_open_live(%s): %s\n", options.interface, errbuf); 
chris's avatar
chris committed
727
        exit(1);
728 729 730 731
    }
    dlt = pcap_datalink(pd);
    if(dlt == DLT_EN10MB) {
        packet_handler = handle_eth_packet;
pdw's avatar
pdw committed
732
    }
733
#ifdef DLT_PFLOG
734 735 736
    else if (dlt == DLT_PFLOG) {
		packet_handler = handle_pflog_packet;
    }
737
#endif
738
    else if(dlt == DLT_RAW) {
739 740
        packet_handler = handle_raw_packet;
    } 
741
    else if(dlt == DLT_NULL) {
742
        packet_handler = handle_null_packet;
743
    } 
744 745 746 747
#ifdef DLT_LOOP
    else if(dlt == DLT_LOOP) {
        packet_handler = handle_null_packet;
    }
pdw's avatar
pdw committed
748 749 750 751 752
#endif
#ifdef DLT_IEEE802_11_RADIO
    else if(dlt == DLT_IEEE802_11_RADIO) {
        packet_handler = handle_radiotap_packet;
    }
753
#endif
pdw's avatar
pdw committed
754 755 756
    else if(dlt == DLT_IEEE802) {
        packet_handler = handle_tokenring_packet;
    }
pdw's avatar
pdw committed
757 758 759
    else if(dlt == DLT_PPP) {
        packet_handler = handle_ppp_packet;
    }
pdw's avatar
pdw committed
760 761 762 763
/* 
 * SLL support not available in older libpcaps
 */
#ifdef DLT_LINUX_SLL
764
    else if(dlt == DLT_LINUX_SLL) {
pdw's avatar
pdw committed
765
      packet_handler = handle_cooked_packet;
766
    }
pdw's avatar
pdw committed
767
#endif
768 769 770 771
    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's avatar
chris committed
772
        exit(1);
773 774
    }

chris's avatar
chris committed
775 776
    if ((m = set_filter_code(options.filtercode))) {
        fprintf(stderr, "set_filter_code: %s\n", m);
chris's avatar
chris committed
777
        exit(1);
chris's avatar
chris committed
778
        return;
chris's avatar
chris committed
779
    }
780 781 782 783 784
}

/* packet_loop:
 * Worker function for packet capture thread. */
void packet_loop(void* ptr) {
chris's avatar
chris committed
785
    pcap_loop(pd,-1,(pcap_handler)packet_handler,NULL);
pdw's avatar
pdw committed
786 787
}

chris's avatar
chris committed
788 789 790

/* main:
 * Entry point. See usage(). */
pdw's avatar
pdw committed
791 792
int main(int argc, char **argv) {
    pthread_t thread;
pdw's avatar
pdw committed
793
    struct sigaction sa = {};
pdw's avatar
pdw committed
794

795 796
    setlocale(LC_ALL, "");

797
    /* TODO: tidy this up */
pdw's avatar
pdw committed
798 799 800 801
    /* read command line options and config file */   
    config_init();
    options_set_defaults();
    options_read_args(argc, argv);
802 803
    /* If a config was explicitly specified, whinge if it can't be found */
    read_config(options.config_file, options.config_file_specified);
pdw's avatar
pdw committed
804
    options_make();
chris's avatar
chris committed
805
    
chris's avatar
chris committed
806 807
    sa.sa_handler = finish;
    sigaction(SIGINT, &sa, NULL);
pdw's avatar
pdw committed
808 809 810

    pthread_mutex_init(&tick_mutex, NULL);

811 812
    packet_init();

pdw's avatar
pdw committed
813 814
    init_history();

815 816 817 818 819 820
    if (options.no_curses) {
      tui_init();
    }
    else {
      ui_init();
    }
821

pdw's avatar
pdw committed
822 823
    pthread_create(&thread, NULL, (void*)&packet_loop, NULL);

824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
    /* 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's avatar
pdw committed
840

chris's avatar
chris committed
841
    pthread_cancel(thread);
842 843
    pthread_join(thread, NULL);
    pcap_close(pd);
chris's avatar
chris committed
844 845 846

    ui_finish();
    
pdw's avatar
pdw committed
847 848
    return 0;
}