source: lib/format_pcapng.c @ e7132d6

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

improvements to meta-api

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