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