source: lib/format_pcapng.c @ 15f32cb

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

Fix potential buffer overflow in pcapng:

Fixes #95.

  • Property mode set to 100644
File size: 74.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#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        err = pcapng_read_body(libtrace, bodyptr, to_read);
1225        if (err <= 0) {
1226                return err;
1227        }
1228
1229        packet->type = TRACE_RT_PCAPNG_META;
1230        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
1231                        packet->type, flags)) {
1232                return -1;
1233        }
1234
1235        return 1;
1236}
1237
1238static int pcapng_read_interface(libtrace_t *libtrace,
1239                libtrace_packet_t *packet, uint32_t blocklen, uint32_t flags) {
1240
1241        pcapng_int_t *inthdr;
1242        pcapng_interface_t *newint;
1243        uint16_t optcode, optlen;
1244        char *optval = NULL;
1245        char *bodyptr = NULL;
1246
1247        if (blocklen < sizeof(pcapng_int_t) + 4) {
1248                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1249                        "Incomplete pcapng interface header block");
1250                return -1;
1251        }
1252        inthdr = (pcapng_int_t *)packet->buffer;
1253
1254        newint = (pcapng_interface_t *)malloc(sizeof(pcapng_interface_t));
1255
1256        newint->id = DATA(libtrace)->nextintid;
1257
1258        newint->received = 0;
1259        newint->dropped = 0;
1260        newint->dropcounter = 0;
1261        newint->accepted = 0;
1262        newint->osdropped = 0;
1263        newint->laststats = 0;
1264        newint->tsresol = 1000000;
1265
1266        if (DATA(libtrace)->byteswapped) {
1267                if (byteswap32(inthdr->blocktype) != PCAPNG_INTERFACE_TYPE) {
1268                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in pcapng interface");
1269                        return -1;
1270                }
1271                newint->snaplen = byteswap32(inthdr->snaplen);
1272                newint->linktype = byteswap16(inthdr->linktype);
1273        } else {
1274                if (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 = inthdr->snaplen;
1279                newint->linktype = inthdr->linktype;
1280        }
1281
1282        if (DATA(libtrace)->nextintid == DATA(libtrace)->allocatedinterfaces) {
1283                DATA(libtrace)->allocatedinterfaces += 10;
1284                DATA(libtrace)->interfaces = (pcapng_interface_t **)realloc(
1285                        DATA(libtrace)->interfaces,
1286                        DATA(libtrace)->allocatedinterfaces * sizeof(
1287                                pcapng_interface_t *));
1288                memset(&DATA(libtrace)->interfaces[DATA(libtrace)->nextintid], 0, sizeof(void *) * 10);
1289        }
1290
1291        DATA(libtrace)->interfaces[newint->id] = newint;
1292        DATA(libtrace)->nextintid += 1;
1293
1294        bodyptr = (char *) packet->buffer + sizeof(pcapng_int_t);
1295
1296        packet->type = TRACE_RT_PCAPNG_META;
1297
1298        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
1299                        packet->type, flags)) {
1300                return -1;
1301        }
1302
1303        do {
1304                optval = pcapng_parse_next_option(libtrace, &bodyptr,
1305                                &optcode, &optlen, (pcapng_hdr_t *) packet->buffer);
1306                if (optval == NULL) {
1307                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1308                                "Failed to read options for pcapng interface");
1309                        return -1;
1310                }
1311
1312                if (optcode == PCAPNG_IFOPT_TSRESOL) {
1313                        uint8_t *resol = (uint8_t *)optval;
1314
1315                        if ((*resol & 0x80) != 0) {
1316                                newint->tsresol = pow(2, *resol & 0x7f);
1317
1318                        } else {
1319                                newint->tsresol = pow(10, *resol & 0x7f);
1320                        }
1321                }
1322
1323        } while (optcode != 0);
1324
1325        return (int) blocklen;
1326
1327}
1328
1329static int pcapng_read_nrb(libtrace_t *libtrace, libtrace_packet_t *packet,
1330                uint32_t blocklen, uint32_t flags) {
1331
1332        /* Just read the NR records and pass them off to the caller. If
1333         * they want to do anything with them, they can parse the records
1334         * themselves.
1335         */
1336        pcapng_nrb_t *hdr = NULL;
1337
1338        if (blocklen < sizeof(pcapng_nrb_t) + 4) {
1339                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1340                                "Incomplete pcapng name resolution block");
1341                return -1;
1342        }
1343
1344        hdr = (pcapng_nrb_t *)packet->buffer;
1345
1346        /* Read the rest of the packet into the buffer */
1347        if (DATA(libtrace)->byteswapped) {
1348                if (byteswap32(hdr->blocktype) != PCAPNG_NAME_RESOLUTION_TYPE) {
1349                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in pcapng name "
1350                                "resolution block");
1351                        return -1;
1352                }
1353        } else {
1354                if (hdr->blocktype != PCAPNG_NAME_RESOLUTION_TYPE) {
1355                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in pcapng name "
1356                                "resolution block");
1357                        return -1;
1358                }
1359        }
1360
1361        packet->type = TRACE_RT_PCAPNG_META;
1362        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
1363                        packet->type, flags)) {
1364                return -1;
1365        }
1366
1367        return (int) blocklen;
1368
1369}
1370
1371static int pcapng_read_custom(libtrace_t *libtrace, libtrace_packet_t *packet,
1372                uint32_t blocklen, uint32_t flags) {
1373
1374        /* Just read the custom records and pass them off to the caller. If
1375         * they want to do anything with them, they can parse the records
1376         * themselves.
1377         */
1378        pcapng_custom_t *hdr = NULL;
1379
1380        if (blocklen < sizeof(pcapng_custom_t) + 4) {
1381                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1382                                "Incomplete pcapng custom block");
1383                return -1;
1384        }
1385
1386        hdr = (pcapng_custom_t *)packet->buffer;
1387
1388        /* Read the rest of the packet into the buffer */
1389        if (DATA(libtrace)->byteswapped) {
1390                if (byteswap32(hdr->blocktype) != PCAPNG_CUSTOM_TYPE ||
1391                        byteswap32(hdr->blocktype) != PCAPNG_CUSTOM_NONCOPY_TYPE) {
1392                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid blocktype "
1393                                "in pcapng custom block");
1394                        return -1;
1395                }
1396        } else {
1397                if (hdr->blocktype != PCAPNG_CUSTOM_TYPE ||
1398                        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        }
1404
1405        packet->type = TRACE_RT_PCAPNG_META;
1406        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
1407                        packet->type, flags)) {
1408                return -1;
1409        }
1410
1411        return (int) blocklen;
1412
1413}
1414
1415static int pcapng_read_stats(libtrace_t *libtrace, libtrace_packet_t *packet,
1416                uint32_t blocklen, uint32_t flags) {
1417        pcapng_stats_t *hdr = NULL;
1418        uint32_t ifaceid;
1419        uint64_t timestamp;
1420        pcapng_interface_t *interface;
1421        uint16_t optcode, optlen;
1422        char *optval;
1423        char *bodyptr;
1424
1425        if (blocklen < sizeof(pcapng_stats_t) + 4) {
1426                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1427                                "Incomplete pcapng interface stats header");
1428                return -1;
1429        }
1430
1431        hdr = (pcapng_stats_t *)packet->buffer;
1432
1433        /* Read the rest of the packet into the buffer */
1434        if (DATA(libtrace)->byteswapped) {
1435                if (byteswap32(hdr->blocktype) != PCAPNG_INTERFACE_STATS_TYPE) {
1436                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type "
1437                                "in pcapng statistics block");
1438                        return -1;
1439                }
1440                ifaceid = byteswap32(hdr->interfaceid);
1441                timestamp = ((uint64_t)(byteswap32(hdr->timestamp_high)) << 32) + byteswap32(hdr->timestamp_low);
1442        } else {
1443                if (hdr->blocktype != PCAPNG_INTERFACE_STATS_TYPE) {
1444                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type "
1445                                "in pcapng statistics block");
1446                        return -1;
1447                }
1448                ifaceid = hdr->interfaceid;
1449                timestamp = ((uint64_t)(hdr->timestamp_high) << 32) +
1450                                hdr->timestamp_low;
1451        }
1452
1453        /* Set packet type based on interface linktype */
1454        interface = lookup_interface(libtrace, ifaceid);
1455        if (interface == NULL) {
1456                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Unknown pcapng interface id: %u", ifaceid);
1457                return -1;
1458        }
1459        packet->type = TRACE_RT_PCAPNG_META;
1460
1461        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
1462                        packet->type, flags)) {
1463                return -1;
1464        }
1465
1466        if (timestamp < interface->laststats) {
1467                return (int) blocklen;
1468        }
1469
1470        /* All of the stats are stored as options */
1471        bodyptr = packet->payload;
1472
1473        do {
1474                optval = pcapng_parse_next_option(packet->trace, &bodyptr,
1475                                &optcode, &optlen, (pcapng_hdr_t *) packet->buffer);
1476                if (optval == NULL) {
1477                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1478                                "Failed to read options for pcapng interface stats");
1479                        return -1;
1480                }
1481
1482                if (optcode == PCAPNG_STATOPT_IFRECV) {
1483                        uint64_t *recvd = (uint64_t *)optval;
1484                        if (DATA(packet->trace)->byteswapped) {
1485                                interface->received = byteswap64(*recvd);
1486                        } else {
1487                                interface->received = *recvd;
1488                        }
1489                }
1490
1491                if (optcode == PCAPNG_STATOPT_IFDROP) {
1492                        uint64_t *drops = (uint64_t *)optval;
1493                        if (DATA(packet->trace)->byteswapped) {
1494                                interface->dropped = byteswap64(*drops);
1495                        } else {
1496                                interface->dropped = *drops;
1497                        }
1498                }
1499
1500                if (optcode == PCAPNG_STATOPT_OSDROP) {
1501                        uint64_t *drops = (uint64_t *)optval;
1502                        if (DATA(packet->trace)->byteswapped) {
1503                                interface->osdropped = byteswap64(*drops);
1504                        } else {
1505                                interface->osdropped = *drops;
1506                        }
1507                }
1508
1509                if (optcode == PCAPNG_STATOPT_FILTERACCEPT) {
1510                        uint64_t *accepts = (uint64_t *)optval;
1511                        if (DATA(packet->trace)->byteswapped) {
1512                                interface->accepted = byteswap64(*accepts);
1513                        } else {
1514                                interface->accepted = *accepts;
1515                        }
1516                }
1517
1518        } while (optcode != 0);
1519        interface->laststats = timestamp;
1520
1521        return (int) blocklen;
1522
1523}
1524
1525static int pcapng_read_simple(libtrace_t *libtrace, libtrace_packet_t *packet,
1526                uint32_t blocklen, uint32_t flags) {
1527
1528        uint32_t caplen;
1529        pcapng_spkt_t *hdr = NULL;
1530        pcapng_interface_t *interface;
1531
1532        if (blocklen < sizeof(pcapng_spkt_t) + 4) {
1533                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1534                                "Incomplete pcapng simple packet header");
1535                return -1;
1536        }
1537
1538        hdr = (pcapng_spkt_t *)packet->buffer;
1539
1540        /* Read the rest of the packet into the buffer */
1541        if (DATA(libtrace)->byteswapped) {
1542                if (byteswap32(hdr->blocktype) != PCAPNG_SIMPLE_PACKET_TYPE) {
1543                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in "
1544                                "pcapng simple packet block");
1545                        return -1;
1546                }
1547                caplen = byteswap32(hdr->blocklen) - sizeof(pcapng_spkt_t) - 4;
1548                         /* account for trailing length field */
1549        } else {
1550                if (hdr->blocktype != PCAPNG_SIMPLE_PACKET_TYPE) {
1551                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in "
1552                                "pcapng simple packet block");
1553                        return -1;
1554                }
1555                caplen = hdr->blocklen - sizeof(pcapng_spkt_t) - 4;
1556                         /* account for trailing length field */
1557        }
1558
1559        /* Set packet type based on interface linktype.
1560         * Assume interface 0, since we have no interface field */
1561        interface = lookup_interface(libtrace, 0);
1562        if (interface == NULL) {
1563                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Unknown pcapng interface id: %u", 0);
1564                return -1;
1565        }
1566        packet->type = pcapng_linktype_to_rt(interface->linktype);
1567
1568        /* May as well cache the capture length now, since we've
1569         * already got it in the right byte order */
1570        packet->cached.capture_length = caplen;
1571
1572        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
1573                        packet->type, flags)) {
1574                return -1;
1575        }
1576        return (int) blocklen;
1577
1578}
1579
1580static int pcapng_read_enhanced(libtrace_t *libtrace, libtrace_packet_t *packet,
1581                uint32_t blocklen, uint32_t flags) {
1582        pcapng_epkt_t *hdr = NULL;
1583        uint32_t caplen;
1584        uint32_t ifaceid;
1585        pcapng_interface_t *interface;
1586        uint16_t optcode, optlen;
1587        char *optval;
1588        char *bodyptr;
1589
1590        if (blocklen < (int)sizeof(pcapng_epkt_t) + 4) {
1591                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1592                                "Incomplete pcapng enhanced packet header");
1593                return -1;
1594        }
1595
1596        hdr = (pcapng_epkt_t *)packet->buffer;
1597
1598        /* Read the rest of the packet into the buffer */
1599        if (DATA(libtrace)->byteswapped) {
1600                if (byteswap32(hdr->blocktype) != PCAPNG_ENHANCED_PACKET_TYPE) {
1601                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in "
1602                                "pcapng enhanced packet block");
1603                        return -1;
1604                }
1605                caplen = byteswap32(hdr->caplen);
1606                ifaceid = byteswap32(hdr->interfaceid);
1607        } else {
1608                if (hdr->blocktype != PCAPNG_ENHANCED_PACKET_TYPE) {
1609                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid block type in "
1610                                "pcapng enhanced packet block");
1611                        return -1;
1612                }
1613                caplen = hdr->caplen;
1614                ifaceid = hdr->interfaceid;
1615        }
1616
1617        bodyptr = (char *) packet->buffer + sizeof(pcapng_epkt_t);
1618
1619        /* Set packet type based on interface linktype */
1620        interface = lookup_interface(libtrace, ifaceid);
1621        if (interface == NULL) {
1622                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Unknown pcapng interface id: %u", ifaceid);
1623                return -1;
1624        }
1625        packet->type = pcapng_linktype_to_rt(interface->linktype);
1626
1627        /* May as well cache the capture length now, since we've
1628         * already got it in the right byte order */
1629        packet->cached.capture_length = caplen;
1630
1631        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
1632                        packet->type, flags)) {
1633                return -1;
1634        }
1635
1636        /* Make sure to parse any useful options */
1637        if ((caplen % 4) == 0) {
1638                bodyptr = (char *) packet->payload + caplen;
1639        } else {
1640                bodyptr = (char *) packet->payload + caplen + (4 - (caplen % 4));
1641        }
1642        // Check the packet caplen actually fits within the block we read
1643        if ((char *) packet->buffer + blocklen < bodyptr + 4) {
1644                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1645                                "Incomplete pcapng enhanced packet header");
1646                return -1;
1647        }
1648
1649        do {
1650                optval = pcapng_parse_next_option(packet->trace, &bodyptr,
1651                                &optcode, &optlen, (pcapng_hdr_t *) packet->buffer);
1652                if (optval == NULL) {
1653                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1654                                "Failed to read options for pcapng enhanced packet");
1655                        return -1;
1656                }
1657
1658                if (optcode == PCAPNG_PKTOPT_DROPCOUNT) {
1659                        uint64_t *drops = (uint64_t *)optval;
1660                        if (DATA(packet->trace)->byteswapped) {
1661                                interface->dropcounter += byteswap64(*drops);
1662                        } else {
1663                                interface->dropcounter += *drops;
1664                        }
1665                }
1666
1667        } while (optcode != 0);
1668        return (int) blocklen;
1669
1670}
1671
1672static int pcapng_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet)
1673{
1674        struct pcapng_peeker peeker;
1675        int err = 0;
1676        uint32_t flags = 0;
1677        uint32_t to_read;
1678        uint32_t btype = 0;
1679        int gotpacket = 0;
1680
1681        /* Ensure trace and packet are not NULL */
1682        if (!libtrace) {
1683                fprintf(stderr, "NULL trace passed into pcapng_read_packet()\n");
1684                return TRACE_ERR_NULL_TRACE;
1685        }
1686        if (!packet) {
1687                trace_set_err(libtrace, TRACE_ERR_NULL_PACKET, "NULL packet passed into "
1688                        "pcapng_read_packet()\n");
1689                return -1;
1690        }
1691
1692        /* Peek to get next block type */
1693        if (!libtrace->format_data) {
1694                trace_set_err(libtrace, TRACE_ERR_BAD_FORMAT, "Trace has no format data in "
1695                        "pcapng_read_packet()");
1696                return -1;
1697        }
1698        if (!libtrace->io) {
1699                trace_set_err(libtrace, TRACE_ERR_BAD_IO, "Trace has no valid file handle "
1700                        "attached to it in pcapng_read_packet()");
1701                return -1;
1702        }
1703
1704        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
1705                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
1706        }
1707
1708        flags |= TRACE_PREP_OWN_BUFFER;
1709
1710        while (!gotpacket) {
1711
1712                if ((err=is_halted(libtrace)) != -1) {
1713                        return err;
1714                }
1715
1716                err = wandio_peek(libtrace->io, &peeker, sizeof(peeker));
1717                if (err < 0) {
1718                        trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng packet");
1719                        return -1;
1720                }
1721
1722                if (err == 0) {
1723                        return 0;
1724                }
1725
1726                if (err < (int)sizeof(struct pcapng_peeker)) {
1727                        trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "Incomplete pcapng block");
1728                        return -1;
1729                }
1730
1731                // Warning: the byteorder might not be set yet, the section header sets this
1732                if (DATA(libtrace)->byteswapped) {
1733                        btype = byteswap32(peeker.blocktype);
1734                        to_read = byteswap32(peeker.blocklen);
1735                } else {
1736                        btype = peeker.blocktype;
1737                        to_read = peeker.blocklen;
1738                }
1739
1740                // Check we won't read off the end of the packet buffer. Assuming corruption.
1741                // Exclude the SECTION header, as this is used to identify the byteorder
1742                if (to_read > LIBTRACE_PACKET_BUFSIZE && btype != PCAPNG_SECTION_TYPE) {
1743                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1744                                      "Oversized pcapng block found, is the trace corrupted?");
1745                        return -1;
1746                }
1747                if (btype != PCAPNG_SECTION_TYPE) {
1748                        // Read the entire block, unless it is a section as our byte ordering has
1749                        // not been set yet.
1750                        err = pcapng_read_body(libtrace, packet->buffer, to_read);
1751                        if (err <= 0) {
1752                                return err;
1753                        }
1754                        if (*((uint32_t *)((char *)packet->buffer+to_read-4)) != peeker.blocklen) {
1755                                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1756                                              "Mismatched pcapng block sizes found, trace is invalid.");
1757                                return -1;
1758                        }
1759                }
1760
1761                switch (btype) {
1762                        /* Section Header */
1763                        case PCAPNG_SECTION_TYPE:
1764                                err = pcapng_read_section(libtrace, packet, flags);
1765                                gotpacket = 1;
1766                                break;
1767
1768                        /* Interface Header */
1769                        case PCAPNG_INTERFACE_TYPE:
1770                                err = pcapng_read_interface(libtrace, packet, to_read, flags);
1771                                gotpacket = 1;
1772                                break;
1773
1774
1775                        case PCAPNG_ENHANCED_PACKET_TYPE:
1776                                err = pcapng_read_enhanced(libtrace, packet,
1777                                                to_read, flags);
1778                                gotpacket = 1;
1779                                break;
1780
1781                        case PCAPNG_SIMPLE_PACKET_TYPE:
1782                                err = pcapng_read_simple(libtrace, packet, to_read, flags);
1783                                gotpacket = 1;
1784                                break;
1785
1786                        case PCAPNG_INTERFACE_STATS_TYPE:
1787                                err = pcapng_read_stats(libtrace, packet, to_read, flags);
1788                                gotpacket = 1;
1789                                break;
1790
1791                        case PCAPNG_NAME_RESOLUTION_TYPE:
1792                                err = pcapng_read_nrb(libtrace, packet, to_read, flags);
1793                                gotpacket = 1;
1794                                break;
1795
1796                        case PCAPNG_CUSTOM_TYPE:
1797                        case PCAPNG_CUSTOM_NONCOPY_TYPE:
1798                                err = pcapng_read_custom(libtrace, packet, to_read, flags);
1799                                gotpacket = 1;
1800                                break;
1801
1802
1803                        case PCAPNG_OLD_PACKET_TYPE:
1804                                /* TODO */
1805
1806                        /* Everything else -- don't care, skip it */
1807                        default:
1808                                break;
1809                }
1810        }
1811
1812        if (err <= 0) {
1813                return err;
1814        }
1815
1816        if (DATA(libtrace)->byteswapped)
1817                return byteswap32(peeker.blocklen);
1818        return peeker.blocklen;
1819
1820}
1821
1822static libtrace_linktype_t pcapng_get_link_type(const libtrace_packet_t *packet) {
1823
1824        if (packet->type == TRACE_RT_PCAPNG_META) {
1825                return TRACE_TYPE_PCAPNG_META;
1826        }
1827
1828        return pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type));
1829}
1830
1831static libtrace_direction_t pcapng_get_direction(const libtrace_packet_t
1832                *packet) {
1833
1834        /* Defined in format_helper.c */
1835        return pcap_get_direction(packet);
1836}
1837
1838static struct timespec pcapng_get_timespec(const libtrace_packet_t *packet) {
1839
1840        struct timespec ts;
1841        uint64_t timestamp = 0;
1842        uint32_t interfaceid = 0;
1843        pcapng_interface_t *interface;
1844
1845        memset(&ts, 0, sizeof(struct timespec));
1846
1847        if (!packet) {
1848                fprintf(stderr, "NULL packet passed into pcapng_get_timespec()");
1849                /* Return default timespec on error? */
1850                return ts;
1851        }
1852        if (!packet->header) {
1853                trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET, "NULL header in packet in pcapng_get_timespec()");
1854                /* Return default timespec on error? */
1855                return ts;
1856        }
1857
1858        ts.tv_sec = 0;
1859        ts.tv_nsec = 0;
1860
1861        /* No timestamps in simple packets :( */
1862        if (PACKET_IS_SIMPLE) {
1863                return ts;
1864        }
1865
1866        if (PACKET_IS_ENHANCED) {
1867                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1868
1869                if (DATA(packet->trace)->byteswapped) {
1870                        timestamp = ((uint64_t)(byteswap32(ehdr->timestamp_high)) << 32) + byteswap32(ehdr->timestamp_low);
1871                        interfaceid = byteswap32(ehdr->interfaceid);
1872                } else {
1873                        timestamp = ((uint64_t)(ehdr->timestamp_high) << 32) +
1874                                        ehdr->timestamp_low;
1875                        interfaceid = ehdr->interfaceid;
1876                }
1877        } else if (PACKET_IS_OLD) {
1878                pcapng_opkt_t *ohdr = (pcapng_opkt_t *)packet->header;
1879
1880                if (DATA(packet->trace)->byteswapped) {
1881                        timestamp = ((uint64_t)(byteswap32(ohdr->timestamp_high)) << 32) + byteswap32(ohdr->timestamp_low);
1882                        interfaceid = byteswap16(ohdr->interfaceid);
1883                } else {
1884                        timestamp = ((uint64_t)(ohdr->timestamp_high) << 32) +
1885                                        ohdr->timestamp_low;
1886                        interfaceid = ohdr->interfaceid;
1887                }
1888
1889        }
1890
1891        if (timestamp == 0)
1892                return ts;
1893
1894
1895        interface = lookup_interface(packet->trace, interfaceid);
1896        if (interface == NULL) {
1897                trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
1898                                "Bad interface %u on pcapng packet",
1899                                interfaceid);
1900                return ts;
1901        }
1902
1903        ts.tv_sec = (timestamp / interface->tsresol);
1904        ts.tv_nsec = (uint64_t)(timestamp - (ts.tv_sec * interface->tsresol))
1905                        / ((double)interface->tsresol) * 1000000000;
1906
1907        return ts;
1908
1909}
1910
1911static inline int pcapng_get_wlen_header(const libtrace_packet_t *packet) {
1912
1913        if (PACKET_IS_ENHANCED) {
1914                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1915
1916                if (DATA(packet->trace)->byteswapped) {
1917                        return byteswap32(ehdr->wlen);
1918                } else {
1919                        return ehdr->wlen;
1920                }
1921        } else if (PACKET_IS_SIMPLE) {
1922                pcapng_spkt_t *shdr = (pcapng_spkt_t *)packet->header;
1923
1924                if (DATA(packet->trace)->byteswapped) {
1925                        return byteswap32(shdr->wlen);
1926                } else {
1927                        return shdr->wlen;
1928                }
1929        } else if (PACKET_IS_OLD) {
1930                pcapng_opkt_t *ohdr = (pcapng_opkt_t *)packet->header;
1931
1932                if (DATA(packet->trace)->byteswapped) {
1933                        return byteswap32(ohdr->wlen);
1934                } else {
1935                        return ohdr->wlen;
1936                }
1937        }
1938
1939        /* If we get here, we aren't a valid pcapng packet */
1940        trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
1941                        "Invalid RT type for pcapng packet: %u",
1942                        packet->type);
1943        return -1;
1944}
1945
1946static int pcapng_get_wire_length(const libtrace_packet_t *packet) {
1947
1948        /* First, get the wire length from the packet header */
1949        int baselen = pcapng_get_wlen_header(packet);
1950
1951        if (baselen == -1)
1952                return -1;
1953
1954        /* Then, account for the vagaries of different DLTs */
1955        if (rt_to_pcap_linktype(packet->type) == TRACE_DLT_EN10MB) {
1956                /* Include the missing FCS */
1957                baselen += 4;
1958        } else if (rt_to_pcap_linktype(packet->type) ==
1959                        TRACE_DLT_IEEE802_11_RADIO) {
1960                /* If the packet is Radiotap and the flags field indicates
1961                 * that the FCS is not included in the 802.11 frame, then
1962                 * we need to add 4 to the wire-length to account for it.
1963                 */
1964                uint8_t flags;
1965                void *link;
1966                libtrace_linktype_t linktype;
1967                link = trace_get_packet_buffer(packet, &linktype, NULL);
1968                trace_get_wireless_flags(link, linktype, &flags);
1969                if ((flags & TRACE_RADIOTAP_F_FCS) == 0) {
1970                        baselen += 4;
1971                }
1972        } else if (rt_to_pcap_linktype(packet->type) == TRACE_DLT_LINUX_SLL) {
1973                libtrace_sll_header_t *sll;
1974                sll = (libtrace_sll_header_t *)packet->payload;
1975
1976                /* Account for FCS when dealing with Ethernet packets that are
1977                 * encapsulated in Linux SLL. This should fix the problem
1978                 * where the wire lengths differ if we convert the packet to
1979                 * ERF */
1980                if (ntohs(sll->protocol) == TRACE_ETHERTYPE_LOOPBACK) {
1981                        baselen += 4;
1982                }
1983        }
1984
1985        return baselen;
1986}
1987
1988static int pcapng_get_capture_length(const libtrace_packet_t *packet) {
1989
1990        if (PACKET_IS_ENHANCED) {
1991                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1992
1993                if (DATA(packet->trace)->byteswapped) {
1994                        return byteswap32(ehdr->caplen);
1995                } else {
1996                        return ehdr->caplen;
1997                }
1998        } else if (PACKET_IS_SIMPLE) {
1999                pcapng_spkt_t *shdr = (pcapng_spkt_t *)packet->header;
2000
2001                /* Have to calculate this one by removing all the headers.
2002                 * Don't forget the extra length field at the end!
2003                 */
2004                if (DATA(packet->trace)->byteswapped) {
2005                        return byteswap32(shdr->blocklen) -
2006                                        sizeof(pcapng_spkt_t) - 4;
2007                } else {
2008                        return shdr->blocklen - sizeof(pcapng_spkt_t) - 4;
2009                }
2010        } else if (PACKET_IS_OLD) {
2011                pcapng_opkt_t *ohdr = (pcapng_opkt_t *)packet->header;
2012
2013                if (DATA(packet->trace)->byteswapped) {
2014                        return byteswap32(ohdr->caplen);
2015                } else {
2016                        return ohdr->caplen;
2017                }
2018        }
2019
2020        /* If we get here, we aren't a valid pcapng packet */
2021        trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
2022                        "Invalid RT type for pcapng packet: %u",
2023                        packet->type);
2024        return -1;
2025}
2026
2027static size_t pcapng_set_capture_length(libtrace_packet_t *packet,
2028                size_t size) {
2029        uint32_t current;
2030        char *copyto, *copyfrom;
2031        uint32_t tocopy;
2032
2033        if (!(PACKET_IS_SIMPLE) && !(PACKET_IS_ENHANCED)) {
2034                return 0;
2035        }
2036
2037        current = pcapng_get_capture_length(packet);
2038
2039        if (current <= size)
2040                return current;
2041
2042        copyto = (char *)packet->payload + size;
2043        copyfrom = (char *)packet->payload + current;
2044
2045        /* Need to make sure we keep the options and trailing length... */
2046
2047        if (PACKET_IS_SIMPLE) {
2048                tocopy = 4;
2049        } else {
2050                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
2051                if (DATA(packet->trace)->byteswapped) {
2052                        tocopy =  byteswap32(ehdr->blocklen) -
2053                                        sizeof(pcapng_epkt_t) - current;
2054                } else {
2055                        tocopy = ehdr->blocklen - sizeof(pcapng_epkt_t) -
2056                                        current;
2057                }
2058        }
2059
2060        memmove(copyto, copyfrom, tocopy);
2061
2062        if (PACKET_IS_SIMPLE) {
2063                pcapng_spkt_t *shdr = (pcapng_spkt_t *)packet->header;
2064
2065                if (DATA(packet->trace)->byteswapped) {
2066                        shdr->blocklen = byteswap32(size + sizeof(pcapng_spkt_t) + tocopy);
2067                } else {
2068                        shdr->blocklen = size + sizeof(pcapng_spkt_t) + tocopy;
2069                }
2070        }
2071
2072        if (PACKET_IS_ENHANCED) {
2073                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
2074
2075                if (DATA(packet->trace)->byteswapped) {
2076                        ehdr->blocklen = byteswap32(size + sizeof(pcapng_epkt_t) + tocopy);
2077                        ehdr->caplen = byteswap32(size);
2078                } else {
2079                        ehdr->blocklen = size + sizeof(pcapng_epkt_t) + tocopy;
2080                        ehdr->caplen = size;
2081                }
2082        }
2083        packet->cached.capture_length = -1;
2084        return trace_get_capture_length(packet);
2085}
2086
2087
2088static struct libtrace_eventobj_t pcapng_event(libtrace_t *libtrace,
2089                libtrace_packet_t *packet) {
2090
2091        libtrace_eventobj_t event = {0,0,0.0,0};
2092
2093        if (DATA(libtrace)->realtime) {
2094                event.size = trace_read_packet(libtrace, packet);
2095                if (event.size < 1) {
2096                        event.type = TRACE_EVENT_TERMINATE;
2097                } else {
2098                        event.type = TRACE_EVENT_PACKET;
2099                }
2100        } else {
2101                event = trace_event_trace(libtrace, packet);
2102        }
2103
2104        return event;
2105}
2106
2107static void pcapng_get_statistics(libtrace_t *trace, libtrace_stat_t *stat) {
2108
2109        int i = 0;
2110        uint64_t drops = 0;
2111        uint64_t accepted = 0;
2112        uint64_t osdrops = 0;
2113        uint64_t received = 0;
2114
2115        if (!trace->format_data) {
2116                return;
2117        }
2118
2119        /* Add up all known interface stats */
2120        for (i = 0; i < DATA(trace)->nextintid; i++) {
2121                pcapng_interface_t *interface;
2122
2123                interface = lookup_interface(trace, i);
2124                if (interface == NULL) {
2125                        continue;
2126                }
2127
2128                received += interface->received;
2129                osdrops += interface->osdropped;
2130                accepted += interface->accepted;
2131                drops += interface->dropped;
2132
2133        }
2134
2135        stat->dropped = drops + osdrops;
2136        stat->dropped_valid = 1;
2137
2138        stat->received = received;
2139        stat->received_valid = 1;
2140
2141        stat->filtered = received - accepted;
2142        stat->filtered_valid = 1;
2143
2144        stat->captured = accepted;
2145        stat->captured_valid = 1;
2146
2147
2148}
2149
2150static void pcapng_help(void) {
2151        printf("pcapng format module: \n");
2152        printf("Supported input URIs:\n");
2153        printf("\tpcapng:/path/to/file\n");
2154        printf("\tpcapng:/path/to/file.gz\n");
2155        printf("\n");
2156        printf("\te.g.: pcapng:/tmp/trace.pcap\n");
2157        printf("\n");
2158}
2159
2160static struct libtrace_format_t pcapng = {
2161        "pcapng",
2162        "$Id$",
2163        TRACE_FORMAT_PCAPNG,
2164        NULL,                           /* probe filename */
2165        pcapng_probe_magic,             /* probe magic */
2166        pcapng_init_input,              /* init_input */
2167        pcapng_config_input,            /* config_input */
2168        pcapng_start_input,             /* start_input */
2169        NULL,                           /* pause_input */
2170        pcapng_init_output,             /* init_output */
2171        pcapng_config_output,           /* config_output */
2172        NULL,                           /* start_output */
2173        pcapng_fin_input,               /* fin_input */
2174        pcapng_fin_output,              /* fin_output */
2175        pcapng_read_packet,             /* read_packet */
2176        pcapng_prepare_packet,          /* prepare_packet */
2177        NULL,                           /* fin_packet */
2178        pcapng_write_packet,            /* write_packet */
2179        pcapng_flush_output,            /* flush_output */
2180        pcapng_get_link_type,           /* get_link_type */
2181        pcapng_get_direction,           /* get_direction */
2182        NULL,                           /* set_direction */
2183        NULL,                           /* get_erf_timestamp */
2184        NULL,                           /* get_timeval */
2185        pcapng_get_timespec,            /* get_timespec */
2186        NULL,                           /* get_seconds */
2187        NULL,                           /* seek_erf */
2188        NULL,                           /* seek_timeval */
2189        NULL,                           /* seek_seconds */
2190        pcapng_get_capture_length,      /* get_capture_length */
2191        pcapng_get_wire_length,         /* get_wire_length */
2192        pcapng_get_framing_length,      /* get_framing_length */
2193        pcapng_set_capture_length,      /* set_capture_length */
2194        NULL,                           /* get_received_packets */
2195        NULL,                           /* get_filtered_packets */
2196        NULL,                           /* get_dropped_packets */
2197        pcapng_get_statistics,          /* get_statistics */
2198        NULL,                           /* get_fd */
2199        pcapng_event,                   /* trace_event */
2200        pcapng_help,                    /* help */
2201        NULL,                           /* next pointer */
2202        NON_PARALLEL(false)
2203};
2204
2205void pcapng_constructor(void) {
2206        register_format(&pcapng);
2207}
Note: See TracBrowser for help on using the repository browser.