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