source: lib/format_pcapng.c @ 0cc91ee

develop
Last change on this file since 0cc91ee was 0cc91ee, checked in by Jacob Van Walraven <jcv9@…>, 20 months ago

Meta-API - Keep ip4 address in network byte order, Cleanup bits and pieces

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