source: lib/format_erf.c @ 7aa03d9

develop
Last change on this file since 7aa03d9 was 7aa03d9, checked in by Jacob Van Walraven <jcv9@…>, 22 months ago

Check for NULL packet buffer in get_meta_data(), Make sure not to read past the end of the packet in pcapng_get_meta_data()

  • Property mode set to 100644
File size: 29.4 KB
Line 
1/*
2 *
3 * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand.
4 * All rights reserved.
5 *
6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/
10 *
11 * libtrace is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * libtrace is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 *
24 *
25 */
26
27#define _GNU_SOURCE
28
29#include "config.h"
30#include "common.h"
31#include "libtrace.h"
32#include "libtrace_int.h"
33#include "format_helper.h"
34#include "format_erf.h"
35#include "wandio.h"
36
37#include <errno.h>
38#include <fcntl.h>
39#include <stdio.h>
40#include <string.h>
41#include <stdlib.h>
42
43
44#ifdef WIN32
45#  include <io.h>
46#  include <share.h>
47#  define PATH_MAX _MAX_PATH
48#else
49#  include <netdb.h>
50#  ifndef PATH_MAX
51#       define PATH_MAX 4096
52#  endif
53#  include <sys/ioctl.h>
54#endif
55
56/* This format module deals with reading and writing ERF traces. ERF is the
57 * trace format developed by Endace for use by DAG hardware capture cards.
58 *
59 * ERF is not a live capture format.
60 *
61 */
62
63#define ERF_META_TYPE 27
64
65static struct libtrace_format_t erfformat;
66
67#define DATA(x) ((struct erf_format_data_t *)x->format_data)
68#define DATAOUT(x) ((struct erf_format_data_out_t *)x->format_data)
69
70#define IN_OPTIONS DATA(libtrace)->options
71#define OUTPUT DATAOUT(libtrace)
72#define OUT_OPTIONS DATAOUT(libtrace)->options
73
74/* "Global" data that is stored for each ERF input trace */
75struct erf_format_data_t {
76       
77        /* Index used for seeking within a trace */
78        struct {
79                /* The index itself */
80                io_t *index;
81                /* The offset of the index */
82                off_t index_len;
83                /* Indicates the existence of an index */
84                enum { INDEX_UNKNOWN=0, INDEX_NONE, INDEX_EXISTS } exists;
85        } seek;
86
87        /* Number of packets that were dropped during the capture */
88        uint64_t drops;
89
90        /* Config options for the input trace */
91        struct {
92                /* Flag indicating whether the event API should replicate the
93                 * time gaps between each packet or return a PACKET event for
94                 * each packet */
95                int real_time;
96        } options;
97};
98
99/* "Global" data that is stored for each ERF output trace */
100struct erf_format_data_out_t {
101
102        /* Config options for the output trace */
103        struct {
104                /* Compression level for the output file */
105                int level;
106                /* Compression type */
107                int compress_type;
108                /* File flags used to open the file, e.g. O_CREATE */
109                int fileflag;
110        } options;
111
112        /* The output file itself */
113        iow_t *file;
114       
115};
116
117typedef struct erf_index_t {
118        uint64_t timestamp;
119        uint64_t offset; 
120} erf_index_t;
121
122static bool erf_can_write(libtrace_packet_t *packet) {
123        /* Get the linktype */
124        libtrace_linktype_t ltype = trace_get_link_type(packet);
125
126        if (ltype == TRACE_TYPE_PCAPNG_META
127                || ltype == TRACE_TYPE_NONDATA) {
128
129                return false;
130        }
131
132        return true;
133}
134
135/* Ethernet packets have a 2 byte padding before the packet
136 * so that the IP header is aligned on a 32 bit boundary.
137 */
138static inline int erf_get_padding(const libtrace_packet_t *packet)
139{
140        dag_record_t *erfptr = (dag_record_t *)packet->header;
141
142        switch(packet->trace->format->type) {
143                case TRACE_FORMAT_ERF:
144                case TRACE_FORMAT_NDAG:
145                case TRACE_FORMAT_RAWERF:
146                case TRACE_FORMAT_DPDK_NDAG:
147                        switch((erfptr->type & 0x7f)) {
148                                case TYPE_ETH:
149                                case TYPE_COLOR_ETH:
150                                case TYPE_DSM_COLOR_ETH:
151                                case TYPE_COLOR_HASH_ETH:
152                                        return 2;
153                                default:
154                                        return 0;
155                        }
156                        break;
157                default:
158                        switch(trace_get_link_type(packet)) {
159                                case TRACE_TYPE_ETH:    return 2;
160                                default:                return 0;
161                        }
162                        break;
163        }
164        return 0;
165}
166
167int erf_is_color_type(uint8_t erf_type)
168{
169        switch(erf_type & 0x7f) {
170                case TYPE_COLOR_HDLC_POS:
171                case TYPE_DSM_COLOR_HDLC_POS:
172                case TYPE_COLOR_ETH:
173                case TYPE_DSM_COLOR_ETH:
174                case TYPE_COLOR_HASH_POS:
175                case TYPE_COLOR_HASH_ETH:
176                        return 1;
177        }
178
179        return 0;
180}
181
182int erf_get_framing_length(const libtrace_packet_t *packet)
183{
184        uint16_t extsize = 0;
185        dag_record_t *erfptr = NULL;
186        uint64_t *exthdr = NULL;
187        uint8_t *firstbyte;
188
189        erfptr = (dag_record_t *)packet->header;
190        if ((erfptr->type & 0x80) == 0x80) {
191                /* Extension headers are present */
192                exthdr = (uint64_t *)((char *)packet->header + dag_record_size);
193                extsize += 8;
194
195                firstbyte = (uint8_t *)exthdr;
196                while ((*firstbyte & 0x80) == 0x80) {
197                        extsize += 8;
198                        exthdr ++;
199                        firstbyte = (uint8_t *)exthdr;
200                        if (extsize > ntohs(erfptr->rlen)) {
201                                trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET, "Extension size is greater than dag record record length in erf_get_framing_length()");
202                                return -1;
203                        }
204                }
205        }
206        return dag_record_size + extsize + erf_get_padding(packet);
207}
208
209/* Attempts to determine whether a given trace file is using the ERF format
210 *
211 * Returns 1 if the trace is probably ERF, 0 otherwise
212 */
213static int erf_probe_magic(io_t *io)
214{
215        char buffer[4096];
216        int len;
217        dag_record_t *erf;
218        len = wandio_peek(io, buffer, sizeof(buffer));
219        if (len < (int)dag_record_size) {
220                return 0; /* False */
221        }
222        erf = (dag_record_t *) buffer;
223        /* If the record is too short */
224        if (ntohs(erf->rlen) < dag_record_size) {
225                return 0;
226        }
227        /* There aren't any erf traces before 1995-01-01 */
228        if (bswap_le_to_host64(erf->ts) < 0x2f0539b000000000ULL) {
229                return 0;
230        }
231        /* And not pcap! */
232        if (bswap_le_to_host64(erf->ts) >>32 == 0xa1b2c3d4) {
233                return 0;
234        }
235        /* And not the other pcap! */
236        if (bswap_le_to_host64(erf->ts) >>32 == 0xd4c3b2a1) {
237                return 0;
238        }
239        /* Is this a proper typed packet */
240        if ((erf->type & 0x7f) > ERF_TYPE_MAX) {
241                return 0;
242        }
243        /* We should put some more tests in here. */
244        /* Yeah, this is probably ERF */
245        return 1;
246}
247
248static int erf_init_input(libtrace_t *libtrace) {
249        libtrace->format_data = malloc(sizeof(struct erf_format_data_t));
250
251        if (!libtrace->format_data) {
252                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Unable to allocate memory for "
253                        "format data inside erf_init_input()");
254                return -1;
255        }
256
257        IN_OPTIONS.real_time = 0;
258        DATA(libtrace)->drops = 0;
259
260        return 0; /* success */
261}
262
263static int erf_config_input(libtrace_t *libtrace, trace_option_t option,
264                void *value) {
265
266        switch (option) {
267                case TRACE_OPTION_EVENT_REALTIME:
268                        IN_OPTIONS.real_time = *(int *)value;
269                        return 0;
270                case TRACE_OPTION_CONSTANT_ERF_FRAMING:
271                        trace_set_err(libtrace, TRACE_ERR_OPTION_UNAVAIL,
272                                        "Setting constant framing length is not supported for %s:", libtrace->format->name);
273                        return -1;
274                case TRACE_OPTION_SNAPLEN:
275                case TRACE_OPTION_PROMISC:
276                case TRACE_OPTION_FILTER:
277                case TRACE_OPTION_META_FREQ:
278                        trace_set_err(libtrace, TRACE_ERR_OPTION_UNAVAIL,
279                                        "Unsupported option");
280                        return -1;
281                default:
282                        /* Unknown option */
283                        trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION,
284                                        "Unknown option");
285                        return -1;
286        }
287}
288
289static int erf_start_input(libtrace_t *libtrace) 
290{
291        if (libtrace->io)
292                return 0; /* Success -- already done. */
293
294        libtrace->io = trace_open_file(libtrace);
295
296        if (!libtrace->io)
297                return -1;
298
299        DATA(libtrace)->drops = 0;
300        return 0; /* success */
301}
302
303/* Raw ERF is a special case -- we want to force libwandio to treat the file
304 * as uncompressed so we can't just use trace_open_file() */
305static int rawerf_start_input(libtrace_t *libtrace)
306{
307        if (libtrace->io)
308                return 0; 
309
310        libtrace->io = wandio_create_uncompressed(libtrace->uridata);
311
312        if (!libtrace->io) {
313                if (errno != 0) {
314                        trace_set_err(libtrace, errno, "Unable to open raw ERF file %s", libtrace->uridata);
315                }
316                return -1;
317        }
318
319        DATA(libtrace)->drops = 0;
320
321        return 0; /* success */
322}
323
324/* Binary search through the index to find the closest point before
325 * the packet.  Consider in future having a btree index perhaps?
326 */
327static int erf_fast_seek_start(libtrace_t *libtrace,uint64_t erfts)
328{
329        size_t max_off = DATA(libtrace)->seek.index_len/sizeof(erf_index_t);
330        size_t min_off = 0;
331        off_t current;
332        erf_index_t record;
333        do {
334                current=(max_off+min_off)>>2;
335
336                wandio_seek(DATA(libtrace)->seek.index,
337                                (int64_t)(current*sizeof(record)),
338                                SEEK_SET);
339                wandio_read(DATA(libtrace)->seek.index,
340                                &record,sizeof(record));
341                if (record.timestamp < erfts) {
342                        min_off=current;
343                }
344                if (record.timestamp > erfts) {
345                        max_off=current;
346                }
347                if (record.timestamp == erfts)
348                        break;
349        } while(min_off<max_off);
350
351        /* If we've passed it, seek backwards.  This loop shouldn't
352         * execute more than twice.
353         */
354        do {
355                wandio_seek(DATA(libtrace)->seek.index,
356                                (int64_t)(current*sizeof(record)),SEEK_SET);
357                wandio_read(DATA(libtrace)->seek.index,
358                                &record,sizeof(record));
359                current--;
360        } while(record.timestamp>erfts);
361
362        /* We've found our location in the trace, now use it. */
363        wandio_seek(libtrace->io,(int64_t) record.offset,SEEK_SET);
364
365        return 0; /* success */
366}
367
368/* There is no index.  Seek through the entire trace from the start, nice
369 * and slowly.
370 */
371static int erf_slow_seek_start(libtrace_t *libtrace,uint64_t erfts UNUSED)
372{
373        if (libtrace->io) {
374                wandio_destroy(libtrace->io);
375        }
376        libtrace->io = trace_open_file(libtrace);
377        if (!libtrace->io)
378                return -1;
379        return 0;
380}
381
382/* Seek within an ERF trace based on an ERF timestamp */
383static int erf_seek_erf(libtrace_t *libtrace,uint64_t erfts)
384{
385        libtrace_packet_t *packet;
386        off_t off = 0;
387
388        if (DATA(libtrace)->seek.exists==INDEX_UNKNOWN) {
389                char buffer[PATH_MAX];
390                snprintf(buffer,sizeof(buffer),"%s.idx",libtrace->uridata);
391                DATA(libtrace)->seek.index=wandio_create(buffer);
392                if (DATA(libtrace)->seek.index) {
393                        DATA(libtrace)->seek.exists=INDEX_EXISTS;
394                }
395                else {
396                        DATA(libtrace)->seek.exists=INDEX_NONE;
397                }
398        }
399
400        /* If theres an index, use it to find the nearest packet that isn't
401         * after the time we're looking for.  If there is no index we need
402         * to seek slowly through the trace from the beginning.  Sigh.
403         */
404        switch(DATA(libtrace)->seek.exists) {
405                case INDEX_EXISTS:
406                        erf_fast_seek_start(libtrace,erfts);
407                        break;
408                case INDEX_NONE:
409                        erf_slow_seek_start(libtrace,erfts);
410                        break;
411                case INDEX_UNKNOWN:
412                        trace_set_err(libtrace, TRACE_ERR_SEEK_ERF, "Cannot seek to erf timestamp with unknown index in erf_seek_erf()");
413                        return -1;
414                        break;
415        }
416
417        /* Now seek forward looking for the correct timestamp */
418        packet=trace_create_packet();
419        do {
420                trace_read_packet(libtrace,packet);
421                if (trace_get_erf_timestamp(packet)==erfts)
422                        break;
423                off=wandio_tell(libtrace->io);
424        } while(trace_get_erf_timestamp(packet)<erfts);
425
426        wandio_seek(libtrace->io,off,SEEK_SET);
427
428        return 0;
429}
430
431static int erf_init_output(libtrace_out_t *libtrace) {
432        libtrace->format_data = malloc(sizeof(struct erf_format_data_out_t));
433
434        if (!libtrace->format_data) {
435                trace_set_err_out(libtrace, TRACE_ERR_INIT_FAILED, "Unable to allocate memory for "
436                        "format data inside erf_init_output()");
437                return -1;
438        }
439
440        OUT_OPTIONS.level = 0;
441        OUT_OPTIONS.compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
442        OUT_OPTIONS.fileflag = O_CREAT | O_WRONLY;
443        OUTPUT->file = 0;
444
445        return 0;
446}
447
448static int erf_config_output(libtrace_out_t *libtrace, 
449                trace_option_output_t option, void *value) {
450
451        switch (option) {
452                case TRACE_OPTION_OUTPUT_COMPRESS:
453                        OUT_OPTIONS.level = *(int*)value;
454                        return 0;
455                case TRACE_OPTION_OUTPUT_COMPRESSTYPE:
456                        OUT_OPTIONS.compress_type = *(int*)value;
457                        return 0;
458                case TRACE_OPTION_OUTPUT_FILEFLAGS:
459                        OUT_OPTIONS.fileflag = *(int*)value;
460                        return 0;
461                default:
462                        /* Unknown option */
463                        trace_set_err_out(libtrace,TRACE_ERR_UNKNOWN_OPTION,
464                                        "Unknown option");
465                        return -1;
466        }
467}
468
469
470
471static int erf_fin_input(libtrace_t *libtrace) {
472        if (libtrace->io)
473                wandio_destroy(libtrace->io);
474        free(libtrace->format_data);
475        return 0;
476}
477
478static int erf_fin_output(libtrace_out_t *libtrace) {
479        if (OUTPUT->file)
480                wandio_wdestroy(OUTPUT->file);
481        free(libtrace->format_data);
482        return 0;
483}
484 
485static int erf_prepare_packet(libtrace_t *libtrace, libtrace_packet_t *packet,
486                void *buffer, libtrace_rt_types_t rt_type, uint32_t flags) {
487       
488        dag_record_t *erfptr;
489
490        if (packet->buffer != buffer && 
491                packet->buf_control == TRACE_CTRL_PACKET) {
492                free(packet->buffer);
493        }
494
495        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
496                packet->buf_control = TRACE_CTRL_PACKET;
497        } else
498                packet->buf_control = TRACE_CTRL_EXTERNAL;
499
500        packet->type = rt_type;
501        packet->buffer = buffer;
502        packet->header = buffer;
503        erfptr = (dag_record_t *)packet->buffer;
504        if (erfptr->flags.rxerror == 1) {
505                packet->payload = NULL;
506        } else {
507                packet->payload = ((char*)packet->buffer) + trace_get_framing_length(packet);
508        }
509
510        if (erfptr->rlen == 0) {
511                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "ERF packet has an invalid record "
512                        "length: zero, in erf_prepare_packet()\n");
513                return -1;
514        }
515
516        if (libtrace->format_data == NULL) {
517                /* Allocates the format_data structure */
518                if (erf_init_input(libtrace)) 
519                        return -1;
520        }
521
522        /* Check for loss */
523        if (erf_is_color_type(erfptr->type)) {
524                /* No idea how we get this yet */
525
526        } else if (erfptr->lctr) {
527                DATA(libtrace)->drops += ntohs(erfptr->lctr);
528        }
529
530        return 0;
531}
532
533static int erf_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
534        int numbytes;
535        unsigned int size;
536        void *buffer2 = packet->buffer;
537        unsigned int rlen;
538        uint32_t flags = 0;
539        libtrace_rt_types_t linktype;
540       
541        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
542                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
543                if (!packet->buffer) {
544                        trace_set_err(libtrace, errno, 
545                                        "Cannot allocate memory");
546                        return -1;
547                }
548        }
549
550        flags |= TRACE_PREP_OWN_BUFFER; 
551       
552        if ((numbytes=wandio_read(libtrace->io,
553                                        packet->buffer,
554                                        (size_t)dag_record_size)) == -1) {
555                trace_set_err(libtrace,errno,"reading ERF file");
556                return -1;
557        }
558        /* EOF */
559        if (numbytes == 0) {
560                return 0;
561        }
562
563        if (numbytes < (int)dag_record_size) {
564                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Incomplete ERF header");
565                return -1;
566        }
567
568        rlen = ntohs(((dag_record_t *)packet->buffer)->rlen);
569        buffer2 = (char*)packet->buffer + dag_record_size;
570        size = rlen - dag_record_size;
571
572        if (size >= LIBTRACE_PACKET_BUFSIZE) {
573                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, 
574                                "Packet size %u larger than supported by libtrace - packet is probably corrupt", 
575                                size);
576                return -1;
577        }
578
579        /* Unknown/corrupt */
580        if ((((dag_record_t *)packet->buffer)->type & 0x7f) > ERF_TYPE_MAX) {
581                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, 
582                                "Corrupt or Unknown ERF type");
583                return -1;
584        }
585       
586        /* read in the rest of the packet */
587        if ((numbytes=wandio_read(libtrace->io,
588                                        buffer2,
589                                        (size_t)size)) != (int)size) {
590                if (numbytes==-1) {
591                        trace_set_err(libtrace,errno, "read(%s)", 
592                                        libtrace->uridata);
593                        return -1;
594                }
595                trace_set_err(libtrace,EIO,
596                                "Truncated packet (wanted %d, got %d)", 
597                                size, numbytes);
598                /* Failed to read the full packet?  must be EOF */
599                return -1;
600        }
601
602        if (numbytes < (int)size) {
603                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Incomplete ERF record");
604                return -1;
605        }
606
607        /* If a provenance packet make sure correct rt linktype is set.
608         * Only bits 0-6 are used for the type */
609        if ((((dag_record_t *)packet->buffer)->type & 127) == ERF_META_TYPE) {
610                linktype = TRACE_RT_ERF_META;
611        } else { linktype = TRACE_RT_DATA_ERF; }
612
613        if (erf_prepare_packet(libtrace, packet, packet->buffer, 
614                                linktype, flags))
615                return -1;
616       
617        return rlen;
618}
619
620static int erf_dump_packet(libtrace_out_t *libtrace,
621                dag_record_t *erfptr, int framinglen, void *buffer,
622                int caplen) {
623        int numbytes = 0;
624
625        if (caplen + framinglen != ntohs(erfptr->rlen))
626                erfptr->rlen = htons(caplen + framinglen);
627
628        if ((numbytes = 
629                wandio_wwrite(OUTPUT->file, 
630                                erfptr,
631                                (size_t)(framinglen))) 
632                        != (int)(framinglen)) {
633                trace_set_err_out(libtrace,errno,
634                                "write(%s)",libtrace->uridata);
635                return -1;
636        }
637
638        numbytes=wandio_wwrite(OUTPUT->file, buffer, (size_t)caplen);
639        if (numbytes != caplen) {
640                trace_set_err_out(libtrace,errno,
641                                "write(%s)",libtrace->uridata);
642                return -1;
643        }
644        return numbytes + framinglen;
645}
646
647static int erf_flush_output(libtrace_out_t *libtrace) {
648        return wandio_wflush(OUTPUT->file);
649}
650
651static int erf_start_output(libtrace_out_t *libtrace)
652{
653        OUTPUT->file = trace_open_file_out(libtrace,
654                        OUT_OPTIONS.compress_type,
655                        OUT_OPTIONS.level,
656                        OUT_OPTIONS.fileflag);
657
658        if (!OUTPUT->file) {
659                return -1;
660        }
661        return 0;
662}
663
664static bool find_compatible_linktype(libtrace_out_t *libtrace,
665                                libtrace_packet_t *packet)
666{
667        /* Keep trying to simplify the packet until we can find
668         * something we can do with it */
669        do {
670                char type=libtrace_to_erf_type(trace_get_link_type(packet));
671
672                /* Success */
673                if (type != (char)-1)
674                        return true;
675
676                if (!demote_packet(packet)) {
677                        trace_set_err_out(libtrace,
678                                        TRACE_ERR_NO_CONVERSION,
679                                        "No erf type for packet (%i)",
680                                        trace_get_link_type(packet));
681                        return false;
682                }
683
684        } while(1);
685
686        return true;
687}
688               
689static int erf_write_packet(libtrace_out_t *libtrace, 
690                libtrace_packet_t *packet) 
691{
692
693        /* Check erf can write this type of packet */
694        if (!erf_can_write(packet)) {
695                return 0;
696        }
697
698        int numbytes = 0;
699        dag_record_t *dag_hdr = (dag_record_t *)packet->header;
700        void *payload = packet->payload;
701
702        if (!OUTPUT->file) {
703                trace_set_err_out(libtrace, TRACE_ERR_BAD_IO, "Attempted to write ERF packets to a "
704                        "closed file, must call trace_create_output() before calling trace_write_output()");
705                return -1;
706        }
707
708        if (!packet->header) {
709                return -1;
710        }
711       
712
713        /* If we've had an rxerror, we have no payload to write - fix
714         * rlen to be the correct length
715         */
716        /* I Think this is bogus, we should somehow figure out
717         * a way to write out the payload even if it is gibberish -- Perry */
718        if (payload == NULL) {
719                unsigned int pad = 0;
720                pad = erf_get_padding(packet);
721                dag_hdr->rlen = htons(dag_record_size + pad);
722               
723        } 
724       
725        if (packet->type == TRACE_RT_DATA_ERF) {
726                        numbytes = erf_dump_packet(libtrace,
727                                (dag_record_t *)packet->header,
728                                trace_get_framing_length(packet),
729                                payload,
730                                trace_get_capture_length(packet)
731                                );
732        } else {
733                dag_record_t erfhdr;
734                int rlen;
735                int framing;
736                /* convert format - build up a new erf header */
737                /* Timestamp */
738                erfhdr.ts = bswap_host_to_le64(trace_get_erf_timestamp(packet));
739
740                /* Flags. Can't do this */
741                memset(&erfhdr.flags,1,sizeof(erfhdr.flags));
742                if (trace_get_direction(packet)!=TRACE_DIR_UNKNOWN)
743                        erfhdr.flags.iface = trace_get_direction(packet);
744
745                if (!find_compatible_linktype(libtrace,packet))
746                        return -1;
747
748                payload=packet->payload;
749
750                erfhdr.type = libtrace_to_erf_type(trace_get_link_type(packet));
751
752                /* Packet length (rlen includes format overhead) */
753                if (trace_get_capture_length(packet) <= 0
754                        || trace_get_capture_length(packet) > 65536) {
755                        trace_set_err_out(libtrace, TRACE_ERR_BAD_PACKET,
756                                "Capture length is out of range in erf_write_packet()");
757                        return -1;
758                }
759                if (trace_get_framing_length(packet) > 65536) {
760                        trace_set_err_out(libtrace, TRACE_ERR_BAD_PACKET,
761                                "Framing length is to large in erf_write_packet()");
762                        return -1;
763                }
764
765                if (erfhdr.type == TYPE_ETH)
766                        framing = dag_record_size + 2;
767                else
768                        framing = dag_record_size;
769
770                rlen = trace_get_capture_length(packet) + framing;
771                if (rlen <= 0 || rlen > 65536) {
772                        trace_set_err_out(libtrace, TRACE_ERR_BAD_PACKET,
773                                "Capture + framing length is out of range in erf_write_packet()");
774                        return -1;
775                }
776                erfhdr.rlen = htons(rlen);
777                /* loss counter. Can't do this */
778                erfhdr.lctr = 0;
779                /* Wire length, does not include padding! */
780                erfhdr.wlen = htons(trace_get_wire_length(packet));
781
782                /* Write it out */
783                numbytes = erf_dump_packet(libtrace,
784                                &erfhdr,
785                                framing,
786                                payload,
787                                trace_get_capture_length(packet));
788        }
789        return numbytes;
790}
791
792libtrace_linktype_t erf_get_link_type(const libtrace_packet_t *packet) {
793        dag_record_t *erfptr = 0;
794        erfptr = (dag_record_t *)packet->header;
795        uint8_t type = (erfptr->type & 0x7f);
796        if (type != TYPE_LEGACY) {
797                /* The top-most bit is now used to indicate the presence of
798                 * extension headers :/ */
799                return erf_type_to_libtrace(type);
800        }
801        else {
802                /* Sigh, lets start wildly guessing */
803                if (((char*)packet->payload)[4]==0x45)
804                        return TRACE_TYPE_PPP;
805                return ~0;
806        }
807}
808
809libtrace_direction_t erf_get_direction(const libtrace_packet_t *packet) {
810        dag_record_t *erfptr = 0;
811        erfptr = (dag_record_t *)packet->header;
812        return erfptr->flags.iface;
813}
814
815libtrace_direction_t erf_set_direction(libtrace_packet_t *packet, libtrace_direction_t direction) {
816        dag_record_t *erfptr = 0;
817        erfptr = (dag_record_t *)packet->header;
818        erfptr->flags.iface = direction;
819        return erfptr->flags.iface;
820}
821
822uint64_t erf_get_erf_timestamp(const libtrace_packet_t *packet) {
823        dag_record_t *erfptr = 0;
824        erfptr = (dag_record_t *)packet->header;
825        return bswap_le_to_host64(erfptr->ts);
826}
827
828int erf_get_capture_length(const libtrace_packet_t *packet) {
829        dag_record_t *erfptr = 0;
830        int caplen;
831        size_t framinglen;
832        uint16_t wlen, rlen;
833
834        if (packet->payload == NULL)
835                return 0;
836
837        erfptr = (dag_record_t *)packet->header;
838        framinglen = trace_get_framing_length(packet);
839        rlen = ntohs(erfptr->rlen);
840        wlen = ntohs(erfptr->wlen);
841
842        caplen = rlen - framinglen;
843        if (wlen < caplen)
844                return wlen;
845
846        return caplen;
847}
848
849int erf_get_wire_length(const libtrace_packet_t *packet) {
850        dag_record_t *erfptr = 0;
851        erfptr = (dag_record_t *)packet->header;
852
853        if ((erfptr->type & 0x7f) == TYPE_META)
854                return 0;
855
856        return ntohs(erfptr->wlen);
857}
858
859size_t erf_set_capture_length(libtrace_packet_t *packet, size_t size) {
860        dag_record_t *erfptr = 0;
861        uint16_t wlen;
862
863        if (!packet) {
864                fprintf(stderr, "NULL packet passed to erf_set_capture_length()\n");
865                return ~0U;
866        }
867        erfptr = (dag_record_t *)packet->header;
868
869        if(size > trace_get_capture_length(packet) || (erfptr->type & 0x7f) == TYPE_META) {
870                /* Can't make a packet larger */
871                return trace_get_capture_length(packet);
872        }
873
874        /* Reset cached capture length - otherwise we will both return the
875         * wrong value here and subsequent get_capture_length() calls will
876         * return the wrong value. */
877        packet->cached.capture_length = -1;
878        erfptr->rlen = htons(size + trace_get_framing_length(packet));
879        wlen = ntohs(erfptr->wlen);
880
881        if (wlen < size) {
882                return wlen;
883        }
884
885        return size;
886}
887
888static struct libtrace_eventobj_t erf_event(struct libtrace_t *libtrace, struct libtrace_packet_t *packet) {
889        struct libtrace_eventobj_t event = {0,0,0.0,0};
890       
891        /* If we are being told to replay packets as fast as possible, then
892         * we just need to read and return the next packet in the trace */
893        if (IN_OPTIONS.real_time) {
894                event.size = trace_read_packet(libtrace, packet);
895                if (event.size < 1)
896                        event.type = TRACE_EVENT_TERMINATE;
897                else
898                        event.type = TRACE_EVENT_PACKET;
899                return event;
900               
901        } else {
902                /* Otherwise, use the generic event function */
903                return trace_event_trace(libtrace, packet);
904        }
905       
906}
907
908static void erf_get_statistics(libtrace_t *trace, libtrace_stat_t *stat) {
909
910        if (trace->format_data) {
911                stat->dropped_valid = 1;
912                stat->dropped = DATA(trace)->drops;
913        }
914}
915
916/* Returns a pointer to the beginning of the section or NULL if not found */
917void *erf_get_meta_data(libtrace_packet_t *packet, uint32_t section_type, uint16_t section) {
918
919        uint32_t remaining;
920        void *bodyptr;
921        dag_sec_t *sec;
922        dag_record_t *hdr;
923        uint16_t curr_sec;
924
925        if (packet->buffer == NULL) { return NULL; }
926
927        hdr = (dag_record_t *)packet->buffer;
928        bodyptr = (char *)packet->payload;
929        /* 24 is size of the ERF header */
930        remaining = ntohs(hdr->rlen) - 24;
931
932        /* ensure this is a meta packet */
933        /* the type only uses bits 0-6 */
934        if ((hdr->type & 127) != 27) { return NULL; }
935
936        sec = (dag_sec_t *)bodyptr;
937        /* loop till we find the correct section within the correct section type
938         * and enough payload is remaining */
939        while (((ntohs(sec->type) != section) || (section_type != curr_sec))
940                && (remaining > sizeof(dag_sec_t))) {
941
942                if (ntohs(sec->type) == ERF_PROV_SECTION_CAPTURE
943                        || ntohs(sec->type) == ERF_PROV_SECTION_HOST
944                        || ntohs(sec->type) == ERF_PROV_SECTION_MODULE
945                        || ntohs(sec->type) == ERF_PROV_SECTION_INTERFACE) {
946
947                        curr_sec = ntohs(sec->type);
948                }
949
950                /* jump over any padding (padded to 32bits/4bytes) */
951                if ((ntohs(sec->len) % 4) != 0) {
952                        remaining -= ntohs(sec->len) + (4 - (ntohs(sec->len) % 4));
953                        bodyptr += ntohs(sec->len) + (4 - (ntohs(sec->len) % 4));
954                } else {
955                        remaining -= ntohs(sec->len);
956                        bodyptr += ntohs(sec->len);
957                }
958                remaining -= sizeof(dag_sec_t);
959                bodyptr += sizeof(dag_sec_t);
960
961                sec = (dag_sec_t *)bodyptr;
962        }
963        /* if found return pointer to the beginning of the section */
964        if (ntohs(sec->type) == section && curr_sec == section_type) {
965                return (void *)bodyptr;
966        } else {
967                return NULL;
968        }
969}
970
971static void erf_help(void) {
972        printf("erf format module: $Revision: 1752 $\n");
973        printf("Supported input URIs:\n");
974        printf("\terf:/path/to/file\t(uncompressed)\n");
975        printf("\terf:/path/to/file.gz\t(gzip-compressed)\n");
976        printf("\terf:-\t(stdin, either compressed or not)\n");
977        printf("\terf:/path/to/socket\n");
978        printf("\n");
979        printf("\te.g.: erf:/tmp/trace\n");
980        printf("\n");
981        printf("Supported output URIs:\n");
982        printf("\terf:path/to/file\t(uncompressed)\n");
983        printf("\terf:/path/to/file.gz\t(gzip-compressed)\n");
984        printf("\terf:-\t(stdout, either compressed or not)\n");
985        printf("\n");
986        printf("\te.g.: erf:/tmp/trace\n");
987        printf("\n");
988
989
990}
991
992static struct libtrace_format_t erfformat = {
993        "erf",
994        "$Id$",
995        TRACE_FORMAT_ERF,
996        NULL,                           /* probe filename */
997        erf_probe_magic,                /* probe magic */
998        erf_init_input,                 /* init_input */       
999        erf_config_input,               /* config_input */
1000        erf_start_input,                /* start_input */
1001        NULL,                           /* pause_input */
1002        erf_init_output,                /* init_output */
1003        erf_config_output,              /* config_output */
1004        erf_start_output,               /* start_output */
1005        erf_fin_input,                  /* fin_input */
1006        erf_fin_output,                 /* fin_output */
1007        erf_read_packet,                /* read_packet */
1008        erf_prepare_packet,             /* prepare_packet */
1009        NULL,                           /* fin_packet */
1010        erf_write_packet,               /* write_packet */
1011        erf_flush_output,               /* flush_output */
1012        erf_get_link_type,              /* get_link_type */
1013        erf_get_direction,              /* get_direction */
1014        erf_set_direction,              /* set_direction */
1015        erf_get_erf_timestamp,          /* get_erf_timestamp */
1016        NULL,                           /* get_timeval */
1017        NULL,                           /* get_timespec */
1018        NULL,                           /* get_seconds */
1019        erf_get_meta_data,              /* get_meta_data */
1020        erf_seek_erf,                   /* seek_erf */
1021        NULL,                           /* seek_timeval */
1022        NULL,                           /* seek_seconds */
1023        erf_get_capture_length,         /* get_capture_length */
1024        erf_get_wire_length,            /* get_wire_length */
1025        erf_get_framing_length,         /* get_framing_length */
1026        erf_set_capture_length,         /* set_capture_length */
1027        NULL,                           /* get_received_packets */
1028        NULL,                           /* get_filtered_packets */
1029        NULL,                           /* get_dropped_packets */
1030        erf_get_statistics,             /* get_statistics */
1031        NULL,                           /* get_fd */
1032        erf_event,                      /* trace_event */
1033        erf_help,                       /* help */
1034        NULL,                           /* next pointer */
1035        NON_PARALLEL(false)
1036};
1037
1038static struct libtrace_format_t rawerfformat = {
1039        "rawerf",
1040        "$Id$",
1041        TRACE_FORMAT_RAWERF,
1042        NULL,                           /* probe filename */
1043        NULL,           /* probe magic */
1044        erf_init_input,                 /* init_input */       
1045        erf_config_input,               /* config_input */
1046        rawerf_start_input,             /* start_input */
1047        NULL,                           /* pause_input */
1048        erf_init_output,                /* init_output */
1049        erf_config_output,              /* config_output */
1050        erf_start_output,               /* start_output */
1051        erf_fin_input,                  /* fin_input */
1052        erf_fin_output,                 /* fin_output */
1053        erf_read_packet,                /* read_packet */
1054        erf_prepare_packet,             /* prepare_packet */
1055        NULL,                           /* fin_packet */
1056        erf_write_packet,               /* write_packet */
1057        erf_flush_output,               /* flush_output */
1058        erf_get_link_type,              /* get_link_type */
1059        erf_get_direction,              /* get_direction */
1060        erf_set_direction,              /* set_direction */
1061        erf_get_erf_timestamp,          /* get_erf_timestamp */
1062        NULL,                           /* get_timeval */
1063        NULL,                           /* get_timespec */
1064        NULL,                           /* get_seconds */
1065        erf_get_meta_data,              /* get_meta_data */
1066        erf_seek_erf,                   /* seek_erf */
1067        NULL,                           /* seek_timeval */
1068        NULL,                           /* seek_seconds */
1069        erf_get_capture_length,         /* get_capture_length */
1070        erf_get_wire_length,            /* get_wire_length */
1071        erf_get_framing_length,         /* get_framing_length */
1072        erf_set_capture_length,         /* set_capture_length */
1073        NULL,                           /* get_received_packets */
1074        NULL,                           /* get_filtered_packets */
1075        NULL,                           /* get_dropped_packets */
1076        erf_get_statistics,             /* get_statistics */
1077        NULL,                           /* get_fd */
1078        erf_event,                      /* trace_event */
1079        erf_help,                       /* help */
1080        NULL,                           /* next pointer */
1081        NON_PARALLEL(false)
1082};
1083
1084
1085
1086void erf_constructor(void) {
1087        register_format(&erfformat);
1088        register_format(&rawerfformat);
1089}
Note: See TracBrowser for help on using the repository browser.