source: lib/format_pcap.c @ d47ca18

cachetimestampsdevelopdpdk-ndagetsilivendag_formatrc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformance
Last change on this file since d47ca18 was d47ca18, checked in by Richard Sanger <rsanger@…>, 4 years ago

Fix issue #49 compile issues when missing BPF header file

If pcap was installed but somehow the BPF header was missing.
Libtrace was using two different macros HAVE_BPF and HAVE_BPF_FILTER
to determine if BPF was installed.

HAVE_BPF_FILTER was set if pcap was found, wereas HAVE_BPF was
set if the BPF header was found.

This removes and replaces HAVE_BPF_FILTER with HAVE_BPF.
It also adds ifdef blocks around formats that try to install
BPF filters directly as needed.

  • Property mode set to 100644
File size: 24.9 KB
RevLine 
[4dedc28]1/*
2 *
[ee6e802]3 * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand.
[4dedc28]4 * All rights reserved.
5 *
[ee6e802]6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
[4dedc28]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
[ee6e802]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
[4dedc28]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
[ee6e802]19 * GNU Lesser General Public License for more details.
[4dedc28]20 *
[ee6e802]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/>.
[4dedc28]23 *
24 *
25 */
26#include "common.h"
27#include "config.h"
28#include "libtrace.h"
[9e2a109]29#include "libtrace_int.h"
[72bfe20]30#include "format_helper.h"
[ffc8c8d]31
[4dedc28]32#include <sys/stat.h>
33#include <assert.h>
[b69afb1]34#include <stdio.h>
[9c6aa95]35#include <stdlib.h>
36#include <string.h>
[880aa58]37#include <errno.h>
[4dedc28]38
[e5c2bc4]39#ifdef HAVE_PCAP_H
[4dedc28]40#  include <pcap.h>
41#  ifdef HAVE_PCAP_INT_H
42#    include <pcap-int.h>
43#  endif
44#endif
45
[238d50a]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
[e5c2bc4]64#ifdef HAVE_LIBPCAP
[f3ed52a]65static struct libtrace_format_t pcap;
66static struct libtrace_format_t pcapint;
[91ebc50]67
[ab4cb04]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))
[3073c04]70
[ab4cb04]71#define INPUT DATA(libtrace)->input
72#define OUTPUT DATAOUT(libtrace)->output
73struct pcap_format_data_t {
[238d50a]74        /** Information about the current state of the input trace */
[9e2a109]75        union {
[238d50a]76                /* The PCAP input source */
77                pcap_t *pcap;
[9e2a109]78        } input;
[238d50a]79        /* A filter to be applied to all packets read from the source */
[df338b3]80        libtrace_filter_t *filter;
[238d50a]81        /* The snap length to be applied to all captured packets (live only) */
[db03808]82        int snaplen;
[238d50a]83        /* Whether the capture interface should be set to promiscuous mode
84         * (live only) */
[df338b3]85        int promisc;
[9e2a109]86};
87
[ab4cb04]88struct pcap_format_data_out_t {
[238d50a]89        /* Information about the current state of the output trace */
[3073c04]90        union {
[1974620]91                struct {
[238d50a]92                        /* The PCAP output device or trace */
93                        pcap_t *pcap;   
94                        /* The PCAP dumper */
[1974620]95                        pcap_dumper_t *dump;
96                } trace;
97
[3073c04]98        } output;
99};
100
[e6d963c]101static int pcap_init_input(libtrace_t *libtrace) {
[ab4cb04]102        libtrace->format_data = malloc(sizeof(struct pcap_format_data_t));
[72bfe20]103
[df338b3]104        INPUT.pcap = NULL;
105        DATA(libtrace)->filter = NULL;
[bdde7b8]106        DATA(libtrace)->snaplen = LIBTRACE_PACKET_BUFSIZE;
[df338b3]107        DATA(libtrace)->promisc = 0;
108
[d5879cc]109        return 0;
[df338b3]110}
111
[e6d963c]112static int pcap_start_input(libtrace_t *libtrace) {
[df338b3]113        char errbuf[PCAP_ERRBUF_SIZE];
[6c248a9]114
[50bbce8]115
[238d50a]116        /* Check if the file is already open */
[6c248a9]117        if (INPUT.pcap)
118                return 0; /* success */
119
[238d50a]120        /* Open the trace file for reading */
[df338b3]121        if ((INPUT.pcap = 
122                pcap_open_offline(libtrace->uridata,
123                        errbuf)) == NULL) {
[0ea3526]124                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",
[df338b3]125                                errbuf);
126                return -1;
127        }
[238d50a]128
129        /* If a filter has been configured, compile and apply it */
[d47ca18]130#ifdef HAVE_BPF
[df338b3]131        if (DATA(libtrace)->filter) {
[3a14f3b]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                }
[df338b3]139                if (pcap_setfilter(INPUT.pcap,&DATA(libtrace)->filter->filter) 
140                                == -1) {
[0ea3526]141                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",
[df338b3]142                                        pcap_geterr(INPUT.pcap));
143                        return -1;
[4dedc28]144                }
145        }
[d47ca18]146#endif
[df338b3]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:
[d47ca18]156#ifdef HAVE_BPF
[df338b3]157                        DATA(libtrace)->filter=data;
158                        return 0;
[d47ca18]159#else
160                        return -1;
161#endif
[df338b3]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:
[238d50a]167                        /* Can't do promisc on a trace! */
[646aca1]168                case TRACE_OPTION_META_FREQ:
[cd7eec7]169                        /* No meta data for this format */
[708f9ae]170                case TRACE_OPTION_EVENT_REALTIME:
[238d50a]171                        /* We do not support this option for PCAP traces */
[df338b3]172                default:
173                        return -1;
174        }
175        assert(0);
176}
177
[e4e95499]178static int pcap_init_output(libtrace_out_t *libtrace) {
[ab4cb04]179        libtrace->format_data = malloc(sizeof(struct pcap_format_data_out_t));
[1974620]180        OUTPUT.trace.pcap = NULL;
181        OUTPUT.trace.dump = NULL;
[fe76c55]182        return 0;
[3073c04]183}
184
[e4e95499]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
[91db67b]198        trace_set_err_out(libtrace,TRACE_ERR_UNSUPPORTED,
[e4e95499]199                        "writing not supported by this version of pcap");
200        return -1;
201#endif
202#endif
203}
204
[e6d963c]205static int pcapint_init_input(libtrace_t *libtrace) {
[ab4cb04]206        libtrace->format_data = malloc(sizeof(struct pcap_format_data_t));
[df338b3]207        DATA(libtrace)->filter = NULL;
[b7d2de5]208        DATA(libtrace)->snaplen = LIBTRACE_PACKET_BUFSIZE;
[df338b3]209        DATA(libtrace)->promisc = 0;
[6c248a9]210        return 0; /* success */
[df338b3]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:
[d47ca18]219#ifdef HAVE_BPF
[85a79b0]220                        DATA(libtrace)->filter=(libtrace_filter_t*)data;
[df338b3]221                        return 0;
[d47ca18]222#else
223                        return -1;
224#endif
[df338b3]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;
[646aca1]231                case TRACE_OPTION_META_FREQ:
[cd7eec7]232                        /* No meta-data for this format */
[708f9ae]233                case TRACE_OPTION_EVENT_REALTIME:
234                        /* live interface is always real-time! */
[df338b3]235                default:
[708f9ae]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. */
[df338b3]240                        return -1;
241        }
242        assert(0);
243}
244
245static int pcapint_start_input(libtrace_t *libtrace) {
246        char errbuf[PCAP_ERRBUF_SIZE];
[c0506ea]247
248#ifdef HAVE_PCAP_CREATE
249        int ret = 0;
[238d50a]250       
[c0506ea]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
[7fe6dfa]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
[c0506ea]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
[238d50a]295        /* Open the live device */
[72bfe20]296        if ((INPUT.pcap = 
[df338b3]297                        pcap_open_live(libtrace->uridata,
298                        DATA(libtrace)->snaplen,
299                        DATA(libtrace)->promisc,
[4dedc28]300                        1,
301                        errbuf)) == NULL) {
[0ea3526]302                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",errbuf);
[6c248a9]303                return -1; /* failure */
[8ea5b38]304        }
[c0506ea]305#endif
[4649fea]306#ifdef HAVE_PCAP_SETNONBLOCK
307        pcap_setnonblock(INPUT.pcap,0,errbuf);
308#endif
[8ea5b38]309        /* Set a filter if one is defined */
[d47ca18]310#ifdef HAVE_BPF
[8ea5b38]311        if (DATA(libtrace)->filter) {
[4649fea]312                struct pcap_pkthdr *pcap_hdr = NULL;
313                u_char *pcap_payload = NULL;
314                int pcapret;
315               
316                if (DATA(libtrace)->filter->flag == 0) {
[c0506ea]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                }
[4649fea]323                if (pcap_setfilter(INPUT.pcap,&DATA(libtrace)->filter->filter)
[8ea5b38]324                        == -1) {
[0ea3526]325                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",
[8ea5b38]326                                        pcap_geterr(INPUT.pcap));
[6c248a9]327                        return -1; /* failure */
[8ea5b38]328                }
[4649fea]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;
[4dedc28]354        }
[d47ca18]355#endif
[6c248a9]356        return 0; /* success */
[4dedc28]357}
358
[1d780e4]359static int pcap_pause_input(libtrace_t *libtrace UNUSED)
[6c248a9]360{
361        return 0; /* success */
362}
363
[747c501]364
[6c248a9]365static int pcap_fin_input(libtrace_t *libtrace) 
366{
[62dec50]367        pcap_close(INPUT.pcap);
368        INPUT.pcap=NULL;
[3073c04]369        free(libtrace->format_data);
[6c248a9]370        return 0; /* success */
[3073c04]371}
372
[6c248a9]373static int pcap_fin_output(libtrace_out_t *libtrace) 
374{
[f875681]375        if (OUTPUT.trace.dump) {
376                pcap_dump_flush(OUTPUT.trace.dump);
377                pcap_dump_close(OUTPUT.trace.dump);
378        }
[f0d19d4]379        pcap_close(OUTPUT.trace.pcap);
380        free(libtrace->format_data);
[3073c04]381        return 0;
[4dedc28]382}
383
[e4e95499]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
[f0fb38f]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}
[ffc8c8d]420
[e6d963c]421static int pcap_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
[62987bb]422        int ret = 0;
[7ac9705]423        int linktype;
[f0fb38f]424        uint32_t flags = 0;
425       
[7ac9705]426        assert(libtrace->format_data);
427        linktype = pcap_datalink(DATA(libtrace)->input.pcap);
[73dd29f]428        packet->type = pcap_linktype_to_rt(linktype);
[62987bb]429
[77285d9]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;
[f0fb38f]441                packet->payload = (char *)packet->buffer+sizeof(struct pcap_pkthdr);
442                       
[77285d9]443        }
[f0fb38f]444
445        flags |= TRACE_PREP_OWN_BUFFER;
[77285d9]446       
[62987bb]447        for(;;) {
[7837dc4]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;
[62987bb]457
458                switch(ret) {
459                        case 1: break; /* no error */
[c0506ea]460                        case 0:
[5e3f16c]461                                if ((ret=is_halted(libtrace)) != -1)
462                                        return ret;
[4649fea]463                                continue; /* timeout expired */
[62987bb]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
[f0fb38f]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                */
[62987bb]485                return ((struct pcap_pkthdr*)packet->header)->len
486                        +sizeof(struct pcap_pkthdr);
[4dedc28]487        }
488}
489
[85a79b0]490static int pcap_write_packet(libtrace_out_t *libtrace, 
491                libtrace_packet_t *packet) 
492{
[3073c04]493        struct pcap_pkthdr pcap_pkt_hdr;
[9bc4689]494        void *link;
495        libtrace_linktype_t linktype;
496        uint32_t remaining;
497
498        link = trace_get_packet_buffer(packet,&linktype,&remaining);
[3073c04]499
[238d50a]500        /* We may have to convert this packet into a suitable PCAP packet */
501
[d5e1796]502        /* If this packet cannot be converted to a pcap linktype then
503         * pop off the top header until it can be converted
504         */
[f7bcbfb]505        while (libtrace_to_pcap_linktype(linktype)==TRACE_DLT_ERROR) {
[d5e1796]506                if (!demote_packet(packet)) {
507                        trace_set_err_out(libtrace, 
508                                TRACE_ERR_NO_CONVERSION,
509                                "pcap does not support this format");
510                        return -1;
511                }
[9bc4689]512
513                link = trace_get_packet_buffer(packet,&linktype,&remaining);
[d5e1796]514        }
515
[73dd29f]516
[1974620]517        if (!OUTPUT.trace.pcap) {
[73dd29f]518                int linktype=libtrace_to_pcap_dlt(trace_get_link_type(packet));
519                OUTPUT.trace.pcap = pcap_open_dead(linktype,65536);
[f875681]520                if (!OUTPUT.trace.pcap) {
[73dd29f]521                        trace_set_err_out(libtrace,TRACE_ERR_INIT_FAILED,
522                                        "Failed to open dead trace: %s\n",
[f875681]523                                        pcap_geterr(OUTPUT.trace.pcap));
524                }
[d5879cc]525                OUTPUT.trace.dump = pcap_dump_open(OUTPUT.trace.pcap,
526                                libtrace->uridata);
[f875681]527                if (!OUTPUT.trace.dump) {
528                        char *errmsg = pcap_geterr(OUTPUT.trace.pcap);
529                        trace_set_err_out(libtrace,TRACE_ERR_INIT_FAILED,"Failed to open output file: %s\n",
530                                        errmsg ? errmsg : "Unknown error");
531                        return -1;
532                }
[3073c04]533        }
[e373992]534
535        /* Corrupt packet, or other "non data" packet, so skip it */
[9bc4689]536        if (link == NULL) {
[e373992]537                /* Return "success", but nothing written */
538                return 0;
539        }
540
[238d50a]541        /* Check if the packet was captured using one of the PCAP formats */
[85a0d42]542        if (packet->trace->format == &pcap || 
543                        packet->trace->format == &pcapint) {
[238d50a]544                /* Yes - this means we can write it straight out */
[ed636fb4]545                pcap_dump((u_char*)OUTPUT.trace.dump,
546                                (struct pcap_pkthdr *)packet->header,
547                                packet->payload);
[3073c04]548        } else {
[238d50a]549                /* No - need to fill in a PCAP header with the appropriate
550                 * values */
551
[7068467]552                /* Leave the manual copy as it is, as it gets around
553                 * some OS's having different structures in pcap_pkt_hdr
554                 */
[41b53c2]555                struct timeval ts = trace_get_timeval(packet);
556                pcap_pkt_hdr.ts.tv_sec = ts.tv_sec;
557                pcap_pkt_hdr.ts.tv_usec = ts.tv_usec;
[9bc4689]558                pcap_pkt_hdr.caplen = remaining;
[ed636fb4]559                /* trace_get_wire_length includes FCS, while pcap doesn't */
560                if (trace_get_link_type(packet)==TRACE_TYPE_ETH)
[e373992]561                        if (trace_get_wire_length(packet) >= 4) { 
562                                pcap_pkt_hdr.len = 
563                                        trace_get_wire_length(packet)-4;
564                        }
565                        else {
566                                pcap_pkt_hdr.len = 0;
567                        }
[ed636fb4]568                else
569                        pcap_pkt_hdr.len = trace_get_wire_length(packet);
[3073c04]570
[85a0d42]571                assert(pcap_pkt_hdr.caplen<65536);
572                assert(pcap_pkt_hdr.len<65536);
573
[14d8a63]574                pcap_dump((u_char*)OUTPUT.trace.dump, &pcap_pkt_hdr, packet->payload);
[3073c04]575        }
576        return 0;
577}
578
[85a79b0]579static int pcapint_write_packet(libtrace_out_t *libtrace,
580                libtrace_packet_t *packet) 
581{
[e4e95499]582        int err;
583
[5f329ab]584        if (trace_get_link_type(packet) == TRACE_TYPE_NONDATA)
585                return 0;
586
[e4e95499]587        if (!OUTPUT.trace.pcap) {
588                OUTPUT.trace.pcap = (pcap_t *)pcap_open_live(
589                        libtrace->uridata,65536,0,0,NULL);
590        }
[e5c2bc4]591#ifdef HAVE_PCAP_INJECT
[e4e95499]592        err=pcap_inject(OUTPUT.trace.pcap,
593                        packet->payload,
594                        trace_get_capture_length(packet));
[7af689a]595        if (err!=(int)trace_get_capture_length(packet))
[e4e95499]596                err=-1;
597#else
[e5c2bc4]598#ifdef HAVE_PCAP_SENDPACKET
[e4e95499]599        err=pcap_sendpacket(OUTPUT.trace.pcap,
600                        packet->payload,
601                        trace_get_capture_length(packet));
[103cc3b]602#else
603    trace_set_err(packet->trace,TRACE_ERR_UNSUPPORTED,"writing is not supported on this platform");
604        return -1;
[e4e95499]605#endif
606#endif
607        return err;
608}
609
[eeab9832]610static libtrace_linktype_t pcap_get_link_type(const libtrace_packet_t *packet) {
[238d50a]611        /* PCAP doesn't store linktype in the framing header so we need
612         * RT to do it for us
[7ac9705]613         */
[73dd29f]614        int linktype = rt_to_pcap_linktype(packet->type);
615        return pcap_linktype_to_libtrace(linktype);
[4dedc28]616}
617
[431548c5]618static libtrace_direction_t pcap_set_direction(libtrace_packet_t *packet,
619                libtrace_direction_t dir) {
[a6c77b0]620
621        /* We only support tagging with IN or OUT return error for any others */
622        if(!(dir == TRACE_DIR_OUTGOING || dir == TRACE_DIR_INCOMING))
623                return -1;
624
[238d50a]625        /* PCAP doesn't have a direction field in the header, so we need to
626         * promote to Linux SLL to tag it properly */
[81f9b6e]627        libtrace_sll_header_t *sll;
628        promote_packet(packet);
629        sll=packet->payload;
[238d50a]630       
[cde66c3]631        /* sll->pkttype should be in the endianness of the host that the
[238d50a]632         * trace was taken on.  This is impossible to achieve so we assume
633         * host endianness
[cde66c3]634         */
[431548c5]635        if(dir==TRACE_DIR_OUTGOING)
[cde66c3]636                sll->pkttype=TRACE_SLL_OUTGOING;
[81f9b6e]637        else
[cde66c3]638                sll->pkttype=TRACE_SLL_HOST;
639        return dir;
[81f9b6e]640}
641
[431548c5]642static libtrace_direction_t pcap_get_direction(const libtrace_packet_t *packet) {
[e5f1431]643        libtrace_direction_t direction  = -1;
[4dedc28]644        switch(pcap_get_link_type(packet)) {
[238d50a]645                /* Only packets encapsulated in Linux SLL or PFLOG have any
646                 * direction information */
647
[4dedc28]648                case TRACE_TYPE_LINUX_SLL:
649                {
[67a14d4]650                        libtrace_sll_header_t *sll;
[9bc4689]651                        sll = trace_get_packet_buffer(packet, NULL, NULL);
652                        /* TODO: should check remaining>=sizeof(*sll) */
[4dedc28]653                        if (!sll) {
[0ea3526]654                                trace_set_err(packet->trace,
655                                        TRACE_ERR_BAD_PACKET,
[880aa58]656                                                "Bad or missing packet");
[4dedc28]657                                return -1;
658                        }
659                        /* 0 == LINUX_SLL_HOST */
660                        /* the Waikato Capture point defines "packets
661                         * originating locally" (ie, outbound), with a
662                         * direction of 0, and "packets destined locally"
663                         * (ie, inbound), with a direction of 1.
664                         * This is kind-of-opposite to LINUX_SLL.
665                         * We return consistent values here, however
666                         *
667                         * Note that in recent versions of pcap, you can
668                         * use "inbound" and "outbound" on ppp in linux
669                         */
[cde66c3]670                        if (sll->pkttype == TRACE_SLL_OUTGOING) {
[431548c5]671                                direction = TRACE_DIR_OUTGOING;
[cde66c3]672                        } else {
673                                direction = TRACE_DIR_INCOMING;
[4dedc28]674                        }
675                        break;
676
677                }
678                case TRACE_TYPE_PFLOG:
679                {
[67a14d4]680                        libtrace_pflog_header_t *pflog;
[9bc4689]681                        pflog = trace_get_packet_buffer(packet, NULL, NULL);
682                        /* TODO: should check remaining >= sizeof(*pflog) */
[4dedc28]683                        if (!pflog) {
[0ea3526]684                                trace_set_err(packet->trace,
685                                                TRACE_ERR_BAD_PACKET,
[880aa58]686                                                "Bad or missing packet");
[4dedc28]687                                return -1;
688                        }
689                        /* enum    { PF_IN=0, PF_OUT=1 }; */
690                        if (ntohs(pflog->dir==0)) {
691
[431548c5]692                                direction = TRACE_DIR_INCOMING;
[4dedc28]693                        }
694                        else {
[431548c5]695                                direction = TRACE_DIR_OUTGOING;
[4dedc28]696                        }
697                        break;
698                }
699                default:
700                        break;
701        }       
702        return direction;
703}
704
705
[e6d963c]706static struct timeval pcap_get_timeval(const libtrace_packet_t *packet) {
[14d8a63]707        struct pcap_pkthdr *pcapptr = (struct pcap_pkthdr *)packet->header;
[41b53c2]708        struct timeval ts;
709        ts.tv_sec = pcapptr->ts.tv_sec;
710        ts.tv_usec = pcapptr->ts.tv_usec;
711        return ts;
[4dedc28]712}
713
714
[d3b2234]715static int pcap_get_capture_length(const libtrace_packet_t *packet) {
[4dedc28]716        struct pcap_pkthdr *pcapptr = 0;
[14d8a63]717        pcapptr = (struct pcap_pkthdr *)packet->header;
[d8f02df]718        assert(pcapptr->caplen<=65536);
[ed636fb4]719
[4dedc28]720        return pcapptr->caplen;
721}
722
[d3b2234]723static int pcap_get_wire_length(const libtrace_packet_t *packet) {
[4dedc28]724        struct pcap_pkthdr *pcapptr = 0;
[14d8a63]725        pcapptr = (struct pcap_pkthdr *)packet->header;
[73dd29f]726        if (packet->type==pcap_linktype_to_rt(TRACE_DLT_EN10MB))
[ed636fb4]727                return pcapptr->len+4; /* Include the missing FCS */
[73dd29f]728        else if (packet->type==pcap_linktype_to_rt(TRACE_DLT_IEEE802_11_RADIO)) {
[9bc4689]729                libtrace_linktype_t linktype;
730                void *link = trace_get_packet_buffer(packet,&linktype,NULL);
[f0c639b]731                /* If the packet is Radiotap and the flags field indicates
732                 * that the FCS is not included in the 802.11 frame, then
733                 * we need to add 4 to the wire-length to account for it.
734                 */
[73dd29f]735                uint8_t flags;
[9bc4689]736                trace_get_wireless_flags(link, 
737                                linktype, &flags);
[f0c639b]738                if ((flags & TRACE_RADIOTAP_F_FCS) == 0)
739                        return pcapptr->len + 4;
740        }
741        return pcapptr->len;
[4dedc28]742}
743
[85a79b0]744static int pcap_get_framing_length(UNUSED const libtrace_packet_t *packet) {
[7c8eacf]745        return sizeof(struct pcap_pkthdr);
746}
747
[d3b2234]748static size_t pcap_set_capture_length(libtrace_packet_t *packet,size_t size) {
[4dedc28]749        struct pcap_pkthdr *pcapptr = 0;
750        assert(packet);
[d3b2234]751        if (size > trace_get_capture_length(packet)) {
[238d50a]752                /* Can't make a packet larger */
[d3b2234]753                return trace_get_capture_length(packet);
[4dedc28]754        }
[e632f2f]755        /* Reset the cached capture length */
756        packet->capture_length = -1;
[14d8a63]757        pcapptr = (struct pcap_pkthdr *)packet->header;
[194d49b]758        pcapptr->caplen = size;
[d3b2234]759        return trace_get_capture_length(packet);
[4dedc28]760}
761
[52f8fc2]762static int pcap_get_fd(const libtrace_t *trace) {
[7ac9705]763
764        assert(trace->format_data);
[ab4cb04]765        return pcap_fileno(DATA(trace)->input.pcap);
[72bfe20]766}
767
[5478d3d]768static void pcap_get_statistics(libtrace_t *trace, libtrace_stat_t *stat) {
769
770        struct pcap_stat pcapstats;
771        if (pcap_stats(DATA(trace)->input.pcap,&pcapstats)==-1) {
[50bbce8]772                char *errmsg = pcap_geterr(DATA(trace)->input.pcap);
773                trace_set_err(trace,TRACE_ERR_UNSUPPORTED,
[5478d3d]774                                "Failed to retrieve stats: %s\n",
[50bbce8]775                                errmsg ? errmsg : "Unknown pcap error");
[5478d3d]776                return;
[50bbce8]777        }
778
[631fdbc]779        stat->received_valid = 1;
780        stat->received = pcapstats.ps_recv;
[5478d3d]781        stat->dropped_valid = 1;
782        stat->dropped = pcapstats.ps_drop;
[50bbce8]783}
784
[33d83d4]785static void pcap_help(void) {
[c909fad]786        printf("pcap format module: $Revision: 1729 $\n");
[40ba6ad]787        printf("Supported input URIs:\n");
788        printf("\tpcap:/path/to/file\n");
789        printf("\n");
790        printf("\te.g.: pcap:/tmp/trace.pcap\n");
[7d69878]791        printf("\n");
[40ba6ad]792        printf("Supported output URIs:\n");
793        printf("\tnone\n");
[7d69878]794        printf("\n");
[dd22d84]795}
[7d69878]796
[33d83d4]797static void pcapint_help(void) {
[c909fad]798        printf("pcapint format module: $Revision: 1729 $\n");
[40ba6ad]799        printf("Supported input URIs:\n");
800        printf("\tpcapint:interface\n");
801        printf("\n");
802        printf("\te.g.: pcapint:eth0\n");
[7d69878]803        printf("\n");
[40ba6ad]804        printf("Supported output URIs:\n");
805        printf("\tnone\n");
[7d69878]806        printf("\n");
[dd22d84]807}
[9e2a109]808
809
810static struct libtrace_format_t pcap = {
[4dedc28]811        "pcap",
812        "$Id$",
[6dbc47a]813        TRACE_FORMAT_PCAP,
[91b72d3]814        NULL,                           /* probe filename */
815        NULL,                           /* probe magic */
[7050c10]816        pcap_init_input,                /* init_input */
[ab4cb04]817        pcap_config_input,              /* config_input */
[df338b3]818        pcap_start_input,               /* start_input */
[2e91590]819        pcap_pause_input,               /* pause_input */
[3073c04]820        pcap_init_output,               /* init_output */
[91ebc50]821        NULL,                           /* config_output */
[d5879cc]822        NULL,                           /* start_output */
[7050c10]823        pcap_fin_input,                 /* fin_input */
[3073c04]824        pcap_fin_output,                /* fin_output */
[7050c10]825        pcap_read_packet,               /* read_packet */
[f0fb38f]826        pcap_prepare_packet,            /* prepare_packet */
[eeab9832]827        NULL,                           /* fin_packet */
[3073c04]828        pcap_write_packet,              /* write_packet */
[7050c10]829        pcap_get_link_type,             /* get_link_type */
830        pcap_get_direction,             /* get_direction */
[81f9b6e]831        pcap_set_direction,             /* set_direction */
[7050c10]832        NULL,                           /* get_erf_timestamp */
833        pcap_get_timeval,               /* get_timeval */
834        NULL,                           /* get_seconds */
[1aa4bf7]835        NULL,                           /* get_timespec */
[1fbd938]836        NULL,                           /* seek_erf */
837        NULL,                           /* seek_timeval */
838        NULL,                           /* seek_seconds */
[7050c10]839        pcap_get_capture_length,        /* get_capture_length */
840        pcap_get_wire_length,           /* get_wire_length */
[7c8eacf]841        pcap_get_framing_length,        /* get_framing_length */
[dd22d84]842        pcap_set_capture_length,        /* set_capture_length */
[f2fae49]843        NULL,                           /* get_received_packets */
844        NULL,                           /* get_filtered_packets */
845        NULL,                           /* get_dropped_packets */
[5ab626a]846        NULL,                           /* get_statistics */
[72bfe20]847        NULL,                           /* get_fd */
848        trace_event_trace,              /* trace_event */
[eeab9832]849        pcap_help,                      /* help */
[b13b939]850        NULL,                   /* next pointer */
851        NON_PARALLEL(false)
[4dedc28]852};
853
[9e2a109]854static struct libtrace_format_t pcapint = {
[4dedc28]855        "pcapint",
856        "$Id$",
[6dbc47a]857        TRACE_FORMAT_PCAP,
[91b72d3]858        NULL,                           /* probe filename */
859        NULL,                           /* probe magic */
[7050c10]860        pcapint_init_input,             /* init_input */
[df338b3]861        pcapint_config_input,           /* config_input */
862        pcapint_start_input,            /* start_input */
[747c501]863        pcap_pause_input,               /* pause_input */
[e4e95499]864        pcapint_init_output,            /* init_output */
[91ebc50]865        NULL,                           /* config_output */
[37195b4]866        NULL,                           /* start_output */
[7050c10]867        pcap_fin_input,                 /* fin_input */
[e4e95499]868        pcapint_fin_output,             /* fin_output */
[7050c10]869        pcap_read_packet,               /* read_packet */
[f0fb38f]870        pcap_prepare_packet,            /* prepare_packet */
[eeab9832]871        NULL,                           /* fin_packet */
[e4e95499]872        pcapint_write_packet,           /* write_packet */
[7050c10]873        pcap_get_link_type,             /* get_link_type */
874        pcap_get_direction,             /* get_direction */
[81f9b6e]875        pcap_set_direction,             /* set_direction */
[7050c10]876        NULL,                           /* get_erf_timestamp */
877        pcap_get_timeval,               /* get_timeval */
878        NULL,                           /* get_seconds */
[1aa4bf7]879        NULL,                           /* get_timespec */
[1fbd938]880        NULL,                           /* seek_erf */
881        NULL,                           /* seek_timeval */
882        NULL,                           /* seek_seconds */
[7050c10]883        pcap_get_capture_length,        /* get_capture_length */
884        pcap_get_wire_length,           /* get_wire_length */
[7c8eacf]885        pcap_get_framing_length,        /* get_framing_length */
[dd22d84]886        pcap_set_capture_length,        /* set_capture_length */
[f2fae49]887        NULL,                           /* get_received_packets */
888        NULL,                           /* get_filtered_packets */
[5478d3d]889        NULL,                           /* get_dropped_packets */
890        pcap_get_statistics,            /* get_statistics */
[72bfe20]891        pcap_get_fd,                    /* get_fd */
[187a6d6]892        trace_event_device,             /* trace_event */
[eeab9832]893        pcapint_help,                   /* help */
[b13b939]894        NULL,                   /* next pointer */
895        NON_PARALLEL(true)
[4dedc28]896};
897
[33d83d4]898void pcap_constructor(void) {
[7c8eacf]899        register_format(&pcap);
900        register_format(&pcapint);
[4dedc28]901}
[91ebc50]902
903
904#endif
Note: See TracBrowser for help on using the repository browser.