source: lib/format_erf.c @ e0d922a

develop
Last change on this file since e0d922a was e0d922a, checked in by Shane Alcock <salcock@…>, 22 months ago

Make sure ERF packet has a header before trying to access fields in it.

Mainly this will make sure things behave sanely if someone was to
ignore an error returned by trace_read_packet() and try to call
trace_get_capture_length() or some other format-specific function
on the packet anyway.

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