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