source: lib/format_pcapng.c @ d439067

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

Move packet cached fields into a distinct structure.

This will help tidy up the packet structure a little, as well as
simplify the cache clearing process (and maybe even speed it up
a little).

  • 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->cached.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->cached.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->cached.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.