source: lib/trace.c @ e5d3718

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

checking for, and including, limits.h

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