iftop.c 23.3 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;
Paul Warren's avatar
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'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) {
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'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, int pld_len)
pdw's avatar
pdw committed
253
{
pdw's avatar
pdw committed
254
    int direction = 0; /* incoming */
255
    int len;
256
    history_type* ht;
257
    union {
pdw's avatar
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's avatar
pdw committed
294
        }
295 296
        else if(hw_dir == 0) {
            /* Packet incoming */
297 298
            assign_addr_pair(&ap, iptr, 1);
            direction = 0;
pdw's avatar
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's avatar
pdw committed
341
            assign_addr_pair(&ap, iptr, 1);
342
            direction = 0;
pdw's avatar
pdw committed
343
        }
344
        else if(IP_V(iptr) == 4) {
345 346
            assign_addr_pair(&ap, iptr, 0);
            direction = 0;
pdw's avatar
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's avatar
pdw committed
366 367
        }
        else {
368 369
            /* drop packet */
            return ;
pdw's avatar
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's avatar
pdw committed
465
        ht->total_sent += len;
466 467 468
    }
    else {
        ht->recv[history_pos] += len;
pdw's avatar
pdw committed
469
        ht->total_recv += len;
470
    }
pdw's avatar
pdw committed
471

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

chris's avatar
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)
505
{
506
    handle_ip_packet((struct ip*)(packet + 4), -1, pkthdr->len);
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's avatar
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's avatar
pdw committed
519
        orgcode = EXTRACT_24BITS(&llc->llc_orgcode[0]);
520
        et = (llc->llc_ethertype[0] << 8) + llc->llc_ethertype[1];
pdw's avatar
pdw committed
521 522 523
        switch(orgcode) {
          case OUI_ENCAP_ETHER:
          case OUI_CISCO_90:
524
	      handle_ip_packet(ip, dir, pldlen);
pdw's avatar
pdw committed
525 526 527
            break;
          case OUI_APPLETALK:
            if(et == ETHERTYPE_ATALK) {
528
		handle_ip_packet(ip, dir, pldlen);
pdw's avatar
pdw committed
529 530
            }
            break;
chris's avatar
chris committed
531
          default:;
pdw's avatar
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's avatar
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's avatar
pdw committed
546
    }
547 548
    hdrlen += TOKEN_HDRLEN;
    packet += hdrlen;
pdw's avatar
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's avatar
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's avatar
pdw committed
562 563 564
    }
}

pdw's avatar
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's avatar
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's avatar
pdw committed
580 581 582

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

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

chris's avatar
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's avatar
chris committed
612
#endif /* DLT_LINUX_SLL */
613

chris's avatar
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's avatar
chris committed
622

623
    if(ether_type == ETHERTYPE_8021Q) {
pdw's avatar
pdw committed
624
        struct vlan_8021q_header* vptr;
625
        vptr = (struct vlan_8021q_header*) (packet + hdrlen);
pdw's avatar
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's avatar
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's avatar
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's avatar
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's avatar
pdw committed
667 668 669 670
}


#endif
671

chris's avatar
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's avatar
chris committed
680
    } else
681
        x = xstrdup("ip or ip6");
chris's avatar
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's avatar
pdw committed
701
    char errbuf[PCAP_ERRBUF_SIZE];
chris's avatar
chris committed
702
    char *m;
703
    int i;
704
    int dlt;
705
    int result;
chris's avatar
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's avatar
chris committed
739
    
740
    //    exit(0);
pdw's avatar
pdw committed
741 742
    resolver_initialise();

pdw's avatar
pdw committed
743
    pd = pcap_open_live(options.interface, CAPTURE_LENGTH, options.promiscuous, 1000, errbuf);
pdw's avatar
pdw committed
744
    // DEBUG: pd = pcap_open_offline("tcpdump.out", errbuf);
pdw's avatar
pdw committed
745
    if(pd == NULL) { 
pdw's avatar
pdw committed
746
        fprintf(stderr, "pcap_open_live(%s): %s\n", options.interface, errbuf); 
chris's avatar
chris committed
747
        exit(1);
748 749 750 751
    }
    dlt = pcap_datalink(pd);
    if(dlt == DLT_EN10MB) {
        packet_handler = handle_eth_packet;
pdw's avatar
pdw committed
752
    }
753
#ifdef DLT_PFLOG
754 755 756
    else if (dlt == DLT_PFLOG) {
		packet_handler = handle_pflog_packet;
    }
757
#endif
758
    else if(dlt == DLT_RAW) {
759 760
        packet_handler = handle_raw_packet;
    } 
761
    else if(dlt == DLT_NULL) {
762
        packet_handler = handle_null_packet;
763
    } 
764 765 766 767
#ifdef DLT_LOOP
    else if(dlt == DLT_LOOP) {
        packet_handler = handle_null_packet;
    }
pdw's avatar
pdw committed
768 769 770 771 772
#endif
#ifdef DLT_IEEE802_11_RADIO
    else if(dlt == DLT_IEEE802_11_RADIO) {
        packet_handler = handle_radiotap_packet;
    }
773
#endif
pdw's avatar
pdw committed
774 775 776
    else if(dlt == DLT_IEEE802) {
        packet_handler = handle_tokenring_packet;
    }
pdw's avatar
pdw committed
777 778 779
    else if(dlt == DLT_PPP) {
        packet_handler = handle_ppp_packet;
    }
pdw's avatar
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's avatar
pdw committed
785
      packet_handler = handle_cooked_packet;
786
    }
pdw's avatar
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's avatar
chris committed
792
        exit(1);
793 794
    }

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

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

chris's avatar
chris committed
808 809 810

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

815 816
    setlocale(LC_ALL, "");

817
    /* TODO: tidy this up */
pdw's avatar
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's avatar
pdw committed
824
    options_make();
chris's avatar
chris committed
825
    
chris's avatar
chris committed
826 827
    sa.sa_handler = finish;
    sigaction(SIGINT, &sa, NULL);
pdw's avatar
pdw committed
828 829 830

    pthread_mutex_init(&tick_mutex, NULL);

831 832
    packet_init();

pdw's avatar
pdw committed
833 834
    init_history();

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

pdw's avatar
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's avatar
pdw committed
860

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

    ui_finish();
    
pdw's avatar
pdw committed
867 868
    return 0;
}