source: lib/trace.c @ be54c88

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

removed some bad debugging stuff i left in. assert(0) doesn't play nice in random places

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