xref: /386bsd/usr/src/usr.sbin/tcpdump/savefile.c (revision a2142627)
1 /*
2  * Copyright (c) 1990 The Regents of the University of California.
3  * 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 #ifndef lint
22 static char rcsid[] =
23     "@(#)$Header: savefile.c,v 1.21 91/06/06 23:07:42 mccanne Exp $ (LBL)";
24 #endif
25 
26 /*
27  * savefile.c - supports offline use of tcpdump
28  *	Extraction/creation by Jeffrey Mogul, DECWRL
29  *	Modified by Steve McCanne, LBL.
30  *
31  * Used to save the received packet headers, after filtering, to
32  * a file, and then read them later.
33  * The first record in the file contains saved values for the machine
34  * dependent values so we can print the dump file on any architecture.
35  */
36 
37 #include <stdio.h>
38 #include <sys/types.h>
39 #include <sys/time.h>
40 #include <net/bpf.h>
41 
42 #include "interface.h"
43 #include "savefile.h"
44 
45 #define TCPDUMP_MAGIC 0xa1b2c3d4
46 
47 /*
48  * The first record in the file contains saved values for some
49  * of the flags used in the printout phases of tcpdump.
50  * Many fields here are longs so compilers won't insert unwanted
51  * padding; these files need should be interchangeable across
52  * architectures.
53  */
54 struct file_header {
55 	u_long magic;
56 	u_short version_major;
57 	u_short version_minor;
58 	long thiszone;		/* gmt to local correction */
59 	u_long sigfigs;		/* accuracy of timestamps */
60 	u_long snaplen;		/* max length saved portion of each pkt */
61 	u_long linktype;
62 };
63 
64 int sf_swapped;
65 
66 FILE *sf_readfile;
67 FILE *sf_writefile;
68 
69 static int
sf_write_header(fp,linktype)70 sf_write_header(fp, linktype)
71 	FILE *fp;
72 	int linktype;
73 {
74 	struct file_header hdr;
75 
76 	hdr.magic = TCPDUMP_MAGIC;
77 	hdr.version_major = VERSION_MAJOR;
78 	hdr.version_minor = VERSION_MINOR;
79 
80 	hdr.thiszone = thiszone;
81 	hdr.snaplen = snaplen;
82 	hdr.sigfigs = clock_sigfigs();
83 	hdr.linktype = linktype;
84 
85 	if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1)
86 		return -1;
87 
88 	return 0;
89 }
90 
91 static void
swap_hdr(hp)92 swap_hdr(hp)
93 	struct file_header *hp;
94 {
95 	hp->version_major = SWAPSHORT(hp->version_major);
96 	hp->version_minor = SWAPSHORT(hp->version_minor);
97 	hp->thiszone = SWAPLONG(hp->thiszone);
98 	hp->sigfigs = SWAPLONG(hp->sigfigs);
99 	hp->snaplen = SWAPLONG(hp->snaplen);
100 	hp->linktype = SWAPLONG(hp->linktype);
101 }
102 
103 int
sf_read_init(fname,linktype)104 sf_read_init(fname, linktype)
105 	char *fname;
106 	int *linktype;
107 {
108 	register FILE *fp;
109 	struct file_header hdr;
110 
111 	if (fname[0] == '-' && fname[1] == '\0')
112 		fp = stdin;
113 	else {
114 		fp = fopen(fname, "r");
115 		if (fp == 0) {
116 			perror(fname);
117 			exit(1);
118 		}
119 	}
120 	if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
121 		perror(fname);
122 		exit(1);
123 	}
124 	if (hdr.magic != TCPDUMP_MAGIC) {
125 		if (SWAPLONG(hdr.magic) != TCPDUMP_MAGIC)
126 			return SFERR_BADF;
127 		sf_swapped = 1;
128 		swap_hdr(&hdr);
129 	}
130 	if (hdr.version_major < VERSION_MAJOR)
131 		return SFERR_BADVERSION;
132 
133 	thiszone = hdr.thiszone;
134 	snaplen = hdr.snaplen;
135 	*linktype = hdr.linktype;
136 	timestampinit((int)hdr.sigfigs);
137 
138 	sf_readfile = fp;
139 
140 	return 0;
141 }
142 
143 /*
144  * Print out packets stored in the file initilized by sf_read_init().
145  * If cflag is true, return after 'cnt' packets.
146  */
147 int
sf_read(filtp,cnt,printit)148 sf_read(filtp, cnt, printit)
149 	struct bpf_program *filtp;
150 	int cnt;
151 	void (*printit)();
152 {
153 	struct packet_header h;
154 	u_char *buf;
155 	struct bpf_insn *fcode = filtp->bf_insns;
156 	int status = 0;
157 
158 	buf = (u_char *)malloc(snaplen);
159 
160 	while (status == 0) {
161 		status = sf_next_packet(&h, buf, snaplen);
162 
163 		if (status)
164 			break;
165 
166 		if (bpf_filter(fcode, buf, h.len, h.caplen)) {
167 			if (cflag && --cnt < 0)
168 				break;
169 			(*printit)(buf, &h.ts, h.len, h.caplen);
170 		}
171 	}
172 
173 	if (status == SFERR_EOF)
174 		/* treat EOF's as okay status */
175 		status = 0;
176 
177 	free((char *)buf);
178 	return status;
179 }
180 
181 /*
182  * Read sf_readfile and return the next packet.  Return the header in hdr
183  * and the contents in buf.  Return 0 on success, SFERR_EOF if there were
184  * no more packets, and SFERR_TRUNC if a partial packet was encountered.
185  */
186 int
sf_next_packet(hdr,buf,buflen)187 sf_next_packet(hdr, buf, buflen)
188 	struct packet_header *hdr;
189 	u_char *buf;
190 	int buflen;
191 {
192 	FILE *fp = sf_readfile;
193 
194 	/* read the stamp */
195 	if (fread((char *)hdr, sizeof(struct packet_header), 1, fp) != 1) {
196 		/* probably an EOF, though could be a truncated packet */
197 		return SFERR_EOF;
198 	}
199 
200 	if (sf_swapped) {
201 		/* these were written in opposite byte order */
202 		hdr->caplen = SWAPLONG(hdr->caplen);
203 		hdr->len = SWAPLONG(hdr->len);
204 		hdr->ts.tv_sec = SWAPLONG(hdr->ts.tv_sec);
205 		hdr->ts.tv_usec = SWAPLONG(hdr->ts.tv_usec);
206 	}
207 
208 	if (hdr->caplen > buflen)
209 		return SFERR_BADF;
210 
211 	/* read the packet itself */
212 
213 	if (fread((char *)buf, hdr->caplen, 1, fp) != 1)
214 		return SFERR_TRUNC;
215 
216 	return 0;
217 }
218 
219 /*
220  * Initialize so that sf_write() will output to the file named 'fname'.
221  */
222 void
sf_write_init(fname,linktype)223 sf_write_init(fname, linktype)
224 	char *fname;
225 	int linktype;
226 {
227 	if (fname[0] == '-' && fname[1] == '\0')
228 		sf_writefile = stdout;
229 	else {
230 		sf_writefile = fopen(fname, "w");
231 		if (sf_writefile == 0) {
232 			perror(fname);
233 			exit(1);
234 		}
235 	}
236 	(void)sf_write_header(sf_writefile, linktype);
237 }
238 
239 /*
240  * Output a packet to the intialized dump file.
241  */
242 void
sf_write(sp,tvp,length,caplen)243 sf_write(sp, tvp, length, caplen)
244 	u_char *sp;
245 	struct timeval *tvp;
246 	int length;
247 	int caplen;
248 {
249 	struct packet_header h;
250 
251 	h.ts.tv_sec = tvp->tv_sec;
252 	h.ts.tv_usec = tvp->tv_usec;
253 	h.len = length;
254 	h.caplen = caplen;
255 
256 	(void)fwrite((char *)&h, sizeof h, 1, sf_writefile);
257 	(void)fwrite((char *)sp, caplen, 1, sf_writefile);
258 }
259 
260 void
sf_err(code)261 sf_err(code)
262 	int code;
263 {
264 	switch (code) {
265 	case SFERR_BADVERSION:
266 		error("archaic file format");
267 		/* NOTREACHED */
268 
269 	case SFERR_BADF:
270 		error("bad dump file format");
271 		/* NOTREACHED */
272 
273 	case SFERR_TRUNC:
274 		error("truncated dump file");
275 		/* NOTREACHED */
276 
277 	case SFERR_EOF:
278 		error("EOF reading dump file");
279 		/* NOTREACHED */
280 
281 	default:
282 		error("unknown dump file error code in sf_err()");
283 		/* NOTREACHED */
284 	}
285 	abort();
286 }
287