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