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