source: lib/format_pcapng.c @ 977e0db

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

Add meta api for erf and pcapng meta packets

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