source: lib/format_pcap.c @ d439067

develop
Last change on this file since d439067 was d439067, checked in by Shane Alcock <salcock@…>, 23 months ago

Move packet cached fields into a distinct structure.

This will help tidy up the packet structure a little, as well as
simplify the cache clearing process (and maybe even speed it up
a little).

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