source: lib/format_pcapfile.c @ c85b715

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

If an error occured opening the file, don't segfault when we cleanup

  • Property mode set to 100644
File size: 12.7 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007 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
48typedef struct pcapfile_header_t {
49                uint32_t magic_number;   /* magic number */
50                uint16_t version_major;  /* major version number */
51                uint16_t version_minor;  /* minor version number */
52                int32_t  thiszone;       /* GMT to local correction */
53                uint32_t sigfigs;        /* timestamp accuracy */
54                uint32_t snaplen;        /* aka "wirelen" */
55                uint32_t network;        /* data link type */
56} pcapfile_header_t; 
57
58struct pcapfile_format_data_t {
59        libtrace_io_t *file;
60        pcapfile_header_t header;
61};
62
63struct pcapfile_format_data_out_t {
64        libtrace_io_t *file;
65        int level;
66        int flag;
67
68};
69
70static int pcapfile_init_input(libtrace_t *libtrace) {
71        libtrace->format_data = malloc(sizeof(struct pcapfile_format_data_t));
72
73        if (libtrace->format_data == NULL) {
74                trace_set_err(libtrace,ENOMEM,"Out of memory");
75                return -1;
76        }
77
78        DATA(libtrace)->file=NULL;
79
80        return 0;
81}
82
83static int pcapfile_init_output(libtrace_out_t *libtrace) {
84        libtrace->format_data = 
85                malloc(sizeof(struct pcapfile_format_data_out_t));
86
87        DATAOUT(libtrace)->file=NULL;
88        DATAOUT(libtrace)->level=0;
89        DATAOUT(libtrace)->flag=O_CREAT|O_WRONLY;
90
91        return 0;
92}
93
94static uint16_t swaps(libtrace_t *libtrace, uint16_t num)
95{
96        /* to deal with open_dead traces that might try and use this
97         * if we don't have any per trace data, assume host byte order
98         */
99        if (!DATA(libtrace))
100                return num;
101        if (DATA(libtrace)->header.magic_number == 0xd4c3b2a1)
102                return byteswap16(num);
103
104        return num;
105}
106
107static uint32_t swapl(libtrace_t *libtrace, uint32_t num)
108{
109        /* to deal with open_dead traces that might try and use this
110         * if we don't have any per trace data, assume host byte order
111         */
112        if (!DATA(libtrace))
113                return num;
114        if (DATA(libtrace)->header.magic_number == 0xd4c3b2a1)
115                return byteswap32(num);
116
117        return num;
118}
119
120
121static int pcapfile_start_input(libtrace_t *libtrace) 
122{
123        int err;
124
125        if (!DATA(libtrace)->file) {
126                DATA(libtrace)->file=trace_open_file(libtrace);
127
128                if (!DATA(libtrace)->file)
129                        return -1;
130
131                err=libtrace_io_read(DATA(libtrace)->file,
132                                &DATA(libtrace)->header,
133                                sizeof(DATA(libtrace)->header));
134
135                if (err<1)
136                        return -1;
137               
138                if (swapl(libtrace,DATA(libtrace)->header.magic_number) != 0xa1b2c3d4) {
139                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"Not a pcap tracefile\n");
140                        return -1; /* Not a pcap file */
141                }
142
143                if (swaps(libtrace,DATA(libtrace)->header.version_major)!=2
144                        && swaps(libtrace,DATA(libtrace)->header.version_minor)!=4) {
145                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"Unknown pcap tracefile version %d.%d\n",
146                                        swaps(libtrace,
147                                                DATA(libtrace)->header.version_major),
148                                        swaps(libtrace,
149                                                DATA(libtrace)->header.version_minor));
150                        return -1;
151                }
152
153        }
154
155        return 0;
156}
157
158static int pcapfile_start_output(libtrace_out_t *libtrace UNUSED)
159{
160        return 0;
161}
162
163static int pcapfile_config_input(libtrace_t *libtrace,
164                trace_option_t option,
165                void *data UNUSED)
166{
167        trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION,
168                        "Unknown option %i", option);
169        return -1;
170}
171
172static int pcapfile_fin_input(libtrace_t *libtrace) 
173{
174        libtrace_io_close(DATA(libtrace)->file);
175        free(libtrace->format_data);
176        return 0; /* success */
177}
178
179static int pcapfile_fin_output(libtrace_out_t *libtrace)
180{
181        if (DATA(libtrace)->file)
182                libtrace_io_close(DATA(libtrace)->file);
183        free(libtrace->format_data);
184        libtrace->format_data=NULL;
185        return 0; /* success */
186}
187
188static int pcapfile_config_output(libtrace_out_t *libtrace,
189                trace_option_output_t option,
190                void *value)
191{
192        switch (option) {
193                case TRACE_OPTION_OUTPUT_COMPRESS:
194                        DATAOUT(libtrace)->level = *(int*)value;
195                        return 0;
196                case TRACE_OPTION_OUTPUT_FILEFLAGS:
197                        DATAOUT(libtrace)->flag = *(int*)value;
198                        return 0;
199                default:
200                        /* Unknown option */
201                        trace_set_err_out(libtrace,TRACE_ERR_UNKNOWN_OPTION,
202                                        "Unknown option");
203                        return -1;
204        }
205        return -1;
206}
207
208static int pcapfile_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet)
209{
210        int err;
211
212        assert(libtrace->format_data);
213
214        packet->type = pcap_dlt_to_rt(swapl(libtrace,
215                                DATA(libtrace)->header.network));
216
217        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
218                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
219                packet->buf_control = TRACE_CTRL_PACKET;
220        }
221
222        err=libtrace_io_read(DATA(libtrace)->file,
223                        packet->buffer,
224                        sizeof(libtrace_pcapfile_pkt_hdr_t));
225
226        if (err<0) {
227                trace_set_err(libtrace,errno,"reading packet");
228                return -1;
229        }
230        if (err==0) {
231                /* EOF */
232                return 0;
233        }
234
235        packet->header = packet->buffer;
236
237
238        err=libtrace_io_read(DATA(libtrace)->file,
239                        (char*)packet->buffer+sizeof(libtrace_pcapfile_pkt_hdr_t),
240                        (size_t)swapl(libtrace,((libtrace_pcapfile_pkt_hdr_t*)packet->buffer)->caplen)
241                        );
242
243       
244        if (err<0) {
245                trace_set_err(libtrace,errno,"reading packet");
246                return -1;
247        }
248        if (err==0) {
249                return 0;
250        }
251
252        packet->payload = (char*)packet->buffer
253                + sizeof(libtrace_pcapfile_pkt_hdr_t);
254       
255        return sizeof(libtrace_pcapfile_pkt_hdr_t)
256                +swapl(libtrace,((libtrace_pcapfile_pkt_hdr_t*)packet->buffer)->caplen);
257}
258
259static int pcapfile_write_packet(libtrace_out_t *out,
260                libtrace_packet_t *packet)
261{
262        struct libtrace_pcapfile_pkt_hdr_t hdr;
263        struct timeval tv = trace_get_timeval(packet);
264        int numbytes;
265        int ret;
266
267        /* If this packet cannot be converted to a pcap linktype then
268         * pop off the top header until it can be converted
269         */
270        while (libtrace_to_pcap_dlt(trace_get_link_type(packet))==~0U) {
271                if (!demote_packet(packet)) {
272                        trace_set_err_out(out, 
273                                TRACE_ERR_NO_CONVERSION,
274                                "pcap does not support this format");
275                        return -1;
276                }
277        }
278
279
280        /* Now we know the link type write out a header if we've not done
281         * so already
282         */
283        if (!DATAOUT(out)->file) {
284                struct pcapfile_header_t pcaphdr;
285
286                DATAOUT(out)->file=trace_open_file_out(out,
287                                DATAOUT(out)->level,
288                                DATAOUT(out)->flag);
289                if (!DATAOUT(out)->file)
290                        return -1;
291
292                pcaphdr.magic_number = 0xa1b2c3d4;
293                pcaphdr.version_major = 2;
294                pcaphdr.version_minor = 4;
295                pcaphdr.thiszone = 0;
296                pcaphdr.sigfigs = 0;
297                pcaphdr.snaplen = 65536;
298                pcaphdr.network = 
299                        libtrace_to_pcap_dlt(trace_get_link_type(packet));
300
301                libtrace_io_write(DATAOUT(out)->file, &pcaphdr, sizeof(pcaphdr));
302        }
303
304        hdr.ts_sec = tv.tv_sec;
305        hdr.ts_usec = tv.tv_usec;
306        hdr.caplen = trace_get_capture_length(packet);
307        /* PCAP doesn't include the FCS, we do */
308        if (trace_get_link_type(packet)==TRACE_TYPE_ETH)
309                if (trace_get_wire_length(packet) >= 4) {
310                        hdr.wirelen =
311                                        trace_get_wire_length(packet)-4;
312                }
313                else {
314                        hdr.wirelen = 0;
315                }
316        else
317                hdr.wirelen = trace_get_wire_length(packet);
318
319
320        numbytes=libtrace_io_write(DATAOUT(out)->file,
321                        &hdr, sizeof(hdr));
322
323        if (numbytes!=sizeof(hdr)) 
324                return -1;
325
326        ret=libtrace_io_write(DATAOUT(out)->file,
327                        trace_get_link(packet),
328                        trace_get_capture_length(packet));
329
330        if (ret!=(int)trace_get_capture_length(packet))
331                return -1;
332
333        return numbytes+ret;
334}
335
336static libtrace_linktype_t pcapfile_get_link_type(
337                const libtrace_packet_t *packet) 
338{
339#if 0
340        return pcap_dlt_to_libtrace(
341                        swapl(packet->trace,
342                                DATA(packet->trace)->header.network
343                             )
344                        );
345#endif
346        return pcap_dlt_to_libtrace(rt_to_pcap_dlt(packet->type));
347}
348
349static libtrace_direction_t pcapfile_get_direction(const libtrace_packet_t *packet) 
350{
351        libtrace_direction_t direction  = -1;
352        switch(pcapfile_get_link_type(packet)) {
353                case TRACE_TYPE_LINUX_SLL:
354                {
355                        libtrace_sll_header_t *sll;
356                        sll = (libtrace_sll_header_t*)trace_get_link(packet);
357                        if (!sll) {
358                                trace_set_err(packet->trace,
359                                        TRACE_ERR_BAD_PACKET,
360                                                "Bad or missing packet");
361                                return -1;
362                        }
363                        /* 0 == LINUX_SLL_HOST */
364                        /* the Waikato Capture point defines "packets
365                         * originating locally" (ie, outbound), with a
366                         * direction of 0, and "packets destined locally"
367                         * (ie, inbound), with a direction of 1.
368                         * This is kind-of-opposite to LINUX_SLL.
369                         * We return consistent values here, however
370                         *
371                         * Note that in recent versions of pcap, you can
372                         * use "inbound" and "outbound" on ppp in linux
373                         */
374                        if (ntohs(sll->pkttype == 0)) {
375                                direction = TRACE_DIR_INCOMING;
376                        } else {
377                                direction = TRACE_DIR_OUTGOING;
378                        }
379                        break;
380
381                }
382                case TRACE_TYPE_PFLOG:
383                {
384                        libtrace_pflog_header_t *pflog;
385                        pflog=(libtrace_pflog_header_t*)trace_get_link(packet);
386                        if (!pflog) {
387                                trace_set_err(packet->trace,
388                                                TRACE_ERR_BAD_PACKET,
389                                                "Bad or missing packet");
390                                return -1;
391                        }
392                        /* enum    { PF_IN=0, PF_OUT=1 }; */
393                        if (ntohs(pflog->dir==0)) {
394
395                                direction = TRACE_DIR_INCOMING;
396                        }
397                        else {
398                                direction = TRACE_DIR_OUTGOING;
399                        }
400                        break;
401                }
402                default:
403                        break;
404        }       
405        return direction;
406}
407
408
409static struct timeval pcapfile_get_timeval(
410                const libtrace_packet_t *packet) 
411{
412        libtrace_pcapfile_pkt_hdr_t *hdr =
413                (libtrace_pcapfile_pkt_hdr_t*)packet->header;
414        struct timeval ts;
415        ts.tv_sec = swapl(packet->trace,hdr->ts_sec);
416        ts.tv_usec = swapl(packet->trace,hdr->ts_usec);
417        return ts;
418}
419
420
421static int pcapfile_get_capture_length(const libtrace_packet_t *packet) {
422        libtrace_pcapfile_pkt_hdr_t *pcapptr
423                = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
424
425        return swapl(packet->trace,pcapptr->caplen);
426}
427
428static int pcapfile_get_wire_length(const libtrace_packet_t *packet) {
429        libtrace_pcapfile_pkt_hdr_t *pcapptr
430                = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
431        if (packet->type==pcap_dlt_to_rt(TRACE_DLT_EN10MB))
432                /* Include the missing FCS */
433                return swapl(packet->trace,pcapptr->wirelen)+4; 
434        else
435                return swapl(packet->trace,pcapptr->wirelen);
436}
437
438static int pcapfile_get_framing_length(const libtrace_packet_t *packet UNUSED) {
439        return sizeof(libtrace_pcapfile_pkt_hdr_t);
440}
441
442static size_t pcapfile_set_capture_length(libtrace_packet_t *packet,size_t size) {
443        libtrace_pcapfile_pkt_hdr_t *pcapptr = 0;
444        assert(packet);
445        if (size > trace_get_capture_length(packet)) {
446                /* can't make a packet larger */
447                return trace_get_capture_length(packet);
448        }
449        pcapptr = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
450        pcapptr->caplen = swapl(packet->trace,(uint32_t)size);
451        return trace_get_capture_length(packet);
452}
453
454static void pcapfile_help(void) {
455        printf("pcapfile format module: $Revision$\n");
456        printf("Supported input URIs:\n");
457        printf("\tpcapfile:/path/to/file\n");
458        printf("\tpcapfile:/path/to/file.gz\n");
459        printf("\n");
460        printf("\te.g.: pcapfile:/tmp/trace.pcap\n");
461        printf("\n");
462}
463
464static struct libtrace_format_t pcapfile = {
465        "pcapfile",
466        "$Id$",
467        TRACE_FORMAT_PCAPFILE,
468        pcapfile_init_input,            /* init_input */
469        pcapfile_config_input,          /* config_input */
470        pcapfile_start_input,           /* start_input */
471        NULL,                           /* pause_input */
472        pcapfile_init_output,           /* init_output */
473        pcapfile_config_output,         /* config_output */
474        pcapfile_start_output,          /* start_output */
475        pcapfile_fin_input,             /* fin_input */
476        pcapfile_fin_output,            /* fin_output */
477        pcapfile_read_packet,           /* read_packet */
478        NULL,                           /* fin_packet */
479        pcapfile_write_packet,          /* write_packet */
480        pcapfile_get_link_type,         /* get_link_type */
481        pcapfile_get_direction,         /* get_direction */
482        NULL,                           /* set_direction */
483        NULL,                           /* get_erf_timestamp */
484        pcapfile_get_timeval,           /* get_timeval */
485        NULL,                           /* get_seconds */
486        NULL,                           /* seek_erf */
487        NULL,                           /* seek_timeval */
488        NULL,                           /* seek_seconds */
489        pcapfile_get_capture_length,    /* get_capture_length */
490        pcapfile_get_wire_length,       /* get_wire_length */
491        pcapfile_get_framing_length,    /* get_framing_length */
492        pcapfile_set_capture_length,    /* set_capture_length */
493        NULL,                           /* get_fd */
494        trace_event_trace,              /* trace_event */
495        pcapfile_help,                  /* help */
496        NULL                            /* next pointer */
497};
498
499
500void pcapfile_constructor(void) {
501        register_format(&pcapfile);
502}
503
504
Note: See TracBrowser for help on using the repository browser.