util.c revision 146773
1/* 2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 3 * The Regents of the University of California. 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 22#ifndef lint 23static const char rcsid[] _U_ = 24 "@(#) $Header: /tcpdump/master/tcpdump/util.c,v 1.95 2005/03/21 11:35:55 hannes Exp $ (LBL)"; 25#endif 26 27#ifdef HAVE_CONFIG_H 28#include "config.h" 29#endif 30 31#include <tcpdump-stdinc.h> 32 33#include <sys/stat.h> 34 35#include <errno.h> 36#ifdef HAVE_FCNTL_H 37#include <fcntl.h> 38#endif 39#include <pcap.h> 40#include <stdio.h> 41#include <stdarg.h> 42#include <stdlib.h> 43#include <string.h> 44 45#include "interface.h" 46 47/* 48 * Print out a filename (or other ascii string). 49 * If ep is NULL, assume no truncation check is needed. 50 * Return true if truncated. 51 */ 52int 53fn_print(register const u_char *s, register const u_char *ep) 54{ 55 register int ret; 56 register u_char c; 57 58 ret = 1; /* assume truncated */ 59 while (ep == NULL || s < ep) { 60 c = *s++; 61 if (c == '\0') { 62 ret = 0; 63 break; 64 } 65 if (!isascii(c)) { 66 c = toascii(c); 67 putchar('M'); 68 putchar('-'); 69 } 70 if (!isprint(c)) { 71 c ^= 0x40; /* DEL to ?, others to alpha */ 72 putchar('^'); 73 } 74 putchar(c); 75 } 76 return(ret); 77} 78 79/* 80 * Print out a counted filename (or other ascii string). 81 * If ep is NULL, assume no truncation check is needed. 82 * Return true if truncated. 83 */ 84int 85fn_printn(register const u_char *s, register u_int n, 86 register const u_char *ep) 87{ 88 register u_char c; 89 90 while (n > 0 && (ep == NULL || s < ep)) { 91 n--; 92 c = *s++; 93 if (!isascii(c)) { 94 c = toascii(c); 95 putchar('M'); 96 putchar('-'); 97 } 98 if (!isprint(c)) { 99 c ^= 0x40; /* DEL to ?, others to alpha */ 100 putchar('^'); 101 } 102 putchar(c); 103 } 104 return (n == 0) ? 0 : 1; 105} 106 107/* 108 * Print the timestamp 109 */ 110void 111ts_print(register const struct timeval *tvp) 112{ 113 register int s; 114 struct tm *tm; 115 time_t Time; 116 static unsigned b_sec; 117 static unsigned b_usec; 118 119 switch (tflag) { 120 121 case 0: /* Default */ 122 s = (tvp->tv_sec + thiszone) % 86400; 123 (void)printf("%02d:%02d:%02d.%06u ", 124 s / 3600, (s % 3600) / 60, s % 60, 125 (unsigned)tvp->tv_usec); 126 break; 127 128 case 1: /* No time stamp */ 129 break; 130 131 case 2: /* Unix timeval style */ 132 (void)printf("%u.%06u ", 133 (unsigned)tvp->tv_sec, 134 (unsigned)tvp->tv_usec); 135 break; 136 137 case 3: /* Microseconds since previous packet */ 138 if (b_sec == 0) { 139 printf("000000 "); 140 } else { 141 int d_usec = tvp->tv_usec - b_usec; 142 int d_sec = tvp->tv_sec - b_sec; 143 144 while (d_usec < 0) { 145 d_usec += 1000000; 146 d_sec--; 147 } 148 if (d_sec) 149 printf("%d. ", d_sec); 150 printf("%06d ", d_usec); 151 } 152 b_sec = tvp->tv_sec; 153 b_usec = tvp->tv_usec; 154 break; 155 156 case 4: /* Default + Date*/ 157 s = (tvp->tv_sec + thiszone) % 86400; 158 Time = (tvp->tv_sec + thiszone) - s; 159 tm = gmtime (&Time); 160 if (!tm) 161 printf("Date fail "); 162 else 163 printf("%04d-%02d-%02d ", 164 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday); 165 printf("%02d:%02d:%02d.%06u ", 166 s / 3600, (s % 3600) / 60, s % 60, (unsigned)tvp->tv_usec); 167 break; 168 } 169} 170 171/* 172 * Print a relative number of seconds (e.g. hold time, prune timer) 173 * in the form 5m1s. This does no truncation, so 32230861 seconds 174 * is represented as 1y1w1d1h1m1s. 175 */ 176void 177relts_print(int secs) 178{ 179 static const char *lengths[] = {"y", "w", "d", "h", "m", "s"}; 180 static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1}; 181 const char **l = lengths; 182 const int *s = seconds; 183 184 if (secs == 0) { 185 (void)printf("0s"); 186 return; 187 } 188 if (secs < 0) { 189 (void)printf("-"); 190 secs = -secs; 191 } 192 while (secs > 0) { 193 if (secs >= *s) { 194 (void)printf("%d%s", secs / *s, *l); 195 secs -= (secs / *s) * *s; 196 } 197 s++; 198 l++; 199 } 200} 201 202/* 203 * this is a generic routine for printing unknown data; 204 * we pass on the linefeed plus indentation string to 205 * get a proper output - returns 0 on error 206 */ 207 208int 209print_unknown_data(const u_char *cp,const char *ident,int len) 210{ 211 hex_print(ident,cp,len); 212 return(1); /* everything is ok */ 213} 214 215/* 216 * Convert a token value to a string; use "fmt" if not found. 217 */ 218const char * 219tok2strbuf(register const struct tok *lp, register const char *fmt, 220 register int v, char *buf, size_t bufsize) 221{ 222 while (lp->s != NULL && lp != NULL) { 223 if (lp->v == v) 224 return (lp->s); 225 ++lp; 226 } 227 if (fmt == NULL) 228 fmt = "#%d"; 229 230 (void)snprintf(buf, bufsize, fmt, v); 231 return (const char *)buf; 232} 233 234/* 235 * Convert a token value to a string; use "fmt" if not found. 236 */ 237const char * 238tok2str(register const struct tok *lp, register const char *fmt, 239 register int v) 240{ 241 static char buf[4][128]; 242 static int idx = 0; 243 char *ret; 244 245 ret = buf[idx]; 246 idx = (idx+1) & 3; 247 return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0])); 248} 249 250/* 251 * Convert a bit token value to a string; use "fmt" if not found. 252 * this is useful for parsing bitfields, the output strings are comma seperated 253 */ 254char * 255bittok2str(register const struct tok *lp, register const char *fmt, 256 register int v) 257{ 258 static char buf[256]; /* our stringbuffer */ 259 int buflen=0; 260 register int rotbit; /* this is the bit we rotate through all bitpositions */ 261 register int tokval; 262 263 while (lp->s != NULL && lp != NULL) { 264 tokval=lp->v; /* load our first value */ 265 rotbit=1; 266 while (rotbit != 0) { 267 /* 268 * lets AND the rotating bit with our token value 269 * and see if we have got a match 270 */ 271 if (tokval == (v&rotbit)) { 272 /* ok we have found something */ 273 buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s, ",lp->s); 274 break; 275 } 276 rotbit=rotbit<<1; /* no match - lets shift and try again */ 277 } 278 lp++; 279 } 280 281 if (buflen != 0) { /* did we find anything */ 282 /* yep, set the the trailing zero 2 bytes before to eliminate the last comma & whitespace */ 283 buf[buflen-2] = '\0'; 284 return (buf); 285 } 286 else { 287 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */ 288 if (fmt == NULL) 289 fmt = "#%d"; 290 (void)snprintf(buf, sizeof(buf), fmt, v); 291 return (buf); 292 } 293} 294 295/* 296 * Convert a value to a string using an array; the macro 297 * tok2strary() in <interface.h> is the public interface to 298 * this function and ensures that the second argument is 299 * correct for bounds-checking. 300 */ 301const char * 302tok2strary_internal(register const char **lp, int n, register const char *fmt, 303 register int v) 304{ 305 static char buf[128]; 306 307 if (v >= 0 && v < n && lp[v] != NULL) 308 return lp[v]; 309 if (fmt == NULL) 310 fmt = "#%d"; 311 (void)snprintf(buf, sizeof(buf), fmt, v); 312 return (buf); 313} 314 315/* 316 * Convert a 32-bit netmask to prefixlen if possible 317 * the function returns the prefix-len; if plen == -1 318 * then conversion was not possible; 319 */ 320 321int 322mask2plen (u_int32_t mask) 323{ 324 u_int32_t bitmasks[33] = { 325 0x00000000, 326 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 327 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000, 328 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, 329 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 330 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, 331 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00, 332 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 333 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff 334 }; 335 int prefix_len = 32; 336 337 /* let's see if we can transform the mask into a prefixlen */ 338 while (prefix_len >= 0) { 339 if (bitmasks[prefix_len] == mask) 340 break; 341 prefix_len--; 342 } 343 return (prefix_len); 344} 345 346/* VARARGS */ 347void 348error(const char *fmt, ...) 349{ 350 va_list ap; 351 352 (void)fprintf(stderr, "%s: ", program_name); 353 va_start(ap, fmt); 354 (void)vfprintf(stderr, fmt, ap); 355 va_end(ap); 356 if (*fmt) { 357 fmt += strlen(fmt); 358 if (fmt[-1] != '\n') 359 (void)fputc('\n', stderr); 360 } 361 exit(1); 362 /* NOTREACHED */ 363} 364 365/* VARARGS */ 366void 367warning(const char *fmt, ...) 368{ 369 va_list ap; 370 371 (void)fprintf(stderr, "%s: WARNING: ", program_name); 372 va_start(ap, fmt); 373 (void)vfprintf(stderr, fmt, ap); 374 va_end(ap); 375 if (*fmt) { 376 fmt += strlen(fmt); 377 if (fmt[-1] != '\n') 378 (void)fputc('\n', stderr); 379 } 380} 381 382/* 383 * Copy arg vector into a new buffer, concatenating arguments with spaces. 384 */ 385char * 386copy_argv(register char **argv) 387{ 388 register char **p; 389 register u_int len = 0; 390 char *buf; 391 char *src, *dst; 392 393 p = argv; 394 if (*p == 0) 395 return 0; 396 397 while (*p) 398 len += strlen(*p++) + 1; 399 400 buf = (char *)malloc(len); 401 if (buf == NULL) 402 error("copy_argv: malloc"); 403 404 p = argv; 405 dst = buf; 406 while ((src = *p++) != NULL) { 407 while ((*dst++ = *src++) != '\0') 408 ; 409 dst[-1] = ' '; 410 } 411 dst[-1] = '\0'; 412 413 return buf; 414} 415 416/* 417 * On Windows, we need to open the file in binary mode, so that 418 * we get all the bytes specified by the size we get from "fstat()". 419 * On UNIX, that's not necessary. O_BINARY is defined on Windows; 420 * we define it as 0 if it's not defined, so it does nothing. 421 */ 422#ifndef O_BINARY 423#define O_BINARY 0 424#endif 425 426char * 427read_infile(char *fname) 428{ 429 register int i, fd, cc; 430 register char *cp; 431 struct stat buf; 432 433 fd = open(fname, O_RDONLY|O_BINARY); 434 if (fd < 0) 435 error("can't open %s: %s", fname, pcap_strerror(errno)); 436 437 if (fstat(fd, &buf) < 0) 438 error("can't stat %s: %s", fname, pcap_strerror(errno)); 439 440 cp = malloc((u_int)buf.st_size + 1); 441 if (cp == NULL) 442 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, 443 fname, pcap_strerror(errno)); 444 cc = read(fd, cp, (u_int)buf.st_size); 445 if (cc < 0) 446 error("read %s: %s", fname, pcap_strerror(errno)); 447 if (cc != buf.st_size) 448 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); 449 450 close(fd); 451 /* replace "# comment" with spaces */ 452 for (i = 0; i < cc; i++) { 453 if (cp[i] == '#') 454 while (i < cc && cp[i] != '\n') 455 cp[i++] = ' '; 456 } 457 cp[cc] = '\0'; 458 return (cp); 459} 460 461void 462safeputs(const char *s) 463{ 464 while (*s) { 465 safeputchar(*s); 466 s++; 467 } 468} 469 470void 471safeputchar(int c) 472{ 473 unsigned char ch; 474 475 ch = (unsigned char)(c & 0xff); 476 if (ch < 0x80 && isprint(ch)) 477 printf("%c", ch); 478 else 479 printf("\\%03o", ch); 480} 481