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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * This is where we have chosen to combine every useful bit of code for 29 * all the Solaris frontends to lookup hosts, services, and netdir information 30 * for inet family (udp, tcp) transports. gethostbyYY(), getservbyYY(), and 31 * netdir_getbyYY() are all implemented on top of this code. Similarly, 32 * netdir_options, taddr2uaddr, and uaddr2taddr for inet transports also 33 * find a home here. 34 * 35 * If the netconfig structure supplied has NO nametoaddr libs (i.e. a "-" 36 * in /etc/netconfig), this code calls the name service switch, and 37 * therefore, /etc/nsswitch.conf is effectively the only place that 38 * dictates hosts/serv lookup policy. 39 * If an administrator chooses to bypass the name service switch by 40 * specifying third party supplied nametoaddr libs in /etc/netconfig, this 41 * implementation does NOT call the name service switch, it merely loops 42 * through the nametoaddr libs. In this case, if this code was called 43 * from gethost/servbyYY() we marshal the inet specific struct into 44 * transport independent netbuf or hostserv, and unmarshal the resulting 45 * nd_addrlist or hostservlist back into hostent and servent, as the case 46 * may be. 47 * 48 * Goes without saying that most of the future bugs in gethost/servbyYY 49 * and netdir_getbyYY are lurking somewhere here. 50 */ 51 52 #include "mt.h" 53 #include <ctype.h> 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <string.h> 57 #include <unistd.h> 58 #include <stropts.h> 59 #include <sys/types.h> 60 #include <sys/byteorder.h> 61 #include <sys/ioctl.h> 62 #include <sys/param.h> 63 #include <sys/time.h> 64 #include <errno.h> 65 #include <fcntl.h> 66 #include <thread.h> 67 #include <synch.h> 68 #include <sys/utsname.h> 69 #include <netdb.h> 70 #include <netconfig.h> 71 #include <netdir.h> 72 #include <tiuser.h> 73 #include <sys/socket.h> 74 #include <sys/sockio.h> 75 #include <netinet/in.h> 76 #include <arpa/inet.h> 77 #include <net/if.h> 78 #include <inet/ip.h> 79 #include <inet/ip6_asp.h> 80 #include <sys/dlpi.h> 81 #include <nss_dbdefs.h> 82 #include <nss_netdir.h> 83 #include <syslog.h> 84 #include <nsswitch.h> 85 #include "nss.h" 86 87 #define MAXIFS 32 88 #define UDPDEV "/dev/udp" 89 #define UDP6DEV "/dev/udp6" 90 91 #define DOOR_GETHOSTBYNAME_R _switch_gethostbyname_r 92 #define DOOR_GETHOSTBYADDR_R _switch_gethostbyaddr_r 93 #define DOOR_GETIPNODEBYNAME_R _switch_getipnodebyname_r 94 #define DOOR_GETIPNODEBYADDR_R _switch_getipnodebyaddr_r 95 96 #define DONT_SORT "SORT_ADDRS=NO" 97 #define DONT_SORT2 "SORT_ADDRS=FALSE" 98 #define LINESIZE 100 99 100 /* 101 * constant values of addresses for HOST_SELF_BIND, HOST_SELF_CONNECT 102 * and localhost. 103 * 104 * The following variables are static to the extent that they should 105 * not be visible outside of this file. 106 */ 107 static char *localaddr[] = {"\000\000\000\000", NULL}; 108 static char *connectaddr[] = {"\177\000\000\001", NULL}; 109 static char *localaddr6[] = 110 {"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", NULL}; 111 static char *connectaddr6[] = 112 {"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001", NULL}; 113 114 /* IPv4 nd_addrlist */ 115 static mutex_t nd_addr_lock = DEFAULTMUTEX; 116 static struct sockaddr_in sa_con; 117 static struct netbuf nd_conbuf = {sizeof (sa_con),\ 118 sizeof (sa_con), (char *)&sa_con}; 119 static struct nd_addrlist nd_conaddrlist = {1, &nd_conbuf}; 120 121 /* IPv6 nd_addrlist */ 122 static mutex_t nd6_addr_lock = DEFAULTMUTEX; 123 static struct sockaddr_in6 sa6_con; 124 static struct netbuf nd6_conbuf = {sizeof (sa6_con),\ 125 sizeof (sa6_con), (char *)&sa6_con}; 126 static struct nd_addrlist nd6_conaddrlist = {1, &nd6_conbuf}; 127 128 #define LOCALHOST "localhost" 129 130 struct servent *_switch_getservbyname_r(const char *, const char *, 131 struct servent *, char *, int); 132 struct servent *_switch_getservbyport_r(int, const char *, struct servent *, 133 char *, int); 134 135 static int __herrno2netdir(int h_errnop); 136 static struct ifinfo *get_local_info(void); 137 static int getbroadcastnets(struct netconfig *, struct in_addr **); 138 static int hent2ndaddr(int, char **, int *, struct nd_addrlist **); 139 static int ndaddr2hent(int, const char *, struct nd_addrlist *, 140 struct hostent *, char *, int); 141 static int hsents2ndhostservs(struct hostent *, struct servent *, ushort_t, 142 struct nd_hostservlist **); 143 static int ndaddr2srent(const char *, const char *, ushort_t, struct servent *, 144 char *, int); 145 static int ndhostserv2hent(struct netbuf *, struct nd_hostservlist *, 146 struct hostent *, char *, int); 147 static int ndhostserv2srent(int, const char *, struct nd_hostservlist *, 148 struct servent *, char *, int); 149 static int nd2herrno(int nerr); 150 static void order_haddrlist_inet(char **haddrlist, size_t addrcount); 151 static void order_haddrlist_inet6(char **haddrlist, size_t addrcount); 152 static int dstcmp(const void *, const void *); 153 static int nss_strioctl(int af, int cmd, void *ptr, int ilen); 154 static struct in_addr _inet_makeaddr(in_addr_t, in_addr_t); 155 static boolean_t _read_nsw_file(void); 156 157 /* 158 * Begin: PART I 159 * Top Level Interfaces that gethost/serv/netdir funnel through. 160 */ 161 162 /* 163 * gethost/servbyname always call this function; if they call 164 * with nametoaddr libs in nconf, we call netdir_getbyname 165 * implementation: __classic_netdir_getbyname, otherwise nsswitch. 166 * 167 * netdir_getbyname calls this only if nametoaddr libs are NOT 168 * specified for inet transports; i.e. it's supposed to follow 169 * the name service switch. 170 */ 171 int 172 _get_hostserv_inetnetdir_byname(struct netconfig *nconf, 173 struct nss_netdirbyname_in *args, union nss_netdirbyname_out *res) 174 { 175 int server_port; 176 int *servp = &server_port; 177 char **haddrlist; 178 uint32_t dotnameaddr; 179 char *dotnamelist[2]; 180 struct in_addr *inaddrs = NULL; 181 struct in6_addr v6nameaddr; 182 char **baddrlist = NULL; 183 184 185 if (nconf == NULL) { 186 _nderror = ND_BADARG; 187 return (ND_BADARG); 188 } 189 190 /* 191 * 1. gethostbyname()/netdir_getbyname() special cases: 192 */ 193 switch (args->op_t) { 194 195 case NSS_HOST: 196 /* 197 * Worth the performance gain -- assuming a lot of inet apps 198 * actively use "localhost". 199 */ 200 if (strcmp(args->arg.nss.host.name, LOCALHOST) == 0) { 201 202 (void) mutex_lock(&nd_addr_lock); 203 IN_SET_LOOPBACK_ADDR(&sa_con); 204 _nderror = ndaddr2hent(AF_INET, args->arg.nss.host.name, 205 &nd_conaddrlist, res->nss.host.hent, 206 args->arg.nss.host.buf, 207 args->arg.nss.host.buflen); 208 (void) mutex_unlock(&nd_addr_lock); 209 if (_nderror != ND_OK) 210 *(res->nss.host.herrno_p) = 211 nd2herrno(_nderror); 212 return (_nderror); 213 } 214 /* 215 * If the caller passed in a dot separated IP notation to 216 * gethostbyname, return that back as the address. 217 * The nd_addr_lock mutex was added to be truely re-entrant. 218 */ 219 if (inet_aton(args->arg.nss.host.name, 220 (struct in_addr *)&dotnameaddr)) { 221 (void) mutex_lock(&nd_addr_lock); 222 (void) memset(&sa_con, 0, sizeof (sa_con)); 223 sa_con.sin_family = AF_INET; 224 sa_con.sin_addr.s_addr = dotnameaddr; 225 _nderror = ndaddr2hent(AF_INET, args->arg.nss.host.name, 226 &nd_conaddrlist, res->nss.host.hent, 227 args->arg.nss.host.buf, 228 args->arg.nss.host.buflen); 229 (void) mutex_unlock(&nd_addr_lock); 230 if (_nderror != ND_OK) 231 *(res->nss.host.herrno_p) = 232 nd2herrno(_nderror); 233 return (_nderror); 234 } 235 break; 236 237 case NSS_HOST6: 238 /* 239 * Handle case of literal address string. 240 */ 241 if (strchr(args->arg.nss.host6.name, ':') != NULL && 242 (inet_pton(AF_INET6, args->arg.nss.host6.name, 243 &v6nameaddr) != 0)) { 244 int ret; 245 246 (void) mutex_lock(&nd6_addr_lock); 247 (void) memset(&sa6_con, 0, sizeof (sa6_con)); 248 sa6_con.sin6_family = AF_INET6; 249 (void) memcpy(&(sa6_con.sin6_addr.s6_addr), 250 &v6nameaddr, sizeof (struct in6_addr)); 251 ret = ndaddr2hent(AF_INET6, 252 args->arg.nss.host6.name, 253 &nd6_conaddrlist, res->nss.host.hent, 254 args->arg.nss.host6.buf, 255 args->arg.nss.host6.buflen); 256 (void) mutex_unlock(&nd6_addr_lock); 257 if (ret != ND_OK) 258 *(res->nss.host.herrno_p) = nd2herrno(ret); 259 else 260 res->nss.host.hent->h_aliases = NULL; 261 return (ret); 262 } 263 break; 264 265 case NETDIR_BY: 266 if (args->arg.nd_hs == 0) { 267 _nderror = ND_BADARG; 268 return (ND_BADARG); 269 } 270 /* 271 * If servname is NULL, return 0 as the port number 272 * If servname is rpcbind, return 111 as the port number 273 * If servname is a number, return it back as the port 274 * number. 275 */ 276 if (args->arg.nd_hs->h_serv == 0) { 277 *servp = htons(0); 278 } else if (strcmp(args->arg.nd_hs->h_serv, 279 "rpcbind") == 0) { 280 *servp = htons(111); 281 } else if (strspn(args->arg.nd_hs->h_serv, 282 "0123456789") == 283 strlen(args->arg.nd_hs->h_serv)) { 284 *servp = htons(atoi(args->arg.nd_hs->h_serv)); 285 } else { 286 /* i.e. need to call a name service on this */ 287 servp = NULL; 288 } 289 290 /* 291 * If the hostname is HOST_SELF_BIND, we return 0.0.0.0 292 * so the binding can be contacted through all 293 * interfaces. If the hostname is HOST_SELF_CONNECT, 294 * we return 127.0.0.1 so the address can be connected 295 * to locally. If the hostname is HOST_ANY, we return 296 * no addresses because IP doesn't know how to specify 297 * a service without a host. And finally if we specify 298 * HOST_BROADCAST then we ask a tli fd to tell us what 299 * the broadcast addresses are for any udp 300 * interfaces on this machine. 301 */ 302 if (args->arg.nd_hs->h_host == 0) { 303 _nderror = ND_NOHOST; 304 return (ND_NOHOST); 305 } else if ((strcmp(args->arg.nd_hs->h_host, 306 HOST_SELF_BIND) == 0)) { 307 haddrlist = localaddr; 308 } else if ((strcmp(args->arg.nd_hs->h_host, 309 HOST_SELF_CONNECT) == 0)) { 310 haddrlist = connectaddr; 311 } else if ((strcmp(args->arg.nd_hs->h_host, 312 LOCALHOST) == 0)) { 313 haddrlist = connectaddr; 314 } else if ((int)(dotnameaddr = 315 inet_addr(args->arg.nd_hs->h_host)) != -1) { 316 /* 317 * If the caller passed in a dot separated IP 318 * notation to netdir_getbyname, convert that 319 * back into address. 320 */ 321 322 dotnamelist[0] = (char *)&dotnameaddr; 323 dotnamelist[1] = NULL; 324 haddrlist = dotnamelist; 325 } else if ((strcmp(args->arg.nd_hs->h_host, 326 HOST_BROADCAST) == 0)) { 327 /* 328 * Now that inaddrs and baddrlist are 329 * dynamically allocated, care must be 330 * taken in freeing up the 331 * memory at each 'return()' point. 332 * 333 * Early return protection (using 334 * FREE_return()) is needed only in NETDIR_BY 335 * cases because dynamic allocation is used 336 * when args->op_t == NETDIR_BY. 337 * 338 * Early return protection is not needed in 339 * haddrlist==0 conditionals because dynamic 340 * allocation guarantees haddrlist!=0. 341 * 342 * Early return protection is not needed in most 343 * servp!=0 conditionals because this is handled 344 * (and returned) first. 345 */ 346 #define FREE_return(ret) \ 347 { \ 348 if (inaddrs) \ 349 free(inaddrs); \ 350 if (baddrlist) \ 351 free(baddrlist); \ 352 _nderror = ret; \ 353 return (ret); \ 354 } 355 int i, bnets; 356 357 bnets = getbroadcastnets(nconf, &inaddrs); 358 if (bnets == 0) { 359 _nderror = ND_NOHOST; 360 return (ND_NOHOST); 361 } 362 baddrlist = malloc((bnets+1)*sizeof (char *)); 363 if (baddrlist == NULL) 364 FREE_return(ND_NOMEM); 365 for (i = 0; i < bnets; i++) 366 baddrlist[i] = (char *)&inaddrs[i]; 367 baddrlist[i] = NULL; 368 haddrlist = baddrlist; 369 } else { 370 /* i.e. need to call a name service on this */ 371 haddrlist = 0; 372 } 373 374 if (haddrlist && servp) { 375 int ret; 376 /* 377 * Convert h_addr_list into nd_addrlist. 378 * malloc's will be done, freed using 379 * netdir_free. 380 */ 381 ret = hent2ndaddr(AF_INET, haddrlist, servp, 382 res->nd_alist); 383 FREE_return(ret); 384 } 385 break; 386 387 388 case NETDIR_BY6: 389 if (args->arg.nd_hs == 0) { 390 _nderror = ND_BADARG; 391 return (ND_BADARG); 392 } 393 /* 394 * If servname is NULL, return 0 as the port number. 395 * If servname is rpcbind, return 111 as the port number 396 * If servname is a number, return it back as the port 397 * number. 398 */ 399 if (args->arg.nd_hs->h_serv == 0) { 400 *servp = htons(0); 401 } else if (strcmp(args->arg.nd_hs->h_serv, 402 "rpcbind") == 0) { 403 *servp = htons(111); 404 } else if (strspn(args->arg.nd_hs->h_serv, "0123456789") 405 == strlen(args->arg.nd_hs->h_serv)) { 406 *servp = htons(atoi(args->arg.nd_hs->h_serv)); 407 } else { 408 /* i.e. need to call a name service on this */ 409 servp = NULL; 410 } 411 412 /* 413 * If the hostname is HOST_SELF_BIND, we return ipv6 414 * localaddress so the binding can be contacted through 415 * all interfaces. 416 * If the hostname is HOST_SELF_CONNECT, we return 417 * ipv6 loopback address so the address can be connected 418 * to locally. 419 * If the hostname is HOST_ANY, we return no addresses 420 * because IP doesn't know how to specify a service 421 * without a host. 422 * And finally if we specify HOST_BROADCAST then we 423 * disallow since IPV6 does not have any 424 * broadcast concept. 425 */ 426 if (args->arg.nd_hs->h_host == 0) { 427 return (ND_NOHOST); 428 } else if ((strcmp(args->arg.nd_hs->h_host, 429 HOST_SELF_BIND) == 0)) { 430 haddrlist = localaddr6; 431 } else if ((strcmp(args->arg.nd_hs->h_host, 432 HOST_SELF_CONNECT) == 0)) { 433 haddrlist = connectaddr6; 434 } else if ((strcmp(args->arg.nd_hs->h_host, 435 LOCALHOST) == 0)) { 436 haddrlist = connectaddr6; 437 } else if (strchr(args->arg.nd_hs->h_host, ':') 438 != NULL) { 439 440 /* 441 * If the caller passed in a dot separated IP notation 442 * to netdir_getbyname, convert that back into address. 443 */ 444 445 if ((inet_pton(AF_INET6, 446 args->arg.nd_hs->h_host, 447 &v6nameaddr)) != 0) { 448 dotnamelist[0] = (char *)&v6nameaddr; 449 dotnamelist[1] = NULL; 450 haddrlist = dotnamelist; 451 } 452 else 453 /* not sure what to return */ 454 return (ND_NOHOST); 455 456 } else if ((strcmp(args->arg.nd_hs->h_host, 457 HOST_BROADCAST) == 0)) { 458 /* 459 * Don't support broadcast in 460 * IPV6 461 */ 462 return (ND_NOHOST); 463 } else { 464 /* i.e. need to call a name service on this */ 465 haddrlist = 0; 466 } 467 468 if (haddrlist && servp) { 469 int ret; 470 /* 471 * Convert h_addr_list into nd_addrlist. 472 * malloc's will be done, freed 473 * using netdir_free. 474 */ 475 ret = hent2ndaddr(AF_INET6, haddrlist, 476 servp, res->nd_alist); 477 FREE_return(ret); 478 } 479 break; 480 481 482 } 483 484 /* 485 * 2. Most common scenario. This is the way we ship /etc/netconfig. 486 * Emphasis on improving performance in the "if" part. 487 */ 488 if (nconf->nc_nlookups == 0) { 489 struct hostent *he = NULL, *tmphe; 490 struct servent *se; 491 int ret; 492 nss_XbyY_buf_t *ndbuf4switch = 0; 493 494 switch (args->op_t) { 495 496 case NSS_HOST: 497 498 he = DOOR_GETHOSTBYNAME_R(args->arg.nss.host.name, 499 res->nss.host.hent, args->arg.nss.host.buf, 500 args->arg.nss.host.buflen, 501 res->nss.host.herrno_p); 502 if (he == NULL) 503 return (_nderror = ND_NOHOST); 504 return (_nderror = ND_OK); 505 506 case NSS_HOST6: 507 508 he = DOOR_GETIPNODEBYNAME_R(args->arg.nss.host6.name, 509 res->nss.host.hent, args->arg.nss.host.buf, 510 args->arg.nss.host6.buflen, 511 args->arg.nss.host6.af_family, 512 args->arg.nss.host6.flags, 513 res->nss.host.herrno_p); 514 515 if (he == NULL) 516 return (_nderror = ND_NOHOST); 517 return (_nderror = ND_OK); 518 519 case NSS_SERV: 520 521 se = _switch_getservbyname_r(args->arg.nss.serv.name, 522 args->arg.nss.serv.proto, 523 res->nss.serv, args->arg.nss.serv.buf, 524 args->arg.nss.serv.buflen); 525 526 _nderror = ND_OK; 527 if (se == 0) 528 _nderror = ND_NOSERV; 529 return (_nderror); 530 531 case NETDIR_BY: 532 533 if (servp == 0) { 534 char *proto = (strcmp(nconf->nc_proto, 535 NC_TCP) == 0) ? NC_TCP : NC_UDP; 536 537 /* 538 * We go through all this for just one port number, 539 * which is most often constant. How about linking in 540 * an indexed database of well-known ports in the name 541 * of performance ? 542 */ 543 ndbuf4switch = _nss_XbyY_buf_alloc( 544 sizeof (struct servent), NSS_BUFLEN_SERVICES); 545 if (ndbuf4switch == 0) 546 FREE_return(ND_NOMEM); 547 se = _switch_getservbyname_r(args->arg.nd_hs->h_serv, 548 proto, ndbuf4switch->result, 549 ndbuf4switch->buffer, ndbuf4switch->buflen); 550 if (!se) { 551 NSS_XbyY_FREE(&ndbuf4switch); 552 FREE_return(ND_NOSERV); 553 } 554 server_port = se->s_port; 555 NSS_XbyY_FREE(&ndbuf4switch); 556 } 557 558 if (haddrlist == 0) { 559 int h_errnop = 0; 560 561 ndbuf4switch = _nss_XbyY_buf_alloc( 562 sizeof (struct hostent), 563 NSS_BUFLEN_HOSTS); 564 if (ndbuf4switch == 0) { 565 _nderror = ND_NOMEM; 566 return (ND_NOMEM); 567 } 568 /* 569 * Search the ipnodes (v6) path first, 570 * search will return the v4 addresses 571 * as v4mapped addresses. 572 */ 573 if ((tmphe = DOOR_GETIPNODEBYNAME_R( 574 args->arg.nd_hs->h_host, 575 ndbuf4switch->result, ndbuf4switch->buffer, 576 ndbuf4switch->buflen, args->arg.nss.host6.af_family, 577 args->arg.nss.host6.flags, &h_errnop)) != NULL) 578 he = __mappedtov4(tmphe, &h_errnop); 579 580 if (he == NULL) { 581 /* Failover case, try hosts db for v4 address */ 582 he = DOOR_GETHOSTBYNAME_R( 583 args->arg.nd_hs->h_host, 584 ndbuf4switch->result, ndbuf4switch->buffer, 585 ndbuf4switch->buflen, &h_errnop); 586 if (he == NULL) { 587 NSS_XbyY_FREE(&ndbuf4switch); 588 _nderror = h_errnop ? 589 __herrno2netdir(h_errnop) : 590 ND_NOHOST; 591 return (_nderror); 592 } 593 /* 594 * Convert h_addr_list into nd_addrlist. 595 * malloc's will be done, freed using 596 * netdir_free. 597 */ 598 ret = hent2ndaddr(AF_INET, he->h_addr_list, 599 &server_port, res->nd_alist); 600 } else { 601 /* 602 * Convert h_addr_list into nd_addrlist. 603 * malloc's will be done, freed using 604 * netdir_free. 605 */ 606 ret = hent2ndaddr(AF_INET, he->h_addr_list, 607 &server_port, res->nd_alist); 608 freehostent(he); 609 } 610 611 _nderror = ret; 612 NSS_XbyY_FREE(&ndbuf4switch); 613 return (ret); 614 } else { 615 int ret; 616 /* 617 * Convert h_addr_list into nd_addrlist. 618 * malloc's will be done, freed using netdir_free. 619 */ 620 ret = hent2ndaddr(AF_INET, haddrlist, 621 &server_port, res->nd_alist); 622 FREE_return(ret); 623 } 624 625 626 case NETDIR_BY6: 627 628 if (servp == 0) { 629 char *proto = (strcmp(nconf->nc_proto, 630 NC_TCP) == 0) ? NC_TCP : NC_UDP; 631 632 /* 633 * We go through all this for just 634 * one port number, 635 * which is most often constant. 636 * How about linking in 637 * an indexed database of well-known 638 * ports in the name 639 * of performance ? 640 */ 641 ndbuf4switch = _nss_XbyY_buf_alloc( 642 sizeof (struct servent), 643 NSS_BUFLEN_SERVICES); 644 if (ndbuf4switch == 0) 645 FREE_return(ND_NOMEM); 646 se = _switch_getservbyname_r( 647 args->arg.nd_hs->h_serv, 648 proto, ndbuf4switch->result, 649 ndbuf4switch->buffer, ndbuf4switch->buflen); 650 if (!se) { 651 NSS_XbyY_FREE(&ndbuf4switch); 652 FREE_return(ND_NOSERV); 653 } 654 server_port = se->s_port; 655 NSS_XbyY_FREE(&ndbuf4switch); 656 } 657 658 if (haddrlist == 0) { 659 int h_errnop = 0; 660 661 ndbuf4switch = _nss_XbyY_buf_alloc( 662 sizeof (struct hostent), 663 NSS_BUFLEN_HOSTS); 664 if (ndbuf4switch == 0) { 665 _nderror = ND_NOMEM; 666 return (ND_NOMEM); 667 } 668 he = DOOR_GETIPNODEBYNAME_R( 669 args->arg.nd_hs->h_host, 670 ndbuf4switch->result, ndbuf4switch->buffer, 671 ndbuf4switch->buflen, 672 args->arg.nss.host6.af_family, 673 args->arg.nss.host6.flags, &h_errnop); 674 if (he == NULL) { 675 NSS_XbyY_FREE(&ndbuf4switch); 676 _nderror = h_errnop ? 677 __herrno2netdir(h_errnop) : 678 ND_NOHOST; 679 return (_nderror); 680 } 681 /* 682 * Convert h_addr_list into nd_addrlist. 683 * malloc's will be done, 684 * freed using netdir_free. 685 */ 686 ret = hent2ndaddr(AF_INET6, 687 ((struct hostent *) 688 (ndbuf4switch->result))->h_addr_list, 689 &server_port, res->nd_alist); 690 _nderror = ret; 691 NSS_XbyY_FREE(&ndbuf4switch); 692 return (ret); 693 } else { 694 int ret; 695 /* 696 * Convert h_addr_list into nd_addrlist. 697 * malloc's will be done, 698 * freed using netdir_free. 699 */ 700 ret = hent2ndaddr(AF_INET6, haddrlist, 701 &server_port, res->nd_alist); 702 FREE_return(ret); 703 } 704 705 default: 706 _nderror = ND_BADARG; 707 return (ND_BADARG); /* should never happen */ 708 } 709 710 } else { 711 /* haddrlist is no longer used, so clean up */ 712 if (inaddrs) 713 free(inaddrs); 714 if (baddrlist) 715 free(baddrlist); 716 } 717 718 /* 719 * 3. We come this far only if nametoaddr libs are specified for 720 * inet transports and we are called by gethost/servbyname only. 721 */ 722 switch (args->op_t) { 723 struct nd_hostserv service; 724 struct nd_addrlist *addrs; 725 int ret; 726 727 case NSS_HOST: 728 729 service.h_host = (char *)args->arg.nss.host.name; 730 service.h_serv = NULL; 731 if ((_nderror = __classic_netdir_getbyname(nconf, 732 &service, &addrs)) != ND_OK) { 733 *(res->nss.host.herrno_p) = nd2herrno(_nderror); 734 return (_nderror); 735 } 736 /* 737 * convert addresses back into sockaddr for gethostbyname. 738 */ 739 ret = ndaddr2hent(AF_INET, service.h_host, addrs, 740 res->nss.host.hent, args->arg.nss.host.buf, 741 args->arg.nss.host.buflen); 742 if (ret != ND_OK) 743 *(res->nss.host.herrno_p) = nd2herrno(ret); 744 netdir_free((char *)addrs, ND_ADDRLIST); 745 _nderror = ret; 746 return (ret); 747 748 case NSS_SERV: 749 750 if (args->arg.nss.serv.proto == NULL) { 751 /* 752 * A similar HACK showed up in Solaris 2.3. 753 * The caller wild-carded proto -- i.e. will 754 * accept a match using tcp or udp for the port 755 * number. Since we have no hope of getting 756 * directly to a name service switch backend 757 * from here that understands this semantics, 758 * we try calling the netdir interfaces first 759 * with "tcp" and then "udp". 760 */ 761 args->arg.nss.serv.proto = "tcp"; 762 _nderror = _get_hostserv_inetnetdir_byname(nconf, args, 763 res); 764 if (_nderror != ND_OK) { 765 args->arg.nss.serv.proto = "udp"; 766 _nderror = 767 _get_hostserv_inetnetdir_byname(nconf, 768 args, res); 769 } 770 return (_nderror); 771 } 772 773 /* 774 * Third-parties should optimize their nametoaddr 775 * libraries for the HOST_SELF case. 776 */ 777 service.h_host = HOST_SELF; 778 service.h_serv = (char *)args->arg.nss.serv.name; 779 if ((_nderror = __classic_netdir_getbyname(nconf, 780 &service, &addrs)) != ND_OK) { 781 return (_nderror); 782 } 783 /* 784 * convert addresses back into servent for getservbyname. 785 */ 786 _nderror = ndaddr2srent(service.h_serv, 787 args->arg.nss.serv.proto, 788 /* LINTED pointer cast */ 789 ((struct sockaddr_in *)addrs->n_addrs->buf)->sin_port, 790 res->nss.serv, 791 args->arg.nss.serv.buf, args->arg.nss.serv.buflen); 792 netdir_free((char *)addrs, ND_ADDRLIST); 793 return (_nderror); 794 795 default: 796 _nderror = ND_BADARG; 797 return (ND_BADARG); /* should never happen */ 798 } 799 } 800 801 /* 802 * gethostbyaddr/servbyport always call this function; if they call 803 * with nametoaddr libs in nconf, we call netdir_getbyaddr 804 * implementation __classic_netdir_getbyaddr, otherwise nsswitch. 805 * 806 * netdir_getbyaddr calls this only if nametoaddr libs are NOT 807 * specified for inet transports; i.e. it's supposed to follow 808 * the name service switch. 809 */ 810 int 811 _get_hostserv_inetnetdir_byaddr(struct netconfig *nconf, 812 struct nss_netdirbyaddr_in *args, union nss_netdirbyaddr_out *res) 813 { 814 if (nconf == 0) { 815 _nderror = ND_BADARG; 816 return (_nderror); 817 } 818 819 /* 820 * 1. gethostbyaddr()/netdir_getbyaddr() special cases: 821 */ 822 switch (args->op_t) { 823 824 case NSS_HOST: 825 /* 826 * Worth the performance gain: assuming a lot of inet apps 827 * actively use "127.0.0.1". 828 */ 829 /* LINTED pointer cast */ 830 if (*(uint32_t *)(args->arg.nss.host.addr) == 831 htonl(INADDR_LOOPBACK)) { 832 (void) mutex_lock(&nd_addr_lock); 833 IN_SET_LOOPBACK_ADDR(&sa_con); 834 _nderror = ndaddr2hent(AF_INET, LOCALHOST, 835 &nd_conaddrlist, res->nss.host.hent, 836 args->arg.nss.host.buf, 837 args->arg.nss.host.buflen); 838 (void) mutex_unlock(&nd_addr_lock); 839 if (_nderror != ND_OK) 840 *(res->nss.host.herrno_p) = 841 nd2herrno(_nderror); 842 return (_nderror); 843 } 844 break; 845 846 case NETDIR_BY: 847 case NETDIR_BY_NOSRV: 848 { 849 struct sockaddr_in *sin; 850 851 if (args->arg.nd_nbuf == NULL) { 852 _nderror = ND_BADARG; 853 return (_nderror); 854 } 855 856 /* 857 * Validate the address which was passed 858 * as the request. 859 */ 860 /* LINTED pointer cast */ 861 sin = (struct sockaddr_in *)args->arg.nd_nbuf->buf; 862 863 if ((args->arg.nd_nbuf->len != 864 sizeof (struct sockaddr_in)) || 865 (sin->sin_family != AF_INET)) { 866 _nderror = ND_BADARG; 867 return (_nderror); 868 } 869 } 870 break; 871 872 case NETDIR_BY6: 873 case NETDIR_BY_NOSRV6: 874 { 875 struct sockaddr_in6 *sin6; 876 877 if (args->arg.nd_nbuf == NULL) { 878 _nderror = ND_BADARG; 879 return (_nderror); 880 } 881 882 /* 883 * Validate the address which was passed 884 * as the request. 885 */ 886 /* LINTED pointer cast */ 887 sin6 = (struct sockaddr_in6 *)args->arg.nd_nbuf->buf; 888 889 if ((args->arg.nd_nbuf->len != 890 sizeof (struct sockaddr_in6)) || 891 (sin6->sin6_family != AF_INET6)) { 892 _nderror = ND_BADARG; 893 return (_nderror); 894 } 895 } 896 break; 897 898 } 899 900 /* 901 * 2. Most common scenario. This is the way we ship /etc/netconfig. 902 * Emphasis on improving performance in the "if" part. 903 */ 904 if (nconf->nc_nlookups == 0) { 905 struct hostent *he = NULL, *tmphe; 906 struct servent *se = NULL; 907 nss_XbyY_buf_t *ndbuf4host = 0; 908 nss_XbyY_buf_t *ndbuf4serv = 0; 909 char *proto = 910 (strcmp(nconf->nc_proto, NC_TCP) == 0) ? NC_TCP : NC_UDP; 911 struct sockaddr_in *sa; 912 struct sockaddr_in6 *sin6; 913 struct in_addr *addr4 = 0; 914 struct in6_addr v4mapbuf; 915 int h_errnop; 916 917 switch (args->op_t) { 918 919 case NSS_HOST: 920 921 he = DOOR_GETHOSTBYADDR_R(args->arg.nss.host.addr, 922 args->arg.nss.host.len, args->arg.nss.host.type, 923 res->nss.host.hent, args->arg.nss.host.buf, 924 args->arg.nss.host.buflen, 925 res->nss.host.herrno_p); 926 if (he == 0) 927 _nderror = ND_NOHOST; 928 else 929 _nderror = ND_OK; 930 return (_nderror); 931 932 933 case NSS_HOST6: 934 he = DOOR_GETIPNODEBYADDR_R(args->arg.nss.host.addr, 935 args->arg.nss.host.len, args->arg.nss.host.type, 936 res->nss.host.hent, args->arg.nss.host.buf, 937 args->arg.nss.host.buflen, 938 res->nss.host.herrno_p); 939 940 if (he == 0) 941 return (ND_NOHOST); 942 return (ND_OK); 943 944 945 case NSS_SERV: 946 947 se = _switch_getservbyport_r(args->arg.nss.serv.port, 948 args->arg.nss.serv.proto, 949 res->nss.serv, args->arg.nss.serv.buf, 950 args->arg.nss.serv.buflen); 951 952 if (se == 0) 953 _nderror = ND_NOSERV; 954 else 955 _nderror = ND_OK; 956 return (_nderror); 957 958 case NETDIR_BY: 959 case NETDIR_BY_NOSRV: 960 961 ndbuf4serv = _nss_XbyY_buf_alloc(sizeof (struct servent), 962 NSS_BUFLEN_SERVICES); 963 if (ndbuf4serv == 0) { 964 _nderror = ND_NOMEM; 965 return (_nderror); 966 } 967 /* LINTED pointer cast */ 968 sa = (struct sockaddr_in *)(args->arg.nd_nbuf->buf); 969 addr4 = (struct in_addr *)&(sa->sin_addr); 970 971 /* 972 * if NETDIR_BY_NOSRV or port == 0 skip the service 973 * lookup. 974 */ 975 if (args->op_t != NETDIR_BY_NOSRV && sa->sin_port != 0) { 976 se = _switch_getservbyport_r(sa->sin_port, proto, 977 ndbuf4serv->result, ndbuf4serv->buffer, 978 ndbuf4serv->buflen); 979 if (!se) { 980 NSS_XbyY_FREE(&ndbuf4serv); 981 /* 982 * We can live with this - i.e. the address 983 * does not 984 * belong to a well known service. The caller 985 * traditionally accepts a stringified port 986 * number 987 * as the service name. The state of se is used 988 * ahead to indicate the same. 989 * However, we do not tolerate this nonsense 990 * when we cannot get a host name. See below. 991 */ 992 } 993 } 994 995 ndbuf4host = _nss_XbyY_buf_alloc(sizeof (struct hostent), 996 NSS_BUFLEN_HOSTS); 997 if (ndbuf4host == 0) { 998 if (ndbuf4serv) 999 NSS_XbyY_FREE(&ndbuf4serv); 1000 _nderror = ND_NOMEM; 1001 return (_nderror); 1002 } 1003 1004 /* 1005 * Since we're going to search the ipnodes (v6) path first, 1006 * we need to treat the address as a v4mapped address. 1007 */ 1008 1009 IN6_INADDR_TO_V4MAPPED(addr4, &v4mapbuf); 1010 if ((tmphe = DOOR_GETIPNODEBYADDR_R((char *)&v4mapbuf, 1011 16, AF_INET6, ndbuf4host->result, 1012 ndbuf4host->buffer, 1013 ndbuf4host->buflen, &h_errnop)) != NULL) 1014 he = __mappedtov4(tmphe, &h_errnop); 1015 1016 if (!he) { 1017 /* Failover case, try hosts db for v4 address */ 1018 he = DOOR_GETHOSTBYADDR_R((char *) 1019 &(sa->sin_addr.s_addr), 4, 1020 sa->sin_family, ndbuf4host->result, 1021 ndbuf4host->buffer, ndbuf4host->buflen, 1022 &h_errnop); 1023 if (!he) { 1024 NSS_XbyY_FREE(&ndbuf4host); 1025 if (ndbuf4serv) 1026 NSS_XbyY_FREE(&ndbuf4serv); 1027 _nderror = __herrno2netdir(h_errnop); 1028 return (_nderror); 1029 } 1030 /* 1031 * Convert host names and service names into hostserv 1032 * pairs. malloc's will be done, freed using 1033 * netdir_free. 1034 */ 1035 h_errnop = hsents2ndhostservs(he, se, 1036 sa->sin_port, res->nd_hslist); 1037 } else { 1038 /* 1039 * Convert host names and service names into hostserv 1040 * pairs. malloc's will be done, freed using 1041 * netdir_free. 1042 */ 1043 h_errnop = hsents2ndhostservs(he, se, 1044 sa->sin_port, res->nd_hslist); 1045 freehostent(he); 1046 } 1047 1048 NSS_XbyY_FREE(&ndbuf4host); 1049 if (ndbuf4serv) 1050 NSS_XbyY_FREE(&ndbuf4serv); 1051 _nderror = __herrno2netdir(h_errnop); 1052 return (_nderror); 1053 1054 case NETDIR_BY6: 1055 case NETDIR_BY_NOSRV6: 1056 1057 ndbuf4serv = _nss_XbyY_buf_alloc(sizeof (struct servent), 1058 NSS_BUFLEN_SERVICES); 1059 if (ndbuf4serv == 0) { 1060 _nderror = ND_NOMEM; 1061 return (ND_NOMEM); 1062 } 1063 /* LINTED pointer cast */ 1064 sin6 = (struct sockaddr_in6 *)(args->arg.nd_nbuf->buf); 1065 1066 /* 1067 * if NETDIR_BY_NOSRV6 or port == 0 skip the service 1068 * lookup. 1069 */ 1070 if (args->op_t != NETDIR_BY_NOSRV6 && sin6->sin6_port == 0) { 1071 se = _switch_getservbyport_r(sin6->sin6_port, proto, 1072 ndbuf4serv->result, ndbuf4serv->buffer, 1073 ndbuf4serv->buflen); 1074 if (!se) { 1075 NSS_XbyY_FREE(&ndbuf4serv); 1076 /* 1077 * We can live with this - i.e. the address does 1078 * not * belong to a well known service. The 1079 * caller traditionally accepts a stringified 1080 * port number 1081 * as the service name. The state of se is used 1082 * ahead to indicate the same. 1083 * However, we do not tolerate this nonsense 1084 * when we cannot get a host name. See below. 1085 */ 1086 } 1087 } 1088 1089 ndbuf4host = _nss_XbyY_buf_alloc(sizeof (struct hostent), 1090 NSS_BUFLEN_HOSTS); 1091 if (ndbuf4host == 0) { 1092 if (ndbuf4serv) 1093 NSS_XbyY_FREE(&ndbuf4serv); 1094 _nderror = ND_NOMEM; 1095 return (_nderror); 1096 } 1097 he = DOOR_GETIPNODEBYADDR_R((char *)&(sin6->sin6_addr), 1098 16, sin6->sin6_family, ndbuf4host->result, 1099 ndbuf4host->buffer, 1100 ndbuf4host->buflen, &h_errnop); 1101 if (!he) { 1102 NSS_XbyY_FREE(&ndbuf4host); 1103 if (ndbuf4serv) 1104 NSS_XbyY_FREE(&ndbuf4serv); 1105 _nderror = __herrno2netdir(h_errnop); 1106 return (_nderror); 1107 } 1108 /* 1109 * Convert host names and service names into hostserv 1110 * pairs. malloc's will be done, freed using netdir_free. 1111 */ 1112 h_errnop = hsents2ndhostservs(he, se, 1113 sin6->sin6_port, res->nd_hslist); 1114 1115 NSS_XbyY_FREE(&ndbuf4host); 1116 if (ndbuf4serv) 1117 NSS_XbyY_FREE(&ndbuf4serv); 1118 _nderror = __herrno2netdir(h_errnop); 1119 return (_nderror); 1120 1121 default: 1122 _nderror = ND_BADARG; 1123 return (_nderror); /* should never happen */ 1124 } 1125 1126 } 1127 /* 1128 * 3. We come this far only if nametoaddr libs are specified for 1129 * inet transports and we are called by gethost/servbyname only. 1130 */ 1131 switch (args->op_t) { 1132 struct netbuf nbuf; 1133 struct nd_hostservlist *addrs; 1134 struct sockaddr_in sa; 1135 1136 case NSS_HOST: 1137 1138 /* LINTED pointer cast */ 1139 sa.sin_addr.s_addr = *(uint32_t *)args->arg.nss.host.addr; 1140 sa.sin_family = AF_INET; 1141 /* Hopefully, third-parties get this optimization */ 1142 sa.sin_port = 0; 1143 nbuf.buf = (char *)&sa; 1144 nbuf.len = nbuf.maxlen = sizeof (sa); 1145 if ((_nderror = __classic_netdir_getbyaddr(nconf, 1146 &addrs, &nbuf)) != 0) { 1147 *(res->nss.host.herrno_p) = nd2herrno(_nderror); 1148 return (_nderror); 1149 } 1150 /* 1151 * convert the host-serv pairs into h_aliases and hent. 1152 */ 1153 _nderror = ndhostserv2hent(&nbuf, addrs, res->nss.host.hent, 1154 args->arg.nss.host.buf, args->arg.nss.host.buflen); 1155 if (_nderror != ND_OK) 1156 *(res->nss.host.herrno_p) = nd2herrno(_nderror); 1157 netdir_free((char *)addrs, ND_HOSTSERVLIST); 1158 return (_nderror); 1159 1160 case NSS_SERV: 1161 1162 if (args->arg.nss.serv.proto == NULL) { 1163 /* 1164 * A similar HACK showed up in Solaris 2.3. 1165 * The caller wild-carded proto -- i.e. will 1166 * accept a match on tcp or udp for the port 1167 * number. Since we have no hope of getting 1168 * directly to a name service switch backend 1169 * from here that understands this semantics, 1170 * we try calling the netdir interfaces first 1171 * with "tcp" and then "udp". 1172 */ 1173 args->arg.nss.serv.proto = "tcp"; 1174 _nderror = _get_hostserv_inetnetdir_byaddr(nconf, args, 1175 res); 1176 if (_nderror != ND_OK) { 1177 args->arg.nss.serv.proto = "udp"; 1178 _nderror = 1179 _get_hostserv_inetnetdir_byaddr(nconf, 1180 args, res); 1181 } 1182 return (_nderror); 1183 } 1184 1185 /* 1186 * Third-party nametoaddr_libs should be optimized for 1187 * this case. It also gives a special semantics twist to 1188 * netdir_getbyaddr. Only for the INADDR_ANY case, it gives 1189 * higher priority to service lookups (over host lookups). 1190 * If service lookup fails, the backend returns ND_NOSERV to 1191 * facilitate lookup in the "next" naming service. 1192 * BugId: 1075403. 1193 */ 1194 sa.sin_addr.s_addr = INADDR_ANY; 1195 sa.sin_family = AF_INET; 1196 sa.sin_port = (ushort_t)args->arg.nss.serv.port; 1197 sa.sin_zero[0] = '\0'; 1198 nbuf.buf = (char *)&sa; 1199 nbuf.len = nbuf.maxlen = sizeof (sa); 1200 if ((_nderror = __classic_netdir_getbyaddr(nconf, 1201 &addrs, &nbuf)) != ND_OK) { 1202 return (_nderror); 1203 } 1204 /* 1205 * convert the host-serv pairs into s_aliases and servent. 1206 */ 1207 _nderror = ndhostserv2srent(args->arg.nss.serv.port, 1208 args->arg.nss.serv.proto, addrs, res->nss.serv, 1209 args->arg.nss.serv.buf, args->arg.nss.serv.buflen); 1210 netdir_free((char *)addrs, ND_HOSTSERVLIST); 1211 return (_nderror); 1212 1213 default: 1214 _nderror = ND_BADARG; 1215 return (_nderror); /* should never happen */ 1216 } 1217 } 1218 1219 /* 1220 * Part II: Name Service Switch interfacing routines. 1221 */ 1222 1223 static DEFINE_NSS_DB_ROOT(db_root_hosts); 1224 static DEFINE_NSS_DB_ROOT(db_root_ipnodes); 1225 static DEFINE_NSS_DB_ROOT(db_root_services); 1226 1227 1228 /* 1229 * There is a copy of __nss2herrno() in nsswitch/files/gethostent.c. 1230 * It is there because /etc/lib/nss_files.so.1 cannot call 1231 * routines in libnsl. Care should be taken to keep the two copies 1232 * in sync (except that case NSS_NISSERVDNS_TRYAGAIN is not needed in 1233 * nsswitch/files). 1234 */ 1235 int 1236 __nss2herrno(nss_status_t nsstat) 1237 { 1238 switch (nsstat) { 1239 case NSS_SUCCESS: 1240 /* no macro-defined success code for h_errno */ 1241 return (0); 1242 case NSS_NOTFOUND: 1243 return (HOST_NOT_FOUND); 1244 case NSS_TRYAGAIN: 1245 return (TRY_AGAIN); 1246 case NSS_UNAVAIL: 1247 return (NO_RECOVERY); 1248 case NSS_NISSERVDNS_TRYAGAIN: 1249 return (TRY_AGAIN); 1250 } 1251 /* anything else */ 1252 return (NO_RECOVERY); 1253 } 1254 1255 nss_status_t 1256 _herrno2nss(int h_errno) 1257 { 1258 switch (h_errno) { 1259 case 0: 1260 return (NSS_SUCCESS); 1261 case TRY_AGAIN: 1262 return (NSS_TRYAGAIN); 1263 case NO_RECOVERY: 1264 case NETDB_INTERNAL: 1265 return (NSS_UNAVAIL); 1266 case HOST_NOT_FOUND: 1267 case NO_DATA: 1268 default: 1269 return (NSS_NOTFOUND); 1270 } 1271 } 1272 1273 static int 1274 __herrno2netdir(int h_errnop) 1275 { 1276 switch (h_errnop) { 1277 case 0: 1278 return (ND_OK); 1279 case HOST_NOT_FOUND: 1280 return (ND_NOHOST); 1281 case TRY_AGAIN: 1282 return (ND_TRY_AGAIN); 1283 case NO_RECOVERY: 1284 case NETDB_INTERNAL: 1285 return (ND_NO_RECOVERY); 1286 case NO_DATA: 1287 return (ND_NO_DATA); 1288 default: 1289 return (ND_NOHOST); 1290 } 1291 } 1292 1293 /* 1294 * The _switch_getXXbyYY_r() routines should be static. They used to 1295 * be exported in SunOS 5.3, and in fact publicised as work-around 1296 * interfaces for getting CNAME/aliases, and therefore, we preserve 1297 * their signatures here. Just in case. 1298 */ 1299 1300 struct hostent * 1301 _switch_gethostbyname_r(const char *name, struct hostent *result, char *buffer, 1302 int buflen, int *h_errnop) 1303 { 1304 nss_XbyY_args_t arg; 1305 nss_status_t res; 1306 1307 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent); 1308 arg.key.name = name; 1309 arg.stayopen = 0; 1310 res = nss_search(&db_root_hosts, _nss_initf_hosts, 1311 NSS_DBOP_HOSTS_BYNAME, &arg); 1312 arg.status = res; 1313 *h_errnop = arg.h_errno; 1314 if (arg.returnval != NULL) 1315 order_haddrlist_af(result->h_addrtype, result->h_addr_list); 1316 return ((struct hostent *)NSS_XbyY_FINI(&arg)); 1317 } 1318 1319 struct hostent * 1320 _switch_getipnodebyname_r(const char *name, struct hostent *result, 1321 char *buffer, int buflen, int af_family, int flags, int *h_errnop) 1322 { 1323 nss_XbyY_args_t arg; 1324 nss_status_t res; 1325 1326 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent6); 1327 arg.key.ipnode.name = name; 1328 arg.key.ipnode.af_family = af_family; 1329 arg.key.ipnode.flags = flags; 1330 arg.stayopen = 0; 1331 res = nss_search(&db_root_ipnodes, _nss_initf_ipnodes, 1332 NSS_DBOP_IPNODES_BYNAME, &arg); 1333 arg.status = res; 1334 *h_errnop = arg.h_errno; 1335 if (arg.returnval != NULL) 1336 order_haddrlist_af(result->h_addrtype, result->h_addr_list); 1337 return ((struct hostent *)NSS_XbyY_FINI(&arg)); 1338 } 1339 1340 struct hostent * 1341 _switch_gethostbyaddr_r(const char *addr, int len, int type, 1342 struct hostent *result, char *buffer, int buflen, int *h_errnop) 1343 { 1344 nss_XbyY_args_t arg; 1345 nss_status_t res; 1346 1347 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent); 1348 arg.key.hostaddr.addr = addr; 1349 arg.key.hostaddr.len = len; 1350 arg.key.hostaddr.type = type; 1351 arg.stayopen = 0; 1352 res = nss_search(&db_root_hosts, _nss_initf_hosts, 1353 NSS_DBOP_HOSTS_BYADDR, &arg); 1354 arg.status = res; 1355 *h_errnop = arg.h_errno; 1356 return (struct hostent *)NSS_XbyY_FINI(&arg); 1357 } 1358 1359 struct hostent * 1360 _switch_getipnodebyaddr_r(const char *addr, int len, int type, 1361 struct hostent *result, char *buffer, int buflen, int *h_errnop) 1362 { 1363 nss_XbyY_args_t arg; 1364 nss_status_t res; 1365 1366 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent6); 1367 arg.key.hostaddr.addr = addr; 1368 arg.key.hostaddr.len = len; 1369 arg.key.hostaddr.type = type; 1370 arg.stayopen = 0; 1371 res = nss_search(&db_root_ipnodes, _nss_initf_ipnodes, 1372 NSS_DBOP_IPNODES_BYADDR, &arg); 1373 arg.status = res; 1374 *h_errnop = arg.h_errno; 1375 return (struct hostent *)NSS_XbyY_FINI(&arg); 1376 } 1377 1378 static void 1379 _nss_initf_services(nss_db_params_t *p) 1380 { 1381 p->name = NSS_DBNAM_SERVICES; 1382 p->default_config = NSS_DEFCONF_SERVICES; 1383 } 1384 1385 struct servent * 1386 _switch_getservbyname_r(const char *name, const char *proto, 1387 struct servent *result, char *buffer, int buflen) 1388 { 1389 nss_XbyY_args_t arg; 1390 nss_status_t res; 1391 1392 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2servent); 1393 arg.key.serv.serv.name = name; 1394 arg.key.serv.proto = proto; 1395 arg.stayopen = 0; 1396 res = nss_search(&db_root_services, _nss_initf_services, 1397 NSS_DBOP_SERVICES_BYNAME, &arg); 1398 arg.status = res; 1399 return ((struct servent *)NSS_XbyY_FINI(&arg)); 1400 } 1401 1402 struct servent * 1403 _switch_getservbyport_r(int port, const char *proto, struct servent *result, 1404 char *buffer, int buflen) 1405 { 1406 nss_XbyY_args_t arg; 1407 nss_status_t res; 1408 1409 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2servent); 1410 arg.key.serv.serv.port = port; 1411 arg.key.serv.proto = proto; 1412 arg.stayopen = 0; 1413 res = nss_search(&db_root_services, _nss_initf_services, 1414 NSS_DBOP_SERVICES_BYPORT, &arg); 1415 arg.status = res; 1416 return ((struct servent *)NSS_XbyY_FINI(&arg)); 1417 } 1418 1419 1420 /* 1421 * Return values: 0 = success, 1 = parse error, 2 = erange ... 1422 * The structure pointer passed in is a structure in the caller's space 1423 * wherein the field pointers would be set to areas in the buffer if 1424 * need be. instring and buffer should be separate areas. 1425 * 1426 * Defined here because we need it and we (libnsl) cannot have a dependency 1427 * on libsocket (however, libsocket always depends on libnsl). 1428 */ 1429 int 1430 str2servent(const char *instr, int lenstr, void *ent, char *buffer, int buflen) 1431 { 1432 struct servent *serv = (struct servent *)ent; 1433 const char *p, *fieldstart, *limit, *namestart; 1434 ssize_t fieldlen, namelen = 0; 1435 char numbuf[12]; 1436 char *numend; 1437 1438 if ((instr >= buffer && (buffer + buflen) > instr) || 1439 (buffer >= instr && (instr + lenstr) > buffer)) { 1440 return (NSS_STR_PARSE_PARSE); 1441 } 1442 1443 p = instr; 1444 limit = p + lenstr; 1445 1446 while (p < limit && isspace(*p)) { 1447 p++; 1448 } 1449 namestart = p; 1450 while (p < limit && !isspace(*p)) { 1451 p++; /* Skip over the canonical name */ 1452 } 1453 namelen = p - namestart; 1454 1455 if (buflen <= namelen) { /* not enough buffer */ 1456 return (NSS_STR_PARSE_ERANGE); 1457 } 1458 (void) memcpy(buffer, namestart, namelen); 1459 buffer[namelen] = '\0'; 1460 serv->s_name = buffer; 1461 1462 while (p < limit && isspace(*p)) { 1463 p++; 1464 } 1465 1466 fieldstart = p; 1467 do { 1468 if (p > limit || isspace(*p)) { 1469 /* Syntax error -- no port/proto */ 1470 return (NSS_STR_PARSE_PARSE); 1471 } 1472 } while (*p++ != '/'); 1473 fieldlen = p - fieldstart - 1; 1474 if (fieldlen == 0 || fieldlen >= sizeof (numbuf)) { 1475 /* Syntax error -- supposed number is empty or too long */ 1476 return (NSS_STR_PARSE_PARSE); 1477 } 1478 (void) memcpy(numbuf, fieldstart, fieldlen); 1479 numbuf[fieldlen] = '\0'; 1480 serv->s_port = htons((int)strtol(numbuf, &numend, 10)); 1481 if (*numend != '\0') { 1482 /* Syntax error -- port number isn't a number */ 1483 return (NSS_STR_PARSE_PARSE); 1484 } 1485 1486 fieldstart = p; 1487 while (p < limit && !isspace(*p)) { 1488 p++; /* Scan the protocol name */ 1489 } 1490 fieldlen = p - fieldstart + 1; /* Include '\0' this time */ 1491 if (fieldlen > buflen - namelen - 1) { 1492 return (NSS_STR_PARSE_ERANGE); 1493 } 1494 serv->s_proto = buffer + namelen + 1; 1495 (void) memcpy(serv->s_proto, fieldstart, fieldlen - 1); 1496 serv->s_proto[fieldlen - 1] = '\0'; 1497 1498 while (p < limit && isspace(*p)) { 1499 p++; 1500 } 1501 /* 1502 * Although nss_files_XY_all calls us with # stripped, 1503 * we should be able to deal with it here in order to 1504 * be more useful. 1505 */ 1506 if (p >= limit || *p == '#') { /* no aliases, no problem */ 1507 char **ptr; 1508 1509 ptr = (char **)ROUND_UP(buffer + namelen + 1 + fieldlen, 1510 sizeof (char *)); 1511 if ((char *)ptr >= buffer + buflen) { 1512 /* hope they don't try to peek in */ 1513 serv->s_aliases = 0; 1514 return (NSS_STR_PARSE_ERANGE); 1515 } else { 1516 *ptr = 0; 1517 serv->s_aliases = ptr; 1518 return (NSS_STR_PARSE_SUCCESS); 1519 } 1520 } 1521 serv->s_aliases = _nss_netdb_aliases(p, (int)(lenstr - (p - instr)), 1522 buffer + namelen + 1 + fieldlen, 1523 (int)(buflen - namelen - 1 - fieldlen)); 1524 return (NSS_STR_PARSE_SUCCESS); 1525 } 1526 1527 /* 1528 * Part III: All `n sundry routines that are useful only in this 1529 * module. In the interest of keeping this source file shorter, 1530 * we would create them a new module only if the linker allowed 1531 * "library-static" functions. 1532 * 1533 * Routines to order addresses based on local interfaces and netmasks, 1534 * to get and check reserved ports, and to get broadcast nets. 1535 */ 1536 1537 union __v4v6addr { 1538 struct in6_addr in6; 1539 struct in_addr in4; 1540 }; 1541 1542 struct __ifaddr { 1543 sa_family_t af; 1544 union __v4v6addr addr; 1545 union __v4v6addr mask; 1546 }; 1547 1548 struct ifinfo { 1549 int count; 1550 struct __ifaddr *addresses; 1551 }; 1552 1553 typedef enum {ADDR_ONLINK = 0, ADDR_OFFLINK} addr_class_t; 1554 #define ADDR_NUMCLASSES 2 1555 1556 typedef enum {IF_ADDR, IF_MASK} __ifaddr_type; 1557 static int __inet_ifassign(sa_family_t, struct __ifaddr *, __ifaddr_type, 1558 void *); 1559 int __inet_address_is_local_af(void *, sa_family_t, void *); 1560 1561 #define ifaf(index) (localinfo->addresses[index].af) 1562 #define ifaddr4(index) (localinfo->addresses[index].addr.in4) 1563 #define ifaddr6(index) (localinfo->addresses[index].addr.in6) 1564 #define ifmask4(index) (localinfo->addresses[index].mask.in4) 1565 #define ifmask6(index) (localinfo->addresses[index].mask.in6) 1566 #define ifinfosize(n) (sizeof (struct ifinfo) + (n)*sizeof (struct __ifaddr)) 1567 1568 #define lifraddrp(lifr) ((lifr.lifr_addr.ss_family == AF_INET6) ? \ 1569 (void *)&((struct sockaddr_in6 *)&lifr.lifr_addr)->sin6_addr : \ 1570 (void *)&((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr) 1571 1572 #define ifassign(lifr, index, type) \ 1573 __inet_ifassign(lifr.lifr_addr.ss_family, \ 1574 &localinfo->addresses[index], type, \ 1575 lifraddrp(lifr)) 1576 1577 /* 1578 * The number of nanoseconds the order_haddrlist_inet() function waits 1579 * to retreive IP interface information. The default is five minutes. 1580 */ 1581 #define IFINFOTIMEOUT ((hrtime_t)300 * NANOSEC) 1582 1583 /* 1584 * Sort the addresses in haddrlist. Since the sorting algorithms are 1585 * address-family specific, the work is done in the address-family 1586 * specific order_haddrlist_<family> functions. 1587 * 1588 * Do not sort addresses if SORT_ADDRS variable is set to NO or FALSE 1589 * in the configuration file /etc/default/nss. This is useful in case 1590 * the order of addresses returned by the nameserver needs to be 1591 * maintained. (DNS round robin feature is one example) 1592 */ 1593 void 1594 order_haddrlist_af(sa_family_t af, char **haddrlist) 1595 { 1596 size_t addrcount; 1597 char **addrptr; 1598 static boolean_t checksortcfg = B_TRUE; 1599 static boolean_t nosort = B_FALSE; 1600 static mutex_t checksortcfg_lock = DEFAULTMUTEX; 1601 1602 if (haddrlist == NULL) 1603 return; 1604 1605 /* 1606 * Check if SORT_ADDRS is set to NO or FALSE in the configuration 1607 * file. We do not have to sort addresses in that case. 1608 */ 1609 (void) mutex_lock(&checksortcfg_lock); 1610 if (checksortcfg == B_TRUE) { 1611 checksortcfg = B_FALSE; 1612 nosort = _read_nsw_file(); 1613 } 1614 (void) mutex_unlock(&checksortcfg_lock); 1615 1616 if (nosort) 1617 return; 1618 1619 /* Count the addresses to sort */ 1620 addrcount = 0; 1621 for (addrptr = haddrlist; *addrptr != NULL; addrptr++) 1622 addrcount++; 1623 1624 /* 1625 * If there's only one address or no addresses to sort, then 1626 * there's nothing for us to do. 1627 */ 1628 if (addrcount <= 1) 1629 return; 1630 1631 /* Call the address-family specific sorting functions. */ 1632 switch (af) { 1633 case AF_INET: 1634 order_haddrlist_inet(haddrlist, addrcount); 1635 break; 1636 case AF_INET6: 1637 order_haddrlist_inet6(haddrlist, addrcount); 1638 break; 1639 default: 1640 break; 1641 } 1642 } 1643 1644 /* 1645 * Move any local (on-link) addresses toward the beginning of haddrlist. 1646 * The order within these two classes is preserved. 1647 * 1648 * The interface list is retrieved no more often than every 1649 * IFINFOTIMEOUT nanoseconds. Access to the interface list is 1650 * protected by an RW lock. 1651 * 1652 * If this function encounters an error, haddrlist is unaltered. 1653 */ 1654 static void 1655 order_haddrlist_inet(char **haddrlist, size_t addrcount) 1656 { 1657 static struct ifinfo *localinfo = NULL; 1658 static hrtime_t then = 0; /* the last time localinfo was updated */ 1659 hrtime_t now; 1660 static rwlock_t localinfo_lock = DEFAULTRWLOCK; 1661 uint8_t *sortbuf; 1662 size_t sortbuf_size; 1663 struct in_addr **inaddrlist = (struct in_addr **)haddrlist; 1664 struct in_addr **sorted; 1665 struct in_addr **classnext[ADDR_NUMCLASSES]; 1666 uint_t classcount[ADDR_NUMCLASSES]; 1667 addr_class_t *sortclass; 1668 int i; 1669 int rc; 1670 1671 1672 /* 1673 * The classes in the sortclass array correspond to the class 1674 * of the address in the haddrlist list of the same index. 1675 * The classes are: 1676 * 1677 * ADDR_ONLINK on-link address 1678 * ADDR_OFFLINK off-link address 1679 */ 1680 sortbuf_size = addrcount * 1681 (sizeof (struct in_addr *) + sizeof (addr_class_t)); 1682 if ((sortbuf = malloc(sortbuf_size)) == NULL) 1683 return; 1684 /* LINTED pointer cast */ 1685 sorted = (struct in_addr **)sortbuf; 1686 /* LINTED pointer cast */ 1687 sortclass = (addr_class_t *)(sortbuf + 1688 (addrcount * sizeof (struct in_addr *))); 1689 1690 /* 1691 * Get a read lock, and check if the interface information 1692 * is too old. 1693 */ 1694 (void) rw_rdlock(&localinfo_lock); 1695 now = gethrtime(); 1696 if (localinfo == NULL || ((now - then) > IFINFOTIMEOUT)) { 1697 /* Need to update I/F info. Upgrade to write lock. */ 1698 (void) rw_unlock(&localinfo_lock); 1699 (void) rw_wrlock(&localinfo_lock); 1700 /* 1701 * Another thread might have updated "then" between 1702 * the rw_unlock() and rw_wrlock() calls above, so 1703 * re-check the timeout. 1704 */ 1705 if (localinfo == NULL || ((now - then) > IFINFOTIMEOUT)) { 1706 if (localinfo != NULL) 1707 free(localinfo); 1708 if ((localinfo = get_local_info()) == NULL) { 1709 (void) rw_unlock(&localinfo_lock); 1710 free(sortbuf); 1711 return; 1712 } 1713 then = now; 1714 } 1715 /* Downgrade to read lock */ 1716 (void) rw_unlock(&localinfo_lock); 1717 (void) rw_rdlock(&localinfo_lock); 1718 /* 1719 * Another thread may have updated the I/F info, 1720 * so verify that the 'localinfo' pointer still 1721 * is non-NULL. 1722 */ 1723 if (localinfo == NULL) { 1724 (void) rw_unlock(&localinfo_lock); 1725 free(sortbuf); 1726 return; 1727 } 1728 } 1729 1730 /* 1731 * Classify the addresses. We also maintain the classcount 1732 * array to keep track of the number of addresses in each 1733 * class. 1734 */ 1735 (void) memset(classcount, 0, sizeof (classcount)); 1736 for (i = 0; i < addrcount; i++) { 1737 if (__inet_address_is_local_af(localinfo, AF_INET, 1738 inaddrlist[i])) 1739 sortclass[i] = ADDR_ONLINK; 1740 else 1741 sortclass[i] = ADDR_OFFLINK; 1742 classcount[sortclass[i]]++; 1743 } 1744 1745 /* Don't need the interface list anymore in this call */ 1746 (void) rw_unlock(&localinfo_lock); 1747 1748 /* 1749 * Each element in the classnext array points to the next 1750 * element for that class in the sorted address list. 'rc' is 1751 * the running count of elements as we sum the class 1752 * sub-totals. 1753 */ 1754 for (rc = 0, i = 0; i < ADDR_NUMCLASSES; i++) { 1755 classnext[i] = &sorted[rc]; 1756 rc += classcount[i]; 1757 } 1758 1759 /* Now for the actual rearrangement of the addresses */ 1760 for (i = 0; i < addrcount; i++) { 1761 *(classnext[sortclass[i]]) = inaddrlist[i]; 1762 classnext[sortclass[i]]++; 1763 } 1764 1765 /* Copy the sorted list to inaddrlist */ 1766 (void) memcpy(inaddrlist, sorted, 1767 addrcount * sizeof (struct in_addr *)); 1768 free(sortbuf); 1769 } 1770 1771 /* 1772 * This function implements the IPv6 Default Address Selection's 1773 * destination address ordering mechanism. The algorithm is described 1774 * in getaddrinfo(3SOCKET). 1775 */ 1776 static void 1777 order_haddrlist_inet6(char **haddrlist, size_t addrcount) 1778 { 1779 struct dstinforeq *dinfo, *dinfoptr; 1780 struct in6_addr **in6addrlist = (struct in6_addr **)haddrlist; 1781 struct in6_addr **in6addr; 1782 1783 if ((dinfo = calloc(addrcount, sizeof (struct dstinforeq))) == NULL) 1784 return; 1785 1786 /* Initialize the dstinfo array we'll use for SIOCGDSTINFO */ 1787 dinfoptr = dinfo; 1788 for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) { 1789 dinfoptr->dir_daddr = **in6addr; 1790 dinfoptr++; 1791 } 1792 1793 if (nss_strioctl(AF_INET6, SIOCGDSTINFO, dinfo, 1794 addrcount * sizeof (struct dstinforeq)) < 0) { 1795 free(dinfo); 1796 return; 1797 } 1798 1799 /* Sort the dinfo array */ 1800 qsort(dinfo, addrcount, sizeof (struct dstinforeq), dstcmp); 1801 1802 /* Copy the addresses back into in6addrlist */ 1803 dinfoptr = dinfo; 1804 for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) { 1805 **in6addr = dinfoptr->dir_daddr; 1806 dinfoptr++; 1807 } 1808 1809 free(dinfo); 1810 } 1811 1812 /* 1813 * Determine number of leading bits that are common between two addresses. 1814 * Only consider bits which fall within the prefix length plen. 1815 */ 1816 static uint_t 1817 ip_addr_commonbits_v6(const in6_addr_t *a1, const in6_addr_t *a2) 1818 { 1819 uint_t bits; 1820 uint_t i; 1821 uint32_t diff; /* Bits that differ */ 1822 1823 for (i = 0; i < 4; i++) { 1824 if (a1->_S6_un._S6_u32[i] != a2->_S6_un._S6_u32[i]) 1825 break; 1826 } 1827 bits = i * 32; 1828 1829 if (bits == IPV6_ABITS) 1830 return (IPV6_ABITS); 1831 1832 /* 1833 * Find number of leading common bits in the word which might 1834 * have some common bits by searching for the first one from the left 1835 * in the xor of the two addresses. 1836 */ 1837 diff = ntohl(a1->_S6_un._S6_u32[i] ^ a2->_S6_un._S6_u32[i]); 1838 if (diff & 0xffff0000ul) 1839 diff >>= 16; 1840 else 1841 bits += 16; 1842 if (diff & 0xff00) 1843 diff >>= 8; 1844 else 1845 bits += 8; 1846 if (diff & 0xf0) 1847 diff >>= 4; 1848 else 1849 bits += 4; 1850 if (diff & 0xc) 1851 diff >>= 2; 1852 else 1853 bits += 2; 1854 if (!(diff & 2)) 1855 bits++; 1856 1857 /* 1858 * We don't need to shift and check for the last bit. The 1859 * check for IPV6_ABITS above would have caught that. 1860 */ 1861 1862 return (bits); 1863 } 1864 1865 1866 /* 1867 * The following group of functions named rule_*() are individual 1868 * sorting rules for the AF_INET6 address sorting algorithm. The 1869 * functions compare two addresses (described by two dstinforeq 1870 * structures), and determines if one is "greater" than the other, or 1871 * if the two are equal according to that rule. 1872 */ 1873 typedef int (*rulef_t)(const struct dstinforeq *, const struct dstinforeq *); 1874 1875 /* 1876 * These values of these constants are no accident. Since qsort() 1877 * implements the AF_INET6 address sorting, the comparison function 1878 * must return an integer less than, equal to, or greater than zero to 1879 * indicate if the first address is considered "less than", "equal 1880 * to", or "greater than" the second one. Since we want the best 1881 * addresses first on the list, "less than" is considered preferrable. 1882 */ 1883 #define RULE_PREFER_DA -1 1884 #define RULE_PREFER_DB 1 1885 #define RULE_EQUAL 0 1886 1887 /* Prefer the addresses that is reachable. */ 1888 static int 1889 rule_reachable(const struct dstinforeq *da, const struct dstinforeq *db) 1890 { 1891 if (da->dir_dreachable == db->dir_dreachable) 1892 return (RULE_EQUAL); 1893 if (da->dir_dreachable) 1894 return (RULE_PREFER_DA); 1895 return (RULE_PREFER_DB); 1896 } 1897 1898 /* Prefer the address whose scope matches that of its source address. */ 1899 static int 1900 rule_matchscope(const struct dstinforeq *da, const struct dstinforeq *db) 1901 { 1902 boolean_t da_scope_match, db_scope_match; 1903 1904 da_scope_match = da->dir_dscope == da->dir_sscope; 1905 db_scope_match = db->dir_dscope == db->dir_sscope; 1906 1907 if (da_scope_match == db_scope_match) 1908 return (RULE_EQUAL); 1909 if (da_scope_match) 1910 return (RULE_PREFER_DA); 1911 return (RULE_PREFER_DB); 1912 } 1913 1914 /* Avoid the address with the link local source address. */ 1915 static int 1916 rule_avoidlinklocal(const struct dstinforeq *da, const struct dstinforeq *db) 1917 { 1918 if (da->dir_sscope == IP6_SCOPE_LINKLOCAL && 1919 da->dir_dscope != IP6_SCOPE_LINKLOCAL && 1920 db->dir_sscope != IP6_SCOPE_LINKLOCAL) 1921 return (RULE_PREFER_DB); 1922 if (db->dir_sscope == IP6_SCOPE_LINKLOCAL && 1923 db->dir_dscope != IP6_SCOPE_LINKLOCAL && 1924 da->dir_sscope != IP6_SCOPE_LINKLOCAL) 1925 return (RULE_PREFER_DA); 1926 return (RULE_EQUAL); 1927 } 1928 1929 /* Prefer the address whose source address isn't deprecated. */ 1930 static int 1931 rule_deprecated(const struct dstinforeq *da, const struct dstinforeq *db) 1932 { 1933 if (da->dir_sdeprecated == db->dir_sdeprecated) 1934 return (RULE_EQUAL); 1935 if (db->dir_sdeprecated) 1936 return (RULE_PREFER_DA); 1937 return (RULE_PREFER_DB); 1938 } 1939 1940 /* Prefer the address whose label matches that of its source address. */ 1941 static int 1942 rule_label(const struct dstinforeq *da, const struct dstinforeq *db) 1943 { 1944 if (da->dir_labelmatch == db->dir_labelmatch) 1945 return (RULE_EQUAL); 1946 if (da->dir_labelmatch) 1947 return (RULE_PREFER_DA); 1948 return (RULE_PREFER_DB); 1949 } 1950 1951 /* Prefer the address with the higher precedence. */ 1952 static int 1953 rule_precedence(const struct dstinforeq *da, const struct dstinforeq *db) 1954 { 1955 if (da->dir_precedence == db->dir_precedence) 1956 return (RULE_EQUAL); 1957 if (da->dir_precedence > db->dir_precedence) 1958 return (RULE_PREFER_DA); 1959 return (RULE_PREFER_DB); 1960 } 1961 1962 /* Prefer the address whose output interface isn't an IP tunnel */ 1963 static int 1964 rule_native(const struct dstinforeq *da, const struct dstinforeq *db) 1965 { 1966 boolean_t isatun, isbtun; 1967 1968 /* Get the common case out of the way early */ 1969 if (da->dir_dmactype == db->dir_dmactype) 1970 return (RULE_EQUAL); 1971 1972 isatun = da->dir_dmactype == DL_IPV4 || da->dir_dmactype == DL_IPV6; 1973 isbtun = db->dir_dmactype == DL_IPV4 || db->dir_dmactype == DL_IPV6; 1974 1975 if (isatun == isbtun) 1976 return (RULE_EQUAL); 1977 if (isbtun) 1978 return (RULE_PREFER_DA); 1979 return (RULE_PREFER_DB); 1980 } 1981 1982 /* Prefer the address with the smaller scope. */ 1983 static int 1984 rule_scope(const struct dstinforeq *da, const struct dstinforeq *db) 1985 { 1986 if (da->dir_dscope == db->dir_dscope) 1987 return (RULE_EQUAL); 1988 if (da->dir_dscope < db->dir_dscope) 1989 return (RULE_PREFER_DA); 1990 return (RULE_PREFER_DB); 1991 } 1992 1993 /* 1994 * Prefer the address that has the most leading bits in common with its 1995 * source address. 1996 */ 1997 static int 1998 rule_prefix(const struct dstinforeq *da, const struct dstinforeq *db) 1999 { 2000 uint_t da_commonbits, db_commonbits; 2001 boolean_t da_isipv4, db_isipv4; 2002 2003 da_isipv4 = IN6_IS_ADDR_V4MAPPED(&da->dir_daddr); 2004 db_isipv4 = IN6_IS_ADDR_V4MAPPED(&db->dir_daddr); 2005 2006 /* 2007 * At this point, the order doesn't matter if the two addresses 2008 * aren't of the same address family. 2009 */ 2010 if (da_isipv4 != db_isipv4) 2011 return (RULE_EQUAL); 2012 2013 da_commonbits = ip_addr_commonbits_v6(&da->dir_daddr, &da->dir_saddr); 2014 db_commonbits = ip_addr_commonbits_v6(&db->dir_daddr, &db->dir_saddr); 2015 2016 if (da_commonbits > db_commonbits) 2017 return (RULE_PREFER_DA); 2018 if (da_commonbits < db_commonbits) 2019 return (RULE_PREFER_DB); 2020 return (RULE_EQUAL); 2021 } 2022 2023 /* 2024 * This is the function passed to qsort() that does the AF_INET6 2025 * address comparisons. It compares two addresses using a list of 2026 * rules. The rules are applied in order until one prefers one 2027 * address over the other. 2028 */ 2029 static int 2030 dstcmp(const void *da, const void *db) 2031 { 2032 int index, result; 2033 rulef_t rules[] = { 2034 rule_reachable, 2035 rule_matchscope, 2036 rule_avoidlinklocal, 2037 rule_deprecated, 2038 rule_label, 2039 rule_precedence, 2040 rule_native, 2041 rule_scope, 2042 rule_prefix, 2043 NULL 2044 }; 2045 2046 result = 0; 2047 for (index = 0; rules[index] != NULL; index++) { 2048 result = (rules[index])(da, db); 2049 if (result != RULE_EQUAL) 2050 break; 2051 } 2052 2053 return (result); 2054 } 2055 2056 /* 2057 * Given haddrlist and a port number, mallocs and populates a new 2058 * nd_addrlist. The new nd_addrlist maintains the order of the addresses 2059 * in haddrlist, which have already been sorted by order_haddrlist_inet() 2060 * or order_haddrlist_inet6(). For IPv6 this function filters out 2061 * IPv4-mapped IPv6 addresses. 2062 */ 2063 int 2064 hent2ndaddr(int af, char **haddrlist, int *servp, struct nd_addrlist **nd_alist) 2065 { 2066 struct nd_addrlist *result; 2067 int num; 2068 struct netbuf *na; 2069 struct sockaddr_in *sinbuf, *sin; 2070 struct sockaddr_in6 *sin6buf, *sin6; 2071 struct in_addr **inaddr, **inaddrlist; 2072 struct in6_addr **in6addr, **in6addrlist; 2073 2074 /* Address count */ 2075 num = 0; 2076 if (af == AF_INET6) { 2077 in6addrlist = (struct in6_addr **)haddrlist; 2078 2079 /* 2080 * Exclude IPv4-mapped IPv6 addresses from the count, as 2081 * these are not included in the nd_addrlist we return. 2082 */ 2083 for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) 2084 if (!IN6_IS_ADDR_V4MAPPED(*in6addr)) 2085 num++; 2086 } else { 2087 inaddrlist = (struct in_addr **)haddrlist; 2088 2089 for (inaddr = inaddrlist; *inaddr != NULL; inaddr++) 2090 num++; 2091 } 2092 if (num == 0) 2093 return (ND_NOHOST); 2094 2095 result = malloc(sizeof (struct nd_addrlist)); 2096 if (result == 0) 2097 return (ND_NOMEM); 2098 2099 result->n_cnt = num; 2100 result->n_addrs = calloc(num, sizeof (struct netbuf)); 2101 if (result->n_addrs == 0) { 2102 free(result); 2103 return (ND_NOMEM); 2104 } 2105 2106 na = result->n_addrs; 2107 if (af == AF_INET) { 2108 sinbuf = calloc(num, sizeof (struct sockaddr_in)); 2109 if (sinbuf == NULL) { 2110 free(result->n_addrs); 2111 free(result); 2112 return (ND_NOMEM); 2113 } 2114 2115 sin = sinbuf; 2116 for (inaddr = inaddrlist; *inaddr != NULL; inaddr++) { 2117 na->len = na->maxlen = sizeof (struct sockaddr_in); 2118 na->buf = (char *)sin; 2119 sin->sin_family = AF_INET; 2120 sin->sin_addr = **inaddr; 2121 sin->sin_port = *servp; 2122 na++; 2123 sin++; 2124 } 2125 } else if (af == AF_INET6) { 2126 sin6buf = calloc(num, sizeof (struct sockaddr_in6)); 2127 if (sin6buf == NULL) { 2128 free(result->n_addrs); 2129 free(result); 2130 return (ND_NOMEM); 2131 } 2132 2133 sin6 = sin6buf; 2134 for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) { 2135 if (IN6_IS_ADDR_V4MAPPED(*in6addr)) 2136 continue; 2137 2138 na->len = na->maxlen = sizeof (struct sockaddr_in6); 2139 na->buf = (char *)sin6; 2140 sin6->sin6_family = AF_INET6; 2141 sin6->sin6_addr = **in6addr; 2142 sin6->sin6_port = *servp; 2143 na++; 2144 sin6++; 2145 } 2146 } 2147 *(nd_alist) = result; 2148 return (ND_OK); 2149 } 2150 2151 /* 2152 * Given a hostent and a servent, mallocs and populates 2153 * a new nd_hostservlist with host and service names. 2154 * 2155 * We could be passed in a NULL servent, in which case stringify port. 2156 */ 2157 int 2158 hsents2ndhostservs(struct hostent *he, struct servent *se, 2159 ushort_t port, struct nd_hostservlist **hslist) 2160 { 2161 struct nd_hostservlist *result; 2162 struct nd_hostserv *hs; 2163 int hosts, servs, i, j; 2164 char **hn, **sn; 2165 2166 if ((result = malloc(sizeof (struct nd_hostservlist))) == 0) 2167 return (ND_NOMEM); 2168 2169 /* 2170 * We initialize the counters to 1 rather than zero because 2171 * we have to count the "official" name as well as the aliases. 2172 */ 2173 for (hn = he->h_aliases, hosts = 1; hn && *hn; hn++, hosts++) {}; 2174 if (se) { 2175 for (sn = se->s_aliases, servs = 1; sn && *sn; sn++, servs++) { 2176 }; 2177 } else 2178 servs = 1; 2179 2180 if ((hs = calloc(hosts * servs, sizeof (struct nd_hostserv))) == 0) { 2181 free(result); 2182 return (ND_NOMEM); 2183 } 2184 2185 result->h_cnt = servs * hosts; 2186 result->h_hostservs = hs; 2187 2188 for (i = 0, hn = he->h_aliases; i < hosts; i++) { 2189 sn = se ? se->s_aliases : NULL; 2190 2191 for (j = 0; j < servs; j++) { 2192 if (i == 0) 2193 hs->h_host = strdup(he->h_name); 2194 else 2195 hs->h_host = strdup(*hn); 2196 if (j == 0) { 2197 if (se) 2198 hs->h_serv = strdup(se->s_name); 2199 else { 2200 /* Convert to a number string */ 2201 char stmp[16]; 2202 2203 (void) sprintf(stmp, "%d", port); 2204 hs->h_serv = strdup(stmp); 2205 } 2206 } else 2207 hs->h_serv = strdup(*sn++); 2208 2209 if ((hs->h_host == 0) || (hs->h_serv == 0)) { 2210 free(result->h_hostservs); 2211 free(result); 2212 return (ND_NOMEM); 2213 } 2214 hs++; 2215 } 2216 if (i) 2217 hn++; 2218 } 2219 *(hslist) = result; 2220 return (ND_OK); 2221 } 2222 2223 /* 2224 * Process results from nd_addrlist ( returned by netdir_getbyname) 2225 * into a hostent using buf. 2226 * *** ASSUMES that nd_addrlist->n_addrs->buf contains IP addresses in 2227 * sockaddr_in's *** 2228 */ 2229 int 2230 ndaddr2hent(int af, const char *nam, struct nd_addrlist *addrs, 2231 struct hostent *result, char *buffer, int buflen) 2232 { 2233 int i, count; 2234 struct in_addr *addrp; 2235 struct in6_addr *addr6p; 2236 char **addrvec; 2237 struct netbuf *na; 2238 size_t len; 2239 2240 result->h_name = buffer; 2241 result->h_addrtype = af; 2242 result->h_length = (af == AF_INET) ? sizeof (*addrp): 2243 sizeof (*addr6p); 2244 2245 /* 2246 * Build addrlist at start of buffer (after name); store the 2247 * addresses themselves at the end of the buffer. 2248 */ 2249 len = strlen(nam) + 1; 2250 addrvec = (char **)ROUND_UP(buffer + len, sizeof (*addrvec)); 2251 result->h_addr_list = addrvec; 2252 2253 if (af == AF_INET) { 2254 addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen, 2255 sizeof (*addrp)); 2256 2257 count = addrs->n_cnt; 2258 if ((char *)(&addrvec[count + 1]) > (char *)(&addrp[-count])) 2259 return (ND_NOMEM); 2260 2261 (void) memcpy(buffer, nam, len); 2262 2263 for (na = addrs->n_addrs, i = 0; i < count; na++, i++) { 2264 --addrp; 2265 (void) memcpy(addrp, 2266 /* LINTED pointer cast */ 2267 &((struct sockaddr_in *)na->buf)->sin_addr, 2268 sizeof (*addrp)); 2269 *addrvec++ = (char *)addrp; 2270 } 2271 } else { 2272 addr6p = (struct in6_addr *)ROUND_DOWN(buffer + buflen, 2273 sizeof (*addr6p)); 2274 2275 count = addrs->n_cnt; 2276 if ((char *)(&addrvec[count + 1]) > (char *)(&addr6p[-count])) 2277 return (ND_NOMEM); 2278 2279 (void) memcpy(buffer, nam, len); 2280 2281 for (na = addrs->n_addrs, i = 0; i < count; na++, i++) { 2282 --addr6p; 2283 (void) memcpy(addr6p, 2284 /* LINTED pointer cast */ 2285 &((struct sockaddr_in6 *)na->buf)->sin6_addr, 2286 sizeof (*addr6p)); 2287 *addrvec++ = (char *)addr6p; 2288 } 2289 } 2290 *addrvec = 0; 2291 result->h_aliases = addrvec; 2292 2293 return (ND_OK); 2294 } 2295 2296 /* 2297 * Process results from nd_addrlist ( returned by netdir_getbyname) 2298 * into a servent using buf. 2299 */ 2300 int 2301 ndaddr2srent(const char *name, const char *proto, ushort_t port, 2302 struct servent *result, char *buffer, int buflen) 2303 { 2304 size_t i; 2305 char *bufend = (buffer + buflen); 2306 2307 result->s_port = (int)port; 2308 2309 result->s_aliases = 2310 (char **)ROUND_UP(buffer, sizeof (char *)); 2311 result->s_aliases[0] = NULL; 2312 buffer = (char *)&result->s_aliases[1]; 2313 result->s_name = buffer; 2314 i = strlen(name) + 1; 2315 if ((buffer + i) > bufend) 2316 return (ND_NOMEM); 2317 (void) memcpy(buffer, name, i); 2318 buffer += i; 2319 2320 result->s_proto = buffer; 2321 i = strlen(proto) + 1; 2322 if ((buffer + i) > bufend) 2323 return (ND_NOMEM); 2324 (void) memcpy(buffer, proto, i); 2325 buffer += i; 2326 2327 return (ND_OK); 2328 } 2329 2330 /* 2331 * Process results from nd_hostservlist ( returned by netdir_getbyaddr) 2332 * into a hostent using buf. 2333 * *** ASSUMES that nd_buf->buf is a sockaddr_in *** 2334 */ 2335 int 2336 ndhostserv2hent(struct netbuf *nbuf, struct nd_hostservlist *addrs, 2337 struct hostent *result, char *buffer, int buflen) 2338 { 2339 int i, count; 2340 char *aliasp; 2341 char **aliasvec; 2342 struct sockaddr_in *sa; 2343 struct nd_hostserv *hs; 2344 const char *la; 2345 size_t length; 2346 2347 /* First, give the lonely address a specious home in h_addr_list. */ 2348 aliasp = (char *)ROUND_UP(buffer, sizeof (sa->sin_addr)); 2349 /* LINTED pointer cast */ 2350 sa = (struct sockaddr_in *)nbuf->buf; 2351 (void) memcpy(aliasp, &(sa->sin_addr), sizeof (sa->sin_addr)); 2352 aliasvec = (char **)ROUND_UP(aliasp + sizeof (sa->sin_addr), 2353 sizeof (*aliasvec)); 2354 result->h_addr_list = aliasvec; 2355 *aliasvec++ = aliasp; 2356 *aliasvec++ = 0; 2357 2358 /* 2359 * Build h_aliases at start of buffer (after addr and h_addr_list); 2360 * store the alias strings at the end of the buffer (before h_name). 2361 */ 2362 2363 aliasp = buffer + buflen; 2364 2365 result->h_aliases = aliasvec; 2366 2367 hs = addrs->h_hostservs; 2368 if (!hs) 2369 return (ND_NOHOST); 2370 2371 length = strlen(hs->h_host) + 1; 2372 aliasp -= length; 2373 if ((char *)(&aliasvec[1]) > aliasp) 2374 return (ND_NOMEM); 2375 (void) memcpy(aliasp, hs->h_host, length); 2376 2377 result->h_name = aliasp; 2378 result->h_addrtype = AF_INET; 2379 result->h_length = sizeof (sa->sin_addr); 2380 2381 /* 2382 * Assumption: the netdir nametoaddr_libs 2383 * sort the vector of (host, serv) pairs in such a way that 2384 * all pairs with the same host name are contiguous. 2385 */ 2386 la = hs->h_host; 2387 count = addrs->h_cnt; 2388 for (i = 0; i < count; i++, hs++) 2389 if (strcmp(la, hs->h_host) != 0) { 2390 size_t len = strlen(hs->h_host) + 1; 2391 2392 aliasp -= len; 2393 if ((char *)(&aliasvec[2]) > aliasp) 2394 return (ND_NOMEM); 2395 (void) memcpy(aliasp, hs->h_host, len); 2396 *aliasvec++ = aliasp; 2397 la = hs->h_host; 2398 } 2399 *aliasvec = 0; 2400 2401 return (ND_OK); 2402 } 2403 2404 /* 2405 * Process results from nd_hostservlist ( returned by netdir_getbyaddr) 2406 * into a servent using buf. 2407 */ 2408 int 2409 ndhostserv2srent(int port, const char *proto, struct nd_hostservlist *addrs, 2410 struct servent *result, char *buffer, int buflen) 2411 { 2412 int i, count; 2413 char *aliasp; 2414 char **aliasvec; 2415 struct nd_hostserv *hs; 2416 const char *host_cname; 2417 size_t leni, lenj; 2418 2419 result->s_port = port; 2420 /* 2421 * Build s_aliases at start of buffer; 2422 * store proto and aliases at the end of the buffer (before h_name). 2423 */ 2424 2425 aliasp = buffer + buflen; 2426 aliasvec = (char **)ROUND_UP(buffer, sizeof (char *)); 2427 2428 result->s_aliases = aliasvec; 2429 2430 hs = addrs->h_hostservs; 2431 if (!hs) 2432 return (ND_NOHOST); 2433 host_cname = hs->h_host; 2434 2435 leni = strlen(proto) + 1; 2436 lenj = strlen(hs->h_serv) + 1; 2437 if ((char *)(&aliasvec[2]) > (aliasp - leni - lenj)) 2438 return (ND_NOMEM); 2439 2440 aliasp -= leni; 2441 (void) memcpy(aliasp, proto, leni); 2442 result->s_proto = aliasp; 2443 2444 aliasp -= lenj; 2445 (void) memcpy(aliasp, hs->h_serv, lenj); 2446 result->s_name = aliasp; 2447 2448 /* 2449 * Assumption: the netdir nametoaddr_libs 2450 * do a host aliases first and serv aliases next 2451 * enumeration for creating the list of hostserv 2452 * structures. 2453 */ 2454 count = addrs->h_cnt; 2455 for (i = 0; 2456 i < count && hs->h_serv && strcmp(hs->h_host, host_cname) == 0; 2457 i++, hs++) { 2458 size_t len = strlen(hs->h_serv) + 1; 2459 2460 aliasp -= len; 2461 if ((char *)(&aliasvec[2]) > aliasp) 2462 return (ND_NOMEM); 2463 (void) memcpy(aliasp, hs->h_serv, len); 2464 *aliasvec++ = aliasp; 2465 } 2466 *aliasvec = NULL; 2467 2468 return (ND_OK); 2469 } 2470 2471 2472 static int 2473 nd2herrno(int nerr) 2474 { 2475 switch (nerr) { 2476 case ND_OK: 2477 return (0); 2478 case ND_TRY_AGAIN: 2479 return (TRY_AGAIN); 2480 case ND_NO_RECOVERY: 2481 case ND_BADARG: 2482 case ND_NOMEM: 2483 return (NO_RECOVERY); 2484 case ND_NO_DATA: 2485 return (NO_DATA); 2486 case ND_NOHOST: 2487 case ND_NOSERV: 2488 return (HOST_NOT_FOUND); 2489 default: 2490 return (NO_RECOVERY); 2491 } 2492 } 2493 2494 /* 2495 * This is a utility function so that various parts of libnsl can 2496 * easily send ioctls down to ip. 2497 * 2498 */ 2499 int 2500 nss_ioctl(int af, int cmd, void *arg) 2501 { 2502 int fd; 2503 char *devpath; 2504 int retv; 2505 2506 switch (af) { 2507 case AF_INET6: 2508 devpath = UDP6DEV; 2509 break; 2510 case AF_INET: 2511 case AF_UNSPEC: 2512 default: 2513 devpath = UDPDEV; 2514 } 2515 if ((fd = open(devpath, O_RDONLY)) < 0) { 2516 return (-1); 2517 } 2518 while ((retv = ioctl(fd, cmd, arg)) == -1) { 2519 if (errno != EINTR) 2520 break; 2521 } 2522 (void) close(fd); 2523 return (retv); 2524 } 2525 2526 static int 2527 nss_strioctl(int af, int cmd, void *ptr, int ilen) 2528 { 2529 struct strioctl str; 2530 2531 str.ic_cmd = cmd; 2532 str.ic_timout = 0; 2533 str.ic_len = ilen; 2534 str.ic_dp = ptr; 2535 2536 return (nss_ioctl(af, I_STR, &str)); 2537 } 2538 2539 static struct ifinfo * 2540 get_local_info(void) 2541 { 2542 int numifs; 2543 int n; 2544 char *buf = NULL; 2545 size_t needed; 2546 struct lifconf lifc; 2547 struct lifreq lifreq, *lifr; 2548 struct lifnum lifn; 2549 struct ifinfo *localinfo; 2550 2551 lifn.lifn_family = AF_UNSPEC; 2552 lifn.lifn_flags = 0; 2553 2554 getifnum: 2555 if (nss_ioctl(AF_UNSPEC, SIOCGLIFNUM, &lifn) == -1) { 2556 numifs = MAXIFS; 2557 } else { 2558 numifs = lifn.lifn_count; 2559 } 2560 2561 /* 2562 * Add a small fudge factor in case interfaces get plumbed between 2563 * the call to SIOCGLIFNUM and SIOCGLIFCONF. 2564 */ 2565 needed = (numifs + 4) * sizeof (lifreq); 2566 if (buf == NULL) 2567 buf = malloc(needed); 2568 else 2569 buf = realloc(buf, needed); 2570 if (buf == NULL) { 2571 (void) syslog(LOG_ERR, "n2a get_local_info: malloc failed: %m"); 2572 _nderror = ND_NOMEM; 2573 return (NULL); 2574 } 2575 lifc.lifc_family = AF_UNSPEC; 2576 lifc.lifc_flags = 0; 2577 lifc.lifc_len = needed; 2578 lifc.lifc_buf = buf; 2579 if (nss_ioctl(AF_UNSPEC, SIOCGLIFCONF, &lifc) == -1) { 2580 /* 2581 * IP returns EINVAL if the buffer was too small to fit 2582 * all of the entries. If that's the case, go back and 2583 * try again. 2584 */ 2585 if (errno == EINVAL) 2586 goto getifnum; 2587 2588 (void) syslog(LOG_ERR, "n2a get_local_info: " 2589 "ioctl (get interface configuration): %m"); 2590 free(buf); 2591 _nderror = ND_SYSTEM; 2592 return (NULL); 2593 } 2594 /* LINTED pointer cast */ 2595 lifr = (struct lifreq *)buf; 2596 numifs = lifc.lifc_len/sizeof (lifreq); 2597 localinfo = malloc(ifinfosize(numifs)); 2598 if (localinfo == NULL) { 2599 (void) syslog(LOG_ERR, "n2a get_local_info: malloc failed: %m"); 2600 free(buf); 2601 _nderror = ND_SYSTEM; 2602 return (NULL); 2603 } 2604 2605 /* LINTED pointer cast */ 2606 localinfo->addresses = (struct __ifaddr *) 2607 ((char *)localinfo + sizeof (struct ifinfo)); 2608 2609 for (localinfo->count = 0, n = numifs; n > 0; n--, lifr++) { 2610 int af; 2611 2612 lifreq = *lifr; 2613 af = lifreq.lifr_addr.ss_family; 2614 2615 /* Squirrel away the address */ 2616 if (ifassign(lifreq, localinfo->count, IF_ADDR) == 0) 2617 continue; 2618 2619 if (nss_ioctl(af, SIOCGLIFFLAGS, &lifreq) < 0) { 2620 (void) syslog(LOG_ERR, 2621 "n2a get_local_info: " 2622 "ioctl (get interface flags): %m"); 2623 continue; 2624 } 2625 if (!(lifreq.lifr_flags & IFF_UP)) 2626 continue; 2627 2628 if (nss_ioctl(af, SIOCGLIFNETMASK, &lifreq) < 0) { 2629 (void) syslog(LOG_ERR, 2630 "n2a get_local_info: " 2631 "ioctl (get interface netmask): %m"); 2632 continue; 2633 } 2634 2635 if (ifassign(lifreq, localinfo->count, IF_MASK) == 0) 2636 continue; 2637 2638 localinfo->count++; 2639 } 2640 2641 free(buf); 2642 return (localinfo); 2643 } 2644 2645 static int 2646 __inet_ifassign(sa_family_t af, struct __ifaddr *ifa, __ifaddr_type type, 2647 void *addr) { 2648 switch (type) { 2649 case IF_ADDR: 2650 ifa->af = af; 2651 if (af == AF_INET6) { 2652 ifa->addr.in6 = *(struct in6_addr *)addr; 2653 } else { 2654 ifa->addr.in4 = *(struct in_addr *)addr; 2655 } 2656 break; 2657 case IF_MASK: 2658 if (ifa->af == af) { 2659 if (af == AF_INET6) { 2660 ifa->mask.in6 = *(struct in6_addr *)addr; 2661 } else { 2662 ifa->mask.in4 = *(struct in_addr *)addr; 2663 } 2664 } else { 2665 return (0); 2666 } 2667 break; 2668 default: 2669 return (0); 2670 } 2671 2672 return (1); 2673 } 2674 2675 /* 2676 * Some higher-level routines for determining if an address is 2677 * on a local network. 2678 * 2679 * __inet_get_local_interfaces() - get an opaque handle with 2680 * with a list of local interfaces 2681 * __inet_address_is_local() - return 1 if an address is 2682 * on a local network; 0 otherwise 2683 * __inet_free_local_interfaces() - free handle that was 2684 * returned by __inet_get_local_interfaces() 2685 * 2686 * A typical calling sequence is: 2687 * 2688 * p = __inet_get_local_interfaces(); 2689 * if (__inet_address_is_local(p, inaddr)) { 2690 * ... 2691 * } 2692 * __inet_free_local_interfaces(p); 2693 */ 2694 2695 /* 2696 * Return an opaque pointer to a list of configured interfaces. 2697 */ 2698 void * 2699 __inet_get_local_interfaces(void) 2700 { 2701 return (get_local_info()); 2702 } 2703 2704 /* 2705 * Free memory allocated by inet_local_interfaces(). 2706 */ 2707 void 2708 __inet_free_local_interfaces(void *p) 2709 { 2710 free(p); 2711 } 2712 2713 /* 2714 * Determine if an address is on a local network. 2715 * 2716 * Might have made sense to use SIOCTONLINK, except that it doesn't 2717 * handle matching on IPv4 network addresses. 2718 */ 2719 int 2720 __inet_address_is_local_af(void *p, sa_family_t af, void *addr) { 2721 2722 struct ifinfo *localinfo = (struct ifinfo *)p; 2723 int i, a; 2724 struct in_addr v4addr; 2725 2726 if (localinfo == 0) 2727 return (0); 2728 2729 if (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr)) { 2730 IN6_V4MAPPED_TO_INADDR((struct in6_addr *)addr, &v4addr); 2731 af = AF_INET; 2732 addr = (void *)&v4addr; 2733 } 2734 2735 for (i = 0; i < localinfo->count; i++) { 2736 if (ifaf(i) == af) { 2737 if (af == AF_INET6) { 2738 struct in6_addr *a6 = (struct in6_addr *)addr; 2739 for (a = 0; a < sizeof (a6->s6_addr); a++) { 2740 if ((a6->s6_addr[a] & 2741 ifmask6(i).s6_addr[a]) != 2742 (ifaddr6(i).s6_addr[a] & 2743 ifmask6(i).s6_addr[a])) 2744 break; 2745 } 2746 if (a >= sizeof (a6->s6_addr)) 2747 return (1); 2748 } else { 2749 if ((((struct in_addr *)addr)->s_addr & 2750 ifmask4(i).s_addr) == 2751 (ifaddr4(i).s_addr & 2752 ifmask4(i).s_addr)) 2753 return (1); 2754 } 2755 } 2756 } 2757 2758 return (0); 2759 } 2760 2761 int 2762 __inet_address_is_local(void *p, struct in_addr addr) 2763 { 2764 return (__inet_address_is_local_af(p, AF_INET, &addr)); 2765 } 2766 2767 int 2768 __inet_uaddr_is_local(void *p, struct netconfig *nc, char *uaddr) 2769 { 2770 struct netbuf *taddr; 2771 sa_family_t af; 2772 int ret; 2773 2774 taddr = uaddr2taddr(nc, uaddr); 2775 if (taddr == 0) 2776 return (0); 2777 2778 /* LINTED pointer cast */ 2779 af = ((struct sockaddr *)taddr->buf)->sa_family; 2780 2781 ret = __inet_address_is_local_af(p, af, (af == AF_INET6) ? 2782 /* LINTED pointer cast */ 2783 (void *)&((struct sockaddr_in6 *)taddr->buf)->sin6_addr : 2784 /* LINTED pointer cast */ 2785 (void *)&((struct sockaddr_in *)taddr->buf)->sin_addr); 2786 2787 netdir_free(taddr, ND_ADDR); 2788 return (ret); 2789 } 2790 2791 2792 int 2793 __inet_address_count(void *p) 2794 { 2795 struct ifinfo *lp = (struct ifinfo *)p; 2796 2797 if (lp != 0) { 2798 return (lp->count); 2799 } else { 2800 return (0); 2801 } 2802 } 2803 2804 uint32_t 2805 __inet_get_addr(void *p, int n) 2806 { 2807 struct ifinfo *localinfo = (struct ifinfo *)p; 2808 2809 if (localinfo == 0 || n >= localinfo->count || ifaf(n) != AF_INET) 2810 return (0); 2811 2812 return (ifaddr4(n).s_addr); 2813 } 2814 2815 uint32_t 2816 __inet_get_network(void *p, int n) 2817 { 2818 struct ifinfo *localinfo = (struct ifinfo *)p; 2819 2820 if (localinfo == 0 || n >= localinfo->count || ifaf(n) != AF_INET) 2821 return (0); 2822 2823 return (ifaddr4(n).s_addr & ifmask4(n).s_addr); 2824 } 2825 2826 char * 2827 __inet_get_uaddr(void *p, struct netconfig *nc, int n) 2828 { 2829 struct ifinfo *localinfo = (struct ifinfo *)p; 2830 char *uaddr; 2831 struct sockaddr_in sin4; 2832 struct sockaddr_in6 sin6; 2833 struct netbuf nb; 2834 2835 if (localinfo == 0 || nc == 0 || n >= localinfo->count) 2836 return (0); 2837 2838 if (ifaf(n) == AF_INET6) { 2839 if (strcmp(NC_INET6, nc->nc_protofmly) != 0) 2840 return (0); 2841 (void) memset(&sin6, 0, sizeof (sin6)); 2842 sin6.sin6_family = AF_INET6; 2843 sin6.sin6_addr = ifaddr6(n); 2844 nb.buf = (char *)&sin6; 2845 nb.len = sizeof (sin6); 2846 } else { 2847 if (strcmp(NC_INET, nc->nc_protofmly) != 0) 2848 return (0); 2849 (void) memset(&sin4, 0, sizeof (sin4)); 2850 sin4.sin_family = AF_INET; 2851 sin4.sin_addr = ifaddr4(n); 2852 nb.buf = (char *)&sin4; 2853 nb.len = sizeof (sin4); 2854 } 2855 2856 nb.maxlen = nb.len; 2857 2858 uaddr = taddr2uaddr(nc, &nb); 2859 return (uaddr); 2860 } 2861 2862 char * 2863 __inet_get_networka(void *p, int n) 2864 { 2865 struct ifinfo *localinfo = (struct ifinfo *)p; 2866 2867 if (localinfo == 0 || n >= localinfo->count) 2868 return (0); 2869 2870 if (ifaf(n) == AF_INET6) { 2871 char buf[INET6_ADDRSTRLEN]; 2872 struct in6_addr in6; 2873 int i; 2874 2875 for (i = 0; i < sizeof (in6.s6_addr); i++) { 2876 in6.s6_addr[i] = ifaddr6(n).s6_addr[i] & 2877 ifmask6(n).s6_addr[i]; 2878 } 2879 return (strdup(inet_ntop(AF_INET6, &in6, buf, sizeof (buf)))); 2880 } else { 2881 struct in_addr in4; 2882 2883 in4.s_addr = ifaddr4(n).s_addr & ifmask4(n).s_addr; 2884 return (strdup(inet_ntoa(in4))); 2885 } 2886 } 2887 2888 static int 2889 in_list(struct in_addr *addrs, int n, struct in_addr a) 2890 { 2891 int i; 2892 2893 for (i = 0; i < n; i++) { 2894 if (addrs[i].s_addr == a.s_addr) 2895 return (1); 2896 } 2897 return (0); 2898 } 2899 2900 static int 2901 getbroadcastnets(struct netconfig *tp, struct in_addr **addrs) 2902 { 2903 struct ifconf ifc; 2904 struct ifreq ifreq, *ifr; 2905 struct sockaddr_in *sin; 2906 struct in_addr a; 2907 int fd; 2908 int n, i, numifs; 2909 char *buf; 2910 int use_loopback = 0; 2911 2912 _nderror = ND_SYSTEM; 2913 fd = open(tp->nc_device, O_RDONLY); 2914 if (fd < 0) { 2915 (void) syslog(LOG_ERR, 2916 "broadcast: open to get interface configuration: %m"); 2917 return (0); 2918 } 2919 if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0) 2920 numifs = MAXIFS; 2921 buf = malloc(numifs * sizeof (struct ifreq)); 2922 if (buf == NULL) { 2923 (void) syslog(LOG_ERR, "broadcast: malloc failed: %m"); 2924 (void) close(fd); 2925 return (0); 2926 } 2927 *addrs = malloc(numifs * sizeof (struct in_addr)); 2928 if (*addrs == NULL) { 2929 (void) syslog(LOG_ERR, "broadcast: malloc failed: %m"); 2930 free(buf); 2931 (void) close(fd); 2932 return (0); 2933 } 2934 ifc.ifc_len = numifs * (int)sizeof (struct ifreq); 2935 ifc.ifc_buf = buf; 2936 /* 2937 * Ideally, this ioctl should also tell me, how many bytes were 2938 * finally allocated, but it doesnt. 2939 */ 2940 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0) { 2941 (void) syslog(LOG_ERR, 2942 "broadcast: ioctl (get interface configuration): %m"); 2943 free(buf); 2944 free(*addrs); 2945 (void) close(fd); 2946 return (0); 2947 } 2948 2949 retry: 2950 /* LINTED pointer cast */ 2951 ifr = (struct ifreq *)buf; 2952 for (i = 0, n = ifc.ifc_len / (int)sizeof (struct ifreq); 2953 n > 0; n--, ifr++) { 2954 ifreq = *ifr; 2955 if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifreq) < 0) { 2956 (void) syslog(LOG_ERR, "broadcast: " 2957 "ioctl (get interface flags): %m"); 2958 continue; 2959 } 2960 if (!(ifreq.ifr_flags & IFF_UP) || 2961 (ifr->ifr_addr.sa_family != AF_INET)) 2962 continue; 2963 if (ifreq.ifr_flags & IFF_BROADCAST) { 2964 /* LINTED pointer cast */ 2965 sin = (struct sockaddr_in *)&ifr->ifr_addr; 2966 if (ioctl(fd, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { 2967 /* May not work with other implementation */ 2968 a = _inet_makeaddr( 2969 inet_netof(sin->sin_addr), 2970 INADDR_ANY); 2971 if (!in_list(*addrs, i, a)) 2972 (*addrs)[i++] = a; 2973 } else { 2974 /* LINTED pointer cast */ 2975 a = ((struct sockaddr_in *) 2976 &ifreq.ifr_addr)->sin_addr; 2977 if (!in_list(*addrs, i, a)) 2978 (*addrs)[i++] = a; 2979 } 2980 continue; 2981 } 2982 if (use_loopback && (ifreq.ifr_flags & IFF_LOOPBACK)) { 2983 /* LINTED pointer cast */ 2984 sin = (struct sockaddr_in *)&ifr->ifr_addr; 2985 a = sin->sin_addr; 2986 if (!in_list(*addrs, i, a)) 2987 (*addrs)[i++] = a; 2988 continue; 2989 } 2990 if (ifreq.ifr_flags & IFF_POINTOPOINT) { 2991 if (ioctl(fd, SIOCGIFDSTADDR, (char *)&ifreq) < 0) 2992 continue; 2993 /* LINTED pointer cast */ 2994 a = ((struct sockaddr_in *) 2995 &ifreq.ifr_addr)->sin_addr; 2996 if (!in_list(*addrs, i, a)) 2997 (*addrs)[i++] = a; 2998 continue; 2999 } 3000 } 3001 if (i == 0 && !use_loopback) { 3002 use_loopback = 1; 3003 goto retry; 3004 } 3005 free(buf); 3006 (void) close(fd); 3007 if (i) 3008 _nderror = ND_OK; 3009 else 3010 free(*addrs); 3011 return (i); 3012 } 3013 3014 /* 3015 * This is lifted straight from libsocket/inet/inet_mkaddr.c. 3016 * Copied here to avoid our dependency on libsocket. More importantly, 3017 * to make sure partially static apps that use libnsl, but not 3018 * libsocket, don't get screwed up. 3019 * If you understand the above paragraph, try to get rid of 3020 * this copy of inet_makeaddr; if you don;t, leave it alone. 3021 * 3022 * Formulate an Internet address from network + host. Used in 3023 * building addresses stored in the ifnet structure. 3024 */ 3025 static struct in_addr 3026 _inet_makeaddr(in_addr_t net, in_addr_t host) 3027 { 3028 in_addr_t addr; 3029 struct in_addr inaddr; 3030 3031 if (net < 128) 3032 addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST); 3033 else if (net < 65536) 3034 addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST); 3035 else if (net < 16777216L) 3036 addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST); 3037 else 3038 addr = net | host; 3039 inaddr.s_addr = htonl(addr); 3040 return (inaddr); 3041 } 3042 3043 /* 3044 * Routine to read the default configuration file and check if SORT_ADDRS 3045 * is set to NO or FALSE. This routine is called by order_haddrlist_af() 3046 * to determine if the addresses need to be sorted. 3047 */ 3048 static boolean_t 3049 _read_nsw_file(void) 3050 { 3051 char defval[LINESIZE]; 3052 FILE *defl; 3053 boolean_t nosort = B_FALSE; 3054 3055 3056 do { 3057 defl = fopen(__NSW_DEFAULT_FILE, "rF"); 3058 } while ((defl == NULL) && (errno == EINTR)); 3059 3060 if (defl == NULL) 3061 return (B_FALSE); 3062 3063 while (fgets(defval, sizeof (defval), defl) != NULL) { 3064 if ((strncmp(DONT_SORT, defval, sizeof (DONT_SORT) - 1) == 0) || 3065 (strncmp(DONT_SORT2, defval, 3066 sizeof (DONT_SORT2) - 1) == 0)) { 3067 nosort = B_TRUE; 3068 break; 3069 } 3070 } 3071 (void) fclose(defl); 3072 return (nosort); 3073 } 3074