source: lib/trace.c @ a9d9fd6

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

poink

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