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