source: lib/format_pcapfile.c @ f0fb38f

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since f0fb38f was f0fb38f, checked in by Shane Alcock <salcock@…>, 14 years ago
  • Added prepare_packet functions to all formats, primarily to support translating RT packets into the appropriate format. These functions are all used internally as well, as most formats still need to "prepare" packets that have been read by setting pointers, updating loss counters etc.
  • Also added a trace_prepare_packet function, but this is not made available externally at this stage
  • Added init_format_data functions to some formats to initialise format data structures in cases where the init_trace function does more than just that
  • Refactored rt packet reading code to use the new trace_prepare_packet functionality - also did a lot of tidying of the code
  • Added missing RT type for BPF format
  • Property mode set to 100644
File size: 15.4 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
45#define DATA(x) ((struct pcapfile_format_data_t*)((x)->format_data))
46#define DATAOUT(x) ((struct pcapfile_format_data_out_t*)((x)->format_data))
47#define IN_OPTIONS DATA(libtrace)->options
48
49typedef struct pcapfile_header_t {
50                uint32_t magic_number;   /* magic number */
51                uint16_t version_major;  /* major version number */
52                uint16_t version_minor;  /* minor version number */
53                int32_t  thiszone;       /* GMT to local correction */
54                uint32_t sigfigs;        /* timestamp accuracy */
55                uint32_t snaplen;        /* aka "wirelen" */
56                uint32_t network;        /* data link type */
57} pcapfile_header_t; 
58
59struct pcapfile_format_data_t {
60        libtrace_io_t *file;
61        struct {
62                int real_time;
63        } options;
64        pcapfile_header_t header;
65};
66
67struct pcapfile_format_data_out_t {
68        libtrace_io_t *file;
69        int level;
70        int flag;
71
72};
73
74static int pcapfile_init_input(libtrace_t *libtrace) {
75        libtrace->format_data = malloc(sizeof(struct pcapfile_format_data_t));
76
77        if (libtrace->format_data == NULL) {
78                trace_set_err(libtrace,ENOMEM,"Out of memory");
79                return -1;
80        }
81
82        DATA(libtrace)->file=NULL;
83        IN_OPTIONS.real_time = 0;
84        return 0;
85}
86
87static int pcapfile_init_output(libtrace_out_t *libtrace) {
88        libtrace->format_data = 
89                malloc(sizeof(struct pcapfile_format_data_out_t));
90
91        DATAOUT(libtrace)->file=NULL;
92        DATAOUT(libtrace)->level=0;
93        DATAOUT(libtrace)->flag=O_CREAT|O_WRONLY;
94
95        return 0;
96}
97
98static uint16_t swaps(libtrace_t *libtrace, uint16_t num)
99{
100        /* to deal with open_dead traces that might try and use this
101         * if we don't have any per trace data, assume host byte order
102         */
103        if (!DATA(libtrace))
104                return num;
105        if (DATA(libtrace)->header.magic_number == 0xd4c3b2a1)
106                return byteswap16(num);
107
108        return num;
109}
110
111static uint32_t swapl(libtrace_t *libtrace, uint32_t num)
112{
113        /* to deal with open_dead traces that might try and use this
114         * if we don't have any per trace data, assume host byte order
115         */
116        if (!DATA(libtrace))
117                return num;
118        if (DATA(libtrace)->header.magic_number == 0xd4c3b2a1)
119                return byteswap32(num);
120
121        return num;
122}
123
124
125static int pcapfile_start_input(libtrace_t *libtrace) 
126{
127        int err;
128
129        if (!DATA(libtrace)->file) {
130                DATA(libtrace)->file=trace_open_file(libtrace);
131
132                if (!DATA(libtrace)->file)
133                        return -1;
134
135                err=libtrace_io_read(DATA(libtrace)->file,
136                                &DATA(libtrace)->header,
137                                sizeof(DATA(libtrace)->header));
138
139                if (err<1)
140                        return -1;
141               
142                if (swapl(libtrace,DATA(libtrace)->header.magic_number) != 0xa1b2c3d4) {
143                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"Not a pcap tracefile\n");
144                        return -1; /* Not a pcap file */
145                }
146
147                if (swaps(libtrace,DATA(libtrace)->header.version_major)!=2
148                        && swaps(libtrace,DATA(libtrace)->header.version_minor)!=4) {
149                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"Unknown pcap tracefile version %d.%d\n",
150                                        swaps(libtrace,
151                                                DATA(libtrace)->header.version_major),
152                                        swaps(libtrace,
153                                                DATA(libtrace)->header.version_minor));
154                        return -1;
155                }
156
157        }
158
159        return 0;
160}
161
162static int pcapfile_start_output(libtrace_out_t *libtrace UNUSED)
163{
164        return 0;
165}
166
167static int pcapfile_config_input(libtrace_t *libtrace,
168                trace_option_t option,
169                void *data)
170{
171        switch(option) {
172                case TRACE_OPTION_EVENT_REALTIME:
173                        IN_OPTIONS.real_time = *(int *)data;
174                        return 0;
175                case TRACE_OPTION_META_FREQ:
176                case TRACE_OPTION_SNAPLEN:
177                case TRACE_OPTION_PROMISC:
178                case TRACE_OPTION_FILTER:
179                        /* all these are either unsupported or handled
180                         * by trace_config */
181                        break;
182        }
183       
184        trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION,
185                        "Unknown option %i", option);
186        return -1;
187}
188
189static int pcapfile_fin_input(libtrace_t *libtrace) 
190{
191        libtrace_io_close(DATA(libtrace)->file);
192        free(libtrace->format_data);
193        return 0; /* success */
194}
195
196static int pcapfile_fin_output(libtrace_out_t *libtrace)
197{
198        if (DATA(libtrace)->file)
199                libtrace_io_close(DATA(libtrace)->file);
200        free(libtrace->format_data);
201        libtrace->format_data=NULL;
202        return 0; /* success */
203}
204
205static int pcapfile_config_output(libtrace_out_t *libtrace,
206                trace_option_output_t option,
207                void *value)
208{
209        switch (option) {
210                case TRACE_OPTION_OUTPUT_COMPRESS:
211                        DATAOUT(libtrace)->level = *(int*)value;
212                        return 0;
213                case TRACE_OPTION_OUTPUT_FILEFLAGS:
214                        DATAOUT(libtrace)->flag = *(int*)value;
215                        return 0;
216                default:
217                        /* Unknown option */
218                        trace_set_err_out(libtrace,TRACE_ERR_UNKNOWN_OPTION,
219                                        "Unknown option");
220                        return -1;
221        }
222        return -1;
223}
224
225static int pcapfile_prepare_packet(libtrace_t *libtrace, 
226                libtrace_packet_t *packet, void *buffer, 
227                libtrace_rt_types_t rt_type, uint32_t flags) {
228
229        if (packet->buffer != buffer && 
230                        packet->buf_control == TRACE_CTRL_PACKET) {
231                free(packet->buffer);
232        }
233
234        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
235                packet->buf_control = TRACE_CTRL_PACKET;
236        } else
237                packet->buf_control = TRACE_CTRL_EXTERNAL;
238       
239       
240        packet->buffer = buffer;
241        packet->header = buffer;
242        packet->payload = (char*)packet->buffer
243                + sizeof(libtrace_pcapfile_pkt_hdr_t);
244        packet->type = rt_type; 
245
246        if (libtrace->format_data == NULL) {
247                if (pcapfile_init_input(libtrace))
248                        return -1;
249        }
250       
251        return 0;
252}
253
254static int pcapfile_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet)
255{
256        int err;
257        uint32_t flags = 0;
258       
259        assert(libtrace->format_data);
260
261        packet->type = pcap_linktype_to_rt(swapl(libtrace,
262                                DATA(libtrace)->header.network));
263
264        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
265                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
266        }
267
268        flags |= TRACE_PREP_OWN_BUFFER;
269       
270        err=libtrace_io_read(DATA(libtrace)->file,
271                        packet->buffer,
272                        sizeof(libtrace_pcapfile_pkt_hdr_t));
273
274        if (err<0) {
275                trace_set_err(libtrace,errno,"reading packet");
276                return -1;
277        }
278        if (err==0) {
279                /* EOF */
280                return 0;
281        }
282
283        err=libtrace_io_read(DATA(libtrace)->file,
284                        (char*)packet->buffer+sizeof(libtrace_pcapfile_pkt_hdr_t),
285                        (size_t)swapl(libtrace,((libtrace_pcapfile_pkt_hdr_t*)packet->buffer)->caplen)
286                        );
287
288       
289        if (err<0) {
290                trace_set_err(libtrace,errno,"reading packet");
291                return -1;
292        }
293        if (err==0) {
294                return 0;
295        }
296
297        if (pcapfile_prepare_packet(libtrace, packet, packet->buffer,
298                                packet->type, flags)) {
299                return -1;
300        }
301       
302        return sizeof(libtrace_pcapfile_pkt_hdr_t)
303                +swapl(libtrace,((libtrace_pcapfile_pkt_hdr_t*)packet->buffer)->caplen);
304}
305
306static int pcapfile_write_packet(libtrace_out_t *out,
307                libtrace_packet_t *packet)
308{
309        struct libtrace_pcapfile_pkt_hdr_t hdr;
310        struct timeval tv = trace_get_timeval(packet);
311        int numbytes;
312        int ret;
313        void *ptr;
314        uint32_t remaining;
315        libtrace_linktype_t linktype;
316
317        ptr = trace_get_packet_buffer(packet,&linktype,&remaining);
318       
319        /* Silently discard RT metadata packets and packets with an
320         * unknown linktype. */
321        if (linktype == TRACE_TYPE_METADATA || linktype == -1) {
322                return 0;
323        }
324
325        /* If this packet cannot be converted to a pcap linktype then
326         * pop off the top header until it can be converted
327         */
328        while (libtrace_to_pcap_linktype(linktype)==~0U) {
329                if (!demote_packet(packet)) {
330                        trace_set_err_out(out, 
331                                TRACE_ERR_NO_CONVERSION,
332                                "pcap does not support this format");
333                        return -1;
334                }
335
336                ptr = trace_get_packet_buffer(packet,&linktype,&remaining);
337        }
338
339
340        /* Now we know the link type write out a header if we've not done
341         * so already
342         */
343        if (!DATAOUT(out)->file) {
344                struct pcapfile_header_t pcaphdr;
345
346                DATAOUT(out)->file=trace_open_file_out(out,
347                                DATAOUT(out)->level,
348                                DATAOUT(out)->flag);
349                if (!DATAOUT(out)->file)
350                        return -1;
351
352                pcaphdr.magic_number = 0xa1b2c3d4;
353                pcaphdr.version_major = 2;
354                pcaphdr.version_minor = 4;
355                pcaphdr.thiszone = 0;
356                pcaphdr.sigfigs = 0;
357                pcaphdr.snaplen = 65536;
358                pcaphdr.network = 
359                        libtrace_to_pcap_linktype(linktype);
360
361                libtrace_io_write(DATAOUT(out)->file, 
362                                &pcaphdr, sizeof(pcaphdr));
363        }
364
365        hdr.ts_sec = tv.tv_sec;
366        hdr.ts_usec = tv.tv_usec;
367        hdr.caplen = trace_get_capture_length(packet);
368        /* PCAP doesn't include the FCS, we do */
369        if (linktype==TRACE_TYPE_ETH)
370                if (trace_get_wire_length(packet) >= 4) {
371                        hdr.wirelen = trace_get_wire_length(packet)-4;
372                }
373                else {
374                        hdr.wirelen = 0;
375                }
376        else
377                hdr.wirelen = trace_get_wire_length(packet);
378
379
380        numbytes=libtrace_io_write(DATAOUT(out)->file,
381                        &hdr, sizeof(hdr));
382
383        if (numbytes!=sizeof(hdr)) 
384                return -1;
385
386        ret=libtrace_io_write(DATAOUT(out)->file,
387                        ptr,
388                        remaining);
389
390        if (ret!=(int)remaining)
391                return -1;
392
393        return numbytes+ret;
394}
395
396static libtrace_linktype_t pcapfile_get_link_type(
397                const libtrace_packet_t *packet) 
398{
399#if 0
400        return pcap_linktype_to_libtrace(
401                        swapl(packet->trace,
402                                DATA(packet->trace)->header.network
403                             )
404                        );
405#endif
406        return pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type));
407}
408
409static libtrace_direction_t pcapfile_get_direction(const libtrace_packet_t *packet) 
410{
411        libtrace_direction_t direction  = -1;
412        switch(pcapfile_get_link_type(packet)) {
413                case TRACE_TYPE_LINUX_SLL:
414                {
415                        libtrace_sll_header_t *sll;
416                        libtrace_linktype_t linktype;
417
418                        sll = (libtrace_sll_header_t*)trace_get_packet_buffer(
419                                        packet,
420                                        &linktype,
421                                        NULL);
422                        if (!sll) {
423                                trace_set_err(packet->trace,
424                                        TRACE_ERR_BAD_PACKET,
425                                                "Bad or missing packet");
426                                return -1;
427                        }
428                        /* 0 == LINUX_SLL_HOST */
429                        /* the Waikato Capture point defines "packets
430                         * originating locally" (ie, outbound), with a
431                         * direction of 0, and "packets destined locally"
432                         * (ie, inbound), with a direction of 1.
433                         * This is kind-of-opposite to LINUX_SLL.
434                         * We return consistent values here, however
435                         *
436                         * Note that in recent versions of pcap, you can
437                         * use "inbound" and "outbound" on ppp in linux
438                         */
439                        if (ntohs(sll->pkttype == 0)) {
440                                direction = TRACE_DIR_INCOMING;
441                        } else {
442                                direction = TRACE_DIR_OUTGOING;
443                        }
444                        break;
445
446                }
447                case TRACE_TYPE_PFLOG:
448                {
449                        libtrace_pflog_header_t *pflog;
450                        libtrace_linktype_t linktype;
451
452                        pflog=(libtrace_pflog_header_t*)trace_get_packet_buffer(
453                                        packet,&linktype,NULL);
454                        if (!pflog) {
455                                trace_set_err(packet->trace,
456                                                TRACE_ERR_BAD_PACKET,
457                                                "Bad or missing packet");
458                                return -1;
459                        }
460                        /* enum    { PF_IN=0, PF_OUT=1 }; */
461                        if (ntohs(pflog->dir==0)) {
462
463                                direction = TRACE_DIR_INCOMING;
464                        }
465                        else {
466                                direction = TRACE_DIR_OUTGOING;
467                        }
468                        break;
469                }
470                default:
471                        break;
472        }       
473        return direction;
474}
475
476
477static struct timeval pcapfile_get_timeval(
478                const libtrace_packet_t *packet) 
479{
480        libtrace_pcapfile_pkt_hdr_t *hdr =
481                (libtrace_pcapfile_pkt_hdr_t*)packet->header;
482        struct timeval ts;
483        ts.tv_sec = swapl(packet->trace,hdr->ts_sec);
484        ts.tv_usec = swapl(packet->trace,hdr->ts_usec);
485        return ts;
486}
487
488
489static int pcapfile_get_capture_length(const libtrace_packet_t *packet) {
490        libtrace_pcapfile_pkt_hdr_t *pcapptr
491                = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
492
493        return swapl(packet->trace,pcapptr->caplen);
494}
495
496static int pcapfile_get_wire_length(const libtrace_packet_t *packet) {
497        libtrace_pcapfile_pkt_hdr_t *pcapptr
498                = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
499        if (packet->type==pcap_linktype_to_rt(TRACE_DLT_EN10MB))
500                /* Include the missing FCS */
501                return swapl(packet->trace,pcapptr->wirelen)+4; 
502        else if (packet->type==pcap_linktype_to_rt(TRACE_DLT_IEEE802_11_RADIO)){
503                /* If the packet is Radiotap and the flags field indicates
504                 * that the FCS is not included in the 802.11 frame, then
505                 * we need to add 4 to the wire-length to account for it.
506                 */
507                uint8_t flags;
508                void *link;
509                libtrace_linktype_t linktype;
510                link = trace_get_packet_buffer(packet, &linktype, NULL);
511                trace_get_wireless_flags(link, linktype, &flags);
512                if ((flags & TRACE_RADIOTAP_F_FCS) == 0)
513                        return swapl(packet->trace,pcapptr->wirelen)+4;
514        }
515        return swapl(packet->trace,pcapptr->wirelen);
516}
517
518static int pcapfile_get_framing_length(const libtrace_packet_t *packet UNUSED) {
519        return sizeof(libtrace_pcapfile_pkt_hdr_t);
520}
521
522static size_t pcapfile_set_capture_length(libtrace_packet_t *packet,size_t size) {
523        libtrace_pcapfile_pkt_hdr_t *pcapptr = 0;
524        assert(packet);
525        if (size > trace_get_capture_length(packet)) {
526                /* can't make a packet larger */
527                return trace_get_capture_length(packet);
528        }
529        /* Reset the cached capture length */
530        packet->capture_length = -1;
531        pcapptr = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
532        pcapptr->caplen = swapl(packet->trace,(uint32_t)size);
533        return trace_get_capture_length(packet);
534}
535
536static struct libtrace_eventobj_t pcapfile_event(libtrace_t *libtrace, libtrace_packet_t *packet) {
537       
538        libtrace_eventobj_t event = {0,0,0.0,0};
539       
540        if (IN_OPTIONS.real_time) {
541                event.size = pcapfile_read_packet(libtrace, packet);
542                if (event.size < 1)
543                        event.type = TRACE_EVENT_TERMINATE;
544                else
545                        event.type = TRACE_EVENT_PACKET;
546                return event;
547        } else {
548                return trace_event_trace(libtrace, packet);
549        }
550}
551
552static void pcapfile_help(void) {
553        printf("pcapfile format module: $Revision$\n");
554        printf("Supported input URIs:\n");
555        printf("\tpcapfile:/path/to/file\n");
556        printf("\tpcapfile:/path/to/file.gz\n");
557        printf("\n");
558        printf("\te.g.: pcapfile:/tmp/trace.pcap\n");
559        printf("\n");
560}
561
562static struct libtrace_format_t pcapfile = {
563        "pcapfile",
564        "$Id$",
565        TRACE_FORMAT_PCAPFILE,
566        pcapfile_init_input,            /* init_input */
567        pcapfile_config_input,          /* config_input */
568        pcapfile_start_input,           /* start_input */
569        NULL,                           /* pause_input */
570        pcapfile_init_output,           /* init_output */
571        pcapfile_config_output,         /* config_output */
572        pcapfile_start_output,          /* start_output */
573        pcapfile_fin_input,             /* fin_input */
574        pcapfile_fin_output,            /* fin_output */
575        pcapfile_read_packet,           /* read_packet */
576        pcapfile_prepare_packet,        /* prepare_packet */
577        NULL,                           /* fin_packet */
578        pcapfile_write_packet,          /* write_packet */
579        pcapfile_get_link_type,         /* get_link_type */
580        pcapfile_get_direction,         /* get_direction */
581        NULL,                           /* set_direction */
582        NULL,                           /* get_erf_timestamp */
583        pcapfile_get_timeval,           /* get_timeval */
584        NULL,                           /* get_seconds */
585        NULL,                           /* seek_erf */
586        NULL,                           /* seek_timeval */
587        NULL,                           /* seek_seconds */
588        pcapfile_get_capture_length,    /* get_capture_length */
589        pcapfile_get_wire_length,       /* get_wire_length */
590        pcapfile_get_framing_length,    /* get_framing_length */
591        pcapfile_set_capture_length,    /* set_capture_length */
592        NULL,                           /* get_received_packets */
593        NULL,                           /* get_filtered_packets */
594        NULL,                           /* get_dropped_packets */
595        NULL,                           /* get_captured_packets */
596        NULL,                           /* get_fd */
597        trace_event_trace,              /* trace_event */
598        pcapfile_help,                  /* help */
599        NULL                            /* next pointer */
600};
601
602
603void pcapfile_constructor(void) {
604        register_format(&pcapfile);
605}
606
607
Note: See TracBrowser for help on using the repository browser.