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_pcapfile.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 #include <fcntl.h>
47 #include <stdbool.h>
48 
49 /* This format module implements our own, more efficient, version of the PCAP
50  * file format. This should always be used in preference to the "pcap" format
51  * provided in format_pcap.c.
52  *
53  * This is a trace file format and does not implement any live interface
54  * capture. This is covered by "pcapint" in format_pcap.c.
55  *
56  * This format supports both reading and writing, regardless of the version
57  * of your PCAP library.
58  */
59 
60 #define DATA(x) ((struct pcapfile_format_data_t*)((x)->format_data))
61 #define DATAOUT(x) ((struct pcapfile_format_data_out_t*)((x)->format_data))
62 #define IN_OPTIONS DATA(libtrace)->options
63 
64 typedef struct pcapfile_header_t {
65 		uint32_t magic_number;   /* magic number */
66 		uint16_t version_major;  /* major version number */
67 		uint16_t version_minor;  /* minor version number */
68 		int32_t  thiszone;       /* GMT to local correction */
69 		uint32_t sigfigs;        /* timestamp accuracy */
70 		uint32_t snaplen;        /* aka "wirelen" */
71 		uint32_t network;        /* data link type */
72 } pcapfile_header_t;
73 
74 #define MAGIC1      0xa1b2c3d4  /* Original */
75 #define MAGIC2      0xa1b23c4d  /* Newer nanosecond format */
76 #define MAGIC1_REV  0xd4c3b2a1  /* Reversed byteorder detection */
77 #define MAGIC2_REV  0x4d3cb2a1
78 
header_is_backwards_magic(pcapfile_header_t * header)79 static inline int header_is_backwards_magic(pcapfile_header_t *header) {
80 	return (header->magic_number == MAGIC1_REV || header->magic_number == MAGIC2_REV);
81 }
82 
header_is_magic(pcapfile_header_t * header)83 static inline int header_is_magic(pcapfile_header_t *header) {
84 	return (header->magic_number == MAGIC1 || header->magic_number == MAGIC2 ||
85 	        header_is_backwards_magic(header));
86 }
87 
trace_in_nanoseconds(pcapfile_header_t * header)88 static inline int trace_in_nanoseconds(pcapfile_header_t *header) {
89 	return (header->magic_number == MAGIC2 || header->magic_number == MAGIC2_REV);
90 }
91 
92 struct pcapfile_format_data_t {
93 	struct {
94 		/* Indicates whether the event API should replicate the pauses
95 		 * between packets */
96 		int real_time;
97 	} options;
98 
99 	/* The PCAP meta-header that should be written at the start of each
100 	 * trace */
101 	pcapfile_header_t header;
102 	/* Indicates whether the input trace is started */
103 	bool started;
104 };
105 
106 struct pcapfile_format_data_out_t {
107 	iow_t *file;
108 	int compress_type;
109 	int level;
110 	int flag;
111 
112 };
113 
pcapfile_probe_magic(io_t * io)114 static int pcapfile_probe_magic(io_t *io)
115 {
116 	pcapfile_header_t header;
117 	int len;
118 	len = wandio_peek(io, &header, sizeof(header));
119 
120 	/* Is this long enough? */
121 	if (len < (int)sizeof(header)) {
122 		return 0;
123 	}
124 	/* Pcap magic? */
125 	if (header_is_magic(&header)) {
126 		return 1;
127 	}
128 	/* Nope, not pcap */
129 	return 0;
130 }
131 
132 
pcapfile_init_input(libtrace_t * libtrace)133 static int pcapfile_init_input(libtrace_t *libtrace) {
134 	libtrace->format_data = malloc(sizeof(struct pcapfile_format_data_t));
135 
136 	if (libtrace->format_data == NULL) {
137 		trace_set_err(libtrace,ENOMEM,"Out of memory");
138 		return -1;
139 	}
140 
141 	IN_OPTIONS.real_time = 0;
142 	DATA(libtrace)->started = false;
143 	return 0;
144 }
145 
pcapfile_init_output(libtrace_out_t * libtrace)146 static int pcapfile_init_output(libtrace_out_t *libtrace) {
147 	libtrace->format_data =
148 		malloc(sizeof(struct pcapfile_format_data_out_t));
149 
150 	DATAOUT(libtrace)->file=NULL;
151 	DATAOUT(libtrace)->compress_type=TRACE_OPTION_COMPRESSTYPE_NONE;
152 	DATAOUT(libtrace)->level=0;
153 	DATAOUT(libtrace)->flag=O_CREAT|O_WRONLY;
154 
155 	return 0;
156 }
157 
158 
swaps(libtrace_t * libtrace,uint16_t num)159 static inline uint16_t swaps(libtrace_t *libtrace, uint16_t num)
160 {
161 	/* To deal with open_dead traces that might try and use this
162 	 * if we don't have any per trace data, assume host byte order
163 	 */
164 	if (!DATA(libtrace))
165 		return num;
166 
167 	/* We can use the PCAP magic number to determine the byte order */
168 	if (header_is_backwards_magic(&(DATA(libtrace)->header)))
169 		return byteswap16(num);
170 
171 	return num;
172 }
173 
swapl(libtrace_t * libtrace,uint32_t num)174 static inline uint32_t swapl(libtrace_t *libtrace, uint32_t num)
175 {
176 	/* To deal with open_dead traces that might try and use this
177 	 * if we don't have any per trace data, assume host byte order
178 	 */
179 	if (!DATA(libtrace))
180 		return num;
181 
182 	/* We can use the PCAP magic number to determine the byte order */
183 	if (header_is_backwards_magic(&(DATA(libtrace)->header)))
184 		return byteswap32(num);
185 
186 	return num;
187 }
188 
189 
pcapfile_start_input(libtrace_t * libtrace)190 static int pcapfile_start_input(libtrace_t *libtrace)
191 {
192 	int err;
193 
194 	if (!libtrace->io) {
195 		libtrace->io=trace_open_file(libtrace);
196 		DATA(libtrace)->started=false;
197 	}
198 
199 	if (!DATA(libtrace)->started) {
200 
201 		if (!libtrace->io)
202 			return -1;
203 
204 		err=wandio_read(libtrace->io,
205 				&DATA(libtrace)->header,
206 				sizeof(DATA(libtrace)->header));
207 
208 		DATA(libtrace)->started = true;
209 		assert(sizeof(DATA(libtrace)->header) > 0);
210 
211 		if (err<1) {
212 			if (err == 0) {
213 				trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
214 						"Reading pcap file header\n");
215 			}
216 			return -1;
217 		}
218 
219 		if (!header_is_magic(&(DATA(libtrace)->header))) {
220 			trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,
221 					"Not a pcap tracefile (magic=%08x)\n",swapl(libtrace,DATA(libtrace)->header.magic_number));
222 			return -1; /* Not a pcap file */
223 		}
224 
225 		if (swaps(libtrace,DATA(libtrace)->header.version_major)!=2
226 			&& swaps(libtrace,DATA(libtrace)->header.version_minor)!=4) {
227 			trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,
228 					"Unknown pcap tracefile version %d.%d\n",
229 					swaps(libtrace,
230 						DATA(libtrace)->header.version_major),
231 					swaps(libtrace,
232 						DATA(libtrace)->header.version_minor));
233 			return -1;
234 		}
235 
236 	}
237 
238 	return 0;
239 }
240 
pcapfile_start_output(libtrace_out_t * libtrace UNUSED)241 static int pcapfile_start_output(libtrace_out_t *libtrace UNUSED)
242 {
243 	/* We can't open the output file until we've seen the first packet.
244 	 * This is because we need to know the DLT to set the "network"
245 	 * value in the meta-header */
246 
247 	return 0;
248 }
249 
pcapfile_config_input(libtrace_t * libtrace,trace_option_t option,void * data)250 static int pcapfile_config_input(libtrace_t *libtrace,
251 		trace_option_t option,
252 		void *data)
253 {
254 	switch(option) {
255 		case TRACE_OPTION_EVENT_REALTIME:
256 			IN_OPTIONS.real_time = *(int *)data;
257 			return 0;
258 		case TRACE_OPTION_META_FREQ:
259 		case TRACE_OPTION_SNAPLEN:
260 		case TRACE_OPTION_PROMISC:
261 		case TRACE_OPTION_FILTER:
262 			/* All these are either unsupported or handled
263 			 * by trace_config */
264 			break;
265 	}
266 
267 	trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION,
268 			"Unknown option %i", option);
269 	return -1;
270 }
271 
pcapfile_fin_input(libtrace_t * libtrace)272 static int pcapfile_fin_input(libtrace_t *libtrace)
273 {
274 	if (libtrace->io)
275 		wandio_destroy(libtrace->io);
276 	free(libtrace->format_data);
277 	return 0; /* success */
278 }
279 
pcapfile_fin_output(libtrace_out_t * libtrace)280 static int pcapfile_fin_output(libtrace_out_t *libtrace)
281 {
282 	if (DATAOUT(libtrace)->file)
283 		wandio_wdestroy(DATAOUT(libtrace)->file);
284 	free(libtrace->format_data);
285 	libtrace->format_data=NULL;
286 	return 0; /* success */
287 }
288 
pcapfile_config_output(libtrace_out_t * libtrace,trace_option_output_t option,void * value)289 static int pcapfile_config_output(libtrace_out_t *libtrace,
290 		trace_option_output_t option,
291 		void *value)
292 {
293 	switch (option) {
294 		case TRACE_OPTION_OUTPUT_COMPRESS:
295 			DATAOUT(libtrace)->level = *(int*)value;
296 			return 0;
297 		case TRACE_OPTION_OUTPUT_COMPRESSTYPE:
298 			DATAOUT(libtrace)->compress_type = *(int*)value;
299 			return 0;
300 		case TRACE_OPTION_OUTPUT_FILEFLAGS:
301 			DATAOUT(libtrace)->flag = *(int*)value;
302 			return 0;
303 		default:
304 			/* Unknown option */
305 			trace_set_err_out(libtrace,TRACE_ERR_UNKNOWN_OPTION,
306 					"Unknown option");
307 			return -1;
308 	}
309 	return -1;
310 }
311 
pcapfile_prepare_packet(libtrace_t * libtrace,libtrace_packet_t * packet,void * buffer,libtrace_rt_types_t rt_type,uint32_t flags)312 static int pcapfile_prepare_packet(libtrace_t *libtrace,
313 		libtrace_packet_t *packet, void *buffer,
314 		libtrace_rt_types_t rt_type, uint32_t flags) {
315 
316 	if (packet->buffer != buffer &&
317 			packet->buf_control == TRACE_CTRL_PACKET) {
318 		free(packet->buffer);
319 	}
320 
321 	if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
322 		packet->buf_control = TRACE_CTRL_PACKET;
323 	} else
324 		packet->buf_control = TRACE_CTRL_EXTERNAL;
325 
326 
327 	packet->buffer = buffer;
328 	packet->header = buffer;
329 	packet->payload = (char*)packet->buffer
330 		+ sizeof(libtrace_pcapfile_pkt_hdr_t);
331 	packet->type = rt_type;
332 
333 	if (libtrace->format_data == NULL) {
334 		if (pcapfile_init_input(libtrace))
335 			return -1;
336 	}
337 
338 	return 0;
339 }
340 
pcapfile_read_packet(libtrace_t * libtrace,libtrace_packet_t * packet)341 static int pcapfile_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet)
342 {
343 	int err;
344 	uint32_t flags = 0;
345 	size_t bytes_to_read = 0;
346 
347 	assert(libtrace->format_data);
348 
349 	packet->type = pcap_linktype_to_rt(swapl(libtrace,
350 				DATA(libtrace)->header.network));
351 
352 	if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
353 		packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
354 	}
355 
356 	flags |= TRACE_PREP_OWN_BUFFER;
357 
358 	err=wandio_read(libtrace->io,
359 			packet->buffer,
360 			sizeof(libtrace_pcapfile_pkt_hdr_t));
361 
362 	if (err<0) {
363 		trace_set_err(libtrace,errno,"reading packet");
364 		return -1;
365 	}
366 	if (err==0) {
367 		/* EOF */
368 		return 0;
369 	}
370 
371 	bytes_to_read = swapl(libtrace,((libtrace_pcapfile_pkt_hdr_t*)packet->buffer)->caplen);
372 
373 	if (bytes_to_read >= LIBTRACE_PACKET_BUFSIZE) {
374 		trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Invalid caplen in pcap header (%u) - trace may be corrupt", (uint32_t)bytes_to_read);
375 		return -1;
376 	}
377 
378 	assert(bytes_to_read < LIBTRACE_PACKET_BUFSIZE);
379 
380 	/* If there is no payload to read, do not ask wandio_read to try and
381 	 * read zero bytes - we'll just get back a zero that we will
382 	 * misinterpret as EOF! */
383 	if (bytes_to_read == 0) {
384 		packet->header = packet->buffer;
385 		return sizeof(libtrace_pcapfile_pkt_hdr_t);
386 	}
387 
388 	err=wandio_read(libtrace->io,
389 			(char*)packet->buffer+sizeof(libtrace_pcapfile_pkt_hdr_t),
390 			(size_t)swapl(libtrace,((libtrace_pcapfile_pkt_hdr_t*)packet->buffer)->caplen)
391 			);
392 
393 
394 	if (err<0) {
395 		trace_set_err(libtrace,errno,"reading packet");
396 		return -1;
397 	}
398 	if (err==0) {
399 		return 0;
400 	}
401 
402 	if (pcapfile_prepare_packet(libtrace, packet, packet->buffer,
403 				packet->type, flags)) {
404 		return -1;
405 	}
406 
407 	/* We may as well cache this value now, seeing as we already had to
408 	 * look it up */
409 	packet->capture_length = bytes_to_read;
410 	return sizeof(libtrace_pcapfile_pkt_hdr_t) + bytes_to_read;
411 }
412 
pcapfile_write_packet(libtrace_out_t * out,libtrace_packet_t * packet)413 static int pcapfile_write_packet(libtrace_out_t *out,
414 		libtrace_packet_t *packet)
415 {
416 	struct libtrace_pcapfile_pkt_hdr_t hdr;
417 	struct timeval tv = trace_get_timeval(packet);
418 	int numbytes;
419 	int ret;
420 	void *ptr;
421 	uint32_t remaining;
422 	libtrace_linktype_t linktype;
423 
424 	ptr = trace_get_packet_buffer(packet,&linktype,&remaining);
425 
426 	/* Silently discard RT metadata packets and packets with an
427 	 * unknown linktype. */
428 	if (linktype == TRACE_TYPE_NONDATA || linktype == TRACE_TYPE_UNKNOWN) {
429 		return 0;
430 	}
431 
432 	/* If this packet cannot be converted to a pcap linktype then
433 	 * pop off the top header until it can be converted
434 	 */
435 	while (libtrace_to_pcap_linktype(linktype)==TRACE_DLT_ERROR) {
436 		if (!demote_packet(packet)) {
437 			trace_set_err_out(out,
438 				TRACE_ERR_NO_CONVERSION,
439 				"pcap does not support this format");
440 			assert(0);
441 			return -1;
442 		}
443 
444 		ptr = trace_get_packet_buffer(packet,&linktype,&remaining);
445 	}
446 
447 
448 	/* Now we know the link type write out a header if we've not done
449 	 * so already
450 	 */
451 	if (!DATAOUT(out)->file) {
452 		struct pcapfile_header_t pcaphdr;
453 
454 		DATAOUT(out)->file=trace_open_file_out(out,
455 				DATAOUT(out)->compress_type,
456 				DATAOUT(out)->level,
457 				DATAOUT(out)->flag);
458 
459 		if (!DATAOUT(out)->file) {
460 			trace_set_err_out(out,errno,"Unable to open file");
461 			return -1;
462 		}
463 
464 		pcaphdr.magic_number = 0xa1b2c3d4;
465 		pcaphdr.version_major = 2;
466 		pcaphdr.version_minor = 4;
467 		pcaphdr.thiszone = 0;
468 		pcaphdr.sigfigs = 0;
469 		pcaphdr.snaplen = 65536;
470 		pcaphdr.network =
471 			libtrace_to_pcap_linktype(linktype);
472 
473 		wandio_wwrite(DATAOUT(out)->file,
474 				&pcaphdr, sizeof(pcaphdr));
475 	}
476 
477 
478 	hdr.ts_sec = (uint32_t)tv.tv_sec;
479 	hdr.ts_usec = (uint32_t)tv.tv_usec;
480 	hdr.caplen = trace_get_capture_length(packet);
481 	assert(hdr.caplen < LIBTRACE_PACKET_BUFSIZE);
482 	/* PCAP doesn't include the FCS in its wire length value, but we do */
483 	if (linktype==TRACE_TYPE_ETH) {
484 		if (trace_get_wire_length(packet) >= 4) {
485 			hdr.wirelen = trace_get_wire_length(packet)-4;
486 		}
487 		else {
488 			hdr.wirelen = 0;
489 		}
490 	}
491 	else
492 		hdr.wirelen = trace_get_wire_length(packet);
493 
494 	/* Reason for removing this assert:
495 	 *
496 	 * There exist some packets, e.g. in IPLS II, where the wire length
497 	 * is clearly corrupt. When converting to pcap, we *could* try to
498 	 * adjust the wire length to something sane but for now, I'll just let
499 	 * the broken length persist through the conversion.
500 	 *
501 	 * XXX Is setting the wire length to zero the best solution in such
502 	 * cases?
503 	 */
504 
505 	/* assert(hdr.wirelen < LIBTRACE_PACKET_BUFSIZE); */
506 
507 	/* Ensure we have a valid capture length, especially if we're going
508 	 * to "remove" the FCS from the wire length */
509 	if (hdr.caplen > hdr.wirelen)
510 		hdr.caplen = hdr.wirelen;
511 
512 	/* Write the packet header */
513 	numbytes=wandio_wwrite(DATAOUT(out)->file,
514 			&hdr, sizeof(hdr));
515 
516 	if (numbytes!=sizeof(hdr))
517 		return -1;
518 
519 	/* Write the rest of the packet now */
520 	ret=wandio_wwrite(DATAOUT(out)->file,
521 			ptr,
522 			hdr.caplen);
523 
524 	if (ret!=(int)hdr.caplen)
525 		return -1;
526 
527 	return numbytes+ret;
528 }
529 
pcapfile_get_link_type(const libtrace_packet_t * packet)530 static libtrace_linktype_t pcapfile_get_link_type(
531 		const libtrace_packet_t *packet)
532 {
533 	return pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type));
534 }
535 
pcapfile_get_direction(const libtrace_packet_t * packet)536 static libtrace_direction_t pcapfile_get_direction(const libtrace_packet_t *packet)
537 {
538 	libtrace_direction_t direction  = -1;
539 	switch(pcapfile_get_link_type(packet)) {
540 		/* We can only get the direction for PCAP packets that have
541 		 * been encapsulated in Linux SLL or PFLOG */
542 		case TRACE_TYPE_LINUX_SLL:
543 		{
544 			libtrace_sll_header_t *sll;
545 			libtrace_linktype_t linktype;
546 
547 			sll = (libtrace_sll_header_t*)trace_get_packet_buffer(
548 					packet,
549 					&linktype,
550 					NULL);
551 			if (!sll) {
552 				trace_set_err(packet->trace,
553 					TRACE_ERR_BAD_PACKET,
554 						"Bad or missing packet");
555 				return -1;
556 			}
557 			/* 0 == LINUX_SLL_HOST */
558 			/* the Waikato Capture point defines "packets
559 			 * originating locally" (ie, outbound), with a
560 			 * direction of 0, and "packets destined locally"
561 			 * (ie, inbound), with a direction of 1.
562 			 * This is kind-of-opposite to LINUX_SLL.
563 			 * We return consistent values here, however
564 			 *
565 			 * Note that in recent versions of pcap, you can
566 			 * use "inbound" and "outbound" on ppp in linux
567 			 */
568 			if (ntohs(sll->pkttype == 0)) {
569 				direction = TRACE_DIR_INCOMING;
570 			} else {
571 				direction = TRACE_DIR_OUTGOING;
572 			}
573 			break;
574 
575 		}
576 		case TRACE_TYPE_PFLOG:
577 		{
578 			libtrace_pflog_header_t *pflog;
579 			libtrace_linktype_t linktype;
580 
581 			pflog=(libtrace_pflog_header_t*)trace_get_packet_buffer(
582 					packet,&linktype,NULL);
583 			if (!pflog) {
584 				trace_set_err(packet->trace,
585 						TRACE_ERR_BAD_PACKET,
586 						"Bad or missing packet");
587 				return -1;
588 			}
589 			/* enum    { PF_IN=0, PF_OUT=1 }; */
590 			if (ntohs(pflog->dir==0)) {
591 
592 				direction = TRACE_DIR_INCOMING;
593 			}
594 			else {
595 				direction = TRACE_DIR_OUTGOING;
596 			}
597 			break;
598 		}
599 		default:
600 			break;
601 	}
602 	return direction;
603 }
604 
605 
pcapfile_get_timeval(const libtrace_packet_t * packet)606 static struct timeval pcapfile_get_timeval(
607 		const libtrace_packet_t *packet)
608 {
609 	libtrace_pcapfile_pkt_hdr_t *hdr;
610 	struct timeval ts;
611 
612 	assert(packet->header);
613 
614 	hdr = (libtrace_pcapfile_pkt_hdr_t*)packet->header;
615 	ts.tv_sec = swapl(packet->trace,hdr->ts_sec);
616 	/* Check trace is not a dummy calling trace_in_nanoseconds */
617 	if (DATA(packet->trace) && trace_in_nanoseconds(&DATA(packet->trace)->header))
618 		ts.tv_usec = swapl(packet->trace, hdr->ts_usec) / 1000;
619 	else
620 		ts.tv_usec = swapl(packet->trace,hdr->ts_usec);
621 	return ts;
622 }
623 
pcapfile_get_timespec(const libtrace_packet_t * packet)624 static struct timespec pcapfile_get_timespec(
625 		const libtrace_packet_t *packet)
626 {
627 	libtrace_pcapfile_pkt_hdr_t *hdr;
628 	struct timespec ts;
629 
630 	assert(packet->header);
631 
632 	hdr = (libtrace_pcapfile_pkt_hdr_t*)packet->header;
633 	ts.tv_sec = swapl(packet->trace,hdr->ts_sec);
634 	/* Check trace is not a dummy calling trace_in_nanoseconds */
635 	if (DATA(packet->trace) && trace_in_nanoseconds(&DATA(packet->trace)->header))
636 		ts.tv_nsec = swapl(packet->trace, hdr->ts_usec);
637 	else
638 		ts.tv_nsec = swapl(packet->trace, hdr->ts_usec) * 1000;
639 	return ts;
640 }
641 
642 
pcapfile_get_capture_length(const libtrace_packet_t * packet)643 static int pcapfile_get_capture_length(const libtrace_packet_t *packet) {
644 	libtrace_pcapfile_pkt_hdr_t *pcapptr;
645 
646 	assert(packet->header);
647 	pcapptr = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
648 
649 	return swapl(packet->trace,pcapptr->caplen);
650 }
651 
pcapfile_get_wire_length(const libtrace_packet_t * packet)652 static int pcapfile_get_wire_length(const libtrace_packet_t *packet) {
653 	libtrace_pcapfile_pkt_hdr_t *pcapptr;
654 
655 	assert(packet->header);
656 
657 	pcapptr	= (libtrace_pcapfile_pkt_hdr_t *)packet->header;
658 	if (packet->type==pcap_linktype_to_rt(TRACE_DLT_EN10MB))
659 		/* Include the missing FCS */
660 		return swapl(packet->trace,pcapptr->wirelen)+4;
661 	else if (packet->type==pcap_linktype_to_rt(TRACE_DLT_IEEE802_11_RADIO)){
662 		/* If the packet is Radiotap and the flags field indicates
663 		 * that the FCS is not included in the 802.11 frame, then
664 		 * we need to add 4 to the wire-length to account for it.
665 		 */
666 		uint8_t flags;
667 		void *link;
668 		libtrace_linktype_t linktype;
669 		link = trace_get_packet_buffer(packet, &linktype, NULL);
670 		trace_get_wireless_flags(link, linktype, &flags);
671 		if ((flags & TRACE_RADIOTAP_F_FCS) == 0)
672 			return swapl(packet->trace,pcapptr->wirelen)+4;
673 	} else if (packet->type == pcap_linktype_to_rt(TRACE_DLT_LINUX_SLL)) {
674 		libtrace_sll_header_t *sll;
675 		sll = (libtrace_sll_header_t *)packet->payload;
676 
677 		/* Account for FCS when dealing with Ethernet packets that are
678 		 * encapsulated in Linux SLL. This should fix the problem
679 		 * where the wire lengths differ if we convert the packet to
680 		 * ERF */
681 		if (ntohs(sll->protocol) == TRACE_ETHERTYPE_LOOPBACK)
682 			return swapl(packet->trace,pcapptr->wirelen)+4;
683 	}
684 
685 	return swapl(packet->trace,pcapptr->wirelen);
686 }
687 
pcapfile_get_framing_length(const libtrace_packet_t * packet UNUSED)688 static int pcapfile_get_framing_length(const libtrace_packet_t *packet UNUSED) {
689 	return sizeof(libtrace_pcapfile_pkt_hdr_t);
690 }
691 
pcapfile_set_capture_length(libtrace_packet_t * packet,size_t size)692 static size_t pcapfile_set_capture_length(libtrace_packet_t *packet,size_t size) {
693 	libtrace_pcapfile_pkt_hdr_t *pcapptr = 0;
694 	assert(packet);
695 	assert(packet->header);
696 	if (size > trace_get_capture_length(packet)) {
697 		/* Can't make a packet larger */
698 		return trace_get_capture_length(packet);
699 	}
700 	/* Reset the cached capture length */
701 	packet->capture_length = -1;
702 	pcapptr = (libtrace_pcapfile_pkt_hdr_t *)packet->header;
703 	pcapptr->caplen = swapl(packet->trace,(uint32_t)size);
704 	return trace_get_capture_length(packet);
705 }
706 
pcapfile_event(libtrace_t * libtrace,libtrace_packet_t * packet)707 static struct libtrace_eventobj_t pcapfile_event(libtrace_t *libtrace, libtrace_packet_t *packet) {
708 
709 	libtrace_eventobj_t event = {0,0,0.0,0};
710 
711 	/* If we are being told to replay packets as fast as possible, then
712 	 * we just need to read and return the next packet in the trace */
713 
714 	if (IN_OPTIONS.real_time) {
715 		event.size = pcapfile_read_packet(libtrace, packet);
716 		if (event.size < 1)
717 			event.type = TRACE_EVENT_TERMINATE;
718 		else
719 			event.type = TRACE_EVENT_PACKET;
720 		return event;
721 	} else {
722 		return trace_event_trace(libtrace, packet);
723 	}
724 }
725 
pcapfile_help(void)726 static void pcapfile_help(void) {
727 	printf("pcapfile format module: $Revision: 1768 $\n");
728 	printf("Supported input URIs:\n");
729 	printf("\tpcapfile:/path/to/file\n");
730 	printf("\tpcapfile:/path/to/file.gz\n");
731 	printf("\n");
732 	printf("\te.g.: pcapfile:/tmp/trace.pcap\n");
733 	printf("\n");
734 }
735 
736 static struct libtrace_format_t pcapfile = {
737 	"pcapfile",
738 	"$Id: format_pcapfile.c 1859 2014-02-20 21:38:06Z salcock $",
739 	TRACE_FORMAT_PCAPFILE,
740 	NULL,				/* probe filename */
741 	pcapfile_probe_magic,		/* probe magic */
742 	pcapfile_init_input,		/* init_input */
743 	pcapfile_config_input,		/* config_input */
744 	pcapfile_start_input,		/* start_input */
745 	NULL,				/* pause_input */
746 	pcapfile_init_output,		/* init_output */
747 	pcapfile_config_output,		/* config_output */
748 	pcapfile_start_output,		/* start_output */
749 	pcapfile_fin_input,		/* fin_input */
750 	pcapfile_fin_output,		/* fin_output */
751 	pcapfile_read_packet,		/* read_packet */
752 	pcapfile_prepare_packet,	/* prepare_packet */
753 	NULL,				/* fin_packet */
754 	pcapfile_write_packet,		/* write_packet */
755 	pcapfile_get_link_type,		/* get_link_type */
756 	pcapfile_get_direction,		/* get_direction */
757 	NULL,				/* set_direction */
758 	NULL,				/* get_erf_timestamp */
759 	pcapfile_get_timeval,		/* get_timeval */
760 	pcapfile_get_timespec,		/* get_timespec */
761 	NULL,				/* get_seconds */
762 	NULL,				/* seek_erf */
763 	NULL,				/* seek_timeval */
764 	NULL,				/* seek_seconds */
765 	pcapfile_get_capture_length,	/* get_capture_length */
766 	pcapfile_get_wire_length,	/* get_wire_length */
767 	pcapfile_get_framing_length,	/* get_framing_length */
768 	pcapfile_set_capture_length,	/* set_capture_length */
769 	NULL,				/* get_received_packets */
770 	NULL,				/* get_filtered_packets */
771 	NULL,				/* get_dropped_packets */
772 	NULL,				/* get_captured_packets */
773 	NULL,				/* get_fd */
774 	pcapfile_event,		/* trace_event */
775 	pcapfile_help,			/* help */
776 	NULL				/* next pointer */
777 };
778 
779 
pcapfile_constructor(void)780 void pcapfile_constructor(void) {
781 	register_format(&pcapfile);
782 }
783 
784 
785