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>