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