source: lib/format_pcapng.c @ f47025d

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

Improve options/custom options byteswapping

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