1 /* 2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 3 * unrestricted use provided that this legend is included on all tape 4 * media and as a part of the software program in whole or part. Users 5 * may copy or modify Sun RPC without charge, but are not authorized 6 * to license or distribute it to anyone else except as part of a product or 7 * program developed by the user. 8 * 9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 12 * 13 * Sun RPC is provided with no support and without any obligation on the 14 * part of Sun Microsystems, Inc. to assist in its use, correction, 15 * modification or enhancement. 16 * 17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 19 * OR ANY PART THEREOF. 20 * 21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 22 * or profits or other special, indirect and consequential damages, even if 23 * Sun has been advised of the possibility of such damages. 24 * 25 * Sun Microsystems, Inc. 26 * 2550 Garcia Avenue 27 * Mountain View, California 94043 28 * @(#)rpc_generic.c 1.17 94/04/24 SMI 29 * $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $ 30 * $FreeBSD: src/lib/libc/rpc/rpc_generic.c,v 1.14 2007/09/20 22:35:24 matteo Exp $ 31 * $DragonFly$ 32 */ 33 /* 34 * Copyright (c) 1986-1991 by Sun Microsystems Inc. 35 */ 36 37 /* 38 * rpc_generic.c, Misc routines for RPC. 39 * 40 */ 41 42 #include "namespace.h" 43 #include "reentrant.h" 44 #include <sys/types.h> 45 #include <sys/param.h> 46 #include <sys/socket.h> 47 #include <sys/time.h> 48 #include <sys/un.h> 49 #include <sys/resource.h> 50 #include <netinet/in.h> 51 #include <arpa/inet.h> 52 #include <rpc/rpc.h> 53 #include <ctype.h> 54 #include <stddef.h> 55 #include <stdio.h> 56 #include <netdb.h> 57 #include <netconfig.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <syslog.h> 61 #include <rpc/nettype.h> 62 #include "un-namespace.h" 63 #include "rpc_com.h" 64 #include "mt_misc.h" 65 66 struct handle { 67 NCONF_HANDLE *nhandle; 68 int nflag; /* Whether NETPATH or NETCONFIG */ 69 int nettype; 70 }; 71 72 static const struct _rpcnettype { 73 const char *name; 74 const int type; 75 } _rpctypelist[] = { 76 { "netpath", _RPC_NETPATH }, 77 { "visible", _RPC_VISIBLE }, 78 { "circuit_v", _RPC_CIRCUIT_V }, 79 { "datagram_v", _RPC_DATAGRAM_V }, 80 { "circuit_n", _RPC_CIRCUIT_N }, 81 { "datagram_n", _RPC_DATAGRAM_N }, 82 { "tcp", _RPC_TCP }, 83 { "udp", _RPC_UDP }, 84 { 0, _RPC_NONE } 85 }; 86 87 struct netid_af { 88 const char *netid; 89 int af; 90 int protocol; 91 }; 92 93 static const struct netid_af na_cvt[] = { 94 { "udp", AF_INET, IPPROTO_UDP }, 95 { "tcp", AF_INET, IPPROTO_TCP }, 96 #ifdef INET6 97 { "udp6", AF_INET6, IPPROTO_UDP }, 98 { "tcp6", AF_INET6, IPPROTO_TCP }, 99 #endif 100 { "local", AF_LOCAL, 0 } 101 }; 102 103 #if 0 104 static char *strlocase(char *); 105 #endif 106 static int getnettype(const char *); 107 108 /* 109 * Cache the result of getrlimit(), so we don't have to do an 110 * expensive call every time. 111 */ 112 int 113 __rpc_dtbsize(void) 114 { 115 static int tbsize; 116 struct rlimit rl; 117 118 if (tbsize) { 119 return (tbsize); 120 } 121 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { 122 return (tbsize = (int)rl.rlim_max); 123 } 124 /* 125 * Something wrong. I'll try to save face by returning a 126 * pessimistic number. 127 */ 128 return (32); 129 } 130 131 132 /* 133 * Find the appropriate buffer size 134 */ 135 u_int 136 /*ARGSUSED*/ 137 __rpc_get_t_size(int af, int proto, 138 int size) /* Size requested */ 139 { 140 int maxsize, defsize; 141 142 maxsize = 256 * 1024; /* XXX */ 143 switch (proto) { 144 case IPPROTO_TCP: 145 defsize = 64 * 1024; /* XXX */ 146 break; 147 case IPPROTO_UDP: 148 defsize = UDPMSGSIZE; 149 break; 150 default: 151 defsize = RPC_MAXDATASIZE; 152 break; 153 } 154 if (size == 0) 155 return defsize; 156 157 /* Check whether the value is within the upper max limit */ 158 return (size > maxsize ? (u_int)maxsize : (u_int)size); 159 } 160 161 /* 162 * Find the appropriate address buffer size 163 */ 164 u_int 165 __rpc_get_a_size(int af) 166 { 167 switch (af) { 168 case AF_INET: 169 return sizeof (struct sockaddr_in); 170 #ifdef INET6 171 case AF_INET6: 172 return sizeof (struct sockaddr_in6); 173 #endif 174 case AF_LOCAL: 175 return sizeof (struct sockaddr_un); 176 default: 177 break; 178 } 179 return ((u_int)RPC_MAXADDRSIZE); 180 } 181 182 #if 0 183 static char * 184 strlocase(char *p) 185 { 186 char *t = p; 187 188 for (; *p; p++) 189 if (isupper(*p)) 190 *p = tolower(*p); 191 return (t); 192 } 193 #endif 194 195 /* 196 * Returns the type of the network as defined in <rpc/nettype.h> 197 * If nettype is NULL, it defaults to NETPATH. 198 */ 199 static int 200 getnettype(const char *nettype) 201 { 202 int i; 203 204 if ((nettype == NULL) || (nettype[0] == 0)) { 205 return (_RPC_NETPATH); /* Default */ 206 } 207 208 #if 0 209 nettype = strlocase(nettype); 210 #endif 211 for (i = 0; _rpctypelist[i].name; i++) 212 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) { 213 return (_rpctypelist[i].type); 214 } 215 return (_rpctypelist[i].type); 216 } 217 218 /* 219 * For the given nettype (tcp or udp only), return the first structure found. 220 * This should be freed by calling freenetconfigent() 221 */ 222 struct netconfig * 223 __rpc_getconfip(const char *nettype) 224 { 225 char *netid; 226 char *netid_tcp = (char *) NULL; 227 char *netid_udp = (char *) NULL; 228 static char *netid_tcp_main; 229 static char *netid_udp_main; 230 struct netconfig *dummy; 231 int main_thread; 232 static thread_key_t tcp_key, udp_key; 233 234 if ((main_thread = thr_main())) { 235 netid_udp = netid_udp_main; 236 netid_tcp = netid_tcp_main; 237 } else { 238 if (tcp_key == 0) { 239 mutex_lock(&tsd_lock); 240 if (tcp_key == 0) 241 thr_keycreate(&tcp_key, free); 242 mutex_unlock(&tsd_lock); 243 } 244 netid_tcp = (char *)thr_getspecific(tcp_key); 245 if (udp_key == 0) { 246 mutex_lock(&tsd_lock); 247 if (udp_key == 0) 248 thr_keycreate(&udp_key, free); 249 mutex_unlock(&tsd_lock); 250 } 251 netid_udp = (char *)thr_getspecific(udp_key); 252 } 253 if (!netid_udp && !netid_tcp) { 254 struct netconfig *nconf; 255 void *confighandle; 256 257 if (!(confighandle = setnetconfig())) { 258 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); 259 return (NULL); 260 } 261 while ((nconf = getnetconfig(confighandle)) != NULL) { 262 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 263 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 264 netid_tcp = strdup(nconf->nc_netid); 265 if (main_thread) 266 netid_tcp_main = netid_tcp; 267 else 268 thr_setspecific(tcp_key, 269 (void *) netid_tcp); 270 } else 271 if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 272 netid_udp = strdup(nconf->nc_netid); 273 if (main_thread) 274 netid_udp_main = netid_udp; 275 else 276 thr_setspecific(udp_key, 277 (void *) netid_udp); 278 } 279 } 280 } 281 endnetconfig(confighandle); 282 } 283 if (strcmp(nettype, "udp") == 0) 284 netid = netid_udp; 285 else if (strcmp(nettype, "tcp") == 0) 286 netid = netid_tcp; 287 else { 288 return (NULL); 289 } 290 if ((netid == NULL) || (netid[0] == 0)) { 291 return (NULL); 292 } 293 dummy = getnetconfigent(netid); 294 return (dummy); 295 } 296 297 /* 298 * Returns the type of the nettype, which should then be used with 299 * __rpc_getconf(). 300 */ 301 void * 302 __rpc_setconf(const char *nettype) 303 { 304 struct handle *handle; 305 306 handle = (struct handle *) malloc(sizeof (struct handle)); 307 if (handle == NULL) { 308 return (NULL); 309 } 310 switch (handle->nettype = getnettype(nettype)) { 311 case _RPC_NETPATH: 312 case _RPC_CIRCUIT_N: 313 case _RPC_DATAGRAM_N: 314 if (!(handle->nhandle = setnetpath())) 315 goto failed; 316 handle->nflag = TRUE; 317 break; 318 case _RPC_VISIBLE: 319 case _RPC_CIRCUIT_V: 320 case _RPC_DATAGRAM_V: 321 case _RPC_TCP: 322 case _RPC_UDP: 323 if (!(handle->nhandle = setnetconfig())) { 324 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); 325 goto failed; 326 } 327 handle->nflag = FALSE; 328 break; 329 default: 330 goto failed; 331 } 332 333 return (handle); 334 335 failed: 336 free(handle); 337 return (NULL); 338 } 339 340 /* 341 * Returns the next netconfig struct for the given "net" type. 342 * __rpc_setconf() should have been called previously. 343 */ 344 struct netconfig * 345 __rpc_getconf(void *vhandle) 346 { 347 struct handle *handle; 348 struct netconfig *nconf; 349 350 handle = (struct handle *)vhandle; 351 if (handle == NULL) { 352 return (NULL); 353 } 354 for (;;) { 355 if (handle->nflag) 356 nconf = getnetpath(handle->nhandle); 357 else 358 nconf = getnetconfig(handle->nhandle); 359 if (nconf == NULL) 360 break; 361 if ((nconf->nc_semantics != NC_TPI_CLTS) && 362 (nconf->nc_semantics != NC_TPI_COTS) && 363 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 364 continue; 365 switch (handle->nettype) { 366 case _RPC_VISIBLE: 367 if (!(nconf->nc_flag & NC_VISIBLE)) 368 continue; 369 /* FALLTHROUGH */ 370 case _RPC_NETPATH: /* Be happy */ 371 break; 372 case _RPC_CIRCUIT_V: 373 if (!(nconf->nc_flag & NC_VISIBLE)) 374 continue; 375 /* FALLTHROUGH */ 376 case _RPC_CIRCUIT_N: 377 if ((nconf->nc_semantics != NC_TPI_COTS) && 378 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 379 continue; 380 break; 381 case _RPC_DATAGRAM_V: 382 if (!(nconf->nc_flag & NC_VISIBLE)) 383 continue; 384 /* FALLTHROUGH */ 385 case _RPC_DATAGRAM_N: 386 if (nconf->nc_semantics != NC_TPI_CLTS) 387 continue; 388 break; 389 case _RPC_TCP: 390 if (((nconf->nc_semantics != NC_TPI_COTS) && 391 (nconf->nc_semantics != NC_TPI_COTS_ORD)) || 392 (strcmp(nconf->nc_protofmly, NC_INET) 393 #ifdef INET6 394 && strcmp(nconf->nc_protofmly, NC_INET6)) 395 #else 396 ) 397 #endif 398 || 399 strcmp(nconf->nc_proto, NC_TCP)) 400 continue; 401 break; 402 case _RPC_UDP: 403 if ((nconf->nc_semantics != NC_TPI_CLTS) || 404 (strcmp(nconf->nc_protofmly, NC_INET) 405 #ifdef INET6 406 && strcmp(nconf->nc_protofmly, NC_INET6)) 407 #else 408 ) 409 #endif 410 || 411 strcmp(nconf->nc_proto, NC_UDP)) 412 continue; 413 break; 414 } 415 break; 416 } 417 return (nconf); 418 } 419 420 void 421 __rpc_endconf(void *vhandle) 422 { 423 struct handle *handle; 424 425 handle = (struct handle *) vhandle; 426 if (handle == NULL) { 427 return; 428 } 429 if (handle->nflag) { 430 endnetpath(handle->nhandle); 431 } else { 432 endnetconfig(handle->nhandle); 433 } 434 free(handle); 435 } 436 437 /* 438 * Used to ping the NULL procedure for clnt handle. 439 * Returns NULL if fails, else a non-NULL pointer. 440 */ 441 void * 442 rpc_nullproc(CLIENT *clnt) 443 { 444 struct timeval TIMEOUT = {25, 0}; 445 446 if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL, 447 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) { 448 return (NULL); 449 } 450 return ((void *) clnt); 451 } 452 453 /* 454 * Try all possible transports until 455 * one succeeds in finding the netconf for the given fd. 456 */ 457 struct netconfig * 458 __rpcgettp(int fd) 459 { 460 const char *netid; 461 struct __rpc_sockinfo si; 462 463 if (!__rpc_fd2sockinfo(fd, &si)) 464 return NULL; 465 466 if (!__rpc_sockinfo2netid(&si, &netid)) 467 return NULL; 468 469 /*LINTED const castaway*/ 470 return getnetconfigent((char *)netid); 471 } 472 473 int 474 __rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip) 475 { 476 socklen_t len; 477 int type, proto; 478 struct sockaddr_storage ss; 479 480 len = sizeof ss; 481 if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0) 482 return 0; 483 sip->si_alen = len; 484 485 len = sizeof type; 486 if (_getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0) 487 return 0; 488 489 /* XXX */ 490 if (ss.ss_family != AF_LOCAL) { 491 if (type == SOCK_STREAM) 492 proto = IPPROTO_TCP; 493 else if (type == SOCK_DGRAM) 494 proto = IPPROTO_UDP; 495 else 496 return 0; 497 } else 498 proto = 0; 499 500 sip->si_af = ss.ss_family; 501 sip->si_proto = proto; 502 sip->si_socktype = type; 503 504 return 1; 505 } 506 507 /* 508 * Linear search, but the number of entries is small. 509 */ 510 int 511 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip) 512 { 513 int i; 514 515 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) 516 if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || ( 517 strcmp(nconf->nc_netid, "unix") == 0 && 518 strcmp(na_cvt[i].netid, "local") == 0)) { 519 sip->si_af = na_cvt[i].af; 520 sip->si_proto = na_cvt[i].protocol; 521 sip->si_socktype = 522 __rpc_seman2socktype((int)nconf->nc_semantics); 523 if (sip->si_socktype == -1) 524 return 0; 525 sip->si_alen = __rpc_get_a_size(sip->si_af); 526 return 1; 527 } 528 529 return 0; 530 } 531 532 int 533 __rpc_nconf2fd(const struct netconfig *nconf) 534 { 535 struct __rpc_sockinfo si; 536 537 if (!__rpc_nconf2sockinfo(nconf, &si)) 538 return 0; 539 540 return _socket(si.si_af, si.si_socktype, si.si_proto); 541 } 542 543 int 544 __rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid) 545 { 546 int i; 547 struct netconfig *nconf; 548 549 nconf = getnetconfigent("local"); 550 551 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) { 552 if (na_cvt[i].af == sip->si_af && 553 na_cvt[i].protocol == sip->si_proto) { 554 if (strcmp(na_cvt[i].netid, "local") == 0 && nconf == NULL) { 555 if (netid) 556 *netid = "unix"; 557 } else { 558 if (netid) 559 *netid = na_cvt[i].netid; 560 } 561 if (nconf != NULL) 562 freenetconfigent(nconf); 563 return 1; 564 } 565 } 566 if (nconf != NULL) 567 freenetconfigent(nconf); 568 569 return 0; 570 } 571 572 char * 573 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf) 574 { 575 struct __rpc_sockinfo si; 576 577 if (!__rpc_nconf2sockinfo(nconf, &si)) 578 return NULL; 579 return __rpc_taddr2uaddr_af(si.si_af, nbuf); 580 } 581 582 struct netbuf * 583 uaddr2taddr(const struct netconfig *nconf, const char *uaddr) 584 { 585 struct __rpc_sockinfo si; 586 587 if (!__rpc_nconf2sockinfo(nconf, &si)) 588 return NULL; 589 return __rpc_uaddr2taddr_af(si.si_af, uaddr); 590 } 591 592 char * 593 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) 594 { 595 char *ret; 596 struct sockaddr_in *sin; 597 struct sockaddr_un *sun; 598 char namebuf[INET_ADDRSTRLEN]; 599 #ifdef INET6 600 struct sockaddr_in6 *sin6; 601 char namebuf6[INET6_ADDRSTRLEN]; 602 #endif 603 u_int16_t port; 604 605 switch (af) { 606 case AF_INET: 607 sin = nbuf->buf; 608 if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf) 609 == NULL) 610 return NULL; 611 port = ntohs(sin->sin_port); 612 if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8, 613 port & 0xff) < 0) 614 return NULL; 615 break; 616 #ifdef INET6 617 case AF_INET6: 618 sin6 = nbuf->buf; 619 if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6) 620 == NULL) 621 return NULL; 622 port = ntohs(sin6->sin6_port); 623 if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8, 624 port & 0xff) < 0) 625 return NULL; 626 break; 627 #endif 628 case AF_LOCAL: 629 sun = nbuf->buf; 630 if (asprintf(&ret, "%.*s", (int)(sun->sun_len - 631 offsetof(struct sockaddr_un, sun_path)), 632 sun->sun_path) < 0) 633 return (NULL); 634 break; 635 default: 636 return NULL; 637 } 638 639 return ret; 640 } 641 642 struct netbuf * 643 __rpc_uaddr2taddr_af(int af, const char *uaddr) 644 { 645 struct netbuf *ret = NULL; 646 char *addrstr, *p; 647 unsigned port, portlo, porthi; 648 struct sockaddr_in *sin; 649 #ifdef INET6 650 struct sockaddr_in6 *sin6; 651 #endif 652 struct sockaddr_un *sun; 653 654 port = 0; 655 sin = NULL; 656 addrstr = strdup(uaddr); 657 if (addrstr == NULL) 658 return NULL; 659 660 /* 661 * AF_LOCAL addresses are expected to be absolute 662 * pathnames, anything else will be AF_INET or AF_INET6. 663 */ 664 if (*addrstr != '/') { 665 p = strrchr(addrstr, '.'); 666 if (p == NULL) 667 goto out; 668 portlo = (unsigned)atoi(p + 1); 669 *p = '\0'; 670 671 p = strrchr(addrstr, '.'); 672 if (p == NULL) 673 goto out; 674 porthi = (unsigned)atoi(p + 1); 675 *p = '\0'; 676 port = (porthi << 8) | portlo; 677 } 678 679 ret = (struct netbuf *)malloc(sizeof *ret); 680 if (ret == NULL) 681 goto out; 682 683 switch (af) { 684 case AF_INET: 685 sin = (struct sockaddr_in *)malloc(sizeof *sin); 686 if (sin == NULL) 687 goto out; 688 memset(sin, 0, sizeof *sin); 689 sin->sin_family = AF_INET; 690 sin->sin_port = htons(port); 691 if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) { 692 free(sin); 693 free(ret); 694 ret = NULL; 695 goto out; 696 } 697 sin->sin_len = ret->maxlen = ret->len = sizeof *sin; 698 ret->buf = sin; 699 break; 700 #ifdef INET6 701 case AF_INET6: 702 sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6); 703 if (sin6 == NULL) 704 goto out; 705 memset(sin6, 0, sizeof *sin6); 706 sin6->sin6_family = AF_INET6; 707 sin6->sin6_port = htons(port); 708 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) { 709 free(sin6); 710 free(ret); 711 ret = NULL; 712 goto out; 713 } 714 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6; 715 ret->buf = sin6; 716 break; 717 #endif 718 case AF_LOCAL: 719 sun = (struct sockaddr_un *)malloc(sizeof *sun); 720 if (sun == NULL) 721 goto out; 722 memset(sun, 0, sizeof *sun); 723 sun->sun_family = AF_LOCAL; 724 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1); 725 ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun); 726 ret->buf = sun; 727 break; 728 default: 729 break; 730 } 731 out: 732 free(addrstr); 733 return ret; 734 } 735 736 int 737 __rpc_seman2socktype(int semantics) 738 { 739 switch (semantics) { 740 case NC_TPI_CLTS: 741 return SOCK_DGRAM; 742 case NC_TPI_COTS_ORD: 743 return SOCK_STREAM; 744 case NC_TPI_RAW: 745 return SOCK_RAW; 746 default: 747 break; 748 } 749 750 return -1; 751 } 752 753 int 754 __rpc_socktype2seman(int socktype) 755 { 756 switch (socktype) { 757 case SOCK_DGRAM: 758 return NC_TPI_CLTS; 759 case SOCK_STREAM: 760 return NC_TPI_COTS_ORD; 761 case SOCK_RAW: 762 return NC_TPI_RAW; 763 default: 764 break; 765 } 766 767 return -1; 768 } 769 770 /* 771 * XXXX - IPv6 scope IDs can't be handled in universal addresses. 772 * Here, we compare the original server address to that of the RPC 773 * service we just received back from a call to rpcbind on the remote 774 * machine. If they are both "link local" or "site local", copy 775 * the scope id of the server address over to the service address. 776 */ 777 int 778 __rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc) 779 { 780 #ifdef INET6 781 struct sockaddr *sa_new, *sa_svc; 782 struct sockaddr_in6 *sin6_new, *sin6_svc; 783 784 sa_svc = (struct sockaddr *)svc->buf; 785 sa_new = (struct sockaddr *)new->buf; 786 787 if (sa_new->sa_family == sa_svc->sa_family && 788 sa_new->sa_family == AF_INET6) { 789 sin6_new = (struct sockaddr_in6 *)new->buf; 790 sin6_svc = (struct sockaddr_in6 *)svc->buf; 791 792 if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) && 793 IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) || 794 (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) && 795 IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) { 796 sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id; 797 } 798 } 799 #endif 800 return 1; 801 } 802 803 int 804 __rpc_sockisbound(int fd) 805 { 806 struct sockaddr_storage ss; 807 socklen_t slen; 808 809 slen = sizeof (struct sockaddr_storage); 810 if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) 811 return 0; 812 813 switch (ss.ss_family) { 814 case AF_INET: 815 return (((struct sockaddr_in *) 816 (void *)&ss)->sin_port != 0); 817 #ifdef INET6 818 case AF_INET6: 819 return (((struct sockaddr_in6 *) 820 (void *)&ss)->sin6_port != 0); 821 #endif 822 case AF_LOCAL: 823 /* XXX check this */ 824 return (((struct sockaddr_un *) 825 (void *)&ss)->sun_path[0] != '\0'); 826 default: 827 break; 828 } 829 830 return 0; 831 } 832