source: lib/trace.c @ 39b37d2

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

added default error to trace_perror = "no such errcode"

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