source: lib/format_pcapfile.c @ 0bd9361

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

Add write support to pcapfile

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