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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1998,2000 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #include <stdio.h> 28 #include <arpa/inet.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <sys/time.h> 32 #include <iconv.h> 33 #include "snoop.h" 34 #include "slp.h" 35 36 #define MAXSUMLEN 30 37 38 /* define VERIFYSLP to enable full message checking in summary mode */ 39 #define VERIFYSLP 40 41 /* Globals -- ugly, yes, but fast and easy in macros */ 42 static int msglength; 43 static int retlength; 44 static char *msgend; /* the end of the summary message buffer */ 45 static char *p; /* current position in the packet */ 46 static char *msgbuf; /* message buffer for summary mode */ 47 static boolean_t url_auth = B_FALSE; 48 static boolean_t attr_auth = B_FALSE; 49 static boolean_t fresh = B_FALSE; 50 static boolean_t overflow = B_FALSE; 51 static int v1_charset = 0; /* character set; only in V1 */ 52 53 /* Entry points for parsing the protocol */ 54 static int interpret_slp_v1(int, struct slpv1_hdr *, int); 55 static int interpret_slp_v2(int, struct slpv2_hdr *, int); 56 57 /* header parsing */ 58 static int v1_header(int, struct slpv1_hdr *, int); 59 static int v2_header(int, struct slpv2_hdr *, int *, int); 60 static int v2_finish(struct slpv2_hdr *, int); 61 62 /* V2 auth blocks */ 63 static int slpv2_authblock(int); 64 65 /* 66 * Functions for parsing each protocol message 67 * Each function takes the interpreter's flags argument as its input 68 * parameter, and returns 1 on success, or 0 on message corruption. 69 * retlength is set as a side-effect in summary mode. 70 */ 71 static int v2_srv_rqst(int); 72 static int v2_srv_rply(int); 73 static int v2_srv_reg(int); 74 static int v2_srv_dereg(int); 75 static int v2_srv_ack(int); 76 static int v2_attr_rqst(int); 77 static int v2_attr_rply(int); 78 static int v2_daadvert(int); 79 static int v2_srv_type_rqst(int); 80 static int v2_srv_type_rply(int); 81 static int v2_saadvert(int); 82 83 static int v1_srv_rqst(int); 84 static int v1_srv_rply(int); 85 static int v1_srv_reg(int); 86 static int v1_srv_dereg(int); 87 static int v1_srv_ack(int); 88 static int v1_attr_rqst(int); 89 static int v1_attr_rply(int); 90 static int v1_daadvert(int); 91 static int v1_srv_type_rqst(int); 92 static int v1_srv_type_rply(int); 93 94 /* 95 * The dispatch tables for handling individual messages, keyed by 96 * function number. 97 */ 98 typedef int function_handler(); 99 100 #define V2_MAX_FUNCTION 11 101 102 static function_handler *v2_functions[V2_MAX_FUNCTION + 1] = { 103 (function_handler *) NULL, 104 (function_handler *) v2_srv_rqst, 105 (function_handler *) v2_srv_rply, 106 (function_handler *) v2_srv_reg, 107 (function_handler *) v2_srv_dereg, 108 (function_handler *) v2_srv_ack, 109 (function_handler *) v2_attr_rqst, 110 (function_handler *) v2_attr_rply, 111 (function_handler *) v2_daadvert, 112 (function_handler *) v2_srv_type_rqst, 113 (function_handler *) v2_srv_type_rply, 114 (function_handler *) v2_saadvert }; 115 116 #define V1_MAX_FUNCTION 10 117 118 static function_handler *v1_functions[V1_MAX_FUNCTION + 1] = { 119 (function_handler *) NULL, 120 (function_handler *) v1_srv_rqst, 121 (function_handler *) v1_srv_rply, 122 (function_handler *) v1_srv_reg, 123 (function_handler *) v1_srv_dereg, 124 (function_handler *) v1_srv_ack, 125 (function_handler *) v1_attr_rqst, 126 (function_handler *) v1_attr_rply, 127 (function_handler *) v1_daadvert, 128 (function_handler *) v1_srv_type_rqst, 129 (function_handler *) v1_srv_type_rply }; 130 131 /* TCP continuation handling */ 132 static boolean_t tcp_continuation = B_FALSE; 133 134 #define MAX_TCPCONT 16 135 136 static struct tcp_cont { 137 int dst_port; 138 char *msg; 139 int totallen; 140 int curr_offset; 141 } *tcp_cont[MAX_TCPCONT]; 142 143 static int current_tcp_cont; 144 145 static void reg_tcp_cont(char *, int, int, int); 146 static int add_tcp_cont(struct tcp_cont *, char *, int); 147 static struct tcp_cont *find_tcp_cont(int); 148 static void remove_tcp_cont(int); 149 150 /* Conversions from numbers to strings */ 151 static char *slpv2_func(int, boolean_t); 152 static char *slpv2_error(unsigned short); 153 static char *slpv1_func(int, boolean_t); 154 static char *slpv1_error(unsigned short); 155 static char *slpv1_charset(unsigned short); 156 157 /* 158 * The only external entry point to the SLP interpreter. This function 159 * simply dispatches the packet based on the version. 160 */ 161 void interpret_slp(int flags, void *slp, int fraglen) { 162 extern int dst_port, curr_proto; 163 struct tcp_cont *tce = NULL; 164 char *s; 165 166 msglength = fraglen; 167 retlength = 0; 168 p = slp; 169 170 /* check if this is a TCP continuation */ 171 if (flags & F_DTAIL && curr_proto == IPPROTO_TCP) { 172 tce = find_tcp_cont(dst_port); 173 if (tce) { 174 if (add_tcp_cont(tce, slp, fraglen)) { 175 slp = tce->msg; 176 fraglen = tce->curr_offset; 177 tcp_continuation = B_TRUE; 178 } 179 } 180 } 181 if (*(char *)slp == 2 || tce) 182 interpret_slp_v2(flags, slp, fraglen); 183 else 184 interpret_slp_v1(flags, slp, fraglen); 185 186 tcp_continuation = B_FALSE; 187 } 188 189 /* 190 * Primitives. These are implemented as much as possible as macros for 191 * speed. 192 */ 193 194 #define FIELD_DEFAULT 0 195 #define FIELD_PREVRESP 1 196 #define FIELD_TYPENA 2 197 198 static long long netval = 0; /* need signed 64 bit quantity */ 199 200 /* gets two bytes from p and leaves the result in netval */ 201 #define nbtohs() \ 202 netval = ((int)(p[0] & 0xff)) << 8; \ 203 netval += ((int)(p[1] & 0xff)) 204 205 /* gets four bytes from p and leaves the result in netval */ 206 #define nbtohl() \ 207 netval = ((int)(p[0] & 0xff)) << 24; \ 208 netval += ((int)(p[1] & 0xff)) << 16; \ 209 netval += ((int)(p[2] & 0xff)) << 8; \ 210 netval += ((int)(p[3] & 0xff)) 211 212 #define get_byte() \ 213 if (msglength >= 1) { \ 214 netval = *p; \ 215 p++; \ 216 msglength--; \ 217 } else \ 218 netval = -1 219 220 #define GETBYTE(x) \ 221 get_byte(); \ 222 if ((retlength = netval) < 0) \ 223 return (0); \ 224 x = netval 225 226 #define SKIPBYTE \ 227 get_byte(); \ 228 if ((retlength = netval) < 0) \ 229 return (0); \ 230 231 /* 232 * gets two bytes from p, leaves the result in netval, and updates 233 * msglength and p. 234 */ 235 #define get_short() \ 236 if (msglength >= sizeof (unsigned short)) { \ 237 nbtohs(); \ 238 p += sizeof (unsigned short); \ 239 msglength -= sizeof (unsigned short); \ 240 } else \ 241 netval = -1 242 243 #define GETSHORT(x) \ 244 get_short(); \ 245 if ((retlength = netval) < 0) \ 246 return (0); \ 247 x = netval 248 249 #define SKIPSHORT \ 250 get_short(); \ 251 if ((retlength = netval) < 0) \ 252 return (0) 253 254 #define get_int24(pp) \ 255 netval = ((int)((pp)[0] & 0xff)) << 16; \ 256 netval += ((int)((pp)[1] & 0xff)) << 8; \ 257 netval += ((int)((pp)[2] & 0xff)) 258 259 static void slp_prevresp(char *p) { 260 char *p2; 261 262 /* cycle through all entries */ 263 for (; p != NULL; p = p2) { 264 p2 = strchr(p, ','); 265 if (p2 != NULL) 266 *p2++ = '\0'; 267 268 /* print entry at p */ 269 sprintf(get_line(0, 0), " \"%s\"", p); 270 } 271 } 272 273 static int skip_field(int type) { 274 unsigned short stringlen; 275 276 get_short(); 277 if (netval < 0) { 278 return (-1); 279 } 280 stringlen = netval; 281 282 /* special case for NA field in SrvTypeRqst */ 283 if (type == FIELD_TYPENA && stringlen == 0xffff) { 284 stringlen = 0; 285 } 286 287 if (stringlen > msglength) { 288 return (-1); 289 } 290 291 msglength -= stringlen; 292 p += stringlen; 293 294 return (stringlen); 295 } 296 297 #define SKIPFIELD(type) \ 298 if ((retlength = skip_field(type)) < 0) \ 299 return (0) 300 301 #define GETFIELD \ 302 get_short(); \ 303 if ((retlength = netval) < 0) \ 304 return (0); \ 305 strncat(msgbuf, p, (retlength > MAXSUMLEN ? MAXSUMLEN : retlength)); \ 306 p += retlength; \ 307 msglength -= retlength 308 309 /* 310 * Determines from the first five bytes of a potential SLP header 311 * if the following message is really an SLP message. Returns 1 if 312 * it is a real SLP message, 0 if not. 313 */ 314 int valid_slp(unsigned char *slphdr, int len) { 315 struct slpv1_hdr slp1; 316 struct slpv2_hdr slp2; 317 318 len -= (8 /* udp */ + 20 /* IP */ + 14 /* ether */); 319 /* a valid version will be 1 or 2 */ 320 switch (*slphdr) { 321 case 1: 322 memcpy(&slp1, slphdr, 5); 323 /* valid function? */ 324 if (slp1.function > V1_MAX_FUNCTION) { 325 return (0); 326 } 327 /* valid length heuristic */ 328 if (slp1.length > len) { 329 return (0); 330 } 331 return (1); 332 case 2: 333 memcpy(&slp2, slphdr, 5); 334 /* valid function? */ 335 if (slp2.function > V2_MAX_FUNCTION) { 336 return (0); 337 } 338 /* valid length heuristic */ 339 get_int24(&(slp2.l1)); 340 if (netval > len) { 341 return (0); 342 } 343 return (1); 344 default: 345 return (0); 346 } 347 } 348 349 /* 350 * Converts a V1 char encoding to UTF8. If this fails, returns 0, 351 * otherwise, 1. This function is the union of iconv UTF-8 352 * modules and character sets registered with IANA. 353 */ 354 static int make_utf8(char *outbuf, size_t outlen, 355 const char *inbuf, size_t inlen) { 356 iconv_t cd; 357 size_t converted; 358 359 switch (v1_charset) { 360 case 4: 361 case 1004: 362 cd = iconv_open("UTF-8", "8859-1"); 363 break; 364 case 5: 365 cd = iconv_open("UTF-8", "8859-2"); 366 break; 367 case 6: 368 cd = iconv_open("UTF-8", "8859-3"); 369 break; 370 case 7: 371 cd = iconv_open("UTF-8", "8859-4"); 372 break; 373 case 8: 374 cd = iconv_open("UTF-8", "8859-5"); 375 break; 376 case 9: 377 cd = iconv_open("UTF-8", "8859-6"); 378 break; 379 case 10: 380 cd = iconv_open("UTF-8", "8859-7"); 381 break; 382 case 11: 383 cd = iconv_open("UTF-8", "8859-8"); 384 break; 385 case 12: 386 cd = iconv_open("UTF-8", "8859-9"); 387 break; 388 case 13: 389 cd = iconv_open("UTF-8", "8859-10"); 390 break; 391 case 37: 392 cd = iconv_open("UTF-8", "ko_KR-iso2022-7"); 393 break; 394 case 104: 395 cd = iconv_open("UTF-8", "iso2022"); 396 break; 397 case 1000: 398 cd = iconv_open("UTF-8", "UCS-2"); 399 break; 400 case 1001: 401 cd = iconv_open("UTF-8", "UCS-4"); 402 break; 403 default: 404 /* 405 * charset not set, or reserved, or not supported, so 406 * just copy it and hope for the best. 407 */ 408 converted = outlen < inlen ? outlen : inlen; 409 memcpy(outbuf, inbuf, converted); 410 outbuf[converted] = 0; 411 return (1); 412 } 413 414 if (cd == (iconv_t)-1) { 415 return (0); 416 } 417 418 if ((converted = iconv(cd, &inbuf, &inlen, &outbuf, &outlen)) 419 == (size_t)-1) { 420 return (0); 421 } 422 423 outbuf[converted] = 0; 424 iconv_close(cd); 425 426 return (1); 427 } 428 429 static int slp_field(char *tag, int type) { 430 int length; 431 432 get_short(); 433 if (netval < 0) { 434 return (-1); 435 } 436 length = netval; 437 438 /* special case for NA field in SrvTypeRqst */ 439 if (type == FIELD_TYPENA && length == 0xffff) { 440 sprintf(get_line(0, 0), "%s: length = -1: Use all NAs", tag); 441 return (0); 442 } 443 444 sprintf(get_line(0, 0), "%s: length = %d", tag, length); 445 if (length > msglength) { 446 /* framing error: message is not long enough to contain data */ 447 sprintf(get_line(0, 0), 448 " [Framing error: remaining pkt length = %u]", 449 msglength); 450 return (-1); 451 } 452 453 if (length > 0) { 454 char *buf = malloc(length + 1); 455 if (buf != NULL) { 456 if (v1_charset) { 457 if (!make_utf8(buf, length, p, length)) { 458 strcpy(buf, "[Invalid Character Encoding]"); 459 } 460 } else { 461 memcpy(buf, p, length); 462 buf[length] = '\0'; /* ensure null-terminated */ 463 } 464 465 switch (type) { 466 case FIELD_PREVRESP: 467 slp_prevresp(buf); 468 break; 469 470 default: 471 sprintf(get_line(0, 0), " \"%s\"", buf); 472 break; 473 } 474 free(buf); 475 } 476 477 p += length; 478 msglength -= length; 479 } 480 481 /* return ok */ 482 return (0); 483 } 484 485 static int slpv2_url(int cnt) { 486 time_t exp; 487 int lifetime, length, n; 488 489 /* reserved */ 490 get_byte(); 491 if (netval < 0) 492 return (-1); 493 494 /* lifetime */ 495 get_short(); 496 if ((lifetime = netval) < 0) 497 return (-1); 498 499 /* length */ 500 get_short(); 501 if ((length = netval) < 0) 502 return (-1); 503 504 /* time */ 505 exp = time(0) + lifetime; 506 if (cnt == -1) 507 sprintf(get_line(0, 0), 508 "URL: length = %u, lifetime = %d (%24.24s)", 509 length, lifetime, ctime(&exp)); 510 else 511 /* number the URLs to make it easier to parse them */ 512 sprintf(get_line(0, 0), 513 "URL %d: length = %u, lifetime = %d (%24.24s)", 514 cnt, length, lifetime, ctime(&exp)); 515 516 if (length > msglength) { 517 if (!tcp_continuation) 518 /* framing error: message is not long enough to contain data */ 519 sprintf(get_line(0, 0), 520 " [Framing error: remaining pkt length = %u]", 521 msglength); 522 return (-1); 523 } 524 525 if (length > 0) { 526 char *buf = malloc(length + 1); 527 if (buf != NULL) { 528 memcpy(buf, p, length); 529 buf[length] = '\0'; /* ensure null-terminated */ 530 sprintf(get_line(0, 0), " \"%s\"", buf); 531 free(buf); 532 } 533 } 534 msglength -= length; 535 p += length; 536 537 get_byte(); 538 if ((n = netval) < 0) 539 return (-1); 540 541 if (n > 0) { 542 int i; 543 sprintf(get_line(0, 0), "%d Authentication Blocks", n); 544 for (i = 0; i < n; i++) 545 if ((length = slpv2_authblock(i)) < 0) 546 return (-1); 547 } 548 return (0); 549 } 550 551 #define DOFIELD(tag, type) \ 552 if (slp_field(tag, type) < 0) \ 553 return (0) 554 555 #define V2_DOURL(x) \ 556 if (slpv2_url(x) < 0) \ 557 return (0) 558 559 #define V2_DOERRCODE \ 560 if (msglength < sizeof (unsigned short)) \ 561 return (0); \ 562 nbtohs(); \ 563 errcode = netval; \ 564 sprintf(get_line(0, 0), "Error code = %d, %s", \ 565 errcode, slpv2_error(errcode)); \ 566 p += sizeof (unsigned short); \ 567 msglength -= sizeof (unsigned short); \ 568 if (errcode != OK) \ 569 msglength = 0; /* skip rest of message */ \ 570 if (errcode != OK) \ 571 return (0) 572 573 #define V2_DOAUTH(cnt) \ 574 if (slpv2_authblock(cnt) < 0) \ 575 return (0) 576 577 #define V2_DOTIMESTAMP \ 578 if (msglength < 4) \ 579 return (0); \ 580 nbtohl(); \ 581 timestamp = netval; \ 582 sprintf(get_line(0, 0), "Timestamp = %u, %s", \ 583 timestamp, (timestamp ? convert_ts(timestamp) : "0")); \ 584 p += 4; \ 585 msglength -= 4 586 587 /* some V1 macros */ 588 #define SKIPAUTH(auth) \ 589 if (auth && ((retlength = skip_v1authblock()) < 0)) \ 590 return (0) 591 592 #define DOERRCODE \ 593 if (msglength < sizeof (unsigned short)) \ 594 return (0); \ 595 nbtohs(); \ 596 errcode = netval; \ 597 sprintf(get_line(0, 0), "Error code = %d, %s", errcode, \ 598 slpv1_error(errcode)); \ 599 p += sizeof (unsigned short); \ 600 msglength -= sizeof (unsigned short); \ 601 if (errcode != OK) \ 602 return (0) 603 604 #define DOURL \ 605 if (slpv1_url(url_auth) < 0) \ 606 return (0) 607 608 #define DOAUTH(auth) \ 609 if (auth && slpv1_authblock() < 0) \ 610 return (0) 611 612 /* 613 * TCP Continuation handling 614 * We keep track of continuations in a fixed size cache, so as to prevent 615 * memory leaks if some continuations are never finished. The continuations 616 * are indexed by their destination ports. 617 */ 618 static void reg_tcp_cont(char *msg, int totallen, 619 int fraglen, int dst_port) { 620 struct tcp_cont *tce = malloc(sizeof (*tce)); 621 622 /* always overwrite the entry at current_tcp_cont */ 623 if (tcp_cont[current_tcp_cont]) { 624 free(tcp_cont[current_tcp_cont]->msg); 625 free(tcp_cont[current_tcp_cont]); 626 } 627 628 tce->dst_port = dst_port; 629 tce->msg = malloc(totallen); 630 memcpy(tce->msg, msg, fraglen); 631 tce->totallen = totallen; 632 tce->curr_offset = fraglen; 633 634 tcp_cont[current_tcp_cont++] = tce; 635 if (current_tcp_cont == MAX_TCPCONT) 636 current_tcp_cont = 0; 637 } 638 639 /* returns 0 if there is a mismatch error, 1 on success */ 640 static int add_tcp_cont(struct tcp_cont *tce, char *msg, int fraglen) { 641 if ((fraglen + tce->curr_offset) > tce->totallen) 642 return (0); 643 644 memcpy(tce->msg + tce->curr_offset, msg, fraglen); 645 tce->curr_offset += fraglen; 646 return (1); 647 } 648 649 static struct tcp_cont *find_tcp_cont(int dst_port) { 650 int i; 651 for (i = current_tcp_cont; i >= 0; i--) 652 if (tcp_cont[i] && tcp_cont[i]->dst_port == dst_port) 653 return (tcp_cont[i]); 654 655 for (i = MAX_TCPCONT -1; i > current_tcp_cont; i--) 656 if (tcp_cont[i] && tcp_cont[i]->dst_port == dst_port) 657 return (tcp_cont[i]); 658 659 return (NULL); 660 } 661 662 static void remove_tcp_cont(int dst_port) { 663 int i; 664 for (i = current_tcp_cont; i >= 0; i--) 665 if (tcp_cont[i] && tcp_cont[i]->dst_port == dst_port) { 666 free(tcp_cont[i]->msg); 667 free(tcp_cont[i]); 668 tcp_cont[i] = NULL; 669 return; 670 } 671 672 for (i = MAX_TCPCONT -1; i > current_tcp_cont; i--) 673 if (tcp_cont[i] && tcp_cont[i]->dst_port == dst_port) { 674 free(tcp_cont[i]->msg); 675 free(tcp_cont[i]); 676 tcp_cont[i] = NULL; 677 return; 678 } 679 } 680 681 /* 682 * V2 interpreter 683 */ 684 685 static int interpret_slp_v2(int flags, struct slpv2_hdr *slp, int fraglen) { 686 extern int src_port, dst_port, curr_proto; 687 char msgbuf_real[256]; 688 int totallen = 0; 689 690 msgbuf = msgbuf_real; 691 692 /* 693 * Somewhat of a hack to decode traffic from a server that does 694 * not send udp replies from its SLP src port. 695 */ 696 697 if (curr_proto == IPPROTO_UDP && 698 dst_port == 427 && 699 src_port != 427) { 700 add_transient(src_port, (int (*)())interpret_slp); 701 } 702 703 /* parse the header */ 704 if (v2_header(flags, slp, &totallen, fraglen)) { 705 706 if (slp->function <= V2_MAX_FUNCTION && slp->function > 0) { 707 708 /* Parse the message body */ 709 if ((v2_functions[slp->function])(flags)) { 710 711 /* finish any remaining tasks */ 712 v2_finish(slp, flags); 713 714 } 715 716 } 717 718 } 719 720 /* summary error check */ 721 if (flags & F_SUM) { 722 if (retlength < 0) { 723 if (curr_proto == IPPROTO_TCP) 724 sprintf(get_sum_line(), 725 "%s [partial TCP message]", msgbuf); 726 else if (overflow) 727 sprintf(get_sum_line(), "%s [OVERFLOW]", msgbuf); 728 else 729 sprintf(get_sum_line(), "%s [CORRUPTED MESSAGE]", msgbuf); 730 } 731 #ifdef VERIFYSLP 732 else if (msglength > 0) 733 sprintf(get_sum_line(), "%s +%d", msgbuf, msglength); 734 #endif 735 else 736 sprintf(get_sum_line(), "%s", msgbuf); 737 } else if (flags & F_DTAIL) { 738 /* detailed error check */ 739 if (msglength > 0) { 740 if (tcp_continuation) { 741 sprintf(get_line(0, 0), 742 "[TCP Continuation, %d bytes remaining]", 743 totallen - fraglen); 744 } else 745 sprintf(get_line(0, 0), 746 "[%d extra bytes at end of SLP message]", msglength); 747 } 748 749 show_trailer(); 750 751 if (tcp_continuation && msglength == 0) 752 remove_tcp_cont(dst_port); 753 } 754 755 return (0); 756 } 757 758 static int v2_header(int flags, 759 struct slpv2_hdr *slp, 760 int *totallen, 761 int fraglen) { 762 extern int curr_proto, dst_port; 763 char *prototag = (curr_proto == IPPROTO_TCP ? "/tcp" : ""); 764 765 if ((slp->flags & V2_OVERFLOW) == V2_OVERFLOW) 766 overflow = B_TRUE; 767 768 /* summary mode header parsing */ 769 if (flags & F_SUM) { 770 771 /* make sure we have at least a header */ 772 if (msglength < sizeof (*slp)) { 773 sprintf(get_sum_line(), "SLP V2 [Incomplete Header]"); 774 return (0); 775 } 776 777 sprintf(msgbuf, "SLP V2 %s [%d%s] ", 778 slpv2_func(slp->function, B_TRUE), 779 ntohs(slp->xid), prototag); 780 781 /* skip to end of header */ 782 msgend = msgbuf + strlen(msgbuf); 783 msglength -= sizeof (*slp); 784 p += sizeof (*slp); 785 786 /* skip language tag */ 787 SKIPFIELD(FIELD_DEFAULT); 788 } else if (flags & F_DTAIL) { 789 char *lang; 790 int len; 791 792 /* detailed mode header parsing */ 793 show_header("SLP: ", "Service Location Protocol (v2)", fraglen); 794 show_space(); 795 796 if (msglength < sizeof (*slp)) { 797 sprintf(get_line(0, 0), "==> Incomplete SLP header"); 798 return (0); 799 } 800 801 sprintf(get_line(0, 0), "Version = %d", slp->vers); 802 sprintf(get_line(0, 0), "Function = %d, %s", 803 slp->function, slpv2_func(slp->function, B_FALSE)); 804 get_int24(&(slp->l1)); 805 *totallen = netval; 806 sprintf(get_line(0, 0), "Message length = %u", *totallen); 807 /* check for TCP continuation */ 808 if (curr_proto == IPPROTO_TCP && 809 *totallen > msglength && 810 !tcp_continuation) { 811 tcp_continuation = B_TRUE; 812 reg_tcp_cont((char *)slp, *totallen, msglength, dst_port); 813 } 814 815 if (!tcp_continuation && *totallen != msglength) { 816 sprintf(get_line(0, 0), 817 " (Stated and on-the-wire lengths differ)"); 818 } 819 /* flags */ 820 sprintf(get_line(0, 0), "Flags = 0x%02x", slp->flags); 821 sprintf(get_line(0, 0), " %s", 822 getflag(slp->flags, V2_OVERFLOW, 823 "overflow", "no overflow")); 824 sprintf(get_line(0, 0), " %s", 825 getflag(slp->flags, V2_FRESH, 826 "fresh registration", "no fresh registration")); 827 sprintf(get_line(0, 0), " %s", 828 getflag(slp->flags, V2_MCAST, 829 "request multicast / broadcast", "unicast")); 830 /* check reserved flags that must be zero */ 831 if ((slp->flags & 7) != 0) { 832 sprintf(get_line(0, 0), 833 " .... .xxx = %d (reserved flags nonzero)", 834 slp->flags & 7); 835 } 836 /* end of flags */ 837 838 /* language tag */ 839 p = (char *)slp + sizeof (*slp); 840 msglength -= sizeof (*slp); 841 GETSHORT(len); 842 if (len > msglength) { 843 sprintf(get_line(0, 0), 844 "Language Tag Length = %u [CORRUPT MESSAGE]", 845 len); 846 return (0); 847 } 848 849 lang = get_line(0, 0); 850 strcpy(lang, "Language Tag = "); 851 strncat(lang, p, len); 852 sprintf(get_line(0, 0), "XID = %u", ntohs(slp->xid)); 853 854 /* set msglength to remaining length of SLP message */ 855 p += len; 856 msglength -= len; 857 } 858 859 return (1); 860 } 861 862 static int v2_finish(struct slpv2_hdr *slp, int flags) { 863 unsigned int firstop; 864 865 if (!(flags & F_DTAIL)) 866 return (1); 867 868 /* check for options */ 869 get_int24(&(slp->o1)); 870 firstop = netval; 871 872 if (firstop) { 873 unsigned short op_id; 874 unsigned short nextop; 875 char *op_class; 876 877 for (;;) { 878 unsigned short real_oplen; 879 880 if (msglength < 4) { 881 sprintf(get_line(0, 0), 882 "Option expected but not present"); 883 return (0); 884 } 885 886 nbtohs(); 887 op_id = netval; 888 p += sizeof (unsigned short); 889 msglength -= sizeof (unsigned short); 890 nbtohs(); 891 nextop = netval; 892 p += sizeof (unsigned short); 893 msglength -= sizeof (unsigned short); 894 895 real_oplen = nextop ? nextop : msglength; 896 897 /* known options */ 898 switch (op_id) { 899 case 1: 900 sprintf(get_line(0, 0), 901 "Option: Required Attribute Missing"); 902 DOFIELD("Template IDVer", FIELD_DEFAULT); 903 DOFIELD("Required Attrs", FIELD_DEFAULT); 904 break; 905 default: 906 sprintf(get_line(0, 0), "Option: Unknown"); 907 p += (real_oplen - 4); 908 msglength -= (real_oplen - 4); 909 break; 910 } 911 912 if (op_id < 0x3fff) 913 op_class = "Standardized, optional"; 914 else if (op_id < 0x7fff) 915 op_class = "Standardized, mandatory"; 916 else if (op_id < 0x8fff) 917 op_class = "Not standardized, private"; 918 else if (op_id < 0xffff) 919 op_class = "Reserved"; 920 sprintf(get_line(0, 0), "Option ID = 0x%04x, %s", 921 op_id, op_class); 922 if (nextop && 923 ((nextop - 4) > msglength) && 924 !tcp_continuation) { 925 sprintf(get_line(0, 0), 926 "[Framing error: remaining pkt length = %u]", 927 msglength); 928 return (0); 929 } 930 931 sprintf(get_line(0, 0), "Option Length = %u", real_oplen); 932 933 if (!nextop) 934 break; 935 } 936 } 937 938 return (1); 939 } 940 941 #ifdef VERIFYSLP 942 static int skip_v2authblock() { 943 unsigned short length, slen; 944 945 /* auth header */ 946 if (msglength < 10) 947 return (-1); 948 949 /* block descriptor: 2 bytes */ 950 p += sizeof (unsigned short); 951 /* length */ 952 nbtohs(); 953 length = netval; 954 p += sizeof (unsigned short); 955 /* timestamp */ 956 p += 4; 957 /* SPI String length */ 958 nbtohs(); 959 slen = netval; 960 p += sizeof (unsigned short); 961 962 msglength -= 10; 963 if (slen > msglength || length > (msglength + 10)) 964 return (-1); 965 966 p += slen; 967 msglength -= slen; 968 969 /* structured auth block */ 970 p += (length - 10 - slen); 971 msglength -= (length - 10 - slen); 972 return (0); 973 } 974 #endif 975 976 static char *display_bsd(unsigned short bsd) { 977 switch (bsd) { 978 case 1: return ("MD5 with RSA"); 979 case 2: return ("DSA with SHA-1"); 980 case 3: return ("Keyed HMAC with MD5"); 981 default: return ("Unknown BSD"); 982 } 983 } 984 985 static char *slpv2_func(int t, boolean_t s) { 986 static char buf[128]; 987 988 switch (t) { 989 case V2_SRVRQST: return s? "SrvRqst" : "Service Request"; 990 case V2_SRVRPLY: return s? "SrvRply" : "Service Reply"; 991 case V2_SRVREG: return s? "SrvReg" : "Service Registration"; 992 case V2_SRVDEREG: 993 return (s ? "SrvDereg" : "Service Deregistration"); 994 case V2_SRVACK: return s? "SrvAck" : "Service Acknowledge"; 995 case V2_ATTRRQST: return s? "AttrRqst" : "Attribute Request"; 996 case V2_ATTRRPLY: return s? "AttrRply" : "Attribute Reply"; 997 case V2_DAADVERT: return s? "DAAdvert" : "DA advertisement"; 998 case V2_SRVTYPERQST: 999 return (s ? "SrvTypeRqst" : "Service Type Request"); 1000 case V2_SRVTYPERPLY: 1001 return (s ? "SrvTypeRply" : "Service Type Reply"); 1002 case V2_SAADVERT: return s? "SAAdvert" : "SA advertisement"; 1003 } 1004 sprintf(buf, "(func %d)", t); 1005 return (s ? buf : "unknown function"); 1006 } 1007 1008 static char *slpv2_error(unsigned short code) { 1009 static char buf[128]; 1010 1011 switch (code) { 1012 case OK: return "ok"; 1013 case LANG_NOT_SUPPORTED: return "language not supported"; 1014 case PROTOCOL_PARSE_ERR: return "protocol parse error"; 1015 case INVALID_REGISTRATION: return "invalid registration"; 1016 case SCOPE_NOT_SUPPORTED: return "scope not supported"; 1017 case AUTHENTICATION_UNKNOWN: return "authentication unknown"; 1018 case V2_AUTHENTICATION_ABSENT: return "authentication absent"; 1019 case V2_AUTHENTICATION_FAILED: return "authentication failed"; 1020 case V2_VER_NOT_SUPPORTED: return "version not supported"; 1021 case V2_INTERNAL_ERROR: return "internal error"; 1022 case V2_DA_BUSY_NOW: return "DA busy"; 1023 case V2_OPTION_NOT_UNDERSTOOD: return "option not understood"; 1024 case V2_INVALID_UPDATE: return "invalid update"; 1025 case V2_RQST_NOT_SUPPORTED: return "request not supported"; 1026 case INVALID_LIFETIME: return "invalid lifetime"; 1027 } 1028 sprintf(buf, "error %d", code); 1029 return (buf); 1030 } 1031 1032 static char *convert_ts(unsigned int timestamp) { 1033 /* timestamp is in UNIX time */ 1034 static char buff[128]; 1035 1036 strcpy(buff, ctime((time_t *)×tamp)); 1037 buff[strlen(buff) - 1] = '\0'; 1038 return (buff); 1039 } 1040 1041 static int slpv2_authblock(int cnt) { 1042 unsigned short bsd, length, slen; 1043 char *pp, *scopes; 1044 unsigned int timestamp; 1045 1046 if (msglength < 10) { 1047 sprintf(get_line(0, 0), 1048 " [no room for auth block header: remaining msg length = %u]", 1049 msglength); 1050 return (-1); 1051 } 1052 1053 /* bsd */ 1054 nbtohs(); 1055 bsd = netval; 1056 p += sizeof (unsigned short); 1057 1058 /* length */ 1059 nbtohs(); 1060 length = netval; 1061 p += sizeof (unsigned short); 1062 1063 /* timestamp */ 1064 nbtohl(); 1065 timestamp = netval; 1066 p += 4; 1067 1068 /* SPI String length */ 1069 nbtohs(); 1070 slen = netval; 1071 p += sizeof (unsigned short); 1072 1073 msglength -= 10; 1074 if (slen > msglength) { 1075 sprintf(get_line(0, 0), 1076 " [no room for auth block scopes: remaining msg length = %u]", 1077 msglength); 1078 return (-1); 1079 } 1080 1081 if (length > (msglength + 10)) { 1082 if (!tcp_continuation) 1083 /* framing error: message is not long enough to contain data */ 1084 sprintf(get_line(0, 0), 1085 " [Framing error: remaining pkt length = %u]", 1086 msglength); 1087 return (-1); 1088 } 1089 1090 scopes = p; 1091 p += slen; 1092 msglength -= slen; 1093 1094 sprintf(get_line(0, 0), 1095 "Auth block %d: timestamp = %s", cnt, 1096 (timestamp) ? convert_ts(timestamp) : "0"); 1097 1098 pp = get_line(0, 0); 1099 strcpy(pp, " SPI = "); 1100 strncat(pp, scopes, slen); 1101 1102 sprintf(get_line(0, 0), 1103 " block desc = 0x%04x: %s", bsd, display_bsd(bsd)); 1104 1105 sprintf(get_line(0, 0), " length = %u", length); 1106 1107 p += (length - 10 - slen); 1108 msglength -= (length - 10 - slen); 1109 return (0); 1110 } 1111 1112 static int v2_srv_rqst(int flags) { 1113 if (flags & F_SUM) { 1114 SKIPFIELD(FIELD_DEFAULT); /* PR list */ 1115 GETFIELD; /* service type */ 1116 SKIPFIELD(FIELD_DEFAULT); /* scopes */ 1117 strcat(msgend, " ["); 1118 GETFIELD; /* predicate */ 1119 strcat(msgend, "]"); 1120 SKIPFIELD(FIELD_DEFAULT); /* SPI */ 1121 } else if (flags & F_DTAIL) { 1122 DOFIELD("Previous responders", FIELD_DEFAULT); 1123 DOFIELD("Service type", FIELD_DEFAULT); 1124 DOFIELD("Scopes", FIELD_DEFAULT); 1125 DOFIELD("Predicate string", FIELD_DEFAULT); 1126 DOFIELD("Requested SPI", FIELD_DEFAULT); 1127 } 1128 1129 return (1); 1130 } 1131 1132 static int v2_srv_rply(int flags) { 1133 unsigned short itemcnt, errcode; 1134 int n; 1135 1136 if (flags & F_SUM) { 1137 int i, auth_cnt; 1138 1139 GETSHORT(errcode); 1140 if (errcode != OK) { 1141 strcat(msgbuf, slpv2_error(errcode)); 1142 msglength = 0; /* skip rest of message */ 1143 return (0); 1144 } else { 1145 GETSHORT(itemcnt); 1146 sprintf(msgend, "%d URL entries", itemcnt); 1147 #ifdef VERIFYSLP 1148 for (n = 0; n < itemcnt; n++) { 1149 SKIPBYTE; /* reserved */ 1150 SKIPSHORT; /* lifetime */ 1151 SKIPFIELD(FIELD_DEFAULT); /* URL */ 1152 GETBYTE(auth_cnt); 1153 for (i = 0; i < auth_cnt; auth_cnt++) 1154 if (skip_v2authblock() < 0) 1155 return (0); 1156 } 1157 #endif 1158 } 1159 } else if (flags & F_DTAIL) { 1160 V2_DOERRCODE; 1161 GETSHORT(itemcnt); 1162 sprintf(get_line(0, 0), "URL entry count = %d", itemcnt); 1163 for (n = 0; n < itemcnt; n++) { 1164 V2_DOURL(n); 1165 } 1166 } 1167 1168 return (1); 1169 } 1170 1171 static int v2_srv_reg(int flags) { 1172 int i, auth_cnt; 1173 1174 if (flags & F_SUM) { 1175 SKIPBYTE; /* reserved */ 1176 SKIPSHORT; /* lifetime */ 1177 GETFIELD; /* URL */ 1178 #ifdef VERIFYSLP 1179 GETBYTE(auth_cnt); 1180 for (i = 0; i < auth_cnt; i++) 1181 if (skip_v2authblock() < 0) 1182 return (0); 1183 SKIPFIELD(FIELD_DEFAULT); /* type */ 1184 SKIPFIELD(FIELD_DEFAULT); /* scopes */ 1185 SKIPFIELD(FIELD_DEFAULT); /* attrs */ 1186 GETBYTE(auth_cnt); 1187 for (i = 0; i < auth_cnt; i++) 1188 if (skip_v2authblock() < 0) 1189 return (0); 1190 #endif 1191 } if (flags & F_DTAIL) { 1192 V2_DOURL(-1); 1193 DOFIELD("Service type", FIELD_DEFAULT); 1194 DOFIELD("Scopes", FIELD_DEFAULT); 1195 DOFIELD("Attribute list", FIELD_DEFAULT); 1196 /* auth */ 1197 GETBYTE(auth_cnt); 1198 for (i = 0; i < auth_cnt; i++) 1199 V2_DOAUTH(i); 1200 } 1201 1202 return (1); 1203 } 1204 1205 static int v2_srv_dereg(int flags) { 1206 if (flags & F_SUM) { 1207 int i, auth_cnt; 1208 1209 SKIPFIELD(FIELD_DEFAULT); /* scopes */ 1210 SKIPBYTE; /* reserved */ 1211 SKIPSHORT; /* lifetime */ 1212 GETFIELD; /* URL */ 1213 1214 #ifdef VERIFYSLP 1215 GETBYTE(auth_cnt); 1216 for (i = 0; i < auth_cnt; i++) 1217 if (skip_v2authblock() < 0) 1218 return (0); 1219 SKIPFIELD(FIELD_DEFAULT); /* attrs */ 1220 #endif 1221 } else if (flags & F_DTAIL) { 1222 DOFIELD("Scopes", FIELD_DEFAULT); 1223 V2_DOURL(-1); 1224 DOFIELD("Tag list", FIELD_DEFAULT); 1225 } 1226 1227 return (1); 1228 } 1229 1230 static int v2_srv_ack(int flags) { 1231 unsigned short errcode; 1232 if (flags & F_SUM) { 1233 GETSHORT(errcode); 1234 strcat(msgbuf, slpv2_error(errcode)); 1235 } else if (flags & F_DTAIL) { 1236 V2_DOERRCODE; 1237 } 1238 1239 return (1); 1240 } 1241 1242 static int v2_attr_rqst(int flags) { 1243 if (flags & F_SUM) { 1244 SKIPFIELD(FIELD_DEFAULT); /* PR list */ 1245 GETFIELD; /* URL */ 1246 SKIPFIELD(FIELD_DEFAULT); /* scopes */ 1247 strcat(msgend, " ["); 1248 GETFIELD; /* attrs */ 1249 strcat(msgend, "]"); 1250 1251 #ifdef VERIFYSLP 1252 SKIPFIELD(FIELD_DEFAULT); /* SPI */ 1253 #endif 1254 } else if (flags & F_DTAIL) { 1255 DOFIELD("Previous responders", FIELD_DEFAULT); 1256 DOFIELD("URL", FIELD_DEFAULT); 1257 DOFIELD("Scopes", FIELD_DEFAULT); 1258 DOFIELD("Tag list", FIELD_DEFAULT); 1259 DOFIELD("Requested SPI", FIELD_DEFAULT); 1260 } 1261 1262 return (1); 1263 } 1264 1265 static int v2_attr_rply(int flags) { 1266 int auth_cnt, i; 1267 unsigned short errcode; 1268 1269 if (flags & F_SUM) { 1270 GETSHORT(errcode); 1271 if (errcode != OK) { 1272 strcat(msgbuf, slpv2_error(errcode)); 1273 msglength = 0; /* skip rest of message */ 1274 return (0); 1275 } else { 1276 GETFIELD; /* attr list */ 1277 1278 #ifdef VERIFYSLP 1279 GETBYTE(auth_cnt); 1280 for (i = 0; i < auth_cnt; i++) 1281 if (skip_v2authblock() < 0) 1282 return (0); 1283 #endif 1284 } 1285 } else if (flags & F_DTAIL) { 1286 V2_DOERRCODE; 1287 DOFIELD("Attribute list", FIELD_DEFAULT); 1288 /* auth */ 1289 GETBYTE(auth_cnt); 1290 for (i = 0; i < auth_cnt; i++) 1291 V2_DOAUTH(i); 1292 } 1293 1294 return (1); 1295 } 1296 1297 static int v2_daadvert(int flags) { 1298 int auth_cnt, i; 1299 unsigned short errcode; 1300 unsigned int timestamp; 1301 1302 if (flags & F_SUM) { 1303 SKIPSHORT; /* error code */ 1304 SKIPSHORT; SKIPSHORT; /* timestamp */ 1305 GETFIELD; /* URL */ 1306 1307 #ifdef VERIFYSLP 1308 SKIPFIELD(FIELD_DEFAULT); /* scopes */ 1309 SKIPFIELD(FIELD_DEFAULT); /* attrs */ 1310 SKIPFIELD(FIELD_DEFAULT); /* SPIs */ 1311 1312 GETBYTE(auth_cnt); 1313 for (i = 0; i < auth_cnt; i++) 1314 if (skip_v2authblock() < 0) 1315 return (0); 1316 #endif 1317 } else if (flags & F_DTAIL) { 1318 V2_DOERRCODE; 1319 V2_DOTIMESTAMP; 1320 DOFIELD("URL", FIELD_DEFAULT); 1321 DOFIELD("Scope list", FIELD_DEFAULT); 1322 DOFIELD("Attribute list", FIELD_DEFAULT); 1323 DOFIELD("Configured SPIs", FIELD_DEFAULT); 1324 /* auth */ 1325 GETBYTE(auth_cnt); 1326 for (i = 0; i < auth_cnt; i++) 1327 V2_DOAUTH(i); 1328 } 1329 1330 return (1); 1331 } 1332 1333 static int v2_srv_type_rqst(int flags) { 1334 if (flags & F_SUM) { 1335 SKIPFIELD(FIELD_DEFAULT); /* prev responders */ 1336 SKIPFIELD(FIELD_TYPENA); /* naming authority */ 1337 GETFIELD; /* scope */ 1338 } else if (flags & F_DTAIL) { 1339 DOFIELD("Previous responders", FIELD_DEFAULT); 1340 DOFIELD("Naming authority", FIELD_TYPENA); 1341 DOFIELD("Scopes", FIELD_DEFAULT); 1342 } 1343 1344 return (1); 1345 } 1346 1347 static int v2_srv_type_rply(int flags) { 1348 unsigned short errcode; 1349 1350 if (flags & F_SUM) { 1351 GETSHORT(errcode); 1352 if (errcode != OK) 1353 strcat(msgbuf, slpv2_error(errcode)); 1354 else 1355 GETFIELD; 1356 } else if (flags & F_DTAIL) { 1357 V2_DOERRCODE; 1358 DOFIELD("Service types", FIELD_DEFAULT); 1359 } 1360 1361 return (1); 1362 } 1363 1364 static int v2_saadvert(int flags) { 1365 int auth_cnt, i; 1366 1367 if (flags & F_SUM) { 1368 GETFIELD; /* URL */ 1369 1370 #ifdef VERIFYSLP 1371 SKIPFIELD(FIELD_DEFAULT); /* scopes */ 1372 SKIPFIELD(FIELD_DEFAULT); /* attrs */ 1373 1374 GETBYTE(auth_cnt); 1375 for (i = 0; i < auth_cnt; i++) 1376 if (skip_v2authblock() < 0) 1377 return (0); 1378 #endif 1379 } else if (flags & F_DTAIL) { 1380 DOFIELD("URL", FIELD_DEFAULT); 1381 DOFIELD("Scopes", FIELD_DEFAULT); 1382 DOFIELD("Attribute list", FIELD_DEFAULT); 1383 /* auth */ 1384 GETBYTE(auth_cnt); 1385 for (i = 0; i < auth_cnt; i++) 1386 V2_DOAUTH(i); 1387 } 1388 1389 return (1); 1390 } 1391 1392 /* 1393 * V1 Interpreter 1394 */ 1395 1396 static int interpret_slp_v1(int flags, struct slpv1_hdr *slp, int fraglen) { 1397 char msgbuf_real[256]; 1398 extern int src_port, dst_port, curr_proto; 1399 boolean_t overflow = B_FALSE; 1400 1401 msgbuf = msgbuf_real; 1402 1403 if (msglength >= sizeof (*slp)) { 1404 if ((slp->flags & V1_URL_AUTH) == V1_URL_AUTH) 1405 url_auth = B_TRUE; 1406 if ((slp->flags & V1_ATTR_AUTH) == V1_ATTR_AUTH) 1407 attr_auth = B_TRUE; 1408 if ((slp->flags & V1_FRESH_REG) == V1_FRESH_REG) 1409 fresh = B_TRUE; 1410 if ((slp->flags & V1_OVERFLOW) == V1_OVERFLOW) 1411 overflow = B_TRUE; 1412 } 1413 1414 /* 1415 * Somewhat of a hack to decode traffic from a server that does 1416 * not send udp replies from its SLP src port. 1417 */ 1418 if (curr_proto == IPPROTO_UDP && 1419 dst_port == 427 && 1420 src_port != 427) 1421 add_transient(src_port, (int (*)())interpret_slp); 1422 1423 /* parse the header */ 1424 if (v1_header(flags, slp, fraglen)) { 1425 1426 if (slp->function <= V1_MAX_FUNCTION && slp->function > 0) { 1427 1428 /* Parse the message body */ 1429 (v1_functions[slp->function])(flags); 1430 1431 } 1432 1433 } 1434 1435 /* summary error check */ 1436 if (flags & F_SUM) { 1437 if (retlength < 0) { 1438 if (curr_proto == IPPROTO_TCP) 1439 sprintf(get_sum_line(), 1440 "%s [partial TCP message]", 1441 msgbuf); 1442 else if (overflow) 1443 sprintf(get_sum_line(), "%s [OVERFLOW]", msgbuf); 1444 else 1445 sprintf(get_sum_line(), "%s [CORRUPTED MESSAGE]", msgbuf); 1446 } 1447 #ifdef VERIFYSLP 1448 else if (msglength > 0) 1449 sprintf(get_sum_line(), "%s +%d", msgbuf, msglength); 1450 #endif 1451 else 1452 sprintf(get_sum_line(), "%s", msgbuf); 1453 } else if (flags & F_DTAIL) { 1454 /* detail error check */ 1455 if (msglength > 0) { 1456 sprintf(get_line(0, 0), 1457 "[%d extra bytes at end of SLP message]", msglength); 1458 } 1459 1460 show_trailer(); 1461 1462 } 1463 1464 v1_charset = 0; 1465 1466 return (0); 1467 } 1468 1469 static int v1_header(int flags, 1470 struct slpv1_hdr *slp, 1471 int fraglen) { 1472 extern int src_port, dst_port, curr_proto; 1473 char *prototag = (curr_proto == IPPROTO_TCP? "/tcp" : ""); 1474 1475 if (flags & F_SUM) { 1476 char portflag = ' '; 1477 1478 if (msglength < sizeof (*slp)) { 1479 sprintf(msgbuf, "SLP V1 [incomplete header]"); 1480 return (0); 1481 } 1482 1483 if (slp->vers != 1) { 1484 if (curr_proto == IPPROTO_TCP) 1485 sprintf(msgbuf, "SLP [TCP Continuation]"); 1486 else 1487 sprintf(msgbuf, "SLP [unknown version %d]", slp->vers); 1488 return (0); 1489 } 1490 1491 if (src_port != 427 && dst_port != 427) 1492 portflag = '-'; 1493 1494 sprintf(msgbuf, "SLP V1%c%s [%d%s] ", portflag, 1495 slpv1_func(slp->function, B_TRUE), 1496 ntohs(slp->xid), prototag); 1497 msgend = msgbuf + strlen(msgbuf); 1498 msglength -= sizeof (*slp); 1499 p += sizeof (*slp); 1500 } else if (flags & F_DTAIL) { 1501 show_header("SLP: ", "Service Location Protocol (v1)", fraglen); 1502 show_space(); 1503 1504 if (msglength < sizeof (*slp)) { 1505 sprintf(get_line(0, 0), "==> Incomplete SLP header"); 1506 return (0); 1507 } 1508 1509 sprintf(get_line(0, 0), "Version = %d", slp->vers); 1510 if (slp->vers != 1) { 1511 if (curr_proto == IPPROTO_TCP) 1512 sprintf(get_line(0, 0), "==> TCP continuation"); 1513 else 1514 sprintf(get_line(0, 0), "==> Unexpected version number"); 1515 return (0); 1516 } 1517 sprintf(get_line(0, 0), "Function = %d, %s", 1518 slp->function, slpv1_func(slp->function, B_FALSE)); 1519 sprintf(get_line(0, 0), "Message length = %u", ntohs(slp->length)); 1520 1521 /* flags */ 1522 sprintf(get_line(0, 0), "Flags = 0x%02x", slp->flags); 1523 sprintf(get_line(0, 0), " %s", 1524 getflag(slp->flags, V1_OVERFLOW, 1525 "overflow", "no overflow")); 1526 sprintf(get_line(0, 0), " %s", 1527 getflag(slp->flags, V1_MONOLINGUAL, 1528 "monolingual", "not monolingual")); 1529 sprintf(get_line(0, 0), " %s", 1530 getflag(slp->flags, V1_URL_AUTH, 1531 "url authentication", "no url authentication")); 1532 sprintf(get_line(0, 0), " %s", 1533 getflag(slp->flags, V1_ATTR_AUTH, 1534 "attribute authentication", "no attribute authentication")); 1535 sprintf(get_line(0, 0), " %s", 1536 getflag(slp->flags, V1_FRESH_REG, 1537 "fresh registration", "no fresh registration")); 1538 /* check reserved flags that must be zero */ 1539 if ((slp->flags & 7) != 0) { 1540 sprintf(get_line(0, 0), 1541 " .... .xxx = %d (reserved flags nonzero)", 1542 slp->flags & 7); 1543 } 1544 /* end of flags */ 1545 1546 sprintf(get_line(0, 0), "Dialect = %u", slp->dialect); 1547 sprintf(get_line(0, 0), "Language = 0x%02x%02x, %c%c", 1548 slp->language[0], slp->language[1], 1549 slp->language[0], slp->language[1]); 1550 v1_charset = ntohs(slp->charset); 1551 sprintf(get_line(0, 0), "Character encoding = %u, %s", 1552 v1_charset, 1553 slpv1_charset(v1_charset)); 1554 sprintf(get_line(0, 0), "XID = %u", ntohs(slp->xid)); 1555 1556 /* set msglength to remaining length of SLP message */ 1557 msglength -= sizeof (*slp); 1558 p += sizeof (*slp); 1559 } 1560 1561 return (1); 1562 } 1563 1564 static char *slpv1_func(int t, boolean_t s) { 1565 static char buf[128]; 1566 switch (t) { 1567 case V1_SRVREQ: return s? "SrvRqst" : "Service Request"; 1568 case V1_SRVRPLY: return s? "SrvRply" : "Service Reply"; 1569 case V1_SRVREG: return s? "SrvReg" : "Service Registration"; 1570 case V1_SRVDEREG: return s? 1571 "SrvDereg" : "Service Deregistration"; 1572 case V1_SRVACK: return s? "SrvAck" : "Service Acknowledge"; 1573 case V1_ATTRRQST: return s? "AttrRqst" : "Attribute Request"; 1574 case V1_ATTRRPLY: return s? "AttrRply" : "Attribute Reply"; 1575 case V1_DAADVERT: return s? "DAAdvert" : "DA advertisement"; 1576 case V1_SRVTYPERQST:return s? "SrvTypeRqst" : "Service Type Request"; 1577 case V1_SRVTYPERPLY:return s? "SrvTypeRply" : "Service Type Reply"; 1578 } 1579 sprintf(buf, "(func %d)", t); 1580 return (s ? buf : "unknown function"); 1581 } 1582 1583 static char *slpv1_error(unsigned short code) { 1584 static char buf[128]; 1585 1586 switch (code) { 1587 case OK: return "ok"; 1588 case LANG_NOT_SUPPORTED: return "language not supported"; 1589 case PROTOCOL_PARSE_ERR: return "protocol parse error"; 1590 case INVALID_REGISTRATION: return "invalid registration"; 1591 case SCOPE_NOT_SUPPORTED: return "scope not supported"; 1592 case CHARSET_NOT_UNDERSTOOD:return "character set not understood"; 1593 case AUTHENTICATION_INVALID:return "invalid authentication"; 1594 case NOT_SUPPORTED_YET: return "not yet supported"; 1595 case REQUEST_TIMED_OUT: return "request timed out"; 1596 case COULD_NOT_INIT_NET_RESOURCES: 1597 return ("could not initialize net resources"); 1598 case COULD_NOT_ALLOCATE_MEMORY: 1599 return ("could not allocate memory"); 1600 case PARAMETER_BAD: return "bad parameter"; 1601 case INTERNAL_NET_ERROR: return "internal network error"; 1602 case INTERNAL_SYSTEM_ERROR: return "internal system error"; 1603 } 1604 sprintf(buf, "error %d", code); 1605 return (buf); 1606 } 1607 1608 /* 1609 * Character set info from 1610 * www.isi.edu/in-notes/iana/assignments/character-sets 1611 * 1612 * Assigned MIB enum Numbers 1613 * ------------------------- 1614 * 0 Reserved 1615 * 1 Reserved 1616 * 3-106 Set By Standards Organizations 1617 * 1000-1010 Unicode / 10646 1618 * 2000-2087 Vendor 1619 * 2250-2258 Vendor 1620 * 1621 * MIBenum: 3 1622 * Alias: US-ASCII (preferred MIME name) 1623 * Source: ECMA registry [RFC1345] 1624 * 1625 * MIBenum: 106 1626 * Name: UTF-8 1627 * Source: RFC 2044 1628 */ 1629 1630 static char *slpv1_charset(unsigned short code) { 1631 if (code <= 1) 1632 return ("Reserved"); 1633 if (code == 3) 1634 return ("US-ASCII"); 1635 if (code == 4) 1636 return ("latin1"); 1637 if (code == 106) 1638 return ("UTF-8"); 1639 if (code >= 3 && code <= 106) 1640 return ("set by standards organization"); 1641 if (code >= 1000 && code <= 1010) 1642 return ("Unicode variant"); 1643 if ((code >= 2000 && code <= 2087) || 1644 (code >= 2250 && code <= 2258)) 1645 return ("Vendor assigned"); 1646 1647 return ("unknown"); 1648 } 1649 1650 #ifdef VERIFYSLP 1651 static int skip_v1authblock() { 1652 unsigned short length; 1653 1654 /* auth header: 12 bytes total */ 1655 if (msglength < 12) 1656 return (-1); 1657 1658 /* timestamp: 8 bytes */ 1659 p += 8; /* timestamp: 8 bytes */ 1660 p += sizeof (short); /* block descriptor: 2 bytes */ 1661 nbtohs(); 1662 length = netval; 1663 p += sizeof (short); 1664 msglength -= 12; 1665 1666 if (length > msglength) { 1667 /* framing error: message is not long enough to contain data */ 1668 return (-1); 1669 } 1670 1671 p += length; 1672 msglength -= length; 1673 return (0); 1674 } 1675 #endif 1676 1677 static int slpv1_authblock() { 1678 unsigned short bsd, length; 1679 char msgbuf[128]; 1680 int n; 1681 1682 if (msglength < 12) { 1683 sprintf(get_line(0, 0), 1684 " [no room for auth block: remaining msg length = %u]", 1685 msglength); 1686 return (-1); 1687 } 1688 1689 /* timestamp: 8 bytes */ 1690 *msgbuf = '\0'; 1691 for (n = 0; n < 8; n++, p += 1) { 1692 char tmp[16]; 1693 sprintf(tmp, "%02x", (unsigned char)(*p)); 1694 strcat(msgbuf, tmp); 1695 } 1696 1697 nbtohs(); 1698 bsd = netval; 1699 p += sizeof (short); 1700 nbtohs(); 1701 length = netval; 1702 p += sizeof (short); 1703 msglength -= 12; 1704 1705 sprintf(get_line(0, 0), 1706 " Auth block: timestamp = %s", 1707 msgbuf); 1708 sprintf(get_line(0, 0), 1709 " block desc = 0x%04x, length = %u", 1710 bsd, length); 1711 if (length > msglength) { 1712 /* framing error: message is not long enough to contain data */ 1713 sprintf(get_line(0, 0), 1714 " [Framing error: remaining pkt length = %u]", msglength); 1715 return (-1); 1716 } 1717 1718 p += length; 1719 msglength -= length; 1720 return (0); 1721 } 1722 1723 static int slpv1_url(boolean_t auth_present) { 1724 time_t exp; 1725 int lifetime, length; 1726 1727 get_short(); 1728 if ((lifetime = netval) < 0) 1729 return (-1); 1730 get_short(); 1731 if ((length = netval) < 0) 1732 return (-1); 1733 1734 exp = time(0) + lifetime; 1735 sprintf(get_line(0, 0), "URL: length = %u, lifetime = %d (%24.24s)", 1736 length, lifetime, ctime(&exp)); 1737 if (length > msglength) { 1738 /* framing error: message is not long enough to contain data */ 1739 sprintf(get_line(0, 0), 1740 " [Framing error: remaining pkt length = %u]", msglength); 1741 return (-1); 1742 } 1743 1744 if (length > 0) { 1745 char *buf = malloc(length + 1); 1746 if (buf != NULL) { 1747 if (!make_utf8(buf, length, p, length)) { 1748 strcpy(buf, "[Invalid Character Encoding]"); 1749 } 1750 sprintf(get_line(0, 0), " \"%s\"", buf); 1751 free(buf); 1752 } 1753 } 1754 msglength -= length; 1755 p += length; 1756 1757 if (auth_present) 1758 return (slpv1_authblock()); 1759 1760 return (0); 1761 } 1762 1763 static int v1_srv_rqst(int flags) { 1764 if (flags & F_SUM) { 1765 SKIPFIELD(FIELD_PREVRESP); /* prev responders */ 1766 GETFIELD; /* predicate */ 1767 } else if (flags & F_DTAIL) { 1768 DOFIELD("Previous responders", FIELD_PREVRESP); 1769 DOFIELD("predicate string", FIELD_DEFAULT); 1770 } 1771 1772 return (1); 1773 } 1774 1775 static int v1_srv_rply(int flags) { 1776 unsigned short errcode, itemcnt; 1777 int n; 1778 1779 if (flags & F_SUM) { 1780 GETSHORT(errcode); 1781 if (errcode != OK) { 1782 strcat(msgbuf, slpv1_error(errcode)); 1783 } else { 1784 GETSHORT(itemcnt); 1785 sprintf(msgend, "%d URL entries", itemcnt); 1786 #ifdef VERIFYSLP 1787 for (n = 0; n < itemcnt; n++) { 1788 SKIPSHORT; /* lifetime */ 1789 SKIPFIELD(FIELD_DEFAULT); /* URL */ 1790 SKIPAUTH(url_auth); /* URL auth */ 1791 } 1792 #endif 1793 } 1794 } else if (flags & F_DTAIL) { 1795 DOERRCODE; 1796 GETSHORT(itemcnt); 1797 sprintf(get_line(0, 0), "URL entry count = %d", itemcnt); 1798 for (n = 0; n < itemcnt; n++) { 1799 DOURL; 1800 } 1801 } 1802 1803 return (1); 1804 } 1805 1806 static int v1_srv_reg(int flags) { 1807 if (flags & F_SUM) { 1808 SKIPSHORT; /* lifetime */ 1809 GETFIELD; /* URL */ 1810 #ifdef VERIFYSLP 1811 SKIPAUTH(url_auth); /* URL auth */ 1812 SKIPFIELD(FIELD_DEFAULT); /* attribute list */ 1813 SKIPAUTH(attr_auth); /* attr auth */ 1814 #endif 1815 } else if (flags & F_DTAIL) { 1816 DOURL; 1817 DOFIELD("Attribute list", FIELD_DEFAULT); 1818 DOAUTH(attr_auth); 1819 } 1820 1821 return (1); 1822 } 1823 1824 static int v1_srv_ack(int flags) { 1825 unsigned short errcode; 1826 1827 if (flags & F_SUM) { 1828 GETSHORT(errcode); 1829 strcat(msgbuf, slpv1_error(errcode)); 1830 if (errcode == OK && fresh) { 1831 strcat(msgbuf, " [Fresh]"); 1832 } 1833 } else if (flags & F_DTAIL) { 1834 DOERRCODE; 1835 } 1836 1837 return (1); 1838 } 1839 1840 static int v1_srv_dereg(int flags) { 1841 if (flags & F_SUM) { 1842 GETFIELD; /* URL */ 1843 #ifdef VERIFYSLP 1844 SKIPAUTH(url_auth); 1845 SKIPFIELD(FIELD_DEFAULT); /* tag spec */ 1846 #endif 1847 } else if (flags & F_DTAIL) { 1848 DOFIELD("URL", FIELD_DEFAULT); 1849 DOAUTH(url_auth); 1850 DOFIELD("Tag spec", FIELD_DEFAULT); 1851 } 1852 1853 return (1); 1854 } 1855 1856 static int v1_attr_rqst(int flags) { 1857 if (flags & F_SUM) { 1858 SKIPFIELD(FIELD_PREVRESP); /* prev responders */ 1859 GETFIELD; /* URL */ 1860 #ifdef VERIFYSLP 1861 SKIPFIELD(FIELD_DEFAULT); /* scope */ 1862 SKIPFIELD(FIELD_DEFAULT); /* select list */ 1863 #endif 1864 } else if (flags & F_DTAIL) { 1865 DOFIELD("Previous responders", FIELD_PREVRESP); 1866 DOFIELD("URL", FIELD_DEFAULT); 1867 DOFIELD("Scope", FIELD_DEFAULT); 1868 DOFIELD("Select list", FIELD_DEFAULT); 1869 } 1870 1871 return (1); 1872 } 1873 1874 static int v1_attr_rply(int flags) { 1875 unsigned short errcode; 1876 1877 if (flags & F_SUM) { 1878 GETSHORT(errcode); 1879 if (errcode != OK) { 1880 strcat(msgbuf, slpv1_error(errcode)); 1881 } else { 1882 GETFIELD; /* attr list */ 1883 #ifdef VERIFYSLP 1884 SKIPAUTH(attr_auth); 1885 #endif 1886 } 1887 } else if (flags & F_DTAIL) { 1888 DOERRCODE; 1889 DOFIELD("Attribute list", FIELD_DEFAULT); 1890 DOAUTH(attr_auth); 1891 } 1892 1893 return (1); 1894 } 1895 1896 static int v1_daadvert(int flags) { 1897 unsigned short errcode; 1898 1899 if (flags & F_SUM) { 1900 GETSHORT(errcode); 1901 if (errcode != OK) { 1902 strcat(msgbuf, slpv1_error(errcode)); 1903 } else { 1904 GETFIELD; /* URL */ 1905 #ifdef VERIFYSLP 1906 SKIPFIELD(FIELD_DEFAULT); /* scope list */ 1907 #endif 1908 } 1909 } else if (flags & F_DTAIL) { 1910 DOERRCODE; 1911 DOFIELD("URL", FIELD_DEFAULT); 1912 DOFIELD("Scope list", FIELD_DEFAULT); 1913 } 1914 1915 return (1); 1916 } 1917 1918 static int v1_srv_type_rqst(int flags) { 1919 if (flags & F_SUM) { 1920 SKIPFIELD(FIELD_PREVRESP); /* prev responders */ 1921 SKIPFIELD(FIELD_TYPENA); /* naming authority */ 1922 GETFIELD; /* scope */ 1923 } else if (flags & F_DTAIL) { 1924 DOFIELD("Previous responders", FIELD_PREVRESP); 1925 DOFIELD("Naming authority", FIELD_TYPENA); 1926 DOFIELD("Scope string", FIELD_DEFAULT); 1927 } 1928 1929 return (1); 1930 } 1931 1932 static int v1_srv_type_rply(int flags) { 1933 unsigned short errcode, itemcnt; 1934 int n; 1935 1936 if (flags & F_SUM) { 1937 GETSHORT(errcode); 1938 if (errcode != OK) { 1939 strcat(msgbuf, slpv1_error(errcode)); 1940 } else { 1941 GETSHORT(itemcnt); 1942 sprintf(msgend, "%d type entries", itemcnt); 1943 #ifdef VERIFYSLP 1944 for (n = 0; n < itemcnt; n++) { 1945 SKIPFIELD(FIELD_DEFAULT); /* Service type item */ 1946 } 1947 #endif 1948 } 1949 } else if (flags & F_DTAIL) { 1950 DOERRCODE; 1951 GETSHORT(itemcnt); 1952 sprintf(get_line(0, 0), "Service type count = %d", itemcnt); 1953 for (n = 0; n < itemcnt; n++) { 1954 DOFIELD(" Service type item", FIELD_DEFAULT); 1955 } 1956 } 1957 1958 return (1); 1959 } 1960