source: lib/trace.c @ b36a3b7

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

poink

  • Property mode set to 100644
File size: 39.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/** @file
32 *
33 * @brief Trace file processing library
34 *
35 * @author Daniel Lawson
36 * @author Perry Lorier
37 *
38 */
39#define _GNU_SOURCE
40#include "common.h"
41#include "config.h"
42#include <assert.h>
43#include <errno.h>
44#include <fcntl.h>
45#include <netdb.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <sys/stat.h>
50#include <sys/types.h>
51
52#ifdef HAVE_LIMITS_H
53#  include <limits.h>
54#endif
55
56#ifdef HAVE_SYS_LIMITS_H
57#  include <sys/limits.h>
58#endif
59
60#include <sys/socket.h>
61#include <sys/un.h>
62#include <sys/mman.h>
63#include <unistd.h>
64#include <net/ethernet.h>
65#include <time.h>
66#include <sys/ioctl.h>
67
68#ifdef HAVE_STDINT_H
69#  include <stdint.h>
70#else
71#  error "Can't find stdint.h - you need to replace this"
72#endif
73
74#ifdef HAVE_STDDEF_H
75#  include <stddef.h>
76#else
77# error "Can't find stddef.h - do you define ptrdiff_t elsewhere?"
78#endif
79
80#include "libtrace.h"
81#include "fifo.h"
82
83#ifdef HAVE_PCAP_BPF_H
84#  include <pcap-bpf.h>
85#else
86#  ifdef HAVE_NET_BPF_H
87#    include <net/bpf.h>
88#  endif
89#endif
90
91#include <zlib.h>
92#include <pcap.h>
93#include <zlib.h>
94
95
96#include "wag.h"
97
98#ifdef HAVE_DAG_API
99#  include "dagnew.h"
100#  include "dagapi.h"
101#  define DAGDEVICE 1
102#else
103#  include "dagformat.h"
104#endif
105
106
107typedef enum {SOCKET, TRACE, STDIN, DEVICE, INTERFACE, RT } source_t;
108
109typedef enum {ERF, PCAP, PCAPINT, DAG, RTCLIENT, WAG, WAGINT } format_t;
110
111struct libtrace_filter_t {
112        struct bpf_insn *filter;
113        char * filterstring;
114};
115
116struct libtrace_t {
117        format_t format;
118        source_t sourcetype;
119        union {
120                struct {
121                        char *hostname;
122                        short port;
123                } rt;
124                char *path;
125                char *interface;
126        } conn_info;
127        union {
128                int fd;
129                gzFile *file;
130                pcap_t *pcap;
131        } input;
132        struct fifo_t *fifo;   
133        void *buf; 
134        struct {
135                void *buffer;
136                int size;
137        } packet;
138        double last_ts;
139        double start_ts;
140};
141
142#define URI_PROTO_LINE 16
143static int init_trace(struct libtrace_t **libtrace, char *uri) {
144        char *scan = calloc(sizeof(char),URI_PROTO_LINE);
145        char *uridata = 0;                 
146        struct stat buf;
147       
148        // parse the URI to determine what sort of event we are dealing with
149       
150        // want snippet before the : to get the uri base type.
151
152        if((uridata = strchr(uri,':')) == NULL) {
153                // badly formed URI - needs a :
154                return 0;
155        }
156
157        if ((*uridata - *uri) > URI_PROTO_LINE) {
158                // badly formed URI - uri type is too long
159                return 0;
160        }
161        strncpy(scan,uri, (uridata - uri));
162
163        if (!strncasecmp(scan,"erf",3)) {
164                (*libtrace)->format=ERF;
165        } else if (!strncasecmp(scan,"pcapint",7)) {
166                (*libtrace)->format=PCAPINT;
167        } else if (!strncasecmp(scan,"pcap",4)) {
168                (*libtrace)->format=PCAP;
169        } else if (!strncasecmp(scan,"dag",3)) {
170                (*libtrace)->format=DAG;
171        } else if (!strncasecmp(scan,"rtclient",7)) {
172                (*libtrace)->format=RTCLIENT;
173        } else if (!strncasecmp(scan,"wagint",6)) {
174                (*libtrace)->format=WAGINT;
175        } else if (!strncasecmp(scan,"wag",3)) {
176                (*libtrace)->format=WAG;
177        } else {
178                //badly formed URI
179                return 0;
180        }
181       
182        // push uridata past the delimiter
183        uridata++;
184       
185        // libtrace->format now contains the type of uri
186        // libtrace->uridata contains the appropriate data for this
187       
188        switch((*libtrace)->format) {
189                case PCAPINT:
190                case WAGINT:
191                        /* Can have uridata of the following format
192                         * eth0
193                         * etc
194                         */
195                        // We basically assume this is correct.
196                        (*libtrace)->sourcetype = INTERFACE;   
197                        (*libtrace)->conn_info.path = strdup(uridata);
198                        break;
199                case PCAP:
200                case ERF:
201                case WAG:
202                        /*
203                         * Can have uridata of the following format
204                         * /path/to/socket (probably not PCAP)
205                         * /path/to/file
206                         * /path/to/file.gz (not PCAP)
207                         * /dev/device (use PCAPINT)
208                         * -
209                         */
210                        if (!strncmp(uridata,"-",1)) {
211                                (*libtrace)->sourcetype = STDIN;
212                        } else {
213                                if (stat(uridata,&buf) == -1) {
214                                        perror("stat");
215                                        return 0;
216                                }
217                                if (S_ISSOCK(buf.st_mode)) {
218                                        (*libtrace)->sourcetype = SOCKET;
219                                } else if (S_ISCHR(buf.st_mode)) {
220                                        (*libtrace)->sourcetype = DEVICE;
221                                } else {
222                                        (*libtrace)->sourcetype = TRACE;
223                                }
224                                (*libtrace)->conn_info.path = strdup(uridata);
225                        }
226                        break;
227                case DAG:
228                        /*
229                         * Can have uridata of the following format:
230                         * /dev/device
231                         */
232                        if (stat(uridata,&buf) == -1) {
233                                perror("stat");
234                                return 0;
235                        }
236                        if (S_ISCHR(buf.st_mode)) {
237                                (*libtrace)->sourcetype = DEVICE;
238                        } else {
239                                fprintf(stderr,"%s isn't a valid char device, exiting\n",uridata);
240                                exit(1);
241                        }
242                        (*libtrace)->conn_info.path = strdup(uridata);
243
244                        break;
245
246                case RTCLIENT:
247                        /*
248                         * Can have the uridata in the format
249                         * hostname
250                         * hostname:port
251                         */
252                        (*libtrace)->sourcetype = RT;
253                        if (strlen(uridata) == 0) {
254                                (*libtrace)->conn_info.rt.hostname = 
255                                        strdup("localhost");
256                                (*libtrace)->conn_info.rt.port = 
257                                        COLLECTOR_PORT;
258                                break;
259                        }
260                        if ((scan = strchr(uridata,':')) == NULL) {
261                                (*libtrace)->conn_info.rt.hostname = 
262                                        strdup(uridata);
263                                (*libtrace)->conn_info.rt.port = 
264                                        COLLECTOR_PORT;
265                        } else {
266                                (*libtrace)->conn_info.rt.hostname =
267                                        (char *)strndup(uridata,(scan - uridata));
268                                       
269                                (*libtrace)->conn_info.rt.port = 
270                                        atoi(++scan);                           
271                        }
272                        break;
273        }
274       
275
276        (*libtrace)->fifo = create_fifo(1048576);
277        //(*libtrace)->packet.buffer = 0;
278        //(*libtrace)->packet.size = 0;
279
280        return 1;
281}
282
283/** Create a trace file from a URI
284 *
285 * @returns opaque pointer to a libtrace_t
286 *
287 * Valid URI's are:
288 *  erf:/path/to/erf/file
289 *  erf:/path/to/erf/file.gz
290 *  erf:/path/to/rtclient/socket
291 *  erf:-                       (stdin)
292 *  pcapint:pcapinterface               (eg: pcapint:eth0)
293 *  pcap:/path/to/pcap/file
294 *  pcap:-
295 *  rtclient:hostname
296 *  rtclient:hostname:port
297 *  wag:-
298 *  wag:/path/to/wag/file
299 *  wag:/path/to/wag/file.gz
300 *  wag:/path/to/wag/socket
301 *  wagint:/dev/device
302 *
303 * URIs which have yet to be implemented are:
304 * dag:/dev/dagcard
305 * pcap:/path/to/pcap/socket
306 *
307 * If an error occured when attempting to open a trace, NULL is returned
308 * and an error is output to stdout.
309 */
310struct libtrace_t *trace_create(char *uri) {
311        struct libtrace_t *libtrace = malloc(sizeof(struct libtrace_t));
312        struct hostent *he;
313        struct sockaddr_in remote;
314        struct sockaddr_un unix_sock;
315        char errbuf[PCAP_ERRBUF_SIZE];
316
317        if(init_trace(&libtrace,uri) == 0) {
318                return 0;
319        }
320       
321        switch(libtrace->sourcetype) {
322                case RT:
323                        if ((he=gethostbyname(libtrace->conn_info.rt.hostname)) == NULL) { 
324                                perror("gethostbyname");
325                                return 0;
326                        } 
327                        if ((libtrace->input.fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
328                                perror("socket");
329                                return 0;
330                        }
331
332                        remote.sin_family = AF_INET;   
333                        remote.sin_port = htons(libtrace->conn_info.rt.port);
334                        remote.sin_addr = *((struct in_addr *)he->h_addr);
335                        bzero(&(remote.sin_zero), 8);
336
337                        if (connect(libtrace->input.fd, (struct sockaddr *)&remote,
338                                                sizeof(struct sockaddr)) == -1) {
339                                perror("connect (inet)");
340                                return 0;
341                        }
342                        break;
343                case TRACE:
344                        if (libtrace->format == PCAP) {
345                                if ((libtrace->input.pcap = pcap_open_offline(libtrace->conn_info.path, errbuf)) == NULL) {
346                                        fprintf(stderr,"%s\n",errbuf);
347                                        return 0;
348                                }
349                        } else {
350                                libtrace->input.file = gzopen(libtrace->conn_info.path, "r");
351                        }
352                        break;
353                case STDIN:
354                        if (libtrace->format == PCAP) {
355                                libtrace->input.pcap = pcap_open_offline("-",errbuf); 
356                        } else {
357                                libtrace->input.file = gzdopen(STDIN, "r");
358                        }
359                        break;
360                case SOCKET:
361                        /* Pcap doesn't work */
362                        if (libtrace->format != PCAP) {
363                                if ((libtrace->input.fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
364                                        perror("socket");
365                                        return 0;
366                                }
367                                unix_sock.sun_family = AF_UNIX;
368                                bzero(unix_sock.sun_path,108);
369                                snprintf(unix_sock.sun_path,108,"%s",libtrace->conn_info.path);
370
371                                if (connect(libtrace->input.fd, (struct sockaddr *)&unix_sock,
372                                                        sizeof(struct sockaddr)) == -1) {
373                                        perror("connect (unix)");
374                                        return 0;
375                                }
376                        }
377                        break;
378                case DEVICE:
379                case INTERFACE:
380                        switch (libtrace->format) {
381                                case PCAPINT:
382                                case PCAP:
383                                        libtrace->input.pcap = pcap_open_live(
384                                                libtrace->conn_info.path,
385                                                4096,
386                                                1,
387                                                0,
388                                                errbuf);
389                                        break;
390                                default:
391                                        fprintf(stderr,"Unknown format trace, hoping I can just read\n");
392                                case WAGINT:
393                                case WAG:
394                                        libtrace->input.fd = open(
395                                                libtrace->conn_info.path,
396                                                O_RDONLY);
397                                        break;
398#ifdef DAGDEVICE
399                                case DAG:
400                                        if((libtrace->input.fd = dag_open(libtrace->conn_info.path)) < 0) {
401                                                fprintf(stderr,"Cannot open DAG %s: %m", libtrace->conn_info.path,errno);
402                                                exit(0);
403                                        }
404                                        if((libtrace->buf = dag_mmap(libtrace->input.fd)) == MAP_FAILED) {
405                                                fprintf(stderr,"Cannot mmap DAG %s: %m", libtrace->conn_info.path,errno);
406                                                exit(0);
407                                        }
408                                        if(dag_start(libtrace->input.fd) < 0) {
409                                                fprintf(stderr,"Cannot start DAG %s: %m", libtrace->conn_info.path,errno);
410                                        }
411                                        break;
412#endif
413                                       
414                        }
415                        break;
416                default:
417                        fprintf(stderr,"Unsupported source type for libtrace, terminating (%i)\n",libtrace->sourcetype);
418                        exit(0);
419               
420        }
421        return libtrace;
422}
423
424/** Close a trace file, freeing up any resources it may have been using
425 *
426 */
427void trace_destroy(struct libtrace_t *libtrace) {
428        assert(libtrace);
429        if (libtrace->format == PCAP || libtrace->format == PCAPINT) {
430                pcap_close(libtrace->input.pcap);
431        } else if (libtrace->sourcetype == SOCKET || libtrace->sourcetype == RT) {
432                close(libtrace->input.fd);
433        } else {
434                gzclose(libtrace->input.file);
435        }       
436        // need to free things!
437        destroy_fifo(libtrace->fifo);
438        free(libtrace);
439}
440
441static int trace_read(struct libtrace_t *libtrace, void *buffer, size_t len) {
442        int numbytes;
443        static unsigned bottom = 0, top, diff, curr, scan;
444        static short lctr = 0;
445        struct dag_record_t *recptr = 0;
446        int rlen;
447        assert(libtrace);
448        assert(len >= 0);
449
450        if (buffer == 0)
451                buffer = malloc(len);
452
453        while(1) {
454                switch(libtrace->sourcetype) {
455                        case SOCKET:
456                        case RT:
457                                // read from the network
458                                if ((numbytes=recv(libtrace->input.fd, 
459                                                                buffer, 
460                                                                len, 
461                                                                MSG_NOSIGNAL)) == -1) {
462                                        if (errno == EINTR) {
463                                                // ignore EINTR in case
464                                                // a caller is using signals
465                                                continue;
466                                        }
467                                        perror("recv");
468                                        return -1;
469                                }
470                                break;
471                        case DEVICE:
472                                switch(libtrace->format) {
473                                        case DAG:
474                                                top = dag_offset(libtrace->input.fd,
475                                                                &bottom,
476                                                                0);
477                                                diff = top - bottom;
478                                                errno = 0;
479                                                curr = 0;
480                                               
481                                                recptr = (dag_record_t *) ((void *)libtrace->buf + (bottom + curr));
482                                               
483                                                buffer=libtrace->buf + (bottom + curr);
484
485                                                numbytes=diff;
486                                               
487                                               
488                                                break;
489                                        default:
490                                                if ((numbytes=read(libtrace->input.fd, 
491                                                                buffer, 
492                                                                len)) == -1) {
493                                                perror("read");
494                                                return -1;
495                                                }
496                                }
497                                break;
498                        default:
499                                if ((numbytes=gzread(libtrace->input.file,
500                                                                buffer,
501                                                                len)) == -1) {
502                                        perror("gzread");
503                                        return -1;
504                                }
505                }
506                break;
507        }
508        return numbytes;
509
510}
511
512/** Read one packet from the trace into buffer
513 *
514 * @param libtrace      the libtrace opaque pointer
515 * @param packet        the packet opaque pointer
516 * @returns false if it failed to read a packet
517 *
518 */
519#define RP_BUFSIZE 65536
520int trace_read_packet(struct libtrace_t *libtrace, struct libtrace_packet_t *packet) {
521        int numbytes;
522        int size;
523        char buf[RP_BUFSIZE];
524        struct pcap_pkthdr pcaphdr;
525        const u_char *pcappkt;
526        int read_required = 0;
527
528        void *buffer = 0;
529        if (!libtrace) {
530                fprintf(stderr,"Oi! You called trace_read_packet() with a NULL libtrace parameter!\n");
531        }
532        assert(libtrace);
533        assert(packet);
534
535        //bzero(buffer,len);
536     
537        /* Store the trace we are reading from into the packet opaque
538         * structure */
539        packet->trace = libtrace;
540
541        buffer = packet->buffer;
542        /* PCAP gives us it's own per-packet interface. Let's use it */
543        if (libtrace->format == PCAP || libtrace->format == PCAPINT) {
544                if ((pcappkt = pcap_next(libtrace->input.pcap, &pcaphdr)) == NULL) {
545                        return -1;
546                }
547                memcpy(buffer,&pcaphdr,sizeof(struct pcap_pkthdr));
548                memcpy(buffer + sizeof(struct pcap_pkthdr),pcappkt,pcaphdr.len);
549                numbytes = pcaphdr.len;
550       
551                packet->size = numbytes + sizeof(struct pcap_pkthdr);
552                return numbytes;
553        } 
554
555        /* If we're reading from an ERF input, it's an offline trace. We can make some assumptions */
556        if (libtrace->format == ERF) {
557                void *buffer2 = buffer;
558                // read in the trace header
559                if ((numbytes=gzread(libtrace->input.file,
560                                                buffer,
561                                                sizeof(dag_record_t))) == -1) {
562                        perror("gzread");
563                        return -1;
564                }
565                if (numbytes == 0) {
566                        return 0;
567                }
568                size = ntohs(((dag_record_t *)buffer)->rlen) - sizeof(dag_record_t);
569                assert(size < LIBTRACE_PACKET_BUFSIZE);
570                buffer2 = buffer +  sizeof(dag_record_t);
571
572                // read in the rest of the packet
573                if ((numbytes=gzread(libtrace->input.file,
574                                                buffer2,
575                                                size)) == -1) {
576                        perror("gzread");
577                        return -1;
578                }
579                packet->size = numbytes + sizeof(dag_record_t);
580                return sizeof(dag_record_t) + numbytes;
581        }
582       
583        do {
584                if (fifo_out_available(libtrace->fifo) == 0 || read_required) {
585                        if ((numbytes = trace_read(libtrace,buf,RP_BUFSIZE))<=0){
586                                return numbytes; 
587                        }
588                        fifo_write(libtrace->fifo,buf,numbytes);
589
590                        read_required = 0;
591                }
592
593                switch (libtrace->format) {
594                        case RTCLIENT:
595                                // only do this if we're reading from the RT interface
596                                if (fifo_out_read(libtrace->fifo, &packet->status, sizeof(int)) == 0) {
597                                        read_required = 1;
598                                        continue;
599                                }
600
601                                fifo_out_update(libtrace->fifo,sizeof(int));
602
603                                /* FALL THRU */
604                        case ERF:
605                        case DAG:
606                                // read in the erf header
607                                if ((numbytes = fifo_out_read(libtrace->fifo, buffer, sizeof(dag_record_t))) == 0) {
608                                        fifo_out_reset(libtrace->fifo);
609                                        read_required = 1;
610                                        continue;
611                                }
612
613                                size = ntohs(((dag_record_t *)buffer)->rlen);
614                                break;
615                        case WAG:
616                                if ((numbytes = fifo_out_read(libtrace->fifo,
617                                                                &size,
618                                                                sizeof(size))) 
619                                                                == 0) {
620                                        fifo_out_reset(libtrace->fifo);
621                                        read_required = 1;
622                                        continue;
623                                }
624                                size*=4;
625                                break;
626                        default:
627                                fprintf(stderr,"Unknown type in _read()\n");
628                                assert(0);
629                }
630
631                assert(size < LIBTRACE_PACKET_BUFSIZE);
632
633                // read in the full packet
634                if ((numbytes = fifo_out_read(libtrace->fifo, buffer, size)) == 0) {
635                        fifo_out_reset(libtrace->fifo);
636                        read_required = 1;
637                        continue;
638                }
639
640                // got in our whole packet, so...
641                fifo_out_update(libtrace->fifo,size);
642
643                if (libtrace->sourcetype == SOCKET || libtrace->sourcetype == RT) {
644                        fifo_ack_update(libtrace->fifo,size + sizeof(int));
645                } else {
646                        fifo_ack_update(libtrace->fifo,size);
647                }
648               
649                packet->size = numbytes;
650                return numbytes;
651
652        } while (1);
653}
654
655
656/** get a pointer to the link layer
657 * @param libtrace      a pointer to the trace object returned from gettrace
658 * @param buffer        a pointer to a filled in buffer
659 * @param buflen        a pointer to the size of the buffer
660 *
661 * @returns a pointer to the link layer, or NULL if there is no link layer
662 * you should call trace_get_link_type() to find out what type of link layer this is
663 */
664void *trace_get_link(struct libtrace_packet_t *packet) {
665        void *ethptr = 0;
666       
667        struct wag_event_t *event = (struct wag_event_t *)packet->buffer;
668        struct wag_data_event_t *data_event;
669       
670       
671        switch(packet->trace->format) {
672                case ERF:
673                case DAG:
674                case RTCLIENT:
675                        if (trace_get_link_type(packet)==TRACE_TYPE_ETH) 
676                                ethptr = ((uint8_t *)packet->buffer + 
677                                                dag_record_size + 2);
678                        else
679                                ethptr = ((uint8_t *)packet->buffer + 
680                                                dag_record_size + 2);
681                        break;
682                case PCAPINT:
683                case PCAP:
684                        ethptr = (struct ether_header *)(packet->buffer + sizeof(struct pcap_pkthdr));
685                        break;
686                case WAGINT:
687                case WAG:
688                        switch (event->type) {
689                                case 0x0:
690                                        data_event = (void*)&(event->payload);
691                                        return data_event->data;
692                                default:
693                                        fprintf(stderr,"Unknown WAG Event (0x%08x)\n",event->type);
694                                        return NULL;
695                        }
696                       
697                default:
698                        fprintf(stderr,"Dunno this trace format\n");
699                        assert(0);
700        }
701        return ethptr;
702}
703
704/** get a pointer to the IP header (if any)
705 * @param libtrace      a pointer to the trace object returned from gettrace
706 * @param buffer        a pointer to a filled in buffer
707 * @param buflen        a pointer to the size of the buffer
708 *
709 * @returns a pointer to the IP header, or NULL if there is not an IP packet
710 */
711struct libtrace_ip *trace_get_ip(struct libtrace_packet_t *packet) {
712        struct libtrace_ip *ipptr = 0;
713
714        switch(trace_get_link_type(packet)) {
715                case TRACE_TYPE_80211:
716                        { 
717                               
718                                struct ieee_802_11_header *wifi = trace_get_link(packet);       
719
720                                // Data packet?
721                                if (wifi->type != 2) {
722                                        ipptr = NULL;
723                                }
724                                else {
725                                        struct ieee_802_11_payload *eth = (void*)wifi->data;
726                                        if (eth->type != 0x0008) {
727                                                ipptr=NULL;
728                                        } else {
729                                                ipptr=(void*)eth->data;
730                                        }
731                                }
732                        }
733                        break;
734                case TRACE_TYPE_ETH:
735                        {
736                                struct ether_header *eth = 
737                                        trace_get_link(packet);
738                                if (ntohs(eth->ether_type)!=0x0800) {
739                                        ipptr = NULL;
740                                }
741                                else {
742                                        ipptr = ((void *)eth) + 14;
743                                }
744                                break;
745                        }
746                case TRACE_TYPE_ATM:
747                        {
748                                struct atm_rec *atm = 
749                                        trace_get_link(packet);
750                                // TODO: Find out what ATM does, and return
751                                //       NULL for non IP data
752                                //       Presumably it uses the normal stuff
753                                ipptr =  (void*)&atm->pload;
754                                break;
755                        }
756                default:
757                        fprintf(stderr,"Don't understand link layer type %i in trace_get_ip()\n",
758                                trace_get_link_type(packet));
759                        ipptr=NULL;
760                        break;
761        }
762
763        return ipptr;
764}
765
766
767/** get a pointer to the TCP header (if any)
768 * @param libtrace      a pointer to the trace object returned from gettrace
769 * @param buffer        a pointer to a filled in buffer
770 * @param buflen        a pointer to the size of the buffer
771 *
772 * @returns a pointer to the TCP header, or NULL if there is not a TCP packet
773 */
774struct libtrace_tcp *trace_get_tcp(struct libtrace_packet_t *packet) {
775        struct libtrace_tcp *tcpptr = 0;
776        struct libtrace_ip *ipptr = 0;
777
778        if(!(ipptr = trace_get_ip(packet))) {
779                return 0;
780        }
781        if (ipptr->ip_p == 6) {
782                tcpptr = (struct libtrace_tcp *)((ptrdiff_t)ipptr + (ipptr->ip_hl * 4));
783        }
784        return tcpptr;
785}
786
787/** get a pointer to the UDP header (if any)
788 * @param libtrace      a pointer to the trace object returned from gettrace
789 * @param buffer        a pointer to a filled in buffer
790 * @param buflen        a pointer to the size of the buffer
791 *
792 * @returns a pointer to the UDP header, or NULL if this is not a UDP packet
793 */
794struct libtrace_udp *trace_get_udp(struct libtrace_packet_t *packet) {
795        struct libtrace_udp *udpptr = 0;
796        struct libtrace_ip *ipptr = 0;
797       
798        if(!(ipptr = trace_get_ip(packet))) {
799                return 0;
800        }
801        if (ipptr->ip_p == 17) {
802                udpptr = (struct libtrace_udp *)((ptrdiff_t)ipptr + (ipptr->ip_hl * 4));
803        }
804        return udpptr;
805}
806
807/** get a pointer to the ICMP header (if any)
808 * @param libtrace      a pointer to the trace object returned from gettrace
809 * @param buffer        a pointer to a filled in buffer
810 * @param buflen        a pointer to the size of the buffer
811 *
812 * @returns a pointer to the ICMP header, or NULL if this is not a ICMP packet
813 */
814struct libtrace_icmp *trace_get_icmp(struct libtrace_packet_t *packet) {
815        struct libtrace_icmp *icmpptr = 0;
816        struct libtrace_ip *ipptr = 0;
817       
818        if(!(ipptr = trace_get_ip(packet))) {
819                return 0;
820        }
821        if (ipptr->ip_p == 1) {
822                icmpptr = (struct libtrace_icmp *)((ptrdiff_t)ipptr + (ipptr->ip_hl * 4));
823        }
824        return icmpptr;
825}
826
827/** Get the current time in DAG time format
828 * @param libtrace the libtrace opaque pointer
829 * @param buffer a pointer to a filled in buffer
830 * @param buflen the length of the buffer
831 * @returns a 64 bit timestamp in DAG ERF format (upper 32 bits are the seconds
832 * past 1970-01-01, the lower 32bits are partial seconds)
833 * @author Daniel Lawson
834 */ 
835uint64_t trace_get_erf_timestamp(struct libtrace_packet_t *packet) {
836        uint64_t timestamp = 0;
837        dag_record_t *erfptr = 0;
838        struct pcap_pkthdr *pcapptr = 0;
839        struct wag_event_t *wagptr = 0;
840        switch (packet->trace->format) {
841                case DAG:
842                case ERF:
843                case RTCLIENT:
844                        erfptr = (dag_record_t *)packet->buffer;
845                        timestamp = erfptr->ts;
846                        break;
847                case PCAPINT:
848                case PCAP:
849                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
850                        timestamp = ((((uint64_t)pcapptr->ts.tv_sec) << 32) + \
851                                (pcapptr->ts.tv_usec*UINT_MAX/1000000));
852                        break;
853                case WAGINT:
854                case WAG:
855                        wagptr = (struct wag_event_t *)packet->buffer;
856                        timestamp = wagptr->timestamp_lo;
857                        timestamp |= (uint64_t)wagptr->timestamp_hi<<32;
858                        timestamp = ((timestamp%44000000)*(UINT_MAX/44000000))
859                                  | ((timestamp/44000000)<<32);
860                        break;
861                default:
862                        fprintf(stderr,"Unknown format in trace_get_erf_timestamp\n");
863                        timestamp = 0;
864        }
865        return timestamp;
866}
867
868/** Get the current time in struct timeval
869 * @param libtrace the libtrace opaque pointer
870 * @param buffer a pointer to a filled in buffer
871 * @param buflen the length of the buffer
872 * @returns time that this packet was seen in a struct timeval
873 * @author Daniel Lawson
874 * @author Perry Lorier
875 */ 
876struct timeval trace_get_timeval(struct libtrace_packet_t *packet) {
877        struct timeval tv;
878        struct pcap_pkthdr *pcapptr = 0;
879        uint64_t ts;
880        //uint32_t seconds;
881        switch (packet->trace->format) {
882                case PCAPINT:
883                case PCAP:
884                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
885                        tv = pcapptr->ts;
886                        break;
887                case WAGINT:
888                case WAG:
889                case DAG:
890                case ERF:
891                case RTCLIENT:
892                default:
893                        // FIXME: This isn't portable to big-endian machines
894                        ts = trace_get_erf_timestamp(packet);
895                        tv.tv_sec = ts >> 32;           
896                        ts = (1000000 * (ts & 0xffffffffULL));
897                        ts += (ts & 0x80000000ULL) << 1;
898                        tv.tv_usec = ts >> 32;
899                        if (tv.tv_usec >= 1000000) {
900                                tv.tv_usec -= 1000000;
901                                tv.tv_sec += 1;
902                        }
903                        break;
904        }
905        return tv;
906}
907
908/** Get the current time in floating point seconds
909 * @param libtrace the libtrace opaque pointer
910 * @param buffer a pointer to a filled in buffer
911 * @param buflen the length of the buffer
912 * @returns time that this packet was seen in 64bit floating point seconds
913 * @author Perry Lorier
914 */ 
915double trace_get_seconds(struct libtrace_packet_t *packet) {
916        uint64_t ts;
917        ts = trace_get_erf_timestamp(packet);
918        return (ts>>32) + ((ts & UINT_MAX)*1.0 / UINT_MAX);
919}
920
921/** Get the size of the packet in the trace
922 * @param packet the packet opaque pointer
923 * @returns the size of the packet in the trace
924 * @author Perry Lorier
925 * @note Due to this being a header capture, or anonymisation, this may not
926 * be the same size as the original packet.  See trace_get_wire_length() for the
927 * original size of the packet.
928 * @note This can (and often is) different for different packets in a trace!
929 * @par
930 *  This is sometimes called the "snaplen".
931 */ 
932int trace_get_capture_length(struct libtrace_packet_t *packet) {
933        dag_record_t *erfptr = 0;
934        struct pcap_pkthdr *pcapptr = 0;
935        struct wag_event_t *wag_event;
936        switch (packet->trace->format) {
937                case DAG:
938                case ERF:
939                case RTCLIENT:
940                        erfptr = (dag_record_t *)packet->buffer;
941                        return ntohs(erfptr->rlen);
942                case PCAPINT:
943                case PCAP:
944                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
945                        //return ntohs(pcapptr->caplen);
946                        return pcapptr->caplen;
947                case WAGINT:
948                case WAG:
949                        wag_event = (struct wag_event_t *)packet->buffer;
950                        switch(wag_event->type) {
951                                case 0:
952                                        return wag_event->length*4-(
953                                                sizeof(struct wag_event_t)+
954                                                sizeof(struct wag_data_event_t)
955                                                );
956                                default:
957                                        assert(0);
958                        }
959                default:
960                        assert(0);
961        }
962        return -1;
963}
964       
965/** Get the size of the packet as it was seen on the wire.
966 * @param libtrace the libtrace opaque pointer
967 * @param buffer a pointer to a filled in buffer
968 * @param buflen the length of the buffer
969 * @returns the size of the packet as it was on the wire.
970 * @author Perry Lorier
971 * @author Daniel Lawson
972 * @note Due to the trace being a header capture, or anonymisation this may
973 * not be the same as the Capture Len.
974 */ 
975int trace_get_wire_length(struct libtrace_packet_t *packet){
976        dag_record_t *erfptr = 0;
977        struct pcap_pkthdr *pcapptr = 0;
978        struct wag_event_t *wag_event = 0;
979        switch (packet->trace->format) {
980                case DAG:
981                case ERF:
982                case RTCLIENT:
983                        erfptr = (dag_record_t *)packet->buffer;
984                        return ntohs(erfptr->wlen);
985                        break;
986                case PCAPINT:
987                case PCAP:
988                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
989                        return ntohs(pcapptr->len);
990                        break;
991                case WAGINT:
992                case WAG:
993                        wag_event = (struct wag_event_t *)packet->buffer;
994                        switch(wag_event->type) {
995                                case 0:
996                                        return ((struct wag_data_event_t *)(&wag_event->payload))->frame_length;
997                                default:
998                                        assert(0);
999                        }
1000        }
1001        return -1;
1002
1003}
1004
1005/** Get the type of the link layer
1006 * @param libtrace the libtrace opaque pointer
1007 * @param buffer a pointer to a filled in buffer
1008 * @param buflen the length of the buffer
1009 * @returns libtrace_linktype_t
1010 * @author Perry Lorier
1011 * @author Daniel Lawson
1012 */
1013libtrace_linktype_t trace_get_link_type(struct libtrace_packet_t *packet ) {
1014        dag_record_t *erfptr = 0;
1015        struct pcap_pkthdr *pcapptr = 0;
1016        int linktype = 0;
1017        switch (packet->trace->format) {
1018                case DAG:
1019                case ERF:
1020                case RTCLIENT:
1021                        erfptr = (dag_record_t *)packet->buffer;
1022                        switch (erfptr->type) {
1023                                case TYPE_ETH: return TRACE_TYPE_ETH;
1024                                case TYPE_ATM: return TRACE_TYPE_ATM;
1025                                default: assert(0);
1026                        }
1027                        return erfptr->type;
1028                       
1029                        break;
1030                case PCAPINT:
1031                case PCAP:
1032                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
1033                        linktype = pcap_datalink(packet->trace->input.pcap);
1034                        switch (linktype) {
1035                                case 1:
1036                                        return TRACE_TYPE_ETH; 
1037                                case 11:
1038                                        return TRACE_TYPE_ATM;
1039                                case DLT_IEEE802_11:
1040                                        return TRACE_TYPE_80211;
1041                        }
1042                        break;
1043                case WAGINT:
1044                case WAG:
1045                        return TRACE_TYPE_80211;
1046        }
1047        return -1;
1048}
1049
1050/** Get the source MAC addres
1051 * @param libtrace the libtrace opaque pointer
1052 * @param buffer a pointer to a filled in buffer
1053 * @param buflen the length of the buffer
1054 * @returns a pointer to the source mac, (or NULL if there is no source MAC)
1055 * @author Perry Lorier
1056 */
1057uint8_t *trace_get_source_mac(struct libtrace_packet_t *packet) {
1058        void *link = trace_get_link(packet);
1059        struct ieee_802_11_header *wifi = link;
1060        struct ether_header *ethptr = link;
1061        if (!link)
1062                return NULL;
1063        switch (trace_get_link_type(packet)) {
1064                case TRACE_TYPE_80211:
1065                        return (uint8_t*)&wifi->mac2;
1066                case TRACE_TYPE_ETH:
1067                        return (uint8_t*)&ethptr->ether_shost;
1068                default:
1069                        fprintf(stderr,"Not implemented\n");
1070                        assert(0);
1071        }
1072}
1073
1074/** Get the destination MAC addres
1075 * @param libtrace the libtrace opaque pointer
1076 * @param buffer a pointer to a filled in buffer
1077 * @param buflen the length of the buffer
1078 * @returns a pointer to the destination mac, (or NULL if there is no
1079 * destination MAC)
1080 * @author Perry Lorier
1081 */
1082uint8_t *trace_get_destination_mac(struct libtrace_packet_t *packet) {
1083        void *link = trace_get_link(packet);
1084        struct ieee_802_11_header *wifi = link;
1085        struct ether_header *ethptr = link;
1086        if (!link)
1087                return NULL;
1088        switch (trace_get_link_type(packet)) {
1089                case TRACE_TYPE_80211:
1090                        return (uint8_t*)&wifi->mac1;
1091                case TRACE_TYPE_ETH:
1092                        return (uint8_t*)&ethptr->ether_dhost;
1093                default:
1094                        fprintf(stderr,"Not implemented\n");
1095                        assert(0);
1096        }
1097}
1098
1099
1100/** process a libtrace event
1101 * @param trace the libtrace opaque pointer
1102 * @param packet the libtrace_packet opaque pointer
1103 * @param fd a pointer to a file descriptor to listen on
1104 * @param seconds a pointer the time in seconds since to the next event
1105 * @returns
1106 *  TRACE_EVENT_IOWAIT  Waiting on I/O on <fd>
1107 *  TRACE_EVENT_SLEEP   Next event in <seconds>
1108 *  TRACE_EVENT_PACKET  Packet arrived in <buffer> with size <size>
1109 * FIXME currently keeps a copy of the packet inside the trace pointer,
1110 * which in turn is stored inside the new packet object...
1111 * @author Perry Lorier
1112 */
1113struct libtrace_eventobj_t trace_event(struct libtrace_t *trace, 
1114                struct libtrace_packet_t *packet) {
1115        struct libtrace_eventobj_t event;
1116
1117        if (!trace) {
1118                fprintf(stderr,"You called trace_event() with a NULL trace object!\n");
1119        }
1120        assert(trace);
1121        assert(packet);
1122
1123        /* Store the trace we are reading from into the packet opaque
1124         * structure */
1125        packet->trace = trace;
1126
1127        /* Is there a packet ready? */
1128        switch (trace->sourcetype) {
1129                case INTERFACE:
1130                        {
1131                                int data;
1132                                event.fd = pcap_fileno(trace->input.pcap);
1133                                if(ioctl(event.fd,FIONREAD,&data)==-1){
1134                                        perror("ioctl(FIONREAD)");
1135                                }
1136                                if (data>0) {
1137                                        trace_read_packet(trace,packet);
1138                                        event.type = TRACE_EVENT_PACKET;
1139                                        return event;
1140                                }
1141                                event.type = TRACE_EVENT_IOWAIT;
1142                                return event;
1143                        }
1144                case SOCKET:
1145                case DEVICE:
1146                case RT:
1147                        {
1148                                int data;
1149                                event.fd = trace->input.fd;
1150                                if(ioctl(event.fd,FIONREAD,&data)==-1){
1151                                        perror("ioctl(FIONREAD)");
1152                                }
1153                                if (data>0) {
1154                                        trace_read_packet(trace,packet);
1155                                        event.type = TRACE_EVENT_PACKET;
1156                                        return event;
1157                                }
1158                                event.type = TRACE_EVENT_IOWAIT;
1159                                return event;
1160                        }
1161                case STDIN:
1162                case TRACE:
1163                        {
1164                                double ts;
1165                                /* "Prime" the pump */
1166                                if (!trace->packet.buffer) {
1167                                        trace->packet.buffer = malloc(4096);
1168                                        trace->packet.size=
1169                                                trace_read_packet(trace,packet);
1170                                }
1171                                ts=trace_get_seconds(packet);
1172                                if (trace->last_ts!=0) {
1173                                        event.seconds = ts - trace->last_ts;
1174                                        if (event.seconds>time(NULL)-trace->start_ts) {
1175                                                event.type = TRACE_EVENT_SLEEP;
1176                                                return event;
1177                                        }
1178                                       
1179                                }
1180                                else {
1181                                        trace->start_ts = time(NULL);
1182                                        trace->last_ts = ts;
1183                                }
1184
1185                                packet->size = trace->packet.size;
1186                                memcpy(packet->buffer,trace->packet.buffer,trace->packet.size);
1187
1188                                free(trace->packet.buffer);
1189                                trace->packet.buffer = 0;
1190                                event.type = TRACE_EVENT_PACKET;
1191                                return event;
1192                        }
1193                default:
1194                        assert(0);
1195        }
1196        assert(0);
1197}
1198
1199/** setup a BPF filter
1200 * @param filterstring a char * containing the bpf filter string
1201 * @returns opaque pointer pointer to a libtrace_filter_t object
1202 * @author Daniel Lawson
1203 */
1204struct libtrace_filter_t *trace_bpf_setfilter(const char *filterstring) {
1205        struct libtrace_filter_t *filter = malloc(sizeof(struct libtrace_filter_t));
1206        filter->filterstring = strdup(filterstring);
1207        filter->filter = 0;
1208        return filter;
1209}
1210
1211/** apply a BPF filter
1212 * @param libtrace the libtrace opaque pointer
1213 * @param filter the filter opaque pointer
1214 * @param buffer a pointer to a filled buffer
1215 * @param buflen the length of the buffer
1216 * @returns 0 if the filter fails, 1 if it succeeds
1217 * @author Daniel Lawson
1218 */
1219int trace_bpf_filter(struct libtrace_filter_t *filter,
1220                        struct libtrace_packet_t *packet) {
1221       
1222        void *linkptr = 0;
1223        int clen = 0;
1224        assert(filter);
1225        assert(packet);
1226        linkptr = trace_get_link(packet);       
1227        assert(linkptr);
1228        clen = trace_get_capture_length(packet);
1229       
1230
1231        if (filter->filterstring && ! filter->filter) {
1232                pcap_t *pcap;
1233                struct bpf_program bpfprog;
1234
1235                switch (trace_get_link_type(packet)) {
1236                        case TRACE_TYPE_ETH:
1237                                pcap = pcap_open_dead(DLT_EN10MB, 1500);
1238                                break;
1239                        default:
1240                                printf("only works for ETH at the moment\n");
1241                                assert(0);
1242                }               
1243
1244                // build filter
1245                if (pcap_compile( pcap, &bpfprog, filter->filterstring, 1, 0)) {
1246                        printf("bpf compilation error: %s\n", 
1247                                pcap_geterr(pcap));
1248                        assert(0);
1249                }
1250                pcap_close(pcap);
1251                filter->filter = bpfprog.bf_insns;     
1252        }
1253
1254        assert(filter->filter);
1255        return bpf_filter(filter->filter, linkptr, clen, clen);
1256       
1257}
1258
1259/** Get the direction flag, if it has one
1260 * @param libtrace the libtrace opaque pointer
1261 * @param buffer a point to a fille in buffer
1262 * @param buflen the length of the buffer
1263 * @returns a signed value containing the direction flag, or -1 if this is not supported
1264 * @author Daniel Lawson
1265 */
1266int8_t trace_get_direction(struct libtrace_packet_t *packet) {
1267       
1268        int8_t direction;
1269        dag_record_t *erfptr = 0;
1270        assert(packet);
1271
1272        switch(packet->trace->format) {
1273                case DAG:
1274                case ERF:
1275                case RTCLIENT:
1276                        erfptr = (dag_record_t *)packet->buffer;
1277                        direction = erfptr->flags.iface;
1278                        break;
1279                default:
1280                        direction = -1;
1281        }
1282       
1283        return direction;
1284       
1285       
1286}
1287
1288
1289/** Attempt to deduce the 'server' port
1290 * @param protocol the IP protocol (eg, 6 or 17 for TCP or UDP)
1291 * @param source the TCP or UDP source port
1292 * @param dest the TCP or UDP destination port
1293 * @returns a hint as to which port is the server port
1294 * @author Daniel Lawson
1295 */
1296#define ROOT_SERVER(x) ((x) < 512)
1297#define ROOT_CLIENT(x) ((512 <= (x)) && ((x) < 1024))
1298#define NONROOT_SERVER(x) ((x) >= 5000)
1299#define NONROOT_CLIENT(x) ((1024 <= (x)) && ((x) < 5000))
1300#define DYNAMIC(x) ((49152 < (x)) && ((x) < 65535))
1301#define SERVER(x) ROOT_SERVER(x) || NONROOT_SERVER(x)
1302#define CLIENT(x) ROOT_CLIENT(x) || NONROOT_CLIENT(x)
1303
1304int8_t trace_get_server_port(uint8_t protocol, uint16_t source, uint16_t dest) {
1305        /*
1306         * * If the ports are equal, return DEST
1307         * * Check for well-known ports in the given protocol
1308         * * Root server ports: 0 - 511
1309         * * Root client ports: 512 - 1023
1310         * * non-root client ports: 1024 - 4999
1311         * * non-root server ports: 5000+
1312         * * Check for static ranges: 1024 - 49151
1313         * * Check for dynamic ranges: 49152 - 65535
1314         * * flip a coin.
1315         */
1316
1317        uint16_t server, client;
1318
1319        /* equal */
1320        if (source == client)
1321                return USE_DEST;
1322
1323        /* root server port, 0 - 511 */
1324        if (ROOT_SERVER(source) && ROOT_SERVER(dest)) {
1325                if (source < dest)
1326                        return USE_SOURCE;
1327                return USE_DEST;
1328        }
1329
1330        if (ROOT_SERVER(source) && !ROOT_SERVER(dest))
1331                return USE_SOURCE;
1332        if (!ROOT_SERVER(source) && ROOT_SERVER(dest))
1333                return USE_DEST;
1334
1335        /* non-root server */
1336        if (NONROOT_SERVER(source) && NONROOT_SERVER(dest)) {
1337                if (source < dest)
1338                        return USE_SOURCE;
1339                return USE_DEST;
1340        }
1341        if (NONROOT_SERVER(source) && !NONROOT_SERVER(dest))
1342                return USE_SOURCE;
1343        if (!NONROOT_SERVER(source) && NONROOT_SERVER(dest))
1344                return USE_DEST;
1345
1346        /* root client */
1347        if (ROOT_CLIENT(source) && ROOT_CLIENT(dest)) {
1348                if (source < dest)
1349                        return USE_SOURCE;
1350                return USE_DEST;
1351        }
1352        if (ROOT_CLIENT(source) && !ROOT_CLIENT(dest)) {
1353                /* prefer root-client over nonroot-client */
1354                if (NONROOT_CLIENT(dest))
1355                        return USE_SOURCE;
1356                return USE_DEST;
1357        }
1358        if (!ROOT_CLIENT(source) && ROOT_CLIENT(dest)) {
1359                /* prefer root-client over nonroot-client */
1360                if (NONROOT_CLIENT(source))
1361                        return USE_DEST;
1362                return USE_SOURCE;
1363        }
1364       
1365        /* nonroot client */
1366        if (NONROOT_CLIENT(source) && NONROOT_CLIENT(dest)) {
1367                if (source < dest) 
1368                        return USE_SOURCE;
1369                return USE_DEST;
1370        }
1371        if (NONROOT_CLIENT(source) && !NONROOT_CLIENT(dest))
1372                return USE_DEST;
1373        if (!NONROOT_CLIENT(source) && NONROOT_CLIENT(dest))
1374                return USE_SOURCE;
1375
1376        /* dynamic range */
1377        if (DYNAMIC(source) && DYNAMIC(dest))
1378                if (source < dest)
1379                        return USE_SOURCE;
1380                return USE_DEST;
1381        if (DYNAMIC(source) && !DYNAMIC(dest))
1382                return USE_DEST;
1383        if (!DYNAMIC(source) && DYNAMIC(dest))
1384                return USE_SOURCE;
1385        /*
1386        if (SERVER(source) && CLIENT(dest))
1387                return USE_SOURCE;
1388       
1389        if (SERVER(dest) && CLIENT(source))
1390                return USE_DEST;
1391        if (ROOT_SERVER(source) && !ROOT_SERVER(dest))
1392                return USE_SOURCE;
1393        if (ROOT_SERVER(dest) && !ROOT_SERVER(source))
1394                return USE_DEST;
1395        */
1396        // failing that test...
1397        if (source < dest) {
1398                return USE_SOURCE;
1399        } 
1400        return USE_DEST;
1401       
1402}
Note: See TracBrowser for help on using the repository browser.