1 /* $OpenBSD: savefile.c,v 1.12 2014/03/14 03:45:41 lteo 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.h> 37 #include <memory.h> 38 #include <stdio.h> 39 #include <stdlib.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_MAGIC 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) \ 61 ((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) 62 #define SWAPSHORT(y) \ 63 ( (((y)&0xff)<<8) | ((u_short)((y)&0xff00)>>8) ) 64 65 #define SFERR_TRUNC 1 66 #define SFERR_BADVERSION 2 67 #define SFERR_BADF 3 68 #define SFERR_EOF 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_MAGIC; 76 hdr.version_major = PCAP_VERSION_MAJOR; 77 hdr.version_minor = PCAP_VERSION_MINOR; 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); 94 hp->version_minor = SWAPSHORT(hp->version_minor); 95 hp->thiszone = SWAPLONG(hp->thiszone); 96 hp->sigfigs = SWAPLONG(hp->sigfigs); 97 hp->snaplen = SWAPLONG(hp->snaplen); 98 hp->linktype = SWAPLONG(hp->linktype); 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; 109 else { 110 fp = fopen(fname, "r"); 111 if (fp == NULL) { 112 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname, 113 pcap_strerror(errno)); 114 return (NULL); 115 } 116 } 117 p = pcap_fopen_offline(fp, errbuf); 118 if (p == NULL) { 119 if (fp != stdin) 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) { 134 strlcpy(errbuf, "out of swap", PCAP_ERRBUF_SIZE); 135 return (NULL); 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_SIZE, "fread: %s", 145 pcap_strerror(errno)); 146 goto bad; 147 } 148 if (hdr.magic != TCPDUMP_MAGIC) { 149 if (SWAPLONG(hdr.magic) != TCPDUMP_MAGIC) { 150 snprintf(errbuf, PCAP_ERRBUF_SIZE, 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_MAJOR) { 158 snprintf(errbuf, PCAP_ERRBUF_SIZE, "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_EN10MB: 172 linklen = 14; 173 break; 174 175 case DLT_FDDI: 176 linklen = 13 + 8; /* fddi_header + llc */ 177 break; 178 179 case DLT_NULL: 180 default: 181 linklen = 0; 182 break; 183 } 184 185 if (p->bufsize < 0) 186 p->bufsize = BPF_MAXBUFSIZE; 187 p->sf.base = (u_char *)malloc(p->bufsize + BPF_ALIGNMENT); 188 if (p->sf.base == NULL) { 189 strlcpy(errbuf, "out of swap", PCAP_ERRBUF_SIZE); 190 goto bad; 191 } 192 p->buffer = p->sf.base + BPF_ALIGNMENT - (linklen % BPF_ALIGNMENT); 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); 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); 225 hdr->len = SWAPLONG(hdr->len); 226 hdr->ts.tv_sec = SWAPLONG(hdr->ts.tv_sec); 227 hdr->ts.tv_usec = SWAPLONG(hdr->ts.tv_usec); 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; 250 static int tsize = 0; 251 252 if (hdr->caplen > 65535) { 253 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 254 "bogus savefile header"); 255 return (-1); 256 } 257 258 if (tsize < hdr->caplen) { 259 tsize = ((hdr->caplen + 1023) / 1024) * 1024; 260 if (tp != NULL) 261 free((u_char *)tp); 262 tp = (u_char *)malloc(tsize); 263 if (tp == NULL) { 264 tsize = 0; 265 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 266 "BUFMOD hack malloc"); 267 return (-1); 268 } 269 } 270 if (fread((char *)tp, hdr->caplen, 1, fp) != 1) { 271 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 272 "truncated dump file"); 273 return (-1); 274 } 275 /* 276 * We can only keep up to buflen bytes. Since caplen > buflen 277 * is exactly how we got here, we know we can only keep the 278 * first buflen bytes and must drop the remainder. Adjust 279 * caplen accordingly, so we don't get confused later as 280 * to how many bytes we have to play with. 281 */ 282 hdr->caplen = buflen; 283 memcpy((char *)buf, (char *)tp, buflen); 284 285 } else { 286 /* read the packet itself */ 287 288 if (fread((char *)buf, hdr->caplen, 1, fp) != 1) { 289 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 290 "truncated dump file"); 291 return (-1); 292 } 293 } 294 return (0); 295 } 296 297 /* 298 * Print out packets stored in the file initialized by sf_read_init(). 299 * If cnt > 0, return after 'cnt' packets, otherwise continue until eof. 300 */ 301 int 302 pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 303 { 304 struct bpf_insn *fcode = p->fcode.bf_insns; 305 int status = 0; 306 int n = 0; 307 308 while (status == 0) { 309 struct pcap_pkthdr h; 310 311 status = sf_next_packet(p, &h, p->buffer, p->bufsize); 312 if (status) { 313 if (status == 1) 314 return (0); 315 return (status); 316 } 317 318 if (fcode == NULL || 319 bpf_filter(fcode, p->buffer, h.len, h.caplen)) { 320 (*callback)(user, &h, p->buffer); 321 if (++n >= cnt && cnt > 0) 322 break; 323 } 324 } 325 /*XXX this breaks semantics tcpslice expects */ 326 return (n); 327 } 328 329 /* 330 * Output a packet to the initialized dump file. 331 */ 332 void 333 pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) 334 { 335 register FILE *f; 336 337 f = (FILE *)user; 338 /* XXX we should check the return status */ 339 (void)fwrite((char *)h, sizeof(*h), 1, f); 340 (void)fwrite((char *)sp, h->caplen, 1, f); 341 } 342 343 static pcap_dumper_t * 344 pcap_setup_dump(pcap_t *p, FILE *f, const char *fname) 345 { 346 if (sf_write_header(f, p->linktype, p->tzoff, p->snapshot) == -1) { 347 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", 348 fname, pcap_strerror(errno)); 349 if (f != stdout) 350 (void)fclose(f); 351 return (NULL); 352 } 353 return ((pcap_dumper_t *)f); 354 } 355 356 /* 357 * Initialize so that sf_write() will output to the file named 'fname'. 358 */ 359 pcap_dumper_t * 360 pcap_dump_open(pcap_t *p, const char *fname) 361 { 362 FILE *f; 363 if (fname[0] == '-' && fname[1] == '\0') 364 f = stdout; 365 else { 366 f = fopen(fname, "w"); 367 if (f == NULL) { 368 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", 369 fname, pcap_strerror(errno)); 370 return (NULL); 371 } 372 } 373 return (pcap_setup_dump(p, f, fname)); 374 } 375 376 /* 377 * Initialize so that sf_write() will output to the given stream. 378 */ 379 pcap_dumper_t * 380 pcap_dump_fopen(pcap_t *p, FILE *f) 381 { 382 return (pcap_setup_dump(p, f, "stream")); 383 } 384 385 FILE * 386 pcap_dump_file(pcap_dumper_t *p) 387 { 388 return ((FILE *)p); 389 } 390 391 long 392 pcap_dump_ftell(pcap_dumper_t *p) 393 { 394 return (ftell((FILE *)p)); 395 } 396 397 int 398 pcap_dump_flush(pcap_dumper_t *p) 399 { 400 401 if (fflush((FILE *)p) == EOF) 402 return (-1); 403 else 404 return (0); 405 } 406 407 void 408 pcap_dump_close(pcap_dumper_t *p) 409 { 410 411 #ifdef notyet 412 if (ferror((FILE *)p)) 413 return-an-error; 414 /* XXX should check return from fclose() too */ 415 #endif 416 (void)fclose((FILE *)p); 417 } 418