source: lib/format_pcapng.c @ d9ca546

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

Add write support for pcapng

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