source: lib/format_pcapfile.c @ 5cdb37d

develop
Last change on this file since 5cdb37d was 5cdb37d, checked in by GitHub <noreply@…>, 2 years ago

Merge pull request #101 from jacobvw/meta-api

Meta API

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