source: lib/format_pcapng.c @ 2193905

develop
Last change on this file since 2193905 was 2193905, checked in by Jacob Van Walraven <jcv9@…>, 2 years ago

Apply changes required for pull request #81

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