source: lib/format_pcap.c @ f6f3ae5

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

Assertion cleanup

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