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