source: lib/format_pcapng.c @ 5cdb37d

develop
Last change on this file since 5cdb37d was 5cdb37d, checked in by GitHub <noreply@…>, 21 months ago

Merge pull request #101 from jacobvw/meta-api

Meta API

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