source: lib/format_pcapng.c @ f6f3ae5

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

Assertion cleanup

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