Coverage Report

Created: 2025-07-18 06:49

/src/libpcap/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
#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
}