source: lib/trace.c @ a79ddbe

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

added license information

  • Property mode set to 100644
File size: 31.9 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 *  - dag:/dev/dagcard                  (not implementd)
237 *  - pcap:pcapinterface                (eg: pcap:eth0)
238 *  - pcap:/path/to/pcap/file
239 *  - pcap:/path/to/pcap/file.gz
240 *  - pcap:/path/to/pcap/socket         (not implemented)
241 *  - pcap:-
242 *  - rtclient:hostname
243 *  - rtclient:hostname:port
244 *  - wag:/path/to/wag/file
245 *  - wag:/path/to/wag/file.gz
246 *  - wag:/path/to/wag/socket
247 *  - wag:/dev/device
248 *
249 *  If an error occured why attempting to open the trace file, NULL is returned
250 *  and an error is output to stdout.
251 */
252struct libtrace_t *create_trace(char *uri) {
253        struct libtrace_t *libtrace = malloc(sizeof(struct libtrace_t));
254        struct hostent *he;
255        struct sockaddr_in remote;
256        struct sockaddr_un unix_sock;
257        char errbuf[PCAP_ERRBUF_SIZE];
258
259        if(init_trace(&libtrace,uri) == 0) {
260                return 0;
261        }
262       
263        switch(libtrace->sourcetype) {
264                case RT:
265                        if ((he=gethostbyname(libtrace->conn_info.rt.hostname)) == NULL) { 
266                                perror("gethostbyname");
267                                return 0;
268                        } 
269                        if ((libtrace->input.fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
270                                perror("socket");
271                                return 0;
272                        }
273
274                        remote.sin_family = AF_INET;   
275                        remote.sin_port = htons(libtrace->conn_info.rt.port);
276                        remote.sin_addr = *((struct in_addr *)he->h_addr);
277                        bzero(&(remote.sin_zero), 8);
278
279                        if (connect(libtrace->input.fd, (struct sockaddr *)&remote,
280                                                sizeof(struct sockaddr)) == -1) {
281                                perror("connect (inet)");
282                                return 0;
283                        }
284                        break;
285                case TRACE:
286                        if (libtrace->format == PCAP) {
287                                libtrace->input.pcap = pcap_open_offline(libtrace->conn_info.path, errbuf); 
288                        } else {
289                                libtrace->input.file = gzopen(libtrace->conn_info.path, "r");
290                        }
291                        break;
292                case STDIN:
293                        if (libtrace->format == PCAP) {
294                                libtrace->input.pcap = pcap_open_offline("-",errbuf); 
295                        } else {
296                                libtrace->input.file = gzdopen(STDIN, "r");
297                        }
298                        break;
299                case SOCKET:
300                        /* Pcap doesn't work */
301                        if (libtrace->format != PCAP) {
302                                if ((libtrace->input.fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
303                                        perror("socket");
304                                        return 0;
305                                }
306                                unix_sock.sun_family = AF_UNIX;
307                                bzero(unix_sock.sun_path,108);
308                                snprintf(unix_sock.sun_path,108,"%s",libtrace->conn_info.path);
309
310                                if (connect(libtrace->input.fd, (struct sockaddr *)&unix_sock,
311                                                        sizeof(struct sockaddr)) == -1) {
312                                        perror("connect (unix)");
313                                        return 0;
314                                }
315                        }
316                        break;
317                case DEVICE:
318                case INTERFACE:
319                        switch (libtrace->format) {
320                                case PCAPINT:
321                                case PCAP:
322                                        libtrace->input.pcap = pcap_open_live(
323                                                libtrace->conn_info.path,
324                                                4096,
325                                                1,
326                                                0,
327                                                errbuf);
328                                        break;
329                                default:
330                                        fprintf(stderr,"Unknown format trace, hoping I can just read\n");
331                                case WAGINT:
332                                case WAG:
333                                        libtrace->input.fd = open(
334                                                libtrace->conn_info.path,
335                                                O_RDONLY);
336                                        break;
337                        }
338                        break;
339                default:
340                        fprintf(stderr,"Unsupported source type for libtrace, terminating (%i)\n",libtrace->sourcetype);
341                        exit(0);
342               
343        }
344        return libtrace;
345}
346
347/** Close a trace file, freeing up any resources it may have been using
348 *
349 */
350void destroy_trace(struct libtrace_t *libtrace) {
351        assert(libtrace);
352        if (libtrace->format == PCAP || libtrace->format == PCAPINT) {
353                pcap_close(libtrace->input.pcap);
354        } else if (libtrace->sourcetype == SOCKET || libtrace->sourcetype == RT) {
355                close(libtrace->input.fd);
356        } else {
357                gzclose(libtrace->input.file);
358        }       
359        // need to free things!
360        destroy_fifo(libtrace->fifo);
361        free(libtrace);
362}
363
364static int libtrace_read(struct libtrace_t *libtrace, void *buffer, size_t len) {
365        int numbytes;
366        assert(libtrace);
367        assert(len >= 0);
368
369        if (buffer == 0)
370                buffer = malloc(len);
371
372        switch(libtrace->sourcetype) {
373                case SOCKET:
374                case RT:
375                        // read from the network
376                        if ((numbytes=recv(libtrace->input.fd, 
377                                                        buffer, 
378                                                        len, 
379                                                        0)) == -1) {
380                                perror("recv");
381                                return -1;
382                        }
383                        break;
384                case DEVICE:
385                        if ((numbytes=read(libtrace->input.fd, 
386                                                        buffer, 
387                                                        len)) == -1) {
388                                perror("read");
389                                return -1;
390                        }
391                        break;
392                default:
393                        if ((numbytes=gzread(libtrace->input.file,
394                                                        buffer,
395                                                        len)) == -1) {
396                                perror("gzread");
397                                return -1;
398                        }
399        }
400        return numbytes;
401
402}
403
404/** Read one packet from the trace into buffer
405 *
406 * @param libtrace      the trace to read from
407 * @param buffer        the buffer to read into
408 * @param len           the length of the buffer
409 * @returns number of bytes copied.
410 *
411 * @note the buffer must be at least as large as the largest packet (plus
412 * link layer, and trace packet metadata overhead)
413 */
414int libtrace_read_packet(struct libtrace_t *libtrace, void *buffer, size_t len, int *status) {
415        int numbytes;
416        int size;
417        char buf[4096];
418        struct pcap_pkthdr pcaphdr;
419        const u_char *pcappkt;
420        int read_required = 0;
421        if (!libtrace) {
422                fprintf(stderr,"Oi! You called libtrace_read_packet() with a NULL libtrace parameter!\n");
423        }
424        assert(libtrace);
425        assert(buffer);
426        assert(status);
427        assert(len > 104); // we know we see packets this big anyway. Don't be silly.
428
429        bzero(buffer,len);
430       
431        if (libtrace->format == PCAP || libtrace->format == PCAPINT) {
432                if ((pcappkt = pcap_next(libtrace->input.pcap, &pcaphdr)) == NULL) {
433                        return -1;
434                }
435                memcpy(buffer,&pcaphdr,sizeof(struct pcap_pkthdr));
436                memcpy(buffer + sizeof(struct pcap_pkthdr),pcappkt,pcaphdr.len);
437                numbytes = pcaphdr.len;
438
439                return numbytes;
440        } 
441
442        do {
443                if (fifo_out_available(libtrace->fifo) == 0 || read_required) {
444                        if ((numbytes = libtrace_read(libtrace,buf,4096))<=0){
445                                return numbytes; 
446                        }
447                        fifo_write(libtrace->fifo,buf,numbytes);
448
449                        read_required = 0;
450                }
451
452                switch (libtrace->format) {
453                        case RTCLIENT:
454                                // only do this if we're reading from the RT interface
455                                if (fifo_out_read(libtrace->fifo, status, sizeof(int)) == 0) {
456                                        read_required = 1;
457                                        continue;
458                                }
459
460                                fifo_out_update(libtrace->fifo,sizeof(int));
461
462                                /* FALL THRU */
463                        case ERF:
464                        case DAG:
465                                // read in the erf header
466                                if ((numbytes = fifo_out_read(libtrace->fifo, buffer, sizeof(dag_record_t))) == 0) {
467                                        fifo_out_reset(libtrace->fifo);
468                                        read_required = 1;
469                                        continue;
470                                }
471
472                                size = ntohs(((dag_record_t *)buffer)->rlen);
473                                break;
474                        case WAG:
475                                if ((numbytes = fifo_out_read(libtrace->fifo,
476                                                                &size,
477                                                                sizeof(size))) 
478                                                                == 0) {
479                                        fifo_out_reset(libtrace->fifo);
480                                        read_required = 1;
481                                        continue;
482                                }
483                                size*=4;
484                                break;
485                        default:
486                                fprintf(stderr,"Unknown type in _read()\n");
487                                assert(0);
488                }
489
490                assert(len > size);
491
492                // read in the full packet
493                if ((numbytes = fifo_out_read(libtrace->fifo, buffer, size)) == 0) {
494                        fifo_out_reset(libtrace->fifo);
495                        read_required = 1;
496                        continue;
497                }
498
499                // got in our whole packet, so...
500                fifo_out_update(libtrace->fifo,size);
501
502                if (libtrace->sourcetype == SOCKET || libtrace->sourcetype == RT) {
503                        fifo_ack_update(libtrace->fifo,size + sizeof(int));
504                } else {
505                        fifo_ack_update(libtrace->fifo,size);
506                }
507               
508                return numbytes;
509
510        } while (1);
511}
512
513
514/** get a pointer to the link layer
515 * @param libtrace      a pointer to the trace object returned from gettrace
516 * @param buffer        a pointer to a filled in buffer
517 * @param buflen        a pointer to the size of the buffer
518 *
519 * @returns a pointer to the link layer, or NULL if there is no link layer
520 * you should call get_link_type() to find out what type of link layer this is
521 */
522void *get_link(struct libtrace_t *libtrace, void *buffer, int buflen) {
523        void *ethptr = 0;
524        struct wag_event_t *event = buffer;
525        struct wag_data_event_t *data_event;
526       
527        switch(libtrace->format) {
528                case ERF:
529                case DAG:
530                case RTCLIENT:
531                        // DAG people are insane, deal with ethernet having
532                        // some extra padding and crap
533                        if (get_link_type(libtrace,buffer,buflen)==TRACE_TYPE_ETH) 
534                                ethptr = ((uint8_t *)buffer + 16 + 2);
535                        else
536                                ethptr = ((uint8_t *)buffer + 16 + 2);
537                        break;
538                case PCAPINT:
539                case PCAP:
540                        ethptr = (struct ether_header *)(buffer + sizeof(struct pcap_pkthdr));
541                        break;
542                case WAGINT:
543                case WAG:
544                        switch (event->type) {
545                                case 0x0:
546                                        data_event = (void*)&(event->payload);
547                                        return data_event->data;
548                                default:
549                                        fprintf(stderr,"Unknown WAG Event (0x%08x)\n",event->type);
550                                        return NULL;
551                        }
552                       
553                default:
554                        fprintf(stderr,"Dunno this trace format\n");
555                        assert(0);
556        }
557        return ethptr;
558}
559
560/** get a pointer to the IP header (if any)
561 * @param libtrace      a pointer to the trace object returned from gettrace
562 * @param buffer        a pointer to a filled in buffer
563 * @param buflen        a pointer to the size of the buffer
564 *
565 * @returns a pointer to the IP header, or NULL if there is not an IP packet
566 */
567struct libtrace_ip *get_ip(struct libtrace_t *libtrace, void *buffer, int buflen) {
568        struct libtrace_ip *ipptr = 0;
569
570        switch(get_link_type(libtrace,buffer,buflen)) {
571                case TRACE_TYPE_80211:
572                        { 
573                               
574                                struct ieee_802_11_header *wifi = get_link(libtrace, buffer, buflen);   
575
576                                // Data packet?
577                                if (wifi->type != 2) {
578                                        ipptr = NULL;
579                                }
580                                else {
581                                        struct ieee_802_11_payload *eth = (void*)wifi->data;
582                                        if (eth->type != 0x0008) {
583                                                ipptr=NULL;
584                                        } else {
585                                                ipptr=(void*)eth->data;
586                                        }
587                                }
588                        }
589                        break;
590                case TRACE_TYPE_ETH:
591                        {
592                                struct ether_header *eth = get_link(libtrace,
593                                                buffer, buflen);
594                                if (ntohs(eth->ether_type)!=0x0800) {
595                                        ipptr = NULL;
596                                }
597                                else {
598                                        ipptr = ((void *)eth) + 14;
599                                }
600                                break;
601                        }
602                case TRACE_TYPE_ATM:
603                        {
604                                struct atm_rec *atm = get_link(libtrace,
605                                                buffer, buflen);
606                                // TODO: Find out what ATM does, and return
607                                //       NULL for non IP data
608                                //       Presumably it uses the normal stuff
609                                ipptr =  (void*)&atm->pload;
610                                break;
611                        }
612                default:
613                        fprintf(stderr,"Don't understand link layer type %i in get_ip()\n",
614                                get_link_type(libtrace,buffer,buflen));
615                        ipptr=NULL;
616                        break;
617        }
618
619        return ipptr;
620}
621
622
623/** get a pointer to the TCP header (if any)
624 * @param libtrace      a pointer to the trace object returned from gettrace
625 * @param buffer        a pointer to a filled in buffer
626 * @param buflen        a pointer to the size of the buffer
627 *
628 * @returns a pointer to the TCP header, or NULL if there is not a TCP packet
629 */
630struct libtrace_tcp *get_tcp(struct libtrace_t *libtrace, void *buffer, int buflen) {
631        struct libtrace_tcp *tcpptr = 0;
632        struct libtrace_ip *ipptr = 0;
633
634        if(!(ipptr = get_ip(libtrace,buffer,buflen))) {
635                return 0;
636        }
637        if (ipptr->ip_p == 6) {
638                tcpptr = (struct libtrace_tcp *)((int)ipptr + (ipptr->ip_hl * 4));
639        }
640        return tcpptr;
641}
642
643/** get a pointer to the UDP header (if any)
644 * @param libtrace      a pointer to the trace object returned from gettrace
645 * @param buffer        a pointer to a filled in buffer
646 * @param buflen        a pointer to the size of the buffer
647 *
648 * @returns a pointer to the UDP header, or NULL if this is not a UDP packet
649 */
650struct libtrace_udp *get_udp(struct libtrace_t *libtrace, void *buffer, int buflen) {
651        struct libtrace_udp *udpptr = 0;
652        struct libtrace_ip *ipptr = 0;
653       
654        if(!(ipptr = get_ip(libtrace,buffer,buflen))) {
655                return 0;
656        }
657        if (ipptr->ip_p == 17) {
658                udpptr = (struct libtrace_udp *)((int)ipptr + (ipptr->ip_hl * 4));
659        }
660        return udpptr;
661}
662
663/** get a pointer to the ICMP header (if any)
664 * @param libtrace      a pointer to the trace object returned from gettrace
665 * @param buffer        a pointer to a filled in buffer
666 * @param buflen        a pointer to the size of the buffer
667 *
668 * @returns a pointer to the ICMP header, or NULL if this is not a ICMP packet
669 */
670struct libtrace_icmp *get_icmp(struct libtrace_t *libtrace, void *buffer, int buflen) {
671        struct libtrace_icmp *icmpptr = 0;
672        struct libtrace_ip *ipptr = 0;
673       
674        if(!(ipptr = get_ip(libtrace,buffer,buflen))) {
675                return 0;
676        }
677        if (ipptr->ip_p == 1) {
678                icmpptr = (struct libtrace_icmp *)((int)ipptr + (ipptr->ip_hl * 4));
679        }
680        return icmpptr;
681}
682
683/** Get the current time in DAG time format
684 * @param libtrace the libtrace opaque pointer
685 * @param buffer a pointer to a filled in buffer
686 * @param buflen the length of the buffer
687 * @returns a 64 bit timestamp in DAG ERF format (upper 32 bits are the seconds
688 * past 1970-01-01, the lower 32bits are partial seconds)
689 * @author Daniel Lawson
690 */ 
691uint64_t get_erf_timestamp(struct libtrace_t *libtrace, void *buffer, int buflen) {
692        uint64_t timestamp = 0;
693        dag_record_t *erfptr = 0;
694        struct pcap_pkthdr *pcapptr = 0;
695        struct wag_event_t *wagptr = 0;
696        switch (libtrace->format) {
697                case DAG:
698                case ERF:
699                case RTCLIENT:
700                        erfptr = (dag_record_t *)buffer;
701                        timestamp = erfptr->ts;
702                        break;
703                case PCAPINT:
704                case PCAP:
705                        pcapptr = (struct pcap_pkthdr *)buffer;
706                        timestamp = ((((uint64_t)pcapptr->ts.tv_sec) << 32) + \
707                                (pcapptr->ts.tv_usec*UINT_MAX/1000000));
708                        break;
709                case WAGINT:
710                case WAG:
711                        wagptr = buffer;
712                        timestamp = wagptr->timestamp_lo;
713                        timestamp |= (uint64_t)wagptr->timestamp_hi<<32;
714                        timestamp = ((timestamp%44000000)*(UINT_MAX/44000000))
715                                  | ((timestamp/44000000)<<32);
716                        break;
717                default:
718                        fprintf(stderr,"Unknown format in get_erf_timestamp\n");
719                        timestamp = 0;
720        }
721        return timestamp;
722}
723
724/** Get the current time in struct timeval
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 time that this packet was seen in a struct timeval
729 * @author Daniel Lawson
730 * @author Perry Lorier
731 */ 
732struct timeval get_timeval(struct libtrace_t *libtrace, void *buffer, int buflen) {
733        struct timeval tv;
734        struct pcap_pkthdr *pcapptr = 0;
735        uint64_t ts;
736        //uint32_t seconds;
737        switch (libtrace->format) {
738                case PCAPINT:
739                case PCAP:
740                        pcapptr = (struct pcap_pkthdr *)buffer;
741                        tv = pcapptr->ts;
742                        break;
743                case WAGINT:
744                case WAG:
745                case DAG:
746                case ERF:
747                case RTCLIENT:
748                default:
749                        // FIXME: This isn't portable to big-endian machines
750                        ts = get_erf_timestamp(libtrace,buffer,buflen);
751                        tv.tv_sec = ts >> 32;           
752                        ts = (1000000 * (ts & 0xffffffffULL));
753                        ts += (ts & 0x80000000ULL) << 1;
754                        tv.tv_usec = ts >> 32;
755                        if (tv.tv_usec >= 1000000) {
756                                tv.tv_usec -= 1000000;
757                                tv.tv_sec += 1;
758                        }
759                        break;
760        }
761        return tv;
762}
763
764/** Get the current time in floating point seconds
765 * @param libtrace the libtrace opaque pointer
766 * @param buffer a pointer to a filled in buffer
767 * @param buflen the length of the buffer
768 * @returns time that this packet was seen in 64bit floating point seconds
769 * @author Perry Lorier
770 */ 
771double get_seconds(struct libtrace_t *libtrace, void *buffer, int buflen) {
772        uint64_t ts;
773        ts = get_erf_timestamp(libtrace,buffer,buflen);
774        return (ts>>32) + ((ts & UINT_MAX)*1.0 / UINT_MAX);
775}
776
777/** Get the size of the packet in the trace
778 * @param libtrace the libtrace opaque pointer
779 * @param buffer a pointer to a filled in buffer
780 * @param buflen the length of the buffer
781 * @returns the size of the packet in the trace
782 * @author Perry Lorier
783 * @note Due to this being a header capture, or anonymisation, this may not
784 * be the same size as the original packet.  See get_wire_length() for the
785 * original size of the packet.
786 * @note This can (and often is) different for different packets in a trace!
787 * @par
788 *  This is sometimes called the "snaplen".
789 */ 
790int get_capture_length(struct libtrace_t *libtrace, void *buffer, int buflen) {
791        dag_record_t *erfptr = 0;
792        struct pcap_pkthdr *pcapptr = 0;
793        struct wag_event_t *wag_event;
794        switch (libtrace->format) {
795                case DAG:
796                case ERF:
797                case RTCLIENT:
798                        erfptr = (dag_record_t *)buffer;
799                        return ntohs(erfptr->rlen);
800                case PCAPINT:
801                case PCAP:
802                        pcapptr = (struct pcap_pkthdr *)buffer;
803                        return ntohs(pcapptr->caplen);
804                case WAGINT:
805                case WAG:
806                        wag_event = buffer;
807                        switch(wag_event->type) {
808                                case 0:
809                                        return wag_event->length*4-(
810                                                sizeof(struct wag_event_t)+
811                                                sizeof(struct wag_data_event_t)
812                                                );
813                                default:
814                                        assert(0);
815                        }
816                default:
817                        assert(0);
818        }
819        return -1;
820}
821       
822/** Get the size of the packet as it was seen on the wire.
823 * @param libtrace the libtrace opaque pointer
824 * @param buffer a pointer to a filled in buffer
825 * @param buflen the length of the buffer
826 * @returns the size of the packet as it was on the wire.
827 * @author Perry Lorier
828 * @author Daniel Lawson
829 * @note Due to the trace being a header capture, or anonymisation this may
830 * not be the same as the Capture Len.
831 */ 
832int get_wire_length(struct libtrace_t *libtrace, void *buffer, int buflen){
833        dag_record_t *erfptr = 0;
834        struct pcap_pkthdr *pcapptr = 0;
835        struct wag_event_t *wag_event = 0;
836        switch (libtrace->format) {
837                case DAG:
838                case ERF:
839                case RTCLIENT:
840                        erfptr = (dag_record_t *)buffer;
841                        return ntohs(erfptr->wlen);
842                        break;
843                case PCAPINT:
844                case PCAP:
845                        pcapptr = (struct pcap_pkthdr *)buffer;
846                        return ntohs(pcapptr->len);
847                        break;
848                case WAGINT:
849                case WAG:
850                        wag_event = buffer;
851                        switch(wag_event->type) {
852                                case 0:
853                                        return ((struct wag_data_event_t *)(&wag_event->payload))->frame_length;
854                                default:
855                                        assert(0);
856                        }
857        }
858        return -1;
859
860}
861
862/** Get the type of the link layer
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 libtrace_linktype_t
867 * @author Perry Lorier
868 * @author Daniel Lawson
869 */
870libtrace_linktype_t get_link_type(
871                struct libtrace_t *libtrace, 
872                void *buffer, 
873                int buflen) {
874        dag_record_t *erfptr = 0;
875        struct pcap_pkthdr *pcapptr = 0;
876        int linktype = 0;
877        switch (libtrace->format) {
878                case DAG:
879                case ERF:
880                case RTCLIENT:
881                        erfptr = (dag_record_t *)buffer;
882                        switch (erfptr->type) {
883                                case TYPE_ETH: return TRACE_TYPE_ETH;
884                                case TYPE_ATM: return TRACE_TYPE_ATM;
885                                default: assert(0);
886                        }
887                        return erfptr->type;
888                       
889                        break;
890                case PCAPINT:
891                case PCAP:
892                        pcapptr = (struct pcap_pkthdr *)buffer;
893                        linktype = pcap_datalink(libtrace->input.pcap);
894                        switch (linktype) {
895                                case 1:
896                                        return TRACE_TYPE_ETH; 
897                                case 11:
898                                        return TRACE_TYPE_ATM;
899                                case DLT_IEEE802_11:
900                                        return TRACE_TYPE_80211;
901                        }
902                        break;
903                case WAGINT:
904                case WAG:
905                        return TRACE_TYPE_80211;
906        }
907        return -1;
908}
909
910/** Get the source MAC addres
911 * @param libtrace the libtrace opaque pointer
912 * @param buffer a pointer to a filled in buffer
913 * @param buflen the length of the buffer
914 * @returns a pointer to the source mac, (or NULL if there is no source MAC)
915 * @author Perry Lorier
916 */
917uint8_t *get_source_mac(struct libtrace_t *libtrace,
918                void *buffer,
919                int buflen) {
920        void *link = get_link(libtrace,buffer,buflen);
921        struct ieee_802_11_header *wifi = link;
922        struct ether_header *ethptr = link;
923        if (!link)
924                return NULL;
925        switch (get_link_type(libtrace,buffer,buflen)) {
926                case TRACE_TYPE_80211:
927                        return (uint8_t*)&wifi->mac2;
928                case TRACE_TYPE_ETH:
929                        return (uint8_t*)&ethptr->ether_shost;
930                default:
931                        fprintf(stderr,"Not implemented\n");
932                        assert(0);
933        }
934}
935
936/** Get the destination MAC addres
937 * @param libtrace the libtrace opaque pointer
938 * @param buffer a pointer to a filled in buffer
939 * @param buflen the length of the buffer
940 * @returns a pointer to the destination mac, (or NULL if there is no
941 * destination MAC)
942 * @author Perry Lorier
943 */
944uint8_t *get_destination_mac(struct libtrace_t *libtrace,
945                void *buffer,
946                int buflen) {
947        void *link = get_link(libtrace,buffer,buflen);
948        struct ieee_802_11_header *wifi = link;
949        struct ether_header *ethptr = link;
950        if (!link)
951                return NULL;
952        switch (get_link_type(libtrace,buffer,buflen)) {
953                case TRACE_TYPE_80211:
954                        return (uint8_t*)&wifi->mac1;
955                case TRACE_TYPE_ETH:
956                        return (uint8_t*)&ethptr->ether_dhost;
957                default:
958                        fprintf(stderr,"Not implemented\n");
959                        assert(0);
960        }
961}
962
963
964/** process a libtrace event
965 * @returns
966 *  TRACE_EVENT_IOWAIT  Waiting on I/O on <fd>
967 *  TRACE_EVENT_SLEEP   Next event in <seconds>
968 *  TRACE_EVENT_PACKET  Packet arrived in <buffer> with size <size>
969 */
970libtrace_event_t libtrace_event(struct libtrace_t *trace,
971                        int *fd,double *seconds,
972                        void *buffer, int *size)
973{
974        *seconds = 0;
975        *fd = 0;
976        /* Is there a packet ready? */
977        switch (trace->sourcetype) {
978                case INTERFACE:
979                        {
980                                int data;
981                                *fd = pcap_fileno(trace->input.pcap);
982                                if(ioctl(*fd,FIONREAD,&data)==-1){
983                                        perror("ioctl(FIONREAD)");
984                                }
985                                if (data>0) {
986                                        return TRACE_EVENT_PACKET;
987                                }
988                                return TRACE_EVENT_IOWAIT;
989                        }
990                case SOCKET:
991                case DEVICE:
992                case RT:
993                        {
994                                int data;
995                                if(ioctl(trace->input.fd,FIONREAD,&data)==-1){
996                                        perror("ioctl(FIONREAD)");
997                                }
998                                if (data>0) {
999                                        return TRACE_EVENT_PACKET;
1000                                }
1001                                *fd = trace->input.fd;
1002                                return TRACE_EVENT_IOWAIT;
1003                        }
1004                case STDIN:
1005                case TRACE:
1006                        {
1007                                int status;
1008                                double ts;
1009                                /* "Prime" the pump */
1010                                if (!trace->packet.buffer) {
1011                                        trace->packet.buffer = malloc(4096);
1012                                        trace->packet.size=libtrace_read_packet(trace,
1013                                                        trace->packet.buffer,
1014                                                        4096,
1015                                                        &status);
1016                                }
1017                                ts=get_seconds(trace,
1018                                        trace->packet.buffer,
1019                                        trace->packet.size);
1020                                if (trace->last_ts!=0) {
1021                                        *seconds = ts - trace->last_ts;
1022                                        if (*seconds>time(NULL)-trace->start_ts)
1023                                                return TRACE_EVENT_SLEEP;
1024                                }
1025                                else {
1026                                        trace->start_ts = time(NULL);
1027                                        trace->last_ts = ts;
1028                                }
1029
1030                                *size = trace->packet.size;
1031                                memcpy(buffer,trace->packet.buffer,*size);
1032
1033                                free(trace->packet.buffer);
1034                                trace->packet.buffer = 0;
1035                                return TRACE_EVENT_PACKET;
1036                        }
1037                default:
1038                        assert(0);
1039        }
1040        /* Shouldn't get here */
1041        assert(0);
1042}
1043
1044/** setup a BPF filter
1045 * @param filterstring a char * containing the bpf filter string
1046 * @returns opaque pointer pointer to a libtrace_filter_t object
1047 * @author Daniel Lawson
1048 */
1049struct libtrace_filter_t *libtrace_bpf_setfilter(const char *filterstring) {
1050        struct libtrace_filter_t *filter = malloc(sizeof(struct libtrace_filter_t));
1051        filter->filterstring = strdup(filterstring);
1052        return filter;
1053}
1054
1055/** apply a BPF filter
1056 * @param libtrace the libtrace opaque pointer
1057 * @param filter the filter opaque pointer
1058 * @param buffer a pointer to a filled buffer
1059 * @param buflen the length of the buffer
1060 * @returns 0 if the filter fails, 1 if it succeeds
1061 * @author Daniel Lawson
1062 */
1063int libtrace_bpf_filter(struct libtrace_t *trace, 
1064                        struct libtrace_filter_t *filter,
1065                        void *buffer, 
1066                        int buflen) {
1067       
1068        int linktype = get_link_type(trace,buffer,buflen);
1069        void *linkptr = get_link(trace,buffer,buflen); 
1070        int clen = get_capture_length(trace,buffer,buflen);
1071        assert(trace);
1072        assert(filter);
1073        assert(buffer);
1074       
1075
1076        if (filter->filterstring && ! filter->filter) {
1077                pcap_t *pcap;
1078                struct bpf_program bpfprog;
1079
1080                switch (linktype) {
1081                        case TYPE_ETH:
1082                                pcap = pcap_open_dead(DLT_EN10MB, 1500);
1083                                break;
1084                        default:
1085                                printf("only works for ETH at the moment\n");
1086                                assert(0);
1087                }               
1088
1089                // build filter
1090                if (pcap_compile( pcap, &bpfprog, filter->filterstring, 1, 0)) {
1091                        printf("bpf compilation error: %s\n", 
1092                                pcap_geterr(pcap));
1093                        assert(0);
1094                }
1095                pcap_close(pcap);
1096                filter->filter = bpfprog.bf_insns;     
1097        }
1098
1099        return bpf_filter(filter->filter, linkptr, clen, clen);
1100}
1101
1102
Note: See TracBrowser for help on using the repository browser.