File: | src/lib/libpcap/savefile.c |
Warning: | line 282, column 3 Null pointer passed as 2nd argument to memory copy function |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: savefile.c,v 1.17 2020/05/27 04:24:01 dlg Exp $ */ | |||
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 | * savefile.c - supports offline use of tcpdump | |||
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 | #include <sys/types.h> | |||
34 | #include <sys/time.h> | |||
35 | ||||
36 | #include <errno(*__errno()).h> | |||
37 | #include <stdio.h> | |||
38 | #include <stdlib.h> | |||
39 | #include <string.h> | |||
40 | #include <unistd.h> | |||
41 | ||||
42 | #ifdef HAVE_OS_PROTO_H | |||
43 | #include "os-proto.h" | |||
44 | #endif | |||
45 | ||||
46 | #include "pcap-int.h" | |||
47 | ||||
48 | #define TCPDUMP_MAGIC0xa1b2c3d4 0xa1b2c3d4 | |||
49 | ||||
50 | /* | |||
51 | * We use the "receiver-makes-right" approach to byte order, | |||
52 | * because time is at a premium when we are writing the file. | |||
53 | * In other words, the pcap_file_header and pcap_pkthdr, | |||
54 | * records are written in host byte order. | |||
55 | * Note that the packets are always written in network byte order. | |||
56 | * | |||
57 | * ntoh[ls] aren't sufficient because we might need to swap on a big-endian | |||
58 | * machine (if the file was written in little-end order). | |||
59 | */ | |||
60 | #define SWAPLONG(y)((((y)&0xff)<<24) | (((y)&0xff00)<<8) | ( ((y)&0xff0000)>>8) | (((y)>>24)&0xff)) \ | |||
61 | ((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) | |||
62 | #define SWAPSHORT(y)( (((y)&0xff)<<8) | ((u_short)((y)&0xff00)>> 8) ) \ | |||
63 | ( (((y)&0xff)<<8) | ((u_short)((y)&0xff00)>>8) ) | |||
64 | ||||
65 | #define SFERR_TRUNC1 1 | |||
66 | #define SFERR_BADVERSION2 2 | |||
67 | #define SFERR_BADF3 3 | |||
68 | #define SFERR_EOF4 4 /* not really an error, just a status */ | |||
69 | ||||
70 | static int | |||
71 | sf_write_header(FILE *fp, int linktype, int thiszone, int snaplen) | |||
72 | { | |||
73 | struct pcap_file_header hdr; | |||
74 | ||||
75 | hdr.magic = TCPDUMP_MAGIC0xa1b2c3d4; | |||
76 | hdr.version_major = PCAP_VERSION_MAJOR2; | |||
77 | hdr.version_minor = PCAP_VERSION_MINOR4; | |||
78 | ||||
79 | hdr.thiszone = thiszone; | |||
80 | hdr.snaplen = snaplen; | |||
81 | hdr.sigfigs = 0; | |||
82 | hdr.linktype = linktype; | |||
83 | ||||
84 | if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) | |||
85 | return (-1); | |||
86 | ||||
87 | return (0); | |||
88 | } | |||
89 | ||||
90 | static void | |||
91 | swap_hdr(struct pcap_file_header *hp) | |||
92 | { | |||
93 | hp->version_major = SWAPSHORT(hp->version_major)( (((hp->version_major)&0xff)<<8) | ((u_short)(( hp->version_major)&0xff00)>>8) ); | |||
94 | hp->version_minor = SWAPSHORT(hp->version_minor)( (((hp->version_minor)&0xff)<<8) | ((u_short)(( hp->version_minor)&0xff00)>>8) ); | |||
95 | hp->thiszone = SWAPLONG(hp->thiszone)((((hp->thiszone)&0xff)<<24) | (((hp->thiszone )&0xff00)<<8) | (((hp->thiszone)&0xff0000)>> 8) | (((hp->thiszone)>>24)&0xff)); | |||
96 | hp->sigfigs = SWAPLONG(hp->sigfigs)((((hp->sigfigs)&0xff)<<24) | (((hp->sigfigs) &0xff00)<<8) | (((hp->sigfigs)&0xff0000)>> 8) | (((hp->sigfigs)>>24)&0xff)); | |||
97 | hp->snaplen = SWAPLONG(hp->snaplen)((((hp->snaplen)&0xff)<<24) | (((hp->snaplen) &0xff00)<<8) | (((hp->snaplen)&0xff0000)>> 8) | (((hp->snaplen)>>24)&0xff)); | |||
98 | hp->linktype = SWAPLONG(hp->linktype)((((hp->linktype)&0xff)<<24) | (((hp->linktype )&0xff00)<<8) | (((hp->linktype)&0xff0000)>> 8) | (((hp->linktype)>>24)&0xff)); | |||
99 | } | |||
100 | ||||
101 | pcap_t * | |||
102 | pcap_open_offline(const char *fname, char *errbuf) | |||
103 | { | |||
104 | pcap_t *p; | |||
105 | FILE *fp; | |||
106 | ||||
107 | if (fname[0] == '-' && fname[1] == '\0') | |||
108 | fp = stdin(&__sF[0]); | |||
109 | else { | |||
110 | fp = fopen(fname, "r"); | |||
111 | if (fp == NULL((void *)0)) { | |||
112 | snprintf(errbuf, PCAP_ERRBUF_SIZE256, "%s: %s", fname, | |||
113 | pcap_strerror(errno(*__errno()))); | |||
114 | return (NULL((void *)0)); | |||
115 | } | |||
116 | } | |||
117 | p = pcap_fopen_offline(fp, errbuf); | |||
118 | if (p == NULL((void *)0)) { | |||
119 | if (fp != stdin(&__sF[0])) | |||
120 | fclose(fp); | |||
121 | } | |||
122 | return (p); | |||
123 | } | |||
124 | ||||
125 | pcap_t * | |||
126 | pcap_fopen_offline(FILE *fp, char *errbuf) | |||
127 | { | |||
128 | pcap_t *p; | |||
129 | struct pcap_file_header hdr; | |||
130 | int linklen; | |||
131 | ||||
132 | p = calloc(1, sizeof(*p)); | |||
133 | if (p == NULL((void *)0)) { | |||
134 | strlcpy(errbuf, "out of swap", PCAP_ERRBUF_SIZE256); | |||
135 | return (NULL((void *)0)); | |||
136 | } | |||
137 | ||||
138 | /* | |||
139 | * Set this field so we don't double-close in pcap_close! | |||
140 | */ | |||
141 | p->fd = -1; | |||
142 | ||||
143 | if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) { | |||
144 | snprintf(errbuf, PCAP_ERRBUF_SIZE256, "fread: %s", | |||
145 | pcap_strerror(errno(*__errno()))); | |||
146 | goto bad; | |||
147 | } | |||
148 | if (hdr.magic != TCPDUMP_MAGIC0xa1b2c3d4) { | |||
149 | if (SWAPLONG(hdr.magic)((((hdr.magic)&0xff)<<24) | (((hdr.magic)&0xff00 )<<8) | (((hdr.magic)&0xff0000)>>8) | (((hdr. magic)>>24)&0xff)) != TCPDUMP_MAGIC0xa1b2c3d4) { | |||
150 | snprintf(errbuf, PCAP_ERRBUF_SIZE256, | |||
151 | "bad dump file format"); | |||
152 | goto bad; | |||
153 | } | |||
154 | p->sf.swapped = 1; | |||
155 | swap_hdr(&hdr); | |||
156 | } | |||
157 | if (hdr.version_major < PCAP_VERSION_MAJOR2) { | |||
158 | snprintf(errbuf, PCAP_ERRBUF_SIZE256, "archaic file format"); | |||
159 | goto bad; | |||
160 | } | |||
161 | p->tzoff = hdr.thiszone; | |||
162 | p->snapshot = hdr.snaplen; | |||
163 | p->linktype = hdr.linktype; | |||
164 | p->sf.rfile = fp; | |||
165 | p->bufsize = hdr.snaplen; | |||
166 | ||||
167 | /* Align link header as required for proper data alignment */ | |||
168 | /* XXX should handle all types */ | |||
169 | switch (p->linktype) { | |||
170 | ||||
171 | case DLT_EN10MB1: | |||
172 | linklen = 14; | |||
173 | break; | |||
174 | ||||
175 | case DLT_FDDI10: | |||
176 | linklen = 13 + 8; /* fddi_header + llc */ | |||
177 | break; | |||
178 | ||||
179 | case DLT_NULL0: | |||
180 | default: | |||
181 | linklen = 0; | |||
182 | break; | |||
183 | } | |||
184 | ||||
185 | if (p->bufsize < 0) | |||
186 | p->bufsize = BPF_MAXBUFSIZE(2 * 1024 * 1024); | |||
187 | p->sf.base = malloc(p->bufsize + BPF_ALIGNMENTsizeof(u_int32_t)); | |||
188 | if (p->sf.base == NULL((void *)0)) { | |||
189 | strlcpy(errbuf, "out of swap", PCAP_ERRBUF_SIZE256); | |||
190 | goto bad; | |||
191 | } | |||
192 | p->buffer = p->sf.base + BPF_ALIGNMENTsizeof(u_int32_t) - (linklen % BPF_ALIGNMENTsizeof(u_int32_t)); | |||
193 | p->sf.version_major = hdr.version_major; | |||
194 | p->sf.version_minor = hdr.version_minor; | |||
195 | #ifdef PCAP_FDDIPAD | |||
196 | /* XXX padding only needed for kernel fcode */ | |||
197 | pcap_fddipad = 0; | |||
198 | #endif | |||
199 | ||||
200 | return (p); | |||
201 | bad: | |||
202 | free(p); | |||
203 | return (NULL((void *)0)); | |||
204 | } | |||
205 | ||||
206 | /* | |||
207 | * Read sf_readfile and return the next packet. Return the header in hdr | |||
208 | * and the contents in buf. Return 0 on success, SFERR_EOF if there were | |||
209 | * no more packets, and SFERR_TRUNC if a partial packet was encountered. | |||
210 | */ | |||
211 | static int | |||
212 | sf_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char *buf, int buflen) | |||
213 | { | |||
214 | FILE *fp = p->sf.rfile; | |||
215 | ||||
216 | /* read the stamp */ | |||
217 | if (fread((char *)hdr, sizeof(struct pcap_pkthdr), 1, fp) != 1) { | |||
218 | /* probably an EOF, though could be a truncated packet */ | |||
219 | return (1); | |||
220 | } | |||
221 | ||||
222 | if (p->sf.swapped) { | |||
223 | /* these were written in opposite byte order */ | |||
224 | hdr->caplen = SWAPLONG(hdr->caplen)((((hdr->caplen)&0xff)<<24) | (((hdr->caplen) &0xff00)<<8) | (((hdr->caplen)&0xff0000)>> 8) | (((hdr->caplen)>>24)&0xff)); | |||
225 | hdr->len = SWAPLONG(hdr->len)((((hdr->len)&0xff)<<24) | (((hdr->len)&0xff00 )<<8) | (((hdr->len)&0xff0000)>>8) | (((hdr ->len)>>24)&0xff)); | |||
226 | hdr->ts.tv_sec = SWAPLONG(hdr->ts.tv_sec)((((hdr->ts.tv_sec)&0xff)<<24) | (((hdr->ts.tv_sec )&0xff00)<<8) | (((hdr->ts.tv_sec)&0xff0000) >>8) | (((hdr->ts.tv_sec)>>24)&0xff)); | |||
227 | hdr->ts.tv_usec = SWAPLONG(hdr->ts.tv_usec)((((hdr->ts.tv_usec)&0xff)<<24) | (((hdr->ts. tv_usec)&0xff00)<<8) | (((hdr->ts.tv_usec)&0xff0000 )>>8) | (((hdr->ts.tv_usec)>>24)&0xff)); | |||
228 | } | |||
229 | /* | |||
230 | * We interchanged the caplen and len fields at version 2.3, | |||
231 | * in order to match the bpf header layout. But unfortunately | |||
232 | * some files were written with version 2.3 in their headers | |||
233 | * but without the interchanged fields. | |||
234 | */ | |||
235 | if (p->sf.version_minor < 3 || | |||
236 | (p->sf.version_minor == 3 && hdr->caplen > hdr->len)) { | |||
237 | int t = hdr->caplen; | |||
238 | hdr->caplen = hdr->len; | |||
239 | hdr->len = t; | |||
240 | } | |||
241 | ||||
242 | if (hdr->caplen > buflen) { | |||
243 | /* | |||
244 | * This can happen due to Solaris 2.3 systems tripping | |||
245 | * over the BUFMOD problem and not setting the snapshot | |||
246 | * correctly in the savefile header. If the caplen isn't | |||
247 | * grossly wrong, try to salvage. | |||
248 | */ | |||
249 | static u_char *tp = NULL((void *)0); | |||
250 | static int tsize = 0; | |||
251 | ||||
252 | if (hdr->caplen > 65535) { | |||
253 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE256, | |||
254 | "bogus savefile header"); | |||
255 | return (-1); | |||
256 | } | |||
257 | ||||
258 | if (tsize < hdr->caplen) { | |||
259 | tsize = ((hdr->caplen + 1023) / 1024) * 1024; | |||
260 | free(tp); | |||
261 | tp = malloc(tsize); | |||
262 | if (tp == NULL((void *)0)) { | |||
263 | tsize = 0; | |||
264 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE256, | |||
265 | "BUFMOD hack malloc"); | |||
266 | return (-1); | |||
267 | } | |||
268 | } | |||
269 | if (fread((char *)tp, hdr->caplen, 1, fp) != 1) { | |||
270 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE256, | |||
271 | "truncated dump file"); | |||
272 | return (-1); | |||
273 | } | |||
274 | /* | |||
275 | * We can only keep up to buflen bytes. Since caplen > buflen | |||
276 | * is exactly how we got here, we know we can only keep the | |||
277 | * first buflen bytes and must drop the remainder. Adjust | |||
278 | * caplen accordingly, so we don't get confused later as | |||
279 | * to how many bytes we have to play with. | |||
280 | */ | |||
281 | hdr->caplen = buflen; | |||
282 | memcpy((char *)buf, (char *)tp, buflen); | |||
| ||||
283 | ||||
284 | } else { | |||
285 | /* read the packet itself */ | |||
286 | ||||
287 | if (fread((char *)buf, hdr->caplen, 1, fp) != 1) { | |||
288 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE256, | |||
289 | "truncated dump file"); | |||
290 | return (-1); | |||
291 | } | |||
292 | } | |||
293 | return (0); | |||
294 | } | |||
295 | ||||
296 | /* | |||
297 | * Print out packets stored in the file initialized by sf_read_init(). | |||
298 | * If cnt > 0, return after 'cnt' packets, otherwise continue until eof. | |||
299 | */ | |||
300 | int | |||
301 | pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) | |||
302 | { | |||
303 | struct bpf_insn *fcode = p->fcode.bf_insns; | |||
304 | int status = 0; | |||
305 | int n = 0; | |||
306 | ||||
307 | while (status == 0) { | |||
| ||||
308 | struct pcap_pkthdr h; | |||
309 | ||||
310 | /* | |||
311 | * Has "pcap_breakloop()" been called? | |||
312 | * If so, return immediately - if we haven't read any | |||
313 | * packets, clear the flag and return -2 to indicate | |||
314 | * that we were told to break out of the loop, otherwise | |||
315 | * leave the flag set, so that the *next* call will break | |||
316 | * out of the loop without having read any packets, and | |||
317 | * return the number of packets we've processed so far. | |||
318 | */ | |||
319 | if (p->break_loop) { | |||
320 | if (n == 0) { | |||
321 | p->break_loop = 0; | |||
322 | return (PCAP_ERROR_BREAK-2); | |||
323 | } else | |||
324 | return (n); | |||
325 | } | |||
326 | ||||
327 | status = sf_next_packet(p, &h, p->buffer, p->bufsize); | |||
328 | if (status) { | |||
329 | if (status == 1) | |||
330 | return (0); | |||
331 | return (status); | |||
332 | } | |||
333 | ||||
334 | if (fcode == NULL((void *)0) || | |||
335 | bpf_filter(fcode, p->buffer, h.len, h.caplen)) { | |||
336 | (*callback)(user, &h, p->buffer); | |||
337 | if (++n >= cnt && cnt > 0) | |||
338 | break; | |||
339 | } | |||
340 | } | |||
341 | /*XXX this breaks semantics tcpslice expects */ | |||
342 | return (n); | |||
343 | } | |||
344 | ||||
345 | /* | |||
346 | * Output a packet to the initialized dump file. | |||
347 | */ | |||
348 | void | |||
349 | pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) | |||
350 | { | |||
351 | FILE *f; | |||
352 | ||||
353 | f = (FILE *)user; | |||
354 | /* XXX we should check the return status */ | |||
355 | (void)fwrite((char *)h, sizeof(*h), 1, f); | |||
356 | (void)fwrite((char *)sp, h->caplen, 1, f); | |||
357 | } | |||
358 | ||||
359 | static pcap_dumper_t * | |||
360 | pcap_setup_dump(pcap_t *p, FILE *f, const char *fname) | |||
361 | { | |||
362 | if (sf_write_header(f, p->linktype, p->tzoff, p->snapshot) == -1) { | |||
363 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE256, "Can't write to %s: %s", | |||
364 | fname, pcap_strerror(errno(*__errno()))); | |||
365 | if (f != stdout(&__sF[1])) | |||
366 | (void)fclose(f); | |||
367 | return (NULL((void *)0)); | |||
368 | } | |||
369 | return ((pcap_dumper_t *)f); | |||
370 | } | |||
371 | ||||
372 | /* | |||
373 | * Initialize so that sf_write() will output to the file named 'fname'. | |||
374 | */ | |||
375 | pcap_dumper_t * | |||
376 | pcap_dump_open(pcap_t *p, const char *fname) | |||
377 | { | |||
378 | FILE *f; | |||
379 | if (fname[0] == '-' && fname[1] == '\0') | |||
380 | f = stdout(&__sF[1]); | |||
381 | else { | |||
382 | f = fopen(fname, "w"); | |||
383 | if (f == NULL((void *)0)) { | |||
384 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE256, "%s: %s", | |||
385 | fname, pcap_strerror(errno(*__errno()))); | |||
386 | return (NULL((void *)0)); | |||
387 | } | |||
388 | } | |||
389 | return (pcap_setup_dump(p, f, fname)); | |||
390 | } | |||
391 | ||||
392 | /* | |||
393 | * Initialize so that sf_write() will output to the given stream. | |||
394 | */ | |||
395 | pcap_dumper_t * | |||
396 | pcap_dump_fopen(pcap_t *p, FILE *f) | |||
397 | { | |||
398 | return (pcap_setup_dump(p, f, "stream")); | |||
399 | } | |||
400 | ||||
401 | FILE * | |||
402 | pcap_dump_file(pcap_dumper_t *p) | |||
403 | { | |||
404 | return ((FILE *)p); | |||
405 | } | |||
406 | ||||
407 | long | |||
408 | pcap_dump_ftell(pcap_dumper_t *p) | |||
409 | { | |||
410 | return (ftell((FILE *)p)); | |||
411 | } | |||
412 | ||||
413 | int | |||
414 | pcap_dump_flush(pcap_dumper_t *p) | |||
415 | { | |||
416 | ||||
417 | if (fflush((FILE *)p) == EOF(-1)) | |||
418 | return (-1); | |||
419 | else | |||
420 | return (0); | |||
421 | } | |||
422 | ||||
423 | void | |||
424 | pcap_dump_close(pcap_dumper_t *p) | |||
425 | { | |||
426 | ||||
427 | #ifdef notyet | |||
428 | if (ferror((FILE *)p)(!__isthreaded ? ((((FILE *)p)->_flags & 0x0040) != 0) : (ferror)((FILE *)p))) | |||
429 | return-an-error; | |||
430 | /* XXX should check return from fclose() too */ | |||
431 | #endif | |||
432 | (void)fclose((FILE *)p); | |||
433 | } |