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@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 #include <sys/cdefs.h> 39 #ifndef lint 40 __RCSID("$NetBSD: util-print.c,v 1.4 2017/02/05 04:05:05 spz 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[256]; /* our stringbuffer */ 530 int buflen=0; 531 register u_int rotbit; /* this is the bit we rotate through all bitpositions */ 532 register u_int tokval; 533 const char * sepstr = ""; 534 535 while (lp != NULL && lp->s != NULL) { 536 tokval=lp->v; /* load our first value */ 537 rotbit=1; 538 while (rotbit != 0) { 539 /* 540 * lets AND the rotating bit with our token value 541 * and see if we have got a match 542 */ 543 if (tokval == (v&rotbit)) { 544 /* ok we have found something */ 545 buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s%s", 546 sepstr, lp->s); 547 sepstr = sep; 548 break; 549 } 550 rotbit=rotbit<<1; /* no match - lets shift and try again */ 551 } 552 lp++; 553 } 554 555 if (buflen == 0) 556 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */ 557 (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%08x" : fmt, v); 558 return (buf); 559 } 560 561 /* 562 * Convert a bit token value to a string; use "fmt" if not found. 563 * this is useful for parsing bitfields, the output strings are not seperated. 564 */ 565 char * 566 bittok2str_nosep(register const struct tok *lp, register const char *fmt, 567 register u_int v) 568 { 569 return (bittok2str_internal(lp, fmt, v, "")); 570 } 571 572 /* 573 * Convert a bit token value to a string; use "fmt" if not found. 574 * this is useful for parsing bitfields, the output strings are comma seperated. 575 */ 576 char * 577 bittok2str(register const struct tok *lp, register const char *fmt, 578 register u_int v) 579 { 580 return (bittok2str_internal(lp, fmt, v, ", ")); 581 } 582 583 /* 584 * Convert a value to a string using an array; the macro 585 * tok2strary() in <netdissect.h> is the public interface to 586 * this function and ensures that the second argument is 587 * correct for bounds-checking. 588 */ 589 const char * 590 tok2strary_internal(register const char **lp, int n, register const char *fmt, 591 register int v) 592 { 593 static char buf[TOKBUFSIZE]; 594 595 if (v >= 0 && v < n && lp[v] != NULL) 596 return lp[v]; 597 if (fmt == NULL) 598 fmt = "#%d"; 599 (void)snprintf(buf, sizeof(buf), fmt, v); 600 return (buf); 601 } 602 603 /* 604 * Convert a 32-bit netmask to prefixlen if possible 605 * the function returns the prefix-len; if plen == -1 606 * then conversion was not possible; 607 */ 608 609 int 610 mask2plen(uint32_t mask) 611 { 612 uint32_t bitmasks[33] = { 613 0x00000000, 614 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 615 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000, 616 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, 617 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 618 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, 619 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00, 620 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 621 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff 622 }; 623 int prefix_len = 32; 624 625 /* let's see if we can transform the mask into a prefixlen */ 626 while (prefix_len >= 0) { 627 if (bitmasks[prefix_len] == mask) 628 break; 629 prefix_len--; 630 } 631 return (prefix_len); 632 } 633 634 int 635 mask62plen(const u_char *mask) 636 { 637 u_char bitmasks[9] = { 638 0x00, 639 0x80, 0xc0, 0xe0, 0xf0, 640 0xf8, 0xfc, 0xfe, 0xff 641 }; 642 int byte; 643 int cidr_len = 0; 644 645 for (byte = 0; byte < 16; byte++) { 646 u_int bits; 647 648 for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) { 649 if (mask[byte] == bitmasks[bits]) { 650 cidr_len += bits; 651 break; 652 } 653 } 654 655 if (mask[byte] != 0xff) 656 break; 657 } 658 return (cidr_len); 659 } 660 661 /* 662 * Routine to print out information for text-based protocols such as FTP, 663 * HTTP, SMTP, RTSP, SIP, .... 664 */ 665 #define MAX_TOKEN 128 666 667 /* 668 * Fetch a token from a packet, starting at the specified index, 669 * and return the length of the token. 670 * 671 * Returns 0 on error; yes, this is indistinguishable from an empty 672 * token, but an "empty token" isn't a valid token - it just means 673 * either a space character at the beginning of the line (this 674 * includes a blank line) or no more tokens remaining on the line. 675 */ 676 static int 677 fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len, 678 u_char *tbuf, size_t tbuflen) 679 { 680 size_t toklen = 0; 681 682 for (; idx < len; idx++) { 683 if (!ND_TTEST(*(pptr + idx))) { 684 /* ran past end of captured data */ 685 return (0); 686 } 687 if (!isascii(*(pptr + idx))) { 688 /* not an ASCII character */ 689 return (0); 690 } 691 if (isspace(*(pptr + idx))) { 692 /* end of token */ 693 break; 694 } 695 if (!isprint(*(pptr + idx))) { 696 /* not part of a command token or response code */ 697 return (0); 698 } 699 if (toklen + 2 > tbuflen) { 700 /* no room for this character and terminating '\0' */ 701 return (0); 702 } 703 tbuf[toklen] = *(pptr + idx); 704 toklen++; 705 } 706 if (toklen == 0) { 707 /* no token */ 708 return (0); 709 } 710 tbuf[toklen] = '\0'; 711 712 /* 713 * Skip past any white space after the token, until we see 714 * an end-of-line (CR or LF). 715 */ 716 for (; idx < len; idx++) { 717 if (!ND_TTEST(*(pptr + idx))) { 718 /* ran past end of captured data */ 719 break; 720 } 721 if (*(pptr + idx) == '\r' || *(pptr + idx) == '\n') { 722 /* end of line */ 723 break; 724 } 725 if (!isascii(*(pptr + idx)) || !isprint(*(pptr + idx))) { 726 /* not a printable ASCII character */ 727 break; 728 } 729 if (!isspace(*(pptr + idx))) { 730 /* beginning of next token */ 731 break; 732 } 733 } 734 return (idx); 735 } 736 737 /* 738 * Scan a buffer looking for a line ending - LF or CR-LF. 739 * Return the index of the character after the line ending or 0 if 740 * we encounter a non-ASCII or non-printable character or don't find 741 * the line ending. 742 */ 743 static u_int 744 print_txt_line(netdissect_options *ndo, const char *protoname, 745 const char *prefix, const u_char *pptr, u_int idx, u_int len) 746 { 747 u_int startidx; 748 u_int linelen; 749 750 startidx = idx; 751 while (idx < len) { 752 ND_TCHECK(*(pptr+idx)); 753 if (*(pptr+idx) == '\n') { 754 /* 755 * LF without CR; end of line. 756 * Skip the LF and print the line, with the 757 * exception of the LF. 758 */ 759 linelen = idx - startidx; 760 idx++; 761 goto print; 762 } else if (*(pptr+idx) == '\r') { 763 /* CR - any LF? */ 764 if ((idx+1) >= len) { 765 /* not in this packet */ 766 return (0); 767 } 768 ND_TCHECK(*(pptr+idx+1)); 769 if (*(pptr+idx+1) == '\n') { 770 /* 771 * CR-LF; end of line. 772 * Skip the CR-LF and print the line, with 773 * the exception of the CR-LF. 774 */ 775 linelen = idx - startidx; 776 idx += 2; 777 goto print; 778 } 779 780 /* 781 * CR followed by something else; treat this 782 * as if it were binary data, and don't print 783 * it. 784 */ 785 return (0); 786 } else if (!isascii(*(pptr+idx)) || 787 (!isprint(*(pptr+idx)) && *(pptr+idx) != '\t')) { 788 /* 789 * Not a printable ASCII character and not a tab; 790 * treat this as if it were binary data, and 791 * don't print it. 792 */ 793 return (0); 794 } 795 idx++; 796 } 797 798 /* 799 * All printable ASCII, but no line ending after that point 800 * in the buffer; treat this as if it were truncated. 801 */ 802 trunc: 803 linelen = idx - startidx; 804 ND_PRINT((ndo, "%s%.*s[!%s]", prefix, (int)linelen, pptr + startidx, 805 protoname)); 806 return (0); 807 808 print: 809 ND_PRINT((ndo, "%s%.*s", prefix, (int)linelen, pptr + startidx)); 810 return (idx); 811 } 812 813 void 814 txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len, 815 const char *protoname, const char **cmds, u_int flags) 816 { 817 u_int idx, eol; 818 u_char token[MAX_TOKEN+1]; 819 const char *cmd; 820 int is_reqresp = 0; 821 const char *pnp; 822 823 if (cmds != NULL) { 824 /* 825 * This protocol has more than just request and 826 * response lines; see whether this looks like a 827 * request or response. 828 */ 829 idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token)); 830 if (idx != 0) { 831 /* Is this a valid request name? */ 832 while ((cmd = *cmds++) != NULL) { 833 if (ascii_strcasecmp((const char *)token, cmd) == 0) { 834 /* Yes. */ 835 is_reqresp = 1; 836 break; 837 } 838 } 839 840 /* 841 * No - is this a valid response code (3 digits)? 842 * 843 * Is this token the response code, or is the next 844 * token the response code? 845 */ 846 if (flags & RESP_CODE_SECOND_TOKEN) { 847 /* 848 * Next token - get it. 849 */ 850 idx = fetch_token(ndo, pptr, idx, len, token, 851 sizeof(token)); 852 } 853 if (idx != 0) { 854 if (isdigit(token[0]) && isdigit(token[1]) && 855 isdigit(token[2]) && token[3] == '\0') { 856 /* Yes. */ 857 is_reqresp = 1; 858 } 859 } 860 } 861 } else { 862 /* 863 * This protocol has only request and response lines 864 * (e.g., FTP, where all the data goes over a 865 * different connection); assume the payload is 866 * a request or response. 867 */ 868 is_reqresp = 1; 869 } 870 871 /* Capitalize the protocol name */ 872 for (pnp = protoname; *pnp != '\0'; pnp++) 873 ND_PRINT((ndo, "%c", toupper((unsigned char)*pnp))); 874 875 if (is_reqresp) { 876 /* 877 * In non-verbose mode, just print the protocol, followed 878 * by the first line as the request or response info. 879 * 880 * In verbose mode, print lines as text until we run out 881 * of characters or see something that's not a 882 * printable-ASCII line. 883 */ 884 if (ndo->ndo_vflag) { 885 /* 886 * We're going to print all the text lines in the 887 * request or response; just print the length 888 * on the first line of the output. 889 */ 890 ND_PRINT((ndo, ", length: %u", len)); 891 for (idx = 0; 892 idx < len && (eol = print_txt_line(ndo, protoname, "\n\t", pptr, idx, len)) != 0; 893 idx = eol) 894 ; 895 } else { 896 /* 897 * Just print the first text line. 898 */ 899 print_txt_line(ndo, protoname, ": ", pptr, 0, len); 900 } 901 } 902 } 903 904 void 905 safeputs(netdissect_options *ndo, 906 const u_char *s, const u_int maxlen) 907 { 908 u_int idx = 0; 909 910 while (*s && idx < maxlen) { 911 safeputchar(ndo, *s); 912 idx++; 913 s++; 914 } 915 } 916 917 void 918 safeputchar(netdissect_options *ndo, 919 const u_char c) 920 { 921 ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c)); 922 } 923 924 #ifdef LBL_ALIGN 925 /* 926 * Some compilers try to optimize memcpy(), using the alignment constraint 927 * on the argument pointer type. by using this function, we try to avoid the 928 * optimization. 929 */ 930 void 931 unaligned_memcpy(void *p, const void *q, size_t l) 932 { 933 memcpy(p, q, l); 934 } 935 936 /* As with memcpy(), so with memcmp(). */ 937 int 938 unaligned_memcmp(const void *p, const void *q, size_t l) 939 { 940 return (memcmp(p, q, l)); 941 } 942 #endif 943 944