source: lib/format_pcapng.c @ 3dc6ed6

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

Add functions to byteswap each packet type of pcapng

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