source: lib/format_bpf.c @ c909fad

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since c909fad was c909fad, checked in by Shane Alcock <salcock@…>, 8 years ago
  • Added checksumming functions for both the IP and transport layer. The functions will calculate the correct checksum for that packet and also return a pointer to the checksum field in the appropriate header so that the caller can either evaluate whether the checksum is correct, replace the existing checksum, or do whatever they want.
  • Also managed to fix a bunch of broken Revision svn tags
  • Property mode set to 100644
File size: 17.7 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007,2008,2009,2010 The University of Waikato, Hamilton,
5 * New Zealand.
6 *
7 * Authors: Daniel Lawson
8 *          Perry Lorier
9 *          Shane Alcock
10 *         
11 * All rights reserved.
12 *
13 * This code has been developed by the University of Waikato WAND
14 * research group. For further information please see http://www.wand.net.nz/
15 *
16 * libtrace is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * libtrace is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with libtrace; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29 *
30 * $Id$
31 *
32 */
33
34#include "libtrace.h"
35#include "libtrace_int.h"
36#include "format_helper.h"
37#include "config.h"
38#include "stdlib.h"
39
40#ifdef HAVE_INTTYPES_H
41#  include <inttypes.h>
42#else
43# error "Can't find inttypes.h"
44#endif
45
46#include <sys/socket.h>
47
48#include <sys/types.h>
49#include <sys/time.h>
50#include <sys/ioctl.h>
51
52#include <string.h>
53#include <net/if.h>
54#include <sys/ioctl.h>
55#include <errno.h>
56#include <fcntl.h>
57#include <unistd.h>
58
59/* This format deals with the BSD Native capture format, perhaps better
60 * known as BPF, which is the equivalent of the Linux Native format for
61 * *BSD systems.
62 *
63 * This is a LIVE capture format - we're always dealing with reading from an
64 * interface.
65 *
66 * This format does not support writing, but BPF packet records can be easily
67 * converted to PCAP or ERF.
68 */ 
69
70struct bpf_timeval {
71        uint32_t tv_sec;
72        uint32_t tv_usec;
73};
74
75struct libtrace_bpf_hdr {
76        struct bpf_timeval bh_tstamp;   /* timestamp */
77        uint32_t bh_caplen;             /* capture length */
78        uint32_t bh_datalen;            /* wire length */
79        uint16_t bh_hdrlen;             /* header length (incl padding) */
80};
81
82#define BPFHDR(x) ((struct libtrace_bpf_hdr *)((x)->header))
83
84#if HAVE_DECL_BIOCSETIF
85/* "Global" data that is stored for each BPF input trace */
86struct libtrace_format_data_t {
87        /* The file descriptor that is being captured from */
88        int fd; 
89        /* The snap length for the capture */
90        int snaplen;
91        /* A boolean flag indicating whether the capture interface should be
92         * in promiscuous mode */ 
93        int promisc;
94        /* A buffer to write captured data into */
95        void *buffer;
96        /* The current read location in the capture buffer */
97        void *bufptr;
98        /* The total size of the capture buffer */
99        unsigned int buffersize;
100        /* The amount of space remaining before the capture buffer is full */
101        int remaining;
102        /* The linktype of the capture interface */ 
103        unsigned int linktype;
104        /* Statistics about how many packets have been dropped, received etc. */
105        struct bpf_stat stats;
106        /* A boolean flag indicating whether the statistics are up-to-date */
107        int stats_valid;
108};
109
110#define FORMATIN(x) ((struct libtrace_format_data_t*)((x->format_data)))
111
112
113/* Attempts to determine if a given filename could refer to a BPF interface */
114static int bpf_probe_filename(const char *filename)
115{
116        return (if_nametoindex(filename) != 0);
117}
118
119/* Initialises a BPF input trace */
120static int bpf_init_input(libtrace_t *libtrace) 
121{
122        libtrace->format_data = (struct libtrace_format_data_t *)
123                malloc(sizeof(struct libtrace_format_data_t));
124       
125        /* Throw some default values into the format data */
126        FORMATIN(libtrace)->fd = -1;
127        FORMATIN(libtrace)->promisc = 0;
128        FORMATIN(libtrace)->snaplen = 65536;
129        FORMATIN(libtrace)->stats_valid = 0;
130
131        return 0;
132}
133
134/* Starts a BPF input trace */
135static int bpf_start_input(libtrace_t *libtrace)
136{
137        int bpfid=0;
138        struct bpf_version bv;
139        struct ifreq ifr;
140        unsigned int v;
141
142        /* Find and open a bpf device */
143        do {
144                char buffer[64];
145                snprintf(buffer,sizeof(buffer),"/dev/bpf%d", bpfid);
146                bpfid++;
147               
148                FORMATIN(libtrace)->fd = open(buffer, O_RDONLY);
149        } while(FORMATIN(libtrace)->fd == -1 && errno == EBUSY);
150
151        if (FORMATIN(libtrace)->fd == -1) {
152                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,
153                                "No free bpf devices");
154                return -1;
155        }
156
157        /* Check the BPF Version is ok */
158        if (ioctl(FORMATIN(libtrace)->fd, BIOCVERSION, &bv) == -1) {
159                trace_set_err(libtrace,errno,
160                                "Failed to read the bpf version");
161                close(FORMATIN(libtrace)->fd);
162                return -1;
163        }
164
165        if (bv.bv_major != BPF_MAJOR_VERSION) {
166                trace_set_err(libtrace,errno, 
167                        "Unknown kernel BPF version (%d.%d, libtrace requires at least %d.%d)",
168                        bv.bv_major,
169                        bv.bv_minor,
170                        BPF_MAJOR_VERSION,
171                        BPF_MINOR_VERSION);
172                close(FORMATIN(libtrace)->fd);
173                return -1;
174        }
175
176        if (bv.bv_minor < BPF_MINOR_VERSION) {
177                trace_set_err(libtrace,errno, "Kernel version too old (%d.%d, libtrace requires at least %d.%d)",
178                        bv.bv_major,
179                        bv.bv_minor,
180                        BPF_MAJOR_VERSION,
181                        BPF_MINOR_VERSION);
182                close(FORMATIN(libtrace)->fd);
183                return -1;
184        }
185
186        /* We assume the default kernel buffer size is sufficient. */
187        if (ioctl(FORMATIN(libtrace)->fd, BIOCGBLEN,
188                        &FORMATIN(libtrace)->buffersize)==-1) {
189                trace_set_err(libtrace,errno,"Failed to find buffer length");
190                close(FORMATIN(libtrace)->fd);
191                return -1;
192        }
193
194        FORMATIN(libtrace)->buffer = malloc(FORMATIN(libtrace)->buffersize);
195        FORMATIN(libtrace)->bufptr = FORMATIN(libtrace)->buffer;
196        FORMATIN(libtrace)->remaining = 0;
197
198        /* Attach to the device */
199        strncpy(ifr.ifr_name, libtrace->uridata, sizeof(ifr.ifr_name));
200        if (ioctl(FORMATIN(libtrace)->fd, BIOCSETIF, &ifr) == -1) {
201                trace_set_err(libtrace,errno,"Failed to attach");
202                close(FORMATIN(libtrace)->fd);
203                return -1;
204        }
205
206        /* Set the link type */
207        if (ioctl(FORMATIN(libtrace)->fd, BIOCGDLT,
208                         &FORMATIN(libtrace)->linktype) == -1) {
209                trace_set_err(libtrace,errno,"Failed to retrieve link type");
210                close(FORMATIN(libtrace)->fd);
211                return -1;
212        }
213       
214        /* TODO: If BIOCGDLTLIST exists then we should perhaps do something
215         *       with it.  We don't have the same concept of multiple DLT's
216         *       as pcap does.  We grab the rawest possible thing and then
217         *       decode packets by understanding the protocols.  So perhaps
218         *       we should setup a rating of DLT's that we'll prefer in order.
219         *       For example we should try and get 802.11 frames rather than
220         *       802.3 frames.  The general rule should be "whatever actually
221         *       went over the air", although of course if we don't support
222         *       what went over the air we should fall back to something we
223         *       /do/ support.
224         */
225       
226        /* Using timeouts seems sucky.  We'll always use immediate mode.  We
227         * pray the kernel is smart enough that if a another packet arrives
228         * while we're processing this one that it will buffer them into it's
229         * kernel buffer so we can receive packets later. (It'll need to do this
230         * to deal with us spending time processing the last 'n' packets anyway)
231         */
232       
233        v=1;
234        if (ioctl(FORMATIN(libtrace)->fd, BIOCIMMEDIATE, &v) == -1) {
235                trace_set_err(libtrace,errno,"Failed to set immediate mode");
236                close(FORMATIN(libtrace)->fd);
237                return -1;
238        }
239
240        /* Set promiscous mode, if the user has asked us to do so */
241        if (FORMATIN(libtrace)->promisc) {
242                if (ioctl(FORMATIN(libtrace)->fd, BIOCPROMISC, NULL) == -1) {
243                        trace_set_err(libtrace,errno,
244                                "Failed to set promisc mode");
245                        close(FORMATIN(libtrace)->fd);
246                        return -1;
247
248                }
249        }
250
251        FORMATIN(libtrace)->stats_valid = 0;
252
253        /* TODO: we should always set a bpf filter for snapping */
254
255        /* We're done! */
256        return 0;
257}
258
259/* Gets a count of the number of packets received on the BPF interface */
260static uint64_t bpf_get_received_packets(libtrace_t *trace)
261{
262        if (trace->format_data == NULL)
263                return (uint64_t)-1;
264
265        if (FORMATIN(trace)->fd == -1) {
266                /* Almost certainly a 'dead' trace so there is no socket
267                 * for us to query */
268                return (uint64_t) -1;
269        }
270        /* If we're called with stats_valid == 0, or we're called again
271         * then refresh the stats.  Don't refresh the stats if we're called
272         * immediately after get_dropped_packets
273         */
274        if ((FORMATIN(trace)->stats_valid & 1)
275                || (FORMATIN(trace)->stats_valid == 0)) {
276                ioctl(FORMATIN(trace)->fd, BIOCGSTATS, &FORMATIN(trace)->stats);
277                FORMATIN(trace)->stats_valid |= 1;
278        }
279
280        return FORMATIN(trace)->stats.bs_recv;
281}
282
283/* Gets a count of the number of packets dropped on the BPF interface */
284static uint64_t bpf_get_dropped_packets(libtrace_t *trace)
285{
286        if (trace->format_data == NULL)
287                return (uint64_t)-1;
288
289        if (FORMATIN(trace)->fd == -1) {
290                /* Almost certainly a 'dead' trace so there is no socket
291                 * for us to query */
292                return (uint64_t) -1;
293        }
294        /* If we're called with stats_valid == 0, or we're called again
295         * then refresh the stats.  Don't refresh the stats if we're called
296         * immediately after get_received_packets
297         */
298        if ((FORMATIN(trace)->stats_valid & 2) 
299                || (FORMATIN(trace)->stats_valid == 0)) {
300                ioctl(FORMATIN(trace)->fd, BIOCGSTATS, &FORMATIN(trace)->stats);
301                FORMATIN(trace)->stats_valid |= 2;
302        }
303
304        return FORMATIN(trace)->stats.bs_drop;
305}
306
307/* Pauses a BPF input trace */
308static int bpf_pause_input(libtrace_t *libtrace)
309{
310        close(FORMATIN(libtrace)->fd);
311        FORMATIN(libtrace)->fd=-1;
312
313        return 0;
314}
315
316/* Closes a BPF input trace */
317static int bpf_fin_input(libtrace_t *libtrace) 
318{
319        free(libtrace->format_data);
320        return 0;
321}
322
323/* Configures a BPF input trace */
324static int bpf_config_input(libtrace_t *libtrace,
325                trace_option_t option,
326                void *data)
327{
328        switch(option) {
329                case TRACE_OPTION_SNAPLEN:
330                        FORMATIN(libtrace)->snaplen=*(int*)data;
331                        return 0;
332                case TRACE_OPTION_PROMISC:
333                        FORMATIN(libtrace)->promisc=*(int*)data;
334                        return 0;
335                case TRACE_OPTION_FILTER:
336                        /* We don't support bpf filters in any special way
337                         * so return an error and let libtrace deal with
338                         * emulating it
339                         */
340                        break;
341                case TRACE_OPTION_META_FREQ:
342                        /* No meta-data for this format */
343                        break;
344                case TRACE_OPTION_EVENT_REALTIME:
345                        /* Captures are always realtime */
346                        break;
347
348                /* Avoid default: so that future options will cause a warning
349                 * here to remind us to implement it, or flag it as
350                 * unimplementable
351                 */
352        }
353        return -1;
354}
355
356#endif  /* HAVE_DECL_BIOCSETIF */
357
358/* Converts a buffer containing a recently read BPF packet record into a
359 * libtrace packet */
360static int bpf_prepare_packet(libtrace_t *libtrace UNUSED, 
361                libtrace_packet_t *packet,
362                void *buffer, libtrace_rt_types_t rt_type, uint32_t flags) {
363       
364        /* If the packet previously owned a buffer that is not the buffer
365         * that contains the new packet data, we're going to need to free the
366         * old one to avoid memory leaks */
367        if (packet->buffer != buffer &&
368                        packet->buf_control == TRACE_CTRL_PACKET) {
369                free(packet->buffer);
370        }
371
372        /* Set the buffer owner appropriately */
373        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
374                packet->buf_control = TRACE_CTRL_PACKET;
375        } else
376                packet->buf_control = TRACE_CTRL_EXTERNAL;
377
378        /* Update the packet pointers and type appropriately */
379        packet->buffer = buffer;
380        packet->header = buffer;
381        packet->type = rt_type;
382
383        /* Find the payload */
384        /* TODO: Pcap deals with a padded FDDI linktype here */
385        packet->payload=(char *)buffer + BPFHDR(packet)->bh_hdrlen;
386
387        /*
388        if (libtrace->format_data == NULL) {
389                if (bpf_init_input(libtrace))
390                        return -1;
391        }
392        */
393
394        return 0;
395}
396
397#if HAVE_DECL_BIOCSETIF
398
399/* Reads the next packet record from a BPF interface and writes it into a
400 * libtrace packet */   
401static int bpf_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
402{
403        uint32_t flags = 0;
404
405        packet->type = bpf_linktype_to_rt(FORMATIN(libtrace)->linktype);
406       
407        /* Read from the BPF interface into our capture buffer */
408        if (FORMATIN(libtrace)->remaining<=0) {
409                int ret;
410
411                ret=read(FORMATIN(libtrace)->fd,
412                        FORMATIN(libtrace)->buffer,
413                        FORMATIN(libtrace)->buffersize);
414
415                if (ret == -1) {
416                        trace_set_err(libtrace,errno,"Failed to read");
417                        return -1;
418                }
419
420                if (ret == 0) {
421                        /* EOF */
422                        return 0;
423                }
424
425                FORMATIN(libtrace)->remaining=ret;
426                FORMATIN(libtrace)->bufptr=
427                                FORMATIN(libtrace)->buffer;
428        }
429
430        /* We do NOT want anything trying to free the memory the packet is
431         * stored in */
432        flags |= TRACE_PREP_DO_NOT_OWN_BUFFER;
433
434        if (packet->buf_control == TRACE_CTRL_PACKET)
435                free(packet->buffer);
436
437        /* Update 'packet' to point to the first packet in our capture
438         * buffer */
439        if (bpf_prepare_packet(libtrace, packet, FORMATIN(libtrace)->bufptr,
440                        packet->type, flags)) {
441                return -1;
442        }
443       
444
445        /* Skip past the packet record we're going to return, making sure
446         * that we deal with padding correctly */
447        FORMATIN(libtrace)->bufptr+=
448                BPF_WORDALIGN(BPFHDR(packet)->bh_hdrlen
449                +BPFHDR(packet)->bh_caplen);
450        FORMATIN(libtrace)->remaining-=
451                BPF_WORDALIGN(BPFHDR(packet)->bh_hdrlen
452                +BPFHDR(packet)->bh_caplen);
453
454        return BPFHDR(packet)->bh_datalen+BPFHDR(packet)->bh_hdrlen;
455}
456
457#endif  /* HAVE_DECL_BIOCSETIF */
458
459/* Returns the linktype for the interface that we are capturing from */
460static libtrace_linktype_t bpf_get_link_type(const libtrace_packet_t *packet) {
461        /* Convert the linktype that we recorded when we started the trace
462         * into a suitable libtrace linktype */
463        return pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type));
464}
465
466/* Returns the direction for a given BPF packet record */
467static libtrace_direction_t bpf_get_direction(const libtrace_packet_t *packet UNUSED) {
468        /* BPF sadly can't do direction tagging */
469        return ~0;
470}
471
472/* Returns the timestamp for a given BPF packet record, in the form of a
473 * struct timeval */
474static struct timeval bpf_get_timeval(const libtrace_packet_t *packet) 
475{
476        struct timeval tv;
477        /* OpenBSD uses a bpf_timeval rather than a timeval so we must copy
478         * each timeval element individually rather than doing a structure
479         * assignment */
480        tv.tv_sec = BPFHDR(packet)->bh_tstamp.tv_sec;
481        tv.tv_usec = BPFHDR(packet)->bh_tstamp.tv_usec;
482
483        return tv;
484}
485
486/* Returns the capture length for a given BPF packet record */
487static int bpf_get_capture_length(const libtrace_packet_t *packet)
488{
489        /* BPF doesn't include the FCS in its caplen field, but libtrace
490         * does so we need to add this extra 4 bytes */
491        return BPFHDR(packet)->bh_caplen+4;
492}
493
494/* Returns the wire length for a given BPF packet record */
495static int bpf_get_wire_length(const libtrace_packet_t *packet) 
496{
497
498        /* BPF doesn't include the FCS in its datalen field, but libtrace
499         * does so we need to add this extra 4 bytes */
500        return BPFHDR(packet)->bh_datalen+4;
501}
502
503/* Returns the framing length for a given BPF packet record */
504static int bpf_get_framing_length(UNUSED
505                const libtrace_packet_t *packet) 
506{
507        return BPFHDR(packet)->bh_hdrlen;
508}
509
510#if HAVE_DECL_BIOCSETIF
511/* Returns the file descriptor that the capture interface is operating on */
512static int bpf_get_fd(const libtrace_t *trace) {
513        return FORMATIN(trace)->fd;
514}
515
516/* Prints some slightly useful help text for the BPF capture format */
517static void bpf_help() {
518        printf("bpf format module: $Revision: 1782 $\n");
519        printf("Supported input URIs:\n");
520        printf("\tbpf:\n");
521        printf("\n");
522        return;
523}
524static struct libtrace_format_t bpf = {
525        "bpf",
526        "$Id$",
527        TRACE_FORMAT_BPF,
528        bpf_probe_filename,     /* probe filename */
529        NULL,                   /* probe magic */
530        bpf_init_input,         /* init_input */
531        bpf_config_input,       /* config_input */
532        bpf_start_input,        /* start_input */
533        bpf_pause_input,        /* pause_input */
534        NULL,                   /* init_output */
535        NULL,                   /* config_output */
536        NULL,                   /* start_ouput */
537        bpf_fin_input,          /* fin_input */
538        NULL,                   /* fin_output */
539        bpf_read_packet,        /* read_packet */
540        bpf_prepare_packet,     /* prepare_packet */
541        NULL,                   /* fin_packet */
542        NULL,                   /* write_packet */
543        bpf_get_link_type,      /* get_link_type */
544        bpf_get_direction,      /* get_direction */
545        NULL,                   /* set_direction */
546        NULL,                   /* get_erf_timestamp */
547        bpf_get_timeval,        /* get_timeval */
548        NULL,                   /* get_timespec */
549        NULL,                   /* get_seconds */
550        NULL,                   /* seek_erf */
551        NULL,                   /* seek_timeval */
552        NULL,                   /* seek_seconds */
553        bpf_get_capture_length, /* get_capture_length */
554        bpf_get_wire_length,    /* get_wire_length */
555        bpf_get_framing_length, /* get_framing_length */
556        NULL,                   /* set_capture_length */
557        bpf_get_received_packets,/* get_received_packets */
558        NULL,                   /* get_filtered_packets */
559        bpf_get_dropped_packets,/* get_dropped_packets */
560        NULL,                   /* get_captured_packets */
561        bpf_get_fd,             /* get_fd */
562        trace_event_device,     /* trace_event */
563        bpf_help,               /* help */
564        NULL
565};
566#else   /* HAVE_DECL_BIOCSETIF */
567/* Prints some slightly useful help text for the BPF capture format */
568static void bpf_help() {
569        printf("bpf format module: $Revision: 1782 $\n");
570        printf("Not supported on this host\n");
571        return;
572}
573static struct libtrace_format_t bpf = {
574        "bpf",
575        "$Id$",
576        TRACE_FORMAT_BPF,
577        NULL,                   /* probe filename */
578        NULL,                   /* probe magic */
579        NULL,                   /* init_input */
580        NULL,                   /* config_input */
581        NULL,                   /* start_input */
582        NULL,                   /* pause_input */
583        NULL,                   /* init_output */
584        NULL,                   /* config_output */
585        NULL,                   /* start_ouput */
586        NULL,                   /* fin_input */
587        NULL,                   /* fin_output */
588        NULL,                   /* read_packet */
589        bpf_prepare_packet,     /* prepare_packet */
590        NULL,                   /* fin_packet */
591        NULL,                   /* write_packet */
592        bpf_get_link_type,      /* get_link_type */
593        bpf_get_direction,      /* get_direction */
594        NULL,                   /* set_direction */
595        NULL,                   /* get_erf_timestamp */
596        bpf_get_timeval,        /* get_timeval */
597        NULL,                   /* get_timespec */
598        NULL,                   /* get_seconds */
599        NULL,                   /* seek_erf */
600        NULL,                   /* seek_timeval */
601        NULL,                   /* seek_seconds */
602        bpf_get_capture_length, /* get_capture_length */
603        bpf_get_wire_length,    /* get_wire_length */
604        bpf_get_framing_length, /* get_framing_length */
605        NULL,                   /* set_capture_length */
606        NULL,/* get_received_packets */
607        NULL,                   /* get_filtered_packets */
608        NULL,/* get_dropped_packets */
609        NULL,                   /* get_captured_packets */
610        NULL,                   /* get_fd */
611        NULL,                   /* trace_event */
612        bpf_help,               /* help */
613        NULL
614};
615#endif  /* HAVE_DECL_BIOCSETIF */
616
617void bpf_constructor() {
618        register_format(&bpf);
619}
Note: See TracBrowser for help on using the repository browser.