1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 26 */ 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <ctype.h> 31 #include <string.h> 32 #include <fcntl.h> 33 #include <string.h> 34 #include <sys/types.h> 35 #include <time.h> 36 #include <sys/time.h> 37 #include <sys/bufmod.h> 38 #include <setjmp.h> 39 #include <stdarg.h> 40 #include <sys/socket.h> 41 #include <net/if.h> 42 #include <netinet/in_systm.h> 43 #include <netinet/in.h> 44 #include <netinet/ip.h> 45 #include <netinet/if_ether.h> 46 #include <rpc/types.h> 47 #include <rpc/xdr.h> 48 #include <inttypes.h> 49 50 #include "snoop.h" 51 52 char *dlc_header; 53 char *src_name, *dst_name; 54 int pi_frame; 55 int pi_time_hour; 56 int pi_time_min; 57 int pi_time_sec; 58 int pi_time_usec; 59 60 #ifndef MIN 61 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 62 #endif 63 64 static void hexdump(char *, int); 65 66 /* 67 * This routine invokes the packet interpreters 68 * on a packet. There's some messing around 69 * setting up a few packet-externals before 70 * starting with the ethernet interpreter. 71 * Yes, we assume here that all packets will 72 * be ethernet packets. 73 */ 74 void 75 process_pkt(struct sb_hdr *hdrp, char *pktp, int num, int flags) 76 { 77 int drops, pktlen; 78 struct timeval *tvp; 79 struct tm *tm; 80 extern int x_offset; 81 extern int x_length; 82 int offset, length; 83 static struct timeval ptv; 84 85 if (hdrp == NULL) 86 return; 87 88 tvp = &hdrp->sbh_timestamp; 89 if (ptv.tv_sec == 0) 90 ptv = *tvp; 91 drops = hdrp->sbh_drops; 92 pktlen = hdrp->sbh_msglen; 93 if (pktlen <= 0) 94 return; 95 96 /* set up externals */ 97 dlc_header = pktp; 98 pi_frame = num; 99 tm = localtime(&tvp->tv_sec); 100 pi_time_hour = tm->tm_hour; 101 pi_time_min = tm->tm_min; 102 pi_time_sec = tm->tm_sec; 103 pi_time_usec = tvp->tv_usec; 104 105 src_name = "?"; 106 dst_name = "*"; 107 108 click(hdrp->sbh_origlen); 109 110 (*interface->interpreter)(flags, dlc_header, hdrp->sbh_msglen, 111 hdrp->sbh_origlen); 112 113 show_pktinfo(flags, num, src_name, dst_name, &ptv, tvp, drops, 114 hdrp->sbh_origlen); 115 116 if (x_offset >= 0) { 117 offset = MIN(x_offset, hdrp->sbh_msglen); 118 offset -= (offset % 2); /* round down */ 119 length = MIN(hdrp->sbh_msglen - offset, x_length); 120 121 hexdump(dlc_header + offset, length); 122 } 123 124 ptv = *tvp; 125 } 126 127 128 /* 129 * ************************************************************* 130 * The following routines constitute a library 131 * used by the packet interpreters to facilitate 132 * the display of packet data. This library 133 * of routines helps provide a consistent 134 * "look and feel". 135 */ 136 137 138 /* 139 * Display the value of a flag bit in 140 * a byte together with some text that 141 * corresponds to its value - whether 142 * true or false. 143 */ 144 char * 145 getflag(int val, int mask, char *s_true, char *s_false) 146 { 147 static char buff[80]; 148 char *p; 149 int set; 150 151 (void) strcpy(buff, ".... .... = "); 152 if (s_false == NULL) 153 s_false = s_true; 154 155 for (p = &buff[8]; p >= buff; p--) { 156 if (*p == ' ') 157 p--; 158 if (mask & 0x1) { 159 set = val & mask & 0x1; 160 *p = set ? '1':'0'; 161 (void) strcat(buff, set ? s_true: s_false); 162 break; 163 } 164 mask >>= 1; 165 val >>= 1; 166 } 167 return (buff); 168 } 169 170 XDR xdrm; 171 jmp_buf xdr_err; 172 int xdr_totlen; 173 char *prot_prefix; 174 char *prot_nest_prefix = ""; 175 char *prot_title; 176 177 void 178 show_header(char *pref, char *str, int len) 179 { 180 prot_prefix = pref; 181 prot_title = str; 182 (void) sprintf(get_detail_line(0, len), "%s%s----- %s -----", 183 prot_nest_prefix, pref, str); 184 } 185 186 void 187 xdr_init(char *addr, int len) 188 { 189 xdr_totlen = len; 190 xdrmem_create(&xdrm, addr, len, XDR_DECODE); 191 } 192 193 /* Note: begin+end are ignored in get_detail_line */ 194 char * 195 get_line(int begin, int end) 196 { 197 char *line; 198 199 line = get_detail_line(begin, end); 200 (void) strcpy(line, prot_nest_prefix); 201 (void) strcat(line, prot_prefix); 202 return (line + strlen(line)); 203 } 204 205 int 206 get_line_remain(void) 207 { 208 return (MAXLINE - strlen(prot_nest_prefix) - strlen(prot_prefix)); 209 } 210 211 void 212 show_line(char *str) 213 { 214 (void) strlcpy(get_line(0, 0), str, get_line_remain()); 215 } 216 217 void 218 show_printf(char *fmt, ...) 219 { 220 va_list ap; 221 222 va_start(ap, fmt); 223 (void) vsnprintf(get_line(0, 0), get_line_remain(), fmt, ap); 224 va_end(ap); 225 } 226 227 char 228 getxdr_char() 229 { 230 char s; 231 232 if (xdr_char(&xdrm, &s)) 233 return (s); 234 longjmp(xdr_err, 1); 235 /* NOTREACHED */ 236 } 237 238 char 239 showxdr_char(char *fmt) 240 { 241 int pos; char val; 242 243 pos = getxdr_pos(); 244 val = getxdr_char(); 245 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 246 return (val); 247 } 248 249 uchar_t 250 getxdr_u_char() 251 { 252 uchar_t s; 253 254 if (xdr_u_char(&xdrm, &s)) 255 return (s); 256 longjmp(xdr_err, 1); 257 /* NOTREACHED */ 258 } 259 260 uchar_t 261 showxdr_u_char(char *fmt) 262 { 263 int pos; 264 uchar_t val; 265 266 pos = getxdr_pos(); 267 val = getxdr_u_char(); 268 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 269 return (val); 270 } 271 272 short 273 getxdr_short() 274 { 275 short s; 276 277 if (xdr_short(&xdrm, &s)) 278 return (s); 279 longjmp(xdr_err, 1); 280 /* NOTREACHED */ 281 } 282 283 short 284 showxdr_short(char *fmt) 285 { 286 int pos; short val; 287 288 pos = getxdr_pos(); 289 val = getxdr_short(); 290 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 291 return (val); 292 } 293 294 ushort_t 295 getxdr_u_short() 296 { 297 ushort_t s; 298 299 if (xdr_u_short(&xdrm, &s)) 300 return (s); 301 longjmp(xdr_err, 1); 302 /* NOTREACHED */ 303 } 304 305 ushort_t 306 showxdr_u_short(char *fmt) 307 { 308 int pos; 309 ushort_t val; 310 311 pos = getxdr_pos(); 312 val = getxdr_u_short(); 313 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 314 return (val); 315 } 316 317 long 318 getxdr_long() 319 { 320 long l; 321 322 if (xdr_long(&xdrm, &l)) 323 return (l); 324 longjmp(xdr_err, 1); 325 /* NOTREACHED */ 326 } 327 328 long 329 showxdr_long(char *fmt) 330 { 331 int pos; long val; 332 333 pos = getxdr_pos(); 334 val = getxdr_long(); 335 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 336 return (val); 337 } 338 339 ulong_t 340 getxdr_u_long() 341 { 342 ulong_t l; 343 344 if (xdr_u_long(&xdrm, &l)) 345 return (l); 346 longjmp(xdr_err, 1); 347 /* NOTREACHED */ 348 } 349 350 ulong_t 351 showxdr_u_long(char *fmt) 352 { 353 int pos; 354 ulong_t val; 355 356 pos = getxdr_pos(); 357 val = getxdr_u_long(); 358 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 359 return (val); 360 } 361 362 longlong_t 363 getxdr_longlong() 364 { 365 longlong_t l; 366 367 if (xdr_longlong_t(&xdrm, &l)) 368 return (l); 369 longjmp(xdr_err, 1); 370 /* NOTREACHED */ 371 } 372 373 longlong_t 374 showxdr_longlong(char *fmt) 375 { 376 int pos; longlong_t val; 377 378 pos = getxdr_pos(); 379 val = getxdr_longlong(); 380 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 381 return (val); 382 } 383 384 u_longlong_t 385 getxdr_u_longlong() 386 { 387 u_longlong_t l; 388 389 if (xdr_u_longlong_t(&xdrm, &l)) 390 return (l); 391 longjmp(xdr_err, 1); 392 /* NOTREACHED */ 393 } 394 395 u_longlong_t 396 showxdr_u_longlong(char *fmt) 397 { 398 int pos; u_longlong_t val; 399 400 pos = getxdr_pos(); 401 val = getxdr_u_longlong(); 402 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 403 return (val); 404 } 405 406 bool_t 407 getxdr_bool() 408 { 409 bool_t b; 410 411 if (xdr_bool(&xdrm, &b)) 412 return (b); 413 longjmp(xdr_err, 1); 414 /* NOTREACHED */ 415 } 416 417 bool_t 418 showxdr_bool(char *fmt) 419 { 420 int pos; bool_t val; 421 422 pos = getxdr_pos(); 423 val = getxdr_bool(); 424 (void) sprintf(get_line(pos, getxdr_pos()), fmt, 425 val ? "True" : "False"); 426 return (val); 427 } 428 429 char * 430 getxdr_opaque(char *p, int len) 431 { 432 if (xdr_opaque(&xdrm, p, len)) 433 return (p); 434 longjmp(xdr_err, 1); 435 /* NOTREACHED */ 436 } 437 438 char * 439 getxdr_string(char *p, /* len+1 bytes or longer */ 440 int len) 441 { 442 if (xdr_string(&xdrm, &p, len)) 443 return (p); 444 longjmp(xdr_err, 1); 445 /* NOTREACHED */ 446 } 447 448 char * 449 showxdr_string(int len, /* XDR length */ 450 char *fmt) 451 { 452 static int buff_len = 0; 453 static char *buff = NULL; 454 int pos; 455 456 /* 457 * XDR strings don't necessarily have a trailing null over the 458 * wire. However, the XDR code will put one in for us. Make sure 459 * we have allocated room for it. 460 */ 461 len++; 462 463 if ((len > buff_len) || (buff_len == 0)) { 464 if (buff) 465 free(buff); 466 if ((buff = (char *)malloc(len)) == NULL) 467 pr_err("showxdr_string: no mem"); 468 buff_len = len; 469 } 470 pos = getxdr_pos(); 471 getxdr_string(buff, len); 472 (void) strcpy(buff+60, "..."); 473 (void) sprintf(get_line(pos, getxdr_pos()), fmt, buff); 474 return (buff); 475 } 476 477 char * 478 getxdr_bytes(uint_t *lenp) 479 { 480 static char buff[1024]; 481 char *p = buff; 482 483 if (xdr_bytes(&xdrm, &p, lenp, 1024)) 484 return (buff); 485 longjmp(xdr_err, 1); 486 /* NOTREACHED */ 487 } 488 489 char * 490 getxdr_context(char *p, int len) 491 { 492 ushort_t size; 493 494 size = getxdr_u_short(); 495 if (((int)size > 0) && ((int)size < len) && getxdr_opaque(p, size)) 496 return (p); 497 longjmp(xdr_err, 1); 498 /* NOTREACHED */ 499 } 500 501 char * 502 showxdr_context(char *fmt) 503 { 504 ushort_t size; 505 static char buff[1024]; 506 int pos; 507 508 pos = getxdr_pos(); 509 size = getxdr_u_short(); 510 if (((int)size > 0) && ((int)size < 1024) && 511 getxdr_opaque(buff, size)) { 512 (void) sprintf(get_line(pos, getxdr_pos()), fmt, buff); 513 return (buff); 514 } 515 longjmp(xdr_err, 1); 516 /* NOTREACHED */ 517 } 518 519 enum_t 520 getxdr_enum() 521 { 522 enum_t e; 523 524 if (xdr_enum(&xdrm, &e)) 525 return (e); 526 longjmp(xdr_err, 1); 527 /* NOTREACHED */ 528 } 529 530 void 531 xdr_skip(int delta) 532 { 533 uint_t pos; 534 if (delta % 4 != 0 || delta < 0) 535 longjmp(xdr_err, 1); 536 /* Check for overflow */ 537 pos = xdr_getpos(&xdrm); 538 if ((pos + delta) < pos) 539 longjmp(xdr_err, 1); 540 /* xdr_setpos() checks for buffer overrun */ 541 if (xdr_setpos(&xdrm, pos + delta) == FALSE) 542 longjmp(xdr_err, 1); 543 } 544 545 int 546 getxdr_pos() 547 { 548 return (xdr_getpos(&xdrm)); 549 } 550 551 void 552 setxdr_pos(int pos) 553 { 554 xdr_setpos(&xdrm, pos); 555 } 556 557 void 558 show_space() 559 { 560 (void) get_line(0, 0); 561 } 562 563 void 564 show_trailer() 565 { 566 show_space(); 567 } 568 569 char * 570 getxdr_date() 571 { 572 time_t sec; 573 int usec; 574 static char buff[64]; 575 char *p; 576 struct tm my_time; /* private buffer to avoid collision */ 577 /* between gmtime and strftime */ 578 struct tm *tmp; 579 580 sec = getxdr_long(); 581 usec = getxdr_long(); 582 if (sec == -1) 583 return ("-1 "); 584 585 if (sec < 3600 * 24 * 365) { /* assume not a date */ 586 (void) sprintf(buff, "%d.%06d", sec, usec); 587 } else { 588 tmp = gmtime(&sec); 589 (void) memcpy(&my_time, tmp, sizeof (struct tm)); 590 strftime(buff, sizeof (buff), "%d-%h-%y %T.", &my_time); 591 p = buff + strlen(buff); 592 (void) sprintf(p, "%06d GMT", usec); 593 } 594 return (buff); 595 } 596 597 char * 598 showxdr_date(char *fmt) 599 { 600 int pos; 601 char *p; 602 603 pos = getxdr_pos(); 604 p = getxdr_date(); 605 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p); 606 return (p); 607 } 608 609 char * 610 getxdr_date_ns(void) 611 { 612 time_t sec, nsec; 613 614 sec = getxdr_long(); 615 nsec = getxdr_long(); 616 if (sec == -1) 617 return ("-1 "); 618 else 619 return (format_time(sec, nsec)); 620 } 621 622 /* 623 * Format the given time. 624 */ 625 char * 626 format_time(int64_t sec, uint32_t nsec) 627 { 628 static char buff[64]; 629 char *p; 630 struct tm my_time; /* private buffer to avoid collision */ 631 /* between gmtime and strftime */ 632 struct tm *tmp; 633 634 if (sec < 3600 * 24 * 365) { 635 /* assume not a date; includes negative times */ 636 (void) sprintf(buff, "%lld.%06d", sec, nsec); 637 } else if (sec > INT32_MAX) { 638 /* 639 * XXX No routines are available yet for formatting 64-bit 640 * times. 641 */ 642 (void) sprintf(buff, "%lld.%06d", sec, nsec); 643 } else { 644 time_t sec32 = (time_t)sec; 645 646 tmp = gmtime(&sec32); 647 memcpy(&my_time, tmp, sizeof (struct tm)); 648 strftime(buff, sizeof (buff), "%d-%h-%y %T.", &my_time); 649 p = buff + strlen(buff); 650 (void) sprintf(p, "%09d GMT", nsec); 651 } 652 return (buff); 653 } 654 655 char * 656 showxdr_date_ns(char *fmt) 657 { 658 int pos; 659 char *p; 660 661 pos = getxdr_pos(); 662 p = getxdr_date_ns(); 663 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p); 664 return (p); 665 } 666 667 char * 668 getxdr_time() 669 { 670 time_t sec; 671 static char buff[64]; 672 struct tm my_time; /* private buffer to avoid collision */ 673 /* between gmtime and strftime */ 674 struct tm *tmp; 675 676 sec = getxdr_long(); 677 if (sec == -1) 678 return ("-1 "); 679 680 if (sec < 3600 * 24 * 365) { /* assume not a date */ 681 (void) sprintf(buff, "%d", sec); 682 } else { 683 tmp = gmtime(&sec); 684 memcpy(&my_time, tmp, sizeof (struct tm)); 685 strftime(buff, sizeof (buff), "%d-%h-%y %T", &my_time); 686 } 687 return (buff); 688 } 689 690 char * 691 showxdr_time(char *fmt) 692 { 693 int pos; 694 char *p; 695 696 pos = getxdr_pos(); 697 p = getxdr_time(); 698 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p); 699 return (p); 700 } 701 702 char * 703 getxdr_hex(int len) 704 { 705 int i, j; 706 static char hbuff[1024]; 707 char rbuff[1024]; 708 static char *hexstr = "0123456789ABCDEF"; 709 char toobig = 0; 710 711 if (len == 0) { 712 hbuff[0] = '\0'; 713 return (hbuff); 714 } 715 if (len > 1024) 716 len = 1024; 717 if (len < 0 || xdr_opaque(&xdrm, rbuff, len) == FALSE) { 718 longjmp(xdr_err, 1); 719 } 720 721 if (len * 2 > sizeof (hbuff)) { 722 toobig++; 723 len = sizeof (hbuff) / 2; 724 } 725 726 j = 0; 727 for (i = 0; i < len; i++) { 728 hbuff[j++] = hexstr[rbuff[i] >> 4 & 0x0f]; 729 hbuff[j++] = hexstr[rbuff[i] & 0x0f]; 730 } 731 732 if (toobig) { 733 hbuff[len * 2 - strlen("<Too Long>")] = '\0'; 734 strcat(hbuff, "<Too Long>"); 735 } else 736 hbuff[j] = '\0'; 737 738 return (hbuff); 739 } 740 741 char * 742 showxdr_hex(int len, char *fmt) 743 { 744 int pos; 745 char *p; 746 747 pos = getxdr_pos(); 748 p = getxdr_hex(len); 749 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p); 750 return (p); 751 } 752 753 static void 754 hexdump(char *data, int datalen) 755 { 756 char *p; 757 ushort_t *p16 = (ushort_t *)data; 758 char *p8 = data; 759 int i, left, len; 760 int chunk = 16; /* 16 bytes per line */ 761 762 printf("\n"); 763 764 for (p = data; p < data + datalen; p += chunk) { 765 printf("\t%4d: ", p - data); 766 left = (data + datalen) - p; 767 len = MIN(chunk, left); 768 for (i = 0; i < (len / 2); i++) 769 printf("%04x ", ntohs(*p16++) & 0xffff); 770 if (len % 2) { 771 printf("%02x ", *((unsigned char *)p16)); 772 } 773 for (i = 0; i < (chunk - left) / 2; i++) 774 printf(" "); 775 776 printf(" "); 777 for (i = 0; i < len; i++, p8++) 778 printf("%c", isprint(*p8) ? *p8 : '.'); 779 printf("\n"); 780 } 781 782 printf("\n"); 783 } 784 785 char * 786 show_string(const char *str, int dlen, int maxlen) 787 /* 788 * Prints len bytes from str enclosed in quotes. 789 * If len is negative, length is taken from strlen(str). 790 * No more than maxlen bytes will be printed. Longer 791 * strings are flagged with ".." after the closing quote. 792 * Non-printing characters are converted to C-style escape 793 * codes or octal digits. 794 */ 795 { 796 #define TBSIZE 256 797 static char tbuff[TBSIZE]; 798 const char *p; 799 char *pp; 800 int printable = 0; 801 int c, len; 802 803 len = dlen > maxlen ? maxlen : dlen; 804 dlen = len; 805 806 for (p = str, pp = tbuff; len; p++, len--) { 807 switch (c = *p & 0xFF) { 808 case '\n': (void) strcpy(pp, "\\n"); pp += 2; break; 809 case '\b': (void) strcpy(pp, "\\b"); pp += 2; break; 810 case '\t': (void) strcpy(pp, "\\t"); pp += 2; break; 811 case '\r': (void) strcpy(pp, "\\r"); pp += 2; break; 812 case '\f': (void) strcpy(pp, "\\f"); pp += 2; break; 813 default: 814 if (isascii(c) && isprint(c)) { 815 *pp++ = c; 816 printable++; 817 } else { 818 (void) snprintf(pp, TBSIZE - (pp - tbuff), 819 isdigit(*(p + 1)) ? 820 "\\%03o" : "\\%o", c); 821 pp += strlen(pp); 822 } 823 break; 824 } 825 *pp = '\0'; 826 /* 827 * Check for overflow of temporary buffer. Allow for 828 * the next character to be a \nnn followed by a trailing 829 * null. If not, then just bail with what we have. 830 */ 831 if (pp + 5 >= &tbuff[TBSIZE]) { 832 break; 833 } 834 } 835 return (printable > dlen / 2 ? tbuff : ""); 836 } 837