source: lib/trace.c @ 8d1956e

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 8d1956e was 8d1956e, checked in by Daniel Lawson <dlawson@…>, 16 years ago

typo in conditional in strndup.c
typos in trace.c

  • Property mode set to 100644
File size: 53.2 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2004 The University of Waikato, Hamilton, New Zealand.
5 * Authors: Daniel Lawson
6 *          Perry Lorier
7 *         
8 * All rights reserved.
9 *
10 * This code has been developed by the University of Waikato WAND
11 * research group. For further information please see http://www.wand.net.nz/
12 *
13 * libtrace is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * libtrace is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with libtrace; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 *
27 * $Id$
28 *
29 */
30
31
32/** @file
33 *
34 * @brief Trace file processing library
35 *
36 * @author Daniel Lawson
37 * @author Perry Lorier
38 *
39 * @internal
40 */
41#define _GNU_SOURCE
42#include "common.h"
43#include "config.h"
44#include <assert.h>
45#include <errno.h>
46#include <fcntl.h>
47#include <netdb.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <sys/stat.h>
52#include <sys/types.h>
53
54#ifdef HAVE_LIMITS_H
55#  include <limits.h>
56#endif
57
58#ifdef HAVE_SYS_LIMITS_H
59#  include <sys/limits.h>
60#endif
61
62#include <sys/socket.h>
63#include <sys/un.h>
64#include <sys/mman.h>
65#include <unistd.h>
66
67#ifdef HAVE_NET_IF_ARP_H
68#  include <net/if_arp.h>
69#endif
70
71#ifdef HAVE_NET_IF_H
72#  include <net/if.h>
73#endif
74
75#ifdef HAVE_NETINET_IN_H
76#  include <netinet/in.h>
77#endif
78
79#ifdef HAVE_NET_ETHERNET_H
80#  include <net/ethernet.h>
81#endif
82
83#ifdef HAVE_NETINET_IF_ETHER_H
84#  include <netinet/if_ether.h>
85#endif
86
87#include <time.h>
88#include <sys/ioctl.h>
89
90#ifdef HAVE_INTTYPES_H
91#  include <inttypes.h>
92#else
93#  error "Can't find inttypes.h - this needs to be fixed"
94#endif
95
96#ifdef HAVE_STDDEF_H
97#  include <stddef.h>
98#else
99# error "Can't find stddef.h - do you define ptrdiff_t elsewhere?"
100#endif
101
102#include "libtrace.h"
103#include "fifo.h"
104
105#if HAVE_PCAP_BPF_H
106#  include <pcap-bpf.h>
107#else
108#  ifdef HAVE_NET_BPF_H
109#    include <net/bpf.h>
110#  endif
111#endif
112
113#if HAVE_PCAP_H
114#  include <pcap.h>
115#  ifdef HAVE_PCAP_INT_H
116#    include <pcap-int.h>
117#  endif
118#endif
119
120#ifdef HAVE_ZLIB_H
121#  include <zlib.h>
122#endif
123
124
125#include "wag.h"
126
127#ifdef HAVE_DAG_API
128#  include "dagnew.h"
129#  include "dagapi.h"
130#else
131#  include "dagformat.h"
132#endif
133
134
135typedef enum {SOCKET, TRACE, STDIN, DEVICE, INTERFACE, RT } source_t;
136
137typedef enum {ERF, PCAP, PCAPINT, DAG, RTCLIENT, WAG, WAGINT } format_t;
138
139#if HAVE_BPF
140/** A type encapsulating a bpf filter
141 * This type covers the compiled bpf filter, as well as the original filter
142 * string
143 *
144 */
145struct libtrace_filter_t {
146        struct bpf_insn *filter;
147        char * filterstring;
148};
149#endif
150
151/** The information about traces that are open
152 * @internal
153 */
154struct libtrace_t {
155        format_t format;        /**< The format that this trace is in */
156        source_t sourcetype;    /**< The type (device,file, etc */
157        union {
158                /** Information about rtclients */
159                struct {
160                        char *hostname;
161                        short port;
162                } rt;
163                char *path;             /**< information for local sockets */
164                char *interface;        /**< intormation for reading of network
165                                             interfaces */
166        } conn_info;
167        /** Information about the current state of the input device */
168        union {
169                int fd;
170#if HAVE_ZLIB
171                gzFile *file;
172#else   
173                FILE *file;
174#endif
175#if HAVE_PCAP
176                pcap_t *pcap;
177#endif
178        } input;
179        struct fifo_t *fifo;   
180        struct {
181                void *buf; 
182                unsigned bottom;
183                unsigned top;
184                unsigned diff;
185                unsigned curr;
186                unsigned offset;
187        } dag;
188        struct {
189                void *buffer;
190                int size;
191        } packet;
192        double tdelta;
193        double trace_start_ts;
194        double real_start_ts;
195        double trace_last_ts;
196
197        double last_ts;
198        double start_ts;
199};
200
201struct trace_sll_header_t {
202        uint16_t pkttype;               /* packet type */
203        uint16_t hatype;                /* link-layer address type */
204        uint16_t halen;                 /* link-layer address length */
205        char addr[8];                   /* link-layer address */
206        uint16_t protocol;              /* protocol */
207};
208
209#ifndef PF_RULESET_NAME_SIZE
210#define PF_RULESET_NAME_SIZE 16
211#endif
212
213struct trace_pflog_header_t {
214        uint8_t    length;
215        sa_family_t   af;
216        uint8_t    action;
217        uint8_t    reason;
218        char       ifname[IFNAMSIZ];
219        char       ruleset[PF_RULESET_NAME_SIZE];
220        uint32_t   rulenr;
221        uint32_t   subrulenr;
222        uint8_t    dir;
223        uint8_t    pad[3];
224};
225
226#define RP_BUFSIZE 65536
227
228#define URI_PROTO_LINE 16
229static int init_trace(struct libtrace_t **libtrace, char *uri) {
230        char *scan = calloc(sizeof(char),URI_PROTO_LINE);
231        char *uridata = 0;                 
232        struct stat buf;
233       
234        // parse the URI to determine what sort of event we are dealing with
235       
236        // want snippet before the : to get the uri base type.
237
238        if((uridata = strchr(uri,':')) == NULL) {
239                // badly formed URI - needs a :
240                return 0;
241        }
242
243        if ((*uridata - *uri) > URI_PROTO_LINE) {
244                // badly formed URI - uri type is too long
245                return 0;
246        }
247        strncpy(scan,uri, (uridata - uri));
248
249        (*libtrace)->tdelta = 0.0;
250
251        if (!strncasecmp(scan,"erf",3)) {
252                (*libtrace)->format=ERF;
253#if HAVE_PCAP
254        } else if (!strncasecmp(scan,"pcapint",7)) {
255                (*libtrace)->format=PCAPINT;
256        } else if (!strncasecmp(scan,"pcap",4)) {
257                (*libtrace)->format=PCAP;
258#else
259        } else if (!strncasecmp(scan,"pcap",4)) { // also catches pcapint
260                fprintf(stderr,"This version of libtrace has been compiled without PCAP support\n");
261                return 0;
262#endif
263       
264#if HAVE_DAG
265        } else if (!strncasecmp(scan,"dag",3)) {
266                (*libtrace)->format=DAG;
267#else
268        } else if (!strncasecmp(scan,"dag",3)) {
269                fprintf(stderr,"This version of libtrace has been compiled without DAG support\n");
270                return 0;
271#endif
272        } else if (!strncasecmp(scan,"rtclient",7)) {
273                (*libtrace)->format=RTCLIENT;
274        } else if (!strncasecmp(scan,"wagint",6)) {
275        struct ports_t *port;
276                (*libtrace)->format=WAGINT;
277        } else if (!strncasecmp(scan,"wag",3)) {
278                (*libtrace)->format=WAG;
279        } else {
280                //badly formed URI
281                return 0;
282        }
283       
284        // push uridata past the delimiter
285        uridata++;
286       
287        // libtrace->format now contains the type of uri
288        // libtrace->uridata contains the appropriate data for this
289       
290        switch((*libtrace)->format) {
291#if HAVE_PCAP
292                case PCAPINT:
293#endif
294                case WAGINT:
295                        /* Can have uridata of the following format
296                         * eth0
297                         * etc
298                         */
299                        // We basically assume this is correct.
300                        (*libtrace)->sourcetype = INTERFACE;   
301                        (*libtrace)->conn_info.path = strdup(uridata);
302                        break;
303#if HAVE_PCAP
304                case PCAP:
305#endif
306                case ERF:
307                case WAG:
308                        /*
309                         * Can have uridata of the following format
310                         * /path/to/socket (probably not PCAP)
311                         * /path/to/file
312                         * /path/to/file.gz (not PCAP)
313                         * /dev/device (use PCAPINT)
314                         * -
315                         */
316                        if (!strncmp(uridata,"-",1)) {
317                                (*libtrace)->sourcetype = STDIN;
318                        } else {
319                                if (stat(uridata,&buf) == -1) {
320                                        perror("stat");
321                                        return 0;
322                                }
323                                if (S_ISSOCK(buf.st_mode)) {
324                                        (*libtrace)->sourcetype = SOCKET;
325                                } else if (S_ISCHR(buf.st_mode)) {
326                                        (*libtrace)->sourcetype = DEVICE;
327                                } else {
328                                        (*libtrace)->sourcetype = TRACE;
329                                }
330                                (*libtrace)->conn_info.path = strdup(uridata);
331                        }
332                        break;
333                case DAG:
334#if HAVE_DAG
335                        /*
336                         * Can have uridata of the following format:
337                         * /dev/device
338                         */
339                        if (stat(uridata,&buf) == -1) {
340                                perror("stat");
341                                return 0;
342                        }
343                        if (S_ISCHR(buf.st_mode)) {
344                                (*libtrace)->sourcetype = DEVICE;
345                        } else {
346                                fprintf(stderr,"%s isn't a valid char device, exiting\n",uridata);
347                                exit(1);
348                        }
349                        (*libtrace)->conn_info.path = strdup(uridata);
350#endif
351                        break;
352
353                case RTCLIENT:
354                        /*
355                         * Can have the uridata in the format
356                         * hostname
357                         * hostname:port
358                         */
359                        (*libtrace)->sourcetype = RT;
360                        if (strlen(uridata) == 0) {
361                                (*libtrace)->conn_info.rt.hostname = 
362                                        strdup("localhost");
363                                (*libtrace)->conn_info.rt.port = 
364                                        COLLECTOR_PORT;
365                                break;
366                        }
367                        if ((scan = strchr(uridata,':')) == NULL) {
368                                (*libtrace)->conn_info.rt.hostname = 
369                                        strdup(uridata);
370                                (*libtrace)->conn_info.rt.port = 
371                                        COLLECTOR_PORT;
372                        } else {
373                                (*libtrace)->conn_info.rt.hostname =
374                                        (char *)strndup(uridata,(scan - uridata));
375                                       
376                                (*libtrace)->conn_info.rt.port = 
377                                        atoi(++scan);                           
378                        }
379                        break;
380        }
381       
382
383        (*libtrace)->fifo = create_fifo(1048576);
384        assert( (*libtrace)->fifo);
385        //(*libtrace)->packet.buffer = 0;
386        //(*libtrace)->packet.size = 0;
387
388        return 1;
389}
390
391/** Create a trace file from a URI
392 *
393 * @returns opaque pointer to a libtrace_t
394 *
395 * Valid URI's are:
396 *  erf:/path/to/erf/file
397 *  erf:/path/to/erf/file.gz
398 *  erf:/path/to/rtclient/socket
399 *  erf:-                       (stdin)
400 *  pcapint:pcapinterface               (eg: pcapint:eth0)
401 *  pcap:/path/to/pcap/file
402 *  pcap:-
403 *  rtclient:hostname
404 *  rtclient:hostname:port
405 *  wag:-
406 *  wag:/path/to/wag/file
407 *  wag:/path/to/wag/file.gz
408 *  wag:/path/to/wag/socket
409 *  wagint:/dev/device
410 *
411 * URIs which have yet to be implemented are:
412 * dag:/dev/dagcard
413 * pcap:/path/to/pcap/socket
414 *
415 * If an error occured when attempting to open a trace, NULL is returned
416 * and an error is output to stdout.
417 */
418struct libtrace_t *trace_create(char *uri) {
419        struct libtrace_t *libtrace = malloc(sizeof(struct libtrace_t));
420        struct hostent *he;
421        struct sockaddr_in remote;
422        struct sockaddr_un unix_sock;
423#if HAVE_PCAP
424        char errbuf[PCAP_ERRBUF_SIZE];
425#endif
426
427        if(init_trace(&libtrace,uri) == 0) {
428                return 0;
429        }
430       
431        switch(libtrace->sourcetype) {
432                case RT:
433                        if ((he=gethostbyname(libtrace->conn_info.rt.hostname)) == NULL) { 
434                                perror("gethostbyname");
435                                return 0;
436                        } 
437                        if ((libtrace->input.fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
438                                perror("socket");
439                                return 0;
440                        }
441
442                        remote.sin_family = AF_INET;   
443                        remote.sin_port = htons(libtrace->conn_info.rt.port);
444                        remote.sin_addr = *((struct in_addr *)he->h_addr);
445                        bzero(&(remote.sin_zero), 8);
446
447                        if (connect(libtrace->input.fd, (struct sockaddr *)&remote,
448                                                sizeof(struct sockaddr)) == -1) {
449                                perror("connect (inet)");
450                                return 0;
451                        }
452                        break;
453                case TRACE:
454#if HAVE_PCAP
455                        if (libtrace->format == PCAP) {
456                                if ((libtrace->input.pcap = pcap_open_offline(libtrace->conn_info.path, errbuf)) == NULL) {
457                                        fprintf(stderr,"%s\n",errbuf);
458                                        return 0;
459                                }
460                        } else {
461#else
462                        {
463#endif
464#if HAVE_ZLIB
465                                libtrace->input.file = gzopen(libtrace->conn_info.path, "r");
466#else
467                                libtrace->input.file = fopen(libtrace->conn_info.path, "r");
468#endif
469                        }
470                        break;
471                case STDIN:
472#if HAVE_PCAP
473                        if (libtrace->format == PCAP) {
474                                libtrace->input.pcap = pcap_open_offline("-",errbuf); 
475                        } else {
476#else
477                        {
478#endif
479#if HAVE_ZLIB
480                                libtrace->input.file = gzdopen(STDIN, "r");
481#else   
482                                libtrace->input.file = stdin;
483#endif
484                        }
485                        break;
486                case SOCKET:
487                        /* Pcap doesn't work */
488                        if (libtrace->format != PCAP) {
489                                if ((libtrace->input.fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
490                                        perror("socket");
491                                        return 0;
492                                }
493                                unix_sock.sun_family = AF_UNIX;
494                                bzero(unix_sock.sun_path,108);
495                                snprintf(unix_sock.sun_path,108,"%s",libtrace->conn_info.path);
496
497                                if (connect(libtrace->input.fd, (struct sockaddr *)&unix_sock,
498                                                        sizeof(struct sockaddr)) == -1) {
499                                        perror("connect (unix)");
500                                        return 0;
501                                }
502                        }
503                        break;
504                case DEVICE:
505                case INTERFACE:
506                        switch (libtrace->format) {
507#if HAVE_PCAP
508                                case PCAPINT:
509                                case PCAP:
510                                        libtrace->input.pcap = pcap_open_live(
511                                                libtrace->conn_info.path,
512                                                4096,
513                                                1,
514                                                1,
515                                                errbuf);
516                                        break;
517#endif
518                                case WAGINT:
519                                case WAG:
520                                        libtrace->input.fd = open(
521                                                libtrace->conn_info.path,
522                                                O_RDONLY);
523                                        break;
524#if HAVE_DAG
525                                case DAG:
526                                        if((libtrace->input.fd = dag_open(libtrace->conn_info.path)) < 0) {
527                                                fprintf(stderr,"Cannot open DAG %s: %m\n", libtrace->conn_info.path,errno);
528                                                exit(0);
529                                        }
530                                        if((libtrace->dag.buf = dag_mmap(libtrace->input.fd)) == MAP_FAILED) {
531                                                fprintf(stderr,"Cannot mmap DAG %s: %m\n", libtrace->conn_info.path,errno);
532                                                exit(0);
533                                        }
534                                        if(dag_start(libtrace->input.fd) < 0) {
535                                                fprintf(stderr,"Cannot start DAG %s: %m\n", libtrace->conn_info.path,errno);
536                                                exit(0);
537                                        }
538                                        break;
539#endif
540                                default:
541                                        fprintf(stderr,"Unknown format trace, hoping I can just read\n");
542                                        break;
543                                       
544                        }
545                        break;
546                default:
547                        fprintf(stderr,"Unsupported source type for libtrace, terminating (%i)\n",libtrace->sourcetype);
548                        exit(0);
549               
550        }
551        return libtrace;
552}
553
554/** Close a trace file, freeing up any resources it may have been using
555 *
556 */
557void trace_destroy(struct libtrace_t *libtrace) {
558        assert(libtrace);
559#if HAVE_PCAP
560        if (libtrace->format == PCAP || libtrace->format == PCAPINT) {
561                pcap_close(libtrace->input.pcap);
562#else
563        if (0) {
564#endif
565        } else if (libtrace->sourcetype == SOCKET || libtrace->sourcetype == RT) {
566                close(libtrace->input.fd);
567#if HAVE_DAG
568        } else if (libtrace->format == DAG) {
569                dag_stop(libtrace->input.fd);
570#endif
571        } else {
572#if HAVE_ZLIB
573                gzclose(libtrace->input.file);
574#else   
575                fclose(libtrace->input.file);   
576#endif
577        }       
578        // need to free things!
579        destroy_fifo(libtrace->fifo);
580        free(libtrace);
581}
582
583static int trace_read(struct libtrace_t *libtrace, void *buffer, size_t len) {
584        int numbytes;
585        static short lctr = 0;
586        struct dag_record_t *recptr = 0;
587        int rlen;
588        assert(libtrace);
589        assert(len >= 0);
590
591        if (buffer == 0)
592                buffer = malloc(len);
593
594        while(1) {
595                switch(libtrace->sourcetype) {
596                        case SOCKET:
597                        case RT:
598
599#ifndef MSG_NOSIGNAL
600#define MSG_NOSIGNAL 0
601#endif
602                                // read from the network
603                                if ((numbytes=recv(libtrace->input.fd, 
604                                                                buffer, 
605                                                                len, 
606                                                                MSG_NOSIGNAL)) == -1) {
607                                        if (errno == EINTR) {
608                                                // ignore EINTR in case
609                                                // a caller is using signals
610                                                continue;
611                                        }
612                                        perror("recv");
613                                        return -1;
614                                }
615                                break;
616                        case DEVICE:
617                                switch(libtrace->format) {
618#if HAVE_DAG
619                                        case DAG:
620
621                                                libtrace->dag.bottom = libtrace->dag.top;
622                                                libtrace->dag.top = dag_offset(
623                                                                libtrace->input.fd,
624                                                                &(libtrace->dag.bottom),
625                                                                0);
626                                                libtrace->dag.diff = libtrace->dag.top -
627                                                        libtrace->dag.bottom;
628                                               
629                                                numbytes=libtrace->dag.diff;
630                                                libtrace->dag.offset = 0;
631                                               
632                                                break;
633#endif
634                                        default:
635                                                if ((numbytes=read(libtrace->input.fd, 
636                                                                buffer, 
637                                                                len)) == -1) {
638                                                perror("read");
639                                                return -1;
640                                                }
641                                }
642                                break;
643                        default:
644#if HAVE_ZLIB
645                                if ((numbytes=gzread(libtrace->input.file,
646                                                                buffer,
647                                                                len)) == -1) {
648                                        perror("gzread");
649                                        return -1;
650                                }
651#else
652                                if ((numbytes=fread(buffer,len,1,libtrace->input.file)) == 0 ) {
653                                        if(feof(libtrace->input.file)) {
654                                                return 0;
655                                        }
656                                        if(ferror(libtrace->input.file)) {
657                                                perror("fread");
658                                                return -1;
659                                        }
660                                        return 0;
661                                }
662#endif
663                }
664                break;
665        }
666        return numbytes;
667
668}
669
670#if HAVE_PCAP
671void trace_pcap_handler(u_char *user, const struct pcap_pkthdr *pcaphdr, const u_char *pcappkt) {
672        struct libtrace_packet_t *packet = (struct libtrace_packet_t *)user;   
673        void *buffer = packet->buffer;
674        int numbytes = 0;
675       
676        memcpy(buffer,pcaphdr,sizeof(struct pcap_pkthdr));
677        numbytes = pcaphdr->len;
678        memcpy(buffer + sizeof(struct pcap_pkthdr),pcappkt,numbytes);
679
680        packet->size = numbytes + sizeof(struct pcap_pkthdr);
681
682}
683#endif
684/** Read one packet from the trace into buffer
685 *
686 * @param libtrace      the libtrace opaque pointer
687 * @param packet        the packet opaque pointer
688 * @returns false if it failed to read a packet
689 *
690 */
691int trace_read_packet(struct libtrace_t *libtrace, struct libtrace_packet_t *packet) {
692        int numbytes;
693        int size;
694        char buf[RP_BUFSIZE];
695#if HAVE_PCAP
696        //struct pcap_pkthdr *pcaphdr = malloc(sizeof(struct pcap_pkthdr));
697        const u_char *pcappkt;
698        int pcapbytes = 0;
699#endif
700        dag_record_t *erfptr;
701        int read_required = 0;
702
703        void *buffer = 0;
704        if (!libtrace) {
705                fprintf(stderr,"Oi! You called trace_read_packet() with a NULL libtrace parameter!\n");
706        }
707        assert(libtrace);
708        assert(packet);
709     
710        /* Store the trace we are reading from into the packet opaque
711         * structure */
712        packet->trace = libtrace;
713
714        buffer = packet->buffer;
715#if HAVE_PCAP
716        /* PCAP gives us it's own per-packet interface. Let's use it */
717        if (libtrace->format == PCAP || libtrace->format == PCAPINT) {
718                /* pcap_next doesn't return enough information for us
719                 * newer libpcap has pcap_next_ex, which does, but we'd
720                 * really rather have it all the time. */
721               
722                //if ((pcappkt = pcap_next(libtrace->input.pcap, &pcaphdr)) == NULL) {
723                /*
724                if ((pcapbytes = pcap_next_ex(libtrace->input.pcap,
725                                                &pcaphdr,
726                                                &pcappkt)) < 0 ) {
727                */
728                /* Instead of pcap_next/pcap_next_ex, we do this ourselves
729                 * with a trivial callback function. This lets us
730                 * catch the same errors as pcap_next_ex, but removes
731                 * the requirement for libpcap >= 0.8.x
732                 */
733                while ((pcapbytes = pcap_dispatch(libtrace->input.pcap,
734                                                1, /* number of packets */
735                                                &trace_pcap_handler,
736                                                (u_char *)packet)) == 0);
737                       
738                if (pcapbytes < 0 ) {                   
739                        return -1;
740                }
741                return (packet->size - sizeof(struct pcap_pkthdr));
742                //memcpy(buffer,&pcaphdr,sizeof(struct pcap_pkthdr));
743                //numbytes = pcaphdr->len;
744                //memcpy(buffer + sizeof(struct pcap_pkthdr),pcappkt,numbytes);
745       
746                //packet->size = numbytes + sizeof(struct pcap_pkthdr);
747                //return numbytes;
748        } 
749#endif
750
751        /* If we're reading from an ERF input, it's an offline trace. We can make some assumptions */
752        if (libtrace->format == ERF) {
753                void *buffer2 = buffer;
754                int rlen;
755                // read in the trace header
756                if ((numbytes=gzread(libtrace->input.file,
757                                                buffer,
758                                                dag_record_size)) == -1) {
759                        perror("gzread");
760                        return -1;
761                }
762                if (numbytes == 0) {
763                        return 0;
764                }
765                rlen = ntohs(((dag_record_t *)buffer)->rlen);
766                size = rlen - dag_record_size;
767                assert(size < LIBTRACE_PACKET_BUFSIZE);
768                buffer2 = buffer +  dag_record_size;
769
770                // read in the rest of the packet
771                if ((numbytes=gzread(libtrace->input.file,
772                                                buffer2,
773                                                size)) == -1) {
774                        perror("gzread");
775                        return -1;
776                }
777                //if ((numbytes + dag_record_size) != rlen) {
778                //      printf("read %d wanted %d\n",numbytes +dag_record_size, rlen);
779                //}
780                packet->size = rlen;
781                       
782                return rlen;
783        }
784
785#if HAVE_DAG
786        if (libtrace->format == DAG) {
787                if (libtrace->dag.diff == 0) {
788                        if ((numbytes = trace_read(libtrace,buf,RP_BUFSIZE)) <= 0) 
789                                return numbytes;
790                }
791                // DAG always gives us whole packets.
792
793                erfptr = (dag_record_t *) ((void *)libtrace->dag.buf + (libtrace->dag.bottom + libtrace->dag.offset));
794                size = ntohs(erfptr->rlen);
795
796                if ( size  > LIBTRACE_PACKET_BUFSIZE) {
797                        printf("%d\n",size);
798                        assert( size < LIBTRACE_PACKET_BUFSIZE);
799                }
800
801                // have to copy it out of the memory hole at this stage:
802                memcpy(packet->buffer, erfptr, size);
803
804                packet->size = size;
805                libtrace->dag.offset += size;
806                libtrace->dag.diff -= size;
807               
808                assert(libtrace->dag.diff >= 0);
809                //assert(libtrace->dag.offset <= libtrace->dag.top);
810                return (size);
811               
812        }
813#endif
814        do {
815                if (fifo_out_available(libtrace->fifo) == 0 || read_required) {
816                        if ((numbytes = trace_read(libtrace,buf,RP_BUFSIZE))<=0){
817                                return numbytes; 
818                        }
819                        assert(libtrace->fifo);
820                        fifo_write(libtrace->fifo,buf,numbytes);
821
822                        read_required = 0;
823                }
824
825                switch (libtrace->format) {
826                        case RTCLIENT:
827                                // only do this if we're reading from the RT interface
828                                if (fifo_out_read(libtrace->fifo, &packet->status, sizeof(int)) == 0) {
829                                        read_required = 1;
830                                        continue;
831                                }
832
833                                fifo_out_update(libtrace->fifo,sizeof(int));
834
835                                /* FALL THRU */
836                        case ERF:
837                        //case DAG:
838                                // read in the erf header
839                                if ((numbytes = fifo_out_read(libtrace->fifo, buffer, sizeof(dag_record_t))) == 0) {
840                                        fifo_out_reset(libtrace->fifo);
841                                        read_required = 1;
842                                        continue;
843                                }
844
845                                size = ntohs(((dag_record_t *)buffer)->rlen);
846                                break;
847                        case WAG:
848                                if ((numbytes = fifo_out_read(libtrace->fifo,
849                                                                &size,
850                                                                sizeof(size))) 
851                                                                == 0) {
852                                        fifo_out_reset(libtrace->fifo);
853                                        read_required = 1;
854                                        continue;
855                                }
856                                size*=4;
857                                break;
858                        default:
859                                fprintf(stderr,"Unknown type in _read()\n");
860                                assert(0);
861                }
862
863                assert(size < LIBTRACE_PACKET_BUFSIZE);
864
865                // read in the full packet
866                if ((numbytes = fifo_out_read(libtrace->fifo, buffer, size)) == 0) {
867                        fifo_out_reset(libtrace->fifo);
868                        read_required = 1;
869                        continue;
870                }
871
872                // got in our whole packet, so...
873                fifo_out_update(libtrace->fifo,size);
874
875                if (libtrace->sourcetype == SOCKET || libtrace->sourcetype == RT) {
876                        fifo_ack_update(libtrace->fifo,size + sizeof(int));
877                } else {
878                        fifo_ack_update(libtrace->fifo,size);
879                }
880               
881                packet->size = numbytes;
882                return numbytes;
883
884        } while (1);
885}
886
887
888/** get a pointer to the link layer
889 * @param packet        a pointer to a libtrace_packet structure
890 *
891 * @returns a pointer to the link layer, or NULL if there is no link layer
892 * you should call trace_get_link_type() to find out what type of link layer this is
893 */
894void *trace_get_link(const struct libtrace_packet_t *packet) {
895        const void *ethptr = 0;
896        dag_record_t *erfptr = 0;
897        struct wag_event_t *event = (struct wag_event_t *)packet->buffer;
898        struct wag_data_event_t *data_event;
899       
900       
901        switch(packet->trace->format) {
902                case ERF:
903                case DAG:
904                case RTCLIENT:
905                        erfptr = (dag_record_t *)packet->buffer;
906                        if (erfptr->flags.rxerror == 1) {
907                                return NULL;
908                        }
909                        if (trace_get_link_type(packet)==TRACE_TYPE_ETH) 
910                                ethptr = ((uint8_t *)packet->buffer + 
911                                                dag_record_size + 2);
912                        else
913                                ethptr = ((uint8_t *)packet->buffer + 
914                                                dag_record_size + 2);
915                        break;
916#if HAVE_PCAP
917                case PCAPINT:
918                case PCAP:
919                        ethptr = (packet->buffer + sizeof(struct pcap_pkthdr));
920                        break;
921#endif
922                case WAGINT:
923                case WAG:
924                        switch (event->type) {
925                                case 0x0:
926                                        data_event = (void*)&(event->payload);
927                                        return data_event->data;
928                                default:
929                                        fprintf(stderr,"Unknown WAG Event (0x%08x)\n",event->type);
930                                        return NULL;
931                        }
932                       
933                default:
934                        fprintf(stderr,"Don't know this trace format\n");
935                        assert(0);
936        }
937        return (void *)ethptr;
938}
939
940/** get a pointer to the IP header (if any)
941 * @param packet        a pointer to a libtrace_packet structure
942 *
943 * @returns a pointer to the IP header, or NULL if there is not an IP packet
944 */
945struct libtrace_ip *trace_get_ip(const struct libtrace_packet_t *packet) {
946        struct libtrace_ip *ipptr = 0;
947
948        switch(trace_get_link_type(packet)) {
949                case TRACE_TYPE_80211:
950                        { 
951                               
952                                struct ieee_802_11_header *wifi = trace_get_link(packet);       
953                                if (!wifi) {
954                                        ipptr = NULL;
955                                        break;
956                                }
957
958                                // Data packet?
959                                if (wifi->type != 2) {
960                                        ipptr = NULL;
961                                }
962                                else {
963                                        struct ieee_802_11_payload *eth = (void*)wifi->data;
964                                        if (eth->type != 0x0008) {
965                                                ipptr=NULL;
966                                        } else {
967                                                ipptr=(void*)eth->data;
968                                        }
969                                }
970                        }
971                        break;
972                case TRACE_TYPE_ETH:
973                        {
974                                struct ether_header *eth = 
975                                        trace_get_link(packet);
976                                if (!eth) {
977                                        ipptr = NULL;
978                                        break;
979                                }
980                                if (ntohs(eth->ether_type)!=0x0800) {
981                                        ipptr = NULL;
982                                }
983                                else {
984                                        ipptr = ((void *)eth) + 14;
985                                }
986                                break;
987                        }
988                case TRACE_TYPE_NONE:
989                        ipptr = trace_get_link(packet);
990                        break;
991                case TRACE_TYPE_LINUX_SLL:
992                        {
993                                struct trace_sll_header_t *sll;
994
995                                sll = trace_get_link(packet);
996                                if (!sll) {
997                                        ipptr = NULL;
998                                        break;
999                                }
1000                                if (ntohs(sll->protocol)!=0x0800) {
1001                                        ipptr = NULL;
1002                                }
1003                                else {
1004                                        ipptr = ((void*)sll)+sizeof(*sll);
1005                                }
1006                        }
1007                        break;
1008                case TRACE_TYPE_PFLOG:
1009                        {
1010                                struct trace_pflog_header_t *pflog;
1011                                pflog = trace_get_link(packet);
1012                                if (!pflog) {
1013                                        ipptr = NULL;
1014                                        break;
1015                                }
1016                                if (pflog->af != AF_INET) {
1017                                        ipptr = NULL;
1018                                } else {
1019                                        ipptr = ((void*)pflog)+sizeof(*pflog);
1020                                }
1021                        }
1022                        break;
1023                case TRACE_TYPE_ATM:
1024                        {
1025                                struct atm_rec *atm = 
1026                                        trace_get_link(packet);
1027                                // TODO: Find out what ATM does, and return
1028                                //       NULL for non IP data
1029                                //       Presumably it uses the normal stuff
1030                                if (!atm) {
1031                                        ipptr = NULL;
1032                                        break;
1033                                }
1034                                ipptr =  (void*)&atm->pload;
1035                                break;
1036                        }
1037                default:
1038                        fprintf(stderr,"Don't understand link layer type %i in trace_get_ip()\n",
1039                                trace_get_link_type(packet));
1040                        ipptr=NULL;
1041                        break;
1042        }
1043
1044        return ipptr;
1045}
1046
1047#define SW_IP_OFFMASK 0xff1f
1048
1049/** get a pointer to the TCP header (if any)
1050 * @param packet        a pointer to a libtrace_packet structure
1051 *
1052 * @returns a pointer to the TCP header, or NULL if there is not a TCP packet
1053 */
1054struct libtrace_tcp *trace_get_tcp(const struct libtrace_packet_t *packet) {
1055        struct libtrace_tcp *tcpptr = 0;
1056        struct libtrace_ip *ipptr = 0;
1057
1058        if(!(ipptr = trace_get_ip(packet))) {
1059                return 0;
1060        }
1061        if ((ipptr->ip_p == 6) && ((ipptr->ip_off & SW_IP_OFFMASK) == 0))  {
1062                tcpptr = (struct libtrace_tcp *)((ptrdiff_t)ipptr + (ipptr->ip_hl * 4));
1063        }
1064        return tcpptr;
1065}
1066
1067/** get a pointer to the TCP header (if any) given a pointer to the IP header
1068 * @param ip            The IP header
1069 * @param[out] skipped  An output variable of the number of bytes skipped
1070 *
1071 * @returns a pointer to the TCP header, or NULL if this is not a TCP packet
1072 *
1073 * Skipped can be NULL, in which case it will be ignored by the program.
1074 */
1075struct libtrace_tcp *get_tcp_from_ip(const struct libtrace_ip *ip, int *skipped)
1076{
1077#define SW_IP_OFFMASK 0xff1f
1078        struct libtrace_tcp *tcpptr = 0;
1079
1080        if ((ip->ip_p == 6) && ((ip->ip_off & SW_IP_OFFMASK) == 0))  {
1081                tcpptr = (struct libtrace_tcp *)((ptrdiff_t)ip+ (ip->ip_hl * 4));
1082        }
1083
1084        if (skipped)
1085                *skipped=(ip->ip_hl*4);
1086
1087        return tcpptr;
1088}
1089
1090/** get a pointer to the UDP header (if any)
1091 * @param packet        a pointer to a libtrace_packet structure
1092 *
1093 * @returns a pointer to the UDP header, or NULL if this is not a UDP packet
1094 */
1095struct libtrace_udp *trace_get_udp(const struct libtrace_packet_t *packet) {
1096        struct libtrace_udp *udpptr = 0;
1097        struct libtrace_ip *ipptr = 0;
1098       
1099        if(!(ipptr = trace_get_ip(packet))) {
1100                return 0;
1101        }
1102        if ((ipptr->ip_p == 17) && ((ipptr->ip_off & SW_IP_OFFMASK) == 0)) {
1103                udpptr = (struct libtrace_udp *)((ptrdiff_t)ipptr + (ipptr->ip_hl * 4));
1104        }
1105
1106        return udpptr;
1107}
1108
1109/** get a pointer to the UDP header (if any) given a pointer to the IP header
1110 * @param ip            The IP header
1111 * @param[out] skipped  An output variable of the number of bytes skipped
1112 *
1113 * @returns a pointer to the UDP header, or NULL if this is not a UDP packet
1114 *
1115 * Skipped can be NULL, in which case it will be ignored by the program.
1116 */
1117struct libtrace_udp *get_udp_from_ip(const struct libtrace_ip *ip, int *skipped)
1118{
1119        struct libtrace_udp *udpptr = 0;
1120
1121        if ((ip->ip_p == 6) && ((ip->ip_off & SW_IP_OFFMASK) == 0))  {
1122                udpptr = (struct libtrace_udp *)((ptrdiff_t)ip+ (ip->ip_hl * 4));
1123        }
1124
1125        if (skipped)
1126                *skipped=(ip->ip_hl*4);
1127
1128        return udpptr;
1129}
1130
1131
1132/** get a pointer to the ICMP header (if any)
1133 * @param packet        a pointer to a libtrace_packet structure
1134 *
1135 * @returns a pointer to the ICMP header, or NULL if this is not a ICMP packet
1136 */
1137struct libtrace_icmp *trace_get_icmp(const struct libtrace_packet_t *packet) {
1138        struct libtrace_icmp *icmpptr = 0;
1139        struct libtrace_ip *ipptr = 0;
1140       
1141        if(!(ipptr = trace_get_ip(packet))) {
1142                return 0;
1143        }
1144        if ((ipptr->ip_p == 1)&& ((ipptr->ip_off & SW_IP_OFFMASK) == 0 )){
1145                icmpptr = (struct libtrace_icmp *)((ptrdiff_t)ipptr + (ipptr->ip_hl * 4));
1146        }
1147        return icmpptr;
1148}
1149
1150/** get a pointer to the ICMP header (if any) given a pointer to the IP header
1151 * @param ip            The IP header
1152 * @param[out] skipped  An output variable of the number of bytes skipped
1153 *
1154 * @returns a pointer to the ICMP header, or NULL if this is not a ICMP packet
1155 *
1156 * Skipped can be NULL, in which case it will be ignored by the program.
1157 */
1158struct libtrace_icmp *get_icmp_from_ip(struct libtrace_ip *ip, int *skipped)
1159{
1160        struct libtrace_icmp *icmpptr = 0;
1161
1162        if ((ip->ip_p == 6) && ((ip->ip_off & SW_IP_OFFMASK) == 0))  {
1163                icmpptr = (struct libtrace_icmp *)((ptrdiff_t)ip+ (ip->ip_hl * 4));
1164        }
1165
1166        if (skipped)
1167                *skipped=(ip->ip_hl*4);
1168
1169        return icmpptr;
1170}
1171/** parse an ip or tcp option
1172 * @param[in,out] ptr   the pointer to the current option
1173 * @param[in,out] len   the length of the remaining buffer
1174 * @param[out] type     the type of the option
1175 * @param[out] optlen   the length of the option
1176 * @param[out] data     the data of the option
1177 *
1178 * @returns bool true if there is another option (and the fields are filled in)
1179 *               or false if this was the last option.
1180 *
1181 * This updates ptr to point to the next option after this one, and updates
1182 * len to be the number of bytes remaining in the options area.  Type is updated
1183 * to be the code of this option, and data points to the data of this option,
1184 * with optlen saying how many bytes there are.
1185 *
1186 * @note Beware of fragmented packets.
1187 * @author Perry Lorier
1188 */
1189int trace_get_next_option(unsigned char **ptr,int *len,
1190                        unsigned char *type,
1191                        unsigned char *optlen,
1192                        unsigned char **data)
1193{
1194        if (*len<=0)
1195                return 0;
1196        *type=**ptr;
1197        switch(*type) {
1198                case 0: /* End of options */
1199                        return 0;
1200                case 1: /* Pad */
1201                        (*ptr)++;
1202                        (*len)--;
1203                        return 1;
1204                default:
1205                        *optlen = *(*ptr+1);
1206                        if (*optlen<2)
1207                                return 0; // I have no idea wtf is going on
1208                                          // with these packets
1209                        (*len)-=*optlen;
1210                        (*data)=(*ptr+2);
1211                        (*ptr)+=*optlen;
1212                        if (*len<0)
1213                                return 0;
1214                        return 1;
1215        }
1216        assert(0);
1217}
1218
1219
1220/** Get the current time in DAG time format
1221 * @param packet        a pointer to a libtrace_packet structure
1222 * @returns a 64 bit timestamp in DAG ERF format (upper 32 bits are the seconds
1223 * past 1970-01-01, the lower 32bits are partial seconds)
1224 * @author Daniel Lawson
1225 */ 
1226uint64_t trace_get_erf_timestamp(const struct libtrace_packet_t *packet) {
1227        uint64_t timestamp = 0;
1228        dag_record_t *erfptr = 0;
1229        struct pcap_pkthdr *pcapptr = 0;
1230        struct wag_event_t *wagptr = 0;
1231        switch (packet->trace->format) {
1232                case DAG:
1233                case ERF:
1234                case RTCLIENT:
1235                        erfptr = (dag_record_t *)packet->buffer;
1236                        timestamp = erfptr->ts;
1237                        break;
1238#if HAVE_PCAP
1239                case PCAPINT:
1240                case PCAP:
1241                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
1242                        timestamp = ((((uint64_t)pcapptr->ts.tv_sec) << 32) + \
1243                                (pcapptr->ts.tv_usec*UINT_MAX/1000000));
1244                        break;
1245#endif
1246                case WAGINT:
1247                case WAG:
1248                        wagptr = (struct wag_event_t *)packet->buffer;
1249                        timestamp = wagptr->timestamp_lo;
1250                        timestamp |= (uint64_t)wagptr->timestamp_hi<<32;
1251                        timestamp = ((timestamp%44000000)*(UINT_MAX/44000000))
1252                                  | ((timestamp/44000000)<<32);
1253                        break;
1254                default:
1255                        fprintf(stderr,"Unknown format in trace_get_erf_timestamp\n");
1256                        timestamp = 0;
1257        }
1258        return timestamp;
1259}
1260
1261/** Get the current time in struct timeval
1262 * @param packet        a pointer to a libtrace_packet structure
1263 *
1264 * @returns time that this packet was seen in a struct timeval
1265 * @author Daniel Lawson
1266 * @author Perry Lorier
1267 */ 
1268struct timeval trace_get_timeval(const struct libtrace_packet_t *packet) {
1269        struct timeval tv;
1270#if HAVE_PCAP
1271        struct pcap_pkthdr *pcapptr = 0;
1272#endif
1273        uint64_t ts;
1274        //uint32_t seconds;
1275        switch (packet->trace->format) {
1276#if HAVE_PCAP
1277                case PCAPINT:
1278                case PCAP:
1279                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
1280                        // ick. FIXME
1281                        tv.tv_sec = pcapptr->ts.tv_sec;
1282                        tv.tv_usec = pcapptr->ts.tv_usec;
1283                        break;
1284#endif
1285                case WAGINT:
1286                case WAG:
1287                case DAG:
1288                case ERF:
1289                case RTCLIENT:
1290                default:
1291                        // FIXME: This isn't portable to big-endian machines
1292                        ts = trace_get_erf_timestamp(packet);
1293                        tv.tv_sec = ts >> 32;           
1294                        ts = (1000000 * (ts & 0xffffffffULL));
1295                        ts += (ts & 0x80000000ULL) << 1;
1296                        tv.tv_usec = ts >> 32;
1297                        if (tv.tv_usec >= 1000000) {
1298                                tv.tv_usec -= 1000000;
1299                                tv.tv_sec += 1;
1300                        }
1301                        break;
1302        }
1303        return tv;
1304}
1305
1306/** Get the current time in floating point seconds
1307 * @param packet        a pointer to a libtrace_packet structure
1308 * @returns time that this packet was seen in 64bit floating point seconds
1309 * @author Perry Lorier
1310 */ 
1311double trace_get_seconds(const struct libtrace_packet_t *packet) {
1312        uint64_t ts;
1313        ts = trace_get_erf_timestamp(packet);
1314        return (ts>>32) + ((ts & UINT_MAX)*1.0 / UINT_MAX);
1315}
1316
1317/** Get the size of the packet in the trace
1318 * @param packet the packet opaque pointer
1319 * @returns the size of the packet in the trace
1320 * @author Perry Lorier
1321 * @note Due to this being a header capture, or anonymisation, this may not
1322 * be the same size as the original packet.  See trace_get_wire_length() for the
1323 * original size of the packet.
1324 * @note This can (and often is) different for different packets in a trace!
1325 * @par
1326 *  This is sometimes called the "snaplen".
1327 */ 
1328int trace_get_capture_length(const struct libtrace_packet_t *packet) {
1329        dag_record_t *erfptr = 0;
1330#if HAVE_PCAP
1331        struct pcap_pkthdr *pcapptr = 0;
1332#endif
1333        struct wag_event_t *wag_event;
1334        switch (packet->trace->format) {
1335                case DAG:
1336                case ERF:
1337                case RTCLIENT:
1338                        erfptr = (dag_record_t *)packet->buffer;
1339                        return ntohs(erfptr->rlen);
1340#if HAVE_PCAP
1341                case PCAPINT:
1342                case PCAP:
1343                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
1344                        //return ntohs(pcapptr->caplen);
1345                        return pcapptr->caplen;
1346#endif
1347                case WAGINT:
1348                case WAG:
1349                        wag_event = (struct wag_event_t *)packet->buffer;
1350                        switch(wag_event->type) {
1351                                case 0:
1352                                        return wag_event->length*4-(
1353                                                sizeof(struct wag_event_t)+
1354                                                sizeof(struct wag_data_event_t)
1355                                                );
1356                                default:
1357                                        assert(0);
1358                        }
1359                default:
1360                        assert(0);
1361        }
1362        return -1;
1363}
1364       
1365/** Get the size of the packet as it was seen on the wire.
1366 * @param packet        a pointer to a libtrace_packet structure
1367 *
1368 * @returns the size of the packet as it was on the wire.
1369 * @author Perry Lorier
1370 * @author Daniel Lawson
1371 * @note Due to the trace being a header capture, or anonymisation this may
1372 * not be the same as the Capture Len.
1373 */ 
1374int trace_get_wire_length(const struct libtrace_packet_t *packet){
1375        dag_record_t *erfptr = 0;
1376#if HAVE_PCAP
1377        struct pcap_pkthdr *pcapptr = 0;
1378#endif
1379        struct wag_event_t *wag_event = 0;
1380        switch (packet->trace->format) {
1381                case DAG:
1382                case ERF:
1383                case RTCLIENT:
1384                        erfptr = (dag_record_t *)packet->buffer;
1385                        return ntohs(erfptr->wlen);
1386                        break;
1387#if HAVE_PCAP
1388                case PCAPINT:
1389                case PCAP:
1390                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
1391                        return ntohs(pcapptr->len);
1392                        break;
1393#endif
1394                case WAGINT:
1395                case WAG:
1396                        wag_event = (struct wag_event_t *)packet->buffer;
1397                        switch(wag_event->type) {
1398                                case 0:
1399                                        return ((struct wag_data_event_t *)(&wag_event->payload))->frame_length;
1400                                default:
1401                                        assert(0);
1402                        }
1403        }
1404        return -1;
1405
1406}
1407
1408/** Get the type of the link layer
1409 * @param packet        a pointer to a libtrace_packet structure
1410 * @returns libtrace_linktype_t
1411 * @author Perry Lorier
1412 * @author Daniel Lawson
1413 */
1414libtrace_linktype_t trace_get_link_type(const struct libtrace_packet_t *packet ) {
1415        dag_record_t *erfptr = 0;
1416#if HAVE_PCAP
1417        struct pcap_pkthdr *pcapptr = 0;
1418#endif
1419        int linktype = 0;
1420        switch (packet->trace->format) {
1421                case DAG:
1422                case ERF:
1423                case RTCLIENT:
1424                        erfptr = (dag_record_t *)packet->buffer;
1425                        switch (erfptr->type) {
1426                                case TYPE_ETH: return TRACE_TYPE_ETH;
1427                                case TYPE_ATM: return TRACE_TYPE_ATM;
1428                                default: assert(0);
1429                        }
1430                        return erfptr->type;
1431                       
1432                        break;
1433#if HAVE_PCAP
1434                case PCAPINT:
1435                case PCAP:
1436                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
1437                        linktype = pcap_datalink(packet->trace->input.pcap);
1438                        switch (linktype) {
1439                                case DLT_NULL:
1440                                        return TRACE_TYPE_NONE;
1441                                case DLT_EN10MB:
1442                                        return TRACE_TYPE_ETH; 
1443                                case DLT_ATM_RFC1483:
1444                                        return TRACE_TYPE_ATM;
1445                                case DLT_IEEE802_11:
1446                                        return TRACE_TYPE_80211;
1447#ifdef DLT_LINUX_SLL
1448                                case DLT_LINUX_SLL:
1449                                        return TRACE_TYPE_LINUX_SLL;
1450#endif
1451#ifdef DLT_PFLOG
1452                                case DLT_PFLOG:
1453                                        return TRACE_TYPE_PFLOG;
1454#endif
1455                        }
1456                        break;
1457#endif
1458                case WAGINT:
1459                case WAG:
1460                        return TRACE_TYPE_80211;
1461        }
1462        return -1;
1463}
1464
1465/** Get the source MAC addres
1466 * @param packet        a pointer to a libtrace_packet structure
1467 * @returns a pointer to the source mac, (or NULL if there is no source MAC)
1468 * @author Perry Lorier
1469 */
1470uint8_t *trace_get_source_mac(const struct libtrace_packet_t *packet) {
1471        void *link = trace_get_link(packet);
1472        struct ieee_802_11_header *wifi = link;
1473        struct ether_header *ethptr = link;
1474        if (!link)
1475                return NULL;
1476        switch (trace_get_link_type(packet)) {
1477                case TRACE_TYPE_80211:
1478                        return (uint8_t*)&wifi->mac2;
1479                case TRACE_TYPE_ETH:
1480                        return (uint8_t*)&ethptr->ether_shost;
1481                default:
1482                        fprintf(stderr,"Not implemented\n");
1483                        assert(0);
1484        }
1485}
1486
1487/** Get the destination MAC addres
1488 * @param packet a libtrace_packet pointer
1489 * @returns a pointer to the destination mac, (or NULL if there is no
1490 * destination MAC)
1491 * @author Perry Lorier
1492 */
1493uint8_t *trace_get_destination_mac(const struct libtrace_packet_t *packet) {
1494        void *link = trace_get_link(packet);
1495        struct ieee_802_11_header *wifi = link;
1496        struct ether_header *ethptr = link;
1497        if (!link)
1498                return NULL;
1499        switch (trace_get_link_type(packet)) {
1500                case TRACE_TYPE_80211:
1501                        return (uint8_t*)&wifi->mac1;
1502                case TRACE_TYPE_ETH:
1503                        return (uint8_t*)&ethptr->ether_dhost;
1504                default:
1505                        fprintf(stderr,"Not implemented\n");
1506                        assert(0);
1507        }
1508}
1509
1510
1511/** process a libtrace event
1512 * @param trace the libtrace opaque pointer
1513 * @param packet the libtrace_packet opaque pointer
1514 * @returns
1515 *  TRACE_EVENT_IOWAIT  Waiting on I/O on fd
1516 *  TRACE_EVENT_SLEEP   Next event in seconds
1517 *  TRACE_EVENT_PACKET  Packet arrived in buffer with size size
1518 *  TRACE_EVENT_TERMINATE Trace terminated (perhaps with an error condition)
1519 * FIXME currently keeps a copy of the packet inside the trace pointer,
1520 * which in turn is stored inside the new packet object...
1521 * @author Perry Lorier
1522 */
1523struct libtrace_eventobj_t trace_event(struct libtrace_t *trace, 
1524                struct libtrace_packet_t *packet) {
1525        struct libtrace_eventobj_t event;
1526
1527        if (!trace) {
1528                fprintf(stderr,"You called trace_event() with a NULL trace object!\n");
1529        }
1530        assert(trace);
1531        assert(packet);
1532
1533        /* Store the trace we are reading from into the packet opaque
1534         * structure */
1535        packet->trace = trace;
1536
1537        /* Is there a packet ready? */
1538        switch (trace->sourcetype) {
1539#if HAVE_PCAP
1540                case INTERFACE:
1541                        {
1542                                int data;
1543                                event.fd = pcap_fileno(trace->input.pcap);
1544                                if(ioctl(event.fd,FIONREAD,&data)==-1){
1545                                        perror("ioctl(FIONREAD)");
1546                                }
1547                                if (data>0) {
1548                                        event.size = trace_read_packet(trace,packet);
1549                                        event.type = TRACE_EVENT_PACKET;
1550                                        return event;
1551                                }
1552                                event.type = TRACE_EVENT_IOWAIT;
1553                                return event;
1554                        }
1555#endif
1556                case SOCKET:
1557                case DEVICE:
1558                case RT:
1559                        {
1560                                int data;
1561                                event.fd = trace->input.fd;
1562                                if(ioctl(event.fd,FIONREAD,&data)==-1){
1563                                        perror("ioctl(FIONREAD)");
1564                                }
1565                                if (data>0) {
1566                                        event.size = trace_read_packet(trace,packet);
1567                                        event.type = TRACE_EVENT_PACKET;
1568                                        return event;
1569                                }
1570                                event.type = TRACE_EVENT_IOWAIT;
1571                                return event;
1572                        }
1573                case STDIN:
1574                case TRACE:
1575                        {
1576                                double ts;
1577                                double now;
1578                                struct timeval stv;
1579                                /* "Prime" the pump */
1580                                if (!trace->packet.buffer) {
1581                                        trace->packet.buffer = malloc(4096);
1582                                        trace->packet.size=
1583                                                trace_read_packet(trace,packet);
1584                                        event.size = trace->packet.size;
1585                                        if (trace->packet.size > 0 ) {
1586                                                memcpy(trace->packet.buffer,packet->buffer,trace->packet.size);
1587                                        } else {
1588                                                // return here, the test for event.size will sort out the error
1589                                                event.type = TRACE_EVENT_PACKET;
1590                                                return event;
1591                                        }
1592                                }
1593
1594                                ts=trace_get_seconds(packet);
1595                                if (trace->tdelta!=0) {
1596                                        // Get the adjusted current time
1597                                        gettimeofday(&stv, NULL);
1598                                        now = stv.tv_sec + ((double)stv.tv_usec / 1000000.0);
1599                                        now -= trace->tdelta; // adjust for trace delta
1600                                       
1601                                       
1602                                        // if the trace timestamp is still in the future,
1603                                        // return a SLEEP event, otherwise fire the packet
1604                                        if (ts > now) {
1605                                                event.seconds = ts - trace->trace_last_ts;
1606                                                event.type = TRACE_EVENT_SLEEP;
1607                                                return event;
1608                                        }
1609                                } else {
1610                                        gettimeofday(&stv, NULL);
1611                                        // work out the difference between the start of trace replay,
1612                                        // and the first packet in the trace
1613                                        trace->tdelta = stv.tv_sec + ((double)stv.tv_usec / 1000000.0);
1614                                        trace->tdelta -= ts;
1615
1616                                }
1617                               
1618                                        // This is the first packet, so just fire away.
1619                                packet->size = trace->packet.size;
1620                                memcpy(packet->buffer,trace->packet.buffer,trace->packet.size);
1621
1622                                free(trace->packet.buffer);
1623                                trace->packet.buffer = 0;
1624                                event.type = TRACE_EVENT_PACKET;
1625                               
1626                                trace->trace_last_ts = ts;
1627
1628                                return event;
1629                        }
1630                default:
1631                        assert(0);
1632        }
1633        assert(0);
1634}
1635
1636/** setup a BPF filter
1637 * @param filterstring a char * containing the bpf filter string
1638 * @returns opaque pointer pointer to a libtrace_filter_t object
1639 * @author Daniel Lawson
1640 */
1641struct libtrace_filter_t *trace_bpf_setfilter(const char *filterstring) {
1642#if HAVE_BPF
1643        struct libtrace_filter_t *filter = malloc(sizeof(struct libtrace_filter_t));
1644        filter->filterstring = strdup(filterstring);
1645        filter->filter = 0;
1646        return filter;
1647#else
1648        fprintf(stderr,"This version of libtrace does not have bpf filter support\n");
1649        return 0;
1650#endif
1651}
1652
1653/** apply a BPF filter
1654 * @param filter the filter opaque pointer
1655 * @param packet the packet opaque pointer
1656 * @returns 0 if the filter fails, 1 if it succeeds
1657 * @author Daniel Lawson
1658 */
1659int trace_bpf_filter(struct libtrace_filter_t *filter,
1660                        const struct libtrace_packet_t *packet) {
1661#if HAVE_BPF
1662        void *linkptr = 0;
1663        int clen = 0;
1664        assert(filter);
1665        assert(packet);
1666        linkptr = trace_get_link(packet);
1667        if (!linkptr) {
1668                return 0;
1669        }
1670       
1671        clen = trace_get_capture_length(packet);
1672       
1673
1674        if (filter->filterstring && ! filter->filter) {
1675                pcap_t *pcap;
1676                struct bpf_program bpfprog;
1677
1678                switch (trace_get_link_type(packet)) {
1679                        case TRACE_TYPE_ETH:
1680                                pcap = (pcap_t *)pcap_open_dead(DLT_EN10MB, 1500);
1681                                break;
1682#ifdef DLT_LINUX_SLL
1683                        case TRACE_TYPE_LINUX_SLL:
1684                                pcap = (pcap_t *)pcap_open_dead(DLT_LINUX_SLL, 1500);
1685                                break;
1686#endif
1687#ifdef DLT_PFLOG
1688                        case TRACE_TYPE_PFLOG:
1689                                pcap = (pcap_t *)pcap_open_dead(DLT_PFLOG, 1500);
1690                                break;
1691#endif
1692                        default:
1693                                printf("only works for ETH and LINUX_SLL (ppp) at the moment\n");
1694                                assert(0);
1695                }               
1696
1697                // build filter
1698                if (pcap_compile( pcap, &bpfprog, filter->filterstring, 1, 0)) {
1699                        printf("bpf compilation error: %s\n", 
1700                                pcap_geterr(pcap));
1701                        assert(0);
1702                }
1703                pcap_close(pcap);
1704                filter->filter = bpfprog.bf_insns;     
1705        }
1706
1707        assert(filter->filter);
1708        return bpf_filter(filter->filter, linkptr, clen, clen);
1709#else
1710        fprintf(stderr,"This version of libtrace does not have bpf filter support\n");
1711        return 0;
1712#endif
1713}
1714
1715/** Set the direction flag, if it has one
1716 * @param packet the packet opaque pointer
1717 * @param direction the new direction (0,1,2,3)
1718 * @returns a signed value containing the direction flag, or -1 if this is not supported
1719 * @author Daniel Lawson
1720 */
1721int8_t trace_set_direction(struct libtrace_packet_t *packet, int8_t direction) {
1722       
1723        dag_record_t *erfptr = 0;
1724        assert(packet);
1725
1726        switch(packet->trace->format) {
1727                case DAG:
1728                case ERF:
1729                case RTCLIENT:
1730                        erfptr = (dag_record_t *)packet->buffer;
1731                        erfptr->flags.iface = direction;
1732                        break;
1733                default:
1734                        direction = -1;
1735        }
1736       
1737        return direction;
1738       
1739       
1740}
1741
1742/** Get the direction flag, if it has one
1743 * @param packet a pointer to a libtrace_packet structure
1744 * @returns a signed value containing the direction flag, or -1 if this is not supported
1745 * The direction is defined as 0 for packets originating locally (ie, outbound)
1746 * and 1 for packets originating remotely (ie, inbound).
1747 * Other values are possible, which might be overloaded to mean special things
1748 * for a special trace.
1749 * @author Daniel Lawson
1750 */
1751int8_t trace_get_direction(const struct libtrace_packet_t *packet) {
1752       
1753        int8_t direction;
1754        dag_record_t *erfptr = 0;
1755        assert(packet);
1756        direction = -1;
1757
1758        switch(packet->trace->format) {
1759                case DAG:
1760                case ERF:
1761                case RTCLIENT:
1762                        erfptr = (dag_record_t *)packet->buffer;
1763                        direction = erfptr->flags.iface;
1764                        break;
1765                case PCAP:
1766                case PCAPINT:
1767                        switch (trace_get_link_type(packet)) {
1768                                case TRACE_TYPE_LINUX_SLL:
1769                                {
1770                                        struct trace_sll_header_t *sll;
1771                                        sll = trace_get_link(packet);
1772                                        if (!sll) {
1773                                                return -1;
1774                                        }
1775                                        /* 0 == LINUX_SLL_HOST */
1776                                        /* the Waikato Capture point defines "packets
1777                                         * originating locally" (ie, outbound), with a
1778                                         * direction of 0, and "packets destined locally"
1779                                         * (ie, inbound), with a direction of 1.
1780                                         * This is kind-of-opposite to LINUX_SLL.
1781                                         * We return consistent values here, however
1782                                         *
1783                                         * Note that in recent versions of pcap, you can
1784                                         * use "inbound" and "outbound" on ppp in linux
1785                                         */
1786                                        if (ntohs(sll->pkttype==0)) {
1787
1788                                                direction = 1;
1789                                        }
1790                                        else {
1791                                                direction = 0;
1792                                        }
1793                                        break;
1794                                }
1795                                case TRACE_TYPE_PFLOG:
1796                                {
1797                                        struct trace_pflog_header_t *pflog;
1798                                        pflog = trace_get_link(packet);
1799                                        if (!pflog) {
1800                                                return -1;
1801                                        }
1802                                        /* enum    { PF_IN=0, PF_OUT=1 }; */
1803                                        if (ntohs(pflog->dir==0)) {
1804
1805                                                direction = 1;
1806                                        }
1807                                        else {
1808                                                direction = 0;
1809                                        }
1810                                        break;
1811                                }
1812                                default:
1813                                        /* pass */
1814                                        break;
1815                        }
1816                default:
1817                        /* pass */
1818                        break;
1819        }
1820       
1821        return direction;
1822       
1823       
1824}
1825
1826struct ports_t {
1827        uint16_t src;
1828        uint16_t dst;
1829};
1830
1831/* Return the client port
1832 */
1833uint16_t trace_get_source_port(const struct libtrace_packet_t *packet)
1834{
1835        struct libtrace_ip *ip = trace_get_ip(packet);
1836        struct ports_t *port;
1837        if (6 != ip->ip_p
1838          && 17 != ip->ip_p)
1839                return 0;
1840        if (0 != (ip->ip_off & SW_IP_OFFMASK))
1841                return 0;
1842
1843        port = (struct ports_t *)((ptrdiff_t)ip + (ip->ip_hl * 4));
1844
1845        return htons(port->src);
1846}
1847
1848/* Same as get_source_port except use the destination port */
1849uint16_t trace_get_destination_port(const struct libtrace_packet_t *packet)
1850{
1851        struct libtrace_ip *ip = trace_get_ip(packet);
1852        struct ports_t *port;
1853
1854        if (6 != ip->ip_p
1855          && 17 != ip->ip_p)
1856                return 0;
1857
1858        if (0 != (ip->ip_off & SW_IP_OFFMASK))
1859                return 0;
1860
1861        port = (struct ports_t *)((ptrdiff_t)ip + (ip->ip_hl * 4));
1862
1863        return htons(port->dst);
1864}
1865
1866#define ROOT_SERVER(x) ((x) < 512)
1867#define ROOT_CLIENT(x) ((512 <= (x)) && ((x) < 1024))
1868#define NONROOT_SERVER(x) ((x) >= 5000)
1869#define NONROOT_CLIENT(x) ((1024 <= (x)) && ((x) < 5000))
1870#define DYNAMIC(x) ((49152 < (x)) && ((x) < 65535))
1871#define SERVER(x) ROOT_SERVER(x) || NONROOT_SERVER(x)
1872#define CLIENT(x) ROOT_CLIENT(x) || NONROOT_CLIENT(x)
1873
1874/* Attempt to deduce the 'server' port
1875 * @param protocol the IP protocol (eg, 6 or 17 for TCP or UDP)
1876 * @param source the TCP or UDP source port
1877 * @param dest the TCP or UDP destination port
1878 * @returns a hint as to which port is the server port
1879 * @author Daniel Lawson
1880 */
1881int8_t trace_get_server_port(uint8_t protocol, uint16_t source, uint16_t dest) {
1882        /*
1883         * * If the ports are equal, return DEST
1884         * * Check for well-known ports in the given protocol
1885         * * Root server ports: 0 - 511
1886         * * Root client ports: 512 - 1023
1887         * * non-root client ports: 1024 - 4999
1888         * * non-root server ports: 5000+
1889         * * Check for static ranges: 1024 - 49151
1890         * * Check for dynamic ranges: 49152 - 65535
1891         * * flip a coin.
1892         */
1893
1894        uint16_t server, client;
1895
1896        /* equal */
1897        if (source == client)
1898                return USE_DEST;
1899
1900        /* root server port, 0 - 511 */
1901        if (ROOT_SERVER(source) && ROOT_SERVER(dest)) {
1902                if (source < dest)
1903                        return USE_SOURCE;
1904                return USE_DEST;
1905        }
1906
1907        if (ROOT_SERVER(source) && !ROOT_SERVER(dest))
1908                return USE_SOURCE;
1909        if (!ROOT_SERVER(source) && ROOT_SERVER(dest))
1910                return USE_DEST;
1911
1912        /* non-root server */
1913        if (NONROOT_SERVER(source) && NONROOT_SERVER(dest)) {
1914                if (source < dest)
1915                        return USE_SOURCE;
1916                return USE_DEST;
1917        }
1918        if (NONROOT_SERVER(source) && !NONROOT_SERVER(dest))
1919                return USE_SOURCE;
1920        if (!NONROOT_SERVER(source) && NONROOT_SERVER(dest))
1921                return USE_DEST;
1922
1923        /* root client */
1924        if (ROOT_CLIENT(source) && ROOT_CLIENT(dest)) {
1925                if (source < dest)
1926                        return USE_SOURCE;
1927                return USE_DEST;
1928        }
1929        if (ROOT_CLIENT(source) && !ROOT_CLIENT(dest)) {
1930                /* prefer root-client over nonroot-client */
1931                if (NONROOT_CLIENT(dest))
1932                        return USE_SOURCE;
1933                return USE_DEST;
1934        }
1935        if (!ROOT_CLIENT(source) && ROOT_CLIENT(dest)) {
1936                /* prefer root-client over nonroot-client */
1937                if (NONROOT_CLIENT(source))
1938                        return USE_DEST;
1939                return USE_SOURCE;
1940        }
1941       
1942        /* nonroot client */
1943        if (NONROOT_CLIENT(source) && NONROOT_CLIENT(dest)) {
1944                if (source < dest) 
1945                        return USE_SOURCE;
1946                return USE_DEST;
1947        }
1948        if (NONROOT_CLIENT(source) && !NONROOT_CLIENT(dest))
1949                return USE_DEST;
1950        if (!NONROOT_CLIENT(source) && NONROOT_CLIENT(dest))
1951                return USE_SOURCE;
1952
1953        /* dynamic range */
1954        if (DYNAMIC(source) && DYNAMIC(dest))
1955                if (source < dest)
1956                        return USE_SOURCE;
1957                return USE_DEST;
1958        if (DYNAMIC(source) && !DYNAMIC(dest))
1959                return USE_DEST;
1960        if (!DYNAMIC(source) && DYNAMIC(dest))
1961                return USE_SOURCE;
1962        /*
1963        if (SERVER(source) && CLIENT(dest))
1964                return USE_SOURCE;
1965       
1966        if (SERVER(dest) && CLIENT(source))
1967                return USE_DEST;
1968        if (ROOT_SERVER(source) && !ROOT_SERVER(dest))
1969                return USE_SOURCE;
1970        if (ROOT_SERVER(dest) && !ROOT_SERVER(source))
1971                return USE_DEST;
1972        */
1973        // failing that test...
1974        if (source < dest) {
1975                return USE_SOURCE;
1976        } 
1977        return USE_DEST;
1978       
1979}
1980
1981/** Truncate the packet at the suggested length
1982 * @param packet        the packet opaque pointer
1983 * @param size          the new length of the packet
1984 * @returns the new length of the packet, or the original length of the
1985 * packet if unchanged
1986 * NOTE: len refers to the network-level payload of the packet, and not
1987 * any capture headers included as well. For example, to truncate a packet
1988 * after the IP header, set scan to sizeof(ethernet_header) + sizeof(ip_header)
1989 * @author Daniel Lawson
1990 */
1991size_t trace_truncate_packet(struct libtrace_packet_t *packet, size_t size) {
1992        dag_record_t *erfptr;
1993#if HAVE_PCAP
1994        struct pcap_pkthdr *pcaphdr;
1995#endif
1996
1997        assert(packet);
1998
1999        if (size > packet->size) {
2000                // can't make a packet larger
2001                return packet->size;
2002        }
2003        switch (packet->trace->format) {
2004#if HAVE_PCAP
2005                case PCAPINT:
2006                case PCAP:
2007                        pcaphdr = (struct pcap_pkthdr *)packet->buffer;
2008                        pcaphdr->caplen = size + sizeof(struct pcap_pkthdr);
2009                        packet->size = pcaphdr->caplen;
2010                        break;
2011#endif
2012                case ERF:
2013                case DAG:
2014                case RTCLIENT:
2015                        erfptr = (dag_record_t *)packet->buffer;
2016                        erfptr->rlen = ntohs(size + sizeof(dag_record_t));
2017                        packet->size = size + sizeof(dag_record_t);
2018                        break;
2019                case WAGINT:
2020                case WAG:
2021                        // don't know how to do this?
2022                        break;
2023        }
2024        return packet->size;
2025}
2026
Note: See TracBrowser for help on using the repository browser.