source: lib/format_pcap.c @ 32ee9b2

cachetimestampsdeveloprc-4.0.4ringdecrementfixringperformance
Last change on this file since 32ee9b2 was 32ee9b2, checked in by Shane Alcock <salcock@…>, 2 years ago

Add new trace_flush_output() to public API

Can be used to force a libtrace output to dump any buffered output
to disk immediately.

Note that if the file is compressed or the output trace format
requires a trailer, the flushed file will still not be properly
readable afterwards as this will not result in any trailers
being written. You'll still have to close the file for that.

Mainly this is useful for ensuring that output file sizes grow
over time in situations where the amount of output is relatively
small, rather than staying stuck at 0 bytes until we either reach
1MB of output or the file is closed. For instance, you could have
a timer that calls trace_flush_output() every 30 seconds so that
the output file size will grow if any packets were written in the
last 30 seconds.

  • Property mode set to 100644
File size: 24.1 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
39#ifdef HAVE_PCAP_H
40#  include <pcap.h>
41#  ifdef HAVE_PCAP_INT_H
42#    include <pcap-int.h>
43#  endif
44#endif
45
46/* This format module deals with traces captured using the PCAP library. This
47 * format module handles both captures from a live interface and from PCAP
48 * files.
49 *
50 * However, the PCAP file support featured in this code is superceded by our
51 * own implementation of the PCAP file format, called pcapfile. See
52 * format_pcapfile.c for more information.
53 *
54 * Both the live and trace formats support writing, provided your PCAP library
55 * also supports it.
56 *
57 */
58
59/* Formats implemented in this module:
60 *      pcap - deals with PCAP trace files
61 *      pcapint - deals with live PCAP interfaces
62 */
63
64#ifdef HAVE_LIBPCAP
65static struct libtrace_format_t pcap;
66static struct libtrace_format_t pcapint;
67
68#define DATA(x) ((struct pcap_format_data_t*)((x)->format_data))
69#define DATAOUT(x) ((struct pcap_format_data_out_t*)((x)->format_data))
70
71#define INPUT DATA(libtrace)->input
72#define OUTPUT DATAOUT(libtrace)->output
73struct pcap_format_data_t {
74        /** Information about the current state of the input trace */
75        union {
76                /* The PCAP input source */
77                pcap_t *pcap;
78        } input;
79        /* A filter to be applied to all packets read from the source */
80        libtrace_filter_t *filter;
81        /* The snap length to be applied to all captured packets (live only) */
82        int snaplen;
83        /* Whether the capture interface should be set to promiscuous mode
84         * (live only) */
85        int promisc;
86};
87
88struct pcap_format_data_out_t {
89        /* Information about the current state of the output trace */
90        union {
91                struct {
92                        /* The PCAP output device or trace */
93                        pcap_t *pcap;   
94                        /* The PCAP dumper */
95                        pcap_dumper_t *dump;
96                } trace;
97
98        } output;
99};
100
101static int pcap_init_input(libtrace_t *libtrace) {
102        libtrace->format_data = malloc(sizeof(struct pcap_format_data_t));
103
104        INPUT.pcap = NULL;
105        DATA(libtrace)->filter = NULL;
106        DATA(libtrace)->snaplen = LIBTRACE_PACKET_BUFSIZE;
107        DATA(libtrace)->promisc = 0;
108
109        return 0;
110}
111
112static int pcap_start_input(libtrace_t *libtrace) {
113        char errbuf[PCAP_ERRBUF_SIZE];
114
115
116        /* Check if the file is already open */
117        if (INPUT.pcap)
118                return 0; /* success */
119
120        /* Open the trace file for reading */
121        if ((INPUT.pcap = 
122                pcap_open_offline(libtrace->uridata,
123                        errbuf)) == NULL) {
124                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",
125                                errbuf);
126                return -1;
127        }
128
129        /* If a filter has been configured, compile and apply it */
130#ifdef HAVE_BPF
131        if (DATA(libtrace)->filter) {
132                if (DATA(libtrace)->filter->flag == 0) {
133                        pcap_compile(INPUT.pcap, 
134                                        &DATA(libtrace)->filter->filter,
135                                        DATA(libtrace)->filter->filterstring, 
136                                        1, 0);
137                        DATA(libtrace)->filter->flag = 1;
138                }
139                if (pcap_setfilter(INPUT.pcap,&DATA(libtrace)->filter->filter) 
140                                == -1) {
141                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",
142                                        pcap_geterr(INPUT.pcap));
143                        return -1;
144                }
145        }
146#endif
147        return 0;
148}
149
150static int pcap_config_input(libtrace_t *libtrace,
151                trace_option_t option,
152                void *data)
153{
154        switch(option) {
155                case TRACE_OPTION_FILTER:
156#ifdef HAVE_BPF
157                        DATA(libtrace)->filter=data;
158                        return 0;
159#else
160                        return -1;
161#endif
162                case TRACE_OPTION_SNAPLEN:
163                        /* Snapping isn't supported directly, so fall thru
164                         * and let libtrace deal with it
165                         */
166                case TRACE_OPTION_PROMISC:
167                        /* Can't do promisc on a trace! */
168                case TRACE_OPTION_META_FREQ:
169                        /* No meta data for this format */
170                case TRACE_OPTION_EVENT_REALTIME:
171                        /* We do not support this option for PCAP traces */
172                default:
173                        return -1;
174        }
175        assert(0);
176}
177
178static int pcap_init_output(libtrace_out_t *libtrace) {
179        libtrace->format_data = malloc(sizeof(struct pcap_format_data_out_t));
180        OUTPUT.trace.pcap = NULL;
181        OUTPUT.trace.dump = NULL;
182        return 0;
183}
184
185static int pcapint_init_output(libtrace_out_t *libtrace) {
186#ifdef HAVE_PCAP_INJECT
187        libtrace->format_data = malloc(sizeof(struct pcap_format_data_out_t));
188        OUTPUT.trace.pcap = NULL;
189        OUTPUT.trace.dump = NULL;
190        return 0;
191#else
192#ifdef HAVE_PCAP_SENDPACKET
193        libtrace->format_data = malloc(sizeof(struct pcap_format_data_out_t));
194        OUTPUT.trace.pcap = NULL;
195        OUTPUT.trace.dump = NULL;
196        return 0;
197#else
198        trace_set_err_out(libtrace,TRACE_ERR_UNSUPPORTED,
199                        "writing not supported by this version of pcap");
200        return -1;
201#endif
202#endif
203}
204
205static int pcapint_init_input(libtrace_t *libtrace) {
206        libtrace->format_data = malloc(sizeof(struct pcap_format_data_t));
207        DATA(libtrace)->filter = NULL;
208        DATA(libtrace)->snaplen = LIBTRACE_PACKET_BUFSIZE;
209        DATA(libtrace)->promisc = 0;
210        return 0; /* success */
211}
212
213static int pcapint_config_input(libtrace_t *libtrace,
214                trace_option_t option,
215                void *data)
216{
217        switch(option) {
218                case TRACE_OPTION_FILTER:
219#ifdef HAVE_BPF
220                        DATA(libtrace)->filter=(libtrace_filter_t*)data;
221                        return 0;
222#else
223                        return -1;
224#endif
225                case TRACE_OPTION_SNAPLEN:
226                        DATA(libtrace)->snaplen=*(int*)data;
227                        return 0;
228                case TRACE_OPTION_PROMISC:
229                        DATA(libtrace)->promisc=*(int*)data;
230                        return 0;
231                case TRACE_OPTION_META_FREQ:
232                        /* No meta-data for this format */
233                case TRACE_OPTION_EVENT_REALTIME:
234                        /* live interface is always real-time! */
235                default:
236                        /* Don't set an error here - trace_config will try
237                         * to handle the option when we return. If it can't
238                         * deal with it, then it will do the necessary
239                         * error-setting. */
240                        return -1;
241        }
242        assert(0);
243}
244
245static int pcapint_start_input(libtrace_t *libtrace) {
246        char errbuf[PCAP_ERRBUF_SIZE];
247
248#ifdef HAVE_PCAP_CREATE
249        int ret = 0;
250       
251        if ((INPUT.pcap = pcap_create(libtrace->uridata, errbuf)) == NULL) {
252                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",errbuf);
253                return -1; /* failure */
254        }
255        if ((pcap_set_snaplen(INPUT.pcap, DATA(libtrace)->snaplen) == 
256                                PCAP_ERROR_ACTIVATED)) {
257                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",errbuf);
258                return -1; /* failure */
259        }
260
261        if ((pcap_set_promisc(INPUT.pcap, DATA(libtrace)->promisc) == 
262                                PCAP_ERROR_ACTIVATED)) {
263                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",errbuf);
264                return -1; /* failure */
265        }
266       
267        if ((pcap_set_timeout(INPUT.pcap, 1) == PCAP_ERROR_ACTIVATED)) {
268                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",errbuf);
269                return -1; /* failure */
270        }
271
272#ifdef HAVE_PCAP_IMMEDIATE
273        if ((pcap_set_immediate_mode(INPUT.pcap, 1) == PCAP_ERROR_ACTIVATED)) {
274                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",errbuf);
275                return -1; /* failure */
276        }
277#endif
278
279        if ((ret = pcap_activate(INPUT.pcap)) != 0) {
280                if (ret == PCAP_WARNING_PROMISC_NOTSUP) {
281                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,"Promiscuous mode unsupported");
282                        return -1;
283                }
284                if (ret == PCAP_WARNING) {
285                        pcap_perror(INPUT.pcap, "Pcap Warning:");
286                } else {
287                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",
288                                        pcap_geterr(INPUT.pcap));
289                        return -1;
290                }
291        }
292                         
293#else   
294
295        /* Open the live device */
296        if ((INPUT.pcap = 
297                        pcap_open_live(libtrace->uridata,
298                        DATA(libtrace)->snaplen,
299                        DATA(libtrace)->promisc,
300                        1,
301                        errbuf)) == NULL) {
302                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",errbuf);
303                return -1; /* failure */
304        }
305#endif
306#ifdef HAVE_PCAP_SETNONBLOCK
307        pcap_setnonblock(INPUT.pcap,0,errbuf);
308#endif
309        /* Set a filter if one is defined */
310#ifdef HAVE_BPF
311        if (DATA(libtrace)->filter) {
312                struct pcap_pkthdr *pcap_hdr = NULL;
313                u_char *pcap_payload = NULL;
314                int pcapret;
315               
316                if (DATA(libtrace)->filter->flag == 0) {
317                        pcap_compile(INPUT.pcap, 
318                                        &DATA(libtrace)->filter->filter,
319                                        DATA(libtrace)->filter->filterstring, 
320                                        1, 0);
321                        DATA(libtrace)->filter->flag = 1;
322                }
323                if (pcap_setfilter(INPUT.pcap,&DATA(libtrace)->filter->filter)
324                        == -1) {
325                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",
326                                        pcap_geterr(INPUT.pcap));
327                        return -1; /* failure */
328                }
329
330                /* Consume the first packet in the queue, as this may not
331                 * have had the filter applied to it.
332                 *
333                 * Otherwise we can get problems with the event API, where
334                 * select tells us that there is a packet available but
335                 * calling trace_read_packet will block forever because the
336                 * packet in the queue didn't match the filter so
337                 * pcap_next_ex returns "timed out".
338                 *
339                 * This does mean we may consume a legitimate packet, but
340                 * that's a pretty small downside compared with trace_event
341                 * getting stuck in an infinite loop because of pcap
342                 * wackiness.
343                 *
344                 * For some reason, we only need to consume one packet for
345                 * this to work, so let's hope that holds in the future.
346                 */
347                do {
348                        pcapret = pcap_next_ex(INPUT.pcap, &pcap_hdr, 
349                                (const u_char **)&pcap_payload);
350                } while (0);
351
352                if (pcapret < 0)
353                        return -1;
354        }
355#endif
356        return 0; /* success */
357}
358
359static int pcap_pause_input(libtrace_t *libtrace UNUSED)
360{
361        return 0; /* success */
362}
363
364
365static int pcap_fin_input(libtrace_t *libtrace) 
366{
367        pcap_close(INPUT.pcap);
368        INPUT.pcap=NULL;
369        free(libtrace->format_data);
370        return 0; /* success */
371}
372
373static int pcap_fin_output(libtrace_out_t *libtrace) 
374{
375        if (OUTPUT.trace.dump) {
376                pcap_dump_flush(OUTPUT.trace.dump);
377                pcap_dump_close(OUTPUT.trace.dump);
378        }
379        pcap_close(OUTPUT.trace.pcap);
380        free(libtrace->format_data);
381        return 0;
382}
383
384static int pcapint_fin_output(libtrace_out_t *libtrace)
385{
386        pcap_close(OUTPUT.trace.pcap);
387        free(libtrace->format_data);
388        return 0;
389}
390
391static int pcap_prepare_packet(libtrace_t *libtrace, libtrace_packet_t *packet,
392                void *buffer, libtrace_rt_types_t rt_type, uint32_t flags) {
393       
394        if (packet->buffer != buffer &&
395                        packet->buf_control == TRACE_CTRL_PACKET) {
396                        free(packet->buffer);
397        }
398
399        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
400                packet->buf_control = TRACE_CTRL_PACKET;
401        } else
402                packet->buf_control = TRACE_CTRL_EXTERNAL;
403       
404       
405        packet->buffer = buffer;
406        packet->header = buffer;
407        packet->type = rt_type;
408
409        /* Assuming header and payload are sequential in the buffer -
410         * regular pcap often doesn't work like this though, so hopefully
411         * we're not called by something that is reading genuine pcap! */
412        packet->payload = (char *)packet->header + sizeof(struct pcap_pkthdr);
413
414        if (libtrace->format_data == NULL) {
415                if (pcap_init_input(libtrace))
416                        return -1;
417        }
418        return 0;
419}
420
421static int pcap_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
422        int ret = 0;
423        int linktype;
424        uint32_t flags = 0;
425       
426        assert(libtrace->format_data);
427        linktype = pcap_datalink(DATA(libtrace)->input.pcap);
428        packet->type = pcap_linktype_to_rt(linktype);
429
430        /* If we're using the replacement pcap_next_ex() we need to
431         * make sure we have a buffer to *shudder* memcpy into
432         */
433        if (!packet->buffer) {
434                packet->buffer = malloc(LIBTRACE_PACKET_BUFSIZE);
435                if (!packet->buffer) {
436                        trace_set_err(libtrace, errno, 
437                                        "Cannot allocate memory");
438                        return -1;
439                }
440                packet->header = packet->buffer;
441                packet->payload = (char *)packet->buffer+sizeof(struct pcap_pkthdr);
442                       
443        }
444
445        flags |= TRACE_PREP_OWN_BUFFER;
446       
447        for(;;) {
448               
449                struct pcap_pkthdr *pcap_hdr = NULL;
450                u_char *pcap_payload = NULL;
451
452                ret = pcap_next_ex(INPUT.pcap, &pcap_hdr, 
453                                (const u_char **)&pcap_payload);
454               
455                packet->header = pcap_hdr;
456                packet->payload = pcap_payload;
457
458                switch(ret) {
459                        case 1: break; /* no error */
460                        case 0:
461                                if ((ret=is_halted(libtrace)) != -1)
462                                        return ret;
463                                continue; /* timeout expired */
464                        case -1:
465                                trace_set_err(libtrace,TRACE_ERR_BAD_PACKET,
466                                                "%s",pcap_geterr(INPUT.pcap));
467                                return -1; /* Error */
468                        case -2:
469                                return 0; /* EOF */
470                }
471
472                /*
473                 * pcap is nasty in that the header and payload aren't
474                 * necessarily located sequentially in memory, but most
475                 * sensible uses of pcap_prepare_packet will involve a
476                 * buffer where header and payload are sequential.
477                 *
478                 * Basically, don't call pcap_prepare_packet here!
479                 *
480                if (pcap_prepare_packet(libtrace, packet, packet->buffer,
481                                packet->type, flags)) {
482                        return -1;
483                }
484                */
485                return ((struct pcap_pkthdr*)packet->header)->len
486                        +sizeof(struct pcap_pkthdr);
487        }
488}
489
490static int pcap_write_packet(libtrace_out_t *libtrace, 
491                libtrace_packet_t *packet) 
492{
493        struct pcap_pkthdr pcap_pkt_hdr;
494        void *link;
495        libtrace_linktype_t linktype;
496        uint32_t remaining;
497
498        link = trace_get_packet_buffer(packet,&linktype,&remaining);
499
500        /* Silently discard RT metadata packets and packets with an
501         * unknown linktype. */
502        if (linktype == TRACE_TYPE_NONDATA || linktype == TRACE_TYPE_UNKNOWN || linktype == TRACE_TYPE_ERF_META) {
503                return 0;
504        }
505
506        /* We may have to convert this packet into a suitable PCAP packet */
507
508        /* If this packet cannot be converted to a pcap linktype then
509         * pop off the top header until it can be converted
510         */
511        while (libtrace_to_pcap_linktype(linktype)==TRACE_DLT_ERROR) {
512                if (!demote_packet(packet)) {
513                        trace_set_err_out(libtrace, 
514                                TRACE_ERR_NO_CONVERSION,
515                                "pcap does not support this format");
516                        return -1;
517                }
518
519                link = trace_get_packet_buffer(packet,&linktype,&remaining);
520        }
521
522
523        if (!OUTPUT.trace.pcap) {
524                int linktype=libtrace_to_pcap_dlt(trace_get_link_type(packet));
525                OUTPUT.trace.pcap = pcap_open_dead(linktype,65536);
526                if (!OUTPUT.trace.pcap) {
527                        trace_set_err_out(libtrace,TRACE_ERR_INIT_FAILED,
528                                        "Failed to open dead trace: %s\n",
529                                        pcap_geterr(OUTPUT.trace.pcap));
530                }
531                OUTPUT.trace.dump = pcap_dump_open(OUTPUT.trace.pcap,
532                                libtrace->uridata);
533                if (!OUTPUT.trace.dump) {
534                        char *errmsg = pcap_geterr(OUTPUT.trace.pcap);
535                        trace_set_err_out(libtrace,TRACE_ERR_INIT_FAILED,"Failed to open output file: %s\n",
536                                        errmsg ? errmsg : "Unknown error");
537                        return -1;
538                }
539        }
540
541        /* Corrupt packet, or other "non data" packet, so skip it */
542        if (link == NULL) {
543                /* Return "success", but nothing written */
544                return 0;
545        }
546
547        /* Check if the packet was captured using one of the PCAP formats */
548        if (packet->trace->format == &pcap || 
549                        packet->trace->format == &pcapint) {
550                /* Yes - this means we can write it straight out */
551                pcap_dump((u_char*)OUTPUT.trace.dump,
552                                (struct pcap_pkthdr *)packet->header,
553                                packet->payload);
554        } else {
555                /* No - need to fill in a PCAP header with the appropriate
556                 * values */
557
558                /* Leave the manual copy as it is, as it gets around
559                 * some OS's having different structures in pcap_pkt_hdr
560                 */
561                struct timeval ts = trace_get_timeval(packet);
562                pcap_pkt_hdr.ts.tv_sec = ts.tv_sec;
563                pcap_pkt_hdr.ts.tv_usec = ts.tv_usec;
564                pcap_pkt_hdr.caplen = remaining;
565                /* trace_get_wire_length includes FCS, while pcap doesn't */
566                if (trace_get_link_type(packet)==TRACE_TYPE_ETH)
567                        if (trace_get_wire_length(packet) >= 4) { 
568                                pcap_pkt_hdr.len = 
569                                        trace_get_wire_length(packet)-4;
570                        }
571                        else {
572                                pcap_pkt_hdr.len = 0;
573                        }
574                else
575                        pcap_pkt_hdr.len = trace_get_wire_length(packet);
576
577                assert(pcap_pkt_hdr.caplen<65536);
578                assert(pcap_pkt_hdr.len<65536);
579
580                pcap_dump((u_char*)OUTPUT.trace.dump, &pcap_pkt_hdr, packet->payload);
581        }
582        return remaining;
583}
584
585static int pcap_flush_output(libtrace_out_t *libtrace) {
586        return pcap_dump_flush(OUTPUT.trace.dump);
587}
588
589static int pcapint_write_packet(libtrace_out_t *libtrace,
590                libtrace_packet_t *packet) 
591{
592        int err;
593        libtrace_linktype_t linktype = trace_get_link_type(packet);
594
595        /* Silently discard RT metadata packets and packets with an
596         * unknown linktype. */
597        if (linktype == TRACE_TYPE_NONDATA || linktype == TRACE_TYPE_UNKNOWN || linktype == TRACE_TYPE_ERF_META) {
598                return 0;
599        }
600
601        if (!OUTPUT.trace.pcap) {
602                OUTPUT.trace.pcap = (pcap_t *)pcap_open_live(
603                        libtrace->uridata,65536,0,0,NULL);
604        }
605#ifdef HAVE_PCAP_INJECT
606        err=pcap_inject(OUTPUT.trace.pcap,
607                        packet->payload,
608                        trace_get_capture_length(packet));
609        if (err!=(int)trace_get_capture_length(packet))
610                err=-1;
611#else
612#ifdef HAVE_PCAP_SENDPACKET
613        err=pcap_sendpacket(OUTPUT.trace.pcap,
614                        packet->payload,
615                        trace_get_capture_length(packet));
616#else
617    trace_set_err(packet->trace,TRACE_ERR_UNSUPPORTED,"writing is not supported on this platform");
618        return -1;
619#endif
620#endif
621        return err;
622}
623
624static libtrace_linktype_t pcap_get_link_type(const libtrace_packet_t *packet) {
625        /* PCAP doesn't store linktype in the framing header so we need
626         * RT to do it for us
627         */
628        int linktype = rt_to_pcap_linktype(packet->type);
629        return pcap_linktype_to_libtrace(linktype);
630}
631
632static libtrace_direction_t pcap_set_direction(libtrace_packet_t *packet,
633                libtrace_direction_t dir) {
634
635        /* We only support tagging with IN or OUT return error for any others */
636        if(!(dir == TRACE_DIR_OUTGOING || dir == TRACE_DIR_INCOMING))
637                return -1;
638
639        /* PCAP doesn't have a direction field in the header, so we need to
640         * promote to Linux SLL to tag it properly */
641        libtrace_sll_header_t *sll;
642        promote_packet(packet);
643        sll=packet->payload;
644       
645        /* sll->pkttype should be in the endianness of the host that the
646         * trace was taken on.  This is impossible to achieve so we assume
647         * host endianness
648         */
649        if(dir==TRACE_DIR_OUTGOING)
650                sll->pkttype=TRACE_SLL_OUTGOING;
651        else
652                sll->pkttype=TRACE_SLL_HOST;
653        return dir;
654}
655
656static libtrace_direction_t pcapint_get_direction(const libtrace_packet_t *packet) {
657        /* This function is defined in format_helper.c */
658        return pcap_get_direction(packet);
659}
660
661
662static struct timeval pcap_get_timeval(const libtrace_packet_t *packet) {
663        struct pcap_pkthdr *pcapptr = (struct pcap_pkthdr *)packet->header;
664        struct timeval ts;
665        ts.tv_sec = pcapptr->ts.tv_sec;
666        ts.tv_usec = pcapptr->ts.tv_usec;
667        return ts;
668}
669
670
671static int pcap_get_capture_length(const libtrace_packet_t *packet) {
672        struct pcap_pkthdr *pcapptr = 0;
673        pcapptr = (struct pcap_pkthdr *)packet->header;
674        assert(pcapptr->caplen<=65536);
675
676        return pcapptr->caplen;
677}
678
679static int pcap_get_wire_length(const libtrace_packet_t *packet) {
680        struct pcap_pkthdr *pcapptr = 0;
681        pcapptr = (struct pcap_pkthdr *)packet->header;
682        if (packet->type==pcap_linktype_to_rt(TRACE_DLT_EN10MB))
683                return pcapptr->len+4; /* Include the missing FCS */
684        else if (packet->type==pcap_linktype_to_rt(TRACE_DLT_IEEE802_11_RADIO)) {
685                libtrace_linktype_t linktype;
686                void *link = trace_get_packet_buffer(packet,&linktype,NULL);
687                /* If the packet is Radiotap and the flags field indicates
688                 * that the FCS is not included in the 802.11 frame, then
689                 * we need to add 4 to the wire-length to account for it.
690                 */
691                uint8_t flags;
692                trace_get_wireless_flags(link, 
693                                linktype, &flags);
694                if ((flags & TRACE_RADIOTAP_F_FCS) == 0)
695                        return pcapptr->len + 4;
696        }
697        return pcapptr->len;
698}
699
700static int pcap_get_framing_length(UNUSED const libtrace_packet_t *packet) {
701        return sizeof(struct pcap_pkthdr);
702}
703
704static size_t pcap_set_capture_length(libtrace_packet_t *packet,size_t size) {
705        struct pcap_pkthdr *pcapptr = 0;
706        assert(packet);
707        if (size > trace_get_capture_length(packet)) {
708                /* Can't make a packet larger */
709                return trace_get_capture_length(packet);
710        }
711        /* Reset the cached capture length */
712        packet->capture_length = -1;
713        pcapptr = (struct pcap_pkthdr *)packet->header;
714        pcapptr->caplen = size;
715        return trace_get_capture_length(packet);
716}
717
718static int pcap_get_fd(const libtrace_t *trace) {
719
720        assert(trace->format_data);
721        return pcap_fileno(DATA(trace)->input.pcap);
722}
723
724static void pcap_get_statistics(libtrace_t *trace, libtrace_stat_t *stat) {
725
726        struct pcap_stat pcapstats;
727        if (pcap_stats(DATA(trace)->input.pcap,&pcapstats)==-1) {
728                char *errmsg = pcap_geterr(DATA(trace)->input.pcap);
729                trace_set_err(trace,TRACE_ERR_UNSUPPORTED,
730                                "Failed to retrieve stats: %s\n",
731                                errmsg ? errmsg : "Unknown pcap error");
732                return;
733        }
734
735        stat->received_valid = 1;
736        stat->received = pcapstats.ps_recv;
737        stat->dropped_valid = 1;
738        stat->dropped = pcapstats.ps_drop;
739}
740
741static void pcap_help(void) {
742        printf("pcap format module: $Revision: 1729 $\n");
743        printf("Supported input URIs:\n");
744        printf("\tpcap:/path/to/file\n");
745        printf("\n");
746        printf("\te.g.: pcap:/tmp/trace.pcap\n");
747        printf("\n");
748        printf("Supported output URIs:\n");
749        printf("\tnone\n");
750        printf("\n");
751}
752
753static void pcapint_help(void) {
754        printf("pcapint format module: $Revision: 1729 $\n");
755        printf("Supported input URIs:\n");
756        printf("\tpcapint:interface\n");
757        printf("\n");
758        printf("\te.g.: pcapint:eth0\n");
759        printf("\n");
760        printf("Supported output URIs:\n");
761        printf("\tnone\n");
762        printf("\n");
763}
764
765
766static struct libtrace_format_t pcap = {
767        "pcap",
768        "$Id$",
769        TRACE_FORMAT_PCAP,
770        NULL,                           /* probe filename */
771        NULL,                           /* probe magic */
772        pcap_init_input,                /* init_input */
773        pcap_config_input,              /* config_input */
774        pcap_start_input,               /* start_input */
775        pcap_pause_input,               /* pause_input */
776        pcap_init_output,               /* init_output */
777        NULL,                           /* config_output */
778        NULL,                           /* start_output */
779        pcap_fin_input,                 /* fin_input */
780        pcap_fin_output,                /* fin_output */
781        pcap_read_packet,               /* read_packet */
782        pcap_prepare_packet,            /* prepare_packet */
783        NULL,                           /* fin_packet */
784        pcap_write_packet,              /* write_packet */
785        pcap_flush_output,              /* flush_output */
786        pcap_get_link_type,             /* get_link_type */
787        pcapint_get_direction,          /* get_direction */
788        pcap_set_direction,             /* set_direction */
789        NULL,                           /* get_erf_timestamp */
790        pcap_get_timeval,               /* get_timeval */
791        NULL,                           /* get_seconds */
792        NULL,                           /* get_timespec */
793        NULL,                           /* seek_erf */
794        NULL,                           /* seek_timeval */
795        NULL,                           /* seek_seconds */
796        pcap_get_capture_length,        /* get_capture_length */
797        pcap_get_wire_length,           /* get_wire_length */
798        pcap_get_framing_length,        /* get_framing_length */
799        pcap_set_capture_length,        /* set_capture_length */
800        NULL,                           /* get_received_packets */
801        NULL,                           /* get_filtered_packets */
802        NULL,                           /* get_dropped_packets */
803        NULL,                           /* get_statistics */
804        NULL,                           /* get_fd */
805        trace_event_trace,              /* trace_event */
806        pcap_help,                      /* help */
807        NULL,                   /* next pointer */
808        NON_PARALLEL(false)
809};
810
811static struct libtrace_format_t pcapint = {
812        "pcapint",
813        "$Id$",
814        TRACE_FORMAT_PCAP,
815        NULL,                           /* probe filename */
816        NULL,                           /* probe magic */
817        pcapint_init_input,             /* init_input */
818        pcapint_config_input,           /* config_input */
819        pcapint_start_input,            /* start_input */
820        pcap_pause_input,               /* pause_input */
821        pcapint_init_output,            /* init_output */
822        NULL,                           /* config_output */
823        NULL,                           /* start_output */
824        pcap_fin_input,                 /* fin_input */
825        pcapint_fin_output,             /* fin_output */
826        pcap_read_packet,               /* read_packet */
827        pcap_prepare_packet,            /* prepare_packet */
828        NULL,                           /* fin_packet */
829        pcapint_write_packet,           /* write_packet */
830        NULL,                           /* flush_output */
831        pcap_get_link_type,             /* get_link_type */
832        pcapint_get_direction,          /* get_direction */
833        pcap_set_direction,             /* set_direction */
834        NULL,                           /* get_erf_timestamp */
835        pcap_get_timeval,               /* get_timeval */
836        NULL,                           /* get_seconds */
837        NULL,                           /* get_timespec */
838        NULL,                           /* seek_erf */
839        NULL,                           /* seek_timeval */
840        NULL,                           /* seek_seconds */
841        pcap_get_capture_length,        /* get_capture_length */
842        pcap_get_wire_length,           /* get_wire_length */
843        pcap_get_framing_length,        /* get_framing_length */
844        pcap_set_capture_length,        /* set_capture_length */
845        NULL,                           /* get_received_packets */
846        NULL,                           /* get_filtered_packets */
847        NULL,                           /* get_dropped_packets */
848        pcap_get_statistics,            /* get_statistics */
849        pcap_get_fd,                    /* get_fd */
850        trace_event_device,             /* trace_event */
851        pcapint_help,                   /* help */
852        NULL,                   /* next pointer */
853        NON_PARALLEL(true)
854};
855
856void pcap_constructor(void) {
857        register_format(&pcap);
858        register_format(&pcapint);
859}
860
861
862#endif
Note: See TracBrowser for help on using the repository browser.