source: lib/format_erf.c @ 2d16fc7

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

Make sure we have four bytes of ERF payload before probing contents.

The PPP check in format_erf is pretty hax as it is, but we should
at least make sure there is enough data there for our probe to be
looking at legit payload, not just some random memory.

  • Property mode set to 100644
File size: 28.2 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                if (trace_get_capture_length(packet) < 5 ||
805                                packet->payload == NULL) {
806                        return ~0;
807                }
808
809                /* Sigh, lets start wildly guessing */
810                if (((char*)packet->payload)[4]==0x45)
811                        return TRACE_TYPE_PPP;
812                return ~0;
813        }
814}
815
816libtrace_direction_t erf_get_direction(const libtrace_packet_t *packet) {
817        dag_record_t *erfptr = 0;
818        erfptr = (dag_record_t *)packet->header;
819        if (packet->header) {
820                return erfptr->flags.iface;
821        }
822        return TRACE_DIR_UNKNOWN;
823}
824
825libtrace_direction_t erf_set_direction(libtrace_packet_t *packet, libtrace_direction_t direction) {
826        dag_record_t *erfptr = 0;
827        erfptr = (dag_record_t *)packet->header;
828
829        if (packet->header == NULL) {
830                return TRACE_DIR_UNKNOWN;
831        }
832        erfptr->flags.iface = direction;
833        return erfptr->flags.iface;
834}
835
836uint64_t erf_get_erf_timestamp(const libtrace_packet_t *packet) {
837        dag_record_t *erfptr = 0;
838        erfptr = (dag_record_t *)packet->header;
839
840        if (erfptr == NULL) {
841                return 0;
842        }
843        return bswap_le_to_host64(erfptr->ts);
844}
845
846int erf_get_capture_length(const libtrace_packet_t *packet) {
847        dag_record_t *erfptr = 0;
848        int caplen;
849        size_t framinglen;
850        uint16_t wlen, rlen;
851
852        if (packet->payload == NULL || packet->header == NULL)
853                return 0;
854
855        erfptr = (dag_record_t *)packet->header;
856        framinglen = trace_get_framing_length(packet);
857        rlen = ntohs(erfptr->rlen);
858        wlen = ntohs(erfptr->wlen);
859
860        caplen = rlen - framinglen;
861        if (wlen < caplen)
862                return wlen;
863
864        return caplen;
865}
866
867int erf_get_wire_length(const libtrace_packet_t *packet) {
868        dag_record_t *erfptr = 0;
869        erfptr = (dag_record_t *)packet->header;
870
871        if (packet->header == NULL) {
872                return 0;
873        }
874
875        if ((erfptr->type & 0x7f) == TYPE_META)
876                return 0;
877
878        return ntohs(erfptr->wlen);
879}
880
881size_t erf_set_capture_length(libtrace_packet_t *packet, size_t size) {
882        dag_record_t *erfptr = 0;
883        uint16_t wlen;
884
885        if (!packet) {
886                fprintf(stderr, "NULL packet passed to erf_set_capture_length()\n");
887                return ~0U;
888        }
889        erfptr = (dag_record_t *)packet->header;
890
891        if (packet->header == NULL) {
892                return ~0U;
893        }
894
895        if(size > trace_get_capture_length(packet) || (erfptr->type & 0x7f) == TYPE_META) {
896                /* Can't make a packet larger */
897                return trace_get_capture_length(packet);
898        }
899
900        /* Reset cached capture length - otherwise we will both return the
901         * wrong value here and subsequent get_capture_length() calls will
902         * return the wrong value. */
903        packet->cached.capture_length = -1;
904        erfptr->rlen = htons(size + trace_get_framing_length(packet));
905        wlen = ntohs(erfptr->wlen);
906
907        if (wlen < size) {
908                return wlen;
909        }
910
911        return size;
912}
913
914static struct libtrace_eventobj_t erf_event(struct libtrace_t *libtrace, struct libtrace_packet_t *packet) {
915        struct libtrace_eventobj_t event = {0,0,0.0,0};
916       
917        /* If we are being told to replay packets as fast as possible, then
918         * we just need to read and return the next packet in the trace */
919        if (IN_OPTIONS.real_time) {
920                event.size = trace_read_packet(libtrace, packet);
921                if (event.size < 1)
922                        event.type = TRACE_EVENT_TERMINATE;
923                else
924                        event.type = TRACE_EVENT_PACKET;
925                return event;
926               
927        } else {
928                /* Otherwise, use the generic event function */
929                return trace_event_trace(libtrace, packet);
930        }
931       
932}
933
934static void erf_get_statistics(libtrace_t *trace, libtrace_stat_t *stat) {
935
936        if (trace->format_data) {
937                stat->dropped_valid = 1;
938                stat->dropped = DATA(trace)->drops;
939        }
940}
941
942static void erf_help(void) {
943        printf("erf format module: $Revision: 1752 $\n");
944        printf("Supported input URIs:\n");
945        printf("\terf:/path/to/file\t(uncompressed)\n");
946        printf("\terf:/path/to/file.gz\t(gzip-compressed)\n");
947        printf("\terf:-\t(stdin, either compressed or not)\n");
948        printf("\terf:/path/to/socket\n");
949        printf("\n");
950        printf("\te.g.: erf:/tmp/trace\n");
951        printf("\n");
952        printf("Supported output URIs:\n");
953        printf("\terf:path/to/file\t(uncompressed)\n");
954        printf("\terf:/path/to/file.gz\t(gzip-compressed)\n");
955        printf("\terf:-\t(stdout, either compressed or not)\n");
956        printf("\n");
957        printf("\te.g.: erf:/tmp/trace\n");
958        printf("\n");
959
960       
961}
962
963static struct libtrace_format_t erfformat = {
964        "erf",
965        "$Id$",
966        TRACE_FORMAT_ERF,
967        NULL,                           /* probe filename */
968        erf_probe_magic,                /* probe magic */
969        erf_init_input,                 /* init_input */       
970        erf_config_input,               /* config_input */
971        erf_start_input,                /* start_input */
972        NULL,                           /* pause_input */
973        erf_init_output,                /* init_output */
974        erf_config_output,              /* config_output */
975        erf_start_output,               /* start_output */
976        erf_fin_input,                  /* fin_input */
977        erf_fin_output,                 /* fin_output */
978        erf_read_packet,                /* read_packet */
979        erf_prepare_packet,             /* prepare_packet */
980        NULL,                           /* fin_packet */
981        erf_write_packet,               /* write_packet */
982        erf_flush_output,               /* flush_output */
983        erf_get_link_type,              /* get_link_type */
984        erf_get_direction,              /* get_direction */
985        erf_set_direction,              /* set_direction */
986        erf_get_erf_timestamp,          /* get_erf_timestamp */
987        NULL,                           /* get_timeval */
988        NULL,                           /* get_timespec */
989        NULL,                           /* get_seconds */
990        erf_seek_erf,                   /* seek_erf */
991        NULL,                           /* seek_timeval */
992        NULL,                           /* seek_seconds */
993        erf_get_capture_length,         /* get_capture_length */
994        erf_get_wire_length,            /* get_wire_length */
995        erf_get_framing_length,         /* get_framing_length */
996        erf_set_capture_length,         /* set_capture_length */
997        NULL,                           /* get_received_packets */
998        NULL,                           /* get_filtered_packets */
999        NULL,                           /* get_dropped_packets */
1000        erf_get_statistics,             /* get_statistics */
1001        NULL,                           /* get_fd */
1002        erf_event,                      /* trace_event */
1003        erf_help,                       /* help */
1004        NULL,                           /* next pointer */
1005        NON_PARALLEL(false)
1006};
1007
1008static struct libtrace_format_t rawerfformat = {
1009        "rawerf",
1010        "$Id$",
1011        TRACE_FORMAT_RAWERF,
1012        NULL,                           /* probe filename */
1013        NULL,           /* probe magic */
1014        erf_init_input,                 /* init_input */       
1015        erf_config_input,               /* config_input */
1016        rawerf_start_input,             /* start_input */
1017        NULL,                           /* pause_input */
1018        erf_init_output,                /* init_output */
1019        erf_config_output,              /* config_output */
1020        erf_start_output,               /* start_output */
1021        erf_fin_input,                  /* fin_input */
1022        erf_fin_output,                 /* fin_output */
1023        erf_read_packet,                /* read_packet */
1024        erf_prepare_packet,             /* prepare_packet */
1025        NULL,                           /* fin_packet */
1026        erf_write_packet,               /* write_packet */
1027        erf_flush_output,               /* flush_output */
1028        erf_get_link_type,              /* get_link_type */
1029        erf_get_direction,              /* get_direction */
1030        erf_set_direction,              /* set_direction */
1031        erf_get_erf_timestamp,          /* get_erf_timestamp */
1032        NULL,                           /* get_timeval */
1033        NULL,                           /* get_timespec */
1034        NULL,                           /* get_seconds */
1035        erf_seek_erf,                   /* seek_erf */
1036        NULL,                           /* seek_timeval */
1037        NULL,                           /* seek_seconds */
1038        erf_get_capture_length,         /* get_capture_length */
1039        erf_get_wire_length,            /* get_wire_length */
1040        erf_get_framing_length,         /* get_framing_length */
1041        erf_set_capture_length,         /* set_capture_length */
1042        NULL,                           /* get_received_packets */
1043        NULL,                           /* get_filtered_packets */
1044        NULL,                           /* get_dropped_packets */
1045        erf_get_statistics,             /* get_statistics */
1046        NULL,                           /* get_fd */
1047        erf_event,                      /* trace_event */
1048        erf_help,                       /* help */
1049        NULL,                           /* next pointer */
1050        NON_PARALLEL(false)
1051};
1052
1053
1054
1055void erf_constructor(void) {
1056        register_format(&erfformat);
1057        register_format(&rawerfformat);
1058}
Note: See TracBrowser for help on using the repository browser.