source: lib/format_pcapng.c @ 063d5dd

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

pcapng: don't try to read section headers that are bigger than our buffer.

Fixes issues related to #95.

Note: in theory a section header larger than 65536 bytes is
technically valid in pcapng, but there is no realistic scenario
where this should happen. If it did, we would actually need to
read the first 64K bytes, update the section header length to
reflect the truncation we're about to do, then make sure we
read any remaining bytes into a temporary buffer so that our
read pointer is in the right place for the next block.

  • Property mode set to 100644
File size: 75.0 KB
Line 
1/*
2 *
3 * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand.
4 * All rights reserved.
5 *
6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/
10 *
11 * libtrace is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * libtrace is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 *
24 *
25 */
26#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#define PCAPNG_DECRYPTION_SECRETS_TYPE 0x0000000A
51
52#define PCAPNG_NRB_RECORD_END 0x0000
53#define PCAPNG_NRB_RECORD_IP4 0x0001
54#define PCAPNG_NRB_RECORD_IP6 0x0002
55
56#define PCAPNG_CUSTOM_OPTION_UTF8 0xBAC
57#define PCAPNG_CUSTOM_OPTION_BIN 0xBAD
58#define PCAPNG_CUSTOM_OPTION_UTF8_NONCOPY 0x4BAC
59#define PCAPNG_CUSTOM_OPTION_BIN_NONCOPY 0x4BAD
60
61#define PCAPNG_OPTION_END 0x0000
62
63#define PACKET_IS_ENHANCED (pcapng_get_record_type(packet) == PCAPNG_ENHANCED_PACKET_TYPE)
64
65#define PACKET_IS_SIMPLE (pcapng_get_record_type(packet) == PCAPNG_SIMPLE_PACKET_TYPE)
66
67#define PACKET_IS_OLD (pcapng_get_record_type(packet) == PCAPNG_OLD_PACKET_TYPE)
68
69#define PCAPNG_IFOPT_TSRESOL 9
70
71#define PCAPNG_PKTOPT_DROPCOUNT 4
72
73#define PCAPNG_STATOPT_START 2
74#define PCAPNG_STATOPT_END 3
75#define PCAPNG_STATOPT_IFRECV 4
76#define PCAPNG_STATOPT_IFDROP 5
77#define PCAPNG_STATOPT_FILTERACCEPT 6
78#define PCAPNG_STATOPT_OSDROP 7
79#define PCAPNG_STATOPT_USRDELIV 8
80
81typedef struct pcagng_section_header_t {
82        uint32_t blocktype;
83        uint32_t blocklen;
84        uint32_t ordering;
85        uint16_t majorversion;
86        uint16_t minorversion;
87        uint64_t sectionlen;
88} pcapng_sec_t;
89
90typedef struct pcapng_interface_header_t {
91        uint32_t blocktype;
92        uint32_t blocklen;
93        uint16_t linktype;
94        uint16_t reserved;
95        uint32_t snaplen;
96} pcapng_int_t;
97
98typedef struct pcapng_nrb_header_t {
99        uint32_t blocktype;
100        uint32_t blocklen;
101} pcapng_nrb_t;
102
103typedef struct pcapng_enhanced_packet_t {
104        uint32_t blocktype;
105        uint32_t blocklen;
106        uint32_t interfaceid;
107        uint32_t timestamp_high;
108        uint32_t timestamp_low;
109        uint32_t caplen;
110        uint32_t wlen;
111} pcapng_epkt_t;
112
113typedef struct pcapng_simple_packet_t {
114        uint32_t blocktype;
115        uint32_t blocklen;
116        uint32_t wlen;
117} pcapng_spkt_t;
118
119typedef struct pcapng_old_packet_t {
120        uint32_t blocktype;
121        uint32_t blocklen;
122        uint16_t interfaceid;
123        uint16_t drops;
124        uint32_t timestamp_high;
125        uint32_t timestamp_low;
126        uint32_t caplen;
127        uint32_t wlen;
128} pcapng_opkt_t;
129
130typedef struct pcapng_stats_header_t {
131        uint32_t blocktype;
132        uint32_t blocklen;
133        uint32_t interfaceid;
134        uint32_t timestamp_high;
135        uint32_t timestamp_low;
136} pcapng_stats_t;
137
138typedef struct pcapng_custom_header_t {
139        uint32_t blocktype;
140        uint32_t blocklen;
141        uint32_t pen;
142} pcapng_custom_t;
143
144typedef struct pcapng_interface_t pcapng_interface_t;
145
146struct pcapng_timestamp {
147        uint32_t timehigh;
148        uint32_t timelow;
149};
150
151struct pcapng_interface_t {
152
153        uint16_t id;
154        libtrace_dlt_t linktype;
155        uint32_t snaplen;
156        uint32_t tsresol;
157
158        uint64_t received;
159        uint64_t dropped;       /* as reported by interface stats */
160        uint64_t dropcounter;   /* as reported by packet records */
161        uint64_t accepted;
162        uint64_t osdropped;
163        uint64_t laststats;
164
165};
166
167struct pcapng_format_data_t {
168        bool started;
169        bool realtime;
170
171        /* Section data */
172        bool byteswapped;
173
174        /* Interface data */
175        pcapng_interface_t **interfaces;
176        uint16_t allocatedinterfaces;
177        uint16_t nextintid;
178
179};
180
181struct pcapng_format_data_out_t {
182        iow_t *file;
183        int compress_level;
184        int compress_type;
185        int flag;
186
187        /* Section data */
188        uint16_t sechdr_count;
189        bool byteswapped;
190
191        /* Interface data */
192        uint16_t nextintid;
193        libtrace_linktype_t lastdlt;
194};
195
196struct pcapng_optheader {
197        uint16_t optcode;
198        uint16_t optlen;
199};
200
201struct pcapng_custom_optheader {
202        uint16_t optcode;
203        uint16_t optlen;
204        uint32_t pen;
205};
206struct pcapng_nrb_record {
207        uint16_t recordtype;
208        uint16_t recordlen;
209};
210struct pcapng_peeker {
211        uint32_t blocktype;
212        uint32_t blocklen;
213};
214
215typedef struct pcapng_peeker pcapng_hdr_t;
216
217#define DATA(x) ((struct pcapng_format_data_t *)((x)->format_data))
218#define DATAOUT(x) ((struct pcapng_format_data_out_t*)((x)->format_data))
219
220static char *pcapng_parse_next_option(libtrace_t *libtrace, char **pktbuf,
221                uint16_t *code, uint16_t *length, pcapng_hdr_t *blockhdr);
222
223static bool pcapng_can_write(libtrace_packet_t *packet) {
224        /* Get the linktype */
225        libtrace_linktype_t ltype = trace_get_link_type(packet);
226
227        /* TODO convert erf meta to pcapng meta? */
228        if (ltype == TRACE_TYPE_CONTENT_INVALID
229                || ltype == TRACE_TYPE_UNKNOWN
230                || ltype == TRACE_TYPE_ERF_META
231                || ltype == TRACE_TYPE_NONDATA) {
232
233                return false;
234        }
235
236        return true;
237}
238
239static pcapng_interface_t *lookup_interface(libtrace_t *libtrace,
240                uint32_t intid) {
241
242        if (intid >= DATA(libtrace)->nextintid) {
243                return NULL;
244        }
245
246        return DATA(libtrace)->interfaces[intid];
247}
248
249static inline uint32_t pcapng_get_record_type(const libtrace_packet_t *packet) {
250        uint32_t *btype = (uint32_t *)packet->header;
251
252        /* only check for byteswapped if input format is pcapng */
253        if (packet->trace->format->type == TRACE_FORMAT_PCAPNG) {
254                if (DATA(packet->trace)->byteswapped)
255                        return byteswap32(*btype);
256        }
257
258        return *btype;
259}
260
261static inline uint32_t pcapng_swap32(libtrace_out_t *libtrace, uint32_t value) {
262        if (DATAOUT(libtrace)->byteswapped) {
263                return byteswap32(value);
264        } else {
265                return value;
266        }
267}
268static inline uint32_t pcapng_swap16(libtrace_out_t *libtrace, uint32_t value) {
269        if (DATAOUT(libtrace)->byteswapped) {
270                return byteswap16(value);
271        } else {
272                return value;
273        }
274}
275static inline uint32_t pcapng_get_blocklen(const libtrace_packet_t *packet) {
276        struct pcapng_peeker *hdr = (struct pcapng_peeker *)packet->buffer;
277
278        /* only check for byteswapped if input format is pcapng */
279        if (packet->trace->format->type == TRACE_FORMAT_PCAPNG) {
280                if (DATA(packet->trace)->byteswapped)
281                        return byteswap32(hdr->blocklen);
282        }
283
284        return hdr->blocklen;
285
286}
287
288#if 0
289static inline uint16_t pcapng_get_customdata_len(libtrace_packet_t *packet, char *ptr) {
290        struct pcapng_custom_optheader *hdr = (struct pcapng_custom_optheader *)ptr;
291
292        if (DATA(packet->trace)->byteswapped) {
293                return byteswap16(hdr->optlen);
294        } else {
295                return hdr->optlen;
296        }
297}
298static inline uint16_t pcapng_get_customdata_optcode(libtrace_packet_t *packet, char *ptr) {
299        struct pcapng_custom_optheader *hdr = (struct pcapng_custom_optheader *)ptr;
300
301        if (DATA(packet->trace)->byteswapped) {
302                return byteswap16(hdr->optcode);
303        } else {
304                return hdr->optcode;
305        }
306}
307#endif
308
309static inline uint16_t pcapng_get_nrb_record_type(libtrace_packet_t *packet, char *ptr) {
310        struct pcapng_nrb_record *hdr = (struct pcapng_nrb_record *)ptr;
311        if (DATA(packet->trace)->byteswapped) {
312                return byteswap16(hdr->recordtype);
313        } else {
314                return hdr->recordtype;
315        }
316}
317static inline uint16_t pcapng_get_nrb_record_len(libtrace_packet_t *packet, char *ptr) {
318        struct pcapng_nrb_record *hdr = (struct pcapng_nrb_record *)ptr;
319        if (DATA(packet->trace)->byteswapped) {
320                return byteswap16(hdr->recordlen);
321        } else {
322                return hdr->recordlen;
323        }
324}
325static uint32_t pcapng_output_options(libtrace_out_t *libtrace, libtrace_packet_t *packet,
326        char *ptr) {
327
328        struct pcapng_optheader opthdr;
329        uint16_t optcode, optlen;
330        char *optval = NULL;
331        char *bodyptr = NULL;
332        int padding;
333        void *padding_data;
334        uint32_t len = 0;
335
336        bodyptr = ptr;
337
338        while ((optval = pcapng_parse_next_option(packet->trace, &bodyptr,
339                        &optcode, &optlen, (pcapng_hdr_t *) packet->buffer))) {
340
341                /* pcapng_parse_next_option byteswaps the opcode and len for us */
342                opthdr.optcode = optcode;
343                opthdr.optlen = optlen;
344
345                /* output the header */
346                wandio_wwrite(DATAOUT(libtrace)->file, &opthdr, sizeof(opthdr));
347
348                /* If this is a custom option */
349                if (optcode == PCAPNG_CUSTOM_OPTION_UTF8 ||
350                        optcode == PCAPNG_CUSTOM_OPTION_BIN ||
351                        optcode == PCAPNG_CUSTOM_OPTION_UTF8_NONCOPY ||
352                        optcode == PCAPNG_CUSTOM_OPTION_BIN_NONCOPY) {
353                        /* flip the pen and output the option value */
354                        //uint32_t pen = byteswap32((uint32_t)*optval);
355                        wandio_wwrite(DATAOUT(libtrace)->file, optval, sizeof(uint32_t));
356
357                        /* the len for custom options include pen */
358                        optval += sizeof(uint32_t);
359                        optlen -= sizeof(uint32_t);
360                }
361
362                /* output the rest of the data */
363                wandio_wwrite(DATAOUT(libtrace)->file, &optval, optlen);
364
365                /* calculate any required padding */
366                padding = optlen % 4;
367                if (padding) { padding = 4 - padding; }
368                padding_data = calloc(1, padding);
369                /* output the padding */
370                wandio_wwrite(DATAOUT(libtrace)->file, padding_data, padding);
371                free(padding_data);
372
373                len += sizeof(opthdr) + optlen;
374        }
375
376        return len;
377}
378static uint32_t pcapng_output_interface_packet(libtrace_out_t *libtrace, libtrace_packet_t *packet) {
379        pcapng_int_t *cur = (pcapng_int_t *)packet->header;
380        pcapng_int_t hdr;
381        char *bodyptr = NULL;
382
383        /* If the input trace is not pcapng we have no way of finding the byteordering
384         * this can occur if a packet is reconstructed with a deadtrace. Or if the packet
385         * is in the correct byte ordering just output it */
386        if ((packet->trace->format->type != TRACE_FORMAT_PCAPNG) ||
387                (DATA(packet->trace)->byteswapped == DATAOUT(libtrace)->byteswapped)) {
388                uint32_t len = pcapng_get_blocklen(packet);
389                wandio_wwrite(DATAOUT(libtrace)->file, packet->buffer, len);
390                return len;
391        }
392
393        /* Byteswap the headers */
394        hdr.blocktype = byteswap32(cur->blocktype);
395        hdr.blocklen = byteswap32(cur->blocklen);
396        hdr.linktype = byteswap16(cur->linktype);
397        hdr.reserved = byteswap16(cur->reserved);
398        hdr.snaplen = byteswap32(cur->snaplen);
399
400        wandio_wwrite(DATAOUT(libtrace)->file, &hdr, sizeof(hdr));
401        /* output any options */
402        bodyptr = (char *)packet->buffer + sizeof(hdr);
403        pcapng_output_options(libtrace, packet, bodyptr);
404        wandio_wwrite(DATAOUT(libtrace)->file, &hdr.blocklen, sizeof(hdr.blocklen));
405
406        return hdr.blocklen;
407}
408static uint32_t pcapng_output_simple_packet(libtrace_out_t *libtrace, libtrace_packet_t *packet) {
409        pcapng_spkt_t *cur = (pcapng_spkt_t *)packet->header;
410        pcapng_spkt_t hdr;
411        uint32_t len;
412        char *bodyptr = NULL;
413
414        /* If the input trace is not pcapng we have no way of finding the byteordering
415         * this can occur if a packet is reconstructed with a deadtrace. Or if the packet
416         * is in the correct byte ordering just output it */
417        if ((packet->trace->format->type != TRACE_FORMAT_PCAPNG) ||
418                (DATA(packet->trace)->byteswapped == DATAOUT(libtrace)->byteswapped)) {
419                len = pcapng_get_blocklen(packet);
420                wandio_wwrite(DATAOUT(libtrace)->file, packet->buffer, len);
421                return len;
422        }
423
424        hdr.blocktype = byteswap32(cur->blocktype);
425        hdr.blocklen = byteswap32(cur->blocklen);
426        hdr.wlen = byteswap32(cur->wlen);
427
428        wandio_wwrite(DATAOUT(libtrace)->file, &hdr, sizeof(hdr));
429
430        /* output the packet payload */
431        bodyptr = (char *)packet->buffer + sizeof(hdr);
432        len = pcapng_get_blocklen(packet) - sizeof(hdr) - sizeof(hdr.blocklen);
433        wandio_wwrite(DATAOUT(libtrace)->file, bodyptr, len);
434
435        wandio_wwrite(DATAOUT(libtrace)->file, &hdr.blocklen, sizeof(hdr.blocklen));
436
437        return hdr.blocklen;
438}
439static uint32_t pcapng_output_old_packet(libtrace_out_t *libtrace, libtrace_packet_t *packet) {
440        pcapng_opkt_t *cur = (pcapng_opkt_t *)packet->header;
441        pcapng_opkt_t hdr;
442        uint32_t len;
443        char *bodyptr = NULL;
444
445        /* If the input trace is not pcapng we have no way of finding the byteordering
446         * this can occur if a packet is reconstructed with a deadtrace. Or if the packet
447         * is in the correct byte ordering just output it */
448        if ((packet->trace->format->type != TRACE_FORMAT_PCAPNG) ||
449                (DATA(packet->trace)->byteswapped == DATAOUT(libtrace)->byteswapped)) {
450                len = pcapng_get_blocklen(packet);
451                wandio_wwrite(DATAOUT(libtrace)->file, packet->buffer, len);
452                return len;
453        }
454
455        hdr.blocktype = byteswap32(cur->blocktype);
456        hdr.blocklen = byteswap32(cur->blocklen);
457        hdr.interfaceid = byteswap16(cur->interfaceid);
458        hdr.drops = byteswap16(cur->drops);
459        hdr.timestamp_high = byteswap32(cur->timestamp_high);
460        hdr.timestamp_low = byteswap32(cur->timestamp_low);
461        hdr.caplen = byteswap32(cur->caplen);
462        hdr.wlen = byteswap32(cur->wlen);
463
464        wandio_wwrite(DATAOUT(libtrace)->file, &hdr, sizeof(hdr));
465
466        /* output the packet payload */
467        bodyptr = (char *)packet->buffer + sizeof(hdr);
468        len = pcapng_get_blocklen(packet) - sizeof(hdr) - sizeof(hdr.blocklen);
469        wandio_wwrite(DATAOUT(libtrace)->file, bodyptr, len);
470
471        /* output any options if present */
472        pcapng_output_options(libtrace, packet, bodyptr);
473
474        wandio_wwrite(DATAOUT(libtrace)->file, &hdr.blocklen, sizeof(hdr.blocklen));
475
476
477        return hdr.blocklen;
478}
479static uint32_t pcapng_output_nameresolution_packet(libtrace_out_t *libtrace, libtrace_packet_t *packet) {
480        pcapng_nrb_t *cur = (pcapng_nrb_t *)packet->buffer;
481        pcapng_nrb_t hdr;
482        char *bodyptr = NULL;
483        int padding;
484        void *padding_data;
485
486        /* If the input trace is not pcapng we have no way of finding the byteordering
487         * this can occur if a packet is reconstructed with a deadtrace. Or if the packet
488         * is in the correct byte ordering just output it */
489        if ((packet->trace->format->type != TRACE_FORMAT_PCAPNG) ||
490                (DATA(packet->trace)->byteswapped == DATAOUT(libtrace)->byteswapped)) {
491                uint32_t len = pcapng_get_blocklen(packet);
492                wandio_wwrite(DATAOUT(libtrace)->file, packet->buffer, len);
493                return len;
494        }
495
496        hdr.blocktype = byteswap32(cur->blocktype);
497        hdr.blocklen = byteswap32(cur->blocklen);
498
499        /* output the header */
500        wandio_wwrite(DATAOUT(libtrace)->file, &hdr, sizeof(hdr));
501        bodyptr = (char *)packet->buffer + sizeof(hdr);
502
503        struct pcapng_nrb_record *nrbr = (struct pcapng_nrb_record *)bodyptr;
504
505        uint16_t record_type = pcapng_get_nrb_record_type(packet, bodyptr);
506        while (record_type != PCAPNG_NRB_RECORD_END) {
507
508                struct pcapng_nrb_record nrb;
509
510                /* recordlen contains only the length of the record value without
511                 * any padding */
512                uint16_t recordlen = pcapng_get_nrb_record_len(packet, bodyptr);
513
514                nrb.recordtype = byteswap16(nrbr->recordtype);
515                nrb.recordlen = byteswap16(nrbr->recordlen);
516
517                /* output the record header */
518                wandio_wwrite(DATAOUT(libtrace)->file, &nrb, sizeof(nrb));
519                bodyptr += sizeof(nrb);
520
521                /* output the record data */
522                wandio_wwrite(DATAOUT(libtrace)->file, bodyptr, recordlen);
523                bodyptr += recordlen;
524
525                /* calculate any required padding. record also contains the 8 byte header
526                 * but we dont need to subtract it because it will be removed with % 4 */
527                padding = recordlen % 4;
528                if (padding) { padding = 4 - padding; }
529                padding_data = calloc(1, padding);
530                /* output the padding */
531                wandio_wwrite(DATAOUT(libtrace)->file, padding_data, padding);
532                free(padding_data);
533                bodyptr += padding;
534
535                /* get the next record if it exists */
536                nrbr = (struct pcapng_nrb_record *)bodyptr;
537                record_type = pcapng_get_nrb_record_type(packet, bodyptr);
538        }
539
540        /* output nrb record end block */
541        struct pcapng_nrb_record nrbftr;
542        nrbftr.recordtype = PCAPNG_NRB_RECORD_END;
543        nrbftr.recordlen = 0;
544        wandio_wwrite(DATAOUT(libtrace)->file, &nrbftr, sizeof(nrbftr));
545        bodyptr += sizeof(nrbftr);
546
547        /* output any options if present */
548        pcapng_output_options(libtrace, packet, bodyptr);
549
550        /* and print out rest of the header */
551        wandio_wwrite(DATAOUT(libtrace)->file, &hdr.blocklen, sizeof(hdr.blocklen));
552
553        return hdr.blocklen;
554}
555static uint32_t pcapng_output_custom_packet(libtrace_out_t *libtrace, libtrace_packet_t *packet) {
556        pcapng_custom_t *cur = (pcapng_custom_t *)packet->buffer;
557        pcapng_custom_t hdr;
558        char *bodyptr = (char *)packet->buffer;
559
560        /* If the input trace is not pcapng we have no way of finding the byteordering
561         * this can occur if a packet is reconstructed with a deadtrace. Or if the packet
562         * is in the correct byte ordering just output it */
563        if ((packet->trace->format->type != TRACE_FORMAT_PCAPNG) ||
564                (DATA(packet->trace)->byteswapped == DATAOUT(libtrace)->byteswapped)) {
565                uint32_t len = pcapng_get_blocklen(packet);
566                wandio_wwrite(DATAOUT(libtrace)->file, packet->buffer, len);
567                return len;
568        }
569
570        hdr.blocktype = byteswap32(cur->blocktype);
571        hdr.blocklen = byteswap32(cur->blocklen);
572        hdr.pen = byteswap32(cur->blocklen);
573
574        /* output the header */
575        wandio_wwrite(DATAOUT(libtrace)->file, &hdr, sizeof(hdr));
576        bodyptr += sizeof(hdr);
577
578        /* now print out any options */
579        pcapng_output_options(libtrace, packet, bodyptr);
580
581        /* and print out rest of the header */
582        wandio_wwrite(DATAOUT(libtrace)->file, &hdr.blocklen, sizeof(hdr.blocklen));
583
584        return hdr.blocklen;
585}
586static uint32_t pcapng_output_enhanced_packet(libtrace_out_t *libtrace, libtrace_packet_t *packet) {
587        pcapng_epkt_t *cur = (pcapng_epkt_t *)packet->buffer;
588        pcapng_epkt_t hdr;
589        char *bodyptr = NULL;
590        uint32_t len;
591
592        /* If the input trace is not pcapng we have no way of finding the byteordering
593         * this can occur if a packet is reconstructed with a deadtrace. Or if the packet
594         * is in the correct byte ordering just output it */
595        if ((packet->trace->format->type != TRACE_FORMAT_PCAPNG) ||
596                (DATA(packet->trace)->byteswapped == DATAOUT(libtrace)->byteswapped)) {
597                len = pcapng_get_blocklen(packet);
598                wandio_wwrite(DATAOUT(libtrace)->file, packet->buffer, len);
599                return len;
600        }
601
602        hdr.blocktype = byteswap32(cur->blocktype);
603        hdr.blocklen = byteswap32(cur->blocklen);
604        hdr.interfaceid = byteswap32(cur->interfaceid);
605        hdr.timestamp_high = byteswap32(cur->timestamp_high);
606        hdr.timestamp_low = byteswap32(cur->timestamp_low);
607        hdr.caplen = byteswap32(cur->caplen);
608        hdr.wlen = byteswap32(cur->wlen);
609
610        /* output beginning of header */
611        wandio_wwrite(DATAOUT(libtrace)->file, &hdr, sizeof(hdr));
612
613        /* output the packet payload */
614        bodyptr = (char *)packet->buffer + sizeof(hdr);
615        len = pcapng_get_blocklen(packet) - sizeof(hdr) - sizeof(hdr.blocklen);
616        wandio_wwrite(DATAOUT(libtrace)->file, bodyptr, len);
617
618        /* output any options */
619        pcapng_output_options(libtrace, packet, bodyptr);
620
621        /* output end of header */
622        wandio_wwrite(DATAOUT(libtrace)->file, &hdr.blocklen, sizeof(hdr.blocklen));
623
624        return hdr.blocklen;
625}
626static uint32_t pcapng_output_interfacestats_packet(libtrace_out_t *libtrace, libtrace_packet_t *packet) {
627        pcapng_stats_t *cur = (pcapng_stats_t *)packet->header;
628        pcapng_stats_t hdr;
629        char *bodyptr = NULL;
630
631        /* If the input trace is not pcapng we have no way of finding the byteordering
632         * this can occur if a packet is reconstructed with a deadtrace. Or if the packet
633         * is in the correct byte ordering just output it */
634        if ((packet->trace->format->type != TRACE_FORMAT_PCAPNG) ||
635                (DATA(packet->trace)->byteswapped == DATAOUT(libtrace)->byteswapped)) {
636                uint32_t len = pcapng_get_blocklen(packet);
637                wandio_wwrite(DATAOUT(libtrace)->file, packet->buffer, len);
638                return len;
639        }
640
641        hdr.blocktype = byteswap32(cur->blocktype);
642        hdr.blocklen = byteswap32(cur->blocklen);
643        hdr.interfaceid = byteswap32(cur->interfaceid);
644        hdr.timestamp_high = byteswap32(cur->timestamp_high);
645        hdr.timestamp_low = byteswap32(cur->timestamp_low);
646
647        /* output interface stats header */
648        wandio_wwrite(DATAOUT(libtrace)->file, &hdr, sizeof(hdr));
649        /* output any options if present */
650        bodyptr = (char *)packet->buffer + sizeof(hdr);
651        pcapng_output_options(libtrace, packet, bodyptr);
652        /* output rest of interface stats header */
653        wandio_wwrite(DATAOUT(libtrace)->file, &hdr.blocklen, sizeof(hdr.blocklen));
654
655        return hdr.blocklen;
656}
657
658static int pcapng_probe_magic(io_t *io) {
659
660        pcapng_sec_t sechdr;
661        int len;
662
663        len = wandio_peek(io, &sechdr, sizeof(sechdr));
664        if (len < (int)sizeof(sechdr)) {
665                return 0;
666        }
667
668        if (sechdr.blocktype == PCAPNG_SECTION_TYPE) {
669                return 1;
670        }
671        return 0;
672}
673
674static struct pcapng_timestamp pcapng_get_timestamp(libtrace_packet_t *packet) {
675        struct timeval tv = trace_get_timeval(packet);
676        uint64_t time = ((uint64_t)tv.tv_sec * (uint64_t)1000000) + tv.tv_usec;
677
678        struct pcapng_timestamp timestamp;
679        timestamp.timehigh = time >> 32;
680        timestamp.timelow = time & 0xFFFFFFFF;
681
682        return timestamp;
683}
684
685
686static int pcapng_init_input(libtrace_t *libtrace) {
687        libtrace->format_data = malloc(sizeof(struct pcapng_format_data_t));
688        if (!libtrace->format_data) {
689                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Unable to allocate memory for "
690                        "format data inside pcapng_init_input()");
691                return -1;
692        }
693
694        DATA(libtrace)->started = false;
695        DATA(libtrace)->realtime = false;
696        DATA(libtrace)->byteswapped = true;
697        DATA(libtrace)->interfaces = (pcapng_interface_t **)calloc(10, \
698                        sizeof(pcapng_interface_t));
699        DATA(libtrace)->allocatedinterfaces = 10;
700        DATA(libtrace)->nextintid = 0;
701
702        return 0;
703}
704
705static int pcapng_config_output(libtrace_out_t *libtrace, trace_option_output_t option,
706        void *value) {
707
708        switch (option) {
709                case TRACE_OPTION_OUTPUT_COMPRESS:
710                        DATAOUT(libtrace)->compress_level = *(int *)value;
711                        return 0;
712                case TRACE_OPTION_OUTPUT_COMPRESSTYPE:
713                        DATAOUT(libtrace)->compress_type = *(int *)value;
714                        return 0;
715                case TRACE_OPTION_OUTPUT_FILEFLAGS:
716                        DATAOUT(libtrace)->flag = *(int *)value;
717                        return 0;
718                default:
719                        trace_set_err_out(libtrace, TRACE_ERR_UNKNOWN_OPTION,
720                                "Unknown option");
721                        return -1;
722        }
723}
724
725static int pcapng_start_input(libtrace_t *libtrace) {
726
727        if (!libtrace->io) {
728                libtrace->io = trace_open_file(libtrace);
729        }
730
731        if (!libtrace->io)
732                return -1;
733
734        return 0;
735}
736
737static int pcapng_config_input(libtrace_t *libtrace, trace_option_t option,
738                void *data) {
739
740        switch(option) {
741                case TRACE_OPTION_EVENT_REALTIME:
742                        if (*(int *)data != 0) {
743                                DATA(libtrace)->realtime = true;
744                        } else {
745                                DATA(libtrace)->realtime = false;
746                        }
747                        return 0;
748                case TRACE_OPTION_META_FREQ:
749                case TRACE_OPTION_SNAPLEN:
750                case TRACE_OPTION_PROMISC:
751                case TRACE_OPTION_FILTER:
752                case TRACE_OPTION_HASHER:
753                case TRACE_OPTION_REPLAY_SPEEDUP:
754                case TRACE_OPTION_CONSTANT_ERF_FRAMING:
755                        break;
756        }
757
758        trace_set_err(libtrace, TRACE_ERR_UNKNOWN_OPTION, "Unknown option %i",
759                        option);
760        return -1;
761}
762
763static int pcapng_init_output(libtrace_out_t *libtrace) {
764        libtrace->format_data = malloc(sizeof(struct pcapng_format_data_out_t));
765
766        DATAOUT(libtrace)->file = NULL;
767        DATAOUT(libtrace)->compress_level = 0;
768        DATAOUT(libtrace)->compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
769        DATAOUT(libtrace)->flag = O_CREAT|O_WRONLY;
770
771        DATAOUT(libtrace)->sechdr_count = 0;
772        DATAOUT(libtrace)->byteswapped = false;
773
774        DATAOUT(libtrace)->nextintid = 0;
775        DATAOUT(libtrace)->lastdlt = 0;
776
777        return 0;
778}
779
780static int pcapng_fin_input(libtrace_t *libtrace) {
781
782        int i = 0;
783
784        for (i = 0; i < DATA(libtrace)->allocatedinterfaces; i++) {
785                free(DATA(libtrace)->interfaces[i]);
786        }
787
788        free(DATA(libtrace)->interfaces);
789
790        if (libtrace->io) {
791                wandio_destroy(libtrace->io);
792        }
793        free(libtrace->format_data);
794        return 0;
795}
796
797static int pcapng_fin_output(libtrace_out_t *libtrace) {
798        if (DATAOUT(libtrace)->file) {
799                wandio_wdestroy(DATAOUT(libtrace)->file);
800        }
801        free(libtrace->format_data);
802        libtrace->format_data = NULL;
803        return 0;
804}
805
806static char *pcapng_parse_next_option(libtrace_t *libtrace, char **pktbuf,
807                uint16_t *code, uint16_t *length, pcapng_hdr_t *blockhdr) {
808
809        struct pcapng_optheader *opthdr = (struct pcapng_optheader *)*pktbuf;
810        int to_skip;
811        int padding = 0;
812        char *eob; //end of block
813        char *optval;
814        if (DATA(libtrace)->byteswapped) {
815                eob = ((char *) blockhdr) + byteswap32(blockhdr->blocklen);
816        } else {
817                eob = ((char *) blockhdr) + blockhdr->blocklen;
818        }
819
820        if ((char *)blockhdr >= *pktbuf) {
821                return NULL;
822        }
823        // Check if we have reached the end of the block, +4 for trailing block-size
824        // We cannot assume a endofopt, so we add one
825        if (eob == (*pktbuf) + 4) {
826                *code = 0;
827                *length = 0;
828                return *pktbuf;
829        }
830        // If there is not enough space for another header we've encountered an error
831        if (eob < (*pktbuf) + 4 + sizeof(struct pcapng_optheader)) {
832                return NULL;
833        }
834
835        if (DATA(libtrace)->byteswapped) {
836                *code = byteswap16(opthdr->optcode);
837                *length = byteswap16(opthdr->optlen);
838        } else {
839                *code = opthdr->optcode;
840                *length = opthdr->optlen;
841        }
842
843        optval = *pktbuf + sizeof(struct pcapng_optheader);
844
845        if ((*length % 4) > 0) {
846                padding = (4 - (*length % 4));
847        } else {
848                padding = 0;
849        }
850
851        to_skip = (*length) + padding;
852        // Check the value we return is within the block length
853        if (eob < optval + to_skip + 4) {
854                return NULL;
855        }
856        *pktbuf = optval + to_skip;
857
858        return optval;
859}
860
861static inline int pcapng_read_body(libtrace_t *libtrace, char *body,
862                uint32_t to_read) {
863
864        int err;
865
866        err = wandio_read(libtrace->io, body, to_read);
867        if (err < 0) {
868                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED,
869                        "Failed reading pcapng block");
870                return err;
871        }
872
873        if (err == 0) {
874                return err;
875        }
876
877        if (err < (int)to_read) {
878                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
879                        "Incomplete pcapng block");
880                return -1;
881        }
882
883        return to_read;
884}
885
886static int pcapng_get_framing_length(const libtrace_packet_t *packet) {
887
888        switch(pcapng_get_record_type(packet)) {
889                case PCAPNG_SECTION_TYPE:
890                        return sizeof(pcapng_sec_t);
891                case PCAPNG_INTERFACE_TYPE:
892                        return sizeof(pcapng_int_t);
893                case PCAPNG_ENHANCED_PACKET_TYPE:
894                        return sizeof(pcapng_epkt_t);
895                case PCAPNG_SIMPLE_PACKET_TYPE:
896                        return sizeof(pcapng_spkt_t);
897                case PCAPNG_OLD_PACKET_TYPE:
898                        return sizeof(pcapng_opkt_t);
899                case PCAPNG_INTERFACE_STATS_TYPE:
900                        return sizeof(pcapng_stats_t);
901                case PCAPNG_NAME_RESOLUTION_TYPE:
902                        return sizeof(pcapng_nrb_t);
903                case PCAPNG_CUSTOM_TYPE:
904                case PCAPNG_CUSTOM_NONCOPY_TYPE:
905                        return sizeof(pcapng_custom_t);
906        }
907
908        /* If we get here, we aren't a valid pcapng packet */
909        trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
910                        "Invalid RT type for pcapng packet: %u",
911                        packet->type);
912        return -1;
913
914}
915
916static int pcapng_prepare_packet(libtrace_t *libtrace,
917                libtrace_packet_t *packet, void *buffer,
918                libtrace_rt_types_t rt_type, uint32_t flags) {
919
920        int hdrlen;
921
922        if (packet->buffer != buffer &&
923                        packet->buf_control == TRACE_CTRL_PACKET) {
924                free(packet->buffer);
925        }
926
927        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
928                packet->buf_control = TRACE_CTRL_PACKET;
929        } else {
930                packet->buf_control = TRACE_CTRL_EXTERNAL;
931        }
932
933        packet->type = rt_type;
934        packet->buffer = buffer;
935        packet->header = buffer;
936
937        hdrlen = pcapng_get_framing_length(packet);
938        if (hdrlen < 0) {
939                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
940                                "X Invalid RT type for pcapng packet: %u",
941                                packet->type);
942                return -1;
943        }
944        packet->payload = ((char *)packet->buffer) + hdrlen;
945
946        return 0;
947}
948
949static int pcapng_write_packet(libtrace_out_t *libtrace, libtrace_packet_t *packet) {
950
951        if (!libtrace) {
952                fprintf(stderr, "NULL trace passed into pcapng_write_packet()\n");
953                return TRACE_ERR_NULL_TRACE;
954        }
955        if (!packet) {
956                trace_set_err_out(libtrace, TRACE_ERR_NULL_PACKET, "NULL packet passed "
957                        "into pcapng_write_packet()\n");
958                return -1;
959        }
960
961        /* Check pcapng can write this type of packet */
962        if (!pcapng_can_write(packet)) {
963                return 0;
964        }
965
966        libtrace_linktype_t linktype = trace_get_link_type(packet);
967
968        /* If the file is not open, open it */
969        if (!DATAOUT(libtrace)->file) {
970                DATAOUT(libtrace)->file = trace_open_file_out(libtrace,
971                        DATAOUT(libtrace)->compress_type,
972                        DATAOUT(libtrace)->compress_level,
973                        DATAOUT(libtrace)->flag);
974        }
975
976        /* If the packet is already encapsulated in a pcapng frame just output it */
977        switch (pcapng_get_record_type(packet)) {
978                case PCAPNG_SECTION_TYPE: {
979                        /* If the section header passed in is byteswapped, everything we output
980                         * till the next section header needs to be byteswapped. The next header
981                         * will determine if we need to continue swapping bytes */
982                        if (DATA(packet->trace)->byteswapped) {
983                                DATAOUT(libtrace)->byteswapped = true;
984                        } else {
985                                DATAOUT(libtrace)->byteswapped = false;
986                        }
987
988                        wandio_wwrite(DATAOUT(libtrace)->file, packet->buffer,
989                                pcapng_get_blocklen(packet));
990
991                        DATAOUT(libtrace)->sechdr_count += 1;
992
993                        return pcapng_get_blocklen(packet);
994                }
995                case PCAPNG_INTERFACE_TYPE: {
996                        /* increment the interface id */
997                        DATAOUT(libtrace)->nextintid += 1;
998
999                        return pcapng_output_interface_packet(libtrace, packet);
1000                }
1001                case PCAPNG_OLD_PACKET_TYPE: {
1002                        return pcapng_output_old_packet(libtrace, packet);
1003                }
1004                case PCAPNG_SIMPLE_PACKET_TYPE: {
1005                        if (DATAOUT(libtrace)->nextintid == 0) {
1006                                trace_set_err_out(libtrace, TRACE_ERR_BAD_PACKET,
1007                                        "Cannot output simple packet before a interface "
1008                                        "block has been output in pcapng_write_packet()\n");
1009                                return -1;
1010                        }
1011                        return pcapng_output_simple_packet(libtrace, packet);
1012                }
1013                case PCAPNG_NAME_RESOLUTION_TYPE: {
1014                        return pcapng_output_nameresolution_packet(libtrace, packet);
1015                }
1016                case PCAPNG_INTERFACE_STATS_TYPE: {
1017                        if (DATAOUT(libtrace)->nextintid == 0) {
1018                                trace_set_err_out(libtrace, TRACE_ERR_BAD_PACKET,
1019                                        "Cannot output a interface statistics block before a "
1020                                        "interface block has been output in pcapng_write_packet()\n");
1021                                return -1;
1022                        }
1023                        return pcapng_output_interfacestats_packet(libtrace, packet);
1024                }
1025                case PCAPNG_ENHANCED_PACKET_TYPE: {
1026                        if (DATAOUT(libtrace)->nextintid == 0) {
1027                                trace_set_err_out(libtrace, TRACE_ERR_BAD_PACKET,
1028                                        "Cannot output enhanced packet before a interface "
1029                                        "block has been output in pcapng_write_packet()\n");
1030                                return -1;
1031                        }
1032                        return pcapng_output_enhanced_packet(libtrace, packet);
1033                }
1034                case PCAPNG_CUSTOM_TYPE: {
1035                        return pcapng_output_custom_packet(libtrace, packet);
1036                }
1037                case PCAPNG_DECRYPTION_SECRETS_TYPE: {
1038                        return 0;
1039                }
1040                case PCAPNG_CUSTOM_NONCOPY_TYPE: {
1041                        /* This custom block type is not ment to be copied */
1042                        return 0;
1043                }
1044                default: {
1045
1046                        /* create section header if not already */
1047                        if (DATAOUT(libtrace)->sechdr_count == 0) {
1048                                /* Create section block */
1049                                pcapng_sec_t sechdr;
1050                                sechdr.blocktype = pcapng_swap32(libtrace, PCAPNG_SECTION_TYPE);
1051                                sechdr.blocklen = pcapng_swap32(libtrace, 28);
1052                                sechdr.ordering = pcapng_swap32(libtrace, 0x1A2B3C4D);
1053                                sechdr.majorversion = pcapng_swap16(libtrace, 1);
1054                                sechdr.minorversion = 0;
1055                                sechdr.sectionlen = 0xFFFFFFFFFFFFFFFF;
1056
1057                                wandio_wwrite(DATAOUT(libtrace)->file, &sechdr, sizeof(sechdr));
1058                                wandio_wwrite(DATAOUT(libtrace)->file, &sechdr.blocklen, sizeof(sechdr.blocklen));
1059
1060                                DATAOUT(libtrace)->sechdr_count += 1;
1061                        }
1062
1063                        /* create interface header if not already or if the linktype has changed */
1064                        if (DATAOUT(libtrace)->nextintid == 0
1065                                || DATAOUT(libtrace)->lastdlt != linktype) {
1066                                /* Create interface block*/
1067                                pcapng_int_t inthdr;
1068                                inthdr.blocktype = pcapng_swap32(libtrace, PCAPNG_INTERFACE_TYPE);
1069                                inthdr.blocklen = pcapng_swap32(libtrace, 20);
1070                                inthdr.linktype = pcapng_swap16(libtrace, libtrace_to_pcap_dlt(linktype));
1071                                inthdr.reserved = 0;
1072                                inthdr.snaplen = 0;
1073
1074                                wandio_wwrite(DATAOUT(libtrace)->file, &inthdr, sizeof(inthdr));
1075                                wandio_wwrite(DATAOUT(libtrace)->file, &inthdr.blocklen, sizeof(inthdr.blocklen));
1076
1077                                /* increment the interface counter */
1078                                DATAOUT(libtrace)->nextintid += 1;
1079                                /* update the last linktype */
1080                                DATAOUT(libtrace)->lastdlt = linktype;
1081                        }
1082
1083                        break;
1084                }
1085        }
1086
1087        /* If we get this far the packet is not a pcapng type so we need to encapsulate it
1088         * within a enhanced pcapng packet */
1089        uint32_t remaining;
1090        void *link;
1091        uint32_t blocklen;
1092        uint32_t padding;
1093        uint32_t caplen;
1094        uint32_t wirelen;
1095        void *padding_data;
1096        pcapng_epkt_t epkthdr;
1097
1098        link = trace_get_packet_buffer(packet, &linktype, &remaining);
1099
1100        wirelen = trace_get_wire_length(packet);
1101        caplen = trace_get_capture_length(packet);
1102
1103        /* trace_get_wirelength includes FCS, while pcapng doesn't */
1104        if (trace_get_link_type(packet)==TRACE_TYPE_ETH) {
1105                if (wirelen >= 4) {
1106                        wirelen -= 4;
1107                } else {
1108                        wirelen = 0;
1109                }
1110        }
1111        /* capture length should always be less than the wirelength */
1112        if (caplen > wirelen) {
1113                caplen = wirelen;
1114        }
1115
1116        /* calculate padding to 32bits */
1117        padding = caplen % 4;
1118        if (padding) { padding = 4 - padding; }
1119        padding_data = calloc(1, padding);
1120
1121        /* get pcapng_timestamp */
1122        struct pcapng_timestamp ts = pcapng_get_timestamp(packet);
1123
1124        /* calculate the block length */
1125        blocklen = sizeof(epkthdr) + sizeof(epkthdr.blocklen) + caplen + padding;
1126
1127        /* construct the packet */
1128        epkthdr.blocktype = pcapng_swap32(libtrace, PCAPNG_ENHANCED_PACKET_TYPE);
1129        epkthdr.blocklen = pcapng_swap32(libtrace, blocklen);
1130        epkthdr.interfaceid = pcapng_swap32(libtrace, DATAOUT(libtrace)->nextintid-1);
1131        epkthdr.timestamp_high = pcapng_swap32(libtrace, ts.timehigh);
1132        epkthdr.timestamp_low = pcapng_swap32(libtrace, ts.timelow);
1133        epkthdr.wlen = pcapng_swap32(libtrace, wirelen);
1134        epkthdr.caplen = pcapng_swap32(libtrace, caplen);
1135
1136        /* output enhanced packet header */
1137        wandio_wwrite(DATAOUT(libtrace)->file, &epkthdr, sizeof(epkthdr));
1138        /* output the packet */
1139        wandio_wwrite(DATAOUT(libtrace)->file, link, (size_t)caplen);
1140        /* output padding */
1141        wandio_wwrite(DATAOUT(libtrace)->file, padding_data, (size_t)padding);
1142        /* output rest of the enhanced packet */
1143        wandio_wwrite(DATAOUT(libtrace)->file, &epkthdr.blocklen, sizeof(epkthdr.blocklen));
1144
1145        /* release padding memory */
1146        free(padding_data);
1147
1148        return blocklen;
1149}
1150
1151static int pcapng_flush_output(libtrace_out_t *libtrace) {
1152        return wandio_wflush(DATAOUT(libtrace)->file);
1153}
1154
1155static int pcapng_read_section(libtrace_t *libtrace,
1156                libtrace_packet_t *packet, uint32_t flags) {
1157
1158        pcapng_sec_t *sechdr;
1159        int err;
1160        uint32_t to_read, blocklen;
1161        char *bodyptr = NULL;
1162
1163        err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_sec_t));
1164        sechdr = (pcapng_sec_t *)packet->buffer;
1165
1166        if (err < 0) {
1167                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED,
1168                        "Reading pcapng section header block");
1169                return -1;
1170        }
1171
1172        if (err == 0) {
1173                return 0;
1174        }
1175
1176        if (err < (int)(sizeof(pcapng_sec_t))) {
1177                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1178                        "Incomplete pcapng section header block");
1179                return -1;
1180        }
1181
1182        if (sechdr->blocktype != PCAPNG_SECTION_TYPE) {
1183                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in pcapng section block");
1184                return -1;
1185        }
1186
1187        if (sechdr->ordering == 0x1A2B3C4D) {
1188                DATA(libtrace)->byteswapped = false;
1189        } else if (sechdr->ordering == 0x4D3C2B1A) {
1190                DATA(libtrace)->byteswapped = true;
1191        } else {
1192                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1193                                "Parsing pcapng section header block");
1194                return -1;
1195        }
1196
1197
1198        if (DATA(libtrace)->byteswapped) {
1199                if (byteswap16(sechdr->majorversion) != 1 && byteswap16(sechdr->minorversion) != 0) {
1200                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1201                                "Parsing pcapng version numbers");
1202                        return -1;
1203                }
1204                blocklen = byteswap32(sechdr->blocklen);
1205
1206        } else {
1207                if (sechdr->majorversion != 1 && sechdr->minorversion != 0) {
1208                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1209                                "Parsing pcapng version numbers");
1210                        return -1;
1211                }
1212                blocklen = sechdr->blocklen;
1213        }
1214
1215        if (blocklen < sizeof(pcapng_sec_t)) {
1216                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1217                                "Block length in pcapng section header is invalid.");
1218                return -1;
1219        }
1220        to_read = blocklen - sizeof(pcapng_sec_t);
1221        /* Read all of the options etc. -- we don't need them for now, but
1222         * we have to skip forward to the next useful header. */
1223        bodyptr = (char *) packet->buffer + sizeof(pcapng_sec_t);
1224
1225        if (to_read > LIBTRACE_PACKET_BUFSIZE) {
1226                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1227                                "Excessively large section header contents of %u bytes, likely a corrupt trace.", to_read);
1228                return -1;
1229        }
1230
1231        err = pcapng_read_body(libtrace, bodyptr, to_read);
1232        if (err <= 0) {
1233                return err;
1234        }
1235
1236        packet->type = TRACE_RT_PCAPNG_META;
1237        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
1238                        packet->type, flags)) {
1239                return -1;
1240        }
1241
1242        return 1;
1243}
1244
1245static int pcapng_read_interface(libtrace_t *libtrace,
1246                libtrace_packet_t *packet, uint32_t blocklen, uint32_t flags) {
1247
1248        pcapng_int_t *inthdr;
1249        pcapng_interface_t *newint;
1250        uint16_t optcode, optlen;
1251        char *optval = NULL;
1252        char *bodyptr = NULL;
1253
1254        if (blocklen < sizeof(pcapng_int_t) + 4) {
1255                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1256                        "Incomplete pcapng interface header block");
1257                return -1;
1258        }
1259        inthdr = (pcapng_int_t *)packet->buffer;
1260
1261        newint = (pcapng_interface_t *)malloc(sizeof(pcapng_interface_t));
1262
1263        newint->id = DATA(libtrace)->nextintid;
1264
1265        newint->received = 0;
1266        newint->dropped = 0;
1267        newint->dropcounter = 0;
1268        newint->accepted = 0;
1269        newint->osdropped = 0;
1270        newint->laststats = 0;
1271        newint->tsresol = 1000000;
1272
1273        if (DATA(libtrace)->byteswapped) {
1274                if (byteswap32(inthdr->blocktype) != PCAPNG_INTERFACE_TYPE) {
1275                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in pcapng interface");
1276                        return -1;
1277                }
1278                newint->snaplen = byteswap32(inthdr->snaplen);
1279                newint->linktype = byteswap16(inthdr->linktype);
1280        } else {
1281                if (inthdr->blocktype != PCAPNG_INTERFACE_TYPE) {
1282                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in pcapng interface");
1283                        return -1;
1284                }
1285                newint->snaplen = inthdr->snaplen;
1286                newint->linktype = inthdr->linktype;
1287        }
1288
1289        if (DATA(libtrace)->nextintid == DATA(libtrace)->allocatedinterfaces) {
1290                DATA(libtrace)->allocatedinterfaces += 10;
1291                DATA(libtrace)->interfaces = (pcapng_interface_t **)realloc(
1292                        DATA(libtrace)->interfaces,
1293                        DATA(libtrace)->allocatedinterfaces * sizeof(
1294                                pcapng_interface_t *));
1295                memset(&DATA(libtrace)->interfaces[DATA(libtrace)->nextintid], 0, sizeof(void *) * 10);
1296        }
1297
1298        DATA(libtrace)->interfaces[newint->id] = newint;
1299        DATA(libtrace)->nextintid += 1;
1300
1301        bodyptr = (char *) packet->buffer + sizeof(pcapng_int_t);
1302
1303        packet->type = TRACE_RT_PCAPNG_META;
1304
1305        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
1306                        packet->type, flags)) {
1307                return -1;
1308        }
1309
1310        do {
1311                optval = pcapng_parse_next_option(libtrace, &bodyptr,
1312                                &optcode, &optlen, (pcapng_hdr_t *) packet->buffer);
1313                if (optval == NULL) {
1314                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1315                                "Failed to read options for pcapng interface");
1316                        return -1;
1317                }
1318
1319                if (optcode == PCAPNG_IFOPT_TSRESOL) {
1320                        uint8_t *resol = (uint8_t *)optval;
1321
1322                        if ((*resol & 0x80) != 0) {
1323                                newint->tsresol = pow(2, *resol & 0x7f);
1324
1325                        } else {
1326                                newint->tsresol = pow(10, *resol & 0x7f);
1327                        }
1328                }
1329
1330        } while (optcode != 0);
1331
1332        return (int) blocklen;
1333
1334}
1335
1336static int pcapng_read_nrb(libtrace_t *libtrace, libtrace_packet_t *packet,
1337                uint32_t blocklen, uint32_t flags) {
1338
1339        /* Just read the NR records and pass them off to the caller. If
1340         * they want to do anything with them, they can parse the records
1341         * themselves.
1342         */
1343        pcapng_nrb_t *hdr = NULL;
1344
1345        if (blocklen < sizeof(pcapng_nrb_t) + 4) {
1346                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1347                                "Incomplete pcapng name resolution block");
1348                return -1;
1349        }
1350
1351        hdr = (pcapng_nrb_t *)packet->buffer;
1352
1353        /* Read the rest of the packet into the buffer */
1354        if (DATA(libtrace)->byteswapped) {
1355                if (byteswap32(hdr->blocktype) != PCAPNG_NAME_RESOLUTION_TYPE) {
1356                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in pcapng name "
1357                                "resolution block");
1358                        return -1;
1359                }
1360        } else {
1361                if (hdr->blocktype != PCAPNG_NAME_RESOLUTION_TYPE) {
1362                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in pcapng name "
1363                                "resolution block");
1364                        return -1;
1365                }
1366        }
1367
1368        packet->type = TRACE_RT_PCAPNG_META;
1369        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
1370                        packet->type, flags)) {
1371                return -1;
1372        }
1373
1374        return (int) blocklen;
1375
1376}
1377
1378static int pcapng_read_custom(libtrace_t *libtrace, libtrace_packet_t *packet,
1379                uint32_t blocklen, uint32_t flags) {
1380
1381        /* Just read the custom records and pass them off to the caller. If
1382         * they want to do anything with them, they can parse the records
1383         * themselves.
1384         */
1385        pcapng_custom_t *hdr = NULL;
1386
1387        if (blocklen < sizeof(pcapng_custom_t) + 4) {
1388                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1389                                "Incomplete pcapng custom block");
1390                return -1;
1391        }
1392
1393        hdr = (pcapng_custom_t *)packet->buffer;
1394
1395        /* Read the rest of the packet into the buffer */
1396        if (DATA(libtrace)->byteswapped) {
1397                if (byteswap32(hdr->blocktype) != PCAPNG_CUSTOM_TYPE ||
1398                        byteswap32(hdr->blocktype) != PCAPNG_CUSTOM_NONCOPY_TYPE) {
1399                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid blocktype "
1400                                "in pcapng custom block");
1401                        return -1;
1402                }
1403        } else {
1404                if (hdr->blocktype != PCAPNG_CUSTOM_TYPE ||
1405                        hdr->blocktype != PCAPNG_CUSTOM_NONCOPY_TYPE) {
1406                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid blocktype "
1407                                "in pcapng custom block");
1408                        return -1;
1409                }
1410        }
1411
1412        packet->type = TRACE_RT_PCAPNG_META;
1413        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
1414                        packet->type, flags)) {
1415                return -1;
1416        }
1417
1418        return (int) blocklen;
1419
1420}
1421
1422static int pcapng_read_stats(libtrace_t *libtrace, libtrace_packet_t *packet,
1423                uint32_t blocklen, uint32_t flags) {
1424        pcapng_stats_t *hdr = NULL;
1425        uint32_t ifaceid;
1426        uint64_t timestamp;
1427        pcapng_interface_t *interface;
1428        uint16_t optcode, optlen;
1429        char *optval;
1430        char *bodyptr;
1431
1432        if (blocklen < sizeof(pcapng_stats_t) + 4) {
1433                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1434                                "Incomplete pcapng interface stats header");
1435                return -1;
1436        }
1437
1438        hdr = (pcapng_stats_t *)packet->buffer;
1439
1440        /* Read the rest of the packet into the buffer */
1441        if (DATA(libtrace)->byteswapped) {
1442                if (byteswap32(hdr->blocktype) != PCAPNG_INTERFACE_STATS_TYPE) {
1443                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type "
1444                                "in pcapng statistics block");
1445                        return -1;
1446                }
1447                ifaceid = byteswap32(hdr->interfaceid);
1448                timestamp = ((uint64_t)(byteswap32(hdr->timestamp_high)) << 32) + byteswap32(hdr->timestamp_low);
1449        } else {
1450                if (hdr->blocktype != PCAPNG_INTERFACE_STATS_TYPE) {
1451                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type "
1452                                "in pcapng statistics block");
1453                        return -1;
1454                }
1455                ifaceid = hdr->interfaceid;
1456                timestamp = ((uint64_t)(hdr->timestamp_high) << 32) +
1457                                hdr->timestamp_low;
1458        }
1459
1460        /* Set packet type based on interface linktype */
1461        interface = lookup_interface(libtrace, ifaceid);
1462        if (interface == NULL) {
1463                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Unknown pcapng interface id: %u", ifaceid);
1464                return -1;
1465        }
1466        packet->type = TRACE_RT_PCAPNG_META;
1467
1468        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
1469                        packet->type, flags)) {
1470                return -1;
1471        }
1472
1473        if (timestamp < interface->laststats) {
1474                return (int) blocklen;
1475        }
1476
1477        /* All of the stats are stored as options */
1478        bodyptr = packet->payload;
1479
1480        do {
1481                optval = pcapng_parse_next_option(packet->trace, &bodyptr,
1482                                &optcode, &optlen, (pcapng_hdr_t *) packet->buffer);
1483                if (optval == NULL) {
1484                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1485                                "Failed to read options for pcapng interface stats");
1486                        return -1;
1487                }
1488
1489                if (optcode == PCAPNG_STATOPT_IFRECV) {
1490                        uint64_t *recvd = (uint64_t *)optval;
1491                        if (DATA(packet->trace)->byteswapped) {
1492                                interface->received = byteswap64(*recvd);
1493                        } else {
1494                                interface->received = *recvd;
1495                        }
1496                }
1497
1498                if (optcode == PCAPNG_STATOPT_IFDROP) {
1499                        uint64_t *drops = (uint64_t *)optval;
1500                        if (DATA(packet->trace)->byteswapped) {
1501                                interface->dropped = byteswap64(*drops);
1502                        } else {
1503                                interface->dropped = *drops;
1504                        }
1505                }
1506
1507                if (optcode == PCAPNG_STATOPT_OSDROP) {
1508                        uint64_t *drops = (uint64_t *)optval;
1509                        if (DATA(packet->trace)->byteswapped) {
1510                                interface->osdropped = byteswap64(*drops);
1511                        } else {
1512                                interface->osdropped = *drops;
1513                        }
1514                }
1515
1516                if (optcode == PCAPNG_STATOPT_FILTERACCEPT) {
1517                        uint64_t *accepts = (uint64_t *)optval;
1518                        if (DATA(packet->trace)->byteswapped) {
1519                                interface->accepted = byteswap64(*accepts);
1520                        } else {
1521                                interface->accepted = *accepts;
1522                        }
1523                }
1524
1525        } while (optcode != 0);
1526        interface->laststats = timestamp;
1527
1528        return (int) blocklen;
1529
1530}
1531
1532static int pcapng_read_simple(libtrace_t *libtrace, libtrace_packet_t *packet,
1533                uint32_t blocklen, uint32_t flags) {
1534
1535        uint32_t caplen;
1536        pcapng_spkt_t *hdr = NULL;
1537        pcapng_interface_t *interface;
1538
1539        if (blocklen < sizeof(pcapng_spkt_t) + 4) {
1540                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1541                                "Incomplete pcapng simple packet header");
1542                return -1;
1543        }
1544
1545        hdr = (pcapng_spkt_t *)packet->buffer;
1546
1547        /* Read the rest of the packet into the buffer */
1548        if (DATA(libtrace)->byteswapped) {
1549                if (byteswap32(hdr->blocktype) != PCAPNG_SIMPLE_PACKET_TYPE) {
1550                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in "
1551                                "pcapng simple packet block");
1552                        return -1;
1553                }
1554                caplen = byteswap32(hdr->blocklen) - sizeof(pcapng_spkt_t) - 4;
1555                         /* account for trailing length field */
1556        } else {
1557                if (hdr->blocktype != PCAPNG_SIMPLE_PACKET_TYPE) {
1558                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in "
1559                                "pcapng simple packet block");
1560                        return -1;
1561                }
1562                caplen = hdr->blocklen - sizeof(pcapng_spkt_t) - 4;
1563                         /* account for trailing length field */
1564        }
1565
1566        /* Set packet type based on interface linktype.
1567         * Assume interface 0, since we have no interface field */
1568        interface = lookup_interface(libtrace, 0);
1569        if (interface == NULL) {
1570                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Unknown pcapng interface id: %u", 0);
1571                return -1;
1572        }
1573        packet->type = pcapng_linktype_to_rt(interface->linktype);
1574
1575        /* May as well cache the capture length now, since we've
1576         * already got it in the right byte order */
1577        packet->cached.capture_length = caplen;
1578
1579        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
1580                        packet->type, flags)) {
1581                return -1;
1582        }
1583        return (int) blocklen;
1584
1585}
1586
1587static int pcapng_read_enhanced(libtrace_t *libtrace, libtrace_packet_t *packet,
1588                uint32_t blocklen, uint32_t flags) {
1589        pcapng_epkt_t *hdr = NULL;
1590        uint32_t caplen;
1591        uint32_t ifaceid;
1592        pcapng_interface_t *interface;
1593        uint16_t optcode, optlen;
1594        char *optval;
1595        char *bodyptr;
1596
1597        if (blocklen < (int)sizeof(pcapng_epkt_t) + 4) {
1598                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1599                                "Incomplete pcapng enhanced packet header");
1600                return -1;
1601        }
1602
1603        hdr = (pcapng_epkt_t *)packet->buffer;
1604
1605        /* Read the rest of the packet into the buffer */
1606        if (DATA(libtrace)->byteswapped) {
1607                if (byteswap32(hdr->blocktype) != PCAPNG_ENHANCED_PACKET_TYPE) {
1608                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in "
1609                                "pcapng enhanced packet block");
1610                        return -1;
1611                }
1612                caplen = byteswap32(hdr->caplen);
1613                ifaceid = byteswap32(hdr->interfaceid);
1614        } else {
1615                if (hdr->blocktype != PCAPNG_ENHANCED_PACKET_TYPE) {
1616                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in "
1617                                "pcapng enhanced packet block");
1618                        return -1;
1619                }
1620                caplen = hdr->caplen;
1621                ifaceid = hdr->interfaceid;
1622        }
1623
1624        bodyptr = (char *) packet->buffer + sizeof(pcapng_epkt_t);
1625
1626        /* Set packet type based on interface linktype */
1627        interface = lookup_interface(libtrace, ifaceid);
1628        if (interface == NULL) {
1629                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Unknown pcapng interface id: %u", ifaceid);
1630                return -1;
1631        }
1632        packet->type = pcapng_linktype_to_rt(interface->linktype);
1633
1634        /* May as well cache the capture length now, since we've
1635         * already got it in the right byte order */
1636        packet->cached.capture_length = caplen;
1637
1638        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
1639                        packet->type, flags)) {
1640                return -1;
1641        }
1642
1643        /* Make sure to parse any useful options */
1644        if ((caplen % 4) == 0) {
1645                bodyptr = (char *) packet->payload + caplen;
1646        } else {
1647                bodyptr = (char *) packet->payload + caplen + (4 - (caplen % 4));
1648        }
1649        // Check the packet caplen actually fits within the block we read
1650        if ((char *) packet->buffer + blocklen < bodyptr + 4) {
1651                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1652                                "Incomplete pcapng enhanced packet header");
1653                return -1;
1654        }
1655
1656        do {
1657                optval = pcapng_parse_next_option(packet->trace, &bodyptr,
1658                                &optcode, &optlen, (pcapng_hdr_t *) packet->buffer);
1659                if (optval == NULL) {
1660                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1661                                "Failed to read options for pcapng enhanced packet");
1662                        return -1;
1663                }
1664
1665                if (optcode == PCAPNG_PKTOPT_DROPCOUNT) {
1666                        uint64_t *drops = (uint64_t *)optval;
1667                        if (DATA(packet->trace)->byteswapped) {
1668                                interface->dropcounter += byteswap64(*drops);
1669                        } else {
1670                                interface->dropcounter += *drops;
1671                        }
1672                }
1673
1674        } while (optcode != 0);
1675        return (int) blocklen;
1676
1677}
1678
1679static int pcapng_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet)
1680{
1681        struct pcapng_peeker peeker;
1682        int err = 0;
1683        uint32_t flags = 0;
1684        uint32_t to_read;
1685        uint32_t btype = 0;
1686        int gotpacket = 0;
1687
1688        /* Ensure trace and packet are not NULL */
1689        if (!libtrace) {
1690                fprintf(stderr, "NULL trace passed into pcapng_read_packet()\n");
1691                return TRACE_ERR_NULL_TRACE;
1692        }
1693        if (!packet) {
1694                trace_set_err(libtrace, TRACE_ERR_NULL_PACKET, "NULL packet passed into "
1695                        "pcapng_read_packet()\n");
1696                return -1;
1697        }
1698
1699        /* Peek to get next block type */
1700        if (!libtrace->format_data) {
1701                trace_set_err(libtrace, TRACE_ERR_BAD_FORMAT, "Trace has no format data in "
1702                        "pcapng_read_packet()");
1703                return -1;
1704        }
1705        if (!libtrace->io) {
1706                trace_set_err(libtrace, TRACE_ERR_BAD_IO, "Trace has no valid file handle "
1707                        "attached to it in pcapng_read_packet()");
1708                return -1;
1709        }
1710
1711        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
1712                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
1713        }
1714
1715        flags |= TRACE_PREP_OWN_BUFFER;
1716
1717        while (!gotpacket) {
1718
1719                if ((err=is_halted(libtrace)) != -1) {
1720                        return err;
1721                }
1722
1723                err = wandio_peek(libtrace->io, &peeker, sizeof(peeker));
1724                if (err < 0) {
1725                        trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng packet");
1726                        return -1;
1727                }
1728
1729                if (err == 0) {
1730                        return 0;
1731                }
1732
1733                if (err < (int)sizeof(struct pcapng_peeker)) {
1734                        trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "Incomplete pcapng block");
1735                        return -1;
1736                }
1737
1738                // Warning: the byteorder might not be set yet, the section header sets this
1739                if (DATA(libtrace)->byteswapped) {
1740                        btype = byteswap32(peeker.blocktype);
1741                        to_read = byteswap32(peeker.blocklen);
1742                } else {
1743                        btype = peeker.blocktype;
1744                        to_read = peeker.blocklen;
1745                }
1746
1747                // Check we won't read off the end of the packet buffer. Assuming corruption.
1748                // Exclude the SECTION header, as this is used to identify the byteorder
1749                if (to_read > LIBTRACE_PACKET_BUFSIZE && btype != PCAPNG_SECTION_TYPE) {
1750                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1751                                      "Oversized pcapng block found, is the trace corrupted?");
1752                        return -1;
1753                }
1754                if (btype != PCAPNG_SECTION_TYPE) {
1755                        // Read the entire block, unless it is a section as our byte ordering has
1756                        // not been set yet.
1757                        err = pcapng_read_body(libtrace, packet->buffer, to_read);
1758                        if (err <= 0) {
1759                                return err;
1760                        }
1761                        if (*((uint32_t *)((char *)packet->buffer+to_read-4)) != peeker.blocklen) {
1762                                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1763                                              "Mismatched pcapng block sizes found, trace is invalid.");
1764                                return -1;
1765                        }
1766                }
1767
1768                switch (btype) {
1769                        /* Section Header */
1770                        case PCAPNG_SECTION_TYPE:
1771                                err = pcapng_read_section(libtrace, packet, flags);
1772                                gotpacket = 1;
1773                                break;
1774
1775                        /* Interface Header */
1776                        case PCAPNG_INTERFACE_TYPE:
1777                                err = pcapng_read_interface(libtrace, packet, to_read, flags);
1778                                gotpacket = 1;
1779                                break;
1780
1781
1782                        case PCAPNG_ENHANCED_PACKET_TYPE:
1783                                err = pcapng_read_enhanced(libtrace, packet,
1784                                                to_read, flags);
1785                                gotpacket = 1;
1786                                break;
1787
1788                        case PCAPNG_SIMPLE_PACKET_TYPE:
1789                                err = pcapng_read_simple(libtrace, packet, to_read, flags);
1790                                gotpacket = 1;
1791                                break;
1792
1793                        case PCAPNG_INTERFACE_STATS_TYPE:
1794                                err = pcapng_read_stats(libtrace, packet, to_read, flags);
1795                                gotpacket = 1;
1796                                break;
1797
1798                        case PCAPNG_NAME_RESOLUTION_TYPE:
1799                                err = pcapng_read_nrb(libtrace, packet, to_read, flags);
1800                                gotpacket = 1;
1801                                break;
1802
1803                        case PCAPNG_CUSTOM_TYPE:
1804                        case PCAPNG_CUSTOM_NONCOPY_TYPE:
1805                                err = pcapng_read_custom(libtrace, packet, to_read, flags);
1806                                gotpacket = 1;
1807                                break;
1808
1809
1810                        case PCAPNG_OLD_PACKET_TYPE:
1811                                /* TODO */
1812
1813                        /* Everything else -- don't care, skip it */
1814                        default:
1815                                break;
1816                }
1817        }
1818
1819        if (err <= 0) {
1820                return err;
1821        }
1822
1823        if (DATA(libtrace)->byteswapped)
1824                return byteswap32(peeker.blocklen);
1825        return peeker.blocklen;
1826
1827}
1828
1829static libtrace_linktype_t pcapng_get_link_type(const libtrace_packet_t *packet) {
1830
1831        if (packet->type == TRACE_RT_PCAPNG_META) {
1832                return TRACE_TYPE_PCAPNG_META;
1833        }
1834
1835        return pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type));
1836}
1837
1838static libtrace_direction_t pcapng_get_direction(const libtrace_packet_t
1839                *packet) {
1840
1841        /* Defined in format_helper.c */
1842        return pcap_get_direction(packet);
1843}
1844
1845static struct timespec pcapng_get_timespec(const libtrace_packet_t *packet) {
1846
1847        struct timespec ts;
1848        uint64_t timestamp = 0;
1849        uint32_t interfaceid = 0;
1850        pcapng_interface_t *interface;
1851
1852        memset(&ts, 0, sizeof(struct timespec));
1853
1854        if (!packet) {
1855                fprintf(stderr, "NULL packet passed into pcapng_get_timespec()");
1856                /* Return default timespec on error? */
1857                return ts;
1858        }
1859        if (!packet->header) {
1860                trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET, "NULL header in packet in pcapng_get_timespec()");
1861                /* Return default timespec on error? */
1862                return ts;
1863        }
1864
1865        ts.tv_sec = 0;
1866        ts.tv_nsec = 0;
1867
1868        /* No timestamps in simple packets :( */
1869        if (PACKET_IS_SIMPLE) {
1870                return ts;
1871        }
1872
1873        if (PACKET_IS_ENHANCED) {
1874                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1875
1876                if (DATA(packet->trace)->byteswapped) {
1877                        timestamp = ((uint64_t)(byteswap32(ehdr->timestamp_high)) << 32) + byteswap32(ehdr->timestamp_low);
1878                        interfaceid = byteswap32(ehdr->interfaceid);
1879                } else {
1880                        timestamp = ((uint64_t)(ehdr->timestamp_high) << 32) +
1881                                        ehdr->timestamp_low;
1882                        interfaceid = ehdr->interfaceid;
1883                }
1884        } else if (PACKET_IS_OLD) {
1885                pcapng_opkt_t *ohdr = (pcapng_opkt_t *)packet->header;
1886
1887                if (DATA(packet->trace)->byteswapped) {
1888                        timestamp = ((uint64_t)(byteswap32(ohdr->timestamp_high)) << 32) + byteswap32(ohdr->timestamp_low);
1889                        interfaceid = byteswap16(ohdr->interfaceid);
1890                } else {
1891                        timestamp = ((uint64_t)(ohdr->timestamp_high) << 32) +
1892                                        ohdr->timestamp_low;
1893                        interfaceid = ohdr->interfaceid;
1894                }
1895
1896        }
1897
1898        if (timestamp == 0)
1899                return ts;
1900
1901
1902        interface = lookup_interface(packet->trace, interfaceid);
1903        if (interface == NULL) {
1904                trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
1905                                "Bad interface %u on pcapng packet",
1906                                interfaceid);
1907                return ts;
1908        }
1909
1910        ts.tv_sec = (timestamp / interface->tsresol);
1911        ts.tv_nsec = (uint64_t)(timestamp - (ts.tv_sec * interface->tsresol))
1912                        / ((double)interface->tsresol) * 1000000000;
1913
1914        return ts;
1915
1916}
1917
1918static inline int pcapng_get_wlen_header(const libtrace_packet_t *packet) {
1919
1920        if (PACKET_IS_ENHANCED) {
1921                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1922
1923                if (DATA(packet->trace)->byteswapped) {
1924                        return byteswap32(ehdr->wlen);
1925                } else {
1926                        return ehdr->wlen;
1927                }
1928        } else if (PACKET_IS_SIMPLE) {
1929                pcapng_spkt_t *shdr = (pcapng_spkt_t *)packet->header;
1930
1931                if (DATA(packet->trace)->byteswapped) {
1932                        return byteswap32(shdr->wlen);
1933                } else {
1934                        return shdr->wlen;
1935                }
1936        } else if (PACKET_IS_OLD) {
1937                pcapng_opkt_t *ohdr = (pcapng_opkt_t *)packet->header;
1938
1939                if (DATA(packet->trace)->byteswapped) {
1940                        return byteswap32(ohdr->wlen);
1941                } else {
1942                        return ohdr->wlen;
1943                }
1944        }
1945
1946        /* If we get here, we aren't a valid pcapng packet */
1947        trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
1948                        "Invalid RT type for pcapng packet: %u",
1949                        packet->type);
1950        return -1;
1951}
1952
1953static int pcapng_get_wire_length(const libtrace_packet_t *packet) {
1954
1955        /* First, get the wire length from the packet header */
1956        int baselen = pcapng_get_wlen_header(packet);
1957
1958        if (baselen == -1)
1959                return -1;
1960
1961        /* Then, account for the vagaries of different DLTs */
1962        if (rt_to_pcap_linktype(packet->type) == TRACE_DLT_EN10MB) {
1963                /* Include the missing FCS */
1964                baselen += 4;
1965        } else if (rt_to_pcap_linktype(packet->type) ==
1966                        TRACE_DLT_IEEE802_11_RADIO) {
1967                /* If the packet is Radiotap and the flags field indicates
1968                 * that the FCS is not included in the 802.11 frame, then
1969                 * we need to add 4 to the wire-length to account for it.
1970                 */
1971                uint8_t flags;
1972                void *link;
1973                libtrace_linktype_t linktype;
1974                link = trace_get_packet_buffer(packet, &linktype, NULL);
1975                trace_get_wireless_flags(link, linktype, &flags);
1976                if ((flags & TRACE_RADIOTAP_F_FCS) == 0) {
1977                        baselen += 4;
1978                }
1979        } else if (rt_to_pcap_linktype(packet->type) == TRACE_DLT_LINUX_SLL) {
1980                libtrace_sll_header_t *sll;
1981                sll = (libtrace_sll_header_t *)packet->payload;
1982
1983                /* Account for FCS when dealing with Ethernet packets that are
1984                 * encapsulated in Linux SLL. This should fix the problem
1985                 * where the wire lengths differ if we convert the packet to
1986                 * ERF */
1987                if (ntohs(sll->protocol) == TRACE_ETHERTYPE_LOOPBACK) {
1988                        baselen += 4;
1989                }
1990        }
1991
1992        return baselen;
1993}
1994
1995static int pcapng_get_capture_length(const libtrace_packet_t *packet) {
1996
1997        if (PACKET_IS_ENHANCED) {
1998                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1999
2000                if (DATA(packet->trace)->byteswapped) {
2001                        return byteswap32(ehdr->caplen);
2002                } else {
2003                        return ehdr->caplen;
2004                }
2005        } else if (PACKET_IS_SIMPLE) {
2006                pcapng_spkt_t *shdr = (pcapng_spkt_t *)packet->header;
2007
2008                /* Have to calculate this one by removing all the headers.
2009                 * Don't forget the extra length field at the end!
2010                 */
2011                if (DATA(packet->trace)->byteswapped) {
2012                        return byteswap32(shdr->blocklen) -
2013                                        sizeof(pcapng_spkt_t) - 4;
2014                } else {
2015                        return shdr->blocklen - sizeof(pcapng_spkt_t) - 4;
2016                }
2017        } else if (PACKET_IS_OLD) {
2018                pcapng_opkt_t *ohdr = (pcapng_opkt_t *)packet->header;
2019
2020                if (DATA(packet->trace)->byteswapped) {
2021                        return byteswap32(ohdr->caplen);
2022                } else {
2023                        return ohdr->caplen;
2024                }
2025        }
2026
2027        /* If we get here, we aren't a valid pcapng packet */
2028        trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
2029                        "Invalid RT type for pcapng packet: %u",
2030                        packet->type);
2031        return -1;
2032}
2033
2034static size_t pcapng_set_capture_length(libtrace_packet_t *packet,
2035                size_t size) {
2036        uint32_t current;
2037        char *copyto, *copyfrom;
2038        uint32_t tocopy;
2039
2040        if (!(PACKET_IS_SIMPLE) && !(PACKET_IS_ENHANCED)) {
2041                return 0;
2042        }
2043
2044        current = pcapng_get_capture_length(packet);
2045
2046        if (current <= size)
2047                return current;
2048
2049        copyto = (char *)packet->payload + size;
2050        copyfrom = (char *)packet->payload + current;
2051
2052        /* Need to make sure we keep the options and trailing length... */
2053
2054        if (PACKET_IS_SIMPLE) {
2055                tocopy = 4;
2056        } else {
2057                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
2058                if (DATA(packet->trace)->byteswapped) {
2059                        tocopy =  byteswap32(ehdr->blocklen) -
2060                                        sizeof(pcapng_epkt_t) - current;
2061                } else {
2062                        tocopy = ehdr->blocklen - sizeof(pcapng_epkt_t) -
2063                                        current;
2064                }
2065        }
2066
2067        memmove(copyto, copyfrom, tocopy);
2068
2069        if (PACKET_IS_SIMPLE) {
2070                pcapng_spkt_t *shdr = (pcapng_spkt_t *)packet->header;
2071
2072                if (DATA(packet->trace)->byteswapped) {
2073                        shdr->blocklen = byteswap32(size + sizeof(pcapng_spkt_t) + tocopy);
2074                } else {
2075                        shdr->blocklen = size + sizeof(pcapng_spkt_t) + tocopy;
2076                }
2077        }
2078
2079        if (PACKET_IS_ENHANCED) {
2080                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
2081
2082                if (DATA(packet->trace)->byteswapped) {
2083                        ehdr->blocklen = byteswap32(size + sizeof(pcapng_epkt_t) + tocopy);
2084                        ehdr->caplen = byteswap32(size);
2085                } else {
2086                        ehdr->blocklen = size + sizeof(pcapng_epkt_t) + tocopy;
2087                        ehdr->caplen = size;
2088                }
2089        }
2090        packet->cached.capture_length = -1;
2091        return trace_get_capture_length(packet);
2092}
2093
2094
2095static struct libtrace_eventobj_t pcapng_event(libtrace_t *libtrace,
2096                libtrace_packet_t *packet) {
2097
2098        libtrace_eventobj_t event = {0,0,0.0,0};
2099
2100        if (DATA(libtrace)->realtime) {
2101                event.size = trace_read_packet(libtrace, packet);
2102                if (event.size < 1) {
2103                        event.type = TRACE_EVENT_TERMINATE;
2104                } else {
2105                        event.type = TRACE_EVENT_PACKET;
2106                }
2107        } else {
2108                event = trace_event_trace(libtrace, packet);
2109        }
2110
2111        return event;
2112}
2113
2114static void pcapng_get_statistics(libtrace_t *trace, libtrace_stat_t *stat) {
2115
2116        int i = 0;
2117        uint64_t drops = 0;
2118        uint64_t accepted = 0;
2119        uint64_t osdrops = 0;
2120        uint64_t received = 0;
2121
2122        if (!trace->format_data) {
2123                return;
2124        }
2125
2126        /* Add up all known interface stats */
2127        for (i = 0; i < DATA(trace)->nextintid; i++) {
2128                pcapng_interface_t *interface;
2129
2130                interface = lookup_interface(trace, i);
2131                if (interface == NULL) {
2132                        continue;
2133                }
2134
2135                received += interface->received;
2136                osdrops += interface->osdropped;
2137                accepted += interface->accepted;
2138                drops += interface->dropped;
2139
2140        }
2141
2142        stat->dropped = drops + osdrops;
2143        stat->dropped_valid = 1;
2144
2145        stat->received = received;
2146        stat->received_valid = 1;
2147
2148        stat->filtered = received - accepted;
2149        stat->filtered_valid = 1;
2150
2151        stat->captured = accepted;
2152        stat->captured_valid = 1;
2153
2154
2155}
2156
2157static void pcapng_help(void) {
2158        printf("pcapng format module: \n");
2159        printf("Supported input URIs:\n");
2160        printf("\tpcapng:/path/to/file\n");
2161        printf("\tpcapng:/path/to/file.gz\n");
2162        printf("\n");
2163        printf("\te.g.: pcapng:/tmp/trace.pcap\n");
2164        printf("\n");
2165}
2166
2167static struct libtrace_format_t pcapng = {
2168        "pcapng",
2169        "$Id$",
2170        TRACE_FORMAT_PCAPNG,
2171        NULL,                           /* probe filename */
2172        pcapng_probe_magic,             /* probe magic */
2173        pcapng_init_input,              /* init_input */
2174        pcapng_config_input,            /* config_input */
2175        pcapng_start_input,             /* start_input */
2176        NULL,                           /* pause_input */
2177        pcapng_init_output,             /* init_output */
2178        pcapng_config_output,           /* config_output */
2179        NULL,                           /* start_output */
2180        pcapng_fin_input,               /* fin_input */
2181        pcapng_fin_output,              /* fin_output */
2182        pcapng_read_packet,             /* read_packet */
2183        pcapng_prepare_packet,          /* prepare_packet */
2184        NULL,                           /* fin_packet */
2185        pcapng_write_packet,            /* write_packet */
2186        pcapng_flush_output,            /* flush_output */
2187        pcapng_get_link_type,           /* get_link_type */
2188        pcapng_get_direction,           /* get_direction */
2189        NULL,                           /* set_direction */
2190        NULL,                           /* get_erf_timestamp */
2191        NULL,                           /* get_timeval */
2192        pcapng_get_timespec,            /* get_timespec */
2193        NULL,                           /* get_seconds */
2194        NULL,                           /* seek_erf */
2195        NULL,                           /* seek_timeval */
2196        NULL,                           /* seek_seconds */
2197        pcapng_get_capture_length,      /* get_capture_length */
2198        pcapng_get_wire_length,         /* get_wire_length */
2199        pcapng_get_framing_length,      /* get_framing_length */
2200        pcapng_set_capture_length,      /* set_capture_length */
2201        NULL,                           /* get_received_packets */
2202        NULL,                           /* get_filtered_packets */
2203        NULL,                           /* get_dropped_packets */
2204        pcapng_get_statistics,          /* get_statistics */
2205        NULL,                           /* get_fd */
2206        pcapng_event,                   /* trace_event */
2207        pcapng_help,                    /* help */
2208        NULL,                           /* next pointer */
2209        NON_PARALLEL(false)
2210};
2211
2212void pcapng_constructor(void) {
2213        register_format(&pcapng);
2214}
Note: See TracBrowser for help on using the repository browser.