source: lib/format_pcapfile.c @ 73dd29f

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

Sooo, pcap has two types of DLT's "pure" DLT's that are platform dependant,
and "linktype" DLT's that are portable and are what are written to pcap files.

Instead of fudging the two concepts together so much, attempt to disintangle
this mess without exposing too much of the god awful mess to the end user.

  • Property mode set to 100644
File size: 13.2 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_linktype_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_linktype(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_linktype(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_linktype_to_libtrace(
341                        swapl(packet->trace,
342                                DATA(packet->trace)->header.network
343                             )
344                        );
345#endif
346        return pcap_linktype_to_libtrace(rt_to_pcap_linktype(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_linktype_to_rt(TRACE_DLT_EN10MB))
432                /* Include the missing FCS */
433                return swapl(packet->trace,pcapptr->wirelen)+4; 
434        else if (packet->type==pcap_linktype_to_rt(TRACE_DLT_IEEE802_11_RADIO)) {
435                /* If the packet is Radiotap and the flags field indicates
436                 * that the FCS is not included in the 802.11 frame, then
437                 * we need to add 4 to the wire-length to account for it.
438                 */
439                uint16_t flags;
440                trace_get_wireless_flags(trace_get_link(packet), trace_get_link_type(packet), &flags);
441                if ((flags & TRACE_RADIOTAP_F_FCS) == 0)
442                        return swapl(packet->trace,pcapptr->wirelen)+4;
443        }
444        return swapl(packet->trace,pcapptr->wirelen);
445}
446
447static int pcapfile_get_framing_length(const libtrace_packet_t *packet UNUSED) {
448        return sizeof(libtrace_pcapfile_pkt_hdr_t);
449}
450
451static size_t pcapfile_set_capture_length(libtrace_packet_t *packet,size_t size) {
452        libtrace_pcapfile_pkt_hdr_t *pcapptr = 0;
453        assert(packet);
454        if (size > trace_get_capture_length(packet)) {
455                /* can't make a packet larger */
456                return trace_get_capture_length(packet);
457        }
458        pcapptr = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
459        pcapptr->caplen = swapl(packet->trace,(uint32_t)size);
460        return trace_get_capture_length(packet);
461}
462
463static void pcapfile_help(void) {
464        printf("pcapfile format module: $Revision$\n");
465        printf("Supported input URIs:\n");
466        printf("\tpcapfile:/path/to/file\n");
467        printf("\tpcapfile:/path/to/file.gz\n");
468        printf("\n");
469        printf("\te.g.: pcapfile:/tmp/trace.pcap\n");
470        printf("\n");
471}
472
473static struct libtrace_format_t pcapfile = {
474        "pcapfile",
475        "$Id$",
476        TRACE_FORMAT_PCAPFILE,
477        pcapfile_init_input,            /* init_input */
478        pcapfile_config_input,          /* config_input */
479        pcapfile_start_input,           /* start_input */
480        NULL,                           /* pause_input */
481        pcapfile_init_output,           /* init_output */
482        pcapfile_config_output,         /* config_output */
483        pcapfile_start_output,          /* start_output */
484        pcapfile_fin_input,             /* fin_input */
485        pcapfile_fin_output,            /* fin_output */
486        pcapfile_read_packet,           /* read_packet */
487        NULL,                           /* fin_packet */
488        pcapfile_write_packet,          /* write_packet */
489        pcapfile_get_link_type,         /* get_link_type */
490        pcapfile_get_direction,         /* get_direction */
491        NULL,                           /* set_direction */
492        NULL,                           /* get_erf_timestamp */
493        pcapfile_get_timeval,           /* get_timeval */
494        NULL,                           /* get_seconds */
495        NULL,                           /* seek_erf */
496        NULL,                           /* seek_timeval */
497        NULL,                           /* seek_seconds */
498        pcapfile_get_capture_length,    /* get_capture_length */
499        pcapfile_get_wire_length,       /* get_wire_length */
500        pcapfile_get_framing_length,    /* get_framing_length */
501        pcapfile_set_capture_length,    /* set_capture_length */
502        NULL,                           /* get_fd */
503        trace_event_trace,              /* trace_event */
504        pcapfile_help,                  /* help */
505        NULL                            /* next pointer */
506};
507
508
509void pcapfile_constructor(void) {
510        register_format(&pcapfile);
511}
512
513
Note: See TracBrowser for help on using the repository browser.