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