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