source: lib/format_pcapfile.c @ b5a23b3

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