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