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