source: lib/trace.c @ c5a22ec

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

changed bpf routines to use an opaque pointer to a filter datastructure

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