source: lib/trace.c @ c3274c6

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

fixed length calculation for uri, so it actually returns the right answer

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