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 /* 23 * txtproto_print() derived from original code by Hannes Gredler 24 * (hannes (at) juniper.net): 25 * 26 * Redistribution and use in source and binary forms, with or without 27 * modification, are permitted provided that: (1) source code 28 * distributions retain the above copyright notice and this paragraph 29 * in its entirety, and (2) distributions including binary code include 30 * the above copyright notice and this paragraph in its entirety in 31 * the documentation or other materials provided with the distribution. 32 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 33 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 34 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 35 * FOR A PARTICULAR PURPOSE. 36 */ 37 38 #define NETDISSECT_REWORKED 39 #ifdef HAVE_CONFIG_H 40 #include "config.h" 41 #endif 42 43 #include <tcpdump-stdinc.h> 44 45 #include <sys/stat.h> 46 47 #ifdef HAVE_FCNTL_H 48 #include <fcntl.h> 49 #endif 50 #include <stdio.h> 51 #include <stdarg.h> 52 #include <stdlib.h> 53 #include <string.h> 54 55 #include "interface.h" 56 57 /* 58 * Print out a null-terminated filename (or other ascii string). 59 * If ep is NULL, assume no truncation check is needed. 60 * Return true if truncated. 61 */ 62 int 63 fn_print(netdissect_options *ndo, 64 register const u_char *s, register const u_char *ep) 65 { 66 register int ret; 67 register u_char c; 68 69 ret = 1; /* assume truncated */ 70 while (ep == NULL || s < ep) { 71 c = *s++; 72 if (c == '\0') { 73 ret = 0; 74 break; 75 } 76 if (!ND_ISASCII(c)) { 77 c = ND_TOASCII(c); 78 ND_PRINT((ndo, "M-")); 79 } 80 if (!ND_ISPRINT(c)) { 81 c ^= 0x40; /* DEL to ?, others to alpha */ 82 ND_PRINT((ndo, "^")); 83 } 84 ND_PRINT((ndo, "%c", c)); 85 } 86 return(ret); 87 } 88 89 /* 90 * Print out a counted filename (or other ascii string). 91 * If ep is NULL, assume no truncation check is needed. 92 * Return true if truncated. 93 */ 94 int 95 fn_printn(netdissect_options *ndo, 96 register const u_char *s, register u_int n, register const u_char *ep) 97 { 98 register u_char c; 99 100 while (n > 0 && (ep == NULL || s < ep)) { 101 n--; 102 c = *s++; 103 if (!ND_ISASCII(c)) { 104 c = ND_TOASCII(c); 105 ND_PRINT((ndo, "M-")); 106 } 107 if (!ND_ISPRINT(c)) { 108 c ^= 0x40; /* DEL to ?, others to alpha */ 109 ND_PRINT((ndo, "^")); 110 } 111 ND_PRINT((ndo, "%c", c)); 112 } 113 return (n == 0) ? 0 : 1; 114 } 115 116 /* 117 * Print out a null-padded filename (or other ascii string). 118 * If ep is NULL, assume no truncation check is needed. 119 * Return true if truncated. 120 */ 121 int 122 fn_printzp(netdissect_options *ndo, 123 register const u_char *s, register u_int n, 124 register const u_char *ep) 125 { 126 register int ret; 127 register u_char c; 128 129 ret = 1; /* assume truncated */ 130 while (n > 0 && (ep == NULL || s < ep)) { 131 n--; 132 c = *s++; 133 if (c == '\0') { 134 ret = 0; 135 break; 136 } 137 if (!ND_ISASCII(c)) { 138 c = ND_TOASCII(c); 139 ND_PRINT((ndo, "M-")); 140 } 141 if (!ND_ISPRINT(c)) { 142 c ^= 0x40; /* DEL to ?, others to alpha */ 143 ND_PRINT((ndo, "^")); 144 } 145 ND_PRINT((ndo, "%c", c)); 146 } 147 return (n == 0) ? 0 : ret; 148 } 149 150 /* 151 * Format the timestamp 152 */ 153 static char * 154 ts_format(netdissect_options *ndo 155 #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION 156 _U_ 157 #endif 158 , int sec, int usec) 159 { 160 static char buf[sizeof("00:00:00.000000000")]; 161 const char *format; 162 163 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION 164 switch (ndo->ndo_tstamp_precision) { 165 166 case PCAP_TSTAMP_PRECISION_MICRO: 167 format = "%02d:%02d:%02d.%06u"; 168 break; 169 170 case PCAP_TSTAMP_PRECISION_NANO: 171 format = "%02d:%02d:%02d.%09u"; 172 break; 173 174 default: 175 format = "%02d:%02d:%02d.{unknown precision}"; 176 break; 177 } 178 #else 179 format = "%02d:%02d:%02d.%06u"; 180 #endif 181 182 snprintf(buf, sizeof(buf), format, 183 sec / 3600, (sec % 3600) / 60, sec % 60, usec); 184 185 return buf; 186 } 187 188 /* 189 * Print the timestamp 190 */ 191 void 192 ts_print(netdissect_options *ndo, 193 register const struct timeval *tvp) 194 { 195 register int s; 196 struct tm *tm; 197 time_t Time; 198 static unsigned b_sec; 199 static unsigned b_usec; 200 int d_usec; 201 int d_sec; 202 203 switch (ndo->ndo_tflag) { 204 205 case 0: /* Default */ 206 s = (tvp->tv_sec + thiszone) % 86400; 207 ND_PRINT((ndo, "%s ", ts_format(ndo, s, tvp->tv_usec))); 208 break; 209 210 case 1: /* No time stamp */ 211 break; 212 213 case 2: /* Unix timeval style */ 214 ND_PRINT((ndo, "%u.%06u ", 215 (unsigned)tvp->tv_sec, 216 (unsigned)tvp->tv_usec)); 217 break; 218 219 case 3: /* Microseconds since previous packet */ 220 case 5: /* Microseconds since first packet */ 221 if (b_sec == 0) { 222 /* init timestamp for first packet */ 223 b_usec = tvp->tv_usec; 224 b_sec = tvp->tv_sec; 225 } 226 227 d_usec = tvp->tv_usec - b_usec; 228 d_sec = tvp->tv_sec - b_sec; 229 230 while (d_usec < 0) { 231 d_usec += 1000000; 232 d_sec--; 233 } 234 235 ND_PRINT((ndo, "%s ", ts_format(ndo, d_sec, d_usec))); 236 237 if (ndo->ndo_tflag == 3) { /* set timestamp for last packet */ 238 b_sec = tvp->tv_sec; 239 b_usec = tvp->tv_usec; 240 } 241 break; 242 243 case 4: /* Default + Date*/ 244 s = (tvp->tv_sec + thiszone) % 86400; 245 Time = (tvp->tv_sec + thiszone) - s; 246 tm = gmtime (&Time); 247 if (!tm) 248 ND_PRINT((ndo, "Date fail ")); 249 else 250 ND_PRINT((ndo, "%04d-%02d-%02d %s ", 251 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, 252 ts_format(ndo, s, tvp->tv_usec))); 253 break; 254 } 255 } 256 257 /* 258 * Print a relative number of seconds (e.g. hold time, prune timer) 259 * in the form 5m1s. This does no truncation, so 32230861 seconds 260 * is represented as 1y1w1d1h1m1s. 261 */ 262 void 263 relts_print(netdissect_options *ndo, 264 int secs) 265 { 266 static const char *lengths[] = {"y", "w", "d", "h", "m", "s"}; 267 static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1}; 268 const char **l = lengths; 269 const int *s = seconds; 270 271 if (secs == 0) { 272 ND_PRINT((ndo, "0s")); 273 return; 274 } 275 if (secs < 0) { 276 ND_PRINT((ndo, "-")); 277 secs = -secs; 278 } 279 while (secs > 0) { 280 if (secs >= *s) { 281 ND_PRINT((ndo, "%d%s", secs / *s, *l)); 282 secs -= (secs / *s) * *s; 283 } 284 s++; 285 l++; 286 } 287 } 288 289 /* 290 * this is a generic routine for printing unknown data; 291 * we pass on the linefeed plus indentation string to 292 * get a proper output - returns 0 on error 293 */ 294 295 int 296 print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len) 297 { 298 if (len < 0) { 299 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length", 300 ident)); 301 return(0); 302 } 303 if (ndo->ndo_snapend - cp < len) 304 len = ndo->ndo_snapend - cp; 305 if (len < 0) { 306 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet", 307 ident)); 308 return(0); 309 } 310 hex_print(ndo, ident,cp,len); 311 return(1); /* everything is ok */ 312 } 313 314 /* 315 * Convert a token value to a string; use "fmt" if not found. 316 */ 317 const char * 318 tok2strbuf(register const struct tok *lp, register const char *fmt, 319 register u_int v, char *buf, size_t bufsize) 320 { 321 if (lp != NULL) { 322 while (lp->s != NULL) { 323 if (lp->v == v) 324 return (lp->s); 325 ++lp; 326 } 327 } 328 if (fmt == NULL) 329 fmt = "#%d"; 330 331 (void)snprintf(buf, bufsize, fmt, v); 332 return (const char *)buf; 333 } 334 335 /* 336 * Convert a token value to a string; use "fmt" if not found. 337 */ 338 const char * 339 tok2str(register const struct tok *lp, register const char *fmt, 340 register u_int v) 341 { 342 static char buf[4][128]; 343 static int idx = 0; 344 char *ret; 345 346 ret = buf[idx]; 347 idx = (idx+1) & 3; 348 return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0])); 349 } 350 351 /* 352 * Convert a bit token value to a string; use "fmt" if not found. 353 * this is useful for parsing bitfields, the output strings are seperated 354 * if the s field is positive. 355 */ 356 static char * 357 bittok2str_internal(register const struct tok *lp, register const char *fmt, 358 register u_int v, const char *sep) 359 { 360 static char buf[256]; /* our stringbuffer */ 361 int buflen=0; 362 register u_int rotbit; /* this is the bit we rotate through all bitpositions */ 363 register u_int tokval; 364 const char * sepstr = ""; 365 366 while (lp != NULL && lp->s != NULL) { 367 tokval=lp->v; /* load our first value */ 368 rotbit=1; 369 while (rotbit != 0) { 370 /* 371 * lets AND the rotating bit with our token value 372 * and see if we have got a match 373 */ 374 if (tokval == (v&rotbit)) { 375 /* ok we have found something */ 376 buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s%s", 377 sepstr, lp->s); 378 sepstr = sep; 379 break; 380 } 381 rotbit=rotbit<<1; /* no match - lets shift and try again */ 382 } 383 lp++; 384 } 385 386 if (buflen == 0) 387 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */ 388 (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%08x" : fmt, v); 389 return (buf); 390 } 391 392 /* 393 * Convert a bit token value to a string; use "fmt" if not found. 394 * this is useful for parsing bitfields, the output strings are not seperated. 395 */ 396 char * 397 bittok2str_nosep(register const struct tok *lp, register const char *fmt, 398 register u_int v) 399 { 400 return (bittok2str_internal(lp, fmt, v, "")); 401 } 402 403 /* 404 * Convert a bit token value to a string; use "fmt" if not found. 405 * this is useful for parsing bitfields, the output strings are comma seperated. 406 */ 407 char * 408 bittok2str(register const struct tok *lp, register const char *fmt, 409 register u_int v) 410 { 411 return (bittok2str_internal(lp, fmt, v, ", ")); 412 } 413 414 /* 415 * Convert a value to a string using an array; the macro 416 * tok2strary() in <interface.h> is the public interface to 417 * this function and ensures that the second argument is 418 * correct for bounds-checking. 419 */ 420 const char * 421 tok2strary_internal(register const char **lp, int n, register const char *fmt, 422 register int v) 423 { 424 static char buf[128]; 425 426 if (v >= 0 && v < n && lp[v] != NULL) 427 return lp[v]; 428 if (fmt == NULL) 429 fmt = "#%d"; 430 (void)snprintf(buf, sizeof(buf), fmt, v); 431 return (buf); 432 } 433 434 /* 435 * Convert a 32-bit netmask to prefixlen if possible 436 * the function returns the prefix-len; if plen == -1 437 * then conversion was not possible; 438 */ 439 440 int 441 mask2plen(uint32_t mask) 442 { 443 uint32_t bitmasks[33] = { 444 0x00000000, 445 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 446 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000, 447 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, 448 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 449 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, 450 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00, 451 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 452 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff 453 }; 454 int prefix_len = 32; 455 456 /* let's see if we can transform the mask into a prefixlen */ 457 while (prefix_len >= 0) { 458 if (bitmasks[prefix_len] == mask) 459 break; 460 prefix_len--; 461 } 462 return (prefix_len); 463 } 464 465 #ifdef INET6 466 int 467 mask62plen(const u_char *mask) 468 { 469 u_char bitmasks[9] = { 470 0x00, 471 0x80, 0xc0, 0xe0, 0xf0, 472 0xf8, 0xfc, 0xfe, 0xff 473 }; 474 int byte; 475 int cidr_len = 0; 476 477 for (byte = 0; byte < 16; byte++) { 478 u_int bits; 479 480 for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) { 481 if (mask[byte] == bitmasks[bits]) { 482 cidr_len += bits; 483 break; 484 } 485 } 486 487 if (mask[byte] != 0xff) 488 break; 489 } 490 return (cidr_len); 491 } 492 #endif /* INET6 */ 493 494 /* 495 * Routine to print out information for text-based protocols such as FTP, 496 * HTTP, SMTP, RTSP, SIP, .... 497 */ 498 #define MAX_TOKEN 128 499 500 /* 501 * Fetch a token from a packet, starting at the specified index, 502 * and return the length of the token. 503 * 504 * Returns 0 on error; yes, this is indistinguishable from an empty 505 * token, but an "empty token" isn't a valid token - it just means 506 * either a space character at the beginning of the line (this 507 * includes a blank line) or no more tokens remaining on the line. 508 */ 509 static int 510 fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len, 511 u_char *tbuf, size_t tbuflen) 512 { 513 size_t toklen = 0; 514 515 for (; idx < len; idx++) { 516 if (!ND_TTEST(*(pptr + idx))) { 517 /* ran past end of captured data */ 518 return (0); 519 } 520 if (!isascii(*(pptr + idx))) { 521 /* not an ASCII character */ 522 return (0); 523 } 524 if (isspace(*(pptr + idx))) { 525 /* end of token */ 526 break; 527 } 528 if (!isprint(*(pptr + idx))) { 529 /* not part of a command token or response code */ 530 return (0); 531 } 532 if (toklen + 2 > tbuflen) { 533 /* no room for this character and terminating '\0' */ 534 return (0); 535 } 536 tbuf[toklen] = *(pptr + idx); 537 toklen++; 538 } 539 if (toklen == 0) { 540 /* no token */ 541 return (0); 542 } 543 tbuf[toklen] = '\0'; 544 545 /* 546 * Skip past any white space after the token, until we see 547 * an end-of-line (CR or LF). 548 */ 549 for (; idx < len; idx++) { 550 if (!ND_TTEST(*(pptr + idx))) { 551 /* ran past end of captured data */ 552 break; 553 } 554 if (*(pptr + idx) == '\r' || *(pptr + idx) == '\n') { 555 /* end of line */ 556 break; 557 } 558 if (!isascii(*(pptr + idx)) || !isprint(*(pptr + idx))) { 559 /* not a printable ASCII character */ 560 break; 561 } 562 if (!isspace(*(pptr + idx))) { 563 /* beginning of next token */ 564 break; 565 } 566 } 567 return (idx); 568 } 569 570 /* 571 * Scan a buffer looking for a line ending - LF or CR-LF. 572 * Return the index of the character after the line ending or 0 if 573 * we encounter a non-ASCII or non-printable character or don't find 574 * the line ending. 575 */ 576 static u_int 577 print_txt_line(netdissect_options *ndo, const char *protoname, 578 const char *prefix, const u_char *pptr, u_int idx, u_int len) 579 { 580 u_int startidx; 581 u_int linelen; 582 583 startidx = idx; 584 while (idx < len) { 585 ND_TCHECK(*(pptr+idx)); 586 if (*(pptr+idx) == '\n') { 587 /* 588 * LF without CR; end of line. 589 * Skip the LF and print the line, with the 590 * exception of the LF. 591 */ 592 linelen = idx - startidx; 593 idx++; 594 goto print; 595 } else if (*(pptr+idx) == '\r') { 596 /* CR - any LF? */ 597 if ((idx+1) >= len) { 598 /* not in this packet */ 599 return (0); 600 } 601 ND_TCHECK(*(pptr+idx+1)); 602 if (*(pptr+idx+1) == '\n') { 603 /* 604 * CR-LF; end of line. 605 * Skip the CR-LF and print the line, with 606 * the exception of the CR-LF. 607 */ 608 linelen = idx - startidx; 609 idx += 2; 610 goto print; 611 } 612 613 /* 614 * CR followed by something else; treat this 615 * as if it were binary data, and don't print 616 * it. 617 */ 618 return (0); 619 } else if (!isascii(*(pptr+idx)) || 620 (!isprint(*(pptr+idx)) && *(pptr+idx) != '\t')) { 621 /* 622 * Not a printable ASCII character and not a tab; 623 * treat this as if it were binary data, and 624 * don't print it. 625 */ 626 return (0); 627 } 628 idx++; 629 } 630 631 /* 632 * All printable ASCII, but no line ending after that point 633 * in the buffer; treat this as if it were truncated. 634 */ 635 trunc: 636 linelen = idx - startidx; 637 ND_PRINT((ndo, "%s%.*s[!%s]", prefix, (int)linelen, pptr + startidx, 638 protoname)); 639 return (0); 640 641 print: 642 ND_PRINT((ndo, "%s%.*s", prefix, (int)linelen, pptr + startidx)); 643 return (idx); 644 } 645 646 void 647 txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len, 648 const char *protoname, const char **cmds, u_int flags) 649 { 650 u_int idx, eol; 651 u_char token[MAX_TOKEN+1]; 652 const char *cmd; 653 int is_reqresp = 0; 654 const char *pnp; 655 656 if (cmds != NULL) { 657 /* 658 * This protocol has more than just request and 659 * response lines; see whether this looks like a 660 * request or response. 661 */ 662 idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token)); 663 if (idx != 0) { 664 /* Is this a valid request name? */ 665 while ((cmd = *cmds++) != NULL) { 666 if (strcasecmp((const char *)token, cmd) == 0) { 667 /* Yes. */ 668 is_reqresp = 1; 669 break; 670 } 671 } 672 673 /* 674 * No - is this a valid response code (3 digits)? 675 * 676 * Is this token the response code, or is the next 677 * token the response code? 678 */ 679 if (flags & RESP_CODE_SECOND_TOKEN) { 680 /* 681 * Next token - get it. 682 */ 683 idx = fetch_token(ndo, pptr, idx, len, token, 684 sizeof(token)); 685 } 686 if (idx != 0) { 687 if (isdigit(token[0]) && isdigit(token[1]) && 688 isdigit(token[2]) && token[3] == '\0') { 689 /* Yes. */ 690 is_reqresp = 1; 691 } 692 } 693 } 694 } else { 695 /* 696 * This protocol has only request and response lines 697 * (e.g., FTP, where all the data goes over a 698 * different connection); assume the payload is 699 * a request or response. 700 */ 701 is_reqresp = 1; 702 } 703 704 /* Capitalize the protocol name */ 705 for (pnp = protoname; *pnp != '\0'; pnp++) 706 ND_PRINT((ndo, "%c", toupper(*pnp))); 707 708 if (is_reqresp) { 709 /* 710 * In non-verbose mode, just print the protocol, followed 711 * by the first line as the request or response info. 712 * 713 * In verbose mode, print lines as text until we run out 714 * of characters or see something that's not a 715 * printable-ASCII line. 716 */ 717 if (ndo->ndo_vflag) { 718 /* 719 * We're going to print all the text lines in the 720 * request or response; just print the length 721 * on the first line of the output. 722 */ 723 ND_PRINT((ndo, ", length: %u", len)); 724 for (idx = 0; 725 idx < len && (eol = print_txt_line(ndo, protoname, "\n\t", pptr, idx, len)) != 0; 726 idx = eol) 727 ; 728 } else { 729 /* 730 * Just print the first text line. 731 */ 732 print_txt_line(ndo, protoname, ": ", pptr, 0, len); 733 } 734 } 735 } 736 737 /* VARARGS */ 738 void 739 error(const char *fmt, ...) 740 { 741 va_list ap; 742 743 (void)fprintf(stderr, "%s: ", program_name); 744 va_start(ap, fmt); 745 (void)vfprintf(stderr, fmt, ap); 746 va_end(ap); 747 if (*fmt) { 748 fmt += strlen(fmt); 749 if (fmt[-1] != '\n') 750 (void)fputc('\n', stderr); 751 } 752 exit(1); 753 /* NOTREACHED */ 754 } 755 756 /* VARARGS */ 757 void 758 warning(const char *fmt, ...) 759 { 760 va_list ap; 761 762 (void)fprintf(stderr, "%s: WARNING: ", program_name); 763 va_start(ap, fmt); 764 (void)vfprintf(stderr, fmt, ap); 765 va_end(ap); 766 if (*fmt) { 767 fmt += strlen(fmt); 768 if (fmt[-1] != '\n') 769 (void)fputc('\n', stderr); 770 } 771 } 772 773 /* 774 * Copy arg vector into a new buffer, concatenating arguments with spaces. 775 */ 776 char * 777 copy_argv(register char **argv) 778 { 779 register char **p; 780 register u_int len = 0; 781 char *buf; 782 char *src, *dst; 783 784 p = argv; 785 if (*p == 0) 786 return 0; 787 788 while (*p) 789 len += strlen(*p++) + 1; 790 791 buf = (char *)malloc(len); 792 if (buf == NULL) 793 error("copy_argv: malloc"); 794 795 p = argv; 796 dst = buf; 797 while ((src = *p++) != NULL) { 798 while ((*dst++ = *src++) != '\0') 799 ; 800 dst[-1] = ' '; 801 } 802 dst[-1] = '\0'; 803 804 return buf; 805 } 806 807 /* 808 * On Windows, we need to open the file in binary mode, so that 809 * we get all the bytes specified by the size we get from "fstat()". 810 * On UNIX, that's not necessary. O_BINARY is defined on Windows; 811 * we define it as 0 if it's not defined, so it does nothing. 812 */ 813 #ifndef O_BINARY 814 #define O_BINARY 0 815 #endif 816 817 char * 818 read_infile(char *fname) 819 { 820 register int i, fd, cc; 821 register char *cp; 822 struct stat buf; 823 824 fd = open(fname, O_RDONLY|O_BINARY); 825 if (fd < 0) 826 error("can't open %s: %s", fname, pcap_strerror(errno)); 827 828 if (fstat(fd, &buf) < 0) 829 error("can't stat %s: %s", fname, pcap_strerror(errno)); 830 831 cp = malloc((u_int)buf.st_size + 1); 832 if (cp == NULL) 833 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, 834 fname, pcap_strerror(errno)); 835 cc = read(fd, cp, (u_int)buf.st_size); 836 if (cc < 0) 837 error("read %s: %s", fname, pcap_strerror(errno)); 838 if (cc != buf.st_size) 839 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); 840 841 close(fd); 842 /* replace "# comment" with spaces */ 843 for (i = 0; i < cc; i++) { 844 if (cp[i] == '#') 845 while (i < cc && cp[i] != '\n') 846 cp[i++] = ' '; 847 } 848 cp[cc] = '\0'; 849 return (cp); 850 } 851 852 void 853 safeputs(netdissect_options *ndo, 854 const u_char *s, const u_int maxlen) 855 { 856 u_int idx = 0; 857 858 while (*s && idx < maxlen) { 859 safeputchar(ndo, *s); 860 idx++; 861 s++; 862 } 863 } 864 865 void 866 safeputchar(netdissect_options *ndo, 867 const u_char c) 868 { 869 ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c)); 870 } 871 872 #ifdef LBL_ALIGN 873 /* 874 * Some compilers try to optimize memcpy(), using the alignment constraint 875 * on the argument pointer type. by using this function, we try to avoid the 876 * optimization. 877 */ 878 void 879 unaligned_memcpy(void *p, const void *q, size_t l) 880 { 881 memcpy(p, q, l); 882 } 883 884 /* As with memcpy(), so with memcmp(). */ 885 int 886 unaligned_memcmp(const void *p, const void *q, size_t l) 887 { 888 return (memcmp(p, q, l)); 889 } 890 #endif 891