source: lib/format_pcapng.c @ 9a792a9

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

Disable unused pcapng parsing functions.

This is mainly to suppress warnings when building with clang. I
assume we may want to use these functions again at some point,
but for now we may as well disable them.

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