source: lib/format_pcapfile.c @ 4811b1e

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 4811b1e was 4811b1e, checked in by Shane Alcock <salcock@…>, 11 years ago
  • Fixed bug where the header pointer was not set correctly for packets that had no payload other than the PCAP header
  • Added a few extra asserts so that we can have a slightly more graceful exit when the header pointer isn't set correctly rather than just segfaulting :)
  • 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 "common.h"
35#include "config.h"
36#include "libtrace.h"
37#include "libtrace_int.h"
38#include "format_helper.h"
39
40#include <sys/stat.h>
41#include <assert.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <errno.h>
46#include <fcntl.h>
47#include <stdbool.h>
48
49/* This format module implements our own, more efficient, version of the PCAP
50 * file format. This should always be used in preference to the "pcap" format
51 * provided in format_pcap.c.
52 *
53 * This is a trace file format and does not implement any live interface
54 * capture. This is covered by "pcapint" in format_pcap.c.
55 *
56 * This format supports both reading and writing, regardless of the version
57 * of your PCAP library.
58 */
59
60#define DATA(x) ((struct pcapfile_format_data_t*)((x)->format_data))
61#define DATAOUT(x) ((struct pcapfile_format_data_out_t*)((x)->format_data))
62#define IN_OPTIONS DATA(libtrace)->options
63
64typedef struct pcapfile_header_t {
65                uint32_t magic_number;   /* magic number */
66                uint16_t version_major;  /* major version number */
67                uint16_t version_minor;  /* minor version number */
68                int32_t  thiszone;       /* GMT to local correction */
69                uint32_t sigfigs;        /* timestamp accuracy */
70                uint32_t snaplen;        /* aka "wirelen" */
71                uint32_t network;        /* data link type */
72} pcapfile_header_t; 
73
74struct pcapfile_format_data_t {
75        struct {
76                /* Indicates whether the event API should replicate the pauses
77                 * between packets */
78                int real_time;
79        } options;
80
81        /* The PCAP meta-header that should be written at the start of each
82         * trace */
83        pcapfile_header_t header;
84        /* Indicates whether the input trace is started */
85        bool started;
86};
87
88struct pcapfile_format_data_out_t {
89        iow_t *file;
90        int level;
91        int flag;
92
93};
94
95static int pcapfile_probe_magic(io_t *io)
96{
97        pcapfile_header_t header;
98        int len;
99        len = wandio_peek(io, &header, sizeof(header));
100        /* Is this long enough? */
101        if (len < (int)sizeof(header)) {
102                return 0;
103        }
104        /* Pcap magic? */
105        if (header.magic_number == 0xa1b2c3d4 || header.magic_number == 0xd4c3b2a1) {
106                return 1;
107        }
108        /* Nope, not pcap */
109        return 0;
110}
111
112static int pcapfile_init_input(libtrace_t *libtrace) {
113        libtrace->format_data = malloc(sizeof(struct pcapfile_format_data_t));
114
115        if (libtrace->format_data == NULL) {
116                trace_set_err(libtrace,ENOMEM,"Out of memory");
117                return -1;
118        }
119
120        IN_OPTIONS.real_time = 0;
121        DATA(libtrace)->started = false;
122        return 0;
123}
124
125static int pcapfile_init_output(libtrace_out_t *libtrace) {
126        libtrace->format_data = 
127                malloc(sizeof(struct pcapfile_format_data_out_t));
128
129        DATAOUT(libtrace)->file=NULL;
130        DATAOUT(libtrace)->level=0;
131        DATAOUT(libtrace)->flag=O_CREAT|O_WRONLY;
132
133        return 0;
134}
135
136
137static uint16_t swaps(libtrace_t *libtrace, uint16_t num)
138{
139        /* To deal with open_dead traces that might try and use this
140         * if we don't have any per trace data, assume host byte order
141         */
142        if (!DATA(libtrace))
143                return num;
144       
145        /* We can use the PCAP magic number to determine the byte order */
146        if (DATA(libtrace)->header.magic_number == 0xd4c3b2a1)
147                return byteswap16(num);
148
149        return num;
150}
151
152static uint32_t swapl(libtrace_t *libtrace, uint32_t num)
153{
154        /* To deal with open_dead traces that might try and use this
155         * if we don't have any per trace data, assume host byte order
156         */
157        if (!DATA(libtrace))
158                return num;
159       
160        /* We can use the PCAP magic number to determine the byte order */
161        if (DATA(libtrace)->header.magic_number == 0xd4c3b2a1)
162                return byteswap32(num);
163
164        return num;
165}
166
167
168static int pcapfile_start_input(libtrace_t *libtrace) 
169{
170        int err;
171
172        if (!libtrace->io) {
173                libtrace->io=trace_open_file(libtrace);
174                DATA(libtrace)->started=false;
175        }
176
177        if (!DATA(libtrace)->started) {
178
179                if (!libtrace->io)
180                        return -1;
181
182                err=wandio_read(libtrace->io,
183                                &DATA(libtrace)->header,
184                                sizeof(DATA(libtrace)->header));
185
186                if (err<1)
187                        return -1;
188               
189                if (swapl(libtrace,DATA(libtrace)->header.magic_number) != 
190                                        0xa1b2c3d4) {
191                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,
192                                        "Not a pcap tracefile\n");
193                        return -1; /* Not a pcap file */
194                }
195
196                if (swaps(libtrace,DATA(libtrace)->header.version_major)!=2
197                        && swaps(libtrace,DATA(libtrace)->header.version_minor)!=4) {
198                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,
199                                        "Unknown pcap tracefile version %d.%d\n",
200                                        swaps(libtrace,
201                                                DATA(libtrace)->header.version_major),
202                                        swaps(libtrace,
203                                                DATA(libtrace)->header.version_minor));
204                        return -1;
205                }
206
207        }
208
209        return 0;
210}
211
212static int pcapfile_start_output(libtrace_out_t *libtrace UNUSED)
213{
214        /* We can't open the output file until we've seen the first packet.
215         * This is because we need to know the DLT to set the "network"
216         * value in the meta-header */
217       
218        return 0;
219}
220
221static int pcapfile_config_input(libtrace_t *libtrace,
222                trace_option_t option,
223                void *data)
224{
225        switch(option) {
226                case TRACE_OPTION_EVENT_REALTIME:
227                        IN_OPTIONS.real_time = *(int *)data;
228                        return 0;
229                case TRACE_OPTION_META_FREQ:
230                case TRACE_OPTION_SNAPLEN:
231                case TRACE_OPTION_PROMISC:
232                case TRACE_OPTION_FILTER:
233                        /* All these are either unsupported or handled
234                         * by trace_config */
235                        break;
236        }
237       
238        trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION,
239                        "Unknown option %i", option);
240        return -1;
241}
242
243static int pcapfile_fin_input(libtrace_t *libtrace) 
244{
245        if (libtrace->io)
246                wandio_destroy(libtrace->io);
247        free(libtrace->format_data);
248        return 0; /* success */
249}
250
251static int pcapfile_fin_output(libtrace_out_t *libtrace)
252{
253        if (DATAOUT(libtrace)->file)
254                wandio_wdestroy(DATAOUT(libtrace)->file);
255        free(libtrace->format_data);
256        libtrace->format_data=NULL;
257        return 0; /* success */
258}
259
260static int pcapfile_config_output(libtrace_out_t *libtrace,
261                trace_option_output_t option,
262                void *value)
263{
264        switch (option) {
265                case TRACE_OPTION_OUTPUT_COMPRESS:
266                        DATAOUT(libtrace)->level = *(int*)value;
267                        return 0;
268                case TRACE_OPTION_OUTPUT_FILEFLAGS:
269                        DATAOUT(libtrace)->flag = *(int*)value;
270                        return 0;
271                default:
272                        /* Unknown option */
273                        trace_set_err_out(libtrace,TRACE_ERR_UNKNOWN_OPTION,
274                                        "Unknown option");
275                        return -1;
276        }
277        return -1;
278}
279
280static int pcapfile_prepare_packet(libtrace_t *libtrace, 
281                libtrace_packet_t *packet, void *buffer, 
282                libtrace_rt_types_t rt_type, uint32_t flags) {
283
284        if (packet->buffer != buffer && 
285                        packet->buf_control == TRACE_CTRL_PACKET) {
286                free(packet->buffer);
287        }
288
289        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
290                packet->buf_control = TRACE_CTRL_PACKET;
291        } else
292                packet->buf_control = TRACE_CTRL_EXTERNAL;
293       
294       
295        packet->buffer = buffer;
296        packet->header = buffer;
297        packet->payload = (char*)packet->buffer
298                + sizeof(libtrace_pcapfile_pkt_hdr_t);
299        packet->type = rt_type; 
300
301        if (libtrace->format_data == NULL) {
302                if (pcapfile_init_input(libtrace))
303                        return -1;
304        }
305       
306        return 0;
307}
308
309static int pcapfile_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet)
310{
311        int err;
312        uint32_t flags = 0;
313        size_t bytes_to_read = 0;
314
315        assert(libtrace->format_data);
316
317        packet->type = pcap_linktype_to_rt(swapl(libtrace,
318                                DATA(libtrace)->header.network));
319
320        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
321                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
322        }
323
324        flags |= TRACE_PREP_OWN_BUFFER;
325       
326        err=wandio_read(libtrace->io,
327                        packet->buffer,
328                        sizeof(libtrace_pcapfile_pkt_hdr_t));
329
330        if (err<0) {
331                trace_set_err(libtrace,errno,"reading packet");
332                return -1;
333        }
334        if (err==0) {
335                /* EOF */
336                return 0;
337        }
338
339        bytes_to_read = swapl(libtrace,((libtrace_pcapfile_pkt_hdr_t*)packet->buffer)->caplen);
340
341        assert(bytes_to_read < LIBTRACE_PACKET_BUFSIZE);
342
343        /* If there is no payload to read, do not ask wandio_read to try and
344         * read zero bytes - we'll just get back a zero that we will
345         * misinterpret as EOF! */
346        if (bytes_to_read == 0) {
347                packet->header = packet->buffer;
348                return sizeof(libtrace_pcapfile_pkt_hdr_t);
349        }
350
351        err=wandio_read(libtrace->io,
352                        (char*)packet->buffer+sizeof(libtrace_pcapfile_pkt_hdr_t),
353                        (size_t)swapl(libtrace,((libtrace_pcapfile_pkt_hdr_t*)packet->buffer)->caplen)
354                        );
355
356       
357        if (err<0) {
358                trace_set_err(libtrace,errno,"reading packet");
359                return -1;
360        }
361        if (err==0) {
362                return 0;
363        }
364
365        if (pcapfile_prepare_packet(libtrace, packet, packet->buffer,
366                                packet->type, flags)) {
367                return -1;
368        }
369       
370        return sizeof(libtrace_pcapfile_pkt_hdr_t) + bytes_to_read;
371}
372
373static int pcapfile_write_packet(libtrace_out_t *out,
374                libtrace_packet_t *packet)
375{
376        struct libtrace_pcapfile_pkt_hdr_t hdr;
377        struct timeval tv = trace_get_timeval(packet);
378        int numbytes;
379        int ret;
380        void *ptr;
381        uint32_t remaining;
382        libtrace_linktype_t linktype;
383
384        ptr = trace_get_packet_buffer(packet,&linktype,&remaining);
385       
386        /* Silently discard RT metadata packets and packets with an
387         * unknown linktype. */
388        if (linktype == TRACE_TYPE_METADATA || linktype == ~0U) {
389                return 0;
390        }
391
392        /* If this packet cannot be converted to a pcap linktype then
393         * pop off the top header until it can be converted
394         */
395        while (libtrace_to_pcap_linktype(linktype)==~0U) {
396                if (!demote_packet(packet)) {
397                        trace_set_err_out(out, 
398                                TRACE_ERR_NO_CONVERSION,
399                                "pcap does not support this format");
400                        return -1;
401                }
402
403                ptr = trace_get_packet_buffer(packet,&linktype,&remaining);
404        }
405
406
407        /* Now we know the link type write out a header if we've not done
408         * so already
409         */
410        if (!DATAOUT(out)->file) {
411                struct pcapfile_header_t pcaphdr;
412
413                DATAOUT(out)->file=trace_open_file_out(out,
414                                DATAOUT(out)->level,
415                                DATAOUT(out)->flag);
416                if (!DATAOUT(out)->file)
417                        return -1;
418
419                pcaphdr.magic_number = 0xa1b2c3d4;
420                pcaphdr.version_major = 2;
421                pcaphdr.version_minor = 4;
422                pcaphdr.thiszone = 0;
423                pcaphdr.sigfigs = 0;
424                pcaphdr.snaplen = 65536;
425                pcaphdr.network = 
426                        libtrace_to_pcap_linktype(linktype);
427
428                wandio_wwrite(DATAOUT(out)->file, 
429                                &pcaphdr, sizeof(pcaphdr));
430        }
431
432        hdr.ts_sec = tv.tv_sec;
433        hdr.ts_usec = tv.tv_usec;
434        hdr.caplen = trace_get_capture_length(packet);
435        assert(hdr.caplen < LIBTRACE_PACKET_BUFSIZE);
436        /* PCAP doesn't include the FCS in its wire length value, but we do */
437        if (linktype==TRACE_TYPE_ETH) {
438                if (trace_get_wire_length(packet) >= 4) {
439                        hdr.wirelen = trace_get_wire_length(packet)-4;
440                }
441                else {
442                        hdr.wirelen = 0;
443                }
444        }
445        else
446                hdr.wirelen = trace_get_wire_length(packet);
447
448        assert(hdr.wirelen < LIBTRACE_PACKET_BUFSIZE);
449
450
451        /* Write the packet header */
452        numbytes=wandio_wwrite(DATAOUT(out)->file,
453                        &hdr, sizeof(hdr));
454
455        if (numbytes!=sizeof(hdr)) 
456                return -1;
457
458        /* Write the rest of the packet now */
459        ret=wandio_wwrite(DATAOUT(out)->file,
460                        ptr,
461                        remaining);
462
463        if (ret!=(int)remaining)
464                return -1;
465
466        return numbytes+ret;
467}
468
469static libtrace_linktype_t pcapfile_get_link_type(
470                const libtrace_packet_t *packet) 
471{
472        return pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type));
473}
474
475static libtrace_direction_t pcapfile_get_direction(const libtrace_packet_t *packet) 
476{
477        libtrace_direction_t direction  = -1;
478        switch(pcapfile_get_link_type(packet)) {
479                /* We can only get the direction for PCAP packets that have
480                 * been encapsulated in Linux SLL or PFLOG */
481                case TRACE_TYPE_LINUX_SLL:
482                {
483                        libtrace_sll_header_t *sll;
484                        libtrace_linktype_t linktype;
485
486                        sll = (libtrace_sll_header_t*)trace_get_packet_buffer(
487                                        packet,
488                                        &linktype,
489                                        NULL);
490                        if (!sll) {
491                                trace_set_err(packet->trace,
492                                        TRACE_ERR_BAD_PACKET,
493                                                "Bad or missing packet");
494                                return -1;
495                        }
496                        /* 0 == LINUX_SLL_HOST */
497                        /* the Waikato Capture point defines "packets
498                         * originating locally" (ie, outbound), with a
499                         * direction of 0, and "packets destined locally"
500                         * (ie, inbound), with a direction of 1.
501                         * This is kind-of-opposite to LINUX_SLL.
502                         * We return consistent values here, however
503                         *
504                         * Note that in recent versions of pcap, you can
505                         * use "inbound" and "outbound" on ppp in linux
506                         */
507                        if (ntohs(sll->pkttype == 0)) {
508                                direction = TRACE_DIR_INCOMING;
509                        } else {
510                                direction = TRACE_DIR_OUTGOING;
511                        }
512                        break;
513
514                }
515                case TRACE_TYPE_PFLOG:
516                {
517                        libtrace_pflog_header_t *pflog;
518                        libtrace_linktype_t linktype;
519
520                        pflog=(libtrace_pflog_header_t*)trace_get_packet_buffer(
521                                        packet,&linktype,NULL);
522                        if (!pflog) {
523                                trace_set_err(packet->trace,
524                                                TRACE_ERR_BAD_PACKET,
525                                                "Bad or missing packet");
526                                return -1;
527                        }
528                        /* enum    { PF_IN=0, PF_OUT=1 }; */
529                        if (ntohs(pflog->dir==0)) {
530
531                                direction = TRACE_DIR_INCOMING;
532                        }
533                        else {
534                                direction = TRACE_DIR_OUTGOING;
535                        }
536                        break;
537                }
538                default:
539                        break;
540        }       
541        return direction;
542}
543
544
545static struct timeval pcapfile_get_timeval(
546                const libtrace_packet_t *packet) 
547{
548        libtrace_pcapfile_pkt_hdr_t *hdr;
549        struct timeval ts;
550       
551        assert(packet->header);
552       
553        hdr = (libtrace_pcapfile_pkt_hdr_t*)packet->header;
554        ts.tv_sec = swapl(packet->trace,hdr->ts_sec);
555        ts.tv_usec = swapl(packet->trace,hdr->ts_usec);
556        return ts;
557}
558
559
560static int pcapfile_get_capture_length(const libtrace_packet_t *packet) {
561        libtrace_pcapfile_pkt_hdr_t *pcapptr; 
562
563        assert(packet->header);
564        pcapptr = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
565
566        return swapl(packet->trace,pcapptr->caplen);
567}
568
569static int pcapfile_get_wire_length(const libtrace_packet_t *packet) {
570        libtrace_pcapfile_pkt_hdr_t *pcapptr;
571         
572        assert(packet->header); 
573
574        pcapptr = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
575        if (packet->type==pcap_linktype_to_rt(TRACE_DLT_EN10MB))
576                /* Include the missing FCS */
577                return swapl(packet->trace,pcapptr->wirelen)+4; 
578        else if (packet->type==pcap_linktype_to_rt(TRACE_DLT_IEEE802_11_RADIO)){
579                /* If the packet is Radiotap and the flags field indicates
580                 * that the FCS is not included in the 802.11 frame, then
581                 * we need to add 4 to the wire-length to account for it.
582                 */
583                uint8_t flags;
584                void *link;
585                libtrace_linktype_t linktype;
586                link = trace_get_packet_buffer(packet, &linktype, NULL);
587                trace_get_wireless_flags(link, linktype, &flags);
588                if ((flags & TRACE_RADIOTAP_F_FCS) == 0)
589                        return swapl(packet->trace,pcapptr->wirelen)+4;
590        }
591        return swapl(packet->trace,pcapptr->wirelen);
592}
593
594static int pcapfile_get_framing_length(const libtrace_packet_t *packet UNUSED) {
595        return sizeof(libtrace_pcapfile_pkt_hdr_t);
596}
597
598static size_t pcapfile_set_capture_length(libtrace_packet_t *packet,size_t size) {
599        libtrace_pcapfile_pkt_hdr_t *pcapptr = 0;
600        assert(packet);
601        assert(packet->header);
602        if (size > trace_get_capture_length(packet)) {
603                /* Can't make a packet larger */
604                return trace_get_capture_length(packet);
605        }
606        /* Reset the cached capture length */
607        packet->capture_length = -1;
608        pcapptr = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
609        pcapptr->caplen = swapl(packet->trace,(uint32_t)size);
610        return trace_get_capture_length(packet);
611}
612
613static struct libtrace_eventobj_t pcapfile_event(libtrace_t *libtrace, libtrace_packet_t *packet) {
614       
615        libtrace_eventobj_t event = {0,0,0.0,0};
616       
617        /* If we are being told to replay packets as fast as possible, then
618         * we just need to read and return the next packet in the trace */
619
620        if (IN_OPTIONS.real_time) {
621                event.size = pcapfile_read_packet(libtrace, packet);
622                if (event.size < 1)
623                        event.type = TRACE_EVENT_TERMINATE;
624                else
625                        event.type = TRACE_EVENT_PACKET;
626                return event;
627        } else {
628                return trace_event_trace(libtrace, packet);
629        }
630}
631
632static void pcapfile_help(void) {
633        printf("pcapfile format module: $Revision$\n");
634        printf("Supported input URIs:\n");
635        printf("\tpcapfile:/path/to/file\n");
636        printf("\tpcapfile:/path/to/file.gz\n");
637        printf("\n");
638        printf("\te.g.: pcapfile:/tmp/trace.pcap\n");
639        printf("\n");
640}
641
642static struct libtrace_format_t pcapfile = {
643        "pcapfile",
644        "$Id$",
645        TRACE_FORMAT_PCAPFILE,
646        NULL,                           /* probe filename */
647        pcapfile_probe_magic,           /* probe magic */
648        pcapfile_init_input,            /* init_input */
649        pcapfile_config_input,          /* config_input */
650        pcapfile_start_input,           /* start_input */
651        NULL,                           /* pause_input */
652        pcapfile_init_output,           /* init_output */
653        pcapfile_config_output,         /* config_output */
654        pcapfile_start_output,          /* start_output */
655        pcapfile_fin_input,             /* fin_input */
656        pcapfile_fin_output,            /* fin_output */
657        pcapfile_read_packet,           /* read_packet */
658        pcapfile_prepare_packet,        /* prepare_packet */
659        NULL,                           /* fin_packet */
660        pcapfile_write_packet,          /* write_packet */
661        pcapfile_get_link_type,         /* get_link_type */
662        pcapfile_get_direction,         /* get_direction */
663        NULL,                           /* set_direction */
664        NULL,                           /* get_erf_timestamp */
665        pcapfile_get_timeval,           /* get_timeval */
666        NULL,                           /* get_timespec */
667        NULL,                           /* get_seconds */
668        NULL,                           /* seek_erf */
669        NULL,                           /* seek_timeval */
670        NULL,                           /* seek_seconds */
671        pcapfile_get_capture_length,    /* get_capture_length */
672        pcapfile_get_wire_length,       /* get_wire_length */
673        pcapfile_get_framing_length,    /* get_framing_length */
674        pcapfile_set_capture_length,    /* set_capture_length */
675        NULL,                           /* get_received_packets */
676        NULL,                           /* get_filtered_packets */
677        NULL,                           /* get_dropped_packets */
678        NULL,                           /* get_captured_packets */
679        NULL,                           /* get_fd */
680        pcapfile_event,         /* trace_event */
681        pcapfile_help,                  /* help */
682        NULL                            /* next pointer */
683};
684
685
686void pcapfile_constructor(void) {
687        register_format(&pcapfile);
688}
689
690
Note: See TracBrowser for help on using the repository browser.