source: lib/format_pcapng.c @ 4854e88

develop
Last change on this file since 4854e88 was 4854e88, checked in by Shane Alcock <salcock@…>, 22 months ago

Don't return uninitialised timevals / timespecs on error

Bug was introduced into both pcapfile and pcapng formats.

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