source: lib/format_pcap.c @ 9a6bdbc

develop
Last change on this file since 9a6bdbc was 9a6bdbc, checked in by Jacob Van Walraven <jcv9@…>, 22 months ago

Added can_write functions to each output format, Fixed pcapng_get_header_type incorrectly flipping type bytes

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