source: lib/format_pcapfile.c @ 509ee47

develop
Last change on this file since 509ee47 was 509ee47, checked in by Shane Alcock <salcock@…>, 2 years ago

Add option to allow users to specify a constant ERF framing length.

This can be useful for situations where

a) the input uses ERF (or some derivative thereof)
b) the link type and ERF record type are constant for the

duration of the capture

c) performance is critical

This option allows users to simply tell libtrace what the ERF
framing length on every packet is going to be, so libtrace
doesn't have to repeatedly derive the framing length for each
packet it processes. At high packet rates, the time taken to
do this calculation can really add up and it makes no sense
to risk dropping packets because you're busy calculating a value
that is always a single constant value.

  • Property mode set to 100644
File size: 22.6 KB
Line 
1/*
2 *
3 * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand.
4 * All rights reserved.
5 *
6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/
10 *
11 * libtrace is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * libtrace is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 *
24 *
25 */
26#include "common.h"
27#include "config.h"
28#include "libtrace.h"
29#include "libtrace_int.h"
30#include "format_helper.h"
31
32#include <sys/stat.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <stdbool.h>
39
40/* This format module implements our own, more efficient, version of the PCAP
41 * file format. This should always be used in preference to the "pcap" format
42 * provided in format_pcap.c.
43 *
44 * This is a trace file format and does not implement any live interface
45 * capture. This is covered by "pcapint" in format_pcap.c.
46 *
47 * This format supports both reading and writing, regardless of the version
48 * of your PCAP library.
49 */
50
51#define DATA(x) ((struct pcapfile_format_data_t*)((x)->format_data))
52#define DATAOUT(x) ((struct pcapfile_format_data_out_t*)((x)->format_data))
53#define IN_OPTIONS DATA(libtrace)->options
54
55typedef struct pcapfile_header_t {
56                uint32_t magic_number;   /* magic number */
57                uint16_t version_major;  /* major version number */
58                uint16_t version_minor;  /* minor version number */
59                int32_t  thiszone;       /* GMT to local correction */
60                uint32_t sigfigs;        /* timestamp accuracy */
61                uint32_t snaplen;        /* aka "wirelen" */
62                uint32_t network;        /* data link type */
63} pcapfile_header_t;
64
65#define MAGIC1      0xa1b2c3d4  /* Original */
66#define MAGIC2      0xa1b23c4d  /* Newer nanosecond format */
67#define MAGIC1_REV  0xd4c3b2a1  /* Reversed byteorder detection */
68#define MAGIC2_REV  0x4d3cb2a1
69
70static inline int header_is_backwards_magic(pcapfile_header_t *header) {
71        return (header->magic_number == MAGIC1_REV || header->magic_number == MAGIC2_REV);
72}
73
74static inline int header_is_magic(pcapfile_header_t *header) {
75        return (header->magic_number == MAGIC1 || header->magic_number == MAGIC2 ||
76                header_is_backwards_magic(header));
77}
78
79static inline int trace_in_nanoseconds(pcapfile_header_t *header) {
80        return (header->magic_number == MAGIC2 || header->magic_number == MAGIC2_REV);
81}
82
83struct pcapfile_format_data_t {
84        struct {
85                /* Indicates whether the event API should replicate the pauses
86                 * between packets */
87                int real_time;
88        } options;
89
90        /* The PCAP meta-header that should be written at the start of each
91         * trace */
92        pcapfile_header_t header;
93        /* Indicates whether the input trace is started */
94        bool started;
95};
96
97struct pcapfile_format_data_out_t {
98        iow_t *file;
99        int compress_type;
100        int level;
101        int flag;
102
103};
104
105static int pcapfile_probe_magic(io_t *io)
106{
107        pcapfile_header_t header;
108        int len;
109        len = wandio_peek(io, &header, sizeof(header));
110
111        /* Is this long enough? */
112        if (len < (int)sizeof(header)) {
113                return 0;
114        }
115        /* Pcap magic? */
116        if (header_is_magic(&header)) {
117                return 1;
118        }
119        /* Nope, not pcap */
120        return 0;
121}
122
123
124static int pcapfile_init_input(libtrace_t *libtrace) {
125        libtrace->format_data = malloc(sizeof(struct pcapfile_format_data_t));
126        if (!libtrace->format_data) {
127                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Unable to allocate memory for "
128                        "format data inside pcapfile_init_input()");
129                return -1;
130        }
131
132        IN_OPTIONS.real_time = 0;
133        DATA(libtrace)->started = false;
134        return 0;
135}
136
137static int pcapfile_init_output(libtrace_out_t *libtrace) {
138        libtrace->format_data = 
139                malloc(sizeof(struct pcapfile_format_data_out_t));
140        if (!libtrace->format_data) {
141                trace_set_err_out(libtrace, TRACE_ERR_INIT_FAILED, "Unable to allocate memory for "
142                        "format data inside pcapfile_init_output()");
143                return -1;
144        }
145
146        DATAOUT(libtrace)->file=NULL;
147        DATAOUT(libtrace)->compress_type=TRACE_OPTION_COMPRESSTYPE_NONE;
148        DATAOUT(libtrace)->level=0;
149        DATAOUT(libtrace)->flag=O_CREAT|O_WRONLY;
150
151        return 0;
152}
153
154
155static inline uint16_t swaps(libtrace_t *libtrace, uint16_t num)
156{
157        /* To deal with open_dead traces that might try and use this
158         * if we don't have any per trace data, assume host byte order
159         */
160        if (!DATA(libtrace))
161                return num;
162       
163        /* We can use the PCAP magic number to determine the byte order */
164        if (header_is_backwards_magic(&(DATA(libtrace)->header)))
165                return byteswap16(num);
166
167        return num;
168}
169
170static inline uint32_t swapl(libtrace_t *libtrace, uint32_t num)
171{
172        /* To deal with open_dead traces that might try and use this
173         * if we don't have any per trace data, assume host byte order
174         */
175        if (!DATA(libtrace))
176                return num;
177       
178        /* We can use the PCAP magic number to determine the byte order */
179        if (header_is_backwards_magic(&(DATA(libtrace)->header)))
180                return byteswap32(num);
181
182        return num;
183}
184
185
186static int pcapfile_start_input(libtrace_t *libtrace) 
187{
188        int err;
189
190        if (!libtrace->io) {
191                libtrace->io=trace_open_file(libtrace);
192                DATA(libtrace)->started=false;
193        }
194
195        if (!DATA(libtrace)->started) {
196
197                if (!libtrace->io) {
198                        trace_set_err(libtrace, TRACE_ERR_BAD_IO, "Trace cannot start IO in pcapfile_start_input()");
199                        return -1;
200                }
201
202                err=wandio_read(libtrace->io,
203                                &DATA(libtrace)->header,
204                                sizeof(DATA(libtrace)->header));
205
206                DATA(libtrace)->started = true;
207                if (!(sizeof(DATA(libtrace)->header) > 0)) {
208                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Trace is missing header in pcapfile_start_input()");
209                        return -1;
210                }
211
212                if (err<1) {
213                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
214                                "Error while reading pcap file header\n");
215                        return -1;
216                }
217
218                if (err != (int)sizeof(DATA(libtrace)->header)) {
219                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
220                                "Incomplete pcap file header");
221                        return -1;
222                }
223               
224                if (!header_is_magic(&(DATA(libtrace)->header))) {
225                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,
226                                        "Not a pcap tracefile (magic=%08x)\n",swapl(libtrace,DATA(libtrace)->header.magic_number));
227                        return -1; /* Not a pcap file */
228                }
229
230                if (swaps(libtrace,DATA(libtrace)->header.version_major)!=2
231                        && swaps(libtrace,DATA(libtrace)->header.version_minor)!=4) {
232                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,
233                                        "Unknown pcap tracefile version %d.%d\n",
234                                        swaps(libtrace,
235                                                DATA(libtrace)->header.version_major),
236                                        swaps(libtrace,
237                                                DATA(libtrace)->header.version_minor));
238                        return -1;
239                }
240
241        }
242
243        return 0;
244}
245
246static int pcapfile_start_output(libtrace_out_t *libtrace UNUSED)
247{
248        /* We can't open the output file until we've seen the first packet.
249         * This is because we need to know the DLT to set the "network"
250         * value in the meta-header */
251       
252        return 0;
253}
254
255static int pcapfile_config_input(libtrace_t *libtrace,
256                trace_option_t option,
257                void *data)
258{
259        switch(option) {
260                case TRACE_OPTION_EVENT_REALTIME:
261                        IN_OPTIONS.real_time = *(int *)data;
262                        return 0;
263                case TRACE_OPTION_META_FREQ:
264                case TRACE_OPTION_SNAPLEN:
265                case TRACE_OPTION_PROMISC:
266                case TRACE_OPTION_FILTER:
267                case TRACE_OPTION_HASHER:
268                case TRACE_OPTION_REPLAY_SPEEDUP:
269                case TRACE_OPTION_CONSTANT_ERF_FRAMING:
270                        /* All these are either unsupported or handled
271                         * by trace_config */
272                        break;
273        }
274       
275        trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION,
276                        "Unknown option %i", option);
277        return -1;
278}
279
280static int pcapfile_fin_input(libtrace_t *libtrace) 
281{
282        if (libtrace->io)
283                wandio_destroy(libtrace->io);
284        free(libtrace->format_data);
285        return 0; /* success */
286}
287
288static int pcapfile_fin_output(libtrace_out_t *libtrace)
289{
290        if (DATAOUT(libtrace)->file)
291                wandio_wdestroy(DATAOUT(libtrace)->file);
292        free(libtrace->format_data);
293        libtrace->format_data=NULL;
294        return 0; /* success */
295}
296
297static int pcapfile_config_output(libtrace_out_t *libtrace,
298                trace_option_output_t option,
299                void *value)
300{
301        switch (option) {
302                case TRACE_OPTION_OUTPUT_COMPRESS:
303                        DATAOUT(libtrace)->level = *(int*)value;
304                        return 0;
305                case TRACE_OPTION_OUTPUT_COMPRESSTYPE:
306                        DATAOUT(libtrace)->compress_type = *(int*)value;
307                        return 0;
308                case TRACE_OPTION_OUTPUT_FILEFLAGS:
309                        DATAOUT(libtrace)->flag = *(int*)value;
310                        return 0;
311                default:
312                        /* Unknown option */
313                        trace_set_err_out(libtrace,TRACE_ERR_UNKNOWN_OPTION,
314                                        "Unknown option");
315                        return -1;
316        }
317        return -1;
318}
319
320static int pcapfile_prepare_packet(libtrace_t *libtrace, 
321                libtrace_packet_t *packet, void *buffer, 
322                libtrace_rt_types_t rt_type, uint32_t flags) {
323
324        if (packet->buffer != buffer && 
325                        packet->buf_control == TRACE_CTRL_PACKET) {
326                free(packet->buffer);
327        }
328
329        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
330                packet->buf_control = TRACE_CTRL_PACKET;
331        } else
332                packet->buf_control = TRACE_CTRL_EXTERNAL;
333       
334       
335        packet->buffer = buffer;
336        packet->header = buffer;
337        packet->payload = (char*)packet->buffer
338                + sizeof(libtrace_pcapfile_pkt_hdr_t);
339        packet->type = rt_type; 
340
341        if (libtrace->format_data == NULL) {
342                if (pcapfile_init_input(libtrace))
343                        return -1;
344        }
345       
346        return 0;
347}
348
349static int pcapfile_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet)
350{
351        int err;
352        uint32_t flags = 0;
353        size_t bytes_to_read = 0;
354
355        if (!libtrace->format_data) {
356                trace_set_err(libtrace, TRACE_ERR_BAD_FORMAT, "Trace format data missing, "
357                        "call trace_create() before calling trace_read_packet()");
358                return -1;
359        }
360
361        packet->type = pcap_linktype_to_rt(swapl(libtrace,
362                                DATA(libtrace)->header.network));
363
364        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
365                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
366        }
367
368        flags |= TRACE_PREP_OWN_BUFFER;
369
370        err=wandio_read(libtrace->io,
371                        packet->buffer,
372                        sizeof(libtrace_pcapfile_pkt_hdr_t));
373        if (err<0) {
374                trace_set_err(libtrace,TRACE_ERR_WANDIO_FAILED,"reading packet");
375                return -1;
376        }
377        if (err==0) {
378                /* EOF */
379                return 0;
380        }
381
382        if (err < (int)sizeof(libtrace_pcapfile_pkt_hdr_t)) {
383                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Incomplete pcap packet header");
384                return -1;
385        }
386
387        bytes_to_read = swapl(libtrace,((libtrace_pcapfile_pkt_hdr_t*)packet->buffer)->caplen);
388
389        if (bytes_to_read >= LIBTRACE_PACKET_BUFSIZE) {
390                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid caplen in pcap header (%u) - trace may be corrupt", (uint32_t)bytes_to_read);
391                return -1;
392        }
393
394        /* If there is no payload to read, do not ask wandio_read to try and
395         * read zero bytes - we'll just get back a zero that we will
396         * misinterpret as EOF! */
397        if (bytes_to_read == 0) {
398                packet->header = packet->buffer;
399                return sizeof(libtrace_pcapfile_pkt_hdr_t);
400        }
401
402        err=wandio_read(libtrace->io,
403                        (char*)packet->buffer+sizeof(libtrace_pcapfile_pkt_hdr_t),
404                        (size_t)swapl(libtrace,((libtrace_pcapfile_pkt_hdr_t*)packet->buffer)->caplen)
405                        );
406
407        if (err<0) {
408                trace_set_err(libtrace,TRACE_ERR_WANDIO_FAILED,"reading packet");
409                return -1;
410        }
411        if (err==0) {
412                return 0;
413        }
414
415        if (err < (int)bytes_to_read) {
416                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "Incomplete pcap packet body");
417                return -1;
418        }
419
420        if (pcapfile_prepare_packet(libtrace, packet, packet->buffer,
421                                packet->type, flags)) {
422                return -1;
423        }
424
425        /* We may as well cache this value now, seeing as we already had to
426         * look it up */
427        packet->capture_length = bytes_to_read; 
428        return sizeof(libtrace_pcapfile_pkt_hdr_t) + bytes_to_read;
429}
430
431static int pcapfile_write_packet(libtrace_out_t *out,
432                libtrace_packet_t *packet)
433{
434        struct libtrace_pcapfile_pkt_hdr_t hdr;
435        struct timeval tv = trace_get_timeval(packet);
436        int numbytes;
437        int ret;
438        void *ptr;
439        uint32_t remaining;
440        libtrace_linktype_t linktype;
441
442        ptr = trace_get_packet_buffer(packet,&linktype,&remaining);
443       
444        /* Silently discard RT metadata packets and packets with an
445         * unknown linktype. */
446        if (linktype == TRACE_TYPE_NONDATA || linktype == TRACE_TYPE_UNKNOWN || linktype == TRACE_TYPE_ERF_META || linktype == TRACE_TYPE_CONTENT_INVALID) {
447                return 0;
448        }
449
450        /* If this packet cannot be converted to a pcap linktype then
451         * pop off the top header until it can be converted
452         */
453        while (libtrace_to_pcap_linktype(linktype)==TRACE_DLT_ERROR) {
454                if (!demote_packet(packet)) {
455                        trace_set_err_out(out, 
456                                TRACE_ERR_NO_CONVERSION,
457                                "pcap does not support this format");
458                        return -1;
459                }
460
461                ptr = trace_get_packet_buffer(packet,&linktype,&remaining);
462        }
463
464
465        /* Now we know the link type write out a header if we've not done
466         * so already
467         */
468        if (!DATAOUT(out)->file) {
469                struct pcapfile_header_t pcaphdr;
470
471                DATAOUT(out)->file=trace_open_file_out(out,
472                                DATAOUT(out)->compress_type,
473                                DATAOUT(out)->level,
474                                DATAOUT(out)->flag);
475
476                if (!DATAOUT(out)->file) {
477                        trace_set_err_out(out,errno,"Unable to open file");
478                        return -1;
479                }
480
481                pcaphdr.magic_number = 0xa1b2c3d4;
482                pcaphdr.version_major = 2;
483                pcaphdr.version_minor = 4;
484                pcaphdr.thiszone = 0;
485                pcaphdr.sigfigs = 0;
486                pcaphdr.snaplen = 65536;
487                pcaphdr.network = 
488                        libtrace_to_pcap_linktype(linktype);
489
490                wandio_wwrite(DATAOUT(out)->file, 
491                                &pcaphdr, sizeof(pcaphdr));
492        }
493
494
495        hdr.ts_sec = (uint32_t)tv.tv_sec;
496        hdr.ts_usec = (uint32_t)tv.tv_usec;
497        hdr.caplen = trace_get_capture_length(packet);
498        if (hdr.caplen >= LIBTRACE_PACKET_BUFSIZE) {
499                trace_set_err_out(out, TRACE_ERR_BAD_PACKET, "Capture length is greater than buffer size in pcap_write_packet()");
500                return -1;
501        }
502        /* PCAP doesn't include the FCS in its wire length value, but we do */
503        if (linktype==TRACE_TYPE_ETH) {
504                if (trace_get_wire_length(packet) >= 4) {
505                        hdr.wirelen = trace_get_wire_length(packet)-4;
506                }
507                else {
508                        hdr.wirelen = 0;
509                }
510        }
511        else
512                hdr.wirelen = trace_get_wire_length(packet);
513
514        /* Reason for removing this assert:
515         *
516         * There exist some packets, e.g. in IPLS II, where the wire length
517         * is clearly corrupt. When converting to pcap, we *could* try to
518         * adjust the wire length to something sane but for now, I'll just let
519         * the broken length persist through the conversion.
520         *
521         * XXX Is setting the wire length to zero the best solution in such
522         * cases?
523         */
524
525        /* assert(hdr.wirelen < LIBTRACE_PACKET_BUFSIZE); */
526
527        /* Ensure we have a valid capture length, especially if we're going
528         * to "remove" the FCS from the wire length */
529        if (hdr.caplen > hdr.wirelen)
530                hdr.caplen = hdr.wirelen;
531
532        /* Write the packet header */
533        numbytes=wandio_wwrite(DATAOUT(out)->file,
534                        &hdr, sizeof(hdr));
535
536        if (numbytes!=sizeof(hdr)) 
537                return -1;
538
539        /* Write the rest of the packet now */
540        ret=wandio_wwrite(DATAOUT(out)->file,
541                        ptr,
542                        hdr.caplen);
543
544        if (ret!=(int)hdr.caplen)
545                return -1;
546
547        return numbytes+ret;
548}
549
550static int pcapfile_flush_output(libtrace_out_t *out) {
551
552        return wandio_wflush(DATAOUT(out)->file);
553}
554
555static libtrace_linktype_t pcapfile_get_link_type(
556                const libtrace_packet_t *packet) 
557{
558        return pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type));
559}
560
561static libtrace_direction_t pcapfile_get_direction(const libtrace_packet_t *packet) 
562{
563        /* This function can be found in format_helper.c */
564        return pcap_get_direction(packet);
565}
566
567
568static struct timeval pcapfile_get_timeval(
569                const libtrace_packet_t *packet) 
570{
571        libtrace_pcapfile_pkt_hdr_t *hdr;
572        struct timeval ts;
573
574        if (!packet) {
575                fprintf(stderr, "NULL packet passed to pcapfile_get_timeval()\n");
576                /* Return default timeval on error? */
577                return ts;
578        }
579
580        if (!packet->header) {
581                trace_set_err(packet->trace, TRACE_ERR_BAD_HEADER, "pcap packet with NULL header passed to "
582                        "pcapfile_get_timeval()");
583                /* Return default timeval on error? */
584                return ts;
585        }
586
587        hdr = (libtrace_pcapfile_pkt_hdr_t*)packet->header;
588        ts.tv_sec = swapl(packet->trace,hdr->ts_sec);
589        /* Check trace is not a dummy calling trace_in_nanoseconds */
590        if (DATA(packet->trace) && trace_in_nanoseconds(&DATA(packet->trace)->header))
591                ts.tv_usec = swapl(packet->trace, hdr->ts_usec) / 1000;
592        else
593                ts.tv_usec = swapl(packet->trace,hdr->ts_usec);
594        return ts;
595}
596
597static struct timespec pcapfile_get_timespec(
598                const libtrace_packet_t *packet) 
599{
600        libtrace_pcapfile_pkt_hdr_t *hdr;
601        struct timespec ts;
602
603        if (!packet) {
604                fprintf(stderr, "NULL packet passed to pcapfile_get_timespec()");
605                /* Return default timespec on error? */
606                return ts;
607        }
608
609        if (!packet->header) {
610                trace_set_err(packet->trace, TRACE_ERR_BAD_HEADER, "pcap packet with NULL header passed to "
611                        "pcapfile_get_timespec()");
612                /* Return fefault timespec on error? */
613                return ts;
614        }
615
616        hdr = (libtrace_pcapfile_pkt_hdr_t*)packet->header;
617        ts.tv_sec = swapl(packet->trace,hdr->ts_sec);
618        /* Check trace is not a dummy calling trace_in_nanoseconds */
619        if (DATA(packet->trace) && trace_in_nanoseconds(&DATA(packet->trace)->header))
620                ts.tv_nsec = swapl(packet->trace, hdr->ts_usec);
621        else
622                ts.tv_nsec = swapl(packet->trace, hdr->ts_usec) * 1000;
623        return ts;
624}
625
626
627static int pcapfile_get_capture_length(const libtrace_packet_t *packet) {
628        libtrace_pcapfile_pkt_hdr_t *pcapptr; 
629
630        if (!packet) {
631                fprintf(stderr, "NULL packet passed to pcapfile_get_capture_length()\n");
632                return TRACE_ERR_NULL_PACKET;
633        }
634
635        if (!packet->header) {
636                trace_set_err(packet->trace, TRACE_ERR_BAD_HEADER, "pcap packet with NULL header passed to "
637                        "pcapfile_get_capture_length()");
638                return -1;
639        }
640        pcapptr = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
641
642        return swapl(packet->trace,pcapptr->caplen);
643}
644
645static int pcapfile_get_wire_length(const libtrace_packet_t *packet) {
646        libtrace_pcapfile_pkt_hdr_t *pcapptr;
647
648        if (!packet) {
649                fprintf(stderr, "NULL packet passed to pcapfile_get_wire_length()\n");
650                return TRACE_ERR_NULL_PACKET;
651        }
652
653        if (!packet->header) {
654                trace_set_err(packet->trace, TRACE_ERR_BAD_HEADER, "pcap packet with NULL header passed to "
655                        "pcapfile_get_wire_length()");
656                return -1;
657        }
658
659        pcapptr = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
660        if (packet->type==pcap_linktype_to_rt(TRACE_DLT_EN10MB))
661                /* Include the missing FCS */
662                return swapl(packet->trace,pcapptr->wirelen)+4; 
663        else if (packet->type==pcap_linktype_to_rt(TRACE_DLT_IEEE802_11_RADIO)){
664                /* If the packet is Radiotap and the flags field indicates
665                 * that the FCS is not included in the 802.11 frame, then
666                 * we need to add 4 to the wire-length to account for it.
667                 */
668                uint8_t flags;
669                void *link;
670                libtrace_linktype_t linktype;
671                link = trace_get_packet_buffer(packet, &linktype, NULL);
672                trace_get_wireless_flags(link, linktype, &flags);
673                if ((flags & TRACE_RADIOTAP_F_FCS) == 0)
674                        return swapl(packet->trace,pcapptr->wirelen)+4;
675        } else if (packet->type == pcap_linktype_to_rt(TRACE_DLT_LINUX_SLL)) {
676                libtrace_sll_header_t *sll;
677                sll = (libtrace_sll_header_t *)packet->payload;
678
679                /* Account for FCS when dealing with Ethernet packets that are
680                 * encapsulated in Linux SLL. This should fix the problem
681                 * where the wire lengths differ if we convert the packet to
682                 * ERF */
683                if (ntohs(sll->protocol) == TRACE_ETHERTYPE_LOOPBACK)
684                        return swapl(packet->trace,pcapptr->wirelen)+4;
685        }
686
687        return swapl(packet->trace,pcapptr->wirelen);
688}
689
690static int pcapfile_get_framing_length(const libtrace_packet_t *packet UNUSED) {
691        return sizeof(libtrace_pcapfile_pkt_hdr_t);
692}
693
694static size_t pcapfile_set_capture_length(libtrace_packet_t *packet,size_t size) {
695        libtrace_pcapfile_pkt_hdr_t *pcapptr = 0;
696
697        if (!packet) {
698                fprintf(stderr, "NULL packet passed into pcapfile_set_capture_length\n");
699                /* Return -1 on error? */
700                return ~0U;
701        }
702
703        if (!packet->header) {
704                trace_set_err(packet->trace, TRACE_ERR_BAD_HEADER, "pcap packet with NULL header passed to "
705                        "pcapfile_set_capture_length()");
706                /* Return -1 on error? */
707                return ~0U;
708        }
709        if (size > trace_get_capture_length(packet)) {
710                /* Can't make a packet larger */
711                return trace_get_capture_length(packet);
712        }
713        /* Reset the cached capture length */
714        packet->capture_length = -1;
715        pcapptr = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
716        pcapptr->caplen = swapl(packet->trace,(uint32_t)size);
717        return trace_get_capture_length(packet);
718}
719
720static struct libtrace_eventobj_t pcapfile_event(libtrace_t *libtrace, libtrace_packet_t *packet) {
721       
722        libtrace_eventobj_t event = {0,0,0.0,0};
723       
724        /* If we are being told to replay packets as fast as possible, then
725         * we just need to read and return the next packet in the trace */
726
727        if (IN_OPTIONS.real_time) {
728                event.size = trace_read_packet(libtrace, packet);
729                if (event.size < 1)
730                        event.type = TRACE_EVENT_TERMINATE;
731                else
732                        event.type = TRACE_EVENT_PACKET;
733                return event;
734        } else {
735                return trace_event_trace(libtrace, packet);
736        }
737}
738
739static void pcapfile_help(void) {
740        printf("pcapfile format module: $Revision: 1768 $\n");
741        printf("Supported input URIs:\n");
742        printf("\tpcapfile:/path/to/file\n");
743        printf("\tpcapfile:/path/to/file.gz\n");
744        printf("\n");
745        printf("\te.g.: pcapfile:/tmp/trace.pcap\n");
746        printf("\n");
747}
748
749static struct libtrace_format_t pcapfile = {
750        "pcapfile",
751        "$Id$",
752        TRACE_FORMAT_PCAPFILE,
753        NULL,                           /* probe filename */
754        pcapfile_probe_magic,           /* probe magic */
755        pcapfile_init_input,            /* init_input */
756        pcapfile_config_input,          /* config_input */
757        pcapfile_start_input,           /* start_input */
758        NULL,                           /* pause_input */
759        pcapfile_init_output,           /* init_output */
760        pcapfile_config_output,         /* config_output */
761        pcapfile_start_output,          /* start_output */
762        pcapfile_fin_input,             /* fin_input */
763        pcapfile_fin_output,            /* fin_output */
764        pcapfile_read_packet,           /* read_packet */
765        pcapfile_prepare_packet,        /* prepare_packet */
766        NULL,                           /* fin_packet */
767        pcapfile_write_packet,          /* write_packet */
768        pcapfile_flush_output,          /* flush_output */
769        pcapfile_get_link_type,         /* get_link_type */
770        pcapfile_get_direction,         /* get_direction */
771        NULL,                           /* set_direction */
772        NULL,                           /* get_erf_timestamp */
773        pcapfile_get_timeval,           /* get_timeval */
774        pcapfile_get_timespec,          /* get_timespec */
775        NULL,                           /* get_seconds */
776        NULL,                           /* seek_erf */
777        NULL,                           /* seek_timeval */
778        NULL,                           /* seek_seconds */
779        pcapfile_get_capture_length,    /* get_capture_length */
780        pcapfile_get_wire_length,       /* get_wire_length */
781        pcapfile_get_framing_length,    /* get_framing_length */
782        pcapfile_set_capture_length,    /* set_capture_length */
783        NULL,                           /* get_received_packets */
784        NULL,                           /* get_filtered_packets */
785        NULL,                           /* get_dropped_packets */
786        NULL,                           /* get_statistics */
787        NULL,                           /* get_fd */
788        pcapfile_event,         /* trace_event */
789        pcapfile_help,                  /* help */
790        NULL,                   /* next pointer */
791        NON_PARALLEL(false)
792};
793
794
795void pcapfile_constructor(void) {
796        register_format(&pcapfile);
797}
798
799
Note: See TracBrowser for help on using the repository browser.