| 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 | } |