source: lib/format_pcapng.c @ ca01854

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

Make sure lastdlt is initialised

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