source: lib/format_pcapng.c @ 4e5a51f

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

Structs mapped directly to a packet/file are now packed.
Replaced hardcoded value 27 with ERF_META_TYPE.
PCAPNG meta packets are still processed when DISCARD_META config is set in order to update the trace state, however the meta callback will not be called.
Removed INET_ADDRSTRLEN definitions and used ones provided by the standard headers.
Replaced %u, %lu in libpacketdump linktypes 21 and 23 with PRIu8, PRIu32 etc.

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