source: lib/format_pcapng.c @ 979ab1a0

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

Remove debugging message

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