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