source: lib/format_pcapfile.c @ d439067

develop
Last change on this file since d439067 was d439067, checked in by Shane Alcock <salcock@…>, 23 months ago

Move packet cached fields into a distinct structure.

This will help tidy up the packet structure a little, as well as
simplify the cache clearing process (and maybe even speed it up
a little).

  • 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->cached.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->cached.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.