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.109 2007-01-29 09:59:42 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 47char * ts_format(register int, register int); 48 49/* 50 * Print out a null-terminated filename (or other ascii string). 51 * If ep is NULL, assume no truncation check is needed. 52 * Return true if truncated. 53 */ 54int 55fn_print(register const u_char *s, register const u_char *ep) 56{ 57 register int ret; 58 register u_char c; 59 60 ret = 1; /* assume truncated */ 61 while (ep == NULL || s < ep) { 62 c = *s++; 63 if (c == '\0') { 64 ret = 0; 65 break; 66 } 67 if (!isascii(c)) { 68 c = toascii(c); 69 putchar('M'); 70 putchar('-'); 71 } 72 if (!isprint(c)) { 73 c ^= 0x40; /* DEL to ?, others to alpha */ 74 putchar('^'); 75 } 76 putchar(c); 77 } 78 return(ret); 79} 80 81/* 82 * Print out a counted filename (or other ascii string). 83 * If ep is NULL, assume no truncation check is needed. 84 * Return true if truncated. 85 */ 86int 87fn_printn(register const u_char *s, register u_int n, 88 register const u_char *ep) 89{ 90 register u_char c; 91 92 while (n > 0 && (ep == NULL || s < ep)) { 93 n--; 94 c = *s++; 95 if (!isascii(c)) { 96 c = toascii(c); 97 putchar('M'); 98 putchar('-'); 99 } 100 if (!isprint(c)) { 101 c ^= 0x40; /* DEL to ?, others to alpha */ 102 putchar('^'); 103 } 104 putchar(c); 105 } 106 return (n == 0) ? 0 : 1; 107} 108 109/* 110 * Print out a null-padded filename (or other ascii string). 111 * If ep is NULL, assume no truncation check is needed. 112 * Return true if truncated. 113 */ 114int 115fn_printzp(register const u_char *s, register u_int n, 116 register const u_char *ep) 117{ 118 register int ret; 119 register u_char c; 120 121 ret = 1; /* assume truncated */ 122 while (n > 0 && (ep == NULL || s < ep)) { 123 n--; 124 c = *s++; 125 if (c == '\0') { 126 ret = 0; 127 break; 128 } 129 if (!isascii(c)) { 130 c = toascii(c); 131 putchar('M'); 132 putchar('-'); 133 } 134 if (!isprint(c)) { 135 c ^= 0x40; /* DEL to ?, others to alpha */ 136 putchar('^'); 137 } 138 putchar(c); 139 } 140 return (n == 0) ? 0 : ret; 141} 142 143/* 144 * Format the timestamp 145 */ 146char * 147ts_format(register int sec, register int usec) 148{ 149 static char buf[sizeof("00:00:00.000000")]; 150 (void)snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%06u", 151 sec / 3600, (sec % 3600) / 60, sec % 60, usec); 152 153 return buf; 154} 155 156/* 157 * Print the timestamp 158 */ 159void 160ts_print(register const struct timeval *tvp) 161{ 162 register int s; 163 struct tm *tm; 164 time_t Time; 165 int d_usec; 166 long d_sec; 167 168 /* Default */ 169 if (tflag == 0 || t0flag) { 170 s = (tvp->tv_sec + thiszone) % 86400; 171 (void)printf("%s ", ts_format(s, tvp->tv_usec)); 172 } 173 174 /* Unix timeval style */ 175 if (tflag == 2 || t2flag) { 176 (void)printf("%u.%06u ", 177 (unsigned)tvp->tv_sec, 178 (unsigned)tvp->tv_usec); 179 } 180 181 /* Microseconds since previous packet */ 182 if (tflag == 3 || t3flag) { 183 static unsigned long p_sec = 0; 184 static unsigned p_usec = 0; 185 186 if (p_sec == 0) { 187 /* init timestamp for first packet */ 188 p_usec = tvp->tv_usec; 189 p_sec = tvp->tv_sec; 190 } 191 192 d_usec = tvp->tv_usec - p_usec; 193 d_sec = tvp->tv_sec - p_sec; 194 195 while (d_usec < 0) { 196 d_usec += 1000000; 197 d_sec--; 198 } 199 200 (void)printf("%s ", ts_format((int)d_sec, d_usec)); 201 202 /* set timestamp for last packet */ 203 p_sec = tvp->tv_sec; 204 p_usec = tvp->tv_usec; 205 } 206 207 /* Default + Date */ 208 if (tflag == 4 || t4flag) { 209 s = (tvp->tv_sec + thiszone) % 86400; 210 Time = (tvp->tv_sec + thiszone) - s; 211 tm = gmtime (&Time); 212 if (!tm) 213 printf("Date fail "); 214 else 215 printf("%04d-%02d-%02d %s ", 216 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, 217 ts_format(s, tvp->tv_usec)); 218 } 219 220 /* Microseconds since first packet */ 221 if (tflag == 5 || t5flag) { 222 static unsigned long b_sec = 0; 223 static unsigned b_usec = 0; 224 225 /* init timestamp for first packet */ 226 if (b_sec == 0 && b_usec == 0) { 227 b_usec = tvp->tv_usec; 228 b_sec = tvp->tv_sec; 229 } 230 231 d_usec = tvp->tv_usec - b_usec; 232 d_sec = tvp->tv_sec - b_sec; 233 234 while (d_usec < 0) { 235 d_usec += 1000000; 236 d_sec--; 237 } 238 239 (void)printf("%s ", ts_format((int)d_sec, d_usec)); 240 } 241} 242 243/* 244 * Print a relative number of seconds (e.g. hold time, prune timer) 245 * in the form 5m1s. This does no truncation, so 32230861 seconds 246 * is represented as 1y1w1d1h1m1s. 247 */ 248void 249relts_print(int secs) 250{ 251 static const char *lengths[] = {"y", "w", "d", "h", "m", "s"}; 252 static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1}; 253 const char **l = lengths; 254 const int *s = seconds; 255 256 if (secs == 0) { 257 (void)printf("0s"); 258 return; 259 } 260 if (secs < 0) { 261 (void)printf("-"); 262 secs = -secs; 263 } 264 while (secs > 0) { 265 if (secs >= *s) { 266 (void)printf("%d%s", secs / *s, *l); 267 secs -= (secs / *s) * *s; 268 } 269 s++; 270 l++; 271 } 272} 273 274/* 275 * this is a generic routine for printing unknown data; 276 * we pass on the linefeed plus indentation string to 277 * get a proper output - returns 0 on error 278 */ 279 280int 281print_unknown_data(const u_char *cp,const char *ident,int len) 282{ 283 if (len < 0) { 284 printf("%sDissector error: print_unknown_data called with negative length", 285 ident); 286 return(0); 287 } 288 if (snapend - cp < len) 289 len = (int)(snapend - cp); 290 if (len < 0) { 291 printf("%sDissector error: print_unknown_data called with pointer past end of packet", 292 ident); 293 return(0); 294 } 295 hex_print(ident,cp,len); 296 return(1); /* everything is ok */ 297} 298 299/* 300 * Convert a token value to a string; use "fmt" if not found. 301 */ 302const char * 303tok2strbuf(register const struct tok *lp, register const char *fmt, 304 register int v, char *buf, size_t bufsize) 305{ 306 if (lp != NULL) { 307 while (lp->s != NULL) { 308 if (lp->v == v) 309 return (lp->s); 310 ++lp; 311 } 312 } 313 if (fmt == NULL) 314 fmt = "#%d"; 315 316 (void)snprintf(buf, bufsize, fmt, v); 317 return (const char *)buf; 318} 319 320/* 321 * Convert a token value to a string; use "fmt" if not found. 322 */ 323const char * 324tok2str(register const struct tok *lp, register const char *fmt, 325 register int v) 326{ 327 static char buf[4][128]; 328 static int idx = 0; 329 char *ret; 330 331 ret = buf[idx]; 332 idx = (idx+1) & 3; 333 return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0])); 334} 335 336/* 337 * Convert a bit token value to a string; use "fmt" if not found. 338 * this is useful for parsing bitfields, the output strings are seperated 339 * if the s field is positive. 340 */ 341static char * 342bittok2str_internal(register const struct tok *lp, register const char *fmt, 343 register int v, register int sep) 344{ 345 static char buf[256]; /* our stringbuffer */ 346 int buflen=0; 347 register int rotbit; /* this is the bit we rotate through all bitpositions */ 348 register int tokval; 349 350 while (lp != NULL && lp->s != NULL) { 351 tokval=lp->v; /* load our first value */ 352 rotbit=1; 353 while (rotbit != 0) { 354 /* 355 * lets AND the rotating bit with our token value 356 * and see if we have got a match 357 */ 358 if (tokval == (v&rotbit)) { 359 /* ok we have found something */ 360 buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s%s", 361 lp->s, sep ? ", " : ""); 362 break; 363 } 364 rotbit=rotbit<<1; /* no match - lets shift and try again */ 365 } 366 lp++; 367 } 368 369 /* user didn't want string seperation - no need to cut off trailing seperators */ 370 if (!sep) { 371 return (buf); 372 } 373 374 if (buflen != 0) { /* did we find anything */ 375 /* yep, set the the trailing zero 2 bytes before to eliminate the last comma & whitespace */ 376 buf[buflen-2] = '\0'; 377 return (buf); 378 } 379 else { 380 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */ 381 if (fmt == NULL) 382 fmt = "#%d"; 383 (void)snprintf(buf, sizeof(buf), fmt, v); 384 return (buf); 385 } 386} 387 388/* 389 * Convert a bit token value to a string; use "fmt" if not found. 390 * this is useful for parsing bitfields, the output strings are not seperated. 391 */ 392char * 393bittok2str_nosep(register const struct tok *lp, register const char *fmt, 394 register int v) 395{ 396 return (bittok2str_internal(lp, fmt, v, 0)); 397} 398 399/* 400 * Convert a bit token value to a string; use "fmt" if not found. 401 * this is useful for parsing bitfields, the output strings are comma seperated. 402 */ 403char * 404bittok2str(register const struct tok *lp, register const char *fmt, 405 register int v) 406{ 407 return (bittok2str_internal(lp, fmt, v, 1)); 408} 409 410/* 411 * Convert a value to a string using an array; the macro 412 * tok2strary() in <interface.h> is the public interface to 413 * this function and ensures that the second argument is 414 * correct for bounds-checking. 415 */ 416const char * 417tok2strary_internal(register const char **lp, int n, register const char *fmt, 418 register int v) 419{ 420 static char buf[128]; 421 422 if (v >= 0 && v < n && lp[v] != NULL) 423 return lp[v]; 424 if (fmt == NULL) 425 fmt = "#%d"; 426 (void)snprintf(buf, sizeof(buf), fmt, v); 427 return (buf); 428} 429 430/* 431 * Convert a 32-bit netmask to prefixlen if possible 432 * the function returns the prefix-len; if plen == -1 433 * then conversion was not possible; 434 */ 435 436int 437mask2plen(u_int32_t mask) 438{ 439 u_int32_t bitmasks[33] = { 440 0x00000000, 441 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 442 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000, 443 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, 444 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 445 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, 446 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00, 447 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 448 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff 449 }; 450 int prefix_len = 32; 451 452 /* let's see if we can transform the mask into a prefixlen */ 453 while (prefix_len >= 0) { 454 if (bitmasks[prefix_len] == mask) 455 break; 456 prefix_len--; 457 } 458 return (prefix_len); 459} 460 461#ifdef INET6 462int 463mask62plen(const u_char *mask) 464{ 465 u_char bitmasks[9] = { 466 0x00, 467 0x80, 0xc0, 0xe0, 0xf0, 468 0xf8, 0xfc, 0xfe, 0xff 469 }; 470 int byte; 471 int cidr_len = 0; 472 473 for (byte = 0; byte < 16; byte++) { 474 u_int bits; 475 476 for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) { 477 if (mask[byte] == bitmasks[bits]) { 478 cidr_len += bits; 479 break; 480 } 481 } 482 483 if (mask[byte] != 0xff) 484 break; 485 } 486 return (cidr_len); 487} 488#endif /* INET6 */ 489 490/* VARARGS */ 491void 492error(const char *fmt, ...) 493{ 494 va_list ap; 495 496 (void)fprintf(stderr, "%s: ", program_name); 497 va_start(ap, fmt); 498 (void)vfprintf(stderr, fmt, ap); 499 va_end(ap); 500 if (*fmt) { 501 fmt += strlen(fmt); 502 if (fmt[-1] != '\n') 503 (void)fputc('\n', stderr); 504 } 505 exit(1); 506 /* NOTREACHED */ 507} 508 509/* VARARGS */ 510void 511warning(const char *fmt, ...) 512{ 513 va_list ap; 514 515 (void)fprintf(stderr, "%s: WARNING: ", program_name); 516 va_start(ap, fmt); 517 (void)vfprintf(stderr, fmt, ap); 518 va_end(ap); 519 if (*fmt) { 520 fmt += strlen(fmt); 521 if (fmt[-1] != '\n') 522 (void)fputc('\n', stderr); 523 } 524} 525 526/* 527 * Copy arg vector into a new buffer, concatenating arguments with spaces. 528 */ 529char * 530copy_argv(register char **argv) 531{ 532 register char **p; 533 register u_int len = 0; 534 char *buf; 535 char *src, *dst; 536 537 p = argv; 538 if (*p == 0) 539 return 0; 540 541 while (*p) 542 len += strlen(*p++) + 1; 543 544 buf = (char *)malloc(len); 545 if (buf == NULL) 546 error("copy_argv: malloc"); 547 548 p = argv; 549 dst = buf; 550 while ((src = *p++) != NULL) { 551 while ((*dst++ = *src++) != '\0') 552 ; 553 dst[-1] = ' '; 554 } 555 dst[-1] = '\0'; 556 557 return buf; 558} 559 560/* 561 * On Windows, we need to open the file in binary mode, so that 562 * we get all the bytes specified by the size we get from "fstat()". 563 * On UNIX, that's not necessary. O_BINARY is defined on Windows; 564 * we define it as 0 if it's not defined, so it does nothing. 565 */ 566#ifndef O_BINARY 567#define O_BINARY 0 568#endif 569 570char * 571read_infile(char *fname) 572{ 573 register int i, fd, cc; 574 register char *cp; 575 struct stat buf; 576 577 fd = open(fname, O_RDONLY|O_BINARY); 578 if (fd < 0) 579 error("can't open %s: %s", fname, pcap_strerror(errno)); 580 581 if (fstat(fd, &buf) < 0) 582 error("can't stat %s: %s", fname, pcap_strerror(errno)); 583 584 cp = malloc((u_int)buf.st_size + 1); 585 if (cp == NULL) 586 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, 587 fname, pcap_strerror(errno)); 588 cc = (int)read(fd, cp, (u_int)buf.st_size); 589 if (cc < 0) 590 error("read %s: %s", fname, pcap_strerror(errno)); 591 if (cc != buf.st_size) 592 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); 593 594 close(fd); 595 /* replace "# comment" with spaces */ 596 for (i = 0; i < cc; i++) { 597 if (cp[i] == '#') 598 while (i < cc && cp[i] != '\n') 599 cp[i++] = ' '; 600 } 601 cp[cc] = '\0'; 602 return (cp); 603} 604 605void 606safeputs(const char *s, int maxlen) 607{ 608 int idx = 0; 609 610 while (*s && idx < maxlen) { 611 safeputchar(*s); 612 idx++; 613 s++; 614 } 615} 616 617void 618safeputchar(int c) 619{ 620 unsigned char ch; 621 622 ch = (unsigned char)(c & 0xff); 623 if (ch < 0x80 && isprint(ch)) 624 printf("%c", ch); 625 else 626 printf("\\0x%02x", ch); 627} 628