source: lib/trace.c @ 3cfa94a

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

bump version to 2.0.16. Not installed anywhere

Fixed the event api to work with tracefiles:

  • wasn't actually copying into internal buffer
  • timekeeping had second resolution, this didn't work very well
  • added a TRACE_EVENT_TERMINATE event, so that we don't loose the

return condition from trace_read_packet

This still needs a bit of work.

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