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 26 #pragma ident "%Z%%M% %I% %E% SMI" 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 <varargs.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 char * 194 get_line(int begin, int end) 195 { 196 char *line; 197 198 line = get_detail_line(begin, end); 199 (void) strcpy(line, prot_nest_prefix); 200 (void) strcat(line, prot_prefix); 201 return (line + strlen(line)); 202 } 203 204 int 205 get_line_remain(void) 206 { 207 return (MAXLINE - strlen(prot_nest_prefix) - strlen(prot_prefix)); 208 } 209 210 void 211 show_line(char *str) 212 { 213 (void) strcpy(get_line(0, 0), str); 214 } 215 216 char 217 getxdr_char() 218 { 219 char s; 220 221 if (xdr_char(&xdrm, &s)) 222 return (s); 223 longjmp(xdr_err, 1); 224 /* NOTREACHED */ 225 } 226 227 char 228 showxdr_char(char *fmt) 229 { 230 int pos; char val; 231 232 pos = getxdr_pos(); 233 val = getxdr_char(); 234 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 235 return (val); 236 } 237 238 uchar_t 239 getxdr_u_char() 240 { 241 uchar_t s; 242 243 if (xdr_u_char(&xdrm, &s)) 244 return (s); 245 longjmp(xdr_err, 1); 246 /* NOTREACHED */ 247 } 248 249 uchar_t 250 showxdr_u_char(char *fmt) 251 { 252 int pos; 253 uchar_t val; 254 255 pos = getxdr_pos(); 256 val = getxdr_u_char(); 257 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 258 return (val); 259 } 260 261 short 262 getxdr_short() 263 { 264 short s; 265 266 if (xdr_short(&xdrm, &s)) 267 return (s); 268 longjmp(xdr_err, 1); 269 /* NOTREACHED */ 270 } 271 272 short 273 showxdr_short(char *fmt) 274 { 275 int pos; short val; 276 277 pos = getxdr_pos(); 278 val = getxdr_short(); 279 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 280 return (val); 281 } 282 283 ushort_t 284 getxdr_u_short() 285 { 286 ushort_t s; 287 288 if (xdr_u_short(&xdrm, &s)) 289 return (s); 290 longjmp(xdr_err, 1); 291 /* NOTREACHED */ 292 } 293 294 ushort_t 295 showxdr_u_short(char *fmt) 296 { 297 int pos; 298 ushort_t val; 299 300 pos = getxdr_pos(); 301 val = getxdr_u_short(); 302 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 303 return (val); 304 } 305 306 long 307 getxdr_long() 308 { 309 long l; 310 311 if (xdr_long(&xdrm, &l)) 312 return (l); 313 longjmp(xdr_err, 1); 314 /* NOTREACHED */ 315 } 316 317 long 318 showxdr_long(char *fmt) 319 { 320 int pos; long val; 321 322 pos = getxdr_pos(); 323 val = getxdr_long(); 324 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 325 return (val); 326 } 327 328 ulong_t 329 getxdr_u_long() 330 { 331 ulong_t l; 332 333 if (xdr_u_long(&xdrm, &l)) 334 return (l); 335 longjmp(xdr_err, 1); 336 /* NOTREACHED */ 337 } 338 339 ulong_t 340 showxdr_u_long(char *fmt) 341 { 342 int pos; 343 ulong_t val; 344 345 pos = getxdr_pos(); 346 val = getxdr_u_long(); 347 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 348 return (val); 349 } 350 351 longlong_t 352 getxdr_longlong() 353 { 354 longlong_t l; 355 356 if (xdr_longlong_t(&xdrm, &l)) 357 return (l); 358 longjmp(xdr_err, 1); 359 /* NOTREACHED */ 360 } 361 362 longlong_t 363 showxdr_longlong(char *fmt) 364 { 365 int pos; longlong_t val; 366 367 pos = getxdr_pos(); 368 val = getxdr_longlong(); 369 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 370 return (val); 371 } 372 373 u_longlong_t 374 getxdr_u_longlong() 375 { 376 u_longlong_t l; 377 378 if (xdr_u_longlong_t(&xdrm, &l)) 379 return (l); 380 longjmp(xdr_err, 1); 381 /* NOTREACHED */ 382 } 383 384 u_longlong_t 385 showxdr_u_longlong(char *fmt) 386 { 387 int pos; u_longlong_t val; 388 389 pos = getxdr_pos(); 390 val = getxdr_u_longlong(); 391 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 392 return (val); 393 } 394 395 bool_t 396 getxdr_bool() 397 { 398 bool_t b; 399 400 if (xdr_bool(&xdrm, &b)) 401 return (b); 402 longjmp(xdr_err, 1); 403 /* NOTREACHED */ 404 } 405 406 bool_t 407 showxdr_bool(char *fmt) 408 { 409 int pos; bool_t val; 410 411 pos = getxdr_pos(); 412 val = getxdr_bool(); 413 (void) sprintf(get_line(pos, getxdr_pos()), fmt, 414 val ? "True" : "False"); 415 return (val); 416 } 417 418 char * 419 getxdr_opaque(char *p, int len) 420 { 421 if (xdr_opaque(&xdrm, p, len)) 422 return (p); 423 longjmp(xdr_err, 1); 424 /* NOTREACHED */ 425 } 426 427 char * 428 getxdr_string(char *p, /* len+1 bytes or longer */ 429 int len) 430 { 431 if (xdr_string(&xdrm, &p, len)) 432 return (p); 433 longjmp(xdr_err, 1); 434 /* NOTREACHED */ 435 } 436 437 char * 438 showxdr_string(int len, /* XDR length */ 439 char *fmt) 440 { 441 static int buff_len = 0; 442 static char *buff = NULL; 443 int pos; 444 445 /* 446 * XDR strings don't necessarily have a trailing null over the 447 * wire. However, the XDR code will put one in for us. Make sure 448 * we have allocated room for it. 449 */ 450 len++; 451 452 if ((len > buff_len) || (buff_len == 0)) { 453 if (buff) 454 free(buff); 455 if ((buff = (char *)malloc(len)) == NULL) 456 pr_err("showxdr_string: no mem"); 457 buff_len = len; 458 } 459 pos = getxdr_pos(); 460 getxdr_string(buff, len); 461 (void) strcpy(buff+60, "..."); 462 (void) sprintf(get_line(pos, getxdr_pos()), fmt, buff); 463 return (buff); 464 } 465 466 char * 467 getxdr_bytes(uint_t *lenp) 468 { 469 static char buff[1024]; 470 char *p = buff; 471 472 if (xdr_bytes(&xdrm, &p, lenp, 1024)) 473 return (buff); 474 longjmp(xdr_err, 1); 475 /* NOTREACHED */ 476 } 477 478 char * 479 getxdr_context(char *p, int len) 480 { 481 ushort_t size; 482 483 size = getxdr_u_short(); 484 if (((int)size > 0) && ((int)size < len) && getxdr_opaque(p, size)) 485 return (p); 486 longjmp(xdr_err, 1); 487 /* NOTREACHED */ 488 } 489 490 char * 491 showxdr_context(char *fmt) 492 { 493 ushort_t size; 494 static char buff[1024]; 495 int pos; 496 497 pos = getxdr_pos(); 498 size = getxdr_u_short(); 499 if (((int)size > 0) && ((int)size < 1024) && 500 getxdr_opaque(buff, size)) { 501 (void) sprintf(get_line(pos, getxdr_pos()), fmt, buff); 502 return (buff); 503 } 504 longjmp(xdr_err, 1); 505 /* NOTREACHED */ 506 } 507 508 enum_t 509 getxdr_enum() 510 { 511 enum_t e; 512 513 if (xdr_enum(&xdrm, &e)) 514 return (e); 515 longjmp(xdr_err, 1); 516 /* NOTREACHED */ 517 } 518 519 void 520 xdr_skip(int delta) 521 { 522 uint_t pos; 523 if (delta % 4 != 0 || delta < 0) 524 longjmp(xdr_err, 1); 525 /* Check for overflow */ 526 pos = xdr_getpos(&xdrm); 527 if ((pos + delta) < pos) 528 longjmp(xdr_err, 1); 529 /* xdr_setpos() checks for buffer overrun */ 530 if (xdr_setpos(&xdrm, pos + delta) == FALSE) 531 longjmp(xdr_err, 1); 532 } 533 534 int 535 getxdr_pos() 536 { 537 return (xdr_getpos(&xdrm)); 538 } 539 540 void 541 setxdr_pos(int pos) 542 { 543 xdr_setpos(&xdrm, pos); 544 } 545 546 void 547 show_space() 548 { 549 (void) get_line(0, 0); 550 } 551 552 void 553 show_trailer() 554 { 555 show_space(); 556 } 557 558 char * 559 getxdr_date() 560 { 561 time_t sec; 562 int usec; 563 static char buff[64]; 564 char *p; 565 struct tm my_time; /* private buffer to avoid collision */ 566 /* between gmtime and strftime */ 567 struct tm *tmp; 568 569 sec = getxdr_long(); 570 usec = getxdr_long(); 571 if (sec == -1) 572 return ("-1 "); 573 574 if (sec < 3600 * 24 * 365) { /* assume not a date */ 575 (void) sprintf(buff, "%d.%06d", sec, usec); 576 } else { 577 tmp = gmtime(&sec); 578 (void) memcpy(&my_time, tmp, sizeof (struct tm)); 579 strftime(buff, sizeof (buff), "%d-%h-%y %T.", &my_time); 580 p = buff + strlen(buff); 581 (void) sprintf(p, "%06d GMT", usec); 582 } 583 return (buff); 584 } 585 586 char * 587 showxdr_date(char *fmt) 588 { 589 int pos; 590 char *p; 591 592 pos = getxdr_pos(); 593 p = getxdr_date(); 594 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p); 595 return (p); 596 } 597 598 char * 599 getxdr_date_ns(void) 600 { 601 time_t sec, nsec; 602 603 sec = getxdr_long(); 604 nsec = getxdr_long(); 605 if (sec == -1) 606 return ("-1 "); 607 else 608 return (format_time(sec, nsec)); 609 } 610 611 /* 612 * Format the given time. 613 */ 614 char * 615 format_time(int64_t sec, uint32_t nsec) 616 { 617 static char buff[64]; 618 char *p; 619 struct tm my_time; /* private buffer to avoid collision */ 620 /* between gmtime and strftime */ 621 struct tm *tmp; 622 623 if (sec < 3600 * 24 * 365) { 624 /* assume not a date; includes negative times */ 625 (void) sprintf(buff, "%lld.%06d", sec, nsec); 626 } else if (sec > INT32_MAX) { 627 /* 628 * XXX No routines are available yet for formatting 64-bit 629 * times. 630 */ 631 (void) sprintf(buff, "%lld.%06d", sec, nsec); 632 } else { 633 time_t sec32 = (time_t)sec; 634 635 tmp = gmtime(&sec32); 636 memcpy(&my_time, tmp, sizeof (struct tm)); 637 strftime(buff, sizeof (buff), "%d-%h-%y %T.", &my_time); 638 p = buff + strlen(buff); 639 (void) sprintf(p, "%09d GMT", nsec); 640 } 641 return (buff); 642 } 643 644 char * 645 showxdr_date_ns(char *fmt) 646 { 647 int pos; 648 char *p; 649 650 pos = getxdr_pos(); 651 p = getxdr_date_ns(); 652 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p); 653 return (p); 654 } 655 656 char * 657 getxdr_time() 658 { 659 time_t sec; 660 static char buff[64]; 661 struct tm my_time; /* private buffer to avoid collision */ 662 /* between gmtime and strftime */ 663 struct tm *tmp; 664 665 sec = getxdr_long(); 666 if (sec == -1) 667 return ("-1 "); 668 669 if (sec < 3600 * 24 * 365) { /* assume not a date */ 670 (void) sprintf(buff, "%d", sec); 671 } else { 672 tmp = gmtime(&sec); 673 memcpy(&my_time, tmp, sizeof (struct tm)); 674 strftime(buff, sizeof (buff), "%d-%h-%y %T", &my_time); 675 } 676 return (buff); 677 } 678 679 char * 680 showxdr_time(char *fmt) 681 { 682 int pos; 683 char *p; 684 685 pos = getxdr_pos(); 686 p = getxdr_time(); 687 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p); 688 return (p); 689 } 690 691 char * 692 getxdr_hex(int len) 693 { 694 int i, j; 695 static char hbuff[1024]; 696 char rbuff[1024]; 697 static char *hexstr = "0123456789ABCDEF"; 698 char toobig = 0; 699 700 if (len == 0) { 701 hbuff[0] = '\0'; 702 return (hbuff); 703 } 704 if (len > 1024) 705 len = 1024; 706 if (len < 0 || xdr_opaque(&xdrm, rbuff, len) == FALSE) { 707 longjmp(xdr_err, 1); 708 } 709 710 if (len * 2 > sizeof (hbuff)) { 711 toobig++; 712 len = sizeof (hbuff) / 2; 713 } 714 715 j = 0; 716 for (i = 0; i < len; i++) { 717 hbuff[j++] = hexstr[rbuff[i] >> 4 & 0x0f]; 718 hbuff[j++] = hexstr[rbuff[i] & 0x0f]; 719 } 720 721 if (toobig) { 722 hbuff[len * 2 - strlen("<Too Long>")] = '\0'; 723 strcat(hbuff, "<Too Long>"); 724 } else 725 hbuff[j] = '\0'; 726 727 return (hbuff); 728 } 729 730 char * 731 showxdr_hex(int len, char *fmt) 732 { 733 int pos; 734 char *p; 735 736 pos = getxdr_pos(); 737 p = getxdr_hex(len); 738 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p); 739 return (p); 740 } 741 742 static void 743 hexdump(char *data, int datalen) 744 { 745 char *p; 746 ushort_t *p16 = (ushort_t *)data; 747 char *p8 = data; 748 int i, left, len; 749 int chunk = 16; /* 16 bytes per line */ 750 751 printf("\n"); 752 753 for (p = data; p < data + datalen; p += chunk) { 754 printf("\t%4d: ", p - data); 755 left = (data + datalen) - p; 756 len = MIN(chunk, left); 757 for (i = 0; i < (len / 2); i++) 758 printf("%04x ", ntohs(*p16++) & 0xffff); 759 if (len % 2) { 760 printf("%02x ", *((unsigned char *)p16)); 761 } 762 for (i = 0; i < (chunk - left) / 2; i++) 763 printf(" "); 764 765 printf(" "); 766 for (i = 0; i < len; i++, p8++) 767 printf("%c", isprint(*p8) ? *p8 : '.'); 768 printf("\n"); 769 } 770 771 printf("\n"); 772 } 773