source: lib/format_pcap.c @ 5ab626a

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivelibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 5ab626a was 5ab626a, checked in by Richard Sanger <rsangerarj@…>, 6 years ago

Deprecate trace_get_filtered/accepted/recevied/dropped() in favour of a single function

Adds the single trace_get_statistics function. This allows the structure to be filled
at a point in time, rather than making multiple calls to the library during which state
might have changed.

This has been designed such that the structure can be added to in the future without
breaking old code.

The old internal get_captured_packets was removed from the formats as it was never used.
Eventually we should completely remove get_filtered and received from the formats and replace
them with get_statistics.

In additon some extra fields have added, such as error and captured and the pre-existing
fields are better defined.

The linux formats have been updated to use this new API, which combined with reading
/proc/net/dev returns a full set of statistics.

  • Property mode set to 100644
File size: 24.5 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007,2008,2009,2010 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        if ((ret = pcap_activate(INPUT.pcap)) != 0) {
271                if (ret == PCAP_WARNING_PROMISC_NOTSUP) {
272                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,"Promiscuous mode unsupported");
273                        return -1;
274                }
275                if (ret == PCAP_WARNING) {
276                        pcap_perror(INPUT.pcap, "Pcap Warning:");
277                } else {
278                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",
279                                        pcap_geterr(INPUT.pcap));
280                        return -1;
281                }
282        }
283                         
284#else   
285
286        /* Open the live device */
287        if ((INPUT.pcap = 
288                        pcap_open_live(libtrace->uridata,
289                        DATA(libtrace)->snaplen,
290                        DATA(libtrace)->promisc,
291                        1,
292                        errbuf)) == NULL) {
293                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",errbuf);
294                return -1; /* failure */
295        }
296#endif
297#ifdef HAVE_PCAP_SETNONBLOCK
298        pcap_setnonblock(INPUT.pcap,0,errbuf);
299#endif
300        /* Set a filter if one is defined */
301        if (DATA(libtrace)->filter) {
302                struct pcap_pkthdr *pcap_hdr = NULL;
303                u_char *pcap_payload = NULL;
304                int pcapret;
305               
306                if (DATA(libtrace)->filter->flag == 0) {
307                        pcap_compile(INPUT.pcap, 
308                                        &DATA(libtrace)->filter->filter,
309                                        DATA(libtrace)->filter->filterstring, 
310                                        1, 0);
311                        DATA(libtrace)->filter->flag = 1;
312                }
313                if (pcap_setfilter(INPUT.pcap,&DATA(libtrace)->filter->filter)
314                        == -1) {
315                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",
316                                        pcap_geterr(INPUT.pcap));
317                        return -1; /* failure */
318                }
319
320                /* Consume the first packet in the queue, as this may not
321                 * have had the filter applied to it.
322                 *
323                 * Otherwise we can get problems with the event API, where
324                 * select tells us that there is a packet available but
325                 * calling trace_read_packet will block forever because the
326                 * packet in the queue didn't match the filter so
327                 * pcap_next_ex returns "timed out".
328                 *
329                 * This does mean we may consume a legitimate packet, but
330                 * that's a pretty small downside compared with trace_event
331                 * getting stuck in an infinite loop because of pcap
332                 * wackiness.
333                 *
334                 * For some reason, we only need to consume one packet for
335                 * this to work, so let's hope that holds in the future.
336                 */
337                do {
338                        pcapret = pcap_next_ex(INPUT.pcap, &pcap_hdr, 
339                                (const u_char **)&pcap_payload);
340                } while (0);
341
342                if (pcapret < 0)
343                        return -1;
344        }
345        return 0; /* success */
346}
347
348static int pcap_pause_input(libtrace_t *libtrace)
349{
350        pcap_close(INPUT.pcap);
351        INPUT.pcap=NULL;
352        return 0; /* success */
353}
354
355
356static int pcap_fin_input(libtrace_t *libtrace) 
357{
358        free(libtrace->format_data);
359        return 0; /* success */
360}
361
362static int pcap_fin_output(libtrace_out_t *libtrace) 
363{
364        if (OUTPUT.trace.dump) {
365                pcap_dump_flush(OUTPUT.trace.dump);
366                pcap_dump_close(OUTPUT.trace.dump);
367        }
368        pcap_close(OUTPUT.trace.pcap);
369        free(libtrace->format_data);
370        return 0;
371}
372
373static int pcapint_fin_output(libtrace_out_t *libtrace)
374{
375        pcap_close(OUTPUT.trace.pcap);
376        free(libtrace->format_data);
377        return 0;
378}
379
380static int pcap_prepare_packet(libtrace_t *libtrace, libtrace_packet_t *packet,
381                void *buffer, libtrace_rt_types_t rt_type, uint32_t flags) {
382       
383        if (packet->buffer != buffer &&
384                        packet->buf_control == TRACE_CTRL_PACKET) {
385                        free(packet->buffer);
386        }
387
388        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
389                packet->buf_control = TRACE_CTRL_PACKET;
390        } else
391                packet->buf_control = TRACE_CTRL_EXTERNAL;
392       
393       
394        packet->buffer = buffer;
395        packet->header = buffer;
396        packet->type = rt_type;
397
398        /* Assuming header and payload are sequential in the buffer -
399         * regular pcap often doesn't work like this though, so hopefully
400         * we're not called by something that is reading genuine pcap! */
401        packet->payload = (char *)packet->header + sizeof(struct pcap_pkthdr);
402
403        if (libtrace->format_data == NULL) {
404                if (pcap_init_input(libtrace))
405                        return -1;
406        }
407        return 0;
408}
409
410static int pcap_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
411        int ret = 0;
412        int linktype;
413        uint32_t flags = 0;
414       
415        assert(libtrace->format_data);
416        linktype = pcap_datalink(DATA(libtrace)->input.pcap);
417        packet->type = pcap_linktype_to_rt(linktype);
418
419        /* If we're using the replacement pcap_next_ex() we need to
420         * make sure we have a buffer to *shudder* memcpy into
421         */
422        if (!packet->buffer) {
423                packet->buffer = malloc(LIBTRACE_PACKET_BUFSIZE);
424                if (!packet->buffer) {
425                        trace_set_err(libtrace, errno, 
426                                        "Cannot allocate memory");
427                        return -1;
428                }
429                packet->header = packet->buffer;
430                packet->payload = (char *)packet->buffer+sizeof(struct pcap_pkthdr);
431                       
432        }
433
434        flags |= TRACE_PREP_OWN_BUFFER;
435       
436        for(;;) {
437               
438                struct pcap_pkthdr *pcap_hdr = NULL;
439                u_char *pcap_payload = NULL;
440
441                ret = pcap_next_ex(INPUT.pcap, &pcap_hdr, 
442                                (const u_char **)&pcap_payload);
443               
444                packet->header = pcap_hdr;
445                packet->payload = pcap_payload;
446
447                switch(ret) {
448                        case 1: break; /* no error */
449                        case 0:
450                                if (libtrace_halt)
451                                        return 0;
452                                continue; /* timeout expired */
453                        case -1:
454                                trace_set_err(libtrace,TRACE_ERR_BAD_PACKET,
455                                                "%s",pcap_geterr(INPUT.pcap));
456                                return -1; /* Error */
457                        case -2:
458                                return 0; /* EOF */
459                }
460
461                /*
462                 * pcap is nasty in that the header and payload aren't
463                 * necessarily located sequentially in memory, but most
464                 * sensible uses of pcap_prepare_packet will involve a
465                 * buffer where header and payload are sequential.
466                 *
467                 * Basically, don't call pcap_prepare_packet here!
468                 *
469                if (pcap_prepare_packet(libtrace, packet, packet->buffer,
470                                packet->type, flags)) {
471                        return -1;
472                }
473                */
474                return ((struct pcap_pkthdr*)packet->header)->len
475                        +sizeof(struct pcap_pkthdr);
476        }
477}
478
479static int pcap_write_packet(libtrace_out_t *libtrace, 
480                libtrace_packet_t *packet) 
481{
482        struct pcap_pkthdr pcap_pkt_hdr;
483        void *link;
484        libtrace_linktype_t linktype;
485        uint32_t remaining;
486
487        link = trace_get_packet_buffer(packet,&linktype,&remaining);
488
489        /* We may have to convert this packet into a suitable PCAP packet */
490
491        /* If this packet cannot be converted to a pcap linktype then
492         * pop off the top header until it can be converted
493         */
494        while (libtrace_to_pcap_linktype(linktype)==TRACE_DLT_ERROR) {
495                if (!demote_packet(packet)) {
496                        trace_set_err_out(libtrace, 
497                                TRACE_ERR_NO_CONVERSION,
498                                "pcap does not support this format");
499                        return -1;
500                }
501
502                link = trace_get_packet_buffer(packet,&linktype,&remaining);
503        }
504
505
506        if (!OUTPUT.trace.pcap) {
507                int linktype=libtrace_to_pcap_dlt(trace_get_link_type(packet));
508                OUTPUT.trace.pcap = pcap_open_dead(linktype,65536);
509                if (!OUTPUT.trace.pcap) {
510                        trace_set_err_out(libtrace,TRACE_ERR_INIT_FAILED,
511                                        "Failed to open dead trace: %s\n",
512                                        pcap_geterr(OUTPUT.trace.pcap));
513                }
514                OUTPUT.trace.dump = pcap_dump_open(OUTPUT.trace.pcap,
515                                libtrace->uridata);
516                if (!OUTPUT.trace.dump) {
517                        char *errmsg = pcap_geterr(OUTPUT.trace.pcap);
518                        trace_set_err_out(libtrace,TRACE_ERR_INIT_FAILED,"Failed to open output file: %s\n",
519                                        errmsg ? errmsg : "Unknown error");
520                        return -1;
521                }
522        }
523
524        /* Corrupt packet, or other "non data" packet, so skip it */
525        if (link == NULL) {
526                /* Return "success", but nothing written */
527                return 0;
528        }
529
530        /* Check if the packet was captured using one of the PCAP formats */
531        if (packet->trace->format == &pcap || 
532                        packet->trace->format == &pcapint) {
533                /* Yes - this means we can write it straight out */
534                pcap_dump((u_char*)OUTPUT.trace.dump,
535                                (struct pcap_pkthdr *)packet->header,
536                                packet->payload);
537        } else {
538                /* No - need to fill in a PCAP header with the appropriate
539                 * values */
540
541                /* Leave the manual copy as it is, as it gets around
542                 * some OS's having different structures in pcap_pkt_hdr
543                 */
544                struct timeval ts = trace_get_timeval(packet);
545                pcap_pkt_hdr.ts.tv_sec = ts.tv_sec;
546                pcap_pkt_hdr.ts.tv_usec = ts.tv_usec;
547                pcap_pkt_hdr.caplen = remaining;
548                /* trace_get_wire_length includes FCS, while pcap doesn't */
549                if (trace_get_link_type(packet)==TRACE_TYPE_ETH)
550                        if (trace_get_wire_length(packet) >= 4) { 
551                                pcap_pkt_hdr.len = 
552                                        trace_get_wire_length(packet)-4;
553                        }
554                        else {
555                                pcap_pkt_hdr.len = 0;
556                        }
557                else
558                        pcap_pkt_hdr.len = trace_get_wire_length(packet);
559
560                assert(pcap_pkt_hdr.caplen<65536);
561                assert(pcap_pkt_hdr.len<65536);
562
563                pcap_dump((u_char*)OUTPUT.trace.dump, &pcap_pkt_hdr, packet->payload);
564        }
565        return 0;
566}
567
568static int pcapint_write_packet(libtrace_out_t *libtrace,
569                libtrace_packet_t *packet) 
570{
571        int err;
572
573        if (trace_get_link_type(packet) == TRACE_TYPE_NONDATA)
574                return 0;
575
576        if (!OUTPUT.trace.pcap) {
577                OUTPUT.trace.pcap = (pcap_t *)pcap_open_live(
578                        libtrace->uridata,65536,0,0,NULL);
579        }
580#ifdef HAVE_PCAP_INJECT
581        err=pcap_inject(OUTPUT.trace.pcap,
582                        packet->payload,
583                        trace_get_capture_length(packet));
584        if (err!=(int)trace_get_capture_length(packet))
585                err=-1;
586#else
587#ifdef HAVE_PCAP_SENDPACKET
588        err=pcap_sendpacket(OUTPUT.trace.pcap,
589                        packet->payload,
590                        trace_get_capture_length(packet));
591#else
592    trace_set_err(packet->trace,TRACE_ERR_UNSUPPORTED,"writing is not supported on this platform");
593        return -1;
594#endif
595#endif
596        return err;
597}
598
599static libtrace_linktype_t pcap_get_link_type(const libtrace_packet_t *packet) {
600        /* PCAP doesn't store linktype in the framing header so we need
601         * RT to do it for us
602         */
603        int linktype = rt_to_pcap_linktype(packet->type);
604        return pcap_linktype_to_libtrace(linktype);
605}
606
607static libtrace_direction_t pcap_set_direction(libtrace_packet_t *packet,
608                libtrace_direction_t dir) {
609
610        /* We only support tagging with IN or OUT return error for any others */
611        if(!(dir == TRACE_DIR_OUTGOING || dir == TRACE_DIR_INCOMING))
612                return -1;
613
614        /* PCAP doesn't have a direction field in the header, so we need to
615         * promote to Linux SLL to tag it properly */
616        libtrace_sll_header_t *sll;
617        promote_packet(packet);
618        sll=packet->payload;
619       
620        /* sll->pkttype should be in the endianness of the host that the
621         * trace was taken on.  This is impossible to achieve so we assume
622         * host endianness
623         */
624        if(dir==TRACE_DIR_OUTGOING)
625                sll->pkttype=TRACE_SLL_OUTGOING;
626        else
627                sll->pkttype=TRACE_SLL_HOST;
628        return dir;
629}
630
631static libtrace_direction_t pcap_get_direction(const libtrace_packet_t *packet) {
632        libtrace_direction_t direction  = -1;
633        switch(pcap_get_link_type(packet)) {
634                /* Only packets encapsulated in Linux SLL or PFLOG have any
635                 * direction information */
636
637                case TRACE_TYPE_LINUX_SLL:
638                {
639                        libtrace_sll_header_t *sll;
640                        sll = trace_get_packet_buffer(packet, NULL, NULL);
641                        /* TODO: should check remaining>=sizeof(*sll) */
642                        if (!sll) {
643                                trace_set_err(packet->trace,
644                                        TRACE_ERR_BAD_PACKET,
645                                                "Bad or missing packet");
646                                return -1;
647                        }
648                        /* 0 == LINUX_SLL_HOST */
649                        /* the Waikato Capture point defines "packets
650                         * originating locally" (ie, outbound), with a
651                         * direction of 0, and "packets destined locally"
652                         * (ie, inbound), with a direction of 1.
653                         * This is kind-of-opposite to LINUX_SLL.
654                         * We return consistent values here, however
655                         *
656                         * Note that in recent versions of pcap, you can
657                         * use "inbound" and "outbound" on ppp in linux
658                         */
659                        if (sll->pkttype == TRACE_SLL_OUTGOING) {
660                                direction = TRACE_DIR_OUTGOING;
661                        } else {
662                                direction = TRACE_DIR_INCOMING;
663                        }
664                        break;
665
666                }
667                case TRACE_TYPE_PFLOG:
668                {
669                        libtrace_pflog_header_t *pflog;
670                        pflog = trace_get_packet_buffer(packet, NULL, NULL);
671                        /* TODO: should check remaining >= sizeof(*pflog) */
672                        if (!pflog) {
673                                trace_set_err(packet->trace,
674                                                TRACE_ERR_BAD_PACKET,
675                                                "Bad or missing packet");
676                                return -1;
677                        }
678                        /* enum    { PF_IN=0, PF_OUT=1 }; */
679                        if (ntohs(pflog->dir==0)) {
680
681                                direction = TRACE_DIR_INCOMING;
682                        }
683                        else {
684                                direction = TRACE_DIR_OUTGOING;
685                        }
686                        break;
687                }
688                default:
689                        break;
690        }       
691        return direction;
692}
693
694
695static struct timeval pcap_get_timeval(const libtrace_packet_t *packet) {
696        struct pcap_pkthdr *pcapptr = (struct pcap_pkthdr *)packet->header;
697        struct timeval ts;
698        ts.tv_sec = pcapptr->ts.tv_sec;
699        ts.tv_usec = pcapptr->ts.tv_usec;
700        return ts;
701}
702
703
704static int pcap_get_capture_length(const libtrace_packet_t *packet) {
705        struct pcap_pkthdr *pcapptr = 0;
706        pcapptr = (struct pcap_pkthdr *)packet->header;
707        assert(pcapptr->caplen<=65536);
708
709        return pcapptr->caplen;
710}
711
712static int pcap_get_wire_length(const libtrace_packet_t *packet) {
713        struct pcap_pkthdr *pcapptr = 0;
714        pcapptr = (struct pcap_pkthdr *)packet->header;
715        if (packet->type==pcap_linktype_to_rt(TRACE_DLT_EN10MB))
716                return pcapptr->len+4; /* Include the missing FCS */
717        else if (packet->type==pcap_linktype_to_rt(TRACE_DLT_IEEE802_11_RADIO)) {
718                libtrace_linktype_t linktype;
719                void *link = trace_get_packet_buffer(packet,&linktype,NULL);
720                /* If the packet is Radiotap and the flags field indicates
721                 * that the FCS is not included in the 802.11 frame, then
722                 * we need to add 4 to the wire-length to account for it.
723                 */
724                uint8_t flags;
725                trace_get_wireless_flags(link, 
726                                linktype, &flags);
727                if ((flags & TRACE_RADIOTAP_F_FCS) == 0)
728                        return pcapptr->len + 4;
729        }
730        return pcapptr->len;
731}
732
733static int pcap_get_framing_length(UNUSED const libtrace_packet_t *packet) {
734        return sizeof(struct pcap_pkthdr);
735}
736
737static size_t pcap_set_capture_length(libtrace_packet_t *packet,size_t size) {
738        struct pcap_pkthdr *pcapptr = 0;
739        assert(packet);
740        if (size > trace_get_capture_length(packet)) {
741                /* Can't make a packet larger */
742                return trace_get_capture_length(packet);
743        }
744        /* Reset the cached capture length */
745        packet->capture_length = -1;
746        pcapptr = (struct pcap_pkthdr *)packet->header;
747        pcapptr->caplen = size;
748        return trace_get_capture_length(packet);
749}
750
751static int pcap_get_fd(const libtrace_t *trace) {
752
753        assert(trace->format_data);
754        return pcap_fileno(DATA(trace)->input.pcap);
755}
756
757static uint64_t pcap_get_dropped_packets(libtrace_t *trace)
758{
759        struct pcap_stat stats;
760        if (pcap_stats(DATA(trace)->input.pcap,&stats)==-1) {
761                char *errmsg = pcap_geterr(DATA(trace)->input.pcap);
762                trace_set_err(trace,TRACE_ERR_UNSUPPORTED,
763                                "Failed to retreive stats: %s\n",
764                                errmsg ? errmsg : "Unknown pcap error");
765                return ~0;
766        }
767
768        return stats.ps_drop;
769}
770
771static void pcap_help(void) {
772        printf("pcap format module: $Revision: 1729 $\n");
773        printf("Supported input URIs:\n");
774        printf("\tpcap:/path/to/file\n");
775        printf("\n");
776        printf("\te.g.: pcap:/tmp/trace.pcap\n");
777        printf("\n");
778        printf("Supported output URIs:\n");
779        printf("\tnone\n");
780        printf("\n");
781}
782
783static void pcapint_help(void) {
784        printf("pcapint format module: $Revision: 1729 $\n");
785        printf("Supported input URIs:\n");
786        printf("\tpcapint:interface\n");
787        printf("\n");
788        printf("\te.g.: pcapint:eth0\n");
789        printf("\n");
790        printf("Supported output URIs:\n");
791        printf("\tnone\n");
792        printf("\n");
793}
794
795
796static struct libtrace_format_t pcap = {
797        "pcap",
798        "$Id$",
799        TRACE_FORMAT_PCAP,
800        NULL,                           /* probe filename */
801        NULL,                           /* probe magic */
802        pcap_init_input,                /* init_input */
803        pcap_config_input,              /* config_input */
804        pcap_start_input,               /* start_input */
805        NULL,                           /* pause_input */
806        pcap_init_output,               /* init_output */
807        NULL,                           /* config_output */
808        NULL,                           /* start_output */
809        pcap_fin_input,                 /* fin_input */
810        pcap_fin_output,                /* fin_output */
811        pcap_read_packet,               /* read_packet */
812        pcap_prepare_packet,            /* prepare_packet */
813        NULL,                           /* fin_packet */
814        pcap_write_packet,              /* write_packet */
815        pcap_get_link_type,             /* get_link_type */
816        pcap_get_direction,             /* get_direction */
817        pcap_set_direction,             /* set_direction */
818        NULL,                           /* get_erf_timestamp */
819        pcap_get_timeval,               /* get_timeval */
820        NULL,                           /* get_seconds */
821        NULL,                           /* get_timespec */
822        NULL,                           /* seek_erf */
823        NULL,                           /* seek_timeval */
824        NULL,                           /* seek_seconds */
825        pcap_get_capture_length,        /* get_capture_length */
826        pcap_get_wire_length,           /* get_wire_length */
827        pcap_get_framing_length,        /* get_framing_length */
828        pcap_set_capture_length,        /* set_capture_length */
829        NULL,                           /* get_received_packets */
830        NULL,                           /* get_filtered_packets */
831        NULL,                           /* get_dropped_packets */
832        NULL,                           /* get_statistics */
833        NULL,                           /* get_fd */
834        trace_event_trace,              /* trace_event */
835        pcap_help,                      /* help */
836        NULL,                   /* next pointer */
837        NON_PARALLEL(false)
838};
839
840static struct libtrace_format_t pcapint = {
841        "pcapint",
842        "$Id$",
843        TRACE_FORMAT_PCAP,
844        NULL,                           /* probe filename */
845        NULL,                           /* probe magic */
846        pcapint_init_input,             /* init_input */
847        pcapint_config_input,           /* config_input */
848        pcapint_start_input,            /* start_input */
849        pcap_pause_input,               /* pause_input */
850        pcapint_init_output,            /* init_output */
851        NULL,                           /* config_output */
852        NULL,                           /* start_output */
853        pcap_fin_input,                 /* fin_input */
854        pcapint_fin_output,             /* fin_output */
855        pcap_read_packet,               /* read_packet */
856        pcap_prepare_packet,            /* prepare_packet */
857        NULL,                           /* fin_packet */
858        pcapint_write_packet,           /* write_packet */
859        pcap_get_link_type,             /* get_link_type */
860        pcap_get_direction,             /* get_direction */
861        pcap_set_direction,             /* set_direction */
862        NULL,                           /* get_erf_timestamp */
863        pcap_get_timeval,               /* get_timeval */
864        NULL,                           /* get_seconds */
865        NULL,                           /* get_timespec */
866        NULL,                           /* seek_erf */
867        NULL,                           /* seek_timeval */
868        NULL,                           /* seek_seconds */
869        pcap_get_capture_length,        /* get_capture_length */
870        pcap_get_wire_length,           /* get_wire_length */
871        pcap_get_framing_length,        /* get_framing_length */
872        pcap_set_capture_length,        /* set_capture_length */
873        NULL,                           /* get_received_packets */
874        NULL,                           /* get_filtered_packets */
875        pcap_get_dropped_packets,       /* get_dropped_packets */
876        NULL,                           /* get_statistics */
877        pcap_get_fd,                    /* get_fd */
878        trace_event_device,             /* trace_event */
879        pcapint_help,                   /* help */
880        NULL,                   /* next pointer */
881        NON_PARALLEL(true)
882};
883
884void pcap_constructor(void) {
885        register_format(&pcap);
886        register_format(&pcapint);
887}
888
889
890#endif
Note: See TracBrowser for help on using the repository browser.