source: lib/format_pcapng.c @ b39eaee

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

cleanup some code and handle some cases where fields need to be byteswapped

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