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.7 2023/08/17 20:19:40 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 <stdio.h> 55 #include <stdarg.h> 56 #include <stdlib.h> 57 #include <string.h> 58 59 #include "netdissect-ctype.h" 60 61 #include "netdissect.h" 62 #include "extract.h" 63 #include "ascii_strcasecmp.h" 64 #include "timeval-operations.h" 65 66 #define TOKBUFSIZE 128 67 68 enum date_flag { WITHOUT_DATE = 0, WITH_DATE = 1 }; 69 enum time_flag { UTC_TIME = 0, LOCAL_TIME = 1 }; 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("M-"); 80 } 81 if (!ND_ASCII_ISPRINT(c)) { 82 c ^= 0x40; /* DEL to ?, others to alpha */ 83 ND_PRINT("^"); 84 } 85 ND_PRINT("%c", c); 86 } 87 88 /* 89 * Print a null-terminated string, filtering out non-printable characters. 90 * DON'T USE IT with a pointer on the packet buffer because there is no 91 * truncation check. For this use, see the nd_printX() functions below. 92 */ 93 void 94 fn_print_str(netdissect_options *ndo, const u_char *s) 95 { 96 while (*s != '\0') { 97 fn_print_char(ndo, *s); 98 s++; 99 } 100 } 101 102 /* 103 * Print out a null-terminated filename (or other ASCII string) from 104 * a fixed-length field in the packet buffer, or from what remains of 105 * the packet. 106 * 107 * n is the length of the fixed-length field, or the number of bytes 108 * remaining in the packet based on its on-the-network length. 109 * 110 * If ep is non-null, it should point just past the last captured byte 111 * of the packet, e.g. ndo->ndo_snapend. If ep is NULL, we assume no 112 * truncation check, other than the checks of the field length/remaining 113 * packet data length, is needed. 114 * 115 * Return the number of bytes of string processed, including the 116 * terminating null, if not truncated; as the terminating null is 117 * included in the count, and as there must be a terminating null, 118 * this will always be non-zero. Return 0 if truncated. 119 */ 120 u_int 121 nd_printztn(netdissect_options *ndo, 122 const u_char *s, u_int n, const u_char *ep) 123 { 124 u_int bytes; 125 u_char c; 126 127 bytes = 0; 128 for (;;) { 129 if (n == 0 || (ep != NULL && s >= ep)) { 130 /* 131 * Truncated. This includes "no null before we 132 * got to the end of the fixed-length buffer or 133 * the end of the packet". 134 * 135 * XXX - BOOTP says "null-terminated", which 136 * means the maximum length of the string, in 137 * bytes, is 1 less than the size of the buffer, 138 * as there must always be a terminating null. 139 */ 140 bytes = 0; 141 break; 142 } 143 144 c = GET_U_1(s); 145 s++; 146 bytes++; 147 n--; 148 if (c == '\0') { 149 /* End of string */ 150 break; 151 } 152 fn_print_char(ndo, c); 153 } 154 return(bytes); 155 } 156 157 /* 158 * Print out a counted filename (or other ASCII string), part of 159 * the packet buffer. 160 * If ep is NULL, assume no truncation check is needed. 161 * Return true if truncated. 162 * Stop at ep (if given) or after n bytes, whichever is first. 163 */ 164 int 165 nd_printn(netdissect_options *ndo, 166 const u_char *s, u_int n, const u_char *ep) 167 { 168 u_char c; 169 170 while (n > 0 && (ep == NULL || s < ep)) { 171 n--; 172 c = GET_U_1(s); 173 s++; 174 fn_print_char(ndo, c); 175 } 176 return (n == 0) ? 0 : 1; 177 } 178 179 /* 180 * Print a null-padded filename (or other ASCII string), part of 181 * the packet buffer, filtering out non-printable characters. 182 * Stop if truncated (via GET_U_1/longjmp) or after n bytes or before 183 * the null char, whichever occurs first. 184 * The suffix comes from: j:longJmp, n:after N bytes, p:null-Padded. 185 */ 186 void 187 nd_printjnp(netdissect_options *ndo, const u_char *s, u_int n) 188 { 189 u_char c; 190 191 while (n > 0) { 192 c = GET_U_1(s); 193 if (c == '\0') 194 break; 195 fn_print_char(ndo, c); 196 n--; 197 s++; 198 } 199 } 200 201 /* 202 * Print the timestamp .FRAC part (Microseconds/nanoseconds) 203 */ 204 static void 205 ts_frac_print(netdissect_options *ndo, long usec) 206 { 207 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION 208 switch (ndo->ndo_tstamp_precision) { 209 210 case PCAP_TSTAMP_PRECISION_MICRO: 211 ND_PRINT(".%06u", (unsigned)usec); 212 break; 213 214 case PCAP_TSTAMP_PRECISION_NANO: 215 ND_PRINT(".%09u", (unsigned)usec); 216 break; 217 218 default: 219 ND_PRINT(".{unknown}"); 220 break; 221 } 222 #else 223 ND_PRINT(".%06u", (unsigned)usec); 224 #endif 225 } 226 227 /* 228 * Print the timestamp as [YY:MM:DD] HH:MM:SS.FRAC. 229 * if time_flag == LOCAL_TIME print local time else UTC/GMT time 230 * if date_flag == WITH_DATE print YY:MM:DD before HH:MM:SS.FRAC 231 */ 232 static void 233 ts_date_hmsfrac_print(netdissect_options *ndo, long sec, long usec, 234 enum date_flag date_flag, enum time_flag time_flag) 235 { 236 time_t Time = sec; 237 struct tm *tm; 238 char timebuf[32]; 239 const char *timestr; 240 241 if ((unsigned)sec & 0x80000000) { 242 ND_PRINT("[Error converting time]"); 243 return; 244 } 245 246 if (time_flag == LOCAL_TIME) 247 tm = localtime(&Time); 248 else 249 tm = gmtime(&Time); 250 251 if (date_flag == WITH_DATE) { 252 timestr = nd_format_time(timebuf, sizeof(timebuf), 253 "%Y-%m-%d %H:%M:%S", tm); 254 } else { 255 timestr = nd_format_time(timebuf, sizeof(timebuf), 256 "%H:%M:%S", tm); 257 } 258 ND_PRINT("%s", timestr); 259 260 ts_frac_print(ndo, usec); 261 } 262 263 /* 264 * Print the timestamp - Unix timeval style, as SECS.FRAC. 265 */ 266 static void 267 ts_unix_print(netdissect_options *ndo, long sec, long usec) 268 { 269 if ((unsigned)sec & 0x80000000) { 270 ND_PRINT("[Error converting time]"); 271 return; 272 } 273 274 ND_PRINT("%u", (unsigned)sec); 275 ts_frac_print(ndo, usec); 276 } 277 278 /* 279 * Print the timestamp 280 */ 281 void 282 ts_print(netdissect_options *ndo, 283 const struct timeval *tvp) 284 { 285 static struct timeval tv_ref; 286 struct timeval tv_result; 287 int negative_offset; 288 int nano_prec; 289 290 switch (ndo->ndo_tflag) { 291 292 case 0: /* Default */ 293 ts_date_hmsfrac_print(ndo, tvp->tv_sec, tvp->tv_usec, 294 WITHOUT_DATE, LOCAL_TIME); 295 ND_PRINT(" "); 296 break; 297 298 case 1: /* No time stamp */ 299 break; 300 301 case 2: /* Unix timeval style */ 302 ts_unix_print(ndo, tvp->tv_sec, tvp->tv_usec); 303 ND_PRINT(" "); 304 break; 305 306 case 3: /* Microseconds/nanoseconds since previous packet */ 307 case 5: /* Microseconds/nanoseconds since first packet */ 308 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION 309 switch (ndo->ndo_tstamp_precision) { 310 case PCAP_TSTAMP_PRECISION_MICRO: 311 nano_prec = 0; 312 break; 313 case PCAP_TSTAMP_PRECISION_NANO: 314 nano_prec = 1; 315 break; 316 default: 317 nano_prec = 0; 318 break; 319 } 320 #else 321 nano_prec = 0; 322 #endif 323 if (!(netdissect_timevalisset(&tv_ref))) 324 tv_ref = *tvp; /* set timestamp for first packet */ 325 326 negative_offset = netdissect_timevalcmp(tvp, &tv_ref, <); 327 if (negative_offset) 328 netdissect_timevalsub(&tv_ref, tvp, &tv_result, nano_prec); 329 else 330 netdissect_timevalsub(tvp, &tv_ref, &tv_result, nano_prec); 331 332 ND_PRINT((negative_offset ? "-" : " ")); 333 ts_date_hmsfrac_print(ndo, tv_result.tv_sec, tv_result.tv_usec, 334 WITHOUT_DATE, UTC_TIME); 335 ND_PRINT(" "); 336 337 if (ndo->ndo_tflag == 3) 338 tv_ref = *tvp; /* set timestamp for previous packet */ 339 break; 340 341 case 4: /* Date + Default */ 342 ts_date_hmsfrac_print(ndo, tvp->tv_sec, tvp->tv_usec, 343 WITH_DATE, LOCAL_TIME); 344 ND_PRINT(" "); 345 break; 346 } 347 } 348 349 /* 350 * Print an unsigned relative number of seconds (e.g. hold time, prune timer) 351 * in the form 5m1s. This does no truncation, so 32230861 seconds 352 * is represented as 1y1w1d1h1m1s. 353 */ 354 void 355 unsigned_relts_print(netdissect_options *ndo, 356 uint32_t secs) 357 { 358 static const char *lengths[] = {"y", "w", "d", "h", "m", "s"}; 359 static const u_int seconds[] = {31536000, 604800, 86400, 3600, 60, 1}; 360 const char **l = lengths; 361 const u_int *s = seconds; 362 363 if (secs == 0) { 364 ND_PRINT("0s"); 365 return; 366 } 367 while (secs > 0) { 368 if (secs >= *s) { 369 ND_PRINT("%u%s", secs / *s, *l); 370 secs -= (secs / *s) * *s; 371 } 372 s++; 373 l++; 374 } 375 } 376 377 /* 378 * Print a signed relative number of seconds (e.g. hold time, prune timer) 379 * in the form 5m1s. This does no truncation, so 32230861 seconds 380 * is represented as 1y1w1d1h1m1s. 381 */ 382 void 383 signed_relts_print(netdissect_options *ndo, 384 int32_t secs) 385 { 386 if (secs < 0) { 387 ND_PRINT("-"); 388 if (secs == INT32_MIN) { 389 /* 390 * -2^31; you can't fit its absolute value into 391 * a 32-bit signed integer. 392 * 393 * Just directly pass said absolute value to 394 * unsigned_relts_print() directly. 395 * 396 * (XXX - does ISO C guarantee that -(-2^n), 397 * when calculated and cast to an n-bit unsigned 398 * integer type, will have the value 2^n?) 399 */ 400 unsigned_relts_print(ndo, 2147483648U); 401 } else { 402 /* 403 * We now know -secs will fit into an int32_t; 404 * negate it and pass that to unsigned_relts_print(). 405 */ 406 unsigned_relts_print(ndo, -secs); 407 } 408 return; 409 } 410 unsigned_relts_print(ndo, secs); 411 } 412 413 /* 414 * Format a struct tm with strftime(). 415 * If the pointer to the struct tm is null, that means that the 416 * routine to convert a time_t to a struct tm failed; the localtime() 417 * and gmtime() in the Microsoft Visual Studio C library will fail, 418 * returning null, if the value is before the UNIX Epoch. 419 */ 420 const char * 421 nd_format_time(char *buf, size_t bufsize, const char *format, 422 const struct tm *timeptr) 423 { 424 if (timeptr != NULL) { 425 if (strftime(buf, bufsize, format, timeptr) != 0) 426 return (buf); 427 else 428 return ("[nd_format_time() buffer is too small]"); 429 } else 430 return ("[localtime() or gmtime() couldn't convert the date and time]"); 431 } 432 433 /* Print the truncated string */ 434 void nd_print_trunc(netdissect_options *ndo) 435 { 436 ND_PRINT(" [|%s]", ndo->ndo_protocol); 437 } 438 439 /* Print the protocol name */ 440 void nd_print_protocol(netdissect_options *ndo) 441 { 442 ND_PRINT("%s", ndo->ndo_protocol); 443 } 444 445 /* Print the protocol name in caps (uppercases) */ 446 void nd_print_protocol_caps(netdissect_options *ndo) 447 { 448 const char *p; 449 for (p = ndo->ndo_protocol; *p != '\0'; p++) 450 ND_PRINT("%c", ND_ASCII_TOUPPER(*p)); 451 } 452 453 /* Print the invalid string */ 454 void nd_print_invalid(netdissect_options *ndo) 455 { 456 ND_PRINT(" (invalid)"); 457 } 458 459 /* 460 * this is a generic routine for printing unknown data; 461 * we pass on the linefeed plus indentation string to 462 * get a proper output - returns 0 on error 463 */ 464 465 int 466 print_unknown_data(netdissect_options *ndo, const u_char *cp, 467 const char *ident, u_int len) 468 { 469 u_int len_to_print; 470 471 len_to_print = len; 472 if (!ND_TTEST_LEN(cp, 0)) { 473 ND_PRINT("%sDissector error: print_unknown_data called with pointer past end of packet", 474 ident); 475 return(0); 476 } 477 if (ND_BYTES_AVAILABLE_AFTER(cp) < len_to_print) 478 len_to_print = ND_BYTES_AVAILABLE_AFTER(cp); 479 hex_print(ndo, ident, cp, len_to_print); 480 return(1); /* everything is ok */ 481 } 482 483 /* 484 * Convert a token value to a string; use "fmt" if not found. 485 */ 486 static const char * 487 tok2strbuf(const struct tok *lp, const char *fmt, 488 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 * Uses tok2strbuf() on one of four local static buffers of size TOKBUFSIZE 507 * in round-robin fashion. 508 */ 509 const char * 510 tok2str(const struct tok *lp, const char *fmt, 511 u_int v) 512 { 513 static char buf[4][TOKBUFSIZE]; 514 static int idx = 0; 515 char *ret; 516 517 ret = buf[idx]; 518 idx = (idx+1) & 3; 519 return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0])); 520 } 521 522 /* 523 * Convert a bit token value to a string; use "fmt" if not found. 524 * this is useful for parsing bitfields, the output strings are separated 525 * if the s field is positive. 526 * 527 * A token matches iff it has one or more bits set and every bit that is set 528 * in the token is set in v. Consequently, a 0 token never matches. 529 */ 530 static char * 531 bittok2str_internal(const struct tok *lp, const char *fmt, 532 u_int v, const char *sep) 533 { 534 static char buf[1024+1]; /* our string buffer */ 535 char *bufp = buf; 536 size_t space_left = sizeof(buf), string_size; 537 const char * sepstr = ""; 538 539 while (lp != NULL && lp->s != NULL) { 540 if (lp->v && (v & lp->v) == lp->v) { 541 /* ok we have found something */ 542 if (space_left <= 1) 543 return (buf); /* only enough room left for NUL, if that */ 544 string_size = strlcpy(bufp, sepstr, space_left); 545 if (string_size >= space_left) 546 return (buf); /* we ran out of room */ 547 bufp += string_size; 548 space_left -= string_size; 549 if (space_left <= 1) 550 return (buf); /* only enough room left for NUL, if that */ 551 string_size = strlcpy(bufp, lp->s, space_left); 552 if (string_size >= space_left) 553 return (buf); /* we ran out of room */ 554 bufp += string_size; 555 space_left -= string_size; 556 sepstr = sep; 557 } 558 lp++; 559 } 560 561 if (bufp == buf) 562 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */ 563 (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%08x" : fmt, v); 564 return (buf); 565 } 566 567 /* 568 * Convert a bit token value to a string; use "fmt" if not found. 569 * this is useful for parsing bitfields, the output strings are not separated. 570 */ 571 char * 572 bittok2str_nosep(const struct tok *lp, const char *fmt, 573 u_int v) 574 { 575 return (bittok2str_internal(lp, fmt, v, "")); 576 } 577 578 /* 579 * Convert a bit token value to a string; use "fmt" if not found. 580 * this is useful for parsing bitfields, the output strings are comma separated. 581 */ 582 char * 583 bittok2str(const struct tok *lp, const char *fmt, 584 u_int v) 585 { 586 return (bittok2str_internal(lp, fmt, v, ", ")); 587 } 588 589 /* 590 * Convert a value to a string using an array; the macro 591 * tok2strary() in <netdissect.h> is the public interface to 592 * this function and ensures that the second argument is 593 * correct for bounds-checking. 594 */ 595 const char * 596 tok2strary_internal(const char **lp, int n, const char *fmt, 597 int v) 598 { 599 static char buf[TOKBUFSIZE]; 600 601 if (v >= 0 && v < n && lp[v] != NULL) 602 return lp[v]; 603 if (fmt == NULL) 604 fmt = "#%d"; 605 (void)snprintf(buf, sizeof(buf), fmt, v); 606 return (buf); 607 } 608 609 const struct tok * 610 uint2tokary_internal(const struct uint_tokary dict[], const size_t size, 611 const u_int val) 612 { 613 size_t i; 614 /* Try a direct lookup before the full scan. */ 615 if (val < size && dict[val].uintval == val) 616 return dict[val].tokary; /* OK if NULL */ 617 for (i = 0; i < size; i++) 618 if (dict[i].uintval == val) 619 return dict[i].tokary; /* OK if NULL */ 620 return NULL; 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 const 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 u_char c; 702 703 for (; idx < len; idx++) { 704 if (!ND_TTEST_1(pptr + idx)) { 705 /* ran past end of captured data */ 706 return (0); 707 } 708 c = GET_U_1(pptr + idx); 709 if (!ND_ISASCII(c)) { 710 /* not an ASCII character */ 711 return (0); 712 } 713 if (c == ' ' || c == '\t' || c == '\r' || c == '\n') { 714 /* end of token */ 715 break; 716 } 717 if (!ND_ASCII_ISPRINT(c)) { 718 /* not part of a command token or response code */ 719 return (0); 720 } 721 if (toklen + 2 > tbuflen) { 722 /* no room for this character and terminating '\0' */ 723 return (0); 724 } 725 tbuf[toklen] = c; 726 toklen++; 727 } 728 if (toklen == 0) { 729 /* no token */ 730 return (0); 731 } 732 tbuf[toklen] = '\0'; 733 734 /* 735 * Skip past any white space after the token, until we see 736 * an end-of-line (CR or LF). 737 */ 738 for (; idx < len; idx++) { 739 if (!ND_TTEST_1(pptr + idx)) { 740 /* ran past end of captured data */ 741 break; 742 } 743 c = GET_U_1(pptr + idx); 744 if (c == '\r' || c == '\n') { 745 /* end of line */ 746 break; 747 } 748 if (!ND_ASCII_ISPRINT(c)) { 749 /* not a printable ASCII character */ 750 break; 751 } 752 if (c != ' ' && c != '\t' && c != '\r' && c != '\n') { 753 /* beginning of next token */ 754 break; 755 } 756 } 757 return (idx); 758 } 759 760 /* 761 * Scan a buffer looking for a line ending - LF or CR-LF. 762 * Return the index of the character after the line ending or 0 if 763 * we encounter a non-ASCII or non-printable character or don't find 764 * the line ending. 765 */ 766 static u_int 767 print_txt_line(netdissect_options *ndo, const char *prefix, 768 const u_char *pptr, u_int idx, u_int len) 769 { 770 u_int startidx; 771 u_int linelen; 772 u_char c; 773 774 startidx = idx; 775 while (idx < len) { 776 c = GET_U_1(pptr + idx); 777 if (c == '\n') { 778 /* 779 * LF without CR; end of line. 780 * Skip the LF and print the line, with the 781 * exception of the LF. 782 */ 783 linelen = idx - startidx; 784 idx++; 785 goto print; 786 } else if (c == '\r') { 787 /* CR - any LF? */ 788 if ((idx+1) >= len) { 789 /* not in this packet */ 790 return (0); 791 } 792 if (GET_U_1(pptr + idx + 1) == '\n') { 793 /* 794 * CR-LF; end of line. 795 * Skip the CR-LF and print the line, with 796 * the exception of the CR-LF. 797 */ 798 linelen = idx - startidx; 799 idx += 2; 800 goto print; 801 } 802 803 /* 804 * CR followed by something else; treat this 805 * as if it were binary data, and don't print 806 * it. 807 */ 808 return (0); 809 } else if (!ND_ASCII_ISPRINT(c) && c != '\t') { 810 /* 811 * Not a printable ASCII character and not a tab; 812 * treat this as if it were binary data, and 813 * don't print it. 814 */ 815 return (0); 816 } 817 idx++; 818 } 819 820 /* 821 * All printable ASCII, but no line ending after that point 822 * in the buffer; treat this as if it were truncated. 823 */ 824 linelen = idx - startidx; 825 ND_PRINT("%s%.*s", prefix, (int)linelen, pptr + startidx); 826 nd_print_trunc(ndo); 827 return (0); 828 829 print: 830 ND_PRINT("%s%.*s", prefix, (int)linelen, pptr + startidx); 831 return (idx); 832 } 833 834 /* Assign needed before calling txtproto_print(): ndo->ndo_protocol = "proto" */ 835 void 836 txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len, 837 const char **cmds, u_int flags) 838 { 839 u_int idx, eol; 840 u_char token[MAX_TOKEN+1]; 841 const char *cmd; 842 int print_this = 0; 843 844 if (cmds != NULL) { 845 /* 846 * This protocol has more than just request and 847 * response lines; see whether this looks like a 848 * request or response and, if so, print it and, 849 * in verbose mode, print everything after it. 850 * 851 * This is for HTTP-like protocols, where we 852 * want to print requests and responses, but 853 * don't want to print continuations of request 854 * or response bodies in packets that don't 855 * contain the request or response line. 856 */ 857 idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token)); 858 if (idx != 0) { 859 /* Is this a valid request name? */ 860 while ((cmd = *cmds++) != NULL) { 861 if (ascii_strcasecmp((const char *)token, cmd) == 0) { 862 /* Yes. */ 863 print_this = 1; 864 break; 865 } 866 } 867 868 /* 869 * No - is this a valid response code (3 digits)? 870 * 871 * Is this token the response code, or is the next 872 * token the response code? 873 */ 874 if (flags & RESP_CODE_SECOND_TOKEN) { 875 /* 876 * Next token - get it. 877 */ 878 idx = fetch_token(ndo, pptr, idx, len, token, 879 sizeof(token)); 880 } 881 if (idx != 0) { 882 if (ND_ASCII_ISDIGIT(token[0]) && ND_ASCII_ISDIGIT(token[1]) && 883 ND_ASCII_ISDIGIT(token[2]) && token[3] == '\0') { 884 /* Yes. */ 885 print_this = 1; 886 } 887 } 888 } 889 } else { 890 /* 891 * Either: 892 * 893 * 1) This protocol has only request and response lines 894 * (e.g., FTP, where all the data goes over a different 895 * connection); assume the payload is a request or 896 * response. 897 * 898 * or 899 * 900 * 2) This protocol is just text, so that we should 901 * always, at minimum, print the first line and, 902 * in verbose mode, print all lines. 903 */ 904 print_this = 1; 905 } 906 907 nd_print_protocol_caps(ndo); 908 909 if (print_this) { 910 /* 911 * In non-verbose mode, just print the protocol, followed 912 * by the first line. 913 * 914 * In verbose mode, print lines as text until we run out 915 * of characters or see something that's not a 916 * printable-ASCII line. 917 */ 918 if (ndo->ndo_vflag) { 919 /* 920 * We're going to print all the text lines in the 921 * request or response; just print the length 922 * on the first line of the output. 923 */ 924 ND_PRINT(", length: %u", len); 925 for (idx = 0; 926 idx < len && (eol = print_txt_line(ndo, "\n\t", pptr, idx, len)) != 0; 927 idx = eol) 928 ; 929 } else { 930 /* 931 * Just print the first text line. 932 */ 933 print_txt_line(ndo, ": ", pptr, 0, len); 934 } 935 } 936 } 937 938 #if (defined(__i386__) || defined(_M_IX86) || defined(__X86__) || defined(__x86_64__) || defined(_M_X64)) || \ 939 (defined(__arm__) || defined(_M_ARM) || defined(__aarch64__)) || \ 940 (defined(__m68k__) && (!defined(__mc68000__) && !defined(__mc68010__))) || \ 941 (defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PPC64)) || \ 942 (defined(__s390__) || defined(__s390x__) || defined(__zarch__)) || \ 943 defined(__vax__) 944 /* 945 * The processor natively handles unaligned loads, so just use memcpy() 946 * and memcmp(), to enable those optimizations. 947 * 948 * XXX - are those all the x86 tests we need? 949 * XXX - do we need to worry about ARMv1 through ARMv5, which didn't 950 * support unaligned loads, and, if so, do we need to worry about all 951 * of them, or just some of them, e.g. ARMv5? 952 * XXX - are those the only 68k tests we need not to generated 953 * unaligned accesses if the target is the 68000 or 68010? 954 * XXX - are there any tests we don't need, because some definitions are for 955 * compilers that also predefine the GCC symbols? 956 * XXX - do we need to test for both 32-bit and 64-bit versions of those 957 * architectures in all cases? 958 */ 959 #else 960 /* 961 * The processor doesn't natively handle unaligned loads, 962 * and the compiler might "helpfully" optimize memcpy() 963 * and memcmp(), when handed pointers that would normally 964 * be properly aligned, into sequences that assume proper 965 * alignment. 966 * 967 * Do copies and compares of possibly-unaligned data by 968 * calling routines that wrap memcpy() and memcmp(), to 969 * prevent that optimization. 970 */ 971 void 972 unaligned_memcpy(void *p, const void *q, size_t l) 973 { 974 memcpy(p, q, l); 975 } 976 977 /* As with memcpy(), so with memcmp(). */ 978 int 979 unaligned_memcmp(const void *p, const void *q, size_t l) 980 { 981 return (memcmp(p, q, l)); 982 } 983 #endif 984 985