source: lib/format_pcap.c @ 2725318

develop
Last change on this file since 2725318 was 2725318, checked in by Jacob Van Walraven <jcv9@…>, 2 years ago

Cleanup some of the assertions

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