source: lib/trace.c @ 2c060e3

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

Initial revision

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