xref: /netbsd-src/external/bsd/libpcap/dist/savefile.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: savefile.c,v 1.4 2017/01/24 22:29:28 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1993, 1994, 1995, 1996, 1997
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that: (1) source code distributions
9  * retain the above copyright notice and this paragraph in its entirety, (2)
10  * distributions including binary code include the above copyright notice and
11  * this paragraph in its entirety in the documentation or other materials
12  * provided with the distribution, and (3) all advertising materials mentioning
13  * features or use of this software display the following acknowledgement:
14  * ``This product includes software developed by the University of California,
15  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16  * the University nor the names of its contributors may be used to endorse
17  * or promote products derived from this software without specific prior
18  * written permission.
19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22  *
23  * savefile.c - supports offline use of tcpdump
24  *	Extraction/creation by Jeffrey Mogul, DECWRL
25  *	Modified by Steve McCanne, LBL.
26  *
27  * Used to save the received packet headers, after filtering, to
28  * a file, and then read them later.
29  * The first record in the file contains saved values for the machine
30  * dependent values so we can print the dump file on any architecture.
31  */
32 
33 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: savefile.c,v 1.4 2017/01/24 22:29:28 christos Exp $");
35 
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39 
40 #ifdef _WIN32
41 #include <pcap-stdinc.h>
42 #else /* _WIN32 */
43 #if HAVE_INTTYPES_H
44 #include <inttypes.h>
45 #elif HAVE_STDINT_H
46 #include <stdint.h>
47 #endif
48 #ifdef HAVE_SYS_BITYPES_H
49 #include <sys/bitypes.h>
50 #endif
51 #include <sys/types.h>
52 #endif /* _WIN32 */
53 
54 #include <errno.h>
55 #include <memory.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 
60 #include "pcap-int.h"
61 
62 #ifdef HAVE_OS_PROTO_H
63 #include "os-proto.h"
64 #endif
65 
66 #include "sf-pcap.h"
67 #include "sf-pcap-ng.h"
68 
69 #ifdef _WIN32
70 /*
71  * These aren't exported on Windows, because they would only work if both
72  * WinPcap and the code using it were to use the Universal CRT; otherwise,
73  * a FILE structure in WinPcap and a FILE structure in the code using it
74  * could be different if they're using different versions of the C runtime.
75  *
76  * Instead, pcap/pcap.h defines them as macros that wrap the hopen versions,
77  * with the wrappers calling _fileno() and _get_osfhandle() themselves,
78  * so that they convert the appropriate CRT version's FILE structure to
79  * a HANDLE (which is OS-defined, not CRT-defined, and is part of the Win32
80  * and Win64 ABIs).
81  */
82 static pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *, u_int, char *);
83 static pcap_t *pcap_fopen_offline(FILE *, char *);
84 #endif
85 
86 /*
87  * Setting O_BINARY on DOS/Windows is a bit tricky
88  */
89 #if defined(_WIN32)
90   #define SET_BINMODE(f)  _setmode(_fileno(f), _O_BINARY)
91 #elif defined(MSDOS)
92   #if defined(__HIGHC__)
93   #define SET_BINMODE(f)  setmode(f, O_BINARY)
94   #else
95   #define SET_BINMODE(f)  setmode(fileno(f), O_BINARY)
96   #endif
97 #endif
98 
99 static int
100 sf_getnonblock(pcap_t *p, char *errbuf)
101 {
102 	/*
103 	 * This is a savefile, not a live capture file, so never say
104 	 * it's in non-blocking mode.
105 	 */
106 	return (0);
107 }
108 
109 static int
110 sf_setnonblock(pcap_t *p, int nonblock, char *errbuf)
111 {
112 	/*
113 	 * This is a savefile, not a live capture file, so reject
114 	 * requests to put it in non-blocking mode.  (If it's a
115 	 * pipe, it could be put in non-blocking mode, but that
116 	 * would significantly complicate the code to read packets,
117 	 * as it would have to handle reading partial packets and
118 	 * keeping the state of the read.)
119 	 */
120 	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
121 	    "Savefiles cannot be put into non-blocking mode");
122 	return (-1);
123 }
124 
125 static int
126 sf_stats(pcap_t *p, struct pcap_stat *ps)
127 {
128 	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
129 	    "Statistics aren't available from savefiles");
130 	return (-1);
131 }
132 
133 #ifdef _WIN32
134 static struct pcap_stat *
135 sf_stats_ex(pcap_t *p, int *size)
136 {
137 	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
138 	    "Statistics aren't available from savefiles");
139 	return (NULL);
140 }
141 
142 static int
143 sf_setbuff(pcap_t *p, int dim)
144 {
145 	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
146 	    "The kernel buffer size cannot be set while reading from a file");
147 	return (-1);
148 }
149 
150 static int
151 sf_setmode(pcap_t *p, int mode)
152 {
153 	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
154 	    "impossible to set mode while reading from a file");
155 	return (-1);
156 }
157 
158 static int
159 sf_setmintocopy(pcap_t *p, int size)
160 {
161 	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
162 	    "The mintocopy parameter cannot be set while reading from a file");
163 	return (-1);
164 }
165 
166 static HANDLE
167 sf_getevent(pcap_t *pcap)
168 {
169 	(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
170 	    "The read event cannot be retrieved while reading from a file");
171 	return (INVALID_HANDLE_VALUE);
172 }
173 
174 static int
175 sf_oid_get_request(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
176     size_t *lenp _U_)
177 {
178 	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
179 	    "An OID get request cannot be performed on a file");
180 	return (PCAP_ERROR);
181 }
182 
183 static int
184 sf_oid_set_request(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
185     size_t *lenp _U_)
186 {
187 	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
188 	    "An OID set request cannot be performed on a file");
189 	return (PCAP_ERROR);
190 }
191 
192 static u_int
193 sf_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue, int sync)
194 {
195 	strlcpy(p->errbuf, "Sending packets isn't supported on savefiles",
196 	    PCAP_ERRBUF_SIZE);
197 	return (0);
198 }
199 
200 static int
201 sf_setuserbuffer(pcap_t *p, int size)
202 {
203 	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
204 	    "The user buffer cannot be set when reading from a file");
205 	return (-1);
206 }
207 
208 static int
209 sf_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks)
210 {
211 	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
212 	    "Live packet dumping cannot be performed when reading from a file");
213 	return (-1);
214 }
215 
216 static int
217 sf_live_dump_ended(pcap_t *p, int sync)
218 {
219 	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
220 	    "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
221 	return (-1);
222 }
223 
224 static PAirpcapHandle
225 sf_get_airpcap_handle(pcap_t *pcap)
226 {
227 	return (NULL);
228 }
229 #endif
230 
231 static int
232 sf_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
233 {
234 	strlcpy(p->errbuf, "Sending packets isn't supported on savefiles",
235 	    PCAP_ERRBUF_SIZE);
236 	return (-1);
237 }
238 
239 /*
240  * Set direction flag: Which packets do we accept on a forwarding
241  * single device? IN, OUT or both?
242  */
243 static int
244 sf_setdirection(pcap_t *p, pcap_direction_t d)
245 {
246 	pcap_snprintf(p->errbuf, sizeof(p->errbuf),
247 	    "Setting direction is not supported on savefiles");
248 	return (-1);
249 }
250 
251 void
252 sf_cleanup(pcap_t *p)
253 {
254 	if (p->rfile != stdin)
255 		(void)fclose(p->rfile);
256 	if (p->buffer != NULL)
257 		free(p->buffer);
258 	pcap_freecode(&p->fcode);
259 }
260 
261 /*
262 * fopen's safe version on Windows.
263 */
264 #ifdef _MSC_VER
265 FILE *fopen_safe(const char *filename, const char* mode)
266 {
267 	FILE *fp = NULL;
268 	errno_t errno;
269 	errno = fopen_s(&fp, filename, mode);
270 	if (errno == 0)
271 		return fp;
272 	else
273 		return NULL;
274 }
275 #endif
276 
277 pcap_t *
278 pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision,
279 					char *errbuf)
280 {
281 	FILE *fp;
282 	pcap_t *p;
283 
284 	if (fname == NULL) {
285 		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
286 		    "A null pointer was supplied as the file name");
287 		return (NULL);
288 	}
289 	if (fname[0] == '-' && fname[1] == '\0')
290 	{
291 		fp = stdin;
292 #if defined(_WIN32) || defined(MSDOS)
293 		/*
294 		 * We're reading from the standard input, so put it in binary
295 		 * mode, as savefiles are binary files.
296 		 */
297 		SET_BINMODE(fp);
298 #endif
299 	}
300 	else {
301 #if !defined(_WIN32) && !defined(MSDOS)
302 		fp = fopen(fname, "r");
303 #else
304 		fp = fopen(fname, "rb");
305 #endif
306 		if (fp == NULL) {
307 			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname,
308 			    pcap_strerror(errno));
309 			return (NULL);
310 		}
311 	}
312 	p = pcap_fopen_offline_with_tstamp_precision(fp, precision, errbuf);
313 	if (p == NULL) {
314 		if (fp != stdin)
315 			fclose(fp);
316 	}
317 	return (p);
318 }
319 
320 pcap_t *
321 pcap_open_offline(const char *fname, char *errbuf)
322 {
323 	return (pcap_open_offline_with_tstamp_precision(fname,
324 	    PCAP_TSTAMP_PRECISION_MICRO, errbuf));
325 }
326 
327 #ifdef _WIN32
328 pcap_t* pcap_hopen_offline_with_tstamp_precision(intptr_t osfd, u_int precision,
329     char *errbuf)
330 {
331 	int fd;
332 	FILE *file;
333 
334 	fd = _open_osfhandle(osfd, _O_RDONLY);
335 	if ( fd < 0 )
336 	{
337 		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno));
338 		return NULL;
339 	}
340 
341 	file = _fdopen(fd, "rb");
342 	if ( file == NULL )
343 	{
344 		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno));
345 		return NULL;
346 	}
347 
348 	return pcap_fopen_offline_with_tstamp_precision(file, precision,
349 	    errbuf);
350 }
351 
352 pcap_t* pcap_hopen_offline(intptr_t osfd, char *errbuf)
353 {
354 	return pcap_hopen_offline_with_tstamp_precision(osfd,
355 	    PCAP_TSTAMP_PRECISION_MICRO, errbuf);
356 }
357 #endif
358 
359 static pcap_t *(*check_headers[])(bpf_u_int32, FILE *, u_int, char *, int *) = {
360 	pcap_check_header,
361 	pcap_ng_check_header
362 };
363 
364 #define	N_FILE_TYPES	(sizeof check_headers / sizeof check_headers[0])
365 
366 #ifdef _WIN32
367 static
368 #endif
369 pcap_t *
370 pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision,
371     char *errbuf)
372 {
373 	register pcap_t *p;
374 	bpf_u_int32 magic;
375 	size_t amt_read;
376 	u_int i;
377 	int err;
378 
379 	/*
380 	 * Read the first 4 bytes of the file; the network analyzer dump
381 	 * file formats we support (pcap and pcap-ng), and several other
382 	 * formats we might support in the future (such as snoop, DOS and
383 	 * Windows Sniffer, and Microsoft Network Monitor) all have magic
384 	 * numbers that are unique in their first 4 bytes.
385 	 */
386 	amt_read = fread((char *)&magic, 1, sizeof(magic), fp);
387 	if (amt_read != sizeof(magic)) {
388 		if (ferror(fp)) {
389 			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
390 			    "error reading dump file: %s",
391 			    pcap_strerror(errno));
392 		} else {
393 			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
394 			    "truncated dump file; tried to read %lu file header bytes, only got %lu",
395 			    (unsigned long)sizeof(magic),
396 			    (unsigned long)amt_read);
397 		}
398 		return (NULL);
399 	}
400 
401 	/*
402 	 * Try all file types.
403 	 */
404 	for (i = 0; i < N_FILE_TYPES; i++) {
405 		p = (*check_headers[i])(magic, fp, precision, errbuf, &err);
406 		if (p != NULL) {
407 			/* Yup, that's it. */
408 			goto found;
409 		}
410 		if (err) {
411 			/*
412 			 * Error trying to read the header.
413 			 */
414 			return (NULL);
415 		}
416 	}
417 
418 	/*
419 	 * Well, who knows what this mess is....
420 	 */
421 	pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format");
422 	return (NULL);
423 
424 found:
425 	p->rfile = fp;
426 
427 	/* Padding only needed for live capture fcode */
428 	p->fddipad = 0;
429 
430 #if !defined(_WIN32) && !defined(MSDOS)
431 	/*
432 	 * You can do "select()" and "poll()" on plain files on most
433 	 * platforms, and should be able to do so on pipes.
434 	 *
435 	 * You can't do "select()" on anything other than sockets in
436 	 * Windows, so, on Win32 systems, we don't have "selectable_fd".
437 	 */
438 	p->selectable_fd = fileno(fp);
439 #endif
440 
441 	p->read_op = pcap_offline_read;
442 	p->inject_op = sf_inject;
443 	p->setfilter_op = install_bpf_program;
444 	p->setdirection_op = sf_setdirection;
445 	p->set_datalink_op = NULL;	/* we don't support munging link-layer headers */
446 	p->getnonblock_op = sf_getnonblock;
447 	p->setnonblock_op = sf_setnonblock;
448 	p->stats_op = sf_stats;
449 #ifdef _WIN32
450 	p->stats_ex_op = sf_stats_ex;
451 	p->setbuff_op = sf_setbuff;
452 	p->setmode_op = sf_setmode;
453 	p->setmintocopy_op = sf_setmintocopy;
454 	p->getevent_op = sf_getevent;
455 	p->oid_get_request_op = sf_oid_get_request;
456 	p->oid_set_request_op = sf_oid_set_request;
457 	p->sendqueue_transmit_op = sf_sendqueue_transmit;
458 	p->setuserbuffer_op = sf_setuserbuffer;
459 	p->live_dump_op = sf_live_dump;
460 	p->live_dump_ended_op = sf_live_dump_ended;
461 	p->get_airpcap_handle_op = sf_get_airpcap_handle;
462 #endif
463 
464 	/*
465 	 * For offline captures, the standard one-shot callback can
466 	 * be used for pcap_next()/pcap_next_ex().
467 	 */
468 	p->oneshot_callback = pcap_oneshot;
469 
470 	/*
471 	 * Savefiles never require special BPF code generation.
472 	 */
473 	p->bpf_codegen_flags = 0;
474 
475 	p->activated = 1;
476 
477 	return (p);
478 }
479 
480 #ifdef _WIN32
481 static
482 #endif
483 pcap_t *
484 pcap_fopen_offline(FILE *fp, char *errbuf)
485 {
486 	return (pcap_fopen_offline_with_tstamp_precision(fp,
487 	    PCAP_TSTAMP_PRECISION_MICRO, errbuf));
488 }
489 
490 /*
491  * Read packets from a capture file, and call the callback for each
492  * packet.
493  * If cnt > 0, return after 'cnt' packets, otherwise continue until eof.
494  */
495 int
496 pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
497 {
498 	struct bpf_insn *fcode;
499 	int status = 0;
500 	int n = 0;
501 	u_char *data;
502 
503 	while (status == 0) {
504 		struct pcap_pkthdr h;
505 
506 		/*
507 		 * Has "pcap_breakloop()" been called?
508 		 * If so, return immediately - if we haven't read any
509 		 * packets, clear the flag and return -2 to indicate
510 		 * that we were told to break out of the loop, otherwise
511 		 * leave the flag set, so that the *next* call will break
512 		 * out of the loop without having read any packets, and
513 		 * return the number of packets we've processed so far.
514 		 */
515 		if (p->break_loop) {
516 			if (n == 0) {
517 				p->break_loop = 0;
518 				return (-2);
519 			} else
520 				return (n);
521 		}
522 
523 		status = p->next_packet_op(p, &h, &data);
524 		if (status) {
525 			if (status == 1)
526 				return (0);
527 			return (status);
528 		}
529 
530 		if ((fcode = p->fcode.bf_insns) == NULL ||
531 		    bpf_filter(fcode, data, h.len, h.caplen)) {
532 			(*callback)(user, &h, data);
533 			if (++n >= cnt && cnt > 0)
534 				break;
535 		}
536 	}
537 	/*XXX this breaks semantics tcpslice expects */
538 	return (n);
539 }
540