source: lib/format_pcapng.c @ ebd6275

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

pcapng do not try to write unknown and meta packets, cleanup the code

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