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

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 8440506 was 8440506, checked in by Chris Johns <chrisj@…>, on 06/15/15 at 07:42:23

Add tcpdump and libpcap.

  • Update the file builder generator to handle generator specific cflags and includes. The tcpdump and libpcap have localised headers and need specific headers paths to see them. There are also module specific flags and these need to be passed to the lex and yacc generators.
  • Add the tcpdump support.
  • 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 <rtems/bsd/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.