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