source: lib/trace.c @ 64ef531

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 64ef531 was 64ef531, checked in by Perry Lorier <perry@…>, 16 years ago

Add fixme for when pcap open fails (don't have the docs handy to do it now)

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