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