source: lib/format_pcapng.c @ 66ffac4

develop
Last change on this file since 66ffac4 was 66ffac4, checked in by Jacob Van Walraven <jcv9@…>, 22 months ago

Add more meta functions, cleanup function names, DLLEXPORT all meta-api prototypes

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