source: lib/format_pcap.c @ 2e91590

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivelibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 2e91590 was 2e91590, checked in by Shane Alcock <salcock@…>, 5 years ago

Fix bug where we were leaking pcap file descriptors

Thanks to Tomas Konir for reporting this bug.

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