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 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 * 27 * lib/libnsl/nss/netdir_inet_sundry.c 28 * 29 * This file contains inet-specific implementations of netdir_options, 30 * uaddr2taddr, and taddr2uaddr. These implementations 31 * used to be in both tcpip.so and switch.so (identical copies). 32 * Since we got rid of those, and also it's a good idea to build-in 33 * inet-specific implementations in one place, we decided to put 34 * them in this file with a not-so glorious name. These are INET-SPECIFIC 35 * only, and will not be used for non-inet transports or by third-parties 36 * that decide to provide their own nametoaddr libs for inet transports 37 * (they are on their own for these as well => they get flexibility). 38 * 39 * Copied mostly from erstwhile lib/nametoaddr/tcpip/tcpip.c. 40 */ 41 42 #pragma ident "%Z%%M% %I% %E% SMI" 43 44 #include "mt.h" 45 #include <stdlib.h> 46 #include <stdio.h> 47 #include <string.h> 48 #include <strings.h> 49 #include <unistd.h> 50 #include <sys/types.h> 51 #include <sys/stat.h> 52 #include <fcntl.h> 53 #include <errno.h> 54 #include <thread.h> 55 #include <netconfig.h> 56 #include <netdir.h> 57 #include <nss_netdir.h> 58 #include <tiuser.h> 59 #include <sys/socket.h> 60 #include <net/if.h> 61 #include <sys/sockio.h> 62 #include <sys/fcntl.h> 63 #include <netinet/in.h> 64 #include <netinet/tcp.h> 65 #include <netinet/udp.h> 66 #include <arpa/inet.h> 67 #include <rpc/types.h> 68 #include <rpc/rpc_com.h> 69 #include <syslog.h> 70 #include <values.h> 71 #include <limits.h> 72 #ifdef DEBUG 73 #include <stdio.h> 74 #endif 75 #include <nss_dbdefs.h> 76 #include "nss.h" 77 78 #define MAXIFS 32 79 80 /* 81 * Extracted from socketvar.h 82 */ 83 #define SOV_DEFAULT 1 /* Select based on so_default_version */ 84 #define SOV_SOCKBSD 3 /* Socket with no streams operations */ 85 86 extern int _so_socket(int, int, int, char *, int); 87 extern int _so_connect(int, struct sockaddr *, socklen_t, int); 88 extern int _so_getsockname(int, struct sockaddr *, socklen_t *, int); 89 90 91 static char *inet_netdir_mergeaddr(struct netconfig *, char *, char *); 92 static int bindresvport(struct netconfig *, int, struct netbuf *); 93 static int checkresvport(struct netbuf *); 94 static struct netbuf *ip_uaddr2taddr(char *); 95 static struct netbuf *ipv6_uaddr2taddr(char *); 96 97 98 extern char *inet_ntoa_r(struct in_addr, char *); 99 100 int 101 __inet_netdir_options(struct netconfig *tp, int opts, int fd, char *par) 102 { 103 struct nd_mergearg *ma; 104 105 switch (opts) { 106 case ND_SET_BROADCAST: 107 /* Every one is allowed to broadcast without asking */ 108 return (ND_OK); 109 case ND_SET_RESERVEDPORT: /* bind to a resered port */ 110 /* LINTED pointer cast */ 111 return (bindresvport(tp, fd, (struct netbuf *)par)); 112 case ND_CHECK_RESERVEDPORT: /* check if reserved prot */ 113 /* LINTED pointer cast */ 114 return (checkresvport((struct netbuf *)par)); 115 case ND_MERGEADDR: /* Merge two addresses */ 116 /* LINTED pointer cast */ 117 ma = (struct nd_mergearg *)(par); 118 ma->m_uaddr = inet_netdir_mergeaddr(tp, ma->c_uaddr, 119 ma->s_uaddr); 120 return (_nderror); 121 default: 122 return (ND_NOCTRL); 123 } 124 } 125 126 127 /* 128 * This routine will convert a TCP/IP internal format address 129 * into a "universal" format address. In our case it prints out the 130 * decimal dot equivalent. h1.h2.h3.h4.p1.p2 where h1-h4 are the host 131 * address and p1-p2 are the port number. 132 */ 133 char * 134 __inet_taddr2uaddr(struct netconfig *tp, struct netbuf *addr) 135 { 136 struct sockaddr_in *sa; /* our internal format */ 137 struct sockaddr_in6 *sa6; /* our internal format */ 138 char tmp[RPC_INET6_MAXUADDRSIZE]; 139 unsigned short myport; 140 141 if (addr == NULL || tp == NULL || addr->buf == NULL) { 142 _nderror = ND_BADARG; 143 return (NULL); 144 } 145 if (strcmp(tp->nc_protofmly, NC_INET) == 0) { 146 /* LINTED pointer cast */ 147 sa = (struct sockaddr_in *)(addr->buf); 148 myport = ntohs(sa->sin_port); 149 (void) inet_ntoa_r(sa->sin_addr, tmp); 150 } else { 151 /* LINTED pointer cast */ 152 sa6 = (struct sockaddr_in6 *)(addr->buf); 153 myport = ntohs(sa6->sin6_port); 154 if (inet_ntop(AF_INET6, (void *)sa6->sin6_addr.s6_addr, 155 tmp, sizeof (tmp)) == 0) { 156 _nderror = ND_BADARG; 157 return (NULL); 158 } 159 } 160 161 (void) sprintf(tmp + strlen(tmp), ".%d.%d", myport >> 8, myport & 255); 162 return (strdup(tmp)); /* Doesn't return static data ! */ 163 } 164 165 /* 166 * This internal routine will convert one of those "universal" addresses 167 * to the internal format used by the Sun TLI TCP/IP provider. 168 */ 169 struct netbuf * 170 __inet_uaddr2taddr(struct netconfig *tp, char *addr) 171 { 172 if (!addr || !tp) { 173 _nderror = ND_BADARG; 174 return (NULL); 175 } 176 if (strcmp(tp->nc_protofmly, NC_INET) == 0) 177 return (ip_uaddr2taddr(addr)); 178 else 179 return (ipv6_uaddr2taddr(addr)); 180 } 181 182 static struct netbuf * 183 ip_uaddr2taddr(char *addr) 184 { 185 186 struct sockaddr_in *sa; 187 uint32_t inaddr; 188 unsigned short inport; 189 int h1, h2, h3, h4, p1, p2; 190 struct netbuf *result; 191 192 result = malloc(sizeof (struct netbuf)); 193 if (!result) { 194 _nderror = ND_NOMEM; 195 return (NULL); 196 } 197 198 sa = calloc(1, sizeof (*sa)); 199 200 if (!sa) { 201 free(result); 202 _nderror = ND_NOMEM; 203 return (NULL); 204 } 205 206 result->buf = (char *)(sa); 207 result->maxlen = sizeof (struct sockaddr_in); 208 result->len = sizeof (struct sockaddr_in); 209 210 /* XXX there is probably a better way to do this. */ 211 if (sscanf(addr, "%d.%d.%d.%d.%d.%d", &h1, &h2, &h3, &h4, 212 &p1, &p2) != 6) { 213 free(result); 214 _nderror = ND_NO_RECOVERY; 215 return (NULL); 216 } 217 218 /* convert the host address first */ 219 inaddr = (h1 << 24) + (h2 << 16) + (h3 << 8) + h4; 220 sa->sin_addr.s_addr = htonl(inaddr); 221 222 /* convert the port */ 223 inport = (p1 << 8) + p2; 224 sa->sin_port = htons(inport); 225 226 sa->sin_family = AF_INET; 227 228 return (result); 229 } 230 231 static struct netbuf * 232 ipv6_uaddr2taddr(char *addr) 233 { 234 struct sockaddr_in6 *sa; 235 unsigned short inport; 236 int p1, p2; 237 struct netbuf *result; 238 char tmpaddr[RPC_INET6_MAXUADDRSIZE]; 239 char *dot; 240 241 result = malloc(sizeof (struct netbuf)); 242 if (!result) { 243 _nderror = ND_NOMEM; 244 return (NULL); 245 } 246 247 sa = calloc(1, sizeof (struct sockaddr_in6)); 248 if (!sa) { 249 free(result); 250 _nderror = ND_NOMEM; 251 return (NULL); 252 } 253 result->buf = (char *)(sa); 254 result->maxlen = sizeof (struct sockaddr_in6); 255 result->len = sizeof (struct sockaddr_in6); 256 257 /* retrieve the ipv6 address and port info */ 258 259 if (strlen(addr) > sizeof (tmpaddr) - 1) { 260 free(result); 261 _nderror = ND_NOMEM; 262 return (NULL); 263 } 264 265 (void) strcpy(tmpaddr, addr); 266 267 if ((dot = strrchr(tmpaddr, '.')) != 0) { 268 *dot = '\0'; 269 p2 = atoi(dot+1); 270 if ((dot = strrchr(tmpaddr, '.')) != 0) { 271 *dot = '\0'; 272 p1 = atoi(dot+1); 273 } 274 } 275 276 if (dot == 0) { 277 free(result); 278 _nderror = ND_NOMEM; 279 return (NULL); 280 } 281 282 if (inet_pton(AF_INET6, tmpaddr, sa->sin6_addr.s6_addr) == 0) { 283 free(result); 284 _nderror = ND_NOMEM; 285 return (NULL); 286 } 287 288 /* convert the port */ 289 inport = (p1 << 8) + p2; 290 sa->sin6_port = htons(inport); 291 292 sa->sin6_family = AF_INET6; 293 294 return (result); 295 } 296 297 /* 298 * Interface caching routines. The cache is refreshed every 299 * IF_CACHE_REFRESH_TIME seconds. A read-write lock is used to 300 * protect the cache. 301 */ 302 #define IF_CACHE_REFRESH_TIME 10 303 304 static int if_cache_refresh_time = IF_CACHE_REFRESH_TIME; 305 static rwlock_t iflock = DEFAULTRWLOCK; 306 static time_t last_updated = 0; /* protected by iflock */ 307 308 /* 309 * Changing the data type of if_flags from uint_t to uint64_t to accomodate 310 * extra flags. Refer <net/if.h> for the extra flags. 311 */ 312 typedef struct if_info_s { 313 struct in_addr if_netmask; /* netmask in network order */ 314 struct in_addr if_address; /* address in network order */ 315 uint64_t if_flags; /* interface flags */ 316 } if_info_t; 317 318 static if_info_t *if_info = NULL; /* if cache, protected by iflock */ 319 static int n_ifs = 0; /* number of cached interfaces */ 320 static int numifs_last = 0; /* number of interfaces last seen */ 321 322 /* 323 * Builds the interface cache. Write lock on iflock is needed 324 * for calling this routine. It sets _nderror for error returns. 325 * Returns TRUE if successful, FALSE otherwise. 326 * Changing the structures ifreq and ifconf to lifreq and lifconf to 327 * have larger flag field. This is to accomodate the extra flags associated 328 * with the interface. Also introducing lifn which will contain the number 329 * of IPV4 interfaces present. 330 */ 331 static bool_t 332 get_if_info(void) 333 { 334 size_t needed; 335 struct lifreq *buf = NULL; 336 int numifs; 337 struct lifconf lifc; 338 struct lifreq *lifr; 339 struct lifnum lifn; 340 341 lifn.lifn_family = AF_INET; 342 lifn.lifn_flags = 0; 343 getifnum: 344 if (nss_ioctl(AF_INET, SIOCGLIFNUM, &lifn) == -1) { 345 numifs = MAXIFS; 346 } else { 347 numifs = lifn.lifn_count; 348 } 349 /* 350 * Add a small fudge factor in case interfaces are plumbed 351 * between the SIOCGLIFNUM and SIOCGLIFCONF. 352 */ 353 needed = (numifs + 4) * sizeof (struct lifreq); 354 if (buf == NULL) 355 buf = malloc(needed); 356 else 357 buf = realloc(buf, needed); 358 if (buf == NULL) { 359 _nderror = ND_NOMEM; 360 return (FALSE); 361 } 362 363 lifc.lifc_family = AF_INET; 364 lifc.lifc_flags = 0; 365 lifc.lifc_len = needed; 366 lifc.lifc_buf = (char *)buf; 367 if (nss_ioctl(AF_INET, SIOCGLIFCONF, &lifc) == -1) { 368 /* 369 * IP returns EINVAL if the buffer was too small to fit 370 * all of the entries. If that's the case, go back and 371 * try again. 372 */ 373 if (errno == EINVAL) 374 goto getifnum; 375 376 free(buf); 377 free(if_info); 378 if_info = NULL; 379 _nderror = ND_SYSTEM; 380 return (FALSE); 381 } 382 numifs = lifc.lifc_len / (int)sizeof (struct lifreq); 383 384 if (if_info == NULL || numifs > numifs_last) { 385 if (if_info == NULL) 386 if_info = malloc(numifs * sizeof (if_info_t)); 387 else 388 if_info = realloc(if_info, numifs * sizeof (if_info_t)); 389 if (if_info == NULL) { 390 free(buf); 391 _nderror = ND_NOMEM; 392 return (FALSE); 393 } 394 numifs_last = numifs; 395 } 396 397 n_ifs = 0; 398 for (lifr = buf; lifr < (buf + numifs); lifr++) { 399 if (lifr->lifr_addr.ss_family != AF_INET) 400 continue; 401 402 if_info[n_ifs].if_address = 403 ((struct sockaddr_in *)&lifr->lifr_addr)->sin_addr; 404 405 if (nss_ioctl(AF_INET, SIOCGLIFFLAGS, lifr) < 0) 406 continue; 407 408 if ((lifr->lifr_flags & IFF_UP) == 0) 409 continue; 410 if_info[n_ifs].if_flags = lifr->lifr_flags; 411 412 if (nss_ioctl(AF_INET, SIOCGLIFNETMASK, lifr) < 0) 413 continue; 414 415 if_info[n_ifs].if_netmask = 416 ((struct sockaddr_in *)&lifr->lifr_addr)->sin_addr; 417 n_ifs++; 418 } 419 free(buf); 420 return (TRUE); 421 } 422 423 424 /* 425 * Update the interface cache based on last update time. 426 */ 427 static bool_t 428 update_if_cache(void) 429 { 430 time_t curtime; 431 432 (void) rw_wrlock(&iflock); 433 /* 434 * Check if some other thread has beaten this one to it. 435 */ 436 (void) time(&curtime); 437 if ((curtime - last_updated) >= if_cache_refresh_time) { 438 if (!get_if_info()) { 439 (void) rw_unlock(&iflock); 440 return (FALSE); 441 } 442 (void) time(&last_updated); 443 } 444 (void) rw_unlock(&iflock); 445 return (TRUE); 446 } 447 448 449 /* 450 * Given an IP address, check if this matches any of the interface 451 * addresses. If an error occurs, return FALSE so that the caller 452 * will not assume that this address belongs to this machine. 453 */ 454 static bool_t 455 is_my_address(struct in_addr addr) 456 { 457 time_t curtime; 458 if_info_t *ifn; 459 460 (void) time(&curtime); 461 if ((curtime - last_updated) >= if_cache_refresh_time) { 462 /* 463 * Cache needs to be refreshed. 464 */ 465 if (!update_if_cache()) 466 return (FALSE); 467 } 468 (void) rw_rdlock(&iflock); 469 for (ifn = if_info; ifn < (if_info + n_ifs); ifn++) { 470 if (addr.s_addr == ifn->if_address.s_addr) { 471 (void) rw_unlock(&iflock); 472 return (TRUE); 473 } 474 } 475 (void) rw_unlock(&iflock); 476 return (FALSE); 477 } 478 479 480 /* 481 * Given a host name, check if it is this host. 482 */ 483 bool_t 484 __inet_netdir_is_my_host(const char *host) 485 { 486 int error; 487 char buf[NSS_BUFLEN_HOSTS]; 488 struct hostent res, *h; 489 char **c; 490 struct in_addr in; 491 492 h = gethostbyname_r(host, (void *)&res, buf, sizeof (buf), &error); 493 if (h == NULL) 494 return (FALSE); 495 if (h->h_addrtype != AF_INET) 496 return (FALSE); 497 for (c = h->h_addr_list; *c != NULL; c++) { 498 (void) memcpy(&in.s_addr, *c, sizeof (in.s_addr)); 499 if (is_my_address(in)) 500 return (TRUE); 501 } 502 return (FALSE); 503 } 504 505 506 /* 507 * Given an IP address, find the interface address that has the best 508 * prefix match. Return the address in network order. 509 */ 510 static uint32_t 511 get_best_match(struct in_addr addr) 512 { 513 if_info_t *bestmatch, *ifn; 514 int bestcount, count, limit; 515 uint32_t mask, netmask, clnt_addr, if_addr; 516 bool_t found, subnet_match; 517 int subnet_count; 518 519 bestmatch = NULL; /* no match yet */ 520 bestcount = BITSPERBYTE * sizeof (uint32_t); /* worst match */ 521 clnt_addr = ntohl(addr.s_addr); /* host order */ 522 523 subnet_match = FALSE; /* subnet match not found yet */ 524 subnet_count = bestcount; /* worst subnet match */ 525 526 for (ifn = if_info; ifn < (if_info + n_ifs); ifn++) { 527 netmask = ntohl(ifn->if_netmask.s_addr); /* host order */ 528 if_addr = ntohl(ifn->if_address.s_addr); /* host order */ 529 530 /* 531 * Checking if the interface selected is FAILED or DEPRECATED. 532 * In case IFF_FAILED or IFF_DEPRECATED flag for the interface 533 * is set, we move on to the next interface in the list. 534 * Refer IPMP(IP Multi Pathing) for more details. 535 */ 536 537 if ((ifn->if_flags & (IFF_FAILED | IFF_DEPRECATED)) != 0) 538 continue; 539 540 /* 541 * set initial count to first bit set in netmask, with 542 * zero being the number of the least significant bit. 543 */ 544 for (count = 0, mask = netmask; mask && ((mask & 1) == 0); 545 count++, mask >>= 1); 546 547 /* 548 * Set limit so that we don't try to match prefixes shorter 549 * than the inherent netmask for the class (A, B, C, etc). 550 */ 551 if (IN_CLASSC(if_addr)) 552 limit = IN_CLASSC_NSHIFT; 553 else if (IN_CLASSB(if_addr)) 554 limit = IN_CLASSB_NSHIFT; 555 else if (IN_CLASSA(if_addr)) 556 limit = IN_CLASSA_NSHIFT; 557 else 558 limit = 0; 559 560 /* 561 * We assume that the netmask consists of a contiguous 562 * sequence of 1-bits starting with the most significant bit. 563 * Prefix comparison starts at the subnet mask level. 564 * The prefix mask used for comparison is progressively 565 * reduced until it equals the inherent mask for the 566 * interface address class. The algorithm finds an 567 * interface in the following order of preference: 568 * 569 * (1) the longest subnet match 570 * (2) the best partial subnet match 571 * (3) the first non-loopback && non-PPP interface 572 * (4) the first non-loopback interface (PPP is OK) 573 * 574 * While checking for condition (3) and (4), we also look 575 * if the interface we are returning is neither FAILED 576 * nor DEPRECATED. In case there are no interface 577 * available, which are neither FAILED nor DEPRECRATED, 578 * we return 0. 579 */ 580 found = FALSE; 581 while (netmask && count < subnet_count) { 582 if ((netmask & clnt_addr) == (netmask & if_addr)) { 583 bestcount = count; 584 bestmatch = ifn; 585 found = TRUE; 586 break; 587 } 588 netmask <<= 1; 589 count++; 590 if (count >= bestcount || count > limit || subnet_match) 591 break; 592 } 593 /* 594 * If a subnet level match occurred, note this for 595 * comparison with future subnet matches. 596 */ 597 if (found && (netmask == ntohl(ifn->if_netmask.s_addr))) { 598 subnet_match = TRUE; 599 subnet_count = count; 600 } 601 } 602 603 /* 604 * If we don't have a match, select the first interface that 605 * is not a loopback interface (and preferably not a PPP interface) 606 * as the best match. 607 */ 608 if (bestmatch == NULL) { 609 for (ifn = if_info; ifn < (if_info + n_ifs); ifn++) { 610 if ((ifn->if_flags & (IFF_LOOPBACK | 611 IFF_FAILED | IFF_DEPRECATED)) == 0) { 612 bestmatch = ifn; 613 614 /* 615 * If this isn't a PPP interface, we're 616 * done. Otherwise, keep walking through 617 * the list in case we have a non-loopback 618 * iface that ISN'T a PPP further down our 619 * list... 620 */ 621 if ((ifn->if_flags & IFF_POINTOPOINT) == 0) { 622 #ifdef DEBUG 623 (void) printf("found !loopback && !non-PPP interface: %s\n", 624 inet_ntoa(ifn->if_address)); 625 #endif 626 break; 627 } 628 } 629 } 630 } 631 632 if (bestmatch != NULL) 633 return (bestmatch->if_address.s_addr); 634 else 635 return (0); 636 } 637 638 static int 639 is_myself(struct sockaddr_in6 *sa6) 640 { 641 struct sioc_addrreq areq; 642 int s; 643 644 if ((s = open("/dev/udp6", O_RDONLY)) < 0) { 645 syslog(LOG_ERR, "is_myself: can't open /dev/udp6: %m"); 646 return (0); 647 } 648 649 (void) memcpy(&areq.sa_addr, sa6, sizeof (struct sockaddr_storage)); 650 areq.sa_res = -1; 651 652 if (ioctl(s, SIOCTMYADDR, (caddr_t)&areq) < 0) { 653 syslog(LOG_ERR, "is_myself:SIOCTMYADDR failed: %m"); 654 (void) close(s); 655 return (0); 656 } 657 658 (void) close(s); 659 return (areq.sa_res); 660 661 } 662 /* 663 * For a given destination address, determine a source address to use. 664 * Returns wildcard address if it cannot determine the source address. 665 * copied from ping.c. 666 */ 667 union any_in_addr { 668 struct in6_addr addr6; 669 struct in_addr addr; 670 }; 671 672 static bool_t 673 select_server_addr(union any_in_addr *dst_addr, int family, 674 union any_in_addr *src_addr) 675 { 676 struct sockaddr *sock; 677 struct sockaddr_in *sin; 678 struct sockaddr_in6 *sin6; 679 int tmp_fd; 680 socklen_t sock_len; 681 682 sock = calloc(1, sizeof (struct sockaddr_in6)); 683 if (sock == NULL) { 684 return (FALSE); 685 } 686 687 if (family == AF_INET) { 688 /* LINTED pointer cast */ 689 sin = (struct sockaddr_in *)sock; 690 sin->sin_family = AF_INET; 691 sin->sin_port = 111; 692 sin->sin_addr = dst_addr->addr; 693 sock_len = sizeof (struct sockaddr_in); 694 } else { 695 /* LINTED pointer cast */ 696 sin6 = (struct sockaddr_in6 *)sock; 697 sin6->sin6_family = AF_INET6; 698 sin6->sin6_port = 111; 699 sin6->sin6_addr = dst_addr->addr6; 700 sock_len = sizeof (struct sockaddr_in6); 701 } 702 703 /* open a UDP socket */ 704 if ((tmp_fd = _so_socket(family, SOCK_DGRAM, 0, 705 NULL, SOV_SOCKBSD)) < 0) { 706 syslog(LOG_ERR, "selsect_server_addr:connect failed\n"); 707 return (FALSE); 708 } 709 710 /* connect it */ 711 if (_so_connect(tmp_fd, sock, sock_len, SOV_SOCKBSD) < 0) { 712 /* 713 * If there's no route to the destination, this connect() call 714 * fails. We just return all-zero (wildcard) as the source 715 * address, so that user can get to see "no route to dest" 716 * message, as it'll try to send the probe packet out and will 717 * receive ICMP unreachable. 718 */ 719 if (family == AF_INET) 720 src_addr->addr.s_addr = INADDR_ANY; 721 else 722 /* 723 * Since in6addr_any is not in the scope 724 * use the following hack 725 */ 726 (void) memset(src_addr->addr6.s6_addr, 727 0, sizeof (struct in6_addr)); 728 (void) close(tmp_fd); 729 free(sock); 730 return (FALSE); 731 } 732 733 /* get the local sock info */ 734 if (_so_getsockname(tmp_fd, sock, &sock_len, SOV_DEFAULT) < 0) { 735 syslog(LOG_ERR, "selsect_server_addr:getsockname failed\n"); 736 (void) close(tmp_fd); 737 free(sock); 738 return (FALSE); 739 } 740 741 if (family == AF_INET) { 742 /* LINTED pointer cast */ 743 sin = (struct sockaddr_in *)sock; 744 src_addr->addr = sin->sin_addr; 745 } else { 746 /* LINTED pointer cast */ 747 sin6 = (struct sockaddr_in6 *)sock; 748 src_addr->addr6 = sin6->sin6_addr; 749 } 750 751 (void) close(tmp_fd); 752 free(sock); 753 return (TRUE); 754 } 755 756 /* 757 * This internal routine will merge one of those "universal" addresses 758 * to the one which will make sense to the remote caller. 759 */ 760 static char * 761 inet_netdir_mergeaddr(struct netconfig *tp, char *ruaddr, char *uaddr) 762 { 763 char tmp[SYS_NMLN], *cp; 764 int j; 765 struct in_addr clientaddr, bestmatch; 766 time_t curtime; 767 int af; 768 769 if (!uaddr || !ruaddr || !tp) { 770 _nderror = ND_BADARG; 771 return (NULL); 772 } 773 (void) bzero(tmp, SYS_NMLN); 774 775 if (strcmp(tp->nc_protofmly, NC_INET) == 0) 776 af = AF_INET; 777 else 778 af = AF_INET6; 779 780 if (af == AF_INET) { 781 if (strncmp(ruaddr, "0.0.0.0.", strlen("0.0.0.0.")) == 0) 782 /* thats me: return the way it is */ 783 return (strdup(uaddr)); 784 785 /* 786 * Convert remote uaddr into an in_addr so that we can compare 787 * to it. Shave off last two dotted-decimal values. 788 */ 789 for (cp = ruaddr, j = 0; j < 4; j++, cp++) 790 if ((cp = strchr(cp, '.')) == NULL) 791 break; 792 793 if (cp != NULL) 794 *--cp = '\0'; /* null out the dot after the IP addr */ 795 else { 796 _nderror = ND_NOHOST; 797 return (NULL); 798 } 799 800 clientaddr.s_addr = inet_addr(ruaddr); 801 802 #ifdef DEBUG 803 (void) printf("client's address is %s and %s\n", 804 ruaddr, inet_ntoa(clientaddr)); 805 #endif 806 807 /* We know cp is not NULL due to the check above */ 808 *cp = '.'; /* Put the dot back in the IP addr */ 809 810 (void) time(&curtime); 811 if ((curtime - last_updated) >= if_cache_refresh_time) { 812 /* 813 * Cache needs to be refreshed. 814 */ 815 if (!update_if_cache()) 816 return (NULL); 817 } 818 819 /* 820 * Find the best match now. 821 */ 822 (void) rw_rdlock(&iflock); 823 bestmatch.s_addr = get_best_match(clientaddr); 824 (void) rw_unlock(&iflock); 825 826 if (bestmatch.s_addr) 827 _nderror = ND_OK; 828 else { 829 _nderror = ND_NOHOST; 830 return (NULL); 831 } 832 833 /* prepare the reply */ 834 (void) memset(tmp, '\0', sizeof (tmp)); 835 836 /* reply consists of the IP addr of the closest interface */ 837 (void) strcpy(tmp, inet_ntoa(bestmatch)); 838 839 /* 840 * ... and the port number part (last two dotted-decimal values) 841 * of uaddr 842 */ 843 for (cp = uaddr, j = 0; j < 4; j++, cp++) 844 cp = strchr(cp, '.'); 845 (void) strcat(tmp, --cp); 846 847 } else { 848 /* IPv6 */ 849 char *dot; 850 char *truaddr; 851 struct sockaddr_in6 sa; 852 struct sockaddr_in6 server_addr; 853 union any_in_addr in_addr, out_addr; 854 855 if (strncmp(ruaddr, "::", strlen("::")) == 0) 856 if (*(ruaddr + strlen("::")) == '\0') 857 /* thats me: return the way it is */ 858 return (strdup(uaddr)); 859 860 bzero(&sa, sizeof (sa)); 861 bzero(&server_addr, sizeof (server_addr)); 862 truaddr = &tmp[0]; 863 (void) strcpy(truaddr, ruaddr); 864 865 /* 866 * now extract the server ip address from 867 * the address supplied by client. It can be 868 * client's own IP address. 869 */ 870 871 if ((dot = strrchr(truaddr, '.')) != 0) { 872 *dot = '\0'; 873 if ((dot = strrchr(truaddr, '.')) != 0) 874 *dot = '\0'; 875 } 876 877 if (dot == 0) { 878 _nderror = ND_NOHOST; 879 return (NULL); 880 } 881 882 if (inet_pton(af, truaddr, sa.sin6_addr.s6_addr) 883 != 1) { 884 _nderror = ND_NOHOST; 885 return (NULL); 886 } 887 888 in_addr.addr6 = sa.sin6_addr; 889 sa.sin6_family = AF_INET6; 890 891 /* is it my IP address */ 892 if (!is_myself(&sa)) { 893 /* have the kernel select one for me */ 894 if (select_server_addr(&in_addr, af, &out_addr) == 895 FALSE) 896 return (NULL); 897 server_addr.sin6_addr = out_addr.addr6; 898 } 899 else 900 (void) memcpy(&server_addr, &sa, 901 sizeof (struct sockaddr_in6)); 902 #ifdef DEBUG 903 printf("%s\n", inet_ntop(af, out_addr.addr6.s6_addr, 904 tmp, sizeof (tmp))); 905 #endif 906 907 if (inet_ntop(af, server_addr.sin6_addr.s6_addr, 908 tmp, sizeof (tmp)) == NULL) { 909 _nderror = ND_NOHOST; 910 return (NULL); 911 } 912 913 /* now extract the port info */ 914 if ((dot = strrchr(uaddr, '.')) != 0) { 915 916 char *p; 917 918 p = --dot; 919 while (*p-- != '.'); 920 p++; 921 (void) strcat(tmp + strlen(tmp), p); 922 _nderror = ND_OK; 923 } else { 924 _nderror = ND_NOHOST; 925 return (NULL); 926 } 927 928 } 929 return (strdup(tmp)); 930 } 931 932 static int 933 bindresvport(struct netconfig *nconf, int fd, struct netbuf *addr) 934 { 935 int res; 936 struct sockaddr_in myaddr; 937 struct sockaddr_in6 myaddr6; 938 struct sockaddr_in *sin; 939 struct sockaddr_in6 *sin6; 940 int i; 941 struct t_bind tbindstr, *tres; 942 struct t_info tinfo; 943 struct t_optmgmt req, resp; 944 struct opthdr *opt; 945 int reqbuf[64/sizeof (int)]; 946 int *optval; 947 948 union { 949 struct sockaddr_in *sin; 950 struct sockaddr_in6 *sin6; 951 char *buf; 952 } u; 953 954 _nderror = ND_SYSTEM; 955 if (geteuid()) { 956 errno = EACCES; 957 return (-1); 958 } 959 if ((i = t_getstate(fd)) != T_UNBND) { 960 if (t_errno == TBADF) 961 errno = EBADF; 962 if (i != -1) 963 errno = EISCONN; 964 return (-1); 965 } 966 967 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 968 if (addr == NULL) { 969 sin = &myaddr; 970 (void) memset(sin, 0, sizeof (*sin)); 971 sin->sin_family = AF_INET; 972 u.buf = (char *)sin; 973 } else 974 u.buf = (char *)addr->buf; 975 } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) { 976 if (addr == NULL) { 977 sin6 = &myaddr6; 978 (void) memset(sin6, 0, sizeof (*sin6)); 979 sin6->sin6_family = AF_INET6; 980 u.buf = (char *)sin6; 981 } else 982 u.buf = addr->buf; 983 984 } else { 985 errno = EPFNOSUPPORT; 986 return (-1); 987 } 988 989 /* Transform sockaddr_in to netbuf */ 990 if (t_getinfo(fd, &tinfo) == -1) 991 return (-1); 992 /* LINTED pointer cast */ 993 tres = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR); 994 if (tres == NULL) { 995 _nderror = ND_NOMEM; 996 return (-1); 997 } 998 999 tbindstr.qlen = 0; /* Always 0; user should change if he wants to */ 1000 tbindstr.addr.buf = (char *)u.buf; 1001 tbindstr.addr.len = tbindstr.addr.maxlen = __rpc_get_a_size(tinfo.addr); 1002 1003 /* 1004 * Use *_ANONPRIVBIND to ask the kernel to pick a port in the 1005 * priviledged range for us. 1006 */ 1007 opt = (struct opthdr *)reqbuf; 1008 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 1009 opt->level = IPPROTO_TCP; 1010 opt->name = TCP_ANONPRIVBIND; 1011 } else if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 1012 opt->level = IPPROTO_UDP; 1013 opt->name = UDP_ANONPRIVBIND; 1014 } else { 1015 errno = EPROTONOSUPPORT; 1016 (void) t_free((char *)tres, T_BIND); 1017 return (-1); 1018 } 1019 1020 opt->len = sizeof (int); 1021 req.flags = T_NEGOTIATE; 1022 req.opt.len = sizeof (struct opthdr) + opt->len; 1023 req.opt.buf = (char *)opt; 1024 /* LINTED pointer cast */ 1025 optval = (int *)((char *)reqbuf + sizeof (struct opthdr)); 1026 *optval = 1; 1027 resp.flags = 0; 1028 resp.opt.buf = (char *)reqbuf; 1029 resp.opt.maxlen = sizeof (reqbuf); 1030 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { 1031 (void) t_free((char *)tres, T_BIND); 1032 return (-1); 1033 } 1034 1035 if (u.sin->sin_family == AF_INET) 1036 u.sin->sin_port = htons(0); 1037 else 1038 u.sin6->sin6_port = htons(0); 1039 res = t_bind(fd, &tbindstr, tres); 1040 if (res != 0) { 1041 if (t_errno == TNOADDR) { 1042 _nderror = ND_FAILCTRL; 1043 res = 1; 1044 } 1045 } else { 1046 _nderror = ND_OK; 1047 } 1048 1049 /* 1050 * Always turn off the option when we are done. Note that by doing 1051 * this, if the caller has set this option before calling 1052 * bindresvport(), it will be unset. Better be safe... 1053 */ 1054 *optval = 0; 1055 resp.flags = 0; 1056 resp.opt.buf = (char *)reqbuf; 1057 resp.opt.maxlen = sizeof (reqbuf); 1058 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { 1059 (void) t_free((char *)tres, T_BIND); 1060 if (res == 0) 1061 (void) t_unbind(fd); 1062 _nderror = ND_FAILCTRL; 1063 return (-1); 1064 } 1065 1066 (void) t_free((char *)tres, T_BIND); 1067 return (res); 1068 } 1069 1070 static int 1071 checkresvport(struct netbuf *addr) 1072 { 1073 struct sockaddr_in *sin; 1074 unsigned short port; 1075 1076 if (addr == NULL) { 1077 _nderror = ND_FAILCTRL; 1078 return (-1); 1079 } 1080 /* 1081 * Still works for IPv6 since the first two memebers of 1082 * both address structure point to family and port # respectively 1083 */ 1084 /* LINTED pointer cast */ 1085 sin = (struct sockaddr_in *)(addr->buf); 1086 port = ntohs(sin->sin_port); 1087 if (port < IPPORT_RESERVED) 1088 return (0); 1089 return (1); 1090 } 1091