source: lib/format_pcapng.c @ aceeda6

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

Add some checks to prevent segfaults with dead traces

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