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