Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 1993, 1994, 1995, 1996, 1997 |
3 | | * The Regents of the University of California. All rights reserved. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that: (1) source code distributions |
7 | | * retain the above copyright notice and this paragraph in its entirety, (2) |
8 | | * distributions including binary code include the above copyright notice and |
9 | | * this paragraph in its entirety in the documentation or other materials |
10 | | * provided with the distribution, and (3) all advertising materials mentioning |
11 | | * features or use of this software display the following acknowledgement: |
12 | | * ``This product includes software developed by the University of California, |
13 | | * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of |
14 | | * the University nor the names of its contributors may be used to endorse |
15 | | * or promote products derived from this software without specific prior |
16 | | * written permission. |
17 | | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
18 | | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
19 | | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
20 | | * |
21 | | * sf-pcap.c - libpcap-file-format-specific code from savefile.c |
22 | | * Extraction/creation by Jeffrey Mogul, DECWRL |
23 | | * Modified by Steve McCanne, LBL. |
24 | | * |
25 | | * Used to save the received packet headers, after filtering, to |
26 | | * a file, and then read them later. |
27 | | * The first record in the file contains saved values for the machine |
28 | | * dependent values so we can print the dump file on any architecture. |
29 | | */ |
30 | | |
31 | | #include <config.h> |
32 | | |
33 | | #include <pcap-types.h> |
34 | | #ifdef _WIN32 |
35 | | #include <io.h> |
36 | | #include <fcntl.h> |
37 | | #endif /* _WIN32 */ |
38 | | |
39 | | #include <errno.h> |
40 | | #include <memory.h> |
41 | | #include <stdio.h> |
42 | | #include <stdlib.h> |
43 | | #include <string.h> |
44 | | #include <limits.h> /* for INT_MAX */ |
45 | | |
46 | | #include "pcap-int.h" |
47 | | #include "pcap-util.h" |
48 | | |
49 | | #include "pcap-common.h" |
50 | | |
51 | | #ifdef HAVE_OS_PROTO_H |
52 | | #include "os-proto.h" |
53 | | #endif |
54 | | |
55 | | #include "sf-pcap.h" |
56 | | |
57 | | /* |
58 | | * Setting O_BINARY on Windows is a bit tricky. |
59 | | */ |
60 | | #if defined(_WIN32) |
61 | | #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY) |
62 | | #endif |
63 | | |
64 | | /* |
65 | | * Standard libpcap format. |
66 | | * |
67 | | * The same value is used in the rpcap protocol as an indication of |
68 | | * the server byte order, to let the client know whether it needs to |
69 | | * byte-swap some host-byte-order metadata. |
70 | | */ |
71 | 60.7k | #define TCPDUMP_MAGIC 0xa1b2c3d4 |
72 | | |
73 | | /* |
74 | | * Alexey Kuznetzov's modified libpcap format. |
75 | | */ |
76 | 75.5k | #define KUZNETZOV_TCPDUMP_MAGIC 0xa1b2cd34 |
77 | | |
78 | | /* |
79 | | * Reserved for Francisco Mesquita <francisco.mesquita@radiomovel.pt> |
80 | | * for another modified format. |
81 | | */ |
82 | | #define FMESQUITA_TCPDUMP_MAGIC 0xa1b234cd |
83 | | |
84 | | /* |
85 | | * Navtel Communications' format, with nanosecond timestamps, |
86 | | * as per a request from Dumas Hwang <dumas.hwang@navtelcom.com>. |
87 | | */ |
88 | 0 | #define NAVTEL_TCPDUMP_MAGIC 0xa12b3c4d |
89 | | |
90 | | /* |
91 | | * Normal libpcap format, except for seconds/nanoseconds timestamps, |
92 | | * as per a request by Ulf Lamping <ulf.lamping@web.de> |
93 | | */ |
94 | 43.5k | #define NSEC_TCPDUMP_MAGIC 0xa1b23c4d |
95 | | |
96 | | /* |
97 | | * Used for identification of cbpf-savefile(5). |
98 | | */ |
99 | | #define CBPF_SAVEFILE_MAGIC 0xa1b2c3cb |
100 | | |
101 | | /* |
102 | | * This is a timeval as stored in a savefile. |
103 | | * It has to use the same types everywhere, independent of the actual |
104 | | * `struct timeval'; `struct timeval' has 32-bit tv_sec values on some |
105 | | * platforms and 64-bit tv_sec values on other platforms, and writing |
106 | | * out native `struct timeval' values would mean files could only be |
107 | | * read on systems with the same tv_sec size as the system on which |
108 | | * the file was written. |
109 | | * |
110 | | * The fields are unsigned, as that's what the pcap draft specification |
111 | | * says they are. (That gives pcap a 68-year Y2.038K reprieve, although |
112 | | * in 2106 it runs out for good. pcapng doesn't have that problem, |
113 | | * unless you pick a *really* high time stamp precision.) |
114 | | */ |
115 | | |
116 | | struct pcap_timeval { |
117 | | bpf_u_int32 tv_sec; /* seconds */ |
118 | | bpf_u_int32 tv_usec; /* microseconds */ |
119 | | }; |
120 | | |
121 | | /* |
122 | | * This is a `pcap_pkthdr' as actually stored in a savefile. |
123 | | * |
124 | | * Do not change the format of this structure, in any way (this includes |
125 | | * changes that only affect the length of fields in this structure), |
126 | | * and do not make the time stamp anything other than seconds and |
127 | | * microseconds (e.g., seconds and nanoseconds). Instead: |
128 | | * |
129 | | * introduce a new structure for the new format; |
130 | | * |
131 | | * send mail to "tcpdump-workers@lists.tcpdump.org", requesting |
132 | | * a new magic number for your new capture file format, and, when |
133 | | * you get the new magic number, put it in "savefile.c"; |
134 | | * |
135 | | * use that magic number for save files with the changed record |
136 | | * header; |
137 | | * |
138 | | * make the code in "savefile.c" capable of reading files with |
139 | | * the old record header as well as files with the new record header |
140 | | * (using the magic number to determine the header format). |
141 | | * |
142 | | * Then supply the changes by forking the branch at |
143 | | * |
144 | | * https://github.com/the-tcpdump-group/libpcap/tree/master |
145 | | * |
146 | | * and issuing a pull request, so that future versions of libpcap and |
147 | | * programs that use it (such as tcpdump) will be able to read your new |
148 | | * capture file format. |
149 | | */ |
150 | | |
151 | | struct pcap_sf_pkthdr { |
152 | | struct pcap_timeval ts; /* time stamp */ |
153 | | bpf_u_int32 caplen; /* length of portion present */ |
154 | | bpf_u_int32 len; /* length of this packet (off wire) */ |
155 | | }; |
156 | | |
157 | | /* |
158 | | * How a `pcap_pkthdr' is actually stored in savefiles written |
159 | | * by some patched versions of libpcap (e.g. the ones in Red |
160 | | * Hat Linux 6.1 and 6.2). |
161 | | * |
162 | | * Do not change the format of this structure, in any way (this includes |
163 | | * changes that only affect the length of fields in this structure). |
164 | | * Instead, introduce a new structure, as per the above. |
165 | | */ |
166 | | |
167 | | struct pcap_sf_patched_pkthdr { |
168 | | struct pcap_timeval ts; /* time stamp */ |
169 | | bpf_u_int32 caplen; /* length of portion present */ |
170 | | bpf_u_int32 len; /* length of this packet (off wire) */ |
171 | | int index; |
172 | | unsigned short protocol; |
173 | | unsigned char pkt_type; |
174 | | }; |
175 | | |
176 | | static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap); |
177 | | |
178 | | #ifdef _WIN32 |
179 | | /* |
180 | | * This isn't exported on Windows, because it would only work if both |
181 | | * libpcap and the code using it were using the same C runtime; otherwise they |
182 | | * would be using different definitions of a FILE structure. |
183 | | * |
184 | | * Instead we define this as a macro in pcap/pcap.h that wraps the hopen |
185 | | * version that we do export, passing it a raw OS HANDLE, as defined by the |
186 | | * Win32 / Win64 ABI, obtained from the _fileno() and _get_osfhandle() |
187 | | * functions of the appropriate CRT. |
188 | | */ |
189 | | static pcap_dumper_t *pcap_dump_fopen(pcap_t *p, FILE *f); |
190 | | #endif /* _WIN32 */ |
191 | | |
192 | | /* |
193 | | * Private data for reading pcap savefiles. |
194 | | */ |
195 | | typedef enum { |
196 | | NOT_SWAPPED, |
197 | | SWAPPED, |
198 | | MAYBE_SWAPPED |
199 | | } swapped_type_t; |
200 | | |
201 | | typedef enum { |
202 | | PASS_THROUGH, |
203 | | SCALE_UP, |
204 | | SCALE_DOWN |
205 | | } tstamp_scale_type_t; |
206 | | |
207 | | struct pcap_sf { |
208 | | size_t hdrsize; |
209 | | swapped_type_t lengths_swapped; |
210 | | tstamp_scale_type_t scale_type; |
211 | | }; |
212 | | |
213 | | /* |
214 | | * Check whether this is a pcap savefile and, if it is, extract the |
215 | | * relevant information from the header. |
216 | | */ |
217 | | pcap_t * |
218 | | pcap_check_header(const uint8_t *magic, FILE *fp, u_int precision, char *errbuf, |
219 | | int *err) |
220 | 19.4k | { |
221 | 19.4k | bpf_u_int32 magic_int; |
222 | 19.4k | struct pcap_file_header hdr; |
223 | 19.4k | size_t amt_read; |
224 | 19.4k | pcap_t *p; |
225 | 19.4k | int swapped = 0; |
226 | 19.4k | struct pcap_sf *ps; |
227 | | |
228 | | /* |
229 | | * Assume no read errors. |
230 | | */ |
231 | 19.4k | *err = 0; |
232 | | |
233 | | /* |
234 | | * Check whether the first 4 bytes of the file are the magic |
235 | | * number for a pcap savefile, or for a byte-swapped pcap |
236 | | * savefile. |
237 | | */ |
238 | 19.4k | memcpy(&magic_int, magic, sizeof(magic_int)); |
239 | 19.4k | if (magic_int != TCPDUMP_MAGIC && |
240 | 19.4k | magic_int != KUZNETZOV_TCPDUMP_MAGIC && |
241 | 19.4k | magic_int != NSEC_TCPDUMP_MAGIC) { |
242 | 10.9k | magic_int = SWAPLONG(magic_int); |
243 | 10.9k | if (magic_int != TCPDUMP_MAGIC && |
244 | 10.9k | magic_int != KUZNETZOV_TCPDUMP_MAGIC && |
245 | 10.9k | magic_int != NSEC_TCPDUMP_MAGIC) |
246 | 2.92k | return (NULL); /* nope */ |
247 | 8.01k | swapped = 1; |
248 | 8.01k | } |
249 | | |
250 | | /* |
251 | | * They are. Put the magic number in the header, and read |
252 | | * the rest of the header. |
253 | | */ |
254 | 16.5k | hdr.magic = magic_int; |
255 | 16.5k | amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1, |
256 | 16.5k | sizeof(hdr) - sizeof(hdr.magic), fp); |
257 | 16.5k | if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) { |
258 | 28 | if (ferror(fp)) { |
259 | 0 | pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, |
260 | 0 | errno, "error reading dump file"); |
261 | 28 | } else { |
262 | 28 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
263 | 28 | "truncated dump file; tried to read %zu file header bytes, only got %zu", |
264 | 28 | sizeof(hdr), amt_read); |
265 | 28 | } |
266 | 28 | *err = 1; |
267 | 28 | return (NULL); |
268 | 28 | } |
269 | | |
270 | | /* |
271 | | * If it's a byte-swapped capture file, byte-swap the header. |
272 | | */ |
273 | 16.4k | if (swapped) { |
274 | 7.99k | hdr.version_major = SWAPSHORT(hdr.version_major); |
275 | 7.99k | hdr.version_minor = SWAPSHORT(hdr.version_minor); |
276 | 7.99k | hdr.thiszone = SWAPLONG(hdr.thiszone); |
277 | 7.99k | hdr.sigfigs = SWAPLONG(hdr.sigfigs); |
278 | 7.99k | hdr.snaplen = SWAPLONG(hdr.snaplen); |
279 | 7.99k | hdr.linktype = SWAPLONG(hdr.linktype); |
280 | 7.99k | } |
281 | | |
282 | 16.4k | if (hdr.version_major < PCAP_VERSION_MAJOR) { |
283 | 4 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
284 | 4 | "archaic pcap savefile format"); |
285 | 4 | *err = 1; |
286 | 4 | return (NULL); |
287 | 4 | } |
288 | | |
289 | | /* |
290 | | * currently only versions 2.[0-4] are supported with |
291 | | * the exception of 543.0 for DG/UX tcpdump. |
292 | | */ |
293 | 16.4k | if (! ((hdr.version_major == PCAP_VERSION_MAJOR && |
294 | 16.4k | hdr.version_minor <= PCAP_VERSION_MINOR) || |
295 | 16.4k | (hdr.version_major == 543 && |
296 | 226 | hdr.version_minor == 0))) { |
297 | 101 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
298 | 101 | "unsupported pcap savefile version %u.%u", |
299 | 101 | hdr.version_major, hdr.version_minor); |
300 | 101 | *err = 1; |
301 | 101 | return NULL; |
302 | 101 | } |
303 | | |
304 | | /* |
305 | | * Check the main reserved field. |
306 | | */ |
307 | 16.3k | if (LT_RESERVED1(hdr.linktype) != 0) { |
308 | 21 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
309 | 21 | "savefile linktype reserved field not zero (0x%08x)", |
310 | 21 | LT_RESERVED1(hdr.linktype)); |
311 | 21 | *err = 1; |
312 | 21 | return NULL; |
313 | 21 | } |
314 | | |
315 | | /* |
316 | | * OK, this is a good pcap file. |
317 | | * Allocate a pcap_t for it. |
318 | | */ |
319 | 16.3k | p = PCAP_OPEN_OFFLINE_COMMON(errbuf, struct pcap_sf); |
320 | 16.3k | if (p == NULL) { |
321 | | /* Allocation failed. */ |
322 | 0 | *err = 1; |
323 | 0 | return (NULL); |
324 | 0 | } |
325 | 16.3k | p->swapped = swapped; |
326 | 16.3k | p->version_major = hdr.version_major; |
327 | 16.3k | p->version_minor = hdr.version_minor; |
328 | 16.3k | p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype)); |
329 | 16.3k | p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype); |
330 | 16.3k | p->snapshot = pcapint_adjust_snapshot(p->linktype, hdr.snaplen); |
331 | | |
332 | 16.3k | p->next_packet_op = pcap_next_packet; |
333 | | |
334 | 16.3k | ps = p->priv; |
335 | | |
336 | 16.3k | p->opt.tstamp_precision = precision; |
337 | | |
338 | | /* |
339 | | * Will we need to scale the timestamps to match what the |
340 | | * user wants? |
341 | | */ |
342 | 16.3k | switch (precision) { |
343 | | |
344 | 16.3k | case PCAP_TSTAMP_PRECISION_MICRO: |
345 | 16.3k | if (magic_int == NSEC_TCPDUMP_MAGIC) { |
346 | | /* |
347 | | * The file has nanoseconds, the user |
348 | | * wants microseconds; scale the |
349 | | * precision down. |
350 | | */ |
351 | 13.2k | ps->scale_type = SCALE_DOWN; |
352 | 13.2k | } else { |
353 | | /* |
354 | | * The file has microseconds, the |
355 | | * user wants microseconds; nothing to do. |
356 | | */ |
357 | 3.09k | ps->scale_type = PASS_THROUGH; |
358 | 3.09k | } |
359 | 16.3k | break; |
360 | | |
361 | 0 | case PCAP_TSTAMP_PRECISION_NANO: |
362 | 0 | if (magic_int == NSEC_TCPDUMP_MAGIC) { |
363 | | /* |
364 | | * The file has nanoseconds, the |
365 | | * user wants nanoseconds; nothing to do. |
366 | | */ |
367 | 0 | ps->scale_type = PASS_THROUGH; |
368 | 0 | } else { |
369 | | /* |
370 | | * The file has microseconds, the user |
371 | | * wants nanoseconds; scale the |
372 | | * precision up. |
373 | | */ |
374 | 0 | ps->scale_type = SCALE_UP; |
375 | 0 | } |
376 | 0 | break; |
377 | | |
378 | 0 | default: |
379 | 0 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
380 | 0 | "unknown time stamp resolution %u", precision); |
381 | 0 | free(p); |
382 | 0 | *err = 1; |
383 | 0 | return (NULL); |
384 | 16.3k | } |
385 | | |
386 | | /* |
387 | | * We interchanged the caplen and len fields at version 2.3, |
388 | | * in order to match the bpf header layout. But unfortunately |
389 | | * some files were written with version 2.3 in their headers |
390 | | * but without the interchanged fields. |
391 | | * |
392 | | * In addition, DG/UX tcpdump writes out files with a version |
393 | | * number of 543.0, and with the caplen and len fields in the |
394 | | * pre-2.3 order. |
395 | | */ |
396 | 16.3k | switch (hdr.version_major) { |
397 | | |
398 | 16.2k | case 2: |
399 | 16.2k | if (hdr.version_minor < 3) |
400 | 11.1k | ps->lengths_swapped = SWAPPED; |
401 | 5.03k | else if (hdr.version_minor == 3) |
402 | 3.69k | ps->lengths_swapped = MAYBE_SWAPPED; |
403 | 1.34k | else |
404 | 1.34k | ps->lengths_swapped = NOT_SWAPPED; |
405 | 16.2k | break; |
406 | | |
407 | 124 | case 543: |
408 | 124 | ps->lengths_swapped = SWAPPED; |
409 | 124 | break; |
410 | | |
411 | 0 | default: |
412 | 0 | ps->lengths_swapped = NOT_SWAPPED; |
413 | 0 | break; |
414 | 16.3k | } |
415 | | |
416 | 16.3k | if (magic_int == KUZNETZOV_TCPDUMP_MAGIC) { |
417 | | /* |
418 | | * XXX - the patch that's in some versions of libpcap |
419 | | * changes the packet header but not the magic number, |
420 | | * and some other versions with this magic number have |
421 | | * some extra debugging information in the packet header; |
422 | | * we'd have to use some hacks^H^H^H^H^Hheuristics to |
423 | | * detect those variants. |
424 | | * |
425 | | * Ethereal does that, but it does so by trying to read |
426 | | * the first two packets of the file with each of the |
427 | | * record header formats. That currently means it seeks |
428 | | * backwards and retries the reads, which doesn't work |
429 | | * on pipes. We want to be able to read from a pipe, so |
430 | | * that strategy won't work; we'd have to buffer some |
431 | | * data ourselves and read from that buffer in order to |
432 | | * make that work. |
433 | | */ |
434 | 1.60k | ps->hdrsize = sizeof(struct pcap_sf_patched_pkthdr); |
435 | | |
436 | 1.60k | if (p->linktype == DLT_EN10MB) { |
437 | | /* |
438 | | * This capture might have been done in raw mode |
439 | | * or cooked mode. |
440 | | * |
441 | | * If it was done in cooked mode, p->snapshot was |
442 | | * passed to recvfrom() as the buffer size, meaning |
443 | | * that the most packet data that would be copied |
444 | | * would be p->snapshot. However, a faked Ethernet |
445 | | * header would then have been added to it, so the |
446 | | * most data that would be in a packet in the file |
447 | | * would be p->snapshot + 14. |
448 | | * |
449 | | * We can't easily tell whether the capture was done |
450 | | * in raw mode or cooked mode, so we'll assume it was |
451 | | * cooked mode, and add 14 to the snapshot length. |
452 | | * That means that, for a raw capture, the snapshot |
453 | | * length will be misleading if you use it to figure |
454 | | * out why a capture doesn't have all the packet data, |
455 | | * but there's not much we can do to avoid that. |
456 | | * |
457 | | * But don't grow the snapshot length past the |
458 | | * maximum value of an int. |
459 | | */ |
460 | 215 | if (p->snapshot <= INT_MAX - 14) |
461 | 211 | p->snapshot += 14; |
462 | 4 | else |
463 | 4 | p->snapshot = INT_MAX; |
464 | 215 | } |
465 | 1.60k | } else |
466 | 14.7k | ps->hdrsize = sizeof(struct pcap_sf_pkthdr); |
467 | | |
468 | | /* |
469 | | * Allocate a buffer for the packet data. |
470 | | * Choose the minimum of the file's snapshot length and 2K bytes; |
471 | | * that should be enough for most network packets - we'll grow it |
472 | | * if necessary. That way, we don't allocate a huge chunk of |
473 | | * memory just because there's a huge snapshot length, as the |
474 | | * snapshot length might be larger than the size of the largest |
475 | | * packet. |
476 | | */ |
477 | 16.3k | p->bufsize = p->snapshot; |
478 | 16.3k | if (p->bufsize > 2048) |
479 | 14.7k | p->bufsize = 2048; |
480 | 16.3k | p->buffer = malloc(p->bufsize); |
481 | 16.3k | if (p->buffer == NULL) { |
482 | 0 | snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); |
483 | 0 | free(p); |
484 | 0 | *err = 1; |
485 | 0 | return (NULL); |
486 | 0 | } |
487 | | |
488 | 16.3k | p->cleanup_op = pcapint_sf_cleanup; |
489 | | |
490 | 16.3k | return (p); |
491 | 16.3k | } |
492 | | |
493 | | /* |
494 | | * Grow the packet buffer to the specified size. |
495 | | */ |
496 | | static int |
497 | | grow_buffer(pcap_t *p, u_int bufsize) |
498 | 7.83k | { |
499 | 7.83k | void *bigger_buffer; |
500 | | |
501 | 7.83k | bigger_buffer = realloc(p->buffer, bufsize); |
502 | 7.83k | if (bigger_buffer == NULL) { |
503 | 0 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "out of memory"); |
504 | 0 | return (0); |
505 | 0 | } |
506 | 7.83k | p->buffer = bigger_buffer; |
507 | 7.83k | p->bufsize = bufsize; |
508 | 7.83k | return (1); |
509 | 7.83k | } |
510 | | |
511 | | /* |
512 | | * Read and return the next packet from the savefile. Return the header |
513 | | * in hdr and a pointer to the contents in data. Return 1 on success, 0 |
514 | | * if there were no more packets, and -1 on an error. |
515 | | */ |
516 | | static int |
517 | | pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) |
518 | 66.5k | { |
519 | 66.5k | struct pcap_sf *ps = p->priv; |
520 | 66.5k | struct pcap_sf_patched_pkthdr sf_hdr; |
521 | 66.5k | FILE *fp = p->rfile; |
522 | 66.5k | size_t amt_read; |
523 | 66.5k | bpf_u_int32 t; |
524 | | |
525 | | /* |
526 | | * Read the packet header; the structure we use as a buffer |
527 | | * is the longer structure for files generated by the patched |
528 | | * libpcap, but if the file has the magic number for an |
529 | | * unpatched libpcap we only read as many bytes as the regular |
530 | | * header has. |
531 | | */ |
532 | 66.5k | amt_read = fread(&sf_hdr, 1, ps->hdrsize, fp); |
533 | 66.5k | if (amt_read != ps->hdrsize) { |
534 | 9.70k | if (ferror(fp)) { |
535 | 0 | pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, |
536 | 0 | errno, "error reading dump file"); |
537 | 0 | return (-1); |
538 | 9.70k | } else { |
539 | 9.70k | if (amt_read != 0) { |
540 | 364 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
541 | 364 | "truncated dump file; tried to read %zu header bytes, only got %zu", |
542 | 364 | ps->hdrsize, amt_read); |
543 | 364 | return (-1); |
544 | 364 | } |
545 | | /* EOF */ |
546 | 9.34k | return (0); |
547 | 9.70k | } |
548 | 9.70k | } |
549 | | |
550 | 56.8k | if (p->swapped) { |
551 | | /* these were written in opposite byte order */ |
552 | 53.0k | hdr->caplen = SWAPLONG(sf_hdr.caplen); |
553 | 53.0k | hdr->len = SWAPLONG(sf_hdr.len); |
554 | 53.0k | hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec); |
555 | 53.0k | hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec); |
556 | 53.0k | } else { |
557 | 3.76k | hdr->caplen = sf_hdr.caplen; |
558 | 3.76k | hdr->len = sf_hdr.len; |
559 | 3.76k | hdr->ts.tv_sec = sf_hdr.ts.tv_sec; |
560 | 3.76k | hdr->ts.tv_usec = sf_hdr.ts.tv_usec; |
561 | 3.76k | } |
562 | | |
563 | 56.8k | switch (ps->scale_type) { |
564 | | |
565 | 10.5k | case PASS_THROUGH: |
566 | | /* |
567 | | * Just pass the time stamp through. |
568 | | */ |
569 | 10.5k | break; |
570 | | |
571 | 0 | case SCALE_UP: |
572 | | /* |
573 | | * File has microseconds, user wants nanoseconds; convert |
574 | | * it. |
575 | | */ |
576 | 0 | hdr->ts.tv_usec = hdr->ts.tv_usec * 1000; |
577 | 0 | break; |
578 | | |
579 | 46.2k | case SCALE_DOWN: |
580 | | /* |
581 | | * File has nanoseconds, user wants microseconds; convert |
582 | | * it. |
583 | | */ |
584 | 46.2k | hdr->ts.tv_usec = hdr->ts.tv_usec / 1000; |
585 | 46.2k | break; |
586 | 56.8k | } |
587 | | |
588 | | /* Swap the caplen and len fields, if necessary. */ |
589 | 56.8k | switch (ps->lengths_swapped) { |
590 | | |
591 | 5.63k | case NOT_SWAPPED: |
592 | 5.63k | break; |
593 | | |
594 | 29.8k | case MAYBE_SWAPPED: |
595 | 29.8k | if (hdr->caplen <= hdr->len) { |
596 | | /* |
597 | | * The captured length is <= the actual length, |
598 | | * so presumably they weren't swapped. |
599 | | */ |
600 | 20.4k | break; |
601 | 20.4k | } |
602 | | /* FALLTHROUGH */ |
603 | | |
604 | 30.7k | case SWAPPED: |
605 | 30.7k | t = hdr->caplen; |
606 | 30.7k | hdr->caplen = hdr->len; |
607 | 30.7k | hdr->len = t; |
608 | 30.7k | break; |
609 | 56.8k | } |
610 | | |
611 | | /* |
612 | | * Is the packet bigger than we consider sane? |
613 | | */ |
614 | 56.8k | if (hdr->caplen > max_snaplen_for_dlt(p->linktype)) { |
615 | | /* |
616 | | * Yes. This may be a damaged or fuzzed file. |
617 | | * |
618 | | * Is it bigger than the snapshot length? |
619 | | * (We don't treat that as an error if it's not |
620 | | * bigger than the maximum we consider sane; see |
621 | | * below.) |
622 | | */ |
623 | 193 | if (hdr->caplen > (bpf_u_int32)p->snapshot) { |
624 | 160 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
625 | 160 | "invalid packet capture length %u, bigger than " |
626 | 160 | "snaplen of %d", hdr->caplen, p->snapshot); |
627 | 160 | } else { |
628 | 33 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
629 | 33 | "invalid packet capture length %u, bigger than " |
630 | 33 | "maximum of %u", hdr->caplen, |
631 | 33 | max_snaplen_for_dlt(p->linktype)); |
632 | 33 | } |
633 | 193 | return (-1); |
634 | 193 | } |
635 | | |
636 | 56.6k | if (hdr->caplen > (bpf_u_int32)p->snapshot) { |
637 | | /* |
638 | | * The packet is bigger than the snapshot length |
639 | | * for this file. |
640 | | * |
641 | | * This can happen due to Solaris 2.3 systems tripping |
642 | | * over the BUFMOD problem and not setting the snapshot |
643 | | * length correctly in the savefile header. |
644 | | * |
645 | | * libpcap 0.4 and later on Solaris 2.3 should set the |
646 | | * snapshot length correctly in the pcap file header, |
647 | | * even though they don't set a snapshot length in bufmod |
648 | | * (the buggy bufmod chops off the *beginning* of the |
649 | | * packet if a snapshot length is specified); they should |
650 | | * also reduce the captured length, as supplied to the |
651 | | * per-packet callback, to the snapshot length if it's |
652 | | * greater than the snapshot length, so the code using |
653 | | * libpcap should see the packet cut off at the snapshot |
654 | | * length, even though the full packet is copied up to |
655 | | * userland. |
656 | | * |
657 | | * However, perhaps some versions of libpcap failed to |
658 | | * set the snapshot length correctly in the file header |
659 | | * or the per-packet header, or perhaps this is a |
660 | | * corrupted savefile or a savefile built/modified by a |
661 | | * fuzz tester, so we check anyway. We grow the buffer |
662 | | * to be big enough for the snapshot length, read up |
663 | | * to the snapshot length, discard the rest of the |
664 | | * packet, and report the snapshot length as the captured |
665 | | * length; we don't want to hand our caller a packet |
666 | | * bigger than the snapshot length, because they might |
667 | | * be assuming they'll never be handed such a packet, |
668 | | * and might copy the packet into a snapshot-length- |
669 | | * sized buffer, assuming it'll fit. |
670 | | */ |
671 | 7.44k | size_t bytes_to_discard; |
672 | 7.44k | size_t bytes_to_read, bytes_read; |
673 | 7.44k | char discard_buf[4096]; |
674 | | |
675 | 7.44k | if (hdr->caplen > p->bufsize) { |
676 | | /* |
677 | | * Grow the buffer to the snapshot length. |
678 | | */ |
679 | 7.44k | if (!grow_buffer(p, p->snapshot)) |
680 | 0 | return (-1); |
681 | 7.44k | } |
682 | | |
683 | | /* |
684 | | * Read the first p->snapshot bytes into the buffer. |
685 | | */ |
686 | 7.44k | amt_read = fread(p->buffer, 1, p->snapshot, fp); |
687 | 7.44k | if (amt_read != (bpf_u_int32)p->snapshot) { |
688 | 127 | if (ferror(fp)) { |
689 | 0 | pcapint_fmt_errmsg_for_errno(p->errbuf, |
690 | 0 | PCAP_ERRBUF_SIZE, errno, |
691 | 0 | "error reading dump file"); |
692 | 127 | } else { |
693 | | /* |
694 | | * Yes, this uses hdr->caplen; technically, |
695 | | * it's true, because we would try to read |
696 | | * and discard the rest of those bytes, and |
697 | | * that would fail because we got EOF before |
698 | | * the read finished. |
699 | | */ |
700 | 127 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
701 | 127 | "truncated dump file; tried to read %d captured bytes, only got %zu", |
702 | 127 | p->snapshot, amt_read); |
703 | 127 | } |
704 | 127 | return (-1); |
705 | 127 | } |
706 | | |
707 | | /* |
708 | | * Now read and discard what's left. |
709 | | */ |
710 | 7.31k | bytes_to_discard = hdr->caplen - p->snapshot; |
711 | 7.31k | bytes_read = amt_read; |
712 | 14.5k | while (bytes_to_discard != 0) { |
713 | 7.40k | bytes_to_read = bytes_to_discard; |
714 | 7.40k | if (bytes_to_read > sizeof (discard_buf)) |
715 | 160 | bytes_to_read = sizeof (discard_buf); |
716 | 7.40k | amt_read = fread(discard_buf, 1, bytes_to_read, fp); |
717 | 7.40k | bytes_read += amt_read; |
718 | 7.40k | if (amt_read != bytes_to_read) { |
719 | 128 | if (ferror(fp)) { |
720 | 0 | pcapint_fmt_errmsg_for_errno(p->errbuf, |
721 | 0 | PCAP_ERRBUF_SIZE, errno, |
722 | 0 | "error reading dump file"); |
723 | 128 | } else { |
724 | 128 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
725 | 128 | "truncated dump file; tried to read %u captured bytes, only got %zu", |
726 | 128 | hdr->caplen, bytes_read); |
727 | 128 | } |
728 | 128 | return (-1); |
729 | 128 | } |
730 | 7.27k | bytes_to_discard -= amt_read; |
731 | 7.27k | } |
732 | | |
733 | | /* |
734 | | * Adjust caplen accordingly, so we don't get confused later |
735 | | * as to how many bytes we have to play with. |
736 | | */ |
737 | 7.19k | hdr->caplen = p->snapshot; |
738 | 49.1k | } else { |
739 | | /* |
740 | | * The packet is within the snapshot length for this file. |
741 | | */ |
742 | 49.1k | if (hdr->caplen > p->bufsize) { |
743 | | /* |
744 | | * Grow the buffer to the next power of 2, or |
745 | | * the snaplen, whichever is lower. |
746 | | */ |
747 | 389 | u_int new_bufsize; |
748 | | |
749 | 389 | new_bufsize = hdr->caplen; |
750 | | /* |
751 | | * https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 |
752 | | */ |
753 | 389 | new_bufsize--; |
754 | 389 | new_bufsize |= new_bufsize >> 1; |
755 | 389 | new_bufsize |= new_bufsize >> 2; |
756 | 389 | new_bufsize |= new_bufsize >> 4; |
757 | 389 | new_bufsize |= new_bufsize >> 8; |
758 | 389 | new_bufsize |= new_bufsize >> 16; |
759 | 389 | new_bufsize++; |
760 | | |
761 | 389 | if (new_bufsize > (u_int)p->snapshot) |
762 | 63 | new_bufsize = p->snapshot; |
763 | | |
764 | 389 | if (!grow_buffer(p, new_bufsize)) |
765 | 0 | return (-1); |
766 | 389 | } |
767 | | |
768 | | /* read the packet itself */ |
769 | 49.1k | amt_read = fread(p->buffer, 1, hdr->caplen, fp); |
770 | 49.1k | if (amt_read != hdr->caplen) { |
771 | 186 | if (ferror(fp)) { |
772 | 0 | pcapint_fmt_errmsg_for_errno(p->errbuf, |
773 | 0 | PCAP_ERRBUF_SIZE, errno, |
774 | 0 | "error reading dump file"); |
775 | 186 | } else { |
776 | 186 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
777 | 186 | "truncated dump file; tried to read %u captured bytes, only got %zu", |
778 | 186 | hdr->caplen, amt_read); |
779 | 186 | } |
780 | 186 | return (-1); |
781 | 186 | } |
782 | 49.1k | } |
783 | 56.1k | *data = p->buffer; |
784 | | |
785 | 56.1k | pcapint_post_process(p->linktype, p->swapped, hdr, *data); |
786 | | |
787 | 56.1k | return (1); |
788 | 56.6k | } |
789 | | |
790 | | static int |
791 | | sf_write_header(pcap_t *p, FILE *fp, int linktype, int snaplen) |
792 | 0 | { |
793 | 0 | struct pcap_file_header hdr; |
794 | |
|
795 | 0 | hdr.magic = p->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? NSEC_TCPDUMP_MAGIC : TCPDUMP_MAGIC; |
796 | 0 | hdr.version_major = PCAP_VERSION_MAJOR; |
797 | 0 | hdr.version_minor = PCAP_VERSION_MINOR; |
798 | | |
799 | | /* |
800 | | * https://www.tcpdump.org/manpages/pcap-savefile.5.txt states: |
801 | | * thiszone (Reserved1): 4-byte not used - SHOULD be filled with 0 |
802 | | * sigfigs (Reserved2): 4-byte not used - SHOULD be filled with 0 |
803 | | */ |
804 | 0 | hdr.thiszone = 0; |
805 | 0 | hdr.sigfigs = 0; |
806 | 0 | hdr.snaplen = snaplen; |
807 | 0 | hdr.linktype = linktype; |
808 | |
|
809 | 0 | if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) |
810 | 0 | return (-1); |
811 | | |
812 | 0 | return (0); |
813 | 0 | } |
814 | | |
815 | | /* |
816 | | * Output a packet to the initialized dump file. |
817 | | */ |
818 | | void |
819 | | pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) |
820 | 0 | { |
821 | 0 | register FILE *f; |
822 | 0 | struct pcap_sf_pkthdr sf_hdr; |
823 | |
|
824 | 0 | f = (FILE *)user; |
825 | | /* |
826 | | * If the output file handle is in an error state, don't write |
827 | | * anything. |
828 | | * |
829 | | * While in principle a file handle can return from an error state |
830 | | * to a normal state (for example if a disk that is full has space |
831 | | * freed), we have possibly left a broken file already, and won't |
832 | | * be able to clean it up. The safest option is to do nothing. |
833 | | * |
834 | | * Note that if we could guarantee that fwrite() was atomic we |
835 | | * might be able to insure that we don't produce a corrupted file, |
836 | | * but the standard defines fwrite() as a series of fputc() calls, |
837 | | * so we really have no insurance that things are not fubared. |
838 | | * |
839 | | * http://pubs.opengroup.org/onlinepubs/009695399/functions/fwrite.html |
840 | | */ |
841 | 0 | if (ferror(f)) |
842 | 0 | return; |
843 | | /* |
844 | | * Better not try writing pcap files after |
845 | | * 2106-02-07 06:28:15 UTC; switch to pcapng. |
846 | | * (And better not try writing pcap files with time stamps |
847 | | * that predate 1970-01-01 00:00:00 UTC; that's not supported. |
848 | | * You could try using pcapng with the if_tsoffset field in |
849 | | * the IDB for the interface(s) with packets with those time |
850 | | * stamps, but you may also have to get a link-layer type for |
851 | | * IBM Bisync or whatever link layer even older forms |
852 | | * of computer communication used.) |
853 | | */ |
854 | 0 | sf_hdr.ts.tv_sec = (bpf_u_int32)h->ts.tv_sec; |
855 | 0 | sf_hdr.ts.tv_usec = (bpf_u_int32)h->ts.tv_usec; |
856 | 0 | sf_hdr.caplen = h->caplen; |
857 | 0 | sf_hdr.len = h->len; |
858 | | /* |
859 | | * We only write the packet if we can write the header properly. |
860 | | * |
861 | | * This doesn't prevent us from having corrupted output, and if we |
862 | | * for some reason don't get a complete write we don't have any |
863 | | * way to set ferror() to prevent future writes from being |
864 | | * attempted, but it is better than nothing. |
865 | | */ |
866 | 0 | if (fwrite(&sf_hdr, sizeof(sf_hdr), 1, f) == 1) { |
867 | 0 | (void)fwrite(sp, h->caplen, 1, f); |
868 | 0 | } |
869 | 0 | } |
870 | | |
871 | | static pcap_dumper_t * |
872 | | pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname) |
873 | 0 | { |
874 | |
|
875 | | #if defined(_WIN32) |
876 | | /* |
877 | | * If we're writing to the standard output, put it in binary |
878 | | * mode, as savefiles are binary files. |
879 | | * |
880 | | * Otherwise, we turn off buffering. |
881 | | * XXX - why? And why not on the standard output? |
882 | | */ |
883 | | if (f == stdout) |
884 | | SET_BINMODE(f); |
885 | | else |
886 | | setvbuf(f, NULL, _IONBF, 0); |
887 | | #endif |
888 | 0 | if (sf_write_header(p, f, linktype, p->snapshot) == -1) { |
889 | 0 | pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, |
890 | 0 | errno, "Can't write to %s", fname); |
891 | 0 | if (f != stdout) |
892 | 0 | (void)fclose(f); |
893 | 0 | return (NULL); |
894 | 0 | } |
895 | 0 | return ((pcap_dumper_t *)f); |
896 | 0 | } |
897 | | |
898 | | /* |
899 | | * Initialize so that sf_write() will output to the file named 'fname'. |
900 | | */ |
901 | | pcap_dumper_t * |
902 | | pcap_dump_open(pcap_t *p, const char *fname) |
903 | 0 | { |
904 | 0 | FILE *f; |
905 | 0 | int linktype; |
906 | | |
907 | | /* |
908 | | * If this pcap_t hasn't been activated, it doesn't have a |
909 | | * link-layer type, so we can't use it. |
910 | | */ |
911 | 0 | if (!p->activated) { |
912 | 0 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
913 | 0 | "%s: not-yet-activated pcap_t passed to pcap_dump_open", |
914 | 0 | fname); |
915 | 0 | return (NULL); |
916 | 0 | } |
917 | 0 | linktype = dlt_to_linktype(p->linktype); |
918 | 0 | if (linktype == -1) { |
919 | 0 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
920 | 0 | "%s: link-layer type %d isn't supported in savefiles", |
921 | 0 | fname, p->linktype); |
922 | 0 | return (NULL); |
923 | 0 | } |
924 | 0 | linktype |= p->linktype_ext; |
925 | |
|
926 | 0 | if (fname == NULL) { |
927 | 0 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
928 | 0 | "A null pointer was supplied as the file name"); |
929 | 0 | return NULL; |
930 | 0 | } |
931 | 0 | if (fname[0] == '-' && fname[1] == '\0') { |
932 | 0 | f = stdout; |
933 | 0 | fname = "standard output"; |
934 | 0 | } else { |
935 | | /* |
936 | | * "b" is supported as of C90, so *all* UN*Xes should |
937 | | * support it, even though it does nothing. It's |
938 | | * required on Windows, as the file is a binary file |
939 | | * and must be written in binary mode. |
940 | | */ |
941 | 0 | f = pcapint_charset_fopen(fname, "wb"); |
942 | 0 | if (f == NULL) { |
943 | 0 | pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, |
944 | 0 | errno, "%s", fname); |
945 | 0 | return (NULL); |
946 | 0 | } |
947 | 0 | } |
948 | 0 | return (pcap_setup_dump(p, linktype, f, fname)); |
949 | 0 | } |
950 | | |
951 | | #ifdef _WIN32 |
952 | | /* |
953 | | * Initialize so that sf_write() will output to a stream wrapping the given raw |
954 | | * OS file HANDLE. |
955 | | */ |
956 | | pcap_dumper_t * |
957 | | pcap_dump_hopen(pcap_t *p, intptr_t osfd) |
958 | | { |
959 | | int fd; |
960 | | FILE *file; |
961 | | |
962 | | fd = _open_osfhandle(osfd, _O_APPEND); |
963 | | if (fd < 0) { |
964 | | pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, |
965 | | errno, "_open_osfhandle"); |
966 | | return NULL; |
967 | | } |
968 | | |
969 | | file = _fdopen(fd, "wb"); |
970 | | if (file == NULL) { |
971 | | pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, |
972 | | errno, "_fdopen"); |
973 | | _close(fd); |
974 | | return NULL; |
975 | | } |
976 | | |
977 | | return pcap_dump_fopen(p, file); |
978 | | } |
979 | | #endif /* _WIN32 */ |
980 | | |
981 | | /* |
982 | | * Initialize so that sf_write() will output to the given stream. |
983 | | */ |
984 | | #ifdef _WIN32 |
985 | | static |
986 | | #endif /* _WIN32 */ |
987 | | pcap_dumper_t * |
988 | | pcap_dump_fopen(pcap_t *p, FILE *f) |
989 | 0 | { |
990 | 0 | int linktype; |
991 | |
|
992 | 0 | linktype = dlt_to_linktype(p->linktype); |
993 | 0 | if (linktype == -1) { |
994 | 0 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
995 | 0 | "stream: link-layer type %d isn't supported in savefiles", |
996 | 0 | p->linktype); |
997 | 0 | return (NULL); |
998 | 0 | } |
999 | 0 | linktype |= p->linktype_ext; |
1000 | |
|
1001 | 0 | return (pcap_setup_dump(p, linktype, f, "stream")); |
1002 | 0 | } |
1003 | | |
1004 | | pcap_dumper_t * |
1005 | | pcap_dump_open_append(pcap_t *p, const char *fname) |
1006 | 0 | { |
1007 | 0 | FILE *f; |
1008 | 0 | int linktype; |
1009 | 0 | size_t amt_read; |
1010 | 0 | struct pcap_file_header ph; |
1011 | |
|
1012 | 0 | linktype = dlt_to_linktype(p->linktype); |
1013 | 0 | if (linktype == -1) { |
1014 | 0 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
1015 | 0 | "%s: link-layer type %d isn't supported in savefiles", |
1016 | 0 | fname, linktype); |
1017 | 0 | return (NULL); |
1018 | 0 | } |
1019 | | |
1020 | 0 | if (fname == NULL) { |
1021 | 0 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
1022 | 0 | "A null pointer was supplied as the file name"); |
1023 | 0 | return NULL; |
1024 | 0 | } |
1025 | 0 | if (fname[0] == '-' && fname[1] == '\0') |
1026 | 0 | return (pcap_setup_dump(p, linktype, stdout, "standard output")); |
1027 | | |
1028 | | /* |
1029 | | * "a" will cause the file *not* to be truncated if it exists |
1030 | | * but will cause it to be created if it doesn't. It will |
1031 | | * also cause all writes to be done at the end of the file, |
1032 | | * but will allow reads to be done anywhere in the file. This |
1033 | | * is what we need, because we need to read from the beginning |
1034 | | * of the file to see if it already has a header and packets |
1035 | | * or if it doesn't. |
1036 | | * |
1037 | | * "b" is supported as of C90, so *all* UN*Xes should support it, |
1038 | | * even though it does nothing. It's required on Windows, as the |
1039 | | * file is a binary file and must be read in binary mode. |
1040 | | */ |
1041 | 0 | f = pcapint_charset_fopen(fname, "ab+"); |
1042 | 0 | if (f == NULL) { |
1043 | 0 | pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, |
1044 | 0 | errno, "%s", fname); |
1045 | 0 | return (NULL); |
1046 | 0 | } |
1047 | | |
1048 | | /* |
1049 | | * Try to read a pcap header. |
1050 | | * |
1051 | | * We do not assume that the file will be positioned at the |
1052 | | * beginning immediately after we've opened it - we seek to |
1053 | | * the beginning. ISO C says it's implementation-defined |
1054 | | * whether the file position indicator is at the beginning |
1055 | | * or the end of the file after an append-mode open, and |
1056 | | * it wasn't obvious from the Single UNIX Specification |
1057 | | * or the Microsoft documentation how that works on SUS- |
1058 | | * compliant systems or on Windows. |
1059 | | */ |
1060 | 0 | if (fseek(f, 0, SEEK_SET) == -1) { |
1061 | 0 | pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, |
1062 | 0 | errno, "Can't seek to the beginning of %s", fname); |
1063 | 0 | (void)fclose(f); |
1064 | 0 | return (NULL); |
1065 | 0 | } |
1066 | 0 | amt_read = fread(&ph, 1, sizeof (ph), f); |
1067 | 0 | if (amt_read != sizeof (ph)) { |
1068 | 0 | if (ferror(f)) { |
1069 | 0 | pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, |
1070 | 0 | errno, "%s", fname); |
1071 | 0 | (void)fclose(f); |
1072 | 0 | return (NULL); |
1073 | 0 | } else if (feof(f) && amt_read > 0) { |
1074 | 0 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
1075 | 0 | "%s: truncated pcap file header", fname); |
1076 | 0 | (void)fclose(f); |
1077 | 0 | return (NULL); |
1078 | 0 | } |
1079 | 0 | } |
1080 | | |
1081 | | #if defined(_WIN32) |
1082 | | /* |
1083 | | * We turn off buffering. |
1084 | | * XXX - why? And why not on the standard output? |
1085 | | */ |
1086 | | setvbuf(f, NULL, _IONBF, 0); |
1087 | | #endif |
1088 | | |
1089 | | /* |
1090 | | * If a header is already present and: |
1091 | | * |
1092 | | * it's not for a pcap file of the appropriate resolution |
1093 | | * and the right byte order for this machine; |
1094 | | * |
1095 | | * the link-layer header types don't match; |
1096 | | * |
1097 | | * the snapshot lengths don't match; |
1098 | | * |
1099 | | * return an error. |
1100 | | */ |
1101 | 0 | if (amt_read > 0) { |
1102 | | /* |
1103 | | * A header is already present. |
1104 | | * Do the checks. |
1105 | | */ |
1106 | 0 | switch (ph.magic) { |
1107 | | |
1108 | 0 | case TCPDUMP_MAGIC: |
1109 | 0 | if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_MICRO) { |
1110 | 0 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
1111 | 0 | "%s: different time stamp precision, cannot append to file", fname); |
1112 | 0 | (void)fclose(f); |
1113 | 0 | return (NULL); |
1114 | 0 | } |
1115 | 0 | break; |
1116 | | |
1117 | 0 | case NSEC_TCPDUMP_MAGIC: |
1118 | 0 | if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_NANO) { |
1119 | 0 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
1120 | 0 | "%s: different time stamp precision, cannot append to file", fname); |
1121 | 0 | (void)fclose(f); |
1122 | 0 | return (NULL); |
1123 | 0 | } |
1124 | 0 | break; |
1125 | | |
1126 | 0 | case SWAPLONG(TCPDUMP_MAGIC): |
1127 | 0 | case SWAPLONG(NSEC_TCPDUMP_MAGIC): |
1128 | 0 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
1129 | 0 | "%s: different byte order, cannot append to file", fname); |
1130 | 0 | (void)fclose(f); |
1131 | 0 | return (NULL); |
1132 | | |
1133 | 0 | case KUZNETZOV_TCPDUMP_MAGIC: |
1134 | 0 | case SWAPLONG(KUZNETZOV_TCPDUMP_MAGIC): |
1135 | 0 | case NAVTEL_TCPDUMP_MAGIC: |
1136 | 0 | case SWAPLONG(NAVTEL_TCPDUMP_MAGIC): |
1137 | 0 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
1138 | 0 | "%s: not a pcap file to which we can append", fname); |
1139 | 0 | (void)fclose(f); |
1140 | 0 | return (NULL); |
1141 | | |
1142 | 0 | default: |
1143 | 0 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
1144 | 0 | "%s: not a pcap file", fname); |
1145 | 0 | (void)fclose(f); |
1146 | 0 | return (NULL); |
1147 | 0 | } |
1148 | | |
1149 | | /* |
1150 | | * Good version? |
1151 | | */ |
1152 | 0 | if (ph.version_major != PCAP_VERSION_MAJOR || |
1153 | 0 | ph.version_minor != PCAP_VERSION_MINOR) { |
1154 | 0 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
1155 | 0 | "%s: version is %u.%u, cannot append to file", fname, |
1156 | 0 | ph.version_major, ph.version_minor); |
1157 | 0 | (void)fclose(f); |
1158 | 0 | return (NULL); |
1159 | 0 | } |
1160 | 0 | if ((bpf_u_int32)linktype != ph.linktype) { |
1161 | 0 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
1162 | 0 | "%s: different linktype, cannot append to file", fname); |
1163 | 0 | (void)fclose(f); |
1164 | 0 | return (NULL); |
1165 | 0 | } |
1166 | 0 | if ((bpf_u_int32)p->snapshot != ph.snaplen) { |
1167 | 0 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
1168 | 0 | "%s: different snaplen, cannot append to file", fname); |
1169 | 0 | (void)fclose(f); |
1170 | 0 | return (NULL); |
1171 | 0 | } |
1172 | 0 | } else { |
1173 | | /* |
1174 | | * A header isn't present; attempt to write it. |
1175 | | */ |
1176 | 0 | if (sf_write_header(p, f, linktype, p->snapshot) == -1) { |
1177 | 0 | pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, |
1178 | 0 | errno, "Can't write to %s", fname); |
1179 | 0 | (void)fclose(f); |
1180 | 0 | return (NULL); |
1181 | 0 | } |
1182 | 0 | } |
1183 | | |
1184 | | /* |
1185 | | * Start writing at the end of the file. |
1186 | | * |
1187 | | * XXX - this shouldn't be necessary, given that we're opening |
1188 | | * the file in append mode, and ISO C specifies that all writes |
1189 | | * are done at the end of the file in that mode. |
1190 | | */ |
1191 | 0 | if (fseek(f, 0, SEEK_END) == -1) { |
1192 | 0 | pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, |
1193 | 0 | errno, "Can't seek to the end of %s", fname); |
1194 | 0 | (void)fclose(f); |
1195 | 0 | return (NULL); |
1196 | 0 | } |
1197 | 0 | return ((pcap_dumper_t *)f); |
1198 | 0 | } |
1199 | | |
1200 | | FILE * |
1201 | | pcap_dump_file(pcap_dumper_t *p) |
1202 | 0 | { |
1203 | 0 | return ((FILE *)p); |
1204 | 0 | } |
1205 | | |
1206 | | long |
1207 | | pcap_dump_ftell(pcap_dumper_t *p) |
1208 | 0 | { |
1209 | 0 | return (ftell((FILE *)p)); |
1210 | 0 | } |
1211 | | |
1212 | | #if defined(HAVE_FSEEKO) |
1213 | | /* |
1214 | | * We have fseeko(), so we have ftello(). |
1215 | | * If we have large file support (files larger than 2^31-1 bytes), |
1216 | | * ftello() will give us a current file position with more than 32 |
1217 | | * bits. |
1218 | | */ |
1219 | | int64_t |
1220 | | pcap_dump_ftell64(pcap_dumper_t *p) |
1221 | 0 | { |
1222 | 0 | return (ftello((FILE *)p)); |
1223 | 0 | } |
1224 | | #elif defined(_MSC_VER) |
1225 | | /* |
1226 | | * We have Visual Studio; we support only 2015 and later, so we have |
1227 | | * _ftelli64(). |
1228 | | */ |
1229 | | int64_t |
1230 | | pcap_dump_ftell64(pcap_dumper_t *p) |
1231 | | { |
1232 | | return (_ftelli64((FILE *)p)); |
1233 | | } |
1234 | | #else |
1235 | | /* |
1236 | | * We don't have ftello() or _ftelli64(), so fall back on ftell(). |
1237 | | * Either long is 64 bits, in which case ftell() should suffice, |
1238 | | * or this is probably an older 32-bit UN*X without large file |
1239 | | * support, which means you'll probably get errors trying to |
1240 | | * write files > 2^31-1, so it won't matter anyway. |
1241 | | * |
1242 | | * XXX - what about MinGW? |
1243 | | */ |
1244 | | int64_t |
1245 | | pcap_dump_ftell64(pcap_dumper_t *p) |
1246 | | { |
1247 | | return (ftell((FILE *)p)); |
1248 | | } |
1249 | | #endif |
1250 | | |
1251 | | int |
1252 | | pcap_dump_flush(pcap_dumper_t *p) |
1253 | 0 | { |
1254 | |
|
1255 | 0 | if (fflush((FILE *)p) == EOF) |
1256 | 0 | return (-1); |
1257 | 0 | else |
1258 | 0 | return (0); |
1259 | 0 | } |
1260 | | |
1261 | | void |
1262 | | pcap_dump_close(pcap_dumper_t *p) |
1263 | 0 | { |
1264 | 0 | FILE *fp = (FILE *)p; |
1265 | |
|
1266 | | #ifdef notyet |
1267 | | if (ferror(fp)) |
1268 | | return-an-error; |
1269 | | /* XXX should check return from fflush()/fclose() too */ |
1270 | | #endif |
1271 | | /* Don't close the standard output, but *do* flush it */ |
1272 | 0 | if (fp == stdout) |
1273 | 0 | (void)fflush(fp); |
1274 | 0 | else |
1275 | 0 | (void)fclose(fp); |
1276 | 0 | } |