source: lib/format_pcap.c @ 89e2ff7

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivendag_formatrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 89e2ff7 was 631fdbc, checked in by GitHub <noreply@…>, 4 years ago

received statistics support for pcap type.

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