source: lib/format_pcapng.c @ c171463

cachetimestampsdeveloprc-4.0.4ringdecrementfixringperformance
Last change on this file since c171463 was c171463, checked in by Richard Sanger <rsanger@…>, 2 years ago

Fixes pcapng bug where pcapng_parse_next_option would read invalid memory

pcapng_parse_next_option was being accidentally called on the trailing
block size in many parts of the code. Which caused invalid memory reads
off the end of the buffer. This commit fixes this by hardening
pcapng_parse_next_option.

pcapng_parse_next_option now checks that it has not read off the end
of a block.
pcapng_parse_next_option will now return a 'endofopt' if the end
of the option list is not found without encountering a 'endofopt'
option type.

I've also added a check to ensure the block size will not overflow the
packet buffer, which it is read into.

  • Property mode set to 100644
File size: 50.8 KB
Line 
1/*
2 *
3 * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand.
4 * All rights reserved.
5 *
6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/
10 *
11 * libtrace is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * libtrace is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 *
24 *
25 */
26#include "common.h"
27#include "config.h"
28#include "libtrace.h"
29#include "libtrace_int.h"
30#include "format_helper.h"
31
32#include <sys/stat.h>
33#include <assert.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
42#define PCAPNG_SECTION_TYPE 0x0A0D0D0A
43#define PCAPNG_INTERFACE_TYPE 0x00000001
44#define PCAPNG_OLD_PACKET_TYPE 0x00000002
45#define PCAPNG_SIMPLE_PACKET_TYPE 0x00000003
46#define PCAPNG_NAME_RESOLUTION_TYPE 0x00000004
47#define PCAPNG_INTERFACE_STATS_TYPE 0x00000005
48#define PCAPNG_ENHANCED_PACKET_TYPE 0x00000006
49#define PCAPNG_CUSTOM_TYPE 0x00000BAD
50#define PCAPNG_CUSTOM_NONCOPY_TYPE 0x40000BAD
51
52#define PACKET_IS_ENHANCED (pcapng_get_record_type(packet) == PCAPNG_ENHANCED_PACKET_TYPE)
53
54#define PACKET_IS_SIMPLE (pcapng_get_record_type(packet) == PCAPNG_SIMPLE_PACKET_TYPE)
55
56#define PACKET_IS_OLD (pcapng_get_record_type(packet) == PCAPNG_OLD_PACKET_TYPE)
57
58
59#define PCAPNG_IFOPT_TSRESOL 9
60
61#define PCAPNG_PKTOPT_DROPCOUNT 4
62
63#define PCAPNG_STATOPT_START 2
64#define PCAPNG_STATOPT_END 3
65#define PCAPNG_STATOPT_IFRECV 4
66#define PCAPNG_STATOPT_IFDROP 5
67#define PCAPNG_STATOPT_FILTERACCEPT 6
68#define PCAPNG_STATOPT_OSDROP 7
69#define PCAPNG_STATOPT_USRDELIV 8
70
71typedef struct pcagng_section_header_t {
72        uint32_t blocktype;
73        uint32_t blocklen;
74        uint32_t ordering;
75        uint16_t majorversion;
76        uint16_t minorversion;
77        uint64_t sectionlen;
78} pcapng_sec_t;
79
80typedef struct pcapng_interface_header_t {
81        uint32_t blocktype;
82        uint32_t blocklen;
83        uint16_t linktype;
84        uint16_t reserved;
85        uint32_t snaplen;
86} pcapng_int_t;
87
88typedef struct pcapng_nrb_header_t {
89        uint32_t blocktype;
90        uint32_t blocklen;
91} pcapng_nrb_t;
92
93typedef struct pcapng_enhanced_packet_t {
94        uint32_t blocktype;
95        uint32_t blocklen;
96        uint32_t interfaceid;
97        uint32_t timestamp_high;
98        uint32_t timestamp_low;
99        uint32_t caplen;
100        uint32_t wlen;
101} pcapng_epkt_t;
102
103typedef struct pcapng_simple_packet_t {
104        uint32_t blocktype;
105        uint32_t blocklen;
106        uint32_t wlen;
107} pcapng_spkt_t;
108
109typedef struct pcapng_old_packet_t {
110        uint32_t blocktype;
111        uint32_t blocklen;
112        uint16_t interfaceid;
113        uint16_t drops;
114        uint32_t timestamp_high;
115        uint32_t timestamp_low;
116        uint32_t caplen;
117        uint32_t wlen;
118} pcapng_opkt_t;
119
120typedef struct pcapng_stats_header_t {
121        uint32_t blocktype;
122        uint32_t blocklen;
123        uint32_t interfaceid;
124        uint32_t timestamp_high;
125        uint32_t timestamp_low;
126} pcapng_stats_t;
127
128typedef struct pcapng_custom_header_t {
129        uint32_t blocktype;
130        uint32_t blocklen;
131        uint32_t pen;
132} pcapng_custom_t;
133
134typedef struct pcapng_interface_t pcapng_interface_t;
135
136struct pcapng_interface_t {
137
138        uint16_t id;
139        libtrace_dlt_t linktype;
140        uint32_t snaplen;
141        uint32_t tsresol;
142
143        uint64_t received;
144        uint64_t dropped;       /* as reported by interface stats */
145        uint64_t dropcounter;   /* as reported by packet records */
146        uint64_t accepted;
147        uint64_t osdropped;
148        uint64_t laststats;
149
150};
151
152struct pcapng_format_data_t {
153        bool started;
154        bool realtime;
155
156        /* Section data */
157        bool byteswapped;
158
159        /* Interface data */
160        pcapng_interface_t **interfaces;
161        uint16_t allocatedinterfaces;
162        uint16_t nextintid;
163};
164
165struct pcapng_optheader {
166        uint16_t optcode;
167        uint16_t optlen;
168};
169
170struct pcapng_peeker {
171        uint32_t blocktype;
172        uint32_t blocklen;
173};
174
175typedef struct pcapng_peeker pcapng_hdr_t;
176
177
178#define DATA(x) ((struct pcapng_format_data_t *)((x)->format_data))
179
180static pcapng_interface_t *lookup_interface(libtrace_t *libtrace,
181                uint32_t intid) {
182
183
184        if (intid >= DATA(libtrace)->nextintid) {
185                return NULL;
186        }
187
188        return DATA(libtrace)->interfaces[intid];
189
190}
191
192static inline uint32_t pcapng_get_record_type(const libtrace_packet_t *packet) {
193
194        uint32_t *btype = (uint32_t *)packet->header;
195
196        if (DATA(packet->trace)->byteswapped)
197                return byteswap32(*btype);
198        return *btype;
199}
200
201static int pcapng_probe_magic(io_t *io) {
202
203        pcapng_sec_t sechdr;
204        int len;
205
206        len = wandio_peek(io, &sechdr, sizeof(sechdr));
207        if (len < (int)sizeof(sechdr)) {
208                return 0;
209        }
210
211        if (sechdr.blocktype == PCAPNG_SECTION_TYPE) {
212                return 1;
213        }
214        return 0;
215}
216
217
218static int pcapng_init_input(libtrace_t *libtrace) {
219        libtrace->format_data = malloc(sizeof(struct pcapng_format_data_t));
220        if (libtrace->format_data == NULL) {
221                trace_set_err(libtrace, ENOMEM, "Out of memory!");
222                return -1;
223        }
224
225        DATA(libtrace)->started = false;
226        DATA(libtrace)->realtime = false;
227        DATA(libtrace)->byteswapped = true;
228        DATA(libtrace)->interfaces = (pcapng_interface_t **)calloc(10, \
229                        sizeof(pcapng_interface_t));
230        DATA(libtrace)->allocatedinterfaces = 10;
231        DATA(libtrace)->nextintid = 0;
232
233        return 0;
234}
235
236static int pcapng_start_input(libtrace_t *libtrace) {
237
238        if (!libtrace->io) {
239                libtrace->io = trace_open_file(libtrace);
240        }
241
242        if (!libtrace->io)
243                return -1;
244
245        return 0;
246}
247
248static int pcapng_config_input(libtrace_t *libtrace, trace_option_t option,
249                void *data) {
250
251        switch(option) {
252                case TRACE_OPTION_EVENT_REALTIME:
253                        if (*(int *)data != 0) {
254                                DATA(libtrace)->realtime = true;
255                        } else {
256                                DATA(libtrace)->realtime = false;
257                        }
258                        return 0;
259                case TRACE_OPTION_META_FREQ:
260                case TRACE_OPTION_SNAPLEN:
261                case TRACE_OPTION_PROMISC:
262                case TRACE_OPTION_FILTER:
263                case TRACE_OPTION_HASHER:
264                case TRACE_OPTION_REPLAY_SPEEDUP:
265                        break;
266        }
267
268        trace_set_err(libtrace, TRACE_ERR_UNKNOWN_OPTION, "Unknown option %i",
269                        option);
270        return -1;
271}
272
273static int pcapng_fin_input(libtrace_t *libtrace) {
274
275        int i = 0;
276
277        for (i = 0; i < DATA(libtrace)->allocatedinterfaces; i++) {
278                free(DATA(libtrace)->interfaces[i]);
279        }
280
281        free(DATA(libtrace)->interfaces);
282
283        if (libtrace->io) {
284                wandio_destroy(libtrace->io);
285        }
286        free(libtrace->format_data);
287        return 0;
288}
289
290static char *pcapng_parse_next_option(libtrace_t *libtrace, char **pktbuf,
291                uint16_t *code, uint16_t *length, pcapng_hdr_t *blockhdr) {
292
293        struct pcapng_optheader *opthdr = (struct pcapng_optheader *)*pktbuf;
294        int to_skip;
295        int padding = 0;
296        char *eob; //end of block
297        char *optval;
298        if (DATA(libtrace)->byteswapped) {
299                eob = ((char *) blockhdr) + byteswap32(blockhdr->blocklen);
300        } else {
301                eob = ((char *) blockhdr) + blockhdr->blocklen;
302        }
303
304        assert((char *)blockhdr < *pktbuf);
305        // Check if we have reached the end of the block, +4 for trailing block-size
306        // We cannot assume a endofopt, so we add one
307        if (eob == (*pktbuf) + 4) {
308                *code = 0;
309                *length = 0;
310                return *pktbuf;
311        }
312        // If there is not enough space for another header we've encountered an error
313        if (eob < (*pktbuf) + 4 + sizeof(struct pcapng_optheader)) {
314                return NULL;
315        }
316
317        if (DATA(libtrace)->byteswapped) {
318                *code = byteswap16(opthdr->optcode);
319                *length = byteswap16(opthdr->optlen);
320        } else {
321                *code = opthdr->optcode;
322                *length = opthdr->optlen;
323        }
324
325        optval = *pktbuf + sizeof(struct pcapng_optheader);
326
327        if ((*length % 4) > 0) {
328                padding = (4 - (*length % 4));
329        } else {
330                padding = 0;
331        }
332
333        to_skip = (*length) + padding;
334        // Check the value we return is within the block length
335        if (eob < optval + to_skip + 4) {
336                return NULL;
337        }
338        *pktbuf = optval + to_skip;
339
340        return optval;
341}
342
343static inline int skip_block(libtrace_t *libtrace, uint32_t toread) {
344        int err;
345
346        while (toread > 0) {
347                char buf[4096];
348                int nextread;
349
350                if (toread < 4096) {
351                        nextread = toread;
352                } else {
353                        nextread = 4096;
354                }
355
356                err = wandio_read(libtrace->io, buf, nextread);
357                if (err < 0) {
358                        trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED,
359                                "Reading section header options");
360                        return -1;
361                }
362                if (err == 0) {
363                        return 0;
364                }
365                toread -= err;
366        }
367
368        return 1;
369
370}
371
372static inline int pcapng_read_body(libtrace_t *libtrace, char *body,
373                uint32_t to_read) {
374
375        int err;
376
377        err = wandio_read(libtrace->io, body, to_read);
378        if (err < 0) {
379                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED,
380                        "Failed to read pcapng interface options");
381                return err;
382        }
383
384        if (err == 0) {
385                return err;
386        }
387
388        if (err < (int)to_read) {
389                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
390                        "Incomplete pcapng interface header block");
391                return -1;
392        }
393
394        return to_read;
395}
396
397static int pcapng_get_framing_length(const libtrace_packet_t *packet) {
398
399        switch(pcapng_get_record_type(packet)) {
400                case PCAPNG_SECTION_TYPE:
401                        return sizeof(pcapng_sec_t);
402                case PCAPNG_INTERFACE_TYPE:
403                        return sizeof(pcapng_int_t);
404                case PCAPNG_ENHANCED_PACKET_TYPE:
405                        return sizeof(pcapng_epkt_t);
406                case PCAPNG_SIMPLE_PACKET_TYPE:
407                        return sizeof(pcapng_spkt_t);
408                case PCAPNG_OLD_PACKET_TYPE:
409                        return sizeof(pcapng_opkt_t);
410                case PCAPNG_INTERFACE_STATS_TYPE:
411                        return sizeof(pcapng_stats_t);
412                case PCAPNG_NAME_RESOLUTION_TYPE:
413                        return sizeof(pcapng_nrb_t);
414                case PCAPNG_CUSTOM_TYPE:
415                case PCAPNG_CUSTOM_NONCOPY_TYPE:
416                        return sizeof(pcapng_custom_t);
417        }
418
419        /* If we get here, we aren't a valid pcapng packet */
420        trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
421                        "Invalid RT type for pcapng packet: %u",
422                        packet->type);
423        return -1;
424
425}
426
427static int pcapng_prepare_packet(libtrace_t *libtrace,
428                libtrace_packet_t *packet, void *buffer,
429                libtrace_rt_types_t rt_type, uint32_t flags) {
430
431        int hdrlen;
432
433        if (packet->buffer != buffer &&
434                        packet->buf_control == TRACE_CTRL_PACKET) {
435                free(packet->buffer);
436        }
437
438        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
439                packet->buf_control = TRACE_CTRL_PACKET;
440        } else {
441                packet->buf_control = TRACE_CTRL_EXTERNAL;
442        }
443
444        packet->type = rt_type;
445        packet->buffer = buffer;
446        packet->header = buffer;
447
448        hdrlen = pcapng_get_framing_length(packet);
449        if (hdrlen < 0) {
450                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
451                                "X Invalid RT type for pcapng packet: %u",
452                                packet->type);
453                return -1;
454        }
455        packet->payload = ((char *)packet->buffer) + hdrlen;
456
457        return 0;
458}
459
460static int pcapng_read_section(libtrace_t *libtrace,
461                libtrace_packet_t *packet, uint32_t flags) {
462
463        pcapng_sec_t *sechdr;
464        int err;
465        uint32_t to_read;
466        char *bodyptr = NULL;
467
468        err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_sec_t));
469        sechdr = (pcapng_sec_t *)packet->buffer;
470
471        if (err < 0) {
472                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED,
473                        "Reading pcapng section header block");
474                return -1;
475        }
476
477        if (err == 0) {
478                return 0;
479        }
480
481        if (err < (int)(sizeof(pcapng_sec_t))) {
482                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
483                        "Incomplete pcapng section header block");
484                return -1;
485        }
486
487        assert(sechdr->blocktype == PCAPNG_SECTION_TYPE);
488
489        if (sechdr->ordering == 0x1A2B3C4D) {
490                DATA(libtrace)->byteswapped = false;
491        } else if (sechdr->ordering == 0x4D3C2B1A) {
492                DATA(libtrace)->byteswapped = true;
493        } else {
494                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
495                                "Parsing pcapng section header block");
496                return -1;
497        }
498
499
500        if (DATA(libtrace)->byteswapped) {
501                if (byteswap16(sechdr->majorversion) != 1 && byteswap16(sechdr->minorversion) != 0) {
502                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
503                                "Parsing pcapng version numbers");
504                        return -1;
505                }
506                to_read = byteswap32(sechdr->blocklen) - sizeof(pcapng_sec_t);
507        } else {
508                if (sechdr->majorversion != 1 && sechdr->minorversion != 0) {
509                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
510                                "Parsing pcapng version numbers");
511                        return -1;
512                }
513                to_read = sechdr->blocklen - sizeof(pcapng_sec_t);
514        }
515
516        /* Read all of the options etc. -- we don't need them for now, but
517         * we have to skip forward to the next useful header. */
518        bodyptr = packet->buffer + sizeof(pcapng_sec_t);
519        err = pcapng_read_body(libtrace, bodyptr, to_read);
520        if (err <= 0) {
521                return err;
522        }
523
524        packet->type = TRACE_RT_PCAPNG_META;
525        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
526                        packet->type, flags)) {
527                return -1;
528        }
529
530        return 1;
531}
532
533static int pcapng_read_interface(libtrace_t *libtrace,
534                libtrace_packet_t *packet, uint32_t flags) {
535
536        pcapng_int_t *inthdr;
537        int err;
538        uint32_t to_read;
539        pcapng_interface_t *newint;
540        uint16_t optcode, optlen;
541        char *optval = NULL;
542        char *bodyptr = NULL;
543
544        err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_int_t));
545
546        if (err < 0) {
547                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED,
548                        "Reading pcapng interface header block");
549                return -1;
550        }
551
552        if (err == 0) {
553                return 0;
554        }
555
556        if (err < (int)sizeof(pcapng_int_t)) {
557                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
558                        "Incomplete pcapng interface header block");
559                return -1;
560        }
561        inthdr = (pcapng_int_t *)packet->buffer;
562
563        newint = (pcapng_interface_t *)malloc(sizeof(pcapng_interface_t));
564
565        newint->id = DATA(libtrace)->nextintid;
566
567        newint->received = 0;
568        newint->dropped = 0;
569        newint->dropcounter = 0;
570        newint->accepted = 0;
571        newint->osdropped = 0;
572        newint->laststats = 0;
573        newint->tsresol = 1000000;
574
575        if (DATA(libtrace)->byteswapped) {
576                assert(byteswap32(inthdr->blocktype) == PCAPNG_INTERFACE_TYPE);
577                newint->snaplen = byteswap32(inthdr->snaplen);
578                newint->linktype = byteswap16(inthdr->linktype);
579                to_read = byteswap32(inthdr->blocklen) - sizeof(pcapng_int_t);
580        } else {
581                assert(inthdr->blocktype == PCAPNG_INTERFACE_TYPE);
582                newint->snaplen = inthdr->snaplen;
583                newint->linktype = inthdr->linktype;
584                to_read = inthdr->blocklen - sizeof(pcapng_int_t);
585        }
586
587        if (DATA(libtrace)->nextintid == DATA(libtrace)->allocatedinterfaces) {
588                DATA(libtrace)->allocatedinterfaces += 10;
589                DATA(libtrace)->interfaces = (pcapng_interface_t **)realloc(
590                        DATA(libtrace)->interfaces,
591                        DATA(libtrace)->allocatedinterfaces * sizeof(
592                                pcapng_interface_t *));
593
594                /* Could memset the new memory to zero, if required */
595        }
596
597        DATA(libtrace)->interfaces[newint->id] = newint;
598        DATA(libtrace)->nextintid += 1;
599
600        bodyptr = packet->buffer + sizeof(pcapng_int_t);
601        err = pcapng_read_body(libtrace, bodyptr, to_read);
602        if (err <= 0) {
603                return err;
604        }
605
606        packet->type = TRACE_RT_PCAPNG_META;
607
608        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
609                        packet->type, flags)) {
610                return -1;
611        }
612
613        do {
614                optval = pcapng_parse_next_option(libtrace, &bodyptr,
615                                &optcode, &optlen, (pcapng_hdr_t *) packet->buffer);
616                if (optval == NULL) {
617                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
618                                "Failed to read options for pcapng interface");
619                        return -1;
620                }
621
622                if (optcode == PCAPNG_IFOPT_TSRESOL) {
623                        uint8_t *resol = (uint8_t *)optval;
624
625                        if ((*resol & 0x80) != 0) {
626                                newint->tsresol = pow(2, *resol & 0x7f);
627
628                        } else {
629                                newint->tsresol = pow(10, *resol & 0x7f);
630                        }
631                }
632
633        } while (optcode != 0);
634
635        return 1;
636
637}
638
639static int pcapng_read_nrb(libtrace_t *libtrace, libtrace_packet_t *packet,
640                uint32_t flags) {
641
642        /* Just read the NR records and pass them off to the caller. If
643         * they want to do anything with them, they can parse the records
644         * themselves.
645         */
646        pcapng_nrb_t *hdr = NULL;
647        int err;
648        uint32_t to_read;
649        char *bodyptr;
650
651        err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_nrb_t));
652
653        if (err < 0) {
654                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng name resolution block");
655                return -1;
656        }
657
658        if (err == 0) {
659                return 0;
660        }
661
662        if (err < (int)sizeof(pcapng_nrb_t)) {
663                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
664                                "Incomplete pcapng name resolution block");
665                return -1;
666        }
667
668        hdr = (pcapng_nrb_t *)packet->buffer;
669
670        /* Read the rest of the packet into the buffer */
671        if (DATA(libtrace)->byteswapped) {
672                assert(byteswap32(hdr->blocktype) == PCAPNG_NAME_RESOLUTION_TYPE);
673                to_read = byteswap32(hdr->blocklen) - sizeof(pcapng_nrb_t);
674        } else {
675                assert(hdr->blocktype == PCAPNG_NAME_RESOLUTION_TYPE);
676                to_read = hdr->blocklen - sizeof(pcapng_nrb_t);
677        }
678
679        bodyptr = packet->buffer + sizeof(pcapng_nrb_t);
680        err = pcapng_read_body(libtrace, bodyptr, to_read);
681        if (err <= 0) {
682                return err;
683        }
684
685        packet->type = TRACE_RT_PCAPNG_META;
686        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
687                        packet->type, flags)) {
688                return -1;
689        }
690
691        return sizeof(pcapng_nrb_t) + to_read;
692
693}
694
695static int pcapng_read_custom(libtrace_t *libtrace, libtrace_packet_t *packet,
696                uint32_t flags) {
697
698        /* Just read the custom records and pass them off to the caller. If
699         * they want to do anything with them, they can parse the records
700         * themselves.
701         */
702        pcapng_custom_t *hdr = NULL;
703        int err;
704        uint32_t to_read;
705        char *bodyptr;
706
707        err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_custom_t));
708
709        if (err < 0) {
710                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng custom block");
711                return -1;
712        }
713
714        if (err == 0) {
715                return 0;
716        }
717
718        if (err < (int)sizeof(pcapng_custom_t)) {
719                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
720                                "Incomplete pcapng custom block");
721                return -1;
722        }
723
724        hdr = (pcapng_custom_t *)packet->buffer;
725
726        /* Read the rest of the packet into the buffer */
727        if (DATA(libtrace)->byteswapped) {
728                assert(byteswap32(hdr->blocktype) == PCAPNG_CUSTOM_TYPE ||
729                        byteswap32(hdr->blocktype) == PCAPNG_CUSTOM_NONCOPY_TYPE);
730                to_read = byteswap32(hdr->blocklen) - sizeof(pcapng_custom_t);
731        } else {
732                assert(hdr->blocktype == PCAPNG_NAME_RESOLUTION_TYPE ||
733                        hdr->blocktype == PCAPNG_CUSTOM_NONCOPY_TYPE);
734                to_read = hdr->blocklen - sizeof(pcapng_custom_t);
735        }
736
737        bodyptr = packet->buffer + sizeof(pcapng_custom_t);
738        err = pcapng_read_body(libtrace, bodyptr, to_read);
739        if (err <= 0) {
740                return err;
741        }
742
743        packet->type = TRACE_RT_PCAPNG_META;
744        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
745                        packet->type, flags)) {
746                return -1;
747        }
748
749        return sizeof(pcapng_custom_t) + to_read;
750
751}
752
753static int pcapng_read_stats(libtrace_t *libtrace, libtrace_packet_t *packet,
754                uint32_t flags) {
755        pcapng_stats_t *hdr = NULL;
756        int err;
757        uint32_t to_read;
758        uint32_t ifaceid;
759        uint64_t timestamp;
760        pcapng_interface_t *interface;
761        uint16_t optcode, optlen;
762        char *optval;
763        char *bodyptr;
764
765        err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_stats_t));
766
767        if (err < 0) {
768                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng interface stats");
769                return -1;
770        }
771
772        if (err == 0) {
773                return 0;
774        }
775
776        if (err < (int)sizeof(pcapng_stats_t)) {
777                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
778                                "Incomplete pcapng interface stats header");
779                return -1;
780        }
781
782        hdr = (pcapng_stats_t *)packet->buffer;
783
784        /* Read the rest of the packet into the buffer */
785        if (DATA(libtrace)->byteswapped) {
786                assert(byteswap32(hdr->blocktype) == PCAPNG_INTERFACE_STATS_TYPE);
787                to_read = byteswap32(hdr->blocklen) - sizeof(pcapng_stats_t);
788                ifaceid = byteswap32(hdr->interfaceid);
789                timestamp = ((uint64_t)(byteswap32(hdr->timestamp_high)) << 32) + byteswap32(hdr->timestamp_low);
790        } else {
791                assert(hdr->blocktype == PCAPNG_INTERFACE_STATS_TYPE);
792                to_read = hdr->blocklen - sizeof(pcapng_stats_t);
793                ifaceid = hdr->interfaceid;
794                timestamp = ((uint64_t)(hdr->timestamp_high) << 32) +
795                                hdr->timestamp_low;
796        }
797
798        bodyptr = packet->buffer + sizeof(pcapng_stats_t);
799        err = pcapng_read_body(libtrace, bodyptr, to_read);
800        if (err <= 0) {
801                return err;
802        }
803
804        /* Set packet type based on interface linktype */
805        interface = lookup_interface(libtrace, ifaceid);
806        if (interface == NULL) {
807                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Unknown pcapng interface id: %u", ifaceid);
808                return -1;
809        }
810        packet->type = TRACE_RT_PCAPNG_META;
811
812        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
813                        packet->type, flags)) {
814                return -1;
815        }
816
817        if (timestamp < interface->laststats) {
818                return sizeof(pcapng_stats_t) + to_read;
819        }
820
821        /* All of the stats are stored as options */
822        bodyptr = packet->payload;
823
824        do {
825                optval = pcapng_parse_next_option(packet->trace, &bodyptr,
826                                &optcode, &optlen, (pcapng_hdr_t *) packet->buffer);
827                if (optval == NULL) {
828                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
829                                "Failed to read options for pcapng enhanced packet");
830                        return -1;
831                }
832
833                if (optcode == PCAPNG_STATOPT_IFRECV) {
834                        uint64_t *recvd = (uint64_t *)optval;
835                        if (DATA(packet->trace)->byteswapped) {
836                                interface->received = byteswap64(*recvd);
837                        } else {
838                                interface->received = *recvd;
839                        }
840                }
841
842                if (optcode == PCAPNG_STATOPT_IFDROP) {
843                        uint64_t *drops = (uint64_t *)optval;
844                        if (DATA(packet->trace)->byteswapped) {
845                                interface->dropped = byteswap64(*drops);
846                        } else {
847                                interface->dropped = *drops;
848                        }
849                }
850
851                if (optcode == PCAPNG_STATOPT_OSDROP) {
852                        uint64_t *drops = (uint64_t *)optval;
853                        if (DATA(packet->trace)->byteswapped) {
854                                interface->osdropped = byteswap64(*drops);
855                        } else {
856                                interface->osdropped = *drops;
857                        }
858                }
859
860                if (optcode == PCAPNG_STATOPT_FILTERACCEPT) {
861                        uint64_t *accepts = (uint64_t *)optval;
862                        if (DATA(packet->trace)->byteswapped) {
863                                interface->accepted = byteswap64(*accepts);
864                        } else {
865                                interface->accepted = *accepts;
866                        }
867                }
868
869        } while (optcode != 0);
870        interface->laststats = timestamp;
871
872        return sizeof(pcapng_stats_t) + to_read;
873
874}
875
876static int pcapng_read_simple(libtrace_t *libtrace, libtrace_packet_t *packet,
877                uint32_t flags) {
878
879        int err;
880        uint32_t to_read;
881        uint32_t caplen;
882        pcapng_spkt_t *hdr = NULL;
883        pcapng_interface_t *interface;
884        char *bodyptr;
885
886        err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_spkt_t));
887
888        if (err < 0) {
889                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng simple packet");
890                return -1;
891        }
892
893        if (err == 0) {
894                return 0;
895        }
896
897        if (err < (int)sizeof(pcapng_spkt_t)) {
898                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
899                                "Incomplete pcapng simple packet header");
900                return -1;
901        }
902
903        hdr = (pcapng_spkt_t *)packet->buffer;
904
905        /* Read the rest of the packet into the buffer */
906        if (DATA(libtrace)->byteswapped) {
907                assert(byteswap32(hdr->blocktype) == PCAPNG_SIMPLE_PACKET_TYPE);
908                to_read = byteswap32(hdr->blocklen) - sizeof(pcapng_spkt_t);
909                caplen = to_read - 4;   /* account for trailing length field */
910        } else {
911                assert(hdr->blocktype == PCAPNG_SIMPLE_PACKET_TYPE);
912                to_read = hdr->blocklen - sizeof(pcapng_spkt_t);
913                caplen = to_read - 4; /* account for trailing length field */
914        }
915
916        bodyptr = packet->buffer + sizeof(pcapng_spkt_t);
917        err = pcapng_read_body(libtrace, bodyptr, to_read);
918        if (err <= 0) {
919                return err;
920        }
921
922        /* Set packet type based on interface linktype.
923         * Assume interface 0, since we have no interface field */
924        interface = lookup_interface(libtrace, 0);
925        if (interface == NULL) {
926                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Unknown pcapng interface id: %u", 0);
927                return -1;
928        }
929        packet->type = pcapng_linktype_to_rt(interface->linktype);
930
931        /* May as well cache the capture length now, since we've
932         * already got it in the right byte order */
933        packet->capture_length = caplen;
934
935        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
936                        packet->type, flags)) {
937                return -1;
938        }
939        return sizeof(pcapng_spkt_t) + to_read;
940
941}
942
943static int pcapng_read_enhanced(libtrace_t *libtrace, libtrace_packet_t *packet,
944                uint32_t flags) {
945        pcapng_epkt_t *hdr = NULL;
946        int err;
947        uint32_t to_read;
948        uint32_t caplen;
949        uint32_t ifaceid;
950        pcapng_interface_t *interface;
951        uint16_t optcode, optlen;
952        char *optval;
953        char *bodyptr;
954
955        err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_epkt_t));
956
957        if (err < 0) {
958                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng enhanced packet");
959                return -1;
960        }
961
962        if (err == 0) {
963                return 0;
964        }
965
966        if (err < (int)sizeof(pcapng_epkt_t)) {
967                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
968                                "Incomplete pcapng enhanced packet header");
969                return -1;
970        }
971
972        hdr = (pcapng_epkt_t *)packet->buffer;
973
974        /* Read the rest of the packet into the buffer */
975        if (DATA(libtrace)->byteswapped) {
976                assert(byteswap32(hdr->blocktype) == PCAPNG_ENHANCED_PACKET_TYPE);
977                caplen = byteswap32(hdr->caplen);
978                to_read = byteswap32(hdr->blocklen) - sizeof(pcapng_epkt_t);
979                ifaceid = byteswap32(hdr->interfaceid);
980        } else {
981                assert(hdr->blocktype == PCAPNG_ENHANCED_PACKET_TYPE);
982                caplen = hdr->caplen;
983                to_read = hdr->blocklen - sizeof(pcapng_epkt_t);
984                ifaceid = hdr->interfaceid;
985        }
986
987        bodyptr = packet->buffer + sizeof(pcapng_epkt_t);
988        err = pcapng_read_body(libtrace, bodyptr, to_read);
989        if (err <= 0) {
990                return err;
991        }
992
993        /* Set packet type based on interface linktype */
994        interface = lookup_interface(libtrace, ifaceid);
995        if (interface == NULL) {
996                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Unknown pcapng interface id: %u", ifaceid);
997                return -1;
998        }
999        packet->type = pcapng_linktype_to_rt(interface->linktype);
1000
1001        /* May as well cache the capture length now, since we've
1002         * already got it in the right byte order */
1003        packet->capture_length = caplen;
1004
1005        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
1006                        packet->type, flags)) {
1007                return -1;
1008        }
1009
1010        /* Make sure to parse any useful options */
1011        if ((caplen % 4) == 0) {
1012                bodyptr = packet->payload + caplen;
1013        } else {
1014                bodyptr = packet->payload + caplen + (4 - (caplen % 4));
1015        }
1016
1017        do {
1018                optval = pcapng_parse_next_option(packet->trace, &bodyptr,
1019                                &optcode, &optlen, (pcapng_hdr_t *) packet->buffer);
1020                if (optval == NULL) {
1021                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1022                                "Failed to read options for pcapng enhanced packet");
1023                        return -1;
1024                }
1025
1026                if (optcode == PCAPNG_PKTOPT_DROPCOUNT) {
1027                        uint64_t *drops = (uint64_t *)optval;
1028                        if (DATA(packet->trace)->byteswapped) {
1029                                interface->dropcounter += byteswap64(*drops);
1030                        } else {
1031                                interface->dropcounter += *drops;
1032                        }
1033                }
1034
1035        } while (optcode != 0);
1036        return sizeof(pcapng_epkt_t) + to_read;
1037
1038}
1039
1040static int pcapng_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet)
1041{
1042        struct pcapng_peeker peeker;
1043        int err = 0;
1044        uint32_t flags = 0;
1045        uint32_t to_read;
1046        uint32_t btype = 0;
1047        int gotpacket = 0;
1048
1049        /* Peek to get next block type */
1050        assert(libtrace->format_data);
1051        assert(libtrace->io);
1052
1053        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
1054                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
1055        }
1056
1057        flags |= TRACE_PREP_OWN_BUFFER;
1058
1059        while (!gotpacket) {
1060
1061                if ((err=is_halted(libtrace)) != -1) {
1062                        return err;
1063                }
1064
1065                err = wandio_peek(libtrace->io, &peeker, sizeof(peeker));
1066                if (err < 0) {
1067                        trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng packet");
1068                        return -1;
1069                }
1070
1071                if (err == 0) {
1072                        return 0;
1073                }
1074
1075                if (err < (int)sizeof(struct pcapng_peeker)) {
1076                        trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "Incomplete pcapng block");
1077                        return -1;
1078                }
1079
1080                if (DATA(libtrace)->byteswapped) {
1081                        btype = byteswap32(peeker.blocktype);
1082                        to_read = byteswap32(peeker.blocklen);
1083                } else {
1084                        btype = peeker.blocktype;
1085                        to_read = peeker.blocklen;
1086                }
1087
1088                // Check we won't read off the end of the packet buffer. Assuming corruption.
1089                // Exclude the SECTION header, as this is used to identify the byteorder
1090                if (to_read > LIBTRACE_PACKET_BUFSIZE && btype != PCAPNG_SECTION_TYPE) {
1091                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
1092                                      "Oversized pcapng block found, is the trace corrupted?");
1093                        return -1;
1094                }
1095
1096                switch (btype) {
1097                        /* Section Header */
1098                        case PCAPNG_SECTION_TYPE:
1099                                err = pcapng_read_section(libtrace, packet, flags);
1100                                gotpacket = 1;
1101                                break;
1102
1103                        /* Interface Header */
1104                        case PCAPNG_INTERFACE_TYPE:
1105                                err = pcapng_read_interface(libtrace, packet, flags);
1106                                gotpacket = 1;
1107                                break;
1108
1109
1110                        case PCAPNG_ENHANCED_PACKET_TYPE:
1111                                err = pcapng_read_enhanced(libtrace, packet,
1112                                                flags);
1113                                gotpacket = 1;
1114                                break;
1115
1116                        case PCAPNG_SIMPLE_PACKET_TYPE:
1117                                err = pcapng_read_simple(libtrace, packet, flags);
1118                                gotpacket = 1;
1119                                break;
1120
1121                        case PCAPNG_INTERFACE_STATS_TYPE:
1122                                err = pcapng_read_stats(libtrace, packet, flags);
1123                                gotpacket = 1;
1124                                break;
1125
1126                        case PCAPNG_NAME_RESOLUTION_TYPE:
1127                                err = pcapng_read_nrb(libtrace, packet, flags);
1128                                gotpacket = 1;
1129                                break;
1130
1131                        case PCAPNG_CUSTOM_TYPE:
1132                        case PCAPNG_CUSTOM_NONCOPY_TYPE:
1133                                err = pcapng_read_custom(libtrace, packet, flags);
1134                                gotpacket = 1;
1135                                break;
1136
1137
1138                        case PCAPNG_OLD_PACKET_TYPE:
1139                                /* TODO */
1140
1141                        /* Everything else -- don't care, skip it */
1142                        default:
1143                                err = skip_block(libtrace, to_read);
1144                                break;
1145                }
1146        }
1147
1148        if (err <= 0) {
1149                return err;
1150        }
1151
1152        if (DATA(libtrace)->byteswapped)
1153                return byteswap32(peeker.blocklen);
1154        return peeker.blocklen;
1155
1156}
1157
1158static libtrace_linktype_t pcapng_get_link_type(const libtrace_packet_t *packet)
1159{
1160
1161        return pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type));
1162
1163}
1164
1165static libtrace_direction_t pcapng_get_direction(const libtrace_packet_t
1166                *packet) {
1167
1168        /* Defined in format_helper.c */
1169        return pcap_get_direction(packet);
1170}
1171
1172static struct timespec pcapng_get_timespec(const libtrace_packet_t *packet) {
1173
1174        struct timespec ts;
1175        uint64_t timestamp = 0;
1176        uint32_t interfaceid = 0;
1177        pcapng_interface_t *interface;
1178
1179        assert(packet->header);
1180
1181        ts.tv_sec = 0;
1182        ts.tv_nsec = 0;
1183
1184        /* No timestamps in simple packets :( */
1185        if (PACKET_IS_SIMPLE) {
1186                return ts;
1187        }
1188
1189        if (PACKET_IS_ENHANCED) {
1190                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1191
1192                if (DATA(packet->trace)->byteswapped) {
1193                        timestamp = ((uint64_t)(byteswap32(ehdr->timestamp_high)) << 32) + byteswap32(ehdr->timestamp_low);
1194                        interfaceid = byteswap32(ehdr->interfaceid);
1195                } else {
1196                        timestamp = ((uint64_t)(ehdr->timestamp_high) << 32) +
1197                                        ehdr->timestamp_low;
1198                        interfaceid = ehdr->interfaceid;
1199                }
1200        } else if (PACKET_IS_OLD) {
1201                pcapng_opkt_t *ohdr = (pcapng_opkt_t *)packet->header;
1202
1203                if (DATA(packet->trace)->byteswapped) {
1204                        timestamp = ((uint64_t)(byteswap32(ohdr->timestamp_high)) << 32) + byteswap32(ohdr->timestamp_low);
1205                        interfaceid = byteswap16(ohdr->interfaceid);
1206                } else {
1207                        timestamp = ((uint64_t)(ohdr->timestamp_high) << 32) +
1208                                        ohdr->timestamp_low;
1209                        interfaceid = ohdr->interfaceid;
1210                }
1211
1212        }
1213
1214        if (timestamp == 0)
1215                return ts;
1216
1217
1218        interface = lookup_interface(packet->trace, interfaceid);
1219        if (interface == NULL) {
1220                trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
1221                                "Bad interface %u on pcapng packet",
1222                                interfaceid);
1223                return ts;
1224        }
1225
1226        ts.tv_sec = (timestamp / interface->tsresol);
1227        ts.tv_nsec = (uint64_t)(timestamp - (ts.tv_sec * interface->tsresol))
1228                        / ((double)interface->tsresol) * 1000000000;
1229
1230        return ts;
1231
1232}
1233
1234static inline int pcapng_get_wlen_header(const libtrace_packet_t *packet) {
1235
1236        if (PACKET_IS_ENHANCED) {
1237                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1238
1239                if (DATA(packet->trace)->byteswapped) {
1240                        return byteswap32(ehdr->wlen);
1241                } else {
1242                        return ehdr->wlen;
1243                }
1244        } else if (PACKET_IS_SIMPLE) {
1245                pcapng_spkt_t *shdr = (pcapng_spkt_t *)packet->header;
1246
1247                if (DATA(packet->trace)->byteswapped) {
1248                        return byteswap32(shdr->wlen);
1249                } else {
1250                        return shdr->wlen;
1251                }
1252        } else if (PACKET_IS_OLD) {
1253                pcapng_opkt_t *ohdr = (pcapng_opkt_t *)packet->header;
1254
1255                if (DATA(packet->trace)->byteswapped) {
1256                        return byteswap32(ohdr->wlen);
1257                } else {
1258                        return ohdr->wlen;
1259                }
1260        }
1261
1262        /* If we get here, we aren't a valid pcapng packet */
1263        trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
1264                        "Invalid RT type for pcapng packet: %u",
1265                        packet->type);
1266        return -1;
1267}
1268
1269static int pcapng_get_wire_length(const libtrace_packet_t *packet) {
1270
1271        /* First, get the wire length from the packet header */
1272        int baselen = pcapng_get_wlen_header(packet);
1273
1274        if (baselen == -1)
1275                return -1;
1276
1277        /* Then, account for the vagaries of different DLTs */
1278        if (rt_to_pcap_linktype(packet->type) == TRACE_DLT_EN10MB) {
1279                /* Include the missing FCS */
1280                baselen += 4;
1281        } else if (rt_to_pcap_linktype(packet->type) ==
1282                        TRACE_DLT_IEEE802_11_RADIO) {
1283                /* If the packet is Radiotap and the flags field indicates
1284                 * that the FCS is not included in the 802.11 frame, then
1285                 * we need to add 4 to the wire-length to account for it.
1286                 */
1287                uint8_t flags;
1288                void *link;
1289                libtrace_linktype_t linktype;
1290                link = trace_get_packet_buffer(packet, &linktype, NULL);
1291                trace_get_wireless_flags(link, linktype, &flags);
1292                if ((flags & TRACE_RADIOTAP_F_FCS) == 0) {
1293                        baselen += 4;
1294                }
1295        } else if (rt_to_pcap_linktype(packet->type) == TRACE_DLT_LINUX_SLL) {
1296                libtrace_sll_header_t *sll;
1297                sll = (libtrace_sll_header_t *)packet->payload;
1298
1299                /* Account for FCS when dealing with Ethernet packets that are
1300                 * encapsulated in Linux SLL. This should fix the problem
1301                 * where the wire lengths differ if we convert the packet to
1302                 * ERF */
1303                if (ntohs(sll->protocol) == TRACE_ETHERTYPE_LOOPBACK) {
1304                        baselen += 4;
1305                }
1306        }
1307
1308        return baselen;
1309}
1310
1311static int pcapng_get_capture_length(const libtrace_packet_t *packet) {
1312
1313        if (PACKET_IS_ENHANCED) {
1314                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1315
1316                if (DATA(packet->trace)->byteswapped) {
1317                        return byteswap32(ehdr->caplen);
1318                } else {
1319                        return ehdr->caplen;
1320                }
1321        } else if (PACKET_IS_SIMPLE) {
1322                pcapng_spkt_t *shdr = (pcapng_spkt_t *)packet->header;
1323
1324                /* Have to calculate this one by removing all the headers.
1325                 * Don't forget the extra length field at the end!
1326                 */
1327                if (DATA(packet->trace)->byteswapped) {
1328                        return byteswap32(shdr->blocklen) -
1329                                        sizeof(pcapng_spkt_t) - 4;
1330                } else {
1331                        return shdr->blocklen - sizeof(pcapng_spkt_t) - 4;
1332                }
1333        } else if (PACKET_IS_OLD) {
1334                pcapng_opkt_t *ohdr = (pcapng_opkt_t *)packet->header;
1335
1336                if (DATA(packet->trace)->byteswapped) {
1337                        return byteswap32(ohdr->caplen);
1338                } else {
1339                        return ohdr->caplen;
1340                }
1341        }
1342
1343        /* If we get here, we aren't a valid pcapng packet */
1344        trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
1345                        "Invalid RT type for pcapng packet: %u",
1346                        packet->type);
1347        return -1;
1348}
1349
1350static size_t pcapng_set_capture_length(libtrace_packet_t *packet,
1351                size_t size) {
1352        uint32_t current;
1353        char *copyto, *copyfrom;
1354        uint32_t tocopy;
1355
1356        if (!(PACKET_IS_SIMPLE) && !(PACKET_IS_ENHANCED)) {
1357                return 0;
1358        }
1359
1360        current = pcapng_get_capture_length(packet);
1361
1362        if (current <= size)
1363                return current;
1364
1365        copyto = (char *)packet->payload + size;
1366        copyfrom = (char *)packet->payload + current;
1367
1368        /* Need to make sure we keep the options and trailing length... */
1369
1370        if (PACKET_IS_SIMPLE) {
1371                tocopy = 4;
1372        } else {
1373                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1374                if (DATA(packet->trace)->byteswapped) {
1375                        tocopy =  byteswap32(ehdr->blocklen) -
1376                                        sizeof(pcapng_epkt_t) - current;
1377                } else {
1378                        tocopy = ehdr->blocklen - sizeof(pcapng_epkt_t) -
1379                                        current;
1380                }
1381        }
1382
1383        memmove(copyto, copyfrom, tocopy);
1384
1385        if (PACKET_IS_SIMPLE) {
1386                pcapng_spkt_t *shdr = (pcapng_spkt_t *)packet->header;
1387
1388                if (DATA(packet->trace)->byteswapped) {
1389                        shdr->blocklen = byteswap32(size + sizeof(pcapng_spkt_t) + tocopy);
1390                } else {
1391                        shdr->blocklen = size + sizeof(pcapng_spkt_t) + tocopy;
1392                }
1393        }
1394
1395        if (PACKET_IS_ENHANCED) {
1396                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1397
1398                if (DATA(packet->trace)->byteswapped) {
1399                        ehdr->blocklen = byteswap32(size + sizeof(pcapng_epkt_t) + tocopy);
1400                        ehdr->caplen = byteswap32(size);
1401                } else {
1402                        ehdr->blocklen = size + sizeof(pcapng_epkt_t) + tocopy;
1403                        ehdr->caplen = size;
1404                }
1405        }
1406        packet->capture_length = -1;
1407        return trace_get_capture_length(packet);
1408}
1409
1410
1411static struct libtrace_eventobj_t pcapng_event(libtrace_t *libtrace,
1412                libtrace_packet_t *packet) {
1413
1414        libtrace_eventobj_t event = {0,0,0.0,0};
1415
1416        if (DATA(libtrace)->realtime) {
1417                event.size = trace_read_packet(libtrace, packet);
1418                if (event.size < 1) {
1419                        event.type = TRACE_EVENT_TERMINATE;
1420                } else {
1421                        event.type = TRACE_EVENT_PACKET;
1422                }
1423        } else {
1424                event = trace_event_trace(libtrace, packet);
1425        }
1426
1427        return event;
1428}
1429
1430static void pcapng_get_statistics(libtrace_t *trace, libtrace_stat_t *stat) {
1431
1432        int i = 0;
1433        uint64_t drops = 0;
1434        uint64_t accepted = 0;
1435        uint64_t osdrops = 0;
1436        uint64_t received = 0;
1437
1438        if (!trace->format_data) {
1439                return;
1440        }
1441
1442        /* Add up all known interface stats */
1443        for (i = 0; i < DATA(trace)->nextintid; i++) {
1444                pcapng_interface_t *interface;
1445
1446                interface = lookup_interface(trace, i);
1447                if (interface == NULL) {
1448                        continue;
1449                }
1450
1451                received += interface->received;
1452                osdrops += interface->osdropped;
1453                accepted += interface->accepted;
1454                drops += interface->dropped;
1455
1456        }
1457
1458        stat->dropped = drops + osdrops;
1459        stat->dropped_valid = 1;
1460
1461        stat->received = received;
1462        stat->received_valid = 1;
1463
1464        stat->filtered = received - accepted;
1465        stat->filtered_valid = 1;
1466
1467        stat->captured = accepted;
1468        stat->captured_valid = 1;
1469
1470
1471}
1472
1473static void pcapng_help(void) {
1474        printf("pcapng format module: \n");
1475        printf("Supported input URIs:\n");
1476        printf("\tpcapng:/path/to/file\n");
1477        printf("\tpcapng:/path/to/file.gz\n");
1478        printf("\n");
1479        printf("\te.g.: pcapng:/tmp/trace.pcap\n");
1480        printf("\n");
1481}
1482
1483static struct libtrace_format_t pcapng = {
1484        "pcapng",
1485        "$Id$",
1486        TRACE_FORMAT_PCAPNG,
1487        NULL,                           /* probe filename */
1488        pcapng_probe_magic,             /* probe magic */
1489        pcapng_init_input,              /* init_input */
1490        pcapng_config_input,            /* config_input */
1491        pcapng_start_input,             /* start_input */
1492        NULL,                           /* pause_input */
1493        NULL,                           /* init_output */
1494        NULL,                           /* config_output */
1495        NULL,                           /* start_output */
1496        pcapng_fin_input,               /* fin_input */
1497        NULL,                           /* fin_output */
1498        pcapng_read_packet,             /* read_packet */
1499        pcapng_prepare_packet,          /* prepare_packet */
1500        NULL,                           /* fin_packet */
1501        NULL,                           /* write_packet */
1502        NULL,                           /* flush_output */
1503        pcapng_get_link_type,           /* get_link_type */
1504        pcapng_get_direction,           /* get_direction */
1505        NULL,                           /* set_direction */
1506        NULL,                           /* get_erf_timestamp */
1507        NULL,                           /* get_timeval */
1508        pcapng_get_timespec,            /* get_timespec */
1509        NULL,                           /* get_seconds */
1510        NULL,                           /* seek_erf */
1511        NULL,                           /* seek_timeval */
1512        NULL,                           /* seek_seconds */
1513        pcapng_get_capture_length,      /* get_capture_length */
1514        pcapng_get_wire_length,         /* get_wire_length */
1515        pcapng_get_framing_length,      /* get_framing_length */
1516        pcapng_set_capture_length,      /* set_capture_length */
1517        NULL,                           /* get_received_packets */
1518        NULL,                           /* get_filtered_packets */
1519        NULL,                           /* get_dropped_packets */
1520        pcapng_get_statistics,          /* get_statistics */
1521        NULL,                           /* get_fd */
1522        pcapng_event,                   /* trace_event */
1523        pcapng_help,                    /* help */
1524        NULL,                           /* next pointer */
1525        NON_PARALLEL(false)
1526};
1527
1528void pcapng_constructor(void) {
1529        register_format(&pcapng);
1530}
1531
Note: See TracBrowser for help on using the repository browser.