aboutsummaryrefslogtreecommitdiffstats
path: root/pcapio.c
blob: bed260c0ae775d47a7755330fa86fb7caaf03d6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/* pcapio.c
 * Our own private code for writing libpcap files when capturing.
 *
 * We have these because we want a way to open a stream for output given
 * only a file descriptor.  libpcap 0.9[.x] has "pcap_dump_fopen()", which
 * provides that, but
 *
 *	1) earlier versions of libpcap doesn't have it
 *
 * and
 *
 *	2) WinPcap doesn't have it, because a file descriptor opened
 *	   by code built for one version of the MSVC++ C library
 *	   can't be used by library routines built for another version
 *	   (e.g., threaded vs. unthreaded).
 *
 * Libpcap's pcap_dump() also doesn't return any error indications.
 *
 * $Id$
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * Derived from code in the Wiretap Library
 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef HAVE_LIBPCAP

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

#include <pcap.h>

#include <glib.h>

#include "pcapio.h"

/* Magic numbers in "libpcap" files.

   "libpcap" file records are written in the byte order of the host that
   writes them, and the reader is expected to fix this up.

   PCAP_MAGIC is the magic number, in host byte order; PCAP_SWAPPED_MAGIC
   is a byte-swapped version of that.

   PCAP_NSEC_MAGIC is for Ulf Lamping's modified "libpcap" format,
   which uses the same common file format as PCAP_MAGIC, but the 
   timestamps are saved in nanosecond resolution instead of microseconds.
   PCAP_SWAPPED_NSEC_MAGIC is a byte-swapped version of that. */
#define	PCAP_MAGIC			0xa1b2c3d4
#define	PCAP_SWAPPED_MAGIC		0xd4c3b2a1
#define	PCAP_NSEC_MAGIC			0xa1b23c4d
#define	PCAP_SWAPPED_NSEC_MAGIC		0x4d3cb2a1

/* "libpcap" file header. */
struct pcap_hdr {
	guint32 magic;		/* magic number */
	guint16	version_major;	/* major version number */
	guint16	version_minor;	/* minor version number */
	gint32	thiszone;	/* GMT to local correction */
	guint32	sigfigs;	/* accuracy of timestamps */
	guint32	snaplen;	/* max length of captured packets, in octets */
	guint32	network;	/* data link type */
};

/* "libpcap" record header. */
struct pcaprec_hdr {
	guint32	ts_sec;		/* timestamp seconds */
	guint32	ts_usec;	/* timestamp microseconds (nsecs for PCAP_NSEC_MAGIC) */
	guint32	incl_len;	/* number of octets of packet saved in file */
	guint32	orig_len;	/* actual length of packet */
};

/* Returns a FILE * to write to on success, NULL on failure */
FILE *
libpcap_fdopen(int fd, int *err)
{
	FILE *fp;

	fp = fdopen(fd, "wb");
	if (fp == NULL) {
		*err = errno;
	}
	return fp;
}

/* Write the file header to a dump file.
   Returns TRUE on success, FALSE on failure.
   Sets "*err" to an error code, or 0 for a short write, on failure*/
gboolean
libpcap_write_file_header(FILE *fp, int linktype, int snaplen, long *bytes_written, int *err)
{
	struct pcap_hdr file_hdr;
	size_t nwritten;

	file_hdr.magic = PCAP_MAGIC;
	/* current "libpcap" format is 2.4 */
	file_hdr.version_major = 2;
	file_hdr.version_minor = 4;
	file_hdr.thiszone = 0;	/* XXX - current offset? */
	file_hdr.sigfigs = 0;	/* unknown, but also apparently unused */
	file_hdr.snaplen = snaplen;
	file_hdr.network = linktype;
	nwritten = fwrite(&file_hdr, 1, sizeof(file_hdr), fp);
	if (nwritten != sizeof(file_hdr)) {
		if (nwritten == 0 && ferror(fp))
			*err = errno;
		else
			*err = 0;	/* short write */
		return FALSE;
	}
	*bytes_written += sizeof(file_hdr);

	return TRUE;
}

/* Write a record for a packet to a dump file.
   Returns TRUE on success, FALSE on failure. */
gboolean
libpcap_write_packet(FILE *fp, const struct pcap_pkthdr *phdr, const u_char *pd,
    long *bytes_written, int *err)
{
	struct pcaprec_hdr rec_hdr;
	size_t nwritten;

	rec_hdr.ts_sec = phdr->ts.tv_sec;
	rec_hdr.ts_usec = phdr->ts.tv_usec;
	rec_hdr.incl_len = phdr->caplen;
	rec_hdr.orig_len = phdr->len;
	nwritten = fwrite(&rec_hdr, 1, sizeof rec_hdr, fp);
	if (nwritten != sizeof rec_hdr) {
		if (nwritten == 0 && ferror(fp))
			*err = errno;
		else
			*err = 0;	/* short write */
		return FALSE;
	}
	*bytes_written += sizeof rec_hdr;

	nwritten = fwrite(pd, 1, phdr->caplen, fp);
	if (nwritten != phdr->caplen) {
		if (nwritten == 0 && ferror(fp))
			*err = errno;
		else
			*err = 0;	/* short write */
		return FALSE;
	}
	*bytes_written += phdr->caplen;
	return TRUE;
}

gboolean
libpcap_dump_flush(FILE *pd, int *err)
{
	if (fflush(pd) == EOF) {
		if (err != NULL)
			*err = errno;
		return FALSE;
	}
	return TRUE;
}

gboolean
libpcap_dump_close(FILE *pd, int *err)
{
	if (fclose(pd) == EOF) {
		if (err != NULL)
			*err = errno;
		return FALSE;
	}
	return TRUE;
}

#endif /* HAVE_LIBPCAP */