source: lib/trace.c @ fe43699

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

help functions in erf, wag modules.

  • Property mode set to 100644
File size: 35.3 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2004 The University of Waikato, Hamilton, New Zealand.
5 * Authors: Daniel Lawson
6 *          Perry Lorier
7 *         
8 * All rights reserved.
9 *
10 * This code has been developed by the University of Waikato WAND
11 * research group. For further information please see http://www.wand.net.nz/
12 *
13 * libtrace is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * libtrace is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with libtrace; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 *
27 * $Id$
28 *
29 */
30
31
32/** @file
33 *
34 * @brief Trace file processing library
35 *
36 * @author Daniel Lawson
37 * @author Perry Lorier
38 *
39 * @internal
40 */
41#define _GNU_SOURCE
42#include "common.h"
43#include "config.h"
44#include <assert.h>
45#include <errno.h>
46#include <fcntl.h>
47#include <netdb.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <sys/stat.h>
52#include <sys/types.h>
53
54#ifdef HAVE_LIMITS_H
55#  include <limits.h>
56#endif
57
58#ifdef HAVE_SYS_LIMITS_H
59#  include <sys/limits.h>
60#endif
61
62#include <sys/socket.h>
63#include <sys/un.h>
64#include <sys/mman.h>
65#include <unistd.h>
66
67#ifdef HAVE_NET_IF_ARP_H
68#  include <net/if_arp.h>
69#endif
70
71#ifdef HAVE_NET_IF_H
72#  include <net/if.h>
73#endif
74
75#ifdef HAVE_NETINET_IN_H
76#  include <netinet/in.h>
77#endif
78
79#ifdef HAVE_NET_ETHERNET_H
80#  include <net/ethernet.h>
81#endif
82
83#ifdef HAVE_NETINET_IF_ETHER_H
84#  include <netinet/if_ether.h>
85#endif
86
87#include <time.h>
88#include <sys/ioctl.h>
89
90#ifdef HAVE_INTTYPES_H
91#  include <inttypes.h>
92#else
93#  error "Can't find inttypes.h - this needs to be fixed"
94#endif
95
96#ifdef HAVE_STDDEF_H
97#  include <stddef.h>
98#else
99# error "Can't find stddef.h - do you define ptrdiff_t elsewhere?"
100#endif
101
102#include "libtrace.h"
103#include "fifo.h"
104#include "format.h"
105#include "parse_cmd.h"
106
107#if HAVE_PCAP_BPF_H
108#  include <pcap-bpf.h>
109#else
110#  ifdef HAVE_NET_BPF_H
111#    include <net/bpf.h>
112#  endif
113#endif
114
115#if HAVE_PCAP_H
116#  include <pcap.h>
117#  ifdef HAVE_PCAP_INT_H
118#    include <pcap-int.h>
119#  endif
120#endif
121
122#ifdef HAVE_ZLIB_H
123#  include <zlib.h>
124#endif
125
126
127#include "wag.h"
128
129#ifdef HAVE_DAG_API
130#  include "dagnew.h"
131#  include "dagapi.h"
132#else
133#  include "dagformat.h"
134#endif
135
136#include "format.h"
137//#include "format/format_list.h"
138#include <err.h>
139
140#define MAXOPTS 1024
141
142//typedef enum {SOCKET, TRACE, STDIN, DEVICE, INTERFACE, RT } source_t;
143
144//typedef enum {ERF, PCAP, PCAPINT, DAG, RTCLIENT, WAG, WAGINT } format_e_t;
145
146//typedef enum {RTSERVER, GZERF } output_t;
147#if HAVE_BPF
148/** A type encapsulating a bpf filter
149 * This type covers the compiled bpf filter, as well as the original filter
150 * string
151 *
152 */
153struct libtrace_filter_t {
154        struct bpf_insn *filter;
155        char * filterstring;
156};
157#endif
158
159struct format_t **format_list = 0;
160int format_size = 0;
161int nformats = 0;
162
163void register_format(struct format_t *f) {
164        fprintf(stderr,"Registering input format %s\n",f->name);
165        if (format_list == 0) {
166                format_size = 10;
167                format_list = malloc(sizeof(struct format_t *) * format_size);
168        } else if (format_size == nformats) {
169                format_size = format_size + 10;
170                format_list = realloc(format_list,
171                                sizeof(struct format_t *) * format_size);
172        }
173        format_list[nformats] = f;
174        nformats++;
175}
176
177/** Prints help information for libtrace
178 *
179 * Function prints out some basic help information regarding libtrace,
180 * and then prints out the help() function registered with each input module
181 */
182void trace_help() {
183        int i = 0;
184        printf("libtrace %s\n",PACKAGE_VERSION);
185        for (i = 0; i < nformats; i++) {
186                if (format_list[i]->help) {
187                        format_list[i]->help();
188                }
189        }
190}
191
192
193#define RP_BUFSIZE 65536
194
195#define URI_PROTO_LINE 16
196static int init_trace(struct libtrace_t **libtrace, char *uri) {
197        char *scan = calloc(sizeof(char),URI_PROTO_LINE);
198        char *uridata = 0;                 
199        int i = 0;
200        struct stat buf;
201       
202        // parse the URI to determine what sort of event we are dealing with
203       
204        // want snippet before the : to get the uri base type.
205
206        if((uridata = strchr(uri,':')) == NULL) {
207                // badly formed URI - needs a :
208                return 0;
209        }
210
211        if ((*uridata - *uri) > URI_PROTO_LINE) {
212                // badly formed URI - uri type is too long
213                return 0;
214        }
215        strncpy(scan,uri, (uridata - uri));
216
217        (*libtrace)->tdelta = 0.0;
218
219
220        (*libtrace)->format = 0;
221        for (i = 0; i < nformats; i++) {
222                if (strlen(scan) == strlen(format_list[i]->name) &&
223                                !strncasecmp(scan,
224                                        format_list[i]->name,
225                                        strlen(scan))) {
226                                (*libtrace)->format=format_list[i];
227                                break;
228                                }
229        }
230        if ((*libtrace)->format == 0) {
231                fprintf(stderr,
232                        "libtrace has no support for this format (%s)\n",scan);
233                return 0;
234        }
235
236        // push uridata past the delimiter
237        uridata++;
238        (*libtrace)->conn_info.path = strdup(uridata);
239
240        // libtrace->format now contains the type of uri
241        // libtrace->uridata contains the appropriate data for this
242       
243        if ((*libtrace)->format->init_input) {
244                (*libtrace)->format->init_input( (*libtrace));
245        } else {
246                fprintf(stderr,
247                        "No init function for format %s\n",scan);
248                return 0;
249        }
250       
251
252        (*libtrace)->fifo = create_fifo(1048576);
253        assert( (*libtrace)->fifo);
254        //(*libtrace)->packet.buffer = 0;
255        //(*libtrace)->packet.size = 0;
256
257        return 1;
258}
259
260/** Initialises the data contained within the libtrace_out_t structure, based on the provided uri.
261 *
262 * @param libtrace      the libtrace_out_t structure to initialise
263 * @param uri           the uri defining the output type and destination
264 * @returns             1 if initialised successfully, 0 otherwise
265 *
266 * @author Shane Alcock
267 * */
268static int init_output(struct libtrace_out_t **libtrace, char *uri) {
269        char *scan = calloc(sizeof(char),URI_PROTO_LINE);
270        char *uridata = 0;
271        int i;
272       
273        // parse the URI to determine what sort of event we are dealing with
274
275        // want snippet before the : to get the uri base type.
276       
277        if((uridata = strchr(uri,':')) == NULL) {
278                // badly formed URI - needs a :
279                return 0;
280        }
281
282        if ((*uridata - *uri) > URI_PROTO_LINE) {
283                // badly formed URI - uri type is too long
284                return 0;
285        }
286       
287        strncpy(scan,uri, (uridata - uri));
288       
289        (*libtrace)->format = 0;
290        for (i = 0; i < nformats; i++) {
291                if (strlen(scan) == strlen(format_list[i]->name) &&
292                                !strncasecmp(scan,
293                                        format_list[i]->name,
294                                        strlen(scan))) {
295                                (*libtrace)->format=format_list[i];
296                                break;
297                                }
298        }
299        if ((*libtrace)->format == 0) {
300                fprintf(stderr,
301                        "libtrace has no support for this format (%s)\n",scan);
302                return 0;
303        }
304       
305        // push uridata past the delimiter
306        uridata++;
307        (*libtrace)->uridata = strdup(uridata);
308       
309       
310        // libtrace->format now contains the type of uri
311        // libtrace->uridata contains the appropriate data for this
312
313        if ((*libtrace)->format->init_output) {
314                (*libtrace)->format->init_output( (*libtrace));
315        } else {
316                fprintf(stderr,
317                        "No init_output function for format %s\n",scan);
318                return 0;
319        }
320
321       
322        (*libtrace)->fifo = create_fifo(1048576);
323        assert( (*libtrace)->fifo);
324        return 1;
325} 
326
327/** Create a trace file from a URI
328 *
329 * @returns opaque pointer to a libtrace_t
330 *
331 * Valid URI's are:
332 *  erf:/path/to/erf/file
333 *  erf:/path/to/erf/file.gz
334 *  erf:/path/to/rtclient/socket
335 *  erf:-                       (stdin)
336 *  pcapint:pcapinterface               (eg: pcapint:eth0)
337 *  pcap:/path/to/pcap/file
338 *  pcap:-
339 *  rtclient:hostname
340 *  rtclient:hostname:port
341 *  wag:-
342 *  wag:/path/to/wag/file
343 *  wag:/path/to/wag/file.gz
344 *  wag:/path/to/wag/socket
345 *  wagint:/dev/device
346 *
347 * URIs which have yet to be implemented are:
348 * dag:/dev/dagcard
349 * pcap:/path/to/pcap/socket
350 *
351 * If an error occured when attempting to open a trace, NULL is returned
352 * and an error is output to stdout.
353 */
354struct libtrace_t *trace_create(char *uri) {
355        struct libtrace_t *libtrace = malloc(sizeof(struct libtrace_t));
356
357        if(init_trace(&libtrace,uri) == 0) {
358                return 0;
359        }
360       
361        return libtrace;
362}
363
364/** Creates a libtrace_out_t structure and the socket / file through which output will be directed.
365 *
366 * @param uri   the uri string describing the output format and the destination
367 * @returns the newly created libtrace_out_t structure
368 *
369 * @author Shane Alcock
370 * */
371struct libtrace_out_t *trace_output_create(char *uri) {
372        struct libtrace_out_t *libtrace = malloc(sizeof(struct libtrace_out_t));
373       
374        if (init_output(&libtrace, uri) == 0)
375                return 0;
376
377        return libtrace;
378}
379
380int trace_output_config(struct libtrace_out_t *libtrace, char *options) {
381        char *opt_string = 0;
382        char *opt_argv[MAXOPTS];
383        int opt_argc = 0;
384       
385        assert(libtrace);
386       
387        if (!options) {
388                printf("No options specified\n");
389                return 0;
390        }
391       
392        asprintf(&opt_string, "%s %s", libtrace->format->name, options);
393        parse_cmd(opt_string, &opt_argc, opt_argv, MAXOPTS);
394       
395        if (libtrace->format->config_output)
396                return libtrace->format->config_output(libtrace, opt_argc, opt_argv);
397
398}
399
400/** Close a trace file, freeing up any resources it may have been using
401 *
402 */
403void trace_destroy(struct libtrace_t *libtrace) {
404        assert(libtrace);
405        libtrace->format->fin_input(libtrace);
406        // need to free things!
407        destroy_fifo(libtrace->fifo);
408        free(libtrace);
409}
410
411/** Close an output trace file, freeing up any resources it may have been using
412 *
413 * @param libtrace      the output trace file to be destroyed
414 *
415 * @author Shane Alcock
416 * */
417void trace_output_destroy(struct libtrace_out_t *libtrace) {
418        assert(libtrace);
419        libtrace->format->fin_output(libtrace);
420        destroy_fifo(libtrace->fifo);
421        free(libtrace);
422}
423
424/** Read one packet from the trace into buffer
425 *
426 * @param libtrace      the libtrace opaque pointer
427 * @param packet        the packet opaque pointer
428 * @returns false if it failed to read a packet
429 *
430 */
431int trace_read_packet(struct libtrace_t *libtrace, struct libtrace_packet_t *packet) {
432
433        if (!libtrace) {
434                fprintf(stderr,"Oi! You called trace_read_packet() with a NULL libtrace parameter!\n");
435        }
436        assert(libtrace);
437        assert(packet);
438     
439        /* Store the trace we are reading from into the packet opaque
440         * structure */
441        packet->trace = libtrace;
442
443        if (libtrace->format->read_packet) {
444                return libtrace->format->read_packet(libtrace,packet);
445        }
446}
447
448/** Writes a packet to the specified output
449 *
450 * @param libtrace      describes the output format, destination, etc.
451 * @param packet        the packet to be written out
452 * @returns the number of bytes written, -1 if write failed
453 *
454 * @author Shane Alcock
455 * */
456int trace_write_packet(struct libtrace_out_t *libtrace, struct libtrace_packet_t *packet) {
457        assert(libtrace);
458        assert(packet); 
459
460        if (libtrace->format->write_packet) {
461                return libtrace->format->write_packet(libtrace, packet);
462        }
463
464}
465
466/** get a pointer to the link layer
467 * @param packet        a pointer to a libtrace_packet structure
468 *
469 * @returns a pointer to the link layer, or NULL if there is no link layer
470 * you should call trace_get_link_type() to find out what type of link layer this is
471 */
472void *trace_get_link(const struct libtrace_packet_t *packet) {
473        const void *ethptr = 0;
474       
475        if (packet->trace->format->get_link) {
476                ethptr = packet->trace->format->get_link(packet);
477        }
478        return (void *)ethptr;
479}
480
481/** get a pointer to the IP header (if any)
482 * @param packet        a pointer to a libtrace_packet structure
483 *
484 * @returns a pointer to the IP header, or NULL if there is not an IP packet
485 */
486struct libtrace_ip *trace_get_ip(const struct libtrace_packet_t *packet) {
487        struct libtrace_ip *ipptr = 0;
488
489        switch(trace_get_link_type(packet)) {
490                case TRACE_TYPE_80211:
491                        { 
492                               
493                                struct ieee_802_11_header *wifi = trace_get_link(packet);       
494                                if (!wifi) {
495                                        ipptr = NULL;
496                                        break;
497                                }
498
499                                // Data packet?
500                                if (wifi->type != 2) {
501                                        ipptr = NULL;
502                                }
503                                else {
504                                        struct ieee_802_11_payload *eth = (void*)wifi->data;
505                                        if (eth->type != 0x0008) {
506                                                ipptr=NULL;
507                                        } else {
508                                                ipptr=(void*)eth->data;
509                                        }
510                                }
511                        }
512                        break;
513                case TRACE_TYPE_ETH:
514                        {
515                                struct ether_header *eth = 
516                                        trace_get_link(packet);
517                                if (!eth) {
518                                        ipptr = NULL;
519                                        break;
520                                }
521                                if (ntohs(eth->ether_type)!=0x0800) {
522                                        ipptr = NULL;
523                                }
524                                else {
525                                        ipptr = ((void *)eth) + 14;
526                                }
527                                break;
528                        }
529                case TRACE_TYPE_NONE:
530                        ipptr = trace_get_link(packet);
531                        break;
532                case TRACE_TYPE_LINUX_SLL:
533                        {
534                                struct trace_sll_header_t *sll;
535
536                                sll = trace_get_link(packet);
537                                if (!sll) {
538                                        ipptr = NULL;
539                                        break;
540                                }
541                                if (ntohs(sll->protocol)!=0x0800) {
542                                        ipptr = NULL;
543                                }
544                                else {
545                                        ipptr = ((void*)sll)+sizeof(*sll);
546                                }
547                        }
548                        break;
549                case TRACE_TYPE_PFLOG:
550                        {
551                                struct trace_pflog_header_t *pflog;
552                                pflog = trace_get_link(packet);
553                                if (!pflog) {
554                                        ipptr = NULL;
555                                        break;
556                                }
557                                if (pflog->af != AF_INET) {
558                                        ipptr = NULL;
559                                } else {
560                                        ipptr = ((void*)pflog)+sizeof(*pflog);
561                                }
562                        }
563                        break;
564                case TRACE_TYPE_ATM:
565                        {
566                                struct atm_rec *atm = 
567                                        trace_get_link(packet);
568                                // TODO: Find out what ATM does, and return
569                                //       NULL for non IP data
570                                //       Presumably it uses the normal stuff
571                                if (!atm) {
572                                        ipptr = NULL;
573                                        break;
574                                }
575                                ipptr =  (void*)&atm->pload;
576                                break;
577                        }
578                default:
579                        fprintf(stderr,"Don't understand link layer type %i in trace_get_ip()\n",
580                                trace_get_link_type(packet));
581                        ipptr=NULL;
582                        break;
583        }
584
585        return ipptr;
586}
587
588#define SW_IP_OFFMASK 0xff1f
589
590/** get a pointer to the TCP header (if any)
591 * @param packet        a pointer to a libtrace_packet structure
592 *
593 * @returns a pointer to the TCP header, or NULL if there is not a TCP packet
594 */
595struct libtrace_tcp *trace_get_tcp(const struct libtrace_packet_t *packet) {
596        struct libtrace_tcp *tcpptr = 0;
597        struct libtrace_ip *ipptr = 0;
598
599        if(!(ipptr = trace_get_ip(packet))) {
600                return 0;
601        }
602        if ((ipptr->ip_p == 6) && ((ipptr->ip_off & SW_IP_OFFMASK) == 0))  {
603                tcpptr = (struct libtrace_tcp *)((ptrdiff_t)ipptr + (ipptr->ip_hl * 4));
604        }
605        return tcpptr;
606}
607
608/** get a pointer to the TCP header (if any) given a pointer to the IP header
609 * @param ip            The IP header
610 * @param[out] skipped  An output variable of the number of bytes skipped
611 *
612 * @returns a pointer to the TCP header, or NULL if this is not a TCP packet
613 *
614 * Skipped can be NULL, in which case it will be ignored by the program.
615 */
616struct libtrace_tcp *get_tcp_from_ip(const struct libtrace_ip *ip, int *skipped)
617{
618#define SW_IP_OFFMASK 0xff1f
619        struct libtrace_tcp *tcpptr = 0;
620
621        if ((ip->ip_p == 6) && ((ip->ip_off & SW_IP_OFFMASK) == 0))  {
622                tcpptr = (struct libtrace_tcp *)((ptrdiff_t)ip+ (ip->ip_hl * 4));
623        }
624
625        if (skipped)
626                *skipped=(ip->ip_hl*4);
627
628        return tcpptr;
629}
630
631/** get a pointer to the UDP header (if any)
632 * @param packet        a pointer to a libtrace_packet structure
633 *
634 * @returns a pointer to the UDP header, or NULL if this is not a UDP packet
635 */
636struct libtrace_udp *trace_get_udp(const struct libtrace_packet_t *packet) {
637        struct libtrace_udp *udpptr = 0;
638        struct libtrace_ip *ipptr = 0;
639       
640        if(!(ipptr = trace_get_ip(packet))) {
641                return 0;
642        }
643        if ((ipptr->ip_p == 17) && ((ipptr->ip_off & SW_IP_OFFMASK) == 0)) {
644                udpptr = (struct libtrace_udp *)((ptrdiff_t)ipptr + (ipptr->ip_hl * 4));
645        }
646
647        return udpptr;
648}
649
650/** get a pointer to the UDP header (if any) given a pointer to the IP header
651 * @param ip            The IP header
652 * @param[out] skipped  An output variable of the number of bytes skipped
653 *
654 * @returns a pointer to the UDP header, or NULL if this is not a UDP packet
655 *
656 * Skipped can be NULL, in which case it will be ignored by the program.
657 */
658struct libtrace_udp *get_udp_from_ip(const struct libtrace_ip *ip, int *skipped)
659{
660        struct libtrace_udp *udpptr = 0;
661
662        if ((ip->ip_p == 6) && ((ip->ip_off & SW_IP_OFFMASK) == 0))  {
663                udpptr = (struct libtrace_udp *)((ptrdiff_t)ip+ (ip->ip_hl * 4));
664        }
665
666        if (skipped)
667                *skipped=(ip->ip_hl*4);
668
669        return udpptr;
670}
671
672
673/** get a pointer to the ICMP header (if any)
674 * @param packet        a pointer to a libtrace_packet structure
675 *
676 * @returns a pointer to the ICMP header, or NULL if this is not a ICMP packet
677 */
678struct libtrace_icmp *trace_get_icmp(const struct libtrace_packet_t *packet) {
679        struct libtrace_icmp *icmpptr = 0;
680        struct libtrace_ip *ipptr = 0;
681       
682        if(!(ipptr = trace_get_ip(packet))) {
683                return 0;
684        }
685        if ((ipptr->ip_p == 1)&& ((ipptr->ip_off & SW_IP_OFFMASK) == 0 )){
686                icmpptr = (struct libtrace_icmp *)((ptrdiff_t)ipptr + (ipptr->ip_hl * 4));
687        }
688        return icmpptr;
689}
690
691/** get a pointer to the ICMP header (if any) given a pointer to the IP header
692 * @param ip            The IP header
693 * @param[out] skipped  An output variable of the number of bytes skipped
694 *
695 * @returns a pointer to the ICMP header, or NULL if this is not a ICMP packet
696 *
697 * Skipped can be NULL, in which case it will be ignored by the program.
698 */
699struct libtrace_icmp *get_icmp_from_ip(struct libtrace_ip *ip, int *skipped)
700{
701        struct libtrace_icmp *icmpptr = 0;
702
703        if ((ip->ip_p == 6) && ((ip->ip_off & SW_IP_OFFMASK) == 0))  {
704                icmpptr = (struct libtrace_icmp *)((ptrdiff_t)ip+ (ip->ip_hl * 4));
705        }
706
707        if (skipped)
708                *skipped=(ip->ip_hl*4);
709
710        return icmpptr;
711}
712/** parse an ip or tcp option
713 * @param[in,out] ptr   the pointer to the current option
714 * @param[in,out] len   the length of the remaining buffer
715 * @param[out] type     the type of the option
716 * @param[out] optlen   the length of the option
717 * @param[out] data     the data of the option
718 *
719 * @returns bool true if there is another option (and the fields are filled in)
720 *               or false if this was the last option.
721 *
722 * This updates ptr to point to the next option after this one, and updates
723 * len to be the number of bytes remaining in the options area.  Type is updated
724 * to be the code of this option, and data points to the data of this option,
725 * with optlen saying how many bytes there are.
726 *
727 * @note Beware of fragmented packets.
728 * @author Perry Lorier
729 */
730int trace_get_next_option(unsigned char **ptr,int *len,
731                        unsigned char *type,
732                        unsigned char *optlen,
733                        unsigned char **data)
734{
735        if (*len<=0)
736                return 0;
737        *type=**ptr;
738        switch(*type) {
739                case 0: /* End of options */
740                        return 0;
741                case 1: /* Pad */
742                        (*ptr)++;
743                        (*len)--;
744                        return 1;
745                default:
746                        *optlen = *(*ptr+1);
747                        if (*optlen<2)
748                                return 0; // I have no idea wtf is going on
749                                          // with these packets
750                        (*len)-=*optlen;
751                        (*data)=(*ptr+2);
752                        (*ptr)+=*optlen;
753                        if (*len<0)
754                                return 0;
755                        return 1;
756        }
757        assert(0);
758}
759
760
761/** Get the current time in DAG time format
762 * @param packet        a pointer to a libtrace_packet structure
763 * @returns a 64 bit timestamp in DAG ERF format (upper 32 bits are the seconds
764 * past 1970-01-01, the lower 32bits are partial seconds)
765 * @author Daniel Lawson
766 */ 
767uint64_t trace_get_erf_timestamp(const struct libtrace_packet_t *packet) {
768        uint64_t timestamp = 0;
769        struct timeval ts;
770
771        if (packet->trace->format->get_erf_timestamp) {
772                timestamp = packet->trace->format->get_erf_timestamp(packet);
773        } else if (packet->trace->format->get_timeval) {
774                ts = packet->trace->format->get_timeval(packet);
775                timestamp = ((((uint64_t)ts.tv_sec) << 32) + \
776                                (((uint64_t)ts.tv_usec * UINT_MAX)/1000000));
777        } 
778        return timestamp;
779}
780
781/** Get the current time in struct timeval
782 * @param packet        a pointer to a libtrace_packet structure
783 *
784 * @returns time that this packet was seen in a struct timeval
785 * @author Daniel Lawson
786 * @author Perry Lorier
787 */ 
788struct timeval trace_get_timeval(const struct libtrace_packet_t *packet) {
789        struct timeval tv;
790        uint64_t ts = 0;
791
792        if (packet->trace->format->get_timeval) {
793                tv = packet->trace->format->get_timeval(packet);
794        } else if (packet->trace->format->get_erf_timestamp) {
795                ts = packet->trace->format->get_erf_timestamp(packet);
796#if __BYTE_ORDER == __BIG_ENDIAN
797                tv.tv_sec = ts & 0xFFFFFFFF;
798#elif __BYTE_ORDER == __LITTLE_ENDIAN
799                tv.tv_sec = ts >> 32;
800#else
801#error "What on earth are you running this on?"
802#endif
803                ts = (1000000 * (ts & 0xffffffffULL));
804                ts += (ts & 0x80000000ULL) << 1;
805                tv.tv_usec = ts >> 32;
806                if (tv.tv_usec >= 1000000) {
807                        tv.tv_usec -= 1000000;
808                        tv.tv_sec += 1;
809                }
810        }
811
812        return tv;
813}
814
815/** Get the current time in floating point seconds
816 * @param packet        a pointer to a libtrace_packet structure
817 * @returns time that this packet was seen in 64bit floating point seconds
818 * @author Perry Lorier
819 */ 
820double trace_get_seconds(const struct libtrace_packet_t *packet) {
821        double seconds;
822        uint64_t ts;
823       
824        if (packet->trace->format->get_seconds) {
825                seconds = packet->trace->format->get_seconds(packet);
826        } else if (packet->trace->format->get_erf_timestamp) {
827                ts = packet->trace->format->get_erf_timestamp(packet);
828                seconds =  (ts>>32) + ((ts & UINT_MAX)*1.0 / UINT_MAX);
829        } 
830        return seconds;
831}
832
833/** Get the size of the packet in the trace
834 * @param packet the packet opaque pointer
835 * @returns the size of the packet in the trace
836 * @author Perry Lorier
837 * @note Due to this being a header capture, or anonymisation, this may not
838 * be the same size as the original packet.  See trace_get_wire_length() for the
839 * original size of the packet.
840 * @note This can (and often is) different for different packets in a trace!
841 * @par
842 *  This is sometimes called the "snaplen".
843 */ 
844int trace_get_capture_length(const struct libtrace_packet_t *packet) {
845
846        if (packet->trace->format->get_capture_length) {
847                return packet->trace->format->get_capture_length(packet);
848        }
849        return -1;
850}
851       
852/** Get the size of the packet as it was seen on the wire.
853 * @param packet        a pointer to a libtrace_packet structure
854 *
855 * @returns the size of the packet as it was on the wire.
856 * @author Perry Lorier
857 * @author Daniel Lawson
858 * @note Due to the trace being a header capture, or anonymisation this may
859 * not be the same as the Capture Len.
860 */ 
861int trace_get_wire_length(const struct libtrace_packet_t *packet){
862        if (packet->trace->format->get_wire_length) {
863                return packet->trace->format->get_wire_length(packet);
864        }
865        return -1;
866
867}
868
869/** Get the type of the link layer
870 * @param packet        a pointer to a libtrace_packet structure
871 * @returns libtrace_linktype_t
872 * @author Perry Lorier
873 * @author Daniel Lawson
874 */
875libtrace_linktype_t trace_get_link_type(const struct libtrace_packet_t *packet ) {
876        if (packet->trace->format->get_link_type) {
877                return packet->trace->format->get_link_type(packet);
878        }
879        return -1;
880}
881
882/** Get the source MAC addres
883 * @param packet        a pointer to a libtrace_packet structure
884 * @returns a pointer to the source mac, (or NULL if there is no source MAC)
885 * @author Perry Lorier
886 */
887uint8_t *trace_get_source_mac(const struct libtrace_packet_t *packet) {
888        void *link = trace_get_link(packet);
889        struct ieee_802_11_header *wifi = link;
890        struct ether_header *ethptr = link;
891        if (!link)
892                return NULL;
893        switch (trace_get_link_type(packet)) {
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 packet a libtrace_packet pointer
906 * @returns a pointer to the destination mac, (or NULL if there is no
907 * destination MAC)
908 * @author Perry Lorier
909 */
910uint8_t *trace_get_destination_mac(const struct libtrace_packet_t *packet) {
911        void *link = trace_get_link(packet);
912        struct ieee_802_11_header *wifi = link;
913        struct ether_header *ethptr = link;
914        if (!link)
915                return NULL;
916        switch (trace_get_link_type(packet)) {
917                case TRACE_TYPE_80211:
918                        return (uint8_t*)&wifi->mac1;
919                case TRACE_TYPE_ETH:
920                        return (uint8_t*)&ethptr->ether_dhost;
921                default:
922                        fprintf(stderr,"Not implemented\n");
923                        assert(0);
924        }
925}
926
927
928/** process a libtrace event
929 * @param trace the libtrace opaque pointer
930 * @param packet the libtrace_packet opaque pointer
931 * @returns
932 *  TRACE_EVENT_IOWAIT  Waiting on I/O on fd
933 *  TRACE_EVENT_SLEEP   Next event in seconds
934 *  TRACE_EVENT_PACKET  Packet arrived in buffer with size size
935 *  TRACE_EVENT_TERMINATE Trace terminated (perhaps with an error condition)
936 * FIXME currently keeps a copy of the packet inside the trace pointer,
937 * which in turn is stored inside the new packet object...
938 * @author Perry Lorier
939 */
940struct libtrace_eventobj_t trace_event(struct libtrace_t *trace, 
941                struct libtrace_packet_t *packet) {
942        struct libtrace_eventobj_t event;
943
944        if (!trace) {
945                fprintf(stderr,"You called trace_event() with a NULL trace object!\n");
946        }
947        assert(trace);
948        assert(packet);
949
950        /* Store the trace we are reading from into the packet opaque
951         * structure */
952        packet->trace = trace;
953
954        /* Is there a packet ready? */
955        switch (trace->sourcetype) {
956#if HAVE_PCAP
957                case INTERFACE:
958                        {
959                                int data;
960                                event.fd = pcap_fileno(trace->input.pcap);
961                                if(ioctl(event.fd,FIONREAD,&data)==-1){
962                                        perror("ioctl(FIONREAD)");
963                                }
964                                if (data>0) {
965                                        event.size = trace_read_packet(trace,packet);
966                                        event.type = TRACE_EVENT_PACKET;
967                                        return event;
968                                }
969                                event.type = TRACE_EVENT_IOWAIT;
970                                return event;
971                        }
972#endif
973                case SOCKET:
974                case DEVICE:
975                case RT:
976                        {
977                                int data;
978                                event.fd = trace->input.fd;
979                                if(ioctl(event.fd,FIONREAD,&data)==-1){
980                                        perror("ioctl(FIONREAD)");
981                                }
982                                if (data>0) {
983                                        event.size = trace_read_packet(trace,packet);
984                                        event.type = TRACE_EVENT_PACKET;
985                                        return event;
986                                }
987                                event.type = TRACE_EVENT_IOWAIT;
988                                return event;
989                        }
990                case STDIN:
991                case TRACE:
992                        {
993                                double ts;
994                                double now;
995                                struct timeval stv;
996                                /* "Prime" the pump */
997                                if (!trace->packet.buffer) {
998                                        trace->packet.buffer = malloc(4096);
999                                        trace->packet.size=
1000                                                trace_read_packet(trace,packet);
1001                                        event.size = trace->packet.size;
1002                                        if (trace->packet.size > 0 ) {
1003                                                memcpy(trace->packet.buffer,packet->buffer,trace->packet.size);
1004                                        } else {
1005                                                // return here, the test for event.size will sort out the error
1006                                                event.type = TRACE_EVENT_PACKET;
1007                                                return event;
1008                                        }
1009                                }
1010
1011                                ts=trace_get_seconds(packet);
1012                                if (trace->tdelta!=0) {
1013                                        // Get the adjusted current time
1014                                        gettimeofday(&stv, NULL);
1015                                        now = stv.tv_sec + ((double)stv.tv_usec / 1000000.0);
1016                                        now -= trace->tdelta; // adjust for trace delta
1017                                       
1018                                       
1019                                        // if the trace timestamp is still in the future,
1020                                        // return a SLEEP event, otherwise fire the packet
1021                                        if (ts > now) {
1022                                                event.seconds = ts - trace->trace_last_ts;
1023                                                event.type = TRACE_EVENT_SLEEP;
1024                                                return event;
1025                                        }
1026                                } else {
1027                                        gettimeofday(&stv, NULL);
1028                                        // work out the difference between the start of trace replay,
1029                                        // and the first packet in the trace
1030                                        trace->tdelta = stv.tv_sec + ((double)stv.tv_usec / 1000000.0);
1031                                        trace->tdelta -= ts;
1032
1033                                }
1034                               
1035                                        // This is the first packet, so just fire away.
1036                                packet->size = trace->packet.size;
1037                                memcpy(packet->buffer,trace->packet.buffer,trace->packet.size);
1038
1039                                free(trace->packet.buffer);
1040                                trace->packet.buffer = 0;
1041                                event.type = TRACE_EVENT_PACKET;
1042                               
1043                                trace->trace_last_ts = ts;
1044
1045                                return event;
1046                        }
1047                default:
1048                        assert(0);
1049        }
1050        assert(0);
1051}
1052
1053/** setup a BPF filter
1054 * @param filterstring a char * containing the bpf filter string
1055 * @returns opaque pointer pointer to a libtrace_filter_t object
1056 * @author Daniel Lawson
1057 */
1058struct libtrace_filter_t *trace_bpf_setfilter(const char *filterstring) {
1059#if HAVE_BPF
1060        struct libtrace_filter_t *filter = malloc(sizeof(struct libtrace_filter_t));
1061        filter->filterstring = strdup(filterstring);
1062        filter->filter = 0;
1063        return filter;
1064#else
1065        fprintf(stderr,"This version of libtrace does not have bpf filter support\n");
1066        return 0;
1067#endif
1068}
1069
1070/** apply a BPF filter
1071 * @param filter the filter opaque pointer
1072 * @param packet the packet opaque pointer
1073 * @returns 0 if the filter fails, 1 if it succeeds
1074 * @author Daniel Lawson
1075 */
1076int trace_bpf_filter(struct libtrace_filter_t *filter,
1077                        const struct libtrace_packet_t *packet) {
1078#if HAVE_BPF
1079        void *linkptr = 0;
1080        int clen = 0;
1081        assert(filter);
1082        assert(packet);
1083        linkptr = trace_get_link(packet);
1084        if (!linkptr) {
1085                return 0;
1086        }
1087       
1088        clen = trace_get_capture_length(packet);
1089       
1090
1091        if (filter->filterstring && ! filter->filter) {
1092                pcap_t *pcap;
1093                struct bpf_program bpfprog;
1094
1095                switch (trace_get_link_type(packet)) {
1096                        case TRACE_TYPE_ETH:
1097                                pcap = (pcap_t *)pcap_open_dead(DLT_EN10MB, 1500);
1098                                break;
1099#ifdef DLT_LINUX_SLL
1100                        case TRACE_TYPE_LINUX_SLL:
1101                                pcap = (pcap_t *)pcap_open_dead(DLT_LINUX_SLL, 1500);
1102                                break;
1103#endif
1104#ifdef DLT_PFLOG
1105                        case TRACE_TYPE_PFLOG:
1106                                pcap = (pcap_t *)pcap_open_dead(DLT_PFLOG, 1500);
1107                                break;
1108#endif
1109                        default:
1110                                printf("only works for ETH and LINUX_SLL (ppp) at the moment\n");
1111                                assert(0);
1112                }               
1113
1114                // build filter
1115                if (pcap_compile( pcap, &bpfprog, filter->filterstring, 1, 0)) {
1116                        printf("bpf compilation error: %s: %s\n", 
1117                                pcap_geterr(pcap),filter->filterstring);
1118                        assert(0);
1119                }
1120                pcap_close(pcap);
1121                filter->filter = bpfprog.bf_insns;     
1122        }
1123
1124        assert(filter->filter);
1125        return bpf_filter(filter->filter, linkptr, clen, clen);
1126#else
1127        fprintf(stderr,"This version of libtrace does not have bpf filter support\n");
1128        return 0;
1129#endif
1130}
1131
1132/** Set the direction flag, if it has one
1133 * @param packet the packet opaque pointer
1134 * @param direction the new direction (0,1,2,3)
1135 * @returns a signed value containing the direction flag, or -1 if this is not supported
1136 * @author Daniel Lawson
1137 */
1138int8_t trace_set_direction(struct libtrace_packet_t *packet, int8_t direction) {
1139        assert(packet);
1140        if (packet->trace->format->set_direction) {
1141                return packet->trace->format->set_direction(packet,direction);
1142        }
1143        return -1;
1144}
1145
1146/** Get the direction flag, if it has one
1147 * @param packet a pointer to a libtrace_packet structure
1148 * @returns a signed value containing the direction flag, or -1 if this is not supported
1149 * The direction is defined as 0 for packets originating locally (ie, outbound)
1150 * and 1 for packets originating remotely (ie, inbound).
1151 * Other values are possible, which might be overloaded to mean special things
1152 * for a special trace.
1153 * @author Daniel Lawson
1154 */
1155int8_t trace_get_direction(const struct libtrace_packet_t *packet) {
1156        assert(packet);
1157        if (packet->trace->format->get_direction) {
1158                return packet->trace->format->get_direction(packet);
1159        }
1160        return -1;
1161}
1162
1163struct ports_t {
1164        uint16_t src;
1165        uint16_t dst;
1166};
1167
1168/* Return the client port
1169 */
1170uint16_t trace_get_source_port(const struct libtrace_packet_t *packet)
1171{
1172        struct libtrace_ip *ip = trace_get_ip(packet);
1173        struct ports_t *port;
1174        if (6 != ip->ip_p
1175          && 17 != ip->ip_p)
1176                return 0;
1177        if (0 != (ip->ip_off & SW_IP_OFFMASK))
1178                return 0;
1179
1180        port = (struct ports_t *)((ptrdiff_t)ip + (ip->ip_hl * 4));
1181
1182        return htons(port->src);
1183}
1184
1185/* Same as get_source_port except use the destination port */
1186uint16_t trace_get_destination_port(const struct libtrace_packet_t *packet)
1187{
1188        struct libtrace_ip *ip = trace_get_ip(packet);
1189        struct ports_t *port;
1190
1191        if (6 != ip->ip_p
1192          && 17 != ip->ip_p)
1193                return 0;
1194
1195        if (0 != (ip->ip_off & SW_IP_OFFMASK))
1196                return 0;
1197
1198        port = (struct ports_t *)((ptrdiff_t)ip + (ip->ip_hl * 4));
1199
1200        return htons(port->dst);
1201}
1202
1203#define ROOT_SERVER(x) ((x) < 512)
1204#define ROOT_CLIENT(x) ((512 <= (x)) && ((x) < 1024))
1205#define NONROOT_SERVER(x) ((x) >= 5000)
1206#define NONROOT_CLIENT(x) ((1024 <= (x)) && ((x) < 5000))
1207#define DYNAMIC(x) ((49152 < (x)) && ((x) < 65535))
1208#define SERVER(x) ROOT_SERVER(x) || NONROOT_SERVER(x)
1209#define CLIENT(x) ROOT_CLIENT(x) || NONROOT_CLIENT(x)
1210
1211/* Attempt to deduce the 'server' port
1212 * @param protocol the IP protocol (eg, 6 or 17 for TCP or UDP)
1213 * @param source the TCP or UDP source port
1214 * @param dest the TCP or UDP destination port
1215 * @returns a hint as to which port is the server port
1216 * @author Daniel Lawson
1217 */
1218int8_t trace_get_server_port(uint8_t protocol, uint16_t source, uint16_t dest) {
1219        /*
1220         * * If the ports are equal, return DEST
1221         * * Check for well-known ports in the given protocol
1222         * * Root server ports: 0 - 511
1223         * * Root client ports: 512 - 1023
1224         * * non-root client ports: 1024 - 4999
1225         * * non-root server ports: 5000+
1226         * * Check for static ranges: 1024 - 49151
1227         * * Check for dynamic ranges: 49152 - 65535
1228         * * flip a coin.
1229         */
1230
1231        uint16_t server, client;
1232
1233        /* equal */
1234        if (source == client)
1235                return USE_DEST;
1236
1237        /* root server port, 0 - 511 */
1238        if (ROOT_SERVER(source) && ROOT_SERVER(dest)) {
1239                if (source < dest)
1240                        return USE_SOURCE;
1241                return USE_DEST;
1242        }
1243
1244        if (ROOT_SERVER(source) && !ROOT_SERVER(dest))
1245                return USE_SOURCE;
1246        if (!ROOT_SERVER(source) && ROOT_SERVER(dest))
1247                return USE_DEST;
1248
1249        /* non-root server */
1250        if (NONROOT_SERVER(source) && NONROOT_SERVER(dest)) {
1251                if (source < dest)
1252                        return USE_SOURCE;
1253                return USE_DEST;
1254        }
1255        if (NONROOT_SERVER(source) && !NONROOT_SERVER(dest))
1256                return USE_SOURCE;
1257        if (!NONROOT_SERVER(source) && NONROOT_SERVER(dest))
1258                return USE_DEST;
1259
1260        /* root client */
1261        if (ROOT_CLIENT(source) && ROOT_CLIENT(dest)) {
1262                if (source < dest)
1263                        return USE_SOURCE;
1264                return USE_DEST;
1265        }
1266        if (ROOT_CLIENT(source) && !ROOT_CLIENT(dest)) {
1267                /* prefer root-client over nonroot-client */
1268                if (NONROOT_CLIENT(dest))
1269                        return USE_SOURCE;
1270                return USE_DEST;
1271        }
1272        if (!ROOT_CLIENT(source) && ROOT_CLIENT(dest)) {
1273                /* prefer root-client over nonroot-client */
1274                if (NONROOT_CLIENT(source))
1275                        return USE_DEST;
1276                return USE_SOURCE;
1277        }
1278       
1279        /* nonroot client */
1280        if (NONROOT_CLIENT(source) && NONROOT_CLIENT(dest)) {
1281                if (source < dest) 
1282                        return USE_SOURCE;
1283                return USE_DEST;
1284        }
1285        if (NONROOT_CLIENT(source) && !NONROOT_CLIENT(dest))
1286                return USE_DEST;
1287        if (!NONROOT_CLIENT(source) && NONROOT_CLIENT(dest))
1288                return USE_SOURCE;
1289
1290        /* dynamic range */
1291        if (DYNAMIC(source) && DYNAMIC(dest))
1292                if (source < dest)
1293                        return USE_SOURCE;
1294                return USE_DEST;
1295        if (DYNAMIC(source) && !DYNAMIC(dest))
1296                return USE_DEST;
1297        if (!DYNAMIC(source) && DYNAMIC(dest))
1298                return USE_SOURCE;
1299        /*
1300        if (SERVER(source) && CLIENT(dest))
1301                return USE_SOURCE;
1302       
1303        if (SERVER(dest) && CLIENT(source))
1304                return USE_DEST;
1305        if (ROOT_SERVER(source) && !ROOT_SERVER(dest))
1306                return USE_SOURCE;
1307        if (ROOT_SERVER(dest) && !ROOT_SERVER(source))
1308                return USE_DEST;
1309        */
1310        // failing that test...
1311        if (source < dest) {
1312                return USE_SOURCE;
1313        } 
1314        return USE_DEST;
1315       
1316}
1317
1318/** Truncate the packet at the suggested length
1319 * @param packet        the packet opaque pointer
1320 * @param size          the new length of the packet
1321 * @returns the new length of the packet, or the original length of the
1322 * packet if unchanged
1323 * NOTE: len refers to the network-level payload of the packet, and not
1324 * any capture headers included as well. For example, to truncate a packet
1325 * after the IP header, set scan to sizeof(ethernet_header) + sizeof(ip_header)
1326 * @author Daniel Lawson
1327 */
1328size_t trace_set_capture_length(struct libtrace_packet_t *packet, size_t size) {
1329        assert(packet);
1330
1331        if (size > packet->size) {
1332                // can't make a packet larger
1333                return packet->size;
1334        }
1335        if (packet->trace->format->truncate_packet) {
1336                return packet->trace->format->truncate_packet(packet,size);
1337        }
1338        return -1;
1339}
1340
Note: See TracBrowser for help on using the repository browser.