source: lib/format_pcapng.c @ 9a6bdbc

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

Added can_write functions to each output format, Fixed pcapng_get_header_type incorrectly flipping type bytes

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