source: lib/format_pcapng.c @ 509ee47

develop
Last change on this file since 509ee47 was 509ee47, checked in by Shane Alcock <salcock@…>, 2 years ago

Add option to allow users to specify a constant ERF framing length.

This can be useful for situations where

a) the input uses ERF (or some derivative thereof)
b) the link type and ERF record type are constant for the

duration of the capture

c) performance is critical

This option allows users to simply tell libtrace what the ERF
framing length on every packet is going to be, so libtrace
doesn't have to repeatedly derive the framing length for each
packet it processes. At high packet rates, the time taken to
do this calculation can really add up and it makes no sense
to risk dropping packets because you're busy calculating a value
that is always a single constant value.

  • Property mode set to 100644
File size: 49.8 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#include "common.h"
27#include "config.h"
28#include "libtrace.h"
29#include "libtrace_int.h"
30#include "format_helper.h"
31
32#include <sys/stat.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <stdbool.h>
39#include <math.h>
40
41#define PCAPNG_SECTION_TYPE 0x0A0D0D0A
42#define PCAPNG_INTERFACE_TYPE 0x00000001
43#define PCAPNG_OLD_PACKET_TYPE 0x00000002
44#define PCAPNG_SIMPLE_PACKET_TYPE 0x00000003
45#define PCAPNG_NAME_RESOLUTION_TYPE 0x00000004
46#define PCAPNG_INTERFACE_STATS_TYPE 0x00000005
47#define PCAPNG_ENHANCED_PACKET_TYPE 0x00000006
48#define PCAPNG_CUSTOM_TYPE 0x00000BAD
49#define PCAPNG_CUSTOM_NONCOPY_TYPE 0x40000BAD
50
51#define PACKET_IS_ENHANCED (pcapng_get_record_type(packet) == PCAPNG_ENHANCED_PACKET_TYPE)
52
53#define PACKET_IS_SIMPLE (pcapng_get_record_type(packet) == PCAPNG_SIMPLE_PACKET_TYPE)
54
55#define PACKET_IS_OLD (pcapng_get_record_type(packet) == PCAPNG_OLD_PACKET_TYPE)
56
57
58#define PCAPNG_IFOPT_TSRESOL 9
59
60#define PCAPNG_PKTOPT_DROPCOUNT 4
61
62#define PCAPNG_STATOPT_START 2
63#define PCAPNG_STATOPT_END 3
64#define PCAPNG_STATOPT_IFRECV 4
65#define PCAPNG_STATOPT_IFDROP 5
66#define PCAPNG_STATOPT_FILTERACCEPT 6
67#define PCAPNG_STATOPT_OSDROP 7
68#define PCAPNG_STATOPT_USRDELIV 8
69
70typedef struct pcagng_section_header_t {
71        uint32_t blocktype;
72        uint32_t blocklen;
73        uint32_t ordering;
74        uint16_t majorversion;
75        uint16_t minorversion;
76        uint64_t sectionlen;
77} pcapng_sec_t;
78
79typedef struct pcapng_interface_header_t {
80        uint32_t blocktype;
81        uint32_t blocklen;
82        uint16_t linktype;
83        uint16_t reserved;
84        uint32_t snaplen;
85} pcapng_int_t;
86
87typedef struct pcapng_nrb_header_t {
88        uint32_t blocktype;
89        uint32_t blocklen;
90} pcapng_nrb_t;
91
92typedef struct pcapng_enhanced_packet_t {
93        uint32_t blocktype;
94        uint32_t blocklen;
95        uint32_t interfaceid;
96        uint32_t timestamp_high;
97        uint32_t timestamp_low;
98        uint32_t caplen;
99        uint32_t wlen;
100} pcapng_epkt_t;
101
102typedef struct pcapng_simple_packet_t {
103        uint32_t blocktype;
104        uint32_t blocklen;
105        uint32_t wlen;
106} pcapng_spkt_t;
107
108typedef struct pcapng_old_packet_t {
109        uint32_t blocktype;
110        uint32_t blocklen;
111        uint16_t interfaceid;
112        uint16_t drops;
113        uint32_t timestamp_high;
114        uint32_t timestamp_low;
115        uint32_t caplen;
116        uint32_t wlen;
117} pcapng_opkt_t;
118
119typedef struct pcapng_stats_header_t {
120        uint32_t blocktype;
121        uint32_t blocklen;
122        uint32_t interfaceid;
123        uint32_t timestamp_high;
124        uint32_t timestamp_low;
125} pcapng_stats_t;
126
127typedef struct pcapng_custom_header_t {
128        uint32_t blocktype;
129        uint32_t blocklen;
130        uint32_t pen;
131} pcapng_custom_t;
132
133typedef struct pcapng_interface_t pcapng_interface_t;
134
135struct pcapng_interface_t {
136
137        uint16_t id;
138        libtrace_dlt_t linktype;
139        uint32_t snaplen;
140        uint32_t tsresol;
141
142        uint64_t received;
143        uint64_t dropped;       /* as reported by interface stats */
144        uint64_t dropcounter;   /* as reported by packet records */
145        uint64_t accepted;
146        uint64_t osdropped;
147        uint64_t laststats;
148
149};
150
151struct pcapng_format_data_t {
152        bool started;
153        bool realtime;
154
155        /* Section data */
156        bool byteswapped;
157
158        /* Interface data */
159        pcapng_interface_t **interfaces;
160        uint16_t allocatedinterfaces;
161        uint16_t nextintid;
162};
163
164struct pcapng_optheader {
165        uint16_t optcode;
166        uint16_t optlen;
167};
168
169struct pcapng_peeker {
170        uint32_t blocktype;
171        uint32_t blocklen;
172};
173
174typedef struct pcapng_peeker pcapng_hdr_t;
175
176
177#define DATA(x) ((struct pcapng_format_data_t *)((x)->format_data))
178
179static pcapng_interface_t *lookup_interface(libtrace_t *libtrace,
180                uint32_t intid) {
181
182
183        if (intid >= DATA(libtrace)->nextintid) {
184                return NULL;
185        }
186
187        return DATA(libtrace)->interfaces[intid];
188
189}
190
191static inline uint32_t pcapng_get_record_type(const libtrace_packet_t *packet) {
192
193        uint32_t *btype = (uint32_t *)packet->header;
194
195        if (DATA(packet->trace)->byteswapped)
196                return byteswap32(*btype);
197        return *btype;
198}
199
200static int pcapng_probe_magic(io_t *io) {
201
202        pcapng_sec_t sechdr;
203        int len;
204
205        len = wandio_peek(io, &sechdr, sizeof(sechdr));
206        if (len < (int)sizeof(sechdr)) {
207                return 0;
208        }
209
210        if (sechdr.blocktype == PCAPNG_SECTION_TYPE) {
211                return 1;
212        }
213        return 0;
214}
215
216
217static int pcapng_init_input(libtrace_t *libtrace) {
218        libtrace->format_data = malloc(sizeof(struct pcapng_format_data_t));
219        if (!libtrace->format_data) {
220                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Unable to allocate memory for "
221                        "format data inside pcapng_init_input()");
222                return -1;
223        }
224
225        DATA(libtrace)->started = false;
226        DATA(libtrace)->realtime = false;
227        DATA(libtrace)->byteswapped = true;
228        DATA(libtrace)->interfaces = (pcapng_interface_t **)calloc(10, \
229                        sizeof(pcapng_interface_t));
230        DATA(libtrace)->allocatedinterfaces = 10;
231        DATA(libtrace)->nextintid = 0;
232
233        return 0;
234}
235
236static int pcapng_start_input(libtrace_t *libtrace) {
237
238        if (!libtrace->io) {
239                libtrace->io = trace_open_file(libtrace);
240        }
241
242        if (!libtrace->io)
243                return -1;
244
245        return 0;
246}
247
248static int pcapng_config_input(libtrace_t *libtrace, trace_option_t option,
249                void *data) {
250
251        switch(option) {
252                case TRACE_OPTION_EVENT_REALTIME:
253                        if (*(int *)data != 0) {
254                                DATA(libtrace)->realtime = true;
255                        } else {
256                                DATA(libtrace)->realtime = false;
257                        }
258                        return 0;
259                case TRACE_OPTION_META_FREQ:
260                case TRACE_OPTION_SNAPLEN:
261                case TRACE_OPTION_PROMISC:
262                case TRACE_OPTION_FILTER:
263                case TRACE_OPTION_HASHER:
264                case TRACE_OPTION_REPLAY_SPEEDUP:
265                case TRACE_OPTION_CONSTANT_ERF_FRAMING:
266                        break;
267        }
268
269        trace_set_err(libtrace, TRACE_ERR_UNKNOWN_OPTION, "Unknown option %i",
270                        option);
271        return -1;
272}
273
274static int pcapng_fin_input(libtrace_t *libtrace) {
275
276        int i = 0;
277
278        for (i = 0; i < DATA(libtrace)->allocatedinterfaces; i++) {
279                free(DATA(libtrace)->interfaces[i]);
280        }
281
282        free(DATA(libtrace)->interfaces);
283
284        if (libtrace->io) {
285                wandio_destroy(libtrace->io);
286        }
287        free(libtrace->format_data);
288        return 0;
289}
290
291static char *pcapng_parse_next_option(libtrace_t *libtrace, char **pktbuf,
292                uint16_t *code, uint16_t *length, pcapng_hdr_t *blockhdr) {
293
294        struct pcapng_optheader *opthdr = (struct pcapng_optheader *)*pktbuf;
295        int to_skip;
296        int padding = 0;
297        char *eob; //end of block
298        char *optval;
299        if (DATA(libtrace)->byteswapped) {
300                eob = ((char *) blockhdr) + byteswap32(blockhdr->blocklen);
301        } else {
302                eob = ((char *) blockhdr) + blockhdr->blocklen;
303        }
304
305        if ((char *)blockhdr >= *pktbuf) {
306                return NULL;
307        }
308        // Check if we have reached the end of the block, +4 for trailing block-size
309        // We cannot assume a endofopt, so we add one
310        if (eob == (*pktbuf) + 4) {
311                *code = 0;
312                *length = 0;
313                return *pktbuf;
314        }
315        // If there is not enough space for another header we've encountered an error
316        if (eob < (*pktbuf) + 4 + sizeof(struct pcapng_optheader)) {
317                return NULL;
318        }
319
320        if (DATA(libtrace)->byteswapped) {
321                *code = byteswap16(opthdr->optcode);
322                *length = byteswap16(opthdr->optlen);
323        } else {
324                *code = opthdr->optcode;
325                *length = opthdr->optlen;
326        }
327
328        optval = *pktbuf + sizeof(struct pcapng_optheader);
329
330        if ((*length % 4) > 0) {
331                padding = (4 - (*length % 4));
332        } else {
333                padding = 0;
334        }
335
336        to_skip = (*length) + padding;
337        // Check the value we return is within the block length
338        if (eob < optval + to_skip + 4) {
339                return NULL;
340        }
341        *pktbuf = optval + to_skip;
342
343        return optval;
344}
345
346static inline int pcapng_read_body(libtrace_t *libtrace, char *body,
347                uint32_t to_read) {
348
349        int err;
350
351        err = wandio_read(libtrace->io, body, to_read);
352        if (err < 0) {
353                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED,
354                        "Failed reading pcapng block");
355                return err;
356        }
357
358        if (err == 0) {
359                return err;
360        }
361
362        if (err < (int)to_read) {
363                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
364                        "Incomplete pcapng block");
365                return -1;
366        }
367
368        return to_read;
369}
370
371static int pcapng_get_framing_length(const libtrace_packet_t *packet) {
372
373        switch(pcapng_get_record_type(packet)) {
374                case PCAPNG_SECTION_TYPE:
375                        return sizeof(pcapng_sec_t);
376                case PCAPNG_INTERFACE_TYPE:
377                        return sizeof(pcapng_int_t);
378                case PCAPNG_ENHANCED_PACKET_TYPE:
379                        return sizeof(pcapng_epkt_t);
380                case PCAPNG_SIMPLE_PACKET_TYPE:
381                        return sizeof(pcapng_spkt_t);
382                case PCAPNG_OLD_PACKET_TYPE:
383                        return sizeof(pcapng_opkt_t);
384                case PCAPNG_INTERFACE_STATS_TYPE:
385                        return sizeof(pcapng_stats_t);
386                case PCAPNG_NAME_RESOLUTION_TYPE:
387                        return sizeof(pcapng_nrb_t);
388                case PCAPNG_CUSTOM_TYPE:
389                case PCAPNG_CUSTOM_NONCOPY_TYPE:
390                        return sizeof(pcapng_custom_t);
391        }
392
393        /* If we get here, we aren't a valid pcapng packet */
394        trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
395                        "Invalid RT type for pcapng packet: %u",
396                        packet->type);
397        return -1;
398
399}
400
401static int pcapng_prepare_packet(libtrace_t *libtrace,
402                libtrace_packet_t *packet, void *buffer,
403                libtrace_rt_types_t rt_type, uint32_t flags) {
404
405        int hdrlen;
406
407        if (packet->buffer != buffer &&
408                        packet->buf_control == TRACE_CTRL_PACKET) {
409                free(packet->buffer);
410        }
411
412        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
413                packet->buf_control = TRACE_CTRL_PACKET;
414        } else {
415                packet->buf_control = TRACE_CTRL_EXTERNAL;
416        }
417
418        packet->type = rt_type;
419        packet->buffer = buffer;
420        packet->header = buffer;
421
422        hdrlen = pcapng_get_framing_length(packet);
423        if (hdrlen < 0) {
424                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
425                                "X Invalid RT type for pcapng packet: %u",
426                                packet->type);
427                return -1;
428        }
429        packet->payload = ((char *)packet->buffer) + hdrlen;
430
431        return 0;
432}
433
434static int pcapng_read_section(libtrace_t *libtrace,
435                libtrace_packet_t *packet, uint32_t flags) {
436
437        pcapng_sec_t *sechdr;
438        int err;
439        uint32_t to_read;
440        char *bodyptr = NULL;
441
442        err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_sec_t));
443        sechdr = (pcapng_sec_t *)packet->buffer;
444
445        if (err < 0) {
446                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED,
447                        "Reading pcapng section header block");
448                return -1;
449        }
450
451        if (err == 0) {
452                return 0;
453        }
454
455        if (err < (int)(sizeof(pcapng_sec_t))) {
456                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
457                        "Incomplete pcapng section header block");
458                return -1;
459        }
460
461        if (sechdr->blocktype != PCAPNG_SECTION_TYPE) {
462                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in pcapng section block");
463                return -1;
464        }
465
466        if (sechdr->ordering == 0x1A2B3C4D) {
467                DATA(libtrace)->byteswapped = false;
468        } else if (sechdr->ordering == 0x4D3C2B1A) {
469                DATA(libtrace)->byteswapped = true;
470        } else {
471                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
472                                "Parsing pcapng section header block");
473                return -1;
474        }
475
476
477        if (DATA(libtrace)->byteswapped) {
478                if (byteswap16(sechdr->majorversion) != 1 && byteswap16(sechdr->minorversion) != 0) {
479                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
480                                "Parsing pcapng version numbers");
481                        return -1;
482                }
483                to_read = byteswap32(sechdr->blocklen) - sizeof(pcapng_sec_t);
484        } else {
485                if (sechdr->majorversion != 1 && sechdr->minorversion != 0) {
486                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
487                                "Parsing pcapng version numbers");
488                        return -1;
489                }
490                to_read = sechdr->blocklen - sizeof(pcapng_sec_t);
491        }
492
493        /* Read all of the options etc. -- we don't need them for now, but
494         * we have to skip forward to the next useful header. */
495        bodyptr = (char *) packet->buffer + sizeof(pcapng_sec_t);
496        err = pcapng_read_body(libtrace, bodyptr, to_read);
497        if (err <= 0) {
498                return err;
499        }
500
501        packet->type = TRACE_RT_PCAPNG_META;
502        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
503                        packet->type, flags)) {
504                return -1;
505        }
506
507        return 1;
508}
509
510static int pcapng_read_interface(libtrace_t *libtrace,
511                libtrace_packet_t *packet, uint32_t blocklen, uint32_t flags) {
512
513        pcapng_int_t *inthdr;
514        pcapng_interface_t *newint;
515        uint16_t optcode, optlen;
516        char *optval = NULL;
517        char *bodyptr = NULL;
518
519        if (blocklen < sizeof(pcapng_int_t) + 4) {
520                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
521                        "Incomplete pcapng interface header block");
522                return -1;
523        }
524        inthdr = (pcapng_int_t *)packet->buffer;
525
526        newint = (pcapng_interface_t *)malloc(sizeof(pcapng_interface_t));
527
528        newint->id = DATA(libtrace)->nextintid;
529
530        newint->received = 0;
531        newint->dropped = 0;
532        newint->dropcounter = 0;
533        newint->accepted = 0;
534        newint->osdropped = 0;
535        newint->laststats = 0;
536        newint->tsresol = 1000000;
537
538        if (DATA(libtrace)->byteswapped) {
539                if (byteswap32(inthdr->blocktype) != PCAPNG_INTERFACE_TYPE) {
540                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in pcapng interface");
541                        return -1;
542                }
543                newint->snaplen = byteswap32(inthdr->snaplen);
544                newint->linktype = byteswap16(inthdr->linktype);
545        } else {
546                if (inthdr->blocktype != PCAPNG_INTERFACE_TYPE) {
547                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in pcapng interface");
548                        return -1;
549                }
550                newint->snaplen = inthdr->snaplen;
551                newint->linktype = inthdr->linktype;
552        }
553
554        if (DATA(libtrace)->nextintid == DATA(libtrace)->allocatedinterfaces) {
555                DATA(libtrace)->allocatedinterfaces += 10;
556                DATA(libtrace)->interfaces = (pcapng_interface_t **)realloc(
557                        DATA(libtrace)->interfaces,
558                        DATA(libtrace)->allocatedinterfaces * sizeof(
559                                pcapng_interface_t *));
560                memset(&DATA(libtrace)->interfaces[DATA(libtrace)->nextintid], 0, sizeof(void *) * 10);
561        }
562
563        DATA(libtrace)->interfaces[newint->id] = newint;
564        DATA(libtrace)->nextintid += 1;
565
566        bodyptr = (char *) packet->buffer + sizeof(pcapng_int_t);
567
568        packet->type = TRACE_RT_PCAPNG_META;
569
570        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
571                        packet->type, flags)) {
572                return -1;
573        }
574
575        do {
576                optval = pcapng_parse_next_option(libtrace, &bodyptr,
577                                &optcode, &optlen, (pcapng_hdr_t *) packet->buffer);
578                if (optval == NULL) {
579                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
580                                "Failed to read options for pcapng interface");
581                        return -1;
582                }
583
584                if (optcode == PCAPNG_IFOPT_TSRESOL) {
585                        uint8_t *resol = (uint8_t *)optval;
586
587                        if ((*resol & 0x80) != 0) {
588                                newint->tsresol = pow(2, *resol & 0x7f);
589
590                        } else {
591                                newint->tsresol = pow(10, *resol & 0x7f);
592                        }
593                }
594
595        } while (optcode != 0);
596
597        return (int) blocklen;
598
599}
600
601static int pcapng_read_nrb(libtrace_t *libtrace, libtrace_packet_t *packet,
602                uint32_t blocklen, uint32_t flags) {
603
604        /* Just read the NR records and pass them off to the caller. If
605         * they want to do anything with them, they can parse the records
606         * themselves.
607         */
608        pcapng_nrb_t *hdr = NULL;
609
610        if (blocklen < sizeof(pcapng_nrb_t) + 4) {
611                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
612                                "Incomplete pcapng name resolution block");
613                return -1;
614        }
615
616        hdr = (pcapng_nrb_t *)packet->buffer;
617
618        /* Read the rest of the packet into the buffer */
619        if (DATA(libtrace)->byteswapped) {
620                if (byteswap32(hdr->blocktype) != PCAPNG_NAME_RESOLUTION_TYPE) {
621                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in pcapng name "
622                                "resolution block");
623                        return -1;
624                }
625        } else {
626                if (hdr->blocktype != PCAPNG_NAME_RESOLUTION_TYPE) {
627                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in pcapng name "
628                                "resolution block");
629                        return -1;
630                }
631        }
632
633        packet->type = TRACE_RT_PCAPNG_META;
634        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
635                        packet->type, flags)) {
636                return -1;
637        }
638
639        return (int) blocklen;
640
641}
642
643static int pcapng_read_custom(libtrace_t *libtrace, libtrace_packet_t *packet,
644                uint32_t blocklen, uint32_t flags) {
645
646        /* Just read the custom records and pass them off to the caller. If
647         * they want to do anything with them, they can parse the records
648         * themselves.
649         */
650        pcapng_custom_t *hdr = NULL;
651
652        if (blocklen < sizeof(pcapng_custom_t) + 4) {
653                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
654                                "Incomplete pcapng custom block");
655                return -1;
656        }
657
658        hdr = (pcapng_custom_t *)packet->buffer;
659
660        /* Read the rest of the packet into the buffer */
661        if (DATA(libtrace)->byteswapped) {
662                if (byteswap32(hdr->blocktype) != PCAPNG_CUSTOM_TYPE ||
663                        byteswap32(hdr->blocktype) != PCAPNG_CUSTOM_NONCOPY_TYPE) {
664                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid blocktype "
665                                "in pcapng custom block");
666                        return -1;
667                }
668        } else {
669                if (hdr->blocktype != PCAPNG_CUSTOM_TYPE ||
670                        hdr->blocktype != PCAPNG_CUSTOM_NONCOPY_TYPE) {
671                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid blocktype "
672                                "in pcapng custom block");
673                        return -1;
674                }
675        }
676
677        packet->type = TRACE_RT_PCAPNG_META;
678        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
679                        packet->type, flags)) {
680                return -1;
681        }
682
683        return (int) blocklen;
684
685}
686
687static int pcapng_read_stats(libtrace_t *libtrace, libtrace_packet_t *packet,
688                uint32_t blocklen, uint32_t flags) {
689        pcapng_stats_t *hdr = NULL;
690        uint32_t ifaceid;
691        uint64_t timestamp;
692        pcapng_interface_t *interface;
693        uint16_t optcode, optlen;
694        char *optval;
695        char *bodyptr;
696
697        if (blocklen < sizeof(pcapng_stats_t) + 4) {
698                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
699                                "Incomplete pcapng interface stats header");
700                return -1;
701        }
702
703        hdr = (pcapng_stats_t *)packet->buffer;
704
705        /* Read the rest of the packet into the buffer */
706        if (DATA(libtrace)->byteswapped) {
707                if (byteswap32(hdr->blocktype) != PCAPNG_INTERFACE_STATS_TYPE) {
708                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type "
709                                "in pcapng statistics block");
710                        return -1;
711                }
712                ifaceid = byteswap32(hdr->interfaceid);
713                timestamp = ((uint64_t)(byteswap32(hdr->timestamp_high)) << 32) + byteswap32(hdr->timestamp_low);
714        } else {
715                if (hdr->blocktype != PCAPNG_INTERFACE_STATS_TYPE) {
716                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type "
717                                "in pcapng statistics block");
718                        return -1;
719                }
720                ifaceid = hdr->interfaceid;
721                timestamp = ((uint64_t)(hdr->timestamp_high) << 32) +
722                                hdr->timestamp_low;
723        }
724
725        /* Set packet type based on interface linktype */
726        interface = lookup_interface(libtrace, ifaceid);
727        if (interface == NULL) {
728                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Unknown pcapng interface id: %u", ifaceid);
729                return -1;
730        }
731        packet->type = TRACE_RT_PCAPNG_META;
732
733        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
734                        packet->type, flags)) {
735                return -1;
736        }
737
738        if (timestamp < interface->laststats) {
739                return (int) blocklen;
740        }
741
742        /* All of the stats are stored as options */
743        bodyptr = packet->payload;
744
745        do {
746                optval = pcapng_parse_next_option(packet->trace, &bodyptr,
747                                &optcode, &optlen, (pcapng_hdr_t *) packet->buffer);
748                if (optval == NULL) {
749                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
750                                "Failed to read options for pcapng interface stats");
751                        return -1;
752                }
753
754                if (optcode == PCAPNG_STATOPT_IFRECV) {
755                        uint64_t *recvd = (uint64_t *)optval;
756                        if (DATA(packet->trace)->byteswapped) {
757                                interface->received = byteswap64(*recvd);
758                        } else {
759                                interface->received = *recvd;
760                        }
761                }
762
763                if (optcode == PCAPNG_STATOPT_IFDROP) {
764                        uint64_t *drops = (uint64_t *)optval;
765                        if (DATA(packet->trace)->byteswapped) {
766                                interface->dropped = byteswap64(*drops);
767                        } else {
768                                interface->dropped = *drops;
769                        }
770                }
771
772                if (optcode == PCAPNG_STATOPT_OSDROP) {
773                        uint64_t *drops = (uint64_t *)optval;
774                        if (DATA(packet->trace)->byteswapped) {
775                                interface->osdropped = byteswap64(*drops);
776                        } else {
777                                interface->osdropped = *drops;
778                        }
779                }
780
781                if (optcode == PCAPNG_STATOPT_FILTERACCEPT) {
782                        uint64_t *accepts = (uint64_t *)optval;
783                        if (DATA(packet->trace)->byteswapped) {
784                                interface->accepted = byteswap64(*accepts);
785                        } else {
786                                interface->accepted = *accepts;
787                        }
788                }
789
790        } while (optcode != 0);
791        interface->laststats = timestamp;
792
793        return (int) blocklen;
794
795}
796
797static int pcapng_read_simple(libtrace_t *libtrace, libtrace_packet_t *packet,
798                uint32_t blocklen, uint32_t flags) {
799
800        uint32_t caplen;
801        pcapng_spkt_t *hdr = NULL;
802        pcapng_interface_t *interface;
803
804        if (blocklen < sizeof(pcapng_spkt_t) + 4) {
805                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
806                                "Incomplete pcapng simple packet header");
807                return -1;
808        }
809
810        hdr = (pcapng_spkt_t *)packet->buffer;
811
812        /* Read the rest of the packet into the buffer */
813        if (DATA(libtrace)->byteswapped) {
814                if (byteswap32(hdr->blocktype) != PCAPNG_SIMPLE_PACKET_TYPE) {
815                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in "
816                                "pcapng simple packet block");
817                        return -1;
818                }
819                caplen = byteswap32(hdr->blocklen) - sizeof(pcapng_spkt_t) - 4;
820                         /* account for trailing length field */
821        } else {
822                if (hdr->blocktype != PCAPNG_SIMPLE_PACKET_TYPE) {
823                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in "
824                                "pcapng simple packet block");
825                        return -1;
826                }
827                caplen = hdr->blocklen - sizeof(pcapng_spkt_t) - 4;
828                         /* account for trailing length field */
829        }
830
831        /* Set packet type based on interface linktype.
832         * Assume interface 0, since we have no interface field */
833        interface = lookup_interface(libtrace, 0);
834        if (interface == NULL) {
835                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Unknown pcapng interface id: %u", 0);
836                return -1;
837        }
838        packet->type = pcapng_linktype_to_rt(interface->linktype);
839
840        /* May as well cache the capture length now, since we've
841         * already got it in the right byte order */
842        packet->capture_length = caplen;
843
844        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
845                        packet->type, flags)) {
846                return -1;
847        }
848        return (int) blocklen;
849
850}
851
852static int pcapng_read_enhanced(libtrace_t *libtrace, libtrace_packet_t *packet,
853                uint32_t blocklen, uint32_t flags) {
854        pcapng_epkt_t *hdr = NULL;
855        uint32_t caplen;
856        uint32_t ifaceid;
857        pcapng_interface_t *interface;
858        uint16_t optcode, optlen;
859        char *optval;
860        char *bodyptr;
861
862        if (blocklen < (int)sizeof(pcapng_epkt_t) + 4) {
863                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
864                                "Incomplete pcapng enhanced packet header");
865                return -1;
866        }
867
868        hdr = (pcapng_epkt_t *)packet->buffer;
869
870        /* Read the rest of the packet into the buffer */
871        if (DATA(libtrace)->byteswapped) {
872                if (byteswap32(hdr->blocktype) != PCAPNG_ENHANCED_PACKET_TYPE) {
873                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in "
874                                "pcapng enhanced packet block");
875                        return -1;
876                }
877                caplen = byteswap32(hdr->caplen);
878                ifaceid = byteswap32(hdr->interfaceid);
879        } else {
880                if (hdr->blocktype != PCAPNG_ENHANCED_PACKET_TYPE) {
881                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in "
882                                "pcapng enhanced packet block");
883                        return -1;
884                }
885                caplen = hdr->caplen;
886                ifaceid = hdr->interfaceid;
887        }
888
889        bodyptr = (char *) packet->buffer + sizeof(pcapng_epkt_t);
890
891        /* Set packet type based on interface linktype */
892        interface = lookup_interface(libtrace, ifaceid);
893        if (interface == NULL) {
894                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Unknown pcapng interface id: %u", ifaceid);
895                return -1;
896        }
897        packet->type = pcapng_linktype_to_rt(interface->linktype);
898
899        /* May as well cache the capture length now, since we've
900         * already got it in the right byte order */
901        packet->capture_length = caplen;
902
903        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
904                        packet->type, flags)) {
905                return -1;
906        }
907
908        /* Make sure to parse any useful options */
909        if ((caplen % 4) == 0) {
910                bodyptr = (char *) packet->payload + caplen;
911        } else {
912                bodyptr = (char *) packet->payload + caplen + (4 - (caplen % 4));
913        }
914        // Check the packet caplen actually fits within the block we read
915        if ((char *) packet->buffer + blocklen < bodyptr + 4) {
916                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
917                                "Incomplete pcapng enhanced packet header");
918                return -1;
919        }
920
921        do {
922                optval = pcapng_parse_next_option(packet->trace, &bodyptr,
923                                &optcode, &optlen, (pcapng_hdr_t *) packet->buffer);
924                if (optval == NULL) {
925                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
926                                "Failed to read options for pcapng enhanced packet");
927                        return -1;
928                }
929
930                if (optcode == PCAPNG_PKTOPT_DROPCOUNT) {
931                        uint64_t *drops = (uint64_t *)optval;
932                        if (DATA(packet->trace)->byteswapped) {
933                                interface->dropcounter += byteswap64(*drops);
934                        } else {
935                                interface->dropcounter += *drops;
936                        }
937                }
938
939        } while (optcode != 0);
940        return (int) blocklen;
941
942}
943
944static int pcapng_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet)
945{
946        struct pcapng_peeker peeker;
947        int err = 0;
948        uint32_t flags = 0;
949        uint32_t to_read;
950        uint32_t btype = 0;
951        int gotpacket = 0;
952
953        /* Ensure trace and packet are not NULL */
954        if (!libtrace) {
955                fprintf(stderr, "NULL trace passed into pcapng_read_packet()\n");
956                return TRACE_ERR_NULL_TRACE;
957        }
958        if (!packet) {
959                trace_set_err(libtrace, TRACE_ERR_NULL_PACKET, "NULL packet passed into "
960                        "pcapng_read_packet()\n");
961                return -1;
962        }
963
964        /* Peek to get next block type */
965        if (!libtrace->format_data) {
966                trace_set_err(libtrace, TRACE_ERR_BAD_FORMAT, "Trace has no format data in "
967                        "pcapng_read_packet()");
968                return -1;
969        }
970        if (!libtrace->io) {
971                trace_set_err(libtrace, TRACE_ERR_BAD_IO, "Trace has no valid file handle "
972                        "attached to it in pcapng_read_packet()");
973                return -1;
974        }
975
976        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
977                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
978        }
979
980        flags |= TRACE_PREP_OWN_BUFFER;
981
982        while (!gotpacket) {
983
984                if ((err=is_halted(libtrace)) != -1) {
985                        return err;
986                }
987
988                err = wandio_peek(libtrace->io, &peeker, sizeof(peeker));
989                if (err < 0) {
990                        trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng packet");
991                        return -1;
992                }
993
994                if (err == 0) {
995                        return 0;
996                }
997
998                if (err < (int)sizeof(struct pcapng_peeker)) {
999                        trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "Incomplete pcapng block");
1000                        return -1;
1001                }
1002
1003                // Warning: the byteorder might not be set yet, the section header sets this
1004                if (DATA(libtrace)->byteswapped) {
1005                        btype = byteswap32(peeker.blocktype);
1006                        to_read = byteswap32(peeker.blocklen);
1007                } else {
1008                        btype = peeker.blocktype;
1009                        to_read = peeker.blocklen;
1010                }
1011
1012                // Check we won't read off the end of the packet buffer. Assuming corruption.
1013                // Exclude the SECTION header, as this is used to identify the byteorder
1014                if (to_read > LIBTRACE_PACKET_BUFSIZE && btype != PCAPNG_SECTION_TYPE) {
1015                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1016                                      "Oversized pcapng block found, is the trace corrupted?");
1017                        return -1;
1018                }
1019                if (btype != PCAPNG_SECTION_TYPE) {
1020                        // Read the entire block, unless it is a section as our byte ordering has
1021                        // not been set yet.
1022                        err = pcapng_read_body(libtrace, packet->buffer, to_read);
1023                        if (err <= 0) {
1024                                return err;
1025                        }
1026                        if (*((uint32_t *)((char *)packet->buffer+to_read-4)) != peeker.blocklen) {
1027                                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1028                                              "Mismatched pcapng block sizes found, trace is invalid.");
1029                                return -1;
1030                        }
1031                }
1032
1033                switch (btype) {
1034                        /* Section Header */
1035                        case PCAPNG_SECTION_TYPE:
1036                                err = pcapng_read_section(libtrace, packet, flags);
1037                                gotpacket = 1;
1038                                break;
1039
1040                        /* Interface Header */
1041                        case PCAPNG_INTERFACE_TYPE:
1042                                err = pcapng_read_interface(libtrace, packet, to_read, flags);
1043                                gotpacket = 1;
1044                                break;
1045
1046
1047                        case PCAPNG_ENHANCED_PACKET_TYPE:
1048                                err = pcapng_read_enhanced(libtrace, packet,
1049                                                to_read, flags);
1050                                gotpacket = 1;
1051                                break;
1052
1053                        case PCAPNG_SIMPLE_PACKET_TYPE:
1054                                err = pcapng_read_simple(libtrace, packet, to_read, flags);
1055                                gotpacket = 1;
1056                                break;
1057
1058                        case PCAPNG_INTERFACE_STATS_TYPE:
1059                                err = pcapng_read_stats(libtrace, packet, to_read, flags);
1060                                gotpacket = 1;
1061                                break;
1062
1063                        case PCAPNG_NAME_RESOLUTION_TYPE:
1064                                err = pcapng_read_nrb(libtrace, packet, to_read, flags);
1065                                gotpacket = 1;
1066                                break;
1067
1068                        case PCAPNG_CUSTOM_TYPE:
1069                        case PCAPNG_CUSTOM_NONCOPY_TYPE:
1070                                err = pcapng_read_custom(libtrace, packet, to_read, flags);
1071                                gotpacket = 1;
1072                                break;
1073
1074
1075                        case PCAPNG_OLD_PACKET_TYPE:
1076                                /* TODO */
1077
1078                        /* Everything else -- don't care, skip it */
1079                        default:
1080                                break;
1081                }
1082        }
1083
1084        if (err <= 0) {
1085                return err;
1086        }
1087
1088        if (DATA(libtrace)->byteswapped)
1089                return byteswap32(peeker.blocklen);
1090        return peeker.blocklen;
1091
1092}
1093
1094static libtrace_linktype_t pcapng_get_link_type(const libtrace_packet_t *packet)
1095{
1096
1097        return pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type));
1098
1099}
1100
1101static libtrace_direction_t pcapng_get_direction(const libtrace_packet_t
1102                *packet) {
1103
1104        /* Defined in format_helper.c */
1105        return pcap_get_direction(packet);
1106}
1107
1108static struct timespec pcapng_get_timespec(const libtrace_packet_t *packet) {
1109
1110        struct timespec ts;
1111        uint64_t timestamp = 0;
1112        uint32_t interfaceid = 0;
1113        pcapng_interface_t *interface;
1114
1115        if (!packet) {
1116                fprintf(stderr, "NULL packet passed into pcapng_get_timespec()");
1117                /* Return default timespec on error? */
1118                return ts;
1119        }
1120        if (!packet->header) {
1121                trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET, "NULL header in packet in pcapng_get_timespec()");
1122                /* Return default timespec on error? */
1123                return ts;
1124        }
1125
1126        ts.tv_sec = 0;
1127        ts.tv_nsec = 0;
1128
1129        /* No timestamps in simple packets :( */
1130        if (PACKET_IS_SIMPLE) {
1131                return ts;
1132        }
1133
1134        if (PACKET_IS_ENHANCED) {
1135                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1136
1137                if (DATA(packet->trace)->byteswapped) {
1138                        timestamp = ((uint64_t)(byteswap32(ehdr->timestamp_high)) << 32) + byteswap32(ehdr->timestamp_low);
1139                        interfaceid = byteswap32(ehdr->interfaceid);
1140                } else {
1141                        timestamp = ((uint64_t)(ehdr->timestamp_high) << 32) +
1142                                        ehdr->timestamp_low;
1143                        interfaceid = ehdr->interfaceid;
1144                }
1145        } else if (PACKET_IS_OLD) {
1146                pcapng_opkt_t *ohdr = (pcapng_opkt_t *)packet->header;
1147
1148                if (DATA(packet->trace)->byteswapped) {
1149                        timestamp = ((uint64_t)(byteswap32(ohdr->timestamp_high)) << 32) + byteswap32(ohdr->timestamp_low);
1150                        interfaceid = byteswap16(ohdr->interfaceid);
1151                } else {
1152                        timestamp = ((uint64_t)(ohdr->timestamp_high) << 32) +
1153                                        ohdr->timestamp_low;
1154                        interfaceid = ohdr->interfaceid;
1155                }
1156
1157        }
1158
1159        if (timestamp == 0)
1160                return ts;
1161
1162
1163        interface = lookup_interface(packet->trace, interfaceid);
1164        if (interface == NULL) {
1165                trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
1166                                "Bad interface %u on pcapng packet",
1167                                interfaceid);
1168                return ts;
1169        }
1170
1171        ts.tv_sec = (timestamp / interface->tsresol);
1172        ts.tv_nsec = (uint64_t)(timestamp - (ts.tv_sec * interface->tsresol))
1173                        / ((double)interface->tsresol) * 1000000000;
1174
1175        return ts;
1176
1177}
1178
1179static inline int pcapng_get_wlen_header(const libtrace_packet_t *packet) {
1180
1181        if (PACKET_IS_ENHANCED) {
1182                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1183
1184                if (DATA(packet->trace)->byteswapped) {
1185                        return byteswap32(ehdr->wlen);
1186                } else {
1187                        return ehdr->wlen;
1188                }
1189        } else if (PACKET_IS_SIMPLE) {
1190                pcapng_spkt_t *shdr = (pcapng_spkt_t *)packet->header;
1191
1192                if (DATA(packet->trace)->byteswapped) {
1193                        return byteswap32(shdr->wlen);
1194                } else {
1195                        return shdr->wlen;
1196                }
1197        } else if (PACKET_IS_OLD) {
1198                pcapng_opkt_t *ohdr = (pcapng_opkt_t *)packet->header;
1199
1200                if (DATA(packet->trace)->byteswapped) {
1201                        return byteswap32(ohdr->wlen);
1202                } else {
1203                        return ohdr->wlen;
1204                }
1205        }
1206
1207        /* If we get here, we aren't a valid pcapng packet */
1208        trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
1209                        "Invalid RT type for pcapng packet: %u",
1210                        packet->type);
1211        return -1;
1212}
1213
1214static int pcapng_get_wire_length(const libtrace_packet_t *packet) {
1215
1216        /* First, get the wire length from the packet header */
1217        int baselen = pcapng_get_wlen_header(packet);
1218
1219        if (baselen == -1)
1220                return -1;
1221
1222        /* Then, account for the vagaries of different DLTs */
1223        if (rt_to_pcap_linktype(packet->type) == TRACE_DLT_EN10MB) {
1224                /* Include the missing FCS */
1225                baselen += 4;
1226        } else if (rt_to_pcap_linktype(packet->type) ==
1227                        TRACE_DLT_IEEE802_11_RADIO) {
1228                /* If the packet is Radiotap and the flags field indicates
1229                 * that the FCS is not included in the 802.11 frame, then
1230                 * we need to add 4 to the wire-length to account for it.
1231                 */
1232                uint8_t flags;
1233                void *link;
1234                libtrace_linktype_t linktype;
1235                link = trace_get_packet_buffer(packet, &linktype, NULL);
1236                trace_get_wireless_flags(link, linktype, &flags);
1237                if ((flags & TRACE_RADIOTAP_F_FCS) == 0) {
1238                        baselen += 4;
1239                }
1240        } else if (rt_to_pcap_linktype(packet->type) == TRACE_DLT_LINUX_SLL) {
1241                libtrace_sll_header_t *sll;
1242                sll = (libtrace_sll_header_t *)packet->payload;
1243
1244                /* Account for FCS when dealing with Ethernet packets that are
1245                 * encapsulated in Linux SLL. This should fix the problem
1246                 * where the wire lengths differ if we convert the packet to
1247                 * ERF */
1248                if (ntohs(sll->protocol) == TRACE_ETHERTYPE_LOOPBACK) {
1249                        baselen += 4;
1250                }
1251        }
1252
1253        return baselen;
1254}
1255
1256static int pcapng_get_capture_length(const libtrace_packet_t *packet) {
1257
1258        if (PACKET_IS_ENHANCED) {
1259                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1260
1261                if (DATA(packet->trace)->byteswapped) {
1262                        return byteswap32(ehdr->caplen);
1263                } else {
1264                        return ehdr->caplen;
1265                }
1266        } else if (PACKET_IS_SIMPLE) {
1267                pcapng_spkt_t *shdr = (pcapng_spkt_t *)packet->header;
1268
1269                /* Have to calculate this one by removing all the headers.
1270                 * Don't forget the extra length field at the end!
1271                 */
1272                if (DATA(packet->trace)->byteswapped) {
1273                        return byteswap32(shdr->blocklen) -
1274                                        sizeof(pcapng_spkt_t) - 4;
1275                } else {
1276                        return shdr->blocklen - sizeof(pcapng_spkt_t) - 4;
1277                }
1278        } else if (PACKET_IS_OLD) {
1279                pcapng_opkt_t *ohdr = (pcapng_opkt_t *)packet->header;
1280
1281                if (DATA(packet->trace)->byteswapped) {
1282                        return byteswap32(ohdr->caplen);
1283                } else {
1284                        return ohdr->caplen;
1285                }
1286        }
1287
1288        /* If we get here, we aren't a valid pcapng packet */
1289        trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
1290                        "Invalid RT type for pcapng packet: %u",
1291                        packet->type);
1292        return -1;
1293}
1294
1295static size_t pcapng_set_capture_length(libtrace_packet_t *packet,
1296                size_t size) {
1297        uint32_t current;
1298        char *copyto, *copyfrom;
1299        uint32_t tocopy;
1300
1301        if (!(PACKET_IS_SIMPLE) && !(PACKET_IS_ENHANCED)) {
1302                return 0;
1303        }
1304
1305        current = pcapng_get_capture_length(packet);
1306
1307        if (current <= size)
1308                return current;
1309
1310        copyto = (char *)packet->payload + size;
1311        copyfrom = (char *)packet->payload + current;
1312
1313        /* Need to make sure we keep the options and trailing length... */
1314
1315        if (PACKET_IS_SIMPLE) {
1316                tocopy = 4;
1317        } else {
1318                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1319                if (DATA(packet->trace)->byteswapped) {
1320                        tocopy =  byteswap32(ehdr->blocklen) -
1321                                        sizeof(pcapng_epkt_t) - current;
1322                } else {
1323                        tocopy = ehdr->blocklen - sizeof(pcapng_epkt_t) -
1324                                        current;
1325                }
1326        }
1327
1328        memmove(copyto, copyfrom, tocopy);
1329
1330        if (PACKET_IS_SIMPLE) {
1331                pcapng_spkt_t *shdr = (pcapng_spkt_t *)packet->header;
1332
1333                if (DATA(packet->trace)->byteswapped) {
1334                        shdr->blocklen = byteswap32(size + sizeof(pcapng_spkt_t) + tocopy);
1335                } else {
1336                        shdr->blocklen = size + sizeof(pcapng_spkt_t) + tocopy;
1337                }
1338        }
1339
1340        if (PACKET_IS_ENHANCED) {
1341                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1342
1343                if (DATA(packet->trace)->byteswapped) {
1344                        ehdr->blocklen = byteswap32(size + sizeof(pcapng_epkt_t) + tocopy);
1345                        ehdr->caplen = byteswap32(size);
1346                } else {
1347                        ehdr->blocklen = size + sizeof(pcapng_epkt_t) + tocopy;
1348                        ehdr->caplen = size;
1349                }
1350        }
1351        packet->capture_length = -1;
1352        return trace_get_capture_length(packet);
1353}
1354
1355
1356static struct libtrace_eventobj_t pcapng_event(libtrace_t *libtrace,
1357                libtrace_packet_t *packet) {
1358
1359        libtrace_eventobj_t event = {0,0,0.0,0};
1360
1361        if (DATA(libtrace)->realtime) {
1362                event.size = trace_read_packet(libtrace, packet);
1363                if (event.size < 1) {
1364                        event.type = TRACE_EVENT_TERMINATE;
1365                } else {
1366                        event.type = TRACE_EVENT_PACKET;
1367                }
1368        } else {
1369                event = trace_event_trace(libtrace, packet);
1370        }
1371
1372        return event;
1373}
1374
1375static void pcapng_get_statistics(libtrace_t *trace, libtrace_stat_t *stat) {
1376
1377        int i = 0;
1378        uint64_t drops = 0;
1379        uint64_t accepted = 0;
1380        uint64_t osdrops = 0;
1381        uint64_t received = 0;
1382
1383        if (!trace->format_data) {
1384                return;
1385        }
1386
1387        /* Add up all known interface stats */
1388        for (i = 0; i < DATA(trace)->nextintid; i++) {
1389                pcapng_interface_t *interface;
1390
1391                interface = lookup_interface(trace, i);
1392                if (interface == NULL) {
1393                        continue;
1394                }
1395
1396                received += interface->received;
1397                osdrops += interface->osdropped;
1398                accepted += interface->accepted;
1399                drops += interface->dropped;
1400
1401        }
1402
1403        stat->dropped = drops + osdrops;
1404        stat->dropped_valid = 1;
1405
1406        stat->received = received;
1407        stat->received_valid = 1;
1408
1409        stat->filtered = received - accepted;
1410        stat->filtered_valid = 1;
1411
1412        stat->captured = accepted;
1413        stat->captured_valid = 1;
1414
1415
1416}
1417
1418static void pcapng_help(void) {
1419        printf("pcapng format module: \n");
1420        printf("Supported input URIs:\n");
1421        printf("\tpcapng:/path/to/file\n");
1422        printf("\tpcapng:/path/to/file.gz\n");
1423        printf("\n");
1424        printf("\te.g.: pcapng:/tmp/trace.pcap\n");
1425        printf("\n");
1426}
1427
1428static struct libtrace_format_t pcapng = {
1429        "pcapng",
1430        "$Id$",
1431        TRACE_FORMAT_PCAPNG,
1432        NULL,                           /* probe filename */
1433        pcapng_probe_magic,             /* probe magic */
1434        pcapng_init_input,              /* init_input */
1435        pcapng_config_input,            /* config_input */
1436        pcapng_start_input,             /* start_input */
1437        NULL,                           /* pause_input */
1438        NULL,                           /* init_output */
1439        NULL,                           /* config_output */
1440        NULL,                           /* start_output */
1441        pcapng_fin_input,               /* fin_input */
1442        NULL,                           /* fin_output */
1443        pcapng_read_packet,             /* read_packet */
1444        pcapng_prepare_packet,          /* prepare_packet */
1445        NULL,                           /* fin_packet */
1446        NULL,                           /* write_packet */
1447        NULL,                           /* flush_output */
1448        pcapng_get_link_type,           /* get_link_type */
1449        pcapng_get_direction,           /* get_direction */
1450        NULL,                           /* set_direction */
1451        NULL,                           /* get_erf_timestamp */
1452        NULL,                           /* get_timeval */
1453        pcapng_get_timespec,            /* get_timespec */
1454        NULL,                           /* get_seconds */
1455        NULL,                           /* seek_erf */
1456        NULL,                           /* seek_timeval */
1457        NULL,                           /* seek_seconds */
1458        pcapng_get_capture_length,      /* get_capture_length */
1459        pcapng_get_wire_length,         /* get_wire_length */
1460        pcapng_get_framing_length,      /* get_framing_length */
1461        pcapng_set_capture_length,      /* set_capture_length */
1462        NULL,                           /* get_received_packets */
1463        NULL,                           /* get_filtered_packets */
1464        NULL,                           /* get_dropped_packets */
1465        pcapng_get_statistics,          /* get_statistics */
1466        NULL,                           /* get_fd */
1467        pcapng_event,                   /* trace_event */
1468        pcapng_help,                    /* help */
1469        NULL,                           /* next pointer */
1470        NON_PARALLEL(false)
1471};
1472
1473void pcapng_constructor(void) {
1474        register_format(&pcapng);
1475}
1476
Note: See TracBrowser for help on using the repository browser.