source: lib/format_pcapfile.c @ 5c4e0c0

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 5c4e0c0 was 5c4e0c0, checked in by Perry Lorier <perry@…>, 13 years ago

Be more aggressive in looking for bad packets.

  • Property mode set to 100644
File size: 15.6 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        if (DATA(libtrace)->file)
192                libtrace_io_close(DATA(libtrace)->file);
193        free(libtrace->format_data);
194        return 0; /* success */
195}
196
197static int pcapfile_fin_output(libtrace_out_t *libtrace)
198{
199        if (DATA(libtrace)->file)
200                libtrace_io_close(DATA(libtrace)->file);
201        free(libtrace->format_data);
202        libtrace->format_data=NULL;
203        return 0; /* success */
204}
205
206static int pcapfile_config_output(libtrace_out_t *libtrace,
207                trace_option_output_t option,
208                void *value)
209{
210        switch (option) {
211                case TRACE_OPTION_OUTPUT_COMPRESS:
212                        DATAOUT(libtrace)->level = *(int*)value;
213                        return 0;
214                case TRACE_OPTION_OUTPUT_FILEFLAGS:
215                        DATAOUT(libtrace)->flag = *(int*)value;
216                        return 0;
217                default:
218                        /* Unknown option */
219                        trace_set_err_out(libtrace,TRACE_ERR_UNKNOWN_OPTION,
220                                        "Unknown option");
221                        return -1;
222        }
223        return -1;
224}
225
226static int pcapfile_prepare_packet(libtrace_t *libtrace, 
227                libtrace_packet_t *packet, void *buffer, 
228                libtrace_rt_types_t rt_type, uint32_t flags) {
229
230        if (packet->buffer != buffer && 
231                        packet->buf_control == TRACE_CTRL_PACKET) {
232                free(packet->buffer);
233        }
234
235        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
236                packet->buf_control = TRACE_CTRL_PACKET;
237        } else
238                packet->buf_control = TRACE_CTRL_EXTERNAL;
239       
240       
241        packet->buffer = buffer;
242        packet->header = buffer;
243        packet->payload = (char*)packet->buffer
244                + sizeof(libtrace_pcapfile_pkt_hdr_t);
245        packet->type = rt_type; 
246
247        if (libtrace->format_data == NULL) {
248                if (pcapfile_init_input(libtrace))
249                        return -1;
250        }
251       
252        return 0;
253}
254
255static int pcapfile_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet)
256{
257        int err;
258        uint32_t flags = 0;
259       
260        assert(libtrace->format_data);
261
262        packet->type = pcap_linktype_to_rt(swapl(libtrace,
263                                DATA(libtrace)->header.network));
264
265        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
266                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
267        }
268
269        flags |= TRACE_PREP_OWN_BUFFER;
270       
271        err=libtrace_io_read(DATA(libtrace)->file,
272                        packet->buffer,
273                        sizeof(libtrace_pcapfile_pkt_hdr_t));
274
275        assert(swapl(libtrace,((libtrace_pcapfile_pkt_hdr_t*)packet->buffer)->caplen)<LIBTRACE_PACKET_BUFSIZE);
276
277        if (err<0) {
278                trace_set_err(libtrace,errno,"reading packet");
279                return -1;
280        }
281        if (err==0) {
282                /* EOF */
283                return 0;
284        }
285
286        err=libtrace_io_read(DATA(libtrace)->file,
287                        (char*)packet->buffer+sizeof(libtrace_pcapfile_pkt_hdr_t),
288                        (size_t)swapl(libtrace,((libtrace_pcapfile_pkt_hdr_t*)packet->buffer)->caplen)
289                        );
290
291       
292        if (err<0) {
293                trace_set_err(libtrace,errno,"reading packet");
294                return -1;
295        }
296        if (err==0) {
297                return 0;
298        }
299
300        if (pcapfile_prepare_packet(libtrace, packet, packet->buffer,
301                                packet->type, flags)) {
302                return -1;
303        }
304       
305        return sizeof(libtrace_pcapfile_pkt_hdr_t)
306                +swapl(libtrace,((libtrace_pcapfile_pkt_hdr_t*)packet->buffer)->caplen);
307}
308
309static int pcapfile_write_packet(libtrace_out_t *out,
310                libtrace_packet_t *packet)
311{
312        struct libtrace_pcapfile_pkt_hdr_t hdr;
313        struct timeval tv = trace_get_timeval(packet);
314        int numbytes;
315        int ret;
316        void *ptr;
317        uint32_t remaining;
318        libtrace_linktype_t linktype;
319
320        ptr = trace_get_packet_buffer(packet,&linktype,&remaining);
321       
322        /* Silently discard RT metadata packets and packets with an
323         * unknown linktype. */
324        if (linktype == TRACE_TYPE_METADATA || linktype == -1) {
325                return 0;
326        }
327
328        /* If this packet cannot be converted to a pcap linktype then
329         * pop off the top header until it can be converted
330         */
331        while (libtrace_to_pcap_linktype(linktype)==~0U) {
332                if (!demote_packet(packet)) {
333                        trace_set_err_out(out, 
334                                TRACE_ERR_NO_CONVERSION,
335                                "pcap does not support this format");
336                        return -1;
337                }
338
339                ptr = trace_get_packet_buffer(packet,&linktype,&remaining);
340        }
341
342
343        /* Now we know the link type write out a header if we've not done
344         * so already
345         */
346        if (!DATAOUT(out)->file) {
347                struct pcapfile_header_t pcaphdr;
348
349                DATAOUT(out)->file=trace_open_file_out(out,
350                                DATAOUT(out)->level,
351                                DATAOUT(out)->flag);
352                if (!DATAOUT(out)->file)
353                        return -1;
354
355                pcaphdr.magic_number = 0xa1b2c3d4;
356                pcaphdr.version_major = 2;
357                pcaphdr.version_minor = 4;
358                pcaphdr.thiszone = 0;
359                pcaphdr.sigfigs = 0;
360                pcaphdr.snaplen = 65536;
361                pcaphdr.network = 
362                        libtrace_to_pcap_linktype(linktype);
363
364                libtrace_io_write(DATAOUT(out)->file, 
365                                &pcaphdr, sizeof(pcaphdr));
366        }
367
368        hdr.ts_sec = tv.tv_sec;
369        hdr.ts_usec = tv.tv_usec;
370        hdr.caplen = trace_get_capture_length(packet);
371        assert(hdr.caplen < LIBTRACE_PACKET_BUFSIZE);
372        /* PCAP doesn't include the FCS, we do */
373        if (linktype==TRACE_TYPE_ETH)
374                if (trace_get_wire_length(packet) >= 4) {
375                        hdr.wirelen = trace_get_wire_length(packet)-4;
376                }
377                else {
378                        hdr.wirelen = 0;
379                }
380        else
381                hdr.wirelen = trace_get_wire_length(packet);
382
383        assert(hdr.wirelen < LIBTRACE_PACKET_BUFSIZE);
384
385
386        numbytes=libtrace_io_write(DATAOUT(out)->file,
387                        &hdr, sizeof(hdr));
388
389        if (numbytes!=sizeof(hdr)) 
390                return -1;
391
392        ret=libtrace_io_write(DATAOUT(out)->file,
393                        ptr,
394                        remaining);
395
396        if (ret!=(int)remaining)
397                return -1;
398
399        return numbytes+ret;
400}
401
402static libtrace_linktype_t pcapfile_get_link_type(
403                const libtrace_packet_t *packet) 
404{
405#if 0
406        return pcap_linktype_to_libtrace(
407                        swapl(packet->trace,
408                                DATA(packet->trace)->header.network
409                             )
410                        );
411#endif
412        return pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type));
413}
414
415static libtrace_direction_t pcapfile_get_direction(const libtrace_packet_t *packet) 
416{
417        libtrace_direction_t direction  = -1;
418        switch(pcapfile_get_link_type(packet)) {
419                case TRACE_TYPE_LINUX_SLL:
420                {
421                        libtrace_sll_header_t *sll;
422                        libtrace_linktype_t linktype;
423
424                        sll = (libtrace_sll_header_t*)trace_get_packet_buffer(
425                                        packet,
426                                        &linktype,
427                                        NULL);
428                        if (!sll) {
429                                trace_set_err(packet->trace,
430                                        TRACE_ERR_BAD_PACKET,
431                                                "Bad or missing packet");
432                                return -1;
433                        }
434                        /* 0 == LINUX_SLL_HOST */
435                        /* the Waikato Capture point defines "packets
436                         * originating locally" (ie, outbound), with a
437                         * direction of 0, and "packets destined locally"
438                         * (ie, inbound), with a direction of 1.
439                         * This is kind-of-opposite to LINUX_SLL.
440                         * We return consistent values here, however
441                         *
442                         * Note that in recent versions of pcap, you can
443                         * use "inbound" and "outbound" on ppp in linux
444                         */
445                        if (ntohs(sll->pkttype == 0)) {
446                                direction = TRACE_DIR_INCOMING;
447                        } else {
448                                direction = TRACE_DIR_OUTGOING;
449                        }
450                        break;
451
452                }
453                case TRACE_TYPE_PFLOG:
454                {
455                        libtrace_pflog_header_t *pflog;
456                        libtrace_linktype_t linktype;
457
458                        pflog=(libtrace_pflog_header_t*)trace_get_packet_buffer(
459                                        packet,&linktype,NULL);
460                        if (!pflog) {
461                                trace_set_err(packet->trace,
462                                                TRACE_ERR_BAD_PACKET,
463                                                "Bad or missing packet");
464                                return -1;
465                        }
466                        /* enum    { PF_IN=0, PF_OUT=1 }; */
467                        if (ntohs(pflog->dir==0)) {
468
469                                direction = TRACE_DIR_INCOMING;
470                        }
471                        else {
472                                direction = TRACE_DIR_OUTGOING;
473                        }
474                        break;
475                }
476                default:
477                        break;
478        }       
479        return direction;
480}
481
482
483static struct timeval pcapfile_get_timeval(
484                const libtrace_packet_t *packet) 
485{
486        libtrace_pcapfile_pkt_hdr_t *hdr =
487                (libtrace_pcapfile_pkt_hdr_t*)packet->header;
488        struct timeval ts;
489        ts.tv_sec = swapl(packet->trace,hdr->ts_sec);
490        ts.tv_usec = swapl(packet->trace,hdr->ts_usec);
491        return ts;
492}
493
494
495static int pcapfile_get_capture_length(const libtrace_packet_t *packet) {
496        libtrace_pcapfile_pkt_hdr_t *pcapptr
497                = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
498
499        return swapl(packet->trace,pcapptr->caplen);
500}
501
502static int pcapfile_get_wire_length(const libtrace_packet_t *packet) {
503        libtrace_pcapfile_pkt_hdr_t *pcapptr
504                = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
505        if (packet->type==pcap_linktype_to_rt(TRACE_DLT_EN10MB))
506                /* Include the missing FCS */
507                return swapl(packet->trace,pcapptr->wirelen)+4; 
508        else if (packet->type==pcap_linktype_to_rt(TRACE_DLT_IEEE802_11_RADIO)){
509                /* If the packet is Radiotap and the flags field indicates
510                 * that the FCS is not included in the 802.11 frame, then
511                 * we need to add 4 to the wire-length to account for it.
512                 */
513                uint8_t flags;
514                void *link;
515                libtrace_linktype_t linktype;
516                link = trace_get_packet_buffer(packet, &linktype, NULL);
517                trace_get_wireless_flags(link, linktype, &flags);
518                if ((flags & TRACE_RADIOTAP_F_FCS) == 0)
519                        return swapl(packet->trace,pcapptr->wirelen)+4;
520        }
521        return swapl(packet->trace,pcapptr->wirelen);
522}
523
524static int pcapfile_get_framing_length(const libtrace_packet_t *packet UNUSED) {
525        return sizeof(libtrace_pcapfile_pkt_hdr_t);
526}
527
528static size_t pcapfile_set_capture_length(libtrace_packet_t *packet,size_t size) {
529        libtrace_pcapfile_pkt_hdr_t *pcapptr = 0;
530        assert(packet);
531        if (size > trace_get_capture_length(packet)) {
532                /* can't make a packet larger */
533                return trace_get_capture_length(packet);
534        }
535        /* Reset the cached capture length */
536        packet->capture_length = -1;
537        pcapptr = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
538        pcapptr->caplen = swapl(packet->trace,(uint32_t)size);
539        return trace_get_capture_length(packet);
540}
541
542static struct libtrace_eventobj_t pcapfile_event(libtrace_t *libtrace, libtrace_packet_t *packet) {
543       
544        libtrace_eventobj_t event = {0,0,0.0,0};
545       
546        if (IN_OPTIONS.real_time) {
547                event.size = pcapfile_read_packet(libtrace, packet);
548                if (event.size < 1)
549                        event.type = TRACE_EVENT_TERMINATE;
550                else
551                        event.type = TRACE_EVENT_PACKET;
552                return event;
553        } else {
554                return trace_event_trace(libtrace, packet);
555        }
556}
557
558static void pcapfile_help(void) {
559        printf("pcapfile format module: $Revision$\n");
560        printf("Supported input URIs:\n");
561        printf("\tpcapfile:/path/to/file\n");
562        printf("\tpcapfile:/path/to/file.gz\n");
563        printf("\n");
564        printf("\te.g.: pcapfile:/tmp/trace.pcap\n");
565        printf("\n");
566}
567
568static struct libtrace_format_t pcapfile = {
569        "pcapfile",
570        "$Id$",
571        TRACE_FORMAT_PCAPFILE,
572        pcapfile_init_input,            /* init_input */
573        pcapfile_config_input,          /* config_input */
574        pcapfile_start_input,           /* start_input */
575        NULL,                           /* pause_input */
576        pcapfile_init_output,           /* init_output */
577        pcapfile_config_output,         /* config_output */
578        pcapfile_start_output,          /* start_output */
579        pcapfile_fin_input,             /* fin_input */
580        pcapfile_fin_output,            /* fin_output */
581        pcapfile_read_packet,           /* read_packet */
582        pcapfile_prepare_packet,        /* prepare_packet */
583        NULL,                           /* fin_packet */
584        pcapfile_write_packet,          /* write_packet */
585        pcapfile_get_link_type,         /* get_link_type */
586        pcapfile_get_direction,         /* get_direction */
587        NULL,                           /* set_direction */
588        NULL,                           /* get_erf_timestamp */
589        pcapfile_get_timeval,           /* get_timeval */
590        NULL,                           /* get_seconds */
591        NULL,                           /* seek_erf */
592        NULL,                           /* seek_timeval */
593        NULL,                           /* seek_seconds */
594        pcapfile_get_capture_length,    /* get_capture_length */
595        pcapfile_get_wire_length,       /* get_wire_length */
596        pcapfile_get_framing_length,    /* get_framing_length */
597        pcapfile_set_capture_length,    /* set_capture_length */
598        NULL,                           /* get_received_packets */
599        NULL,                           /* get_filtered_packets */
600        NULL,                           /* get_dropped_packets */
601        NULL,                           /* get_captured_packets */
602        NULL,                           /* get_fd */
603        trace_event_trace,              /* trace_event */
604        pcapfile_help,                  /* help */
605        NULL                            /* next pointer */
606};
607
608
609void pcapfile_constructor(void) {
610        register_format(&pcapfile);
611}
612
613
Note: See TracBrowser for help on using the repository browser.