source: rtems-libbsd/freebsd/contrib/libpcap/sf-pcap.c @ 3d1e767

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 3d1e767 was 3d1e767, checked in by Sebastian Huber <sebastian.huber@…>, on 04/27/16 at 08:25:22

Directly use <sys/types.h> provided by Newlib

  • Property mode set to 100644
File size: 16.0 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2
3/*
4 * Copyright (c) 1993, 1994, 1995, 1996, 1997
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that: (1) source code distributions
9 * retain the above copyright notice and this paragraph in its entirety, (2)
10 * distributions including binary code include the above copyright notice and
11 * this paragraph in its entirety in the documentation or other materials
12 * provided with the distribution, and (3) all advertising materials mentioning
13 * features or use of this software display the following acknowledgement:
14 * ``This product includes software developed by the University of California,
15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16 * the University nor the names of its contributors may be used to endorse
17 * or promote products derived from this software without specific prior
18 * written permission.
19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 *
23 * sf-pcap.c - libpcap-file-format-specific code from savefile.c
24 *      Extraction/creation by Jeffrey Mogul, DECWRL
25 *      Modified by Steve McCanne, LBL.
26 *
27 * Used to save the received packet headers, after filtering, to
28 * a file, and then read them later.
29 * The first record in the file contains saved values for the machine
30 * dependent values so we can print the dump file on any architecture.
31 */
32
33#ifndef lint
34static const char rcsid[] _U_ =
35    "@(#) $Header$ (LBL)";
36#endif
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#endif
41
42#ifdef WIN32
43#include <pcap-stdinc.h>
44#else /* WIN32 */
45#if HAVE_INTTYPES_H
46#include <inttypes.h>
47#elif HAVE_STDINT_H
48#include <stdint.h>
49#endif
50#ifdef HAVE_SYS_BITYPES_H
51#include <sys/bitypes.h>
52#endif
53#include <sys/types.h>
54#endif /* WIN32 */
55
56#include <errno.h>
57#include <memory.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <string.h>
61
62#include "pcap-int.h"
63
64#include "pcap-common.h"
65
66#ifdef HAVE_OS_PROTO_H
67#include "os-proto.h"
68#endif
69
70#include "sf-pcap.h"
71
72/*
73 * Setting O_BINARY on DOS/Windows is a bit tricky
74 */
75#if defined(WIN32)
76  #define SET_BINMODE(f)  _setmode(_fileno(f), _O_BINARY)
77#elif defined(MSDOS)
78  #if defined(__HIGHC__)
79  #define SET_BINMODE(f)  setmode(f, O_BINARY)
80  #else
81  #define SET_BINMODE(f)  setmode(fileno(f), O_BINARY)
82  #endif
83#endif
84
85/*
86 * Standard libpcap format.
87 */
88#define TCPDUMP_MAGIC           0xa1b2c3d4
89
90/*
91 * Alexey Kuznetzov's modified libpcap format.
92 */
93#define KUZNETZOV_TCPDUMP_MAGIC 0xa1b2cd34
94
95/*
96 * Reserved for Francisco Mesquita <francisco.mesquita@radiomovel.pt>
97 * for another modified format.
98 */
99#define FMESQUITA_TCPDUMP_MAGIC 0xa1b234cd
100
101/*
102 * Navtel Communcations' format, with nanosecond timestamps,
103 * as per a request from Dumas Hwang <dumas.hwang@navtelcom.com>.
104 */
105#define NAVTEL_TCPDUMP_MAGIC    0xa12b3c4d
106
107/*
108 * Normal libpcap format, except for seconds/nanoseconds timestamps,
109 * as per a request by Ulf Lamping <ulf.lamping@web.de>
110 */
111#define NSEC_TCPDUMP_MAGIC      0xa1b23c4d
112
113/*
114 * Mechanism for storing information about a capture in the upper
115 * 6 bits of a linktype value in a capture file.
116 *
117 * LT_LINKTYPE_EXT(x) extracts the additional information.
118 *
119 * The rest of the bits are for a value describing the link-layer
120 * value.  LT_LINKTYPE(x) extracts that value.
121 */
122#define LT_LINKTYPE(x)          ((x) & 0x03FFFFFF)
123#define LT_LINKTYPE_EXT(x)      ((x) & 0xFC000000)
124
125static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap);
126
127/*
128 * Check whether this is a pcap savefile and, if it is, extract the
129 * relevant information from the header.
130 */
131int
132pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf)
133{
134        struct pcap_file_header hdr;
135        size_t amt_read;
136
137        /*
138         * Check whether the first 4 bytes of the file are the magic
139         * number for a pcap savefile, or for a byte-swapped pcap
140         * savefile.
141         */
142        if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC) {
143                magic = SWAPLONG(magic);
144                if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC)
145                        return (0);     /* nope */
146                p->sf.swapped = 1;
147        }
148
149        /*
150         * They are.  Put the magic number in the header, and read
151         * the rest of the header.
152         */
153        hdr.magic = magic;
154        amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1,
155            sizeof(hdr) - sizeof(hdr.magic), fp);
156        if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) {
157                if (ferror(fp)) {
158                        snprintf(errbuf, PCAP_ERRBUF_SIZE,
159                            "error reading dump file: %s",
160                            pcap_strerror(errno));
161                } else {
162                        snprintf(errbuf, PCAP_ERRBUF_SIZE,
163                            "truncated dump file; tried to read %lu file header bytes, only got %lu",
164                            (unsigned long)sizeof(hdr),
165                            (unsigned long)amt_read);
166                }
167                return (-1);
168        }
169
170        /*
171         * If it's a byte-swapped capture file, byte-swap the header.
172         */
173        if (p->sf.swapped) {
174                hdr.version_major = SWAPSHORT(hdr.version_major);
175                hdr.version_minor = SWAPSHORT(hdr.version_minor);
176                hdr.thiszone = SWAPLONG(hdr.thiszone);
177                hdr.sigfigs = SWAPLONG(hdr.sigfigs);
178                hdr.snaplen = SWAPLONG(hdr.snaplen);
179                hdr.linktype = SWAPLONG(hdr.linktype);
180        }
181
182        if (hdr.version_major < PCAP_VERSION_MAJOR) {
183                snprintf(errbuf, PCAP_ERRBUF_SIZE,
184                    "archaic pcap savefile format");
185                return (-1);
186        }
187        p->sf.version_major = hdr.version_major;
188        p->sf.version_minor = hdr.version_minor;
189        p->tzoff = hdr.thiszone;
190        p->snapshot = hdr.snaplen;
191        p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype));
192        p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype);
193
194        p->sf.next_packet_op = pcap_next_packet;
195
196        /*
197         * We interchanged the caplen and len fields at version 2.3,
198         * in order to match the bpf header layout.  But unfortunately
199         * some files were written with version 2.3 in their headers
200         * but without the interchanged fields.
201         *
202         * In addition, DG/UX tcpdump writes out files with a version
203         * number of 543.0, and with the caplen and len fields in the
204         * pre-2.3 order.
205         */
206        switch (hdr.version_major) {
207
208        case 2:
209                if (hdr.version_minor < 3)
210                        p->sf.lengths_swapped = SWAPPED;
211                else if (hdr.version_minor == 3)
212                        p->sf.lengths_swapped = MAYBE_SWAPPED;
213                else
214                        p->sf.lengths_swapped = NOT_SWAPPED;
215                break;
216
217        case 543:
218                p->sf.lengths_swapped = SWAPPED;
219                break;
220
221        default:
222                p->sf.lengths_swapped = NOT_SWAPPED;
223                break;
224        }
225
226        if (magic == KUZNETZOV_TCPDUMP_MAGIC) {
227                /*
228                 * XXX - the patch that's in some versions of libpcap
229                 * changes the packet header but not the magic number,
230                 * and some other versions with this magic number have
231                 * some extra debugging information in the packet header;
232                 * we'd have to use some hacks^H^H^H^H^Hheuristics to
233                 * detect those variants.
234                 *
235                 * Ethereal does that, but it does so by trying to read
236                 * the first two packets of the file with each of the
237                 * record header formats.  That currently means it seeks
238                 * backwards and retries the reads, which doesn't work
239                 * on pipes.  We want to be able to read from a pipe, so
240                 * that strategy won't work; we'd have to buffer some
241                 * data ourselves and read from that buffer in order to
242                 * make that work.
243                 */
244                p->sf.hdrsize = sizeof(struct pcap_sf_patched_pkthdr);
245
246                if (p->linktype == DLT_EN10MB) {
247                        /*
248                         * This capture might have been done in raw mode
249                         * or cooked mode.
250                         *
251                         * If it was done in cooked mode, p->snapshot was
252                         * passed to recvfrom() as the buffer size, meaning
253                         * that the most packet data that would be copied
254                         * would be p->snapshot.  However, a faked Ethernet
255                         * header would then have been added to it, so the
256                         * most data that would be in a packet in the file
257                         * would be p->snapshot + 14.
258                         *
259                         * We can't easily tell whether the capture was done
260                         * in raw mode or cooked mode, so we'll assume it was
261                         * cooked mode, and add 14 to the snapshot length.
262                         * That means that, for a raw capture, the snapshot
263                         * length will be misleading if you use it to figure
264                         * out why a capture doesn't have all the packet data,
265                         * but there's not much we can do to avoid that.
266                         */
267                        p->snapshot += 14;
268                }
269        } else
270                p->sf.hdrsize = sizeof(struct pcap_sf_pkthdr);
271
272        /*
273         * Allocate a buffer for the packet data.
274         */
275        p->bufsize = p->snapshot;
276        if (p->bufsize <= 0) {
277                /*
278                 * Bogus snapshot length; use 64KiB as a fallback.
279                 */
280                p->bufsize = 65536;
281        }
282        p->buffer = malloc(p->bufsize);
283        if (p->buffer == NULL) {
284                snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
285                return (-1);
286        }
287
288        return (1);
289}
290
291/*
292 * Read and return the next packet from the savefile.  Return the header
293 * in hdr and a pointer to the contents in data.  Return 0 on success, 1
294 * if there were no more packets, and -1 on an error.
295 */
296static int
297pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
298{
299        struct pcap_sf_patched_pkthdr sf_hdr;
300        FILE *fp = p->sf.rfile;
301        size_t amt_read;
302        bpf_u_int32 t;
303
304        /*
305         * Read the packet header; the structure we use as a buffer
306         * is the longer structure for files generated by the patched
307         * libpcap, but if the file has the magic number for an
308         * unpatched libpcap we only read as many bytes as the regular
309         * header has.
310         */
311        amt_read = fread(&sf_hdr, 1, p->sf.hdrsize, fp);
312        if (amt_read != p->sf.hdrsize) {
313                if (ferror(fp)) {
314                        snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
315                            "error reading dump file: %s",
316                            pcap_strerror(errno));
317                        return (-1);
318                } else {
319                        if (amt_read != 0) {
320                                snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
321                                    "truncated dump file; tried to read %lu header bytes, only got %lu",
322                                    (unsigned long)p->sf.hdrsize,
323                                    (unsigned long)amt_read);
324                                return (-1);
325                        }
326                        /* EOF */
327                        return (1);
328                }
329        }
330
331        if (p->sf.swapped) {
332                /* these were written in opposite byte order */
333                hdr->caplen = SWAPLONG(sf_hdr.caplen);
334                hdr->len = SWAPLONG(sf_hdr.len);
335                hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec);
336                hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec);
337        } else {
338                hdr->caplen = sf_hdr.caplen;
339                hdr->len = sf_hdr.len;
340                hdr->ts.tv_sec = sf_hdr.ts.tv_sec;
341                hdr->ts.tv_usec = sf_hdr.ts.tv_usec;
342        }
343        /* Swap the caplen and len fields, if necessary. */
344        switch (p->sf.lengths_swapped) {
345
346        case NOT_SWAPPED:
347                break;
348
349        case MAYBE_SWAPPED:
350                if (hdr->caplen <= hdr->len) {
351                        /*
352                         * The captured length is <= the actual length,
353                         * so presumably they weren't swapped.
354                         */
355                        break;
356                }
357                /* FALLTHROUGH */
358
359        case SWAPPED:
360                t = hdr->caplen;
361                hdr->caplen = hdr->len;
362                hdr->len = t;
363                break;
364        }
365
366        if (hdr->caplen > p->bufsize) {
367                /*
368                 * This can happen due to Solaris 2.3 systems tripping
369                 * over the BUFMOD problem and not setting the snapshot
370                 * correctly in the savefile header.  If the caplen isn't
371                 * grossly wrong, try to salvage.
372                 */
373                static u_char *tp = NULL;
374                static size_t tsize = 0;
375
376                if (hdr->caplen > 65535) {
377                        snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
378                            "bogus savefile header");
379                        return (-1);
380                }
381
382                if (tsize < hdr->caplen) {
383                        tsize = ((hdr->caplen + 1023) / 1024) * 1024;
384                        if (tp != NULL)
385                                free((u_char *)tp);
386                        tp = (u_char *)malloc(tsize);
387                        if (tp == NULL) {
388                                tsize = 0;
389                                snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
390                                    "BUFMOD hack malloc");
391                                return (-1);
392                        }
393                }
394                amt_read = fread((char *)tp, 1, hdr->caplen, fp);
395                if (amt_read != hdr->caplen) {
396                        if (ferror(fp)) {
397                                snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
398                                    "error reading dump file: %s",
399                                    pcap_strerror(errno));
400                        } else {
401                                snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
402                                    "truncated dump file; tried to read %u captured bytes, only got %lu",
403                                    hdr->caplen, (unsigned long)amt_read);
404                        }
405                        return (-1);
406                }
407                /*
408                 * We can only keep up to p->bufsize bytes.  Since
409                 * caplen > p->bufsize is exactly how we got here,
410                 * we know we can only keep the first p->bufsize bytes
411                 * and must drop the remainder.  Adjust caplen accordingly,
412                 * so we don't get confused later as to how many bytes we
413                 * have to play with.
414                 */
415                hdr->caplen = p->bufsize;
416                memcpy(p->buffer, (char *)tp, p->bufsize);
417        } else {
418                /* read the packet itself */
419                amt_read = fread(p->buffer, 1, hdr->caplen, fp);
420                if (amt_read != hdr->caplen) {
421                        if (ferror(fp)) {
422                                snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
423                                    "error reading dump file: %s",
424                                    pcap_strerror(errno));
425                        } else {
426                                snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
427                                    "truncated dump file; tried to read %u captured bytes, only got %lu",
428                                    hdr->caplen, (unsigned long)amt_read);
429                        }
430                        return (-1);
431                }
432        }
433        *data = p->buffer;
434
435        if (p->sf.swapped) {
436                /*
437                 * Convert pseudo-headers from the byte order of
438                 * the host on which the file was saved to our
439                 * byte order, as necessary.
440                 */
441                switch (p->linktype) {
442
443                case DLT_USB_LINUX:
444                        swap_linux_usb_header(hdr, *data, 0);
445                        break;
446
447                case DLT_USB_LINUX_MMAPPED:
448                        swap_linux_usb_header(hdr, *data, 1);
449                        break;
450                }
451        }
452
453        return (0);
454}
455
456static int
457sf_write_header(FILE *fp, int linktype, int thiszone, int snaplen)
458{
459        struct pcap_file_header hdr;
460
461        hdr.magic = TCPDUMP_MAGIC;
462        hdr.version_major = PCAP_VERSION_MAJOR;
463        hdr.version_minor = PCAP_VERSION_MINOR;
464
465        hdr.thiszone = thiszone;
466        hdr.snaplen = snaplen;
467        hdr.sigfigs = 0;
468        hdr.linktype = linktype;
469
470        if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1)
471                return (-1);
472
473        return (0);
474}
475
476/*
477 * Output a packet to the initialized dump file.
478 */
479void
480pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
481{
482        register FILE *f;
483        struct pcap_sf_pkthdr sf_hdr;
484
485        f = (FILE *)user;
486        sf_hdr.ts.tv_sec  = h->ts.tv_sec;
487        sf_hdr.ts.tv_usec = h->ts.tv_usec;
488        sf_hdr.caplen     = h->caplen;
489        sf_hdr.len        = h->len;
490        /* XXX we should check the return status */
491        (void)fwrite(&sf_hdr, sizeof(sf_hdr), 1, f);
492        (void)fwrite(sp, h->caplen, 1, f);
493}
494
495static pcap_dumper_t *
496pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname)
497{
498
499#if defined(WIN32) || defined(MSDOS)
500        /*
501         * If we're writing to the standard output, put it in binary
502         * mode, as savefiles are binary files.
503         *
504         * Otherwise, we turn off buffering.
505         * XXX - why?  And why not on the standard output?
506         */
507        if (f == stdout)
508                SET_BINMODE(f);
509        else
510                setbuf(f, NULL);
511#endif
512        if (sf_write_header(f, linktype, p->tzoff, p->snapshot) == -1) {
513                snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s",
514                    fname, pcap_strerror(errno));
515                if (f != stdout)
516                        (void)fclose(f);
517                return (NULL);
518        }
519        return ((pcap_dumper_t *)f);
520}
521
522/*
523 * Initialize so that sf_write() will output to the file named 'fname'.
524 */
525pcap_dumper_t *
526pcap_dump_open(pcap_t *p, const char *fname)
527{
528        FILE *f;
529        int linktype;
530
531        /*
532         * If this pcap_t hasn't been activated, it doesn't have a
533         * link-layer type, so we can't use it.
534         */
535        if (!p->activated) {
536                snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
537                    "%s: not-yet-activated pcap_t passed to pcap_dump_open",
538                    fname);
539                return (NULL);
540        }
541        linktype = dlt_to_linktype(p->linktype);
542        if (linktype == -1) {
543                snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
544                    "%s: link-layer type %d isn't supported in savefiles",
545                    fname, p->linktype);
546                return (NULL);
547        }
548        linktype |= p->linktype_ext;
549
550        if (fname[0] == '-' && fname[1] == '\0') {
551                f = stdout;
552                fname = "standard output";
553        } else {
554#if !defined(WIN32) && !defined(MSDOS)
555                f = fopen(fname, "w");
556#else
557                f = fopen(fname, "wb");
558#endif
559                if (f == NULL) {
560                        snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
561                            fname, pcap_strerror(errno));
562                        return (NULL);
563                }
564        }
565        return (pcap_setup_dump(p, linktype, f, fname));
566}
567
568/*
569 * Initialize so that sf_write() will output to the given stream.
570 */
571pcap_dumper_t *
572pcap_dump_fopen(pcap_t *p, FILE *f)
573{       
574        int linktype;
575
576        linktype = dlt_to_linktype(p->linktype);
577        if (linktype == -1) {
578                snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
579                    "stream: link-layer type %d isn't supported in savefiles",
580                    p->linktype);
581                return (NULL);
582        }
583        linktype |= p->linktype_ext;
584
585        return (pcap_setup_dump(p, linktype, f, "stream"));
586}
587
588FILE *
589pcap_dump_file(pcap_dumper_t *p)
590{
591        return ((FILE *)p);
592}
593
594long
595pcap_dump_ftell(pcap_dumper_t *p)
596{
597        return (ftell((FILE *)p));
598}
599
600int
601pcap_dump_flush(pcap_dumper_t *p)
602{
603
604        if (fflush((FILE *)p) == EOF)
605                return (-1);
606        else
607                return (0);
608}
609
610void
611pcap_dump_close(pcap_dumper_t *p)
612{
613
614#ifdef notyet
615        if (ferror((FILE *)p))
616                return-an-error;
617        /* XXX should check return from fclose() too */
618#endif
619        (void)fclose((FILE *)p);
620}
Note: See TracBrowser for help on using the repository browser.