source: lib/trace.c @ dfef05d

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

fixes for AMD64

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