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