1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 * Copyright 2012 Milan Jurik. All rights reserved. 27 */ 28 29 /* 30 * This is where we have chosen to combine every useful bit of code for 31 * all the Solaris frontends to lookup hosts, services, and netdir information 32 * for inet family (udp, tcp) transports. gethostbyYY(), getservbyYY(), and 33 * netdir_getbyYY() are all implemented on top of this code. Similarly, 34 * netdir_options, taddr2uaddr, and uaddr2taddr for inet transports also 35 * find a home here. 36 * 37 * If the netconfig structure supplied has NO nametoaddr libs (i.e. a "-" 38 * in /etc/netconfig), this code calls the name service switch, and 39 * therefore, /etc/nsswitch.conf is effectively the only place that 40 * dictates hosts/serv lookup policy. 41 * If an administrator chooses to bypass the name service switch by 42 * specifying third party supplied nametoaddr libs in /etc/netconfig, this 43 * implementation does NOT call the name service switch, it merely loops 44 * through the nametoaddr libs. In this case, if this code was called 45 * from gethost/servbyYY() we marshal the inet specific struct into 46 * transport independent netbuf or hostserv, and unmarshal the resulting 47 * nd_addrlist or hostservlist back into hostent and servent, as the case 48 * may be. 49 * 50 * Goes without saying that most of the future bugs in gethost/servbyYY 51 * and netdir_getbyYY are lurking somewhere here. 52 */ 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 static int 165 inetdir_free(int ret, struct in_addr *inaddrs, char **baddrlist) 166 { 167 if (inaddrs) 168 free(inaddrs); 169 if (baddrlist) 170 free(baddrlist); 171 _nderror = ret; 172 return (ret); 173 } 174 175 /* 176 * gethost/servbyname always call this function; if they call 177 * with nametoaddr libs in nconf, we call netdir_getbyname 178 * implementation: __classic_netdir_getbyname, otherwise nsswitch. 179 * 180 * netdir_getbyname calls this only if nametoaddr libs are NOT 181 * specified for inet transports; i.e. it's supposed to follow 182 * the name service switch. 183 */ 184 int 185 _get_hostserv_inetnetdir_byname(struct netconfig *nconf, 186 struct nss_netdirbyname_in *args, union nss_netdirbyname_out *res) 187 { 188 int server_port; 189 int *servp = &server_port; 190 char **haddrlist; 191 uint32_t dotnameaddr; 192 char *dotnamelist[2]; 193 struct in_addr *inaddrs = NULL; 194 struct in6_addr v6nameaddr; 195 char **baddrlist = NULL; 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, 291 "rpcbind") == 0) { 292 *servp = htons(111); 293 } else if (strspn(args->arg.nd_hs->h_serv, 294 "0123456789") == 295 strlen(args->arg.nd_hs->h_serv)) { 296 *servp = htons(atoi(args->arg.nd_hs->h_serv)); 297 } else { 298 /* i.e. need to call a name service on this */ 299 servp = NULL; 300 } 301 302 /* 303 * If the hostname is HOST_SELF_BIND, we return 0.0.0.0 304 * so the binding can be contacted through all 305 * interfaces. If the hostname is HOST_SELF_CONNECT, 306 * we return 127.0.0.1 so the address can be connected 307 * to locally. If the hostname is HOST_ANY, we return 308 * no addresses because IP doesn't know how to specify 309 * a service without a host. And finally if we specify 310 * HOST_BROADCAST then we ask a tli fd to tell us what 311 * the broadcast addresses are for any udp 312 * interfaces on this machine. 313 */ 314 if (args->arg.nd_hs->h_host == 0) { 315 _nderror = ND_NOHOST; 316 return (ND_NOHOST); 317 } else if ((strcmp(args->arg.nd_hs->h_host, 318 HOST_SELF_BIND) == 0)) { 319 haddrlist = localaddr; 320 } else if ((strcmp(args->arg.nd_hs->h_host, 321 HOST_SELF_CONNECT) == 0)) { 322 haddrlist = connectaddr; 323 } else if ((strcmp(args->arg.nd_hs->h_host, 324 LOCALHOST) == 0)) { 325 haddrlist = connectaddr; 326 } else if ((int)(dotnameaddr = 327 inet_addr(args->arg.nd_hs->h_host)) != -1) { 328 /* 329 * If the caller passed in a dot separated IP 330 * notation to netdir_getbyname, convert that 331 * back into address. 332 */ 333 334 dotnamelist[0] = (char *)&dotnameaddr; 335 dotnamelist[1] = NULL; 336 haddrlist = dotnamelist; 337 } else if ((strcmp(args->arg.nd_hs->h_host, 338 HOST_BROADCAST) == 0)) { 339 /* 340 * Now that inaddrs and baddrlist are 341 * dynamically allocated, care must be 342 * taken in freeing up the 343 * memory at each 'return()' point. 344 * 345 * Early return protection (using 346 * inetdir_free()) is needed only in NETDIR_BY 347 * cases because dynamic allocation is used 348 * when args->op_t == NETDIR_BY. 349 * 350 * Early return protection is not needed in 351 * haddrlist==0 conditionals because dynamic 352 * allocation guarantees haddrlist!=0. 353 * 354 * Early return protection is not needed in most 355 * servp!=0 conditionals because this is handled 356 * (and returned) first. 357 */ 358 int i, bnets; 359 360 bnets = getbroadcastnets(nconf, &inaddrs); 361 if (bnets == 0) { 362 _nderror = ND_NOHOST; 363 return (ND_NOHOST); 364 } 365 baddrlist = malloc((bnets+1)*sizeof (char *)); 366 if (baddrlist == NULL) 367 return (inetdir_free(ND_NOMEM, inaddrs, 368 baddrlist)); 369 for (i = 0; i < bnets; i++) 370 baddrlist[i] = (char *)&inaddrs[i]; 371 baddrlist[i] = NULL; 372 haddrlist = baddrlist; 373 } else { 374 /* i.e. need to call a name service on this */ 375 haddrlist = 0; 376 } 377 378 if (haddrlist && servp) { 379 int ret; 380 /* 381 * Convert h_addr_list into nd_addrlist. 382 * malloc's will be done, freed using 383 * netdir_free. 384 */ 385 ret = hent2ndaddr(AF_INET, haddrlist, servp, 386 res->nd_alist); 387 return (inetdir_free(ret, inaddrs, baddrlist)); 388 } 389 break; 390 391 392 case NETDIR_BY6: 393 if (args->arg.nd_hs == 0) { 394 _nderror = ND_BADARG; 395 return (ND_BADARG); 396 } 397 /* 398 * If servname is NULL, return 0 as the port number. 399 * If servname is rpcbind, return 111 as the port number 400 * If servname is a number, return it back as the port 401 * number. 402 */ 403 if (args->arg.nd_hs->h_serv == 0) { 404 *servp = htons(0); 405 } else if (strcmp(args->arg.nd_hs->h_serv, 406 "rpcbind") == 0) { 407 *servp = htons(111); 408 } else if (strspn(args->arg.nd_hs->h_serv, "0123456789") 409 == strlen(args->arg.nd_hs->h_serv)) { 410 *servp = htons(atoi(args->arg.nd_hs->h_serv)); 411 } else { 412 /* i.e. need to call a name service on this */ 413 servp = NULL; 414 } 415 416 /* 417 * If the hostname is HOST_SELF_BIND, we return ipv6 418 * localaddress so the binding can be contacted through 419 * all interfaces. 420 * If the hostname is HOST_SELF_CONNECT, we return 421 * ipv6 loopback address so the address can be connected 422 * to locally. 423 * If the hostname is HOST_ANY, we return no addresses 424 * because IP doesn't know how to specify a service 425 * without a host. 426 * And finally if we specify HOST_BROADCAST then we 427 * disallow since IPV6 does not have any 428 * broadcast concept. 429 */ 430 if (args->arg.nd_hs->h_host == 0) { 431 return (ND_NOHOST); 432 } else if ((strcmp(args->arg.nd_hs->h_host, 433 HOST_SELF_BIND) == 0)) { 434 haddrlist = localaddr6; 435 } else if ((strcmp(args->arg.nd_hs->h_host, 436 HOST_SELF_CONNECT) == 0)) { 437 haddrlist = connectaddr6; 438 } else if ((strcmp(args->arg.nd_hs->h_host, 439 LOCALHOST) == 0)) { 440 haddrlist = connectaddr6; 441 } else if (strchr(args->arg.nd_hs->h_host, ':') 442 != NULL) { 443 444 /* 445 * If the caller passed in a dot separated IP notation 446 * to netdir_getbyname, convert that back into address. 447 */ 448 449 if ((inet_pton(AF_INET6, 450 args->arg.nd_hs->h_host, 451 &v6nameaddr)) != 0) { 452 dotnamelist[0] = (char *)&v6nameaddr; 453 dotnamelist[1] = NULL; 454 haddrlist = dotnamelist; 455 } 456 else 457 /* not sure what to return */ 458 return (ND_NOHOST); 459 460 } else if ((strcmp(args->arg.nd_hs->h_host, 461 HOST_BROADCAST) == 0)) { 462 /* 463 * Don't support broadcast in 464 * IPV6 465 */ 466 return (ND_NOHOST); 467 } else { 468 /* i.e. need to call a name service on this */ 469 haddrlist = 0; 470 } 471 472 if (haddrlist && servp) { 473 int ret; 474 /* 475 * Convert h_addr_list into nd_addrlist. 476 * malloc's will be done, freed 477 * using netdir_free. 478 */ 479 ret = hent2ndaddr(AF_INET6, haddrlist, 480 servp, res->nd_alist); 481 return (inetdir_free(ret, inaddrs, baddrlist)); 482 } 483 break; 484 485 486 } 487 488 /* 489 * 2. Most common scenario. This is the way we ship /etc/netconfig. 490 * Emphasis on improving performance in the "if" part. 491 */ 492 if (nconf->nc_nlookups == 0) { 493 struct hostent *he = NULL, *tmphe; 494 struct servent *se; 495 int ret; 496 nss_XbyY_buf_t *ndbuf4switch = 0; 497 498 switch (args->op_t) { 499 500 case NSS_HOST: 501 502 he = DOOR_GETHOSTBYNAME_R(args->arg.nss.host.name, 503 res->nss.host.hent, args->arg.nss.host.buf, 504 args->arg.nss.host.buflen, 505 res->nss.host.herrno_p); 506 if (he == NULL) 507 return (_nderror = ND_NOHOST); 508 return (_nderror = ND_OK); 509 510 case NSS_HOST6: 511 512 he = DOOR_GETIPNODEBYNAME_R(args->arg.nss.host6.name, 513 res->nss.host.hent, args->arg.nss.host.buf, 514 args->arg.nss.host6.buflen, 515 args->arg.nss.host6.af_family, 516 args->arg.nss.host6.flags, 517 res->nss.host.herrno_p); 518 519 if (he == NULL) 520 return (_nderror = ND_NOHOST); 521 return (_nderror = ND_OK); 522 523 case NSS_SERV: 524 525 se = _switch_getservbyname_r(args->arg.nss.serv.name, 526 args->arg.nss.serv.proto, 527 res->nss.serv, args->arg.nss.serv.buf, 528 args->arg.nss.serv.buflen); 529 530 _nderror = ND_OK; 531 if (se == 0) 532 _nderror = ND_NOSERV; 533 return (_nderror); 534 535 case NETDIR_BY: 536 537 if (servp == 0) { 538 char *proto = (strcmp(nconf->nc_proto, 539 NC_TCP) == 0) ? NC_TCP : NC_UDP; 540 541 /* 542 * We go through all this for just one port number, 543 * which is most often constant. How about linking in 544 * an indexed database of well-known ports in the name 545 * of performance ? 546 */ 547 ndbuf4switch = _nss_XbyY_buf_alloc( 548 sizeof (struct servent), NSS_BUFLEN_SERVICES); 549 if (ndbuf4switch == 0) 550 return (inetdir_free(ND_NOMEM, inaddrs, 551 baddrlist)); 552 se = _switch_getservbyname_r(args->arg.nd_hs->h_serv, 553 proto, ndbuf4switch->result, 554 ndbuf4switch->buffer, ndbuf4switch->buflen); 555 if (!se) { 556 NSS_XbyY_FREE(&ndbuf4switch); 557 return (inetdir_free(ND_NOSERV, inaddrs, 558 baddrlist)); 559 } 560 server_port = se->s_port; 561 NSS_XbyY_FREE(&ndbuf4switch); 562 } 563 564 if (haddrlist == 0) { 565 int h_errnop = 0; 566 567 ndbuf4switch = _nss_XbyY_buf_alloc( 568 sizeof (struct hostent), 569 NSS_BUFLEN_HOSTS); 570 if (ndbuf4switch == 0) { 571 _nderror = ND_NOMEM; 572 return (ND_NOMEM); 573 } 574 /* 575 * Search the ipnodes (v6) path first, 576 * search will return the v4 addresses 577 * as v4mapped addresses. 578 */ 579 if ((tmphe = DOOR_GETIPNODEBYNAME_R( 580 args->arg.nd_hs->h_host, 581 ndbuf4switch->result, ndbuf4switch->buffer, 582 ndbuf4switch->buflen, args->arg.nss.host6.af_family, 583 args->arg.nss.host6.flags, &h_errnop)) != NULL) 584 he = __mappedtov4(tmphe, &h_errnop); 585 586 if (he == NULL) { 587 /* Failover case, try hosts db for v4 address */ 588 he = DOOR_GETHOSTBYNAME_R( 589 args->arg.nd_hs->h_host, 590 ndbuf4switch->result, ndbuf4switch->buffer, 591 ndbuf4switch->buflen, &h_errnop); 592 if (he == NULL) { 593 NSS_XbyY_FREE(&ndbuf4switch); 594 _nderror = __herrno2netdir(h_errnop); 595 return (_nderror); 596 } 597 /* 598 * Convert h_addr_list into nd_addrlist. 599 * malloc's will be done, freed using 600 * netdir_free. 601 */ 602 ret = hent2ndaddr(AF_INET, he->h_addr_list, 603 &server_port, res->nd_alist); 604 } else { 605 /* 606 * Convert h_addr_list into nd_addrlist. 607 * malloc's will be done, freed using 608 * netdir_free. 609 */ 610 ret = hent2ndaddr(AF_INET, he->h_addr_list, 611 &server_port, res->nd_alist); 612 freehostent(he); 613 } 614 615 _nderror = ret; 616 NSS_XbyY_FREE(&ndbuf4switch); 617 return (ret); 618 } else { 619 int ret; 620 /* 621 * Convert h_addr_list into nd_addrlist. 622 * malloc's will be done, freed using netdir_free. 623 */ 624 ret = hent2ndaddr(AF_INET, haddrlist, 625 &server_port, res->nd_alist); 626 return (inetdir_free(ret, inaddrs, baddrlist)); 627 } 628 629 630 case NETDIR_BY6: 631 632 if (servp == 0) { 633 char *proto = (strcmp(nconf->nc_proto, 634 NC_TCP) == 0) ? NC_TCP : NC_UDP; 635 636 /* 637 * We go through all this for just 638 * one port number, 639 * which is most often constant. 640 * How about linking in 641 * an indexed database of well-known 642 * ports in the name 643 * of performance ? 644 */ 645 ndbuf4switch = _nss_XbyY_buf_alloc( 646 sizeof (struct servent), 647 NSS_BUFLEN_SERVICES); 648 if (ndbuf4switch == 0) 649 return (inetdir_free(ND_NOMEM, inaddrs, 650 baddrlist)); 651 se = _switch_getservbyname_r( 652 args->arg.nd_hs->h_serv, 653 proto, ndbuf4switch->result, 654 ndbuf4switch->buffer, ndbuf4switch->buflen); 655 if (!se) { 656 NSS_XbyY_FREE(&ndbuf4switch); 657 return (inetdir_free(ND_NOSERV, inaddrs, 658 baddrlist)); 659 } 660 server_port = se->s_port; 661 NSS_XbyY_FREE(&ndbuf4switch); 662 } 663 664 if (haddrlist == 0) { 665 int h_errnop = 0; 666 667 ndbuf4switch = _nss_XbyY_buf_alloc( 668 sizeof (struct hostent), 669 NSS_BUFLEN_HOSTS); 670 if (ndbuf4switch == 0) { 671 _nderror = ND_NOMEM; 672 return (ND_NOMEM); 673 } 674 he = DOOR_GETIPNODEBYNAME_R( 675 args->arg.nd_hs->h_host, 676 ndbuf4switch->result, ndbuf4switch->buffer, 677 ndbuf4switch->buflen, 678 args->arg.nss.host6.af_family, 679 args->arg.nss.host6.flags, &h_errnop); 680 if (he == NULL) { 681 NSS_XbyY_FREE(&ndbuf4switch); 682 _nderror = __herrno2netdir(h_errnop); 683 return (_nderror); 684 } 685 /* 686 * Convert h_addr_list into nd_addrlist. 687 * malloc's will be done, 688 * freed using netdir_free. 689 */ 690 ret = hent2ndaddr(AF_INET6, 691 ((struct hostent *) 692 (ndbuf4switch->result))->h_addr_list, 693 &server_port, res->nd_alist); 694 _nderror = ret; 695 NSS_XbyY_FREE(&ndbuf4switch); 696 return (ret); 697 } else { 698 int ret; 699 /* 700 * Convert h_addr_list into nd_addrlist. 701 * malloc's will be done, 702 * freed using netdir_free. 703 */ 704 ret = hent2ndaddr(AF_INET6, haddrlist, 705 &server_port, res->nd_alist); 706 return (inetdir_free(ret, inaddrs, baddrlist)); 707 } 708 709 default: 710 _nderror = ND_BADARG; 711 return (ND_BADARG); /* should never happen */ 712 } 713 714 } else { 715 /* haddrlist is no longer used, so clean up */ 716 if (inaddrs) 717 free(inaddrs); 718 if (baddrlist) 719 free(baddrlist); 720 } 721 722 /* 723 * 3. We come this far only if nametoaddr libs are specified for 724 * inet transports and we are called by gethost/servbyname only. 725 */ 726 switch (args->op_t) { 727 struct nd_hostserv service; 728 struct nd_addrlist *addrs; 729 int ret; 730 731 case NSS_HOST: 732 733 service.h_host = (char *)args->arg.nss.host.name; 734 service.h_serv = NULL; 735 if ((_nderror = __classic_netdir_getbyname(nconf, 736 &service, &addrs)) != ND_OK) { 737 *(res->nss.host.herrno_p) = nd2herrno(_nderror); 738 return (_nderror); 739 } 740 /* 741 * convert addresses back into sockaddr for gethostbyname. 742 */ 743 ret = ndaddr2hent(AF_INET, service.h_host, addrs, 744 res->nss.host.hent, args->arg.nss.host.buf, 745 args->arg.nss.host.buflen); 746 if (ret != ND_OK) 747 *(res->nss.host.herrno_p) = nd2herrno(ret); 748 netdir_free((char *)addrs, ND_ADDRLIST); 749 _nderror = ret; 750 return (ret); 751 752 case NSS_SERV: 753 754 if (args->arg.nss.serv.proto == NULL) { 755 /* 756 * A similar HACK showed up in Solaris 2.3. 757 * The caller wild-carded proto -- i.e. will 758 * accept a match using tcp or udp for the port 759 * number. Since we have no hope of getting 760 * directly to a name service switch backend 761 * from here that understands this semantics, 762 * we try calling the netdir interfaces first 763 * with "tcp" and then "udp". 764 */ 765 args->arg.nss.serv.proto = "tcp"; 766 _nderror = _get_hostserv_inetnetdir_byname(nconf, args, 767 res); 768 if (_nderror != ND_OK) { 769 args->arg.nss.serv.proto = "udp"; 770 _nderror = 771 _get_hostserv_inetnetdir_byname(nconf, 772 args, res); 773 } 774 return (_nderror); 775 } 776 777 /* 778 * Third-parties should optimize their nametoaddr 779 * libraries for the HOST_SELF case. 780 */ 781 service.h_host = HOST_SELF; 782 service.h_serv = (char *)args->arg.nss.serv.name; 783 if ((_nderror = __classic_netdir_getbyname(nconf, 784 &service, &addrs)) != ND_OK) { 785 return (_nderror); 786 } 787 /* 788 * convert addresses back into servent for getservbyname. 789 */ 790 _nderror = ndaddr2srent(service.h_serv, 791 args->arg.nss.serv.proto, 792 /* LINTED pointer cast */ 793 ((struct sockaddr_in *)addrs->n_addrs->buf)->sin_port, 794 res->nss.serv, 795 args->arg.nss.serv.buf, args->arg.nss.serv.buflen); 796 netdir_free((char *)addrs, ND_ADDRLIST); 797 return (_nderror); 798 799 default: 800 _nderror = ND_BADARG; 801 return (ND_BADARG); /* should never happen */ 802 } 803 } 804 805 /* 806 * gethostbyaddr/servbyport always call this function; if they call 807 * with nametoaddr libs in nconf, we call netdir_getbyaddr 808 * implementation __classic_netdir_getbyaddr, otherwise nsswitch. 809 * 810 * netdir_getbyaddr calls this only if nametoaddr libs are NOT 811 * specified for inet transports; i.e. it's supposed to follow 812 * the name service switch. 813 */ 814 int 815 _get_hostserv_inetnetdir_byaddr(struct netconfig *nconf, 816 struct nss_netdirbyaddr_in *args, union nss_netdirbyaddr_out *res) 817 { 818 if (nconf == 0) { 819 _nderror = ND_BADARG; 820 return (_nderror); 821 } 822 823 /* 824 * 1. gethostbyaddr()/netdir_getbyaddr() special cases: 825 */ 826 switch (args->op_t) { 827 828 case NSS_HOST: 829 /* 830 * Worth the performance gain: assuming a lot of inet apps 831 * actively use "127.0.0.1". 832 */ 833 /* LINTED pointer cast */ 834 if (*(uint32_t *)(args->arg.nss.host.addr) == 835 htonl(INADDR_LOOPBACK)) { 836 (void) mutex_lock(&nd_addr_lock); 837 IN_SET_LOOPBACK_ADDR(&sa_con); 838 _nderror = ndaddr2hent(AF_INET, LOCALHOST, 839 &nd_conaddrlist, res->nss.host.hent, 840 args->arg.nss.host.buf, 841 args->arg.nss.host.buflen); 842 (void) mutex_unlock(&nd_addr_lock); 843 if (_nderror != ND_OK) 844 *(res->nss.host.herrno_p) = 845 nd2herrno(_nderror); 846 return (_nderror); 847 } 848 break; 849 850 case NETDIR_BY: 851 case NETDIR_BY_NOSRV: 852 { 853 struct sockaddr_in *sin; 854 855 if (args->arg.nd_nbuf == NULL) { 856 _nderror = ND_BADARG; 857 return (_nderror); 858 } 859 860 /* 861 * Validate the address which was passed 862 * as the request. 863 */ 864 /* LINTED pointer cast */ 865 sin = (struct sockaddr_in *)args->arg.nd_nbuf->buf; 866 867 if ((args->arg.nd_nbuf->len != 868 sizeof (struct sockaddr_in)) || 869 (sin->sin_family != AF_INET)) { 870 _nderror = ND_BADARG; 871 return (_nderror); 872 } 873 } 874 break; 875 876 case NETDIR_BY6: 877 case NETDIR_BY_NOSRV6: 878 { 879 struct sockaddr_in6 *sin6; 880 881 if (args->arg.nd_nbuf == NULL) { 882 _nderror = ND_BADARG; 883 return (_nderror); 884 } 885 886 /* 887 * Validate the address which was passed 888 * as the request. 889 */ 890 /* LINTED pointer cast */ 891 sin6 = (struct sockaddr_in6 *)args->arg.nd_nbuf->buf; 892 893 if ((args->arg.nd_nbuf->len != 894 sizeof (struct sockaddr_in6)) || 895 (sin6->sin6_family != AF_INET6)) { 896 _nderror = ND_BADARG; 897 return (_nderror); 898 } 899 } 900 break; 901 902 } 903 904 /* 905 * 2. Most common scenario. This is the way we ship /etc/netconfig. 906 * Emphasis on improving performance in the "if" part. 907 */ 908 if (nconf->nc_nlookups == 0) { 909 struct hostent *he = NULL, *tmphe; 910 struct servent *se = NULL; 911 nss_XbyY_buf_t *ndbuf4host = 0; 912 nss_XbyY_buf_t *ndbuf4serv = 0; 913 char *proto = 914 (strcmp(nconf->nc_proto, NC_TCP) == 0) ? NC_TCP : NC_UDP; 915 struct sockaddr_in *sa; 916 struct sockaddr_in6 *sin6; 917 struct in_addr *addr4 = 0; 918 struct in6_addr v4mapbuf; 919 int h_errnop; 920 921 switch (args->op_t) { 922 923 case NSS_HOST: 924 925 he = DOOR_GETHOSTBYADDR_R(args->arg.nss.host.addr, 926 args->arg.nss.host.len, args->arg.nss.host.type, 927 res->nss.host.hent, args->arg.nss.host.buf, 928 args->arg.nss.host.buflen, 929 res->nss.host.herrno_p); 930 if (he == 0) 931 _nderror = ND_NOHOST; 932 else 933 _nderror = ND_OK; 934 return (_nderror); 935 936 937 case NSS_HOST6: 938 he = DOOR_GETIPNODEBYADDR_R(args->arg.nss.host.addr, 939 args->arg.nss.host.len, args->arg.nss.host.type, 940 res->nss.host.hent, args->arg.nss.host.buf, 941 args->arg.nss.host.buflen, 942 res->nss.host.herrno_p); 943 944 if (he == 0) 945 return (ND_NOHOST); 946 return (ND_OK); 947 948 949 case NSS_SERV: 950 951 se = _switch_getservbyport_r(args->arg.nss.serv.port, 952 args->arg.nss.serv.proto, 953 res->nss.serv, args->arg.nss.serv.buf, 954 args->arg.nss.serv.buflen); 955 956 if (se == 0) 957 _nderror = ND_NOSERV; 958 else 959 _nderror = ND_OK; 960 return (_nderror); 961 962 case NETDIR_BY: 963 case NETDIR_BY_NOSRV: 964 965 ndbuf4serv = _nss_XbyY_buf_alloc(sizeof (struct servent), 966 NSS_BUFLEN_SERVICES); 967 if (ndbuf4serv == 0) { 968 _nderror = ND_NOMEM; 969 return (_nderror); 970 } 971 /* LINTED pointer cast */ 972 sa = (struct sockaddr_in *)(args->arg.nd_nbuf->buf); 973 addr4 = (struct in_addr *)&(sa->sin_addr); 974 975 /* 976 * if NETDIR_BY_NOSRV or port == 0 skip the service 977 * lookup. 978 */ 979 if (args->op_t != NETDIR_BY_NOSRV && sa->sin_port != 0) { 980 se = _switch_getservbyport_r(sa->sin_port, proto, 981 ndbuf4serv->result, ndbuf4serv->buffer, 982 ndbuf4serv->buflen); 983 if (!se) { 984 NSS_XbyY_FREE(&ndbuf4serv); 985 /* 986 * We can live with this - i.e. the address 987 * does not 988 * belong to a well known service. The caller 989 * traditionally accepts a stringified port 990 * number 991 * as the service name. The state of se is used 992 * ahead to indicate the same. 993 * However, we do not tolerate this nonsense 994 * when we cannot get a host name. See below. 995 */ 996 } 997 } 998 999 ndbuf4host = _nss_XbyY_buf_alloc(sizeof (struct hostent), 1000 NSS_BUFLEN_HOSTS); 1001 if (ndbuf4host == 0) { 1002 if (ndbuf4serv) 1003 NSS_XbyY_FREE(&ndbuf4serv); 1004 _nderror = ND_NOMEM; 1005 return (_nderror); 1006 } 1007 1008 /* 1009 * Since we're going to search the ipnodes (v6) path first, 1010 * we need to treat the address as a v4mapped address. 1011 */ 1012 1013 IN6_INADDR_TO_V4MAPPED(addr4, &v4mapbuf); 1014 if ((tmphe = DOOR_GETIPNODEBYADDR_R((char *)&v4mapbuf, 1015 16, AF_INET6, ndbuf4host->result, 1016 ndbuf4host->buffer, 1017 ndbuf4host->buflen, &h_errnop)) != NULL) 1018 he = __mappedtov4(tmphe, &h_errnop); 1019 1020 if (!he) { 1021 /* Failover case, try hosts db for v4 address */ 1022 he = DOOR_GETHOSTBYADDR_R((char *) 1023 &(sa->sin_addr.s_addr), 4, 1024 sa->sin_family, ndbuf4host->result, 1025 ndbuf4host->buffer, ndbuf4host->buflen, 1026 &h_errnop); 1027 if (!he) { 1028 NSS_XbyY_FREE(&ndbuf4host); 1029 if (ndbuf4serv) 1030 NSS_XbyY_FREE(&ndbuf4serv); 1031 _nderror = __herrno2netdir(h_errnop); 1032 return (_nderror); 1033 } 1034 /* 1035 * Convert host names and service names into hostserv 1036 * pairs. malloc's will be done, freed using 1037 * netdir_free. 1038 */ 1039 h_errnop = hsents2ndhostservs(he, se, 1040 sa->sin_port, res->nd_hslist); 1041 } else { 1042 /* 1043 * Convert host names and service names into hostserv 1044 * pairs. malloc's will be done, freed using 1045 * netdir_free. 1046 */ 1047 h_errnop = hsents2ndhostservs(he, se, 1048 sa->sin_port, res->nd_hslist); 1049 freehostent(he); 1050 } 1051 1052 NSS_XbyY_FREE(&ndbuf4host); 1053 if (ndbuf4serv) 1054 NSS_XbyY_FREE(&ndbuf4serv); 1055 _nderror = __herrno2netdir(h_errnop); 1056 return (_nderror); 1057 1058 case NETDIR_BY6: 1059 case NETDIR_BY_NOSRV6: 1060 1061 ndbuf4serv = _nss_XbyY_buf_alloc(sizeof (struct servent), 1062 NSS_BUFLEN_SERVICES); 1063 if (ndbuf4serv == 0) { 1064 _nderror = ND_NOMEM; 1065 return (ND_NOMEM); 1066 } 1067 /* LINTED pointer cast */ 1068 sin6 = (struct sockaddr_in6 *)(args->arg.nd_nbuf->buf); 1069 1070 /* 1071 * if NETDIR_BY_NOSRV6 or port == 0 skip the service 1072 * lookup. 1073 */ 1074 if (args->op_t != NETDIR_BY_NOSRV6 && sin6->sin6_port == 0) { 1075 se = _switch_getservbyport_r(sin6->sin6_port, proto, 1076 ndbuf4serv->result, ndbuf4serv->buffer, 1077 ndbuf4serv->buflen); 1078 if (!se) { 1079 NSS_XbyY_FREE(&ndbuf4serv); 1080 /* 1081 * We can live with this - i.e. the address does 1082 * not * belong to a well known service. The 1083 * caller traditionally accepts a stringified 1084 * port number 1085 * as the service name. The state of se is used 1086 * ahead to indicate the same. 1087 * However, we do not tolerate this nonsense 1088 * when we cannot get a host name. See below. 1089 */ 1090 } 1091 } 1092 1093 ndbuf4host = _nss_XbyY_buf_alloc(sizeof (struct hostent), 1094 NSS_BUFLEN_HOSTS); 1095 if (ndbuf4host == 0) { 1096 if (ndbuf4serv) 1097 NSS_XbyY_FREE(&ndbuf4serv); 1098 _nderror = ND_NOMEM; 1099 return (_nderror); 1100 } 1101 he = DOOR_GETIPNODEBYADDR_R((char *)&(sin6->sin6_addr), 1102 16, sin6->sin6_family, ndbuf4host->result, 1103 ndbuf4host->buffer, 1104 ndbuf4host->buflen, &h_errnop); 1105 if (!he) { 1106 NSS_XbyY_FREE(&ndbuf4host); 1107 if (ndbuf4serv) 1108 NSS_XbyY_FREE(&ndbuf4serv); 1109 _nderror = __herrno2netdir(h_errnop); 1110 return (_nderror); 1111 } 1112 /* 1113 * Convert host names and service names into hostserv 1114 * pairs. malloc's will be done, freed using netdir_free. 1115 */ 1116 h_errnop = hsents2ndhostservs(he, se, 1117 sin6->sin6_port, res->nd_hslist); 1118 1119 NSS_XbyY_FREE(&ndbuf4host); 1120 if (ndbuf4serv) 1121 NSS_XbyY_FREE(&ndbuf4serv); 1122 _nderror = __herrno2netdir(h_errnop); 1123 return (_nderror); 1124 1125 default: 1126 _nderror = ND_BADARG; 1127 return (_nderror); /* should never happen */ 1128 } 1129 1130 } 1131 /* 1132 * 3. We come this far only if nametoaddr libs are specified for 1133 * inet transports and we are called by gethost/servbyname only. 1134 */ 1135 switch (args->op_t) { 1136 struct netbuf nbuf; 1137 struct nd_hostservlist *addrs; 1138 struct sockaddr_in sa; 1139 1140 case NSS_HOST: 1141 1142 /* LINTED pointer cast */ 1143 sa.sin_addr.s_addr = *(uint32_t *)args->arg.nss.host.addr; 1144 sa.sin_family = AF_INET; 1145 /* Hopefully, third-parties get this optimization */ 1146 sa.sin_port = 0; 1147 nbuf.buf = (char *)&sa; 1148 nbuf.len = nbuf.maxlen = sizeof (sa); 1149 if ((_nderror = __classic_netdir_getbyaddr(nconf, 1150 &addrs, &nbuf)) != 0) { 1151 *(res->nss.host.herrno_p) = nd2herrno(_nderror); 1152 return (_nderror); 1153 } 1154 /* 1155 * convert the host-serv pairs into h_aliases and hent. 1156 */ 1157 _nderror = ndhostserv2hent(&nbuf, addrs, res->nss.host.hent, 1158 args->arg.nss.host.buf, args->arg.nss.host.buflen); 1159 if (_nderror != ND_OK) 1160 *(res->nss.host.herrno_p) = nd2herrno(_nderror); 1161 netdir_free((char *)addrs, ND_HOSTSERVLIST); 1162 return (_nderror); 1163 1164 case NSS_SERV: 1165 1166 if (args->arg.nss.serv.proto == NULL) { 1167 /* 1168 * A similar HACK showed up in Solaris 2.3. 1169 * The caller wild-carded proto -- i.e. will 1170 * accept a match on tcp or udp for the port 1171 * number. Since we have no hope of getting 1172 * directly to a name service switch backend 1173 * from here that understands this semantics, 1174 * we try calling the netdir interfaces first 1175 * with "tcp" and then "udp". 1176 */ 1177 args->arg.nss.serv.proto = "tcp"; 1178 _nderror = _get_hostserv_inetnetdir_byaddr(nconf, args, 1179 res); 1180 if (_nderror != ND_OK) { 1181 args->arg.nss.serv.proto = "udp"; 1182 _nderror = 1183 _get_hostserv_inetnetdir_byaddr(nconf, 1184 args, res); 1185 } 1186 return (_nderror); 1187 } 1188 1189 /* 1190 * Third-party nametoaddr_libs should be optimized for 1191 * this case. It also gives a special semantics twist to 1192 * netdir_getbyaddr. Only for the INADDR_ANY case, it gives 1193 * higher priority to service lookups (over host lookups). 1194 * If service lookup fails, the backend returns ND_NOSERV to 1195 * facilitate lookup in the "next" naming service. 1196 * BugId: 1075403. 1197 */ 1198 sa.sin_addr.s_addr = INADDR_ANY; 1199 sa.sin_family = AF_INET; 1200 sa.sin_port = (ushort_t)args->arg.nss.serv.port; 1201 sa.sin_zero[0] = '\0'; 1202 nbuf.buf = (char *)&sa; 1203 nbuf.len = nbuf.maxlen = sizeof (sa); 1204 if ((_nderror = __classic_netdir_getbyaddr(nconf, 1205 &addrs, &nbuf)) != ND_OK) { 1206 return (_nderror); 1207 } 1208 /* 1209 * convert the host-serv pairs into s_aliases and servent. 1210 */ 1211 _nderror = ndhostserv2srent(args->arg.nss.serv.port, 1212 args->arg.nss.serv.proto, addrs, res->nss.serv, 1213 args->arg.nss.serv.buf, args->arg.nss.serv.buflen); 1214 netdir_free((char *)addrs, ND_HOSTSERVLIST); 1215 return (_nderror); 1216 1217 default: 1218 _nderror = ND_BADARG; 1219 return (_nderror); /* should never happen */ 1220 } 1221 } 1222 1223 /* 1224 * Part II: Name Service Switch interfacing routines. 1225 */ 1226 1227 static DEFINE_NSS_DB_ROOT(db_root_hosts); 1228 static DEFINE_NSS_DB_ROOT(db_root_ipnodes); 1229 static DEFINE_NSS_DB_ROOT(db_root_services); 1230 1231 1232 /* 1233 * There is a copy of __nss2herrno() in nsswitch/files/gethostent.c. 1234 * It is there because /etc/lib/nss_files.so.1 cannot call 1235 * routines in libnsl. Care should be taken to keep the two copies 1236 * in sync (except that case NSS_NISSERVDNS_TRYAGAIN is not needed in 1237 * nsswitch/files). 1238 */ 1239 int 1240 __nss2herrno(nss_status_t nsstat) 1241 { 1242 switch (nsstat) { 1243 case NSS_SUCCESS: 1244 /* no macro-defined success code for h_errno */ 1245 return (0); 1246 case NSS_NOTFOUND: 1247 return (HOST_NOT_FOUND); 1248 case NSS_TRYAGAIN: 1249 return (TRY_AGAIN); 1250 case NSS_UNAVAIL: 1251 return (NO_RECOVERY); 1252 case NSS_NISSERVDNS_TRYAGAIN: 1253 return (TRY_AGAIN); 1254 } 1255 /* anything else */ 1256 return (NO_RECOVERY); 1257 } 1258 1259 nss_status_t 1260 _herrno2nss(int h_errno) 1261 { 1262 switch (h_errno) { 1263 case 0: 1264 return (NSS_SUCCESS); 1265 case TRY_AGAIN: 1266 return (NSS_TRYAGAIN); 1267 case NO_RECOVERY: 1268 case NETDB_INTERNAL: 1269 return (NSS_UNAVAIL); 1270 case HOST_NOT_FOUND: 1271 case NO_DATA: 1272 default: 1273 return (NSS_NOTFOUND); 1274 } 1275 } 1276 1277 static int 1278 __herrno2netdir(int h_errnop) 1279 { 1280 switch (h_errnop) { 1281 case 0: 1282 return (ND_OK); 1283 case HOST_NOT_FOUND: 1284 return (ND_NOHOST); 1285 case TRY_AGAIN: 1286 return (ND_TRY_AGAIN); 1287 case NO_RECOVERY: 1288 case NETDB_INTERNAL: 1289 return (ND_NO_RECOVERY); 1290 case NO_DATA: 1291 return (ND_NO_DATA); 1292 default: 1293 return (ND_NOHOST); 1294 } 1295 } 1296 1297 /* 1298 * The _switch_getXXbyYY_r() routines should be static. They used to 1299 * be exported in SunOS 5.3, and in fact publicised as work-around 1300 * interfaces for getting CNAME/aliases, and therefore, we preserve 1301 * their signatures here. Just in case. 1302 */ 1303 1304 struct hostent * 1305 _switch_gethostbyname_r(const char *name, struct hostent *result, char *buffer, 1306 int buflen, int *h_errnop) 1307 { 1308 nss_XbyY_args_t arg; 1309 nss_status_t res; 1310 1311 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent); 1312 arg.key.name = name; 1313 arg.stayopen = 0; 1314 res = nss_search(&db_root_hosts, _nss_initf_hosts, 1315 NSS_DBOP_HOSTS_BYNAME, &arg); 1316 arg.status = res; 1317 if (res != NSS_SUCCESS) 1318 *h_errnop = arg.h_errno ? arg.h_errno : __nss2herrno(res); 1319 if (arg.returnval != NULL) 1320 order_haddrlist_af(result->h_addrtype, result->h_addr_list); 1321 return ((struct hostent *)NSS_XbyY_FINI(&arg)); 1322 } 1323 1324 struct hostent * 1325 _switch_getipnodebyname_r(const char *name, struct hostent *result, 1326 char *buffer, int buflen, int af_family, int flags, int *h_errnop) 1327 { 1328 nss_XbyY_args_t arg; 1329 nss_status_t res; 1330 1331 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent6); 1332 arg.key.ipnode.name = name; 1333 arg.key.ipnode.af_family = af_family; 1334 arg.key.ipnode.flags = flags; 1335 arg.stayopen = 0; 1336 res = nss_search(&db_root_ipnodes, _nss_initf_ipnodes, 1337 NSS_DBOP_IPNODES_BYNAME, &arg); 1338 arg.status = res; 1339 if (res != NSS_SUCCESS) 1340 *h_errnop = arg.h_errno ? arg.h_errno : __nss2herrno(res); 1341 if (arg.returnval != NULL) 1342 order_haddrlist_af(result->h_addrtype, result->h_addr_list); 1343 return ((struct hostent *)NSS_XbyY_FINI(&arg)); 1344 } 1345 1346 struct hostent * 1347 _switch_gethostbyaddr_r(const char *addr, int len, int type, 1348 struct hostent *result, char *buffer, int buflen, int *h_errnop) 1349 { 1350 nss_XbyY_args_t arg; 1351 nss_status_t res; 1352 1353 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent); 1354 arg.key.hostaddr.addr = addr; 1355 arg.key.hostaddr.len = len; 1356 arg.key.hostaddr.type = type; 1357 arg.stayopen = 0; 1358 res = nss_search(&db_root_hosts, _nss_initf_hosts, 1359 NSS_DBOP_HOSTS_BYADDR, &arg); 1360 arg.status = res; 1361 if (res != NSS_SUCCESS) 1362 *h_errnop = arg.h_errno ? arg.h_errno : __nss2herrno(res); 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 if (res != NSS_SUCCESS) 1382 *h_errnop = arg.h_errno ? arg.h_errno : __nss2herrno(res); 1383 return (struct hostent *)NSS_XbyY_FINI(&arg); 1384 } 1385 1386 static void 1387 _nss_initf_services(nss_db_params_t *p) 1388 { 1389 p->name = NSS_DBNAM_SERVICES; 1390 p->default_config = NSS_DEFCONF_SERVICES; 1391 } 1392 1393 struct servent * 1394 _switch_getservbyname_r(const char *name, const char *proto, 1395 struct servent *result, char *buffer, int buflen) 1396 { 1397 nss_XbyY_args_t arg; 1398 nss_status_t res; 1399 1400 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2servent); 1401 arg.key.serv.serv.name = name; 1402 arg.key.serv.proto = proto; 1403 arg.stayopen = 0; 1404 res = nss_search(&db_root_services, _nss_initf_services, 1405 NSS_DBOP_SERVICES_BYNAME, &arg); 1406 arg.status = res; 1407 return ((struct servent *)NSS_XbyY_FINI(&arg)); 1408 } 1409 1410 struct servent * 1411 _switch_getservbyport_r(int port, const char *proto, struct servent *result, 1412 char *buffer, int buflen) 1413 { 1414 nss_XbyY_args_t arg; 1415 nss_status_t res; 1416 1417 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2servent); 1418 arg.key.serv.serv.port = port; 1419 arg.key.serv.proto = proto; 1420 arg.stayopen = 0; 1421 res = nss_search(&db_root_services, _nss_initf_services, 1422 NSS_DBOP_SERVICES_BYPORT, &arg); 1423 arg.status = res; 1424 return ((struct servent *)NSS_XbyY_FINI(&arg)); 1425 } 1426 1427 1428 /* 1429 * Return values: 0 = success, 1 = parse error, 2 = erange ... 1430 * The structure pointer passed in is a structure in the caller's space 1431 * wherein the field pointers would be set to areas in the buffer if 1432 * need be. instring and buffer should be separate areas. 1433 * 1434 * Defined here because we need it and we (libnsl) cannot have a dependency 1435 * on libsocket (however, libsocket always depends on libnsl). 1436 */ 1437 int 1438 str2servent(const char *instr, int lenstr, void *ent, char *buffer, int buflen) 1439 { 1440 struct servent *serv = (struct servent *)ent; 1441 const char *p, *fieldstart, *limit, *namestart; 1442 ssize_t fieldlen, namelen = 0; 1443 char numbuf[12]; 1444 char *numend; 1445 1446 if ((instr >= buffer && (buffer + buflen) > instr) || 1447 (buffer >= instr && (instr + lenstr) > buffer)) { 1448 return (NSS_STR_PARSE_PARSE); 1449 } 1450 1451 p = instr; 1452 limit = p + lenstr; 1453 1454 while (p < limit && isspace(*p)) { 1455 p++; 1456 } 1457 namestart = p; 1458 while (p < limit && !isspace(*p)) { 1459 p++; /* Skip over the canonical name */ 1460 } 1461 namelen = p - namestart; 1462 1463 if (buflen <= namelen) { /* not enough buffer */ 1464 return (NSS_STR_PARSE_ERANGE); 1465 } 1466 (void) memcpy(buffer, namestart, namelen); 1467 buffer[namelen] = '\0'; 1468 serv->s_name = buffer; 1469 1470 while (p < limit && isspace(*p)) { 1471 p++; 1472 } 1473 1474 fieldstart = p; 1475 do { 1476 if (p > limit || isspace(*p)) { 1477 /* Syntax error -- no port/proto */ 1478 return (NSS_STR_PARSE_PARSE); 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 }; 2185 } else 2186 servs = 1; 2187 2188 if ((hs = calloc(hosts * servs, sizeof (struct nd_hostserv))) == 0) { 2189 free(result); 2190 return (ND_NOMEM); 2191 } 2192 2193 result->h_cnt = servs * hosts; 2194 result->h_hostservs = hs; 2195 2196 for (i = 0, hn = he->h_aliases; i < hosts; i++) { 2197 sn = se ? se->s_aliases : NULL; 2198 2199 for (j = 0; j < servs; j++) { 2200 if (i == 0) 2201 hs->h_host = strdup(he->h_name); 2202 else 2203 hs->h_host = strdup(*hn); 2204 if (j == 0) { 2205 if (se) 2206 hs->h_serv = strdup(se->s_name); 2207 else { 2208 /* Convert to a number string */ 2209 char stmp[16]; 2210 2211 (void) sprintf(stmp, "%d", port); 2212 hs->h_serv = strdup(stmp); 2213 } 2214 } else 2215 hs->h_serv = strdup(*sn++); 2216 2217 if ((hs->h_host == 0) || (hs->h_serv == 0)) { 2218 free(result->h_hostservs); 2219 free(result); 2220 return (ND_NOMEM); 2221 } 2222 hs++; 2223 } 2224 if (i) 2225 hn++; 2226 } 2227 *(hslist) = result; 2228 return (ND_OK); 2229 } 2230 2231 /* 2232 * Process results from nd_addrlist ( returned by netdir_getbyname) 2233 * into a hostent using buf. 2234 * *** ASSUMES that nd_addrlist->n_addrs->buf contains IP addresses in 2235 * sockaddr_in's *** 2236 */ 2237 int 2238 ndaddr2hent(int af, const char *nam, struct nd_addrlist *addrs, 2239 struct hostent *result, char *buffer, int buflen) 2240 { 2241 int i, count; 2242 struct in_addr *addrp; 2243 struct in6_addr *addr6p; 2244 char **addrvec; 2245 struct netbuf *na; 2246 size_t len; 2247 2248 result->h_name = buffer; 2249 result->h_addrtype = af; 2250 result->h_length = (af == AF_INET) ? sizeof (*addrp): 2251 sizeof (*addr6p); 2252 2253 /* 2254 * Build addrlist at start of buffer (after name); store the 2255 * addresses themselves at the end of the buffer. 2256 */ 2257 len = strlen(nam) + 1; 2258 addrvec = (char **)ROUND_UP(buffer + len, sizeof (*addrvec)); 2259 result->h_addr_list = addrvec; 2260 2261 if (af == AF_INET) { 2262 addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen, 2263 sizeof (*addrp)); 2264 2265 count = addrs->n_cnt; 2266 if ((char *)(&addrvec[count + 1]) > (char *)(&addrp[-count])) 2267 return (ND_NOMEM); 2268 2269 (void) memcpy(buffer, nam, len); 2270 2271 for (na = addrs->n_addrs, i = 0; i < count; na++, i++) { 2272 --addrp; 2273 (void) memcpy(addrp, 2274 /* LINTED pointer cast */ 2275 &((struct sockaddr_in *)na->buf)->sin_addr, 2276 sizeof (*addrp)); 2277 *addrvec++ = (char *)addrp; 2278 } 2279 } else { 2280 addr6p = (struct in6_addr *)ROUND_DOWN(buffer + buflen, 2281 sizeof (*addr6p)); 2282 2283 count = addrs->n_cnt; 2284 if ((char *)(&addrvec[count + 1]) > (char *)(&addr6p[-count])) 2285 return (ND_NOMEM); 2286 2287 (void) memcpy(buffer, nam, len); 2288 2289 for (na = addrs->n_addrs, i = 0; i < count; na++, i++) { 2290 --addr6p; 2291 (void) memcpy(addr6p, 2292 /* LINTED pointer cast */ 2293 &((struct sockaddr_in6 *)na->buf)->sin6_addr, 2294 sizeof (*addr6p)); 2295 *addrvec++ = (char *)addr6p; 2296 } 2297 } 2298 *addrvec = 0; 2299 result->h_aliases = addrvec; 2300 2301 return (ND_OK); 2302 } 2303 2304 /* 2305 * Process results from nd_addrlist ( returned by netdir_getbyname) 2306 * into a servent using buf. 2307 */ 2308 int 2309 ndaddr2srent(const char *name, const char *proto, ushort_t port, 2310 struct servent *result, char *buffer, int buflen) 2311 { 2312 size_t i; 2313 char *bufend = (buffer + buflen); 2314 2315 result->s_port = (int)port; 2316 2317 result->s_aliases = 2318 (char **)ROUND_UP(buffer, sizeof (char *)); 2319 result->s_aliases[0] = NULL; 2320 buffer = (char *)&result->s_aliases[1]; 2321 result->s_name = buffer; 2322 i = strlen(name) + 1; 2323 if ((buffer + i) > bufend) 2324 return (ND_NOMEM); 2325 (void) memcpy(buffer, name, i); 2326 buffer += i; 2327 2328 result->s_proto = buffer; 2329 i = strlen(proto) + 1; 2330 if ((buffer + i) > bufend) 2331 return (ND_NOMEM); 2332 (void) memcpy(buffer, proto, i); 2333 buffer += i; 2334 2335 return (ND_OK); 2336 } 2337 2338 /* 2339 * Process results from nd_hostservlist ( returned by netdir_getbyaddr) 2340 * into a hostent using buf. 2341 * *** ASSUMES that nd_buf->buf is a sockaddr_in *** 2342 */ 2343 int 2344 ndhostserv2hent(struct netbuf *nbuf, struct nd_hostservlist *addrs, 2345 struct hostent *result, char *buffer, int buflen) 2346 { 2347 int i, count; 2348 char *aliasp; 2349 char **aliasvec; 2350 struct sockaddr_in *sa; 2351 struct nd_hostserv *hs; 2352 const char *la; 2353 size_t length; 2354 2355 /* First, give the lonely address a specious home in h_addr_list. */ 2356 aliasp = (char *)ROUND_UP(buffer, sizeof (sa->sin_addr)); 2357 /* LINTED pointer cast */ 2358 sa = (struct sockaddr_in *)nbuf->buf; 2359 (void) memcpy(aliasp, &(sa->sin_addr), sizeof (sa->sin_addr)); 2360 aliasvec = (char **)ROUND_UP(aliasp + sizeof (sa->sin_addr), 2361 sizeof (*aliasvec)); 2362 result->h_addr_list = aliasvec; 2363 *aliasvec++ = aliasp; 2364 *aliasvec++ = 0; 2365 2366 /* 2367 * Build h_aliases at start of buffer (after addr and h_addr_list); 2368 * store the alias strings at the end of the buffer (before h_name). 2369 */ 2370 2371 aliasp = buffer + buflen; 2372 2373 result->h_aliases = aliasvec; 2374 2375 hs = addrs->h_hostservs; 2376 if (!hs) 2377 return (ND_NOHOST); 2378 2379 length = strlen(hs->h_host) + 1; 2380 aliasp -= length; 2381 if ((char *)(&aliasvec[1]) > aliasp) 2382 return (ND_NOMEM); 2383 (void) memcpy(aliasp, hs->h_host, length); 2384 2385 result->h_name = aliasp; 2386 result->h_addrtype = AF_INET; 2387 result->h_length = sizeof (sa->sin_addr); 2388 2389 /* 2390 * Assumption: the netdir nametoaddr_libs 2391 * sort the vector of (host, serv) pairs in such a way that 2392 * all pairs with the same host name are contiguous. 2393 */ 2394 la = hs->h_host; 2395 count = addrs->h_cnt; 2396 for (i = 0; i < count; i++, hs++) 2397 if (strcmp(la, hs->h_host) != 0) { 2398 size_t len = strlen(hs->h_host) + 1; 2399 2400 aliasp -= len; 2401 if ((char *)(&aliasvec[2]) > aliasp) 2402 return (ND_NOMEM); 2403 (void) memcpy(aliasp, hs->h_host, len); 2404 *aliasvec++ = aliasp; 2405 la = hs->h_host; 2406 } 2407 *aliasvec = 0; 2408 2409 return (ND_OK); 2410 } 2411 2412 /* 2413 * Process results from nd_hostservlist ( returned by netdir_getbyaddr) 2414 * into a servent using buf. 2415 */ 2416 int 2417 ndhostserv2srent(int port, const char *proto, struct nd_hostservlist *addrs, 2418 struct servent *result, char *buffer, int buflen) 2419 { 2420 int i, count; 2421 char *aliasp; 2422 char **aliasvec; 2423 struct nd_hostserv *hs; 2424 const char *host_cname; 2425 size_t leni, lenj; 2426 2427 result->s_port = port; 2428 /* 2429 * Build s_aliases at start of buffer; 2430 * store proto and aliases at the end of the buffer (before h_name). 2431 */ 2432 2433 aliasp = buffer + buflen; 2434 aliasvec = (char **)ROUND_UP(buffer, sizeof (char *)); 2435 2436 result->s_aliases = aliasvec; 2437 2438 hs = addrs->h_hostservs; 2439 if (!hs) 2440 return (ND_NOHOST); 2441 host_cname = hs->h_host; 2442 2443 leni = strlen(proto) + 1; 2444 lenj = strlen(hs->h_serv) + 1; 2445 if ((char *)(&aliasvec[2]) > (aliasp - leni - lenj)) 2446 return (ND_NOMEM); 2447 2448 aliasp -= leni; 2449 (void) memcpy(aliasp, proto, leni); 2450 result->s_proto = aliasp; 2451 2452 aliasp -= lenj; 2453 (void) memcpy(aliasp, hs->h_serv, lenj); 2454 result->s_name = aliasp; 2455 2456 /* 2457 * Assumption: the netdir nametoaddr_libs 2458 * do a host aliases first and serv aliases next 2459 * enumeration for creating the list of hostserv 2460 * structures. 2461 */ 2462 count = addrs->h_cnt; 2463 for (i = 0; 2464 i < count && hs->h_serv && strcmp(hs->h_host, host_cname) == 0; 2465 i++, hs++) { 2466 size_t len = strlen(hs->h_serv) + 1; 2467 2468 aliasp -= len; 2469 if ((char *)(&aliasvec[2]) > aliasp) 2470 return (ND_NOMEM); 2471 (void) memcpy(aliasp, hs->h_serv, len); 2472 *aliasvec++ = aliasp; 2473 } 2474 *aliasvec = NULL; 2475 2476 return (ND_OK); 2477 } 2478 2479 2480 static int 2481 nd2herrno(int nerr) 2482 { 2483 switch (nerr) { 2484 case ND_OK: 2485 return (0); 2486 case ND_TRY_AGAIN: 2487 return (TRY_AGAIN); 2488 case ND_NO_RECOVERY: 2489 case ND_BADARG: 2490 case ND_NOMEM: 2491 return (NO_RECOVERY); 2492 case ND_NO_DATA: 2493 return (NO_DATA); 2494 case ND_NOHOST: 2495 case ND_NOSERV: 2496 return (HOST_NOT_FOUND); 2497 default: 2498 return (NO_RECOVERY); 2499 } 2500 } 2501 2502 /* 2503 * This is a utility function so that various parts of libnsl can 2504 * easily send ioctls down to ip. 2505 * 2506 */ 2507 int 2508 nss_ioctl(int af, int cmd, void *arg) 2509 { 2510 int fd; 2511 char *devpath; 2512 int retv; 2513 2514 switch (af) { 2515 case AF_INET6: 2516 devpath = UDP6DEV; 2517 break; 2518 case AF_INET: 2519 case AF_UNSPEC: 2520 default: 2521 devpath = UDPDEV; 2522 } 2523 if ((fd = open(devpath, O_RDONLY)) < 0) { 2524 return (-1); 2525 } 2526 while ((retv = ioctl(fd, cmd, arg)) == -1) { 2527 if (errno != EINTR) 2528 break; 2529 } 2530 (void) close(fd); 2531 return (retv); 2532 } 2533 2534 static int 2535 nss_strioctl(int af, int cmd, void *ptr, int ilen) 2536 { 2537 struct strioctl str; 2538 2539 str.ic_cmd = cmd; 2540 str.ic_timout = 0; 2541 str.ic_len = ilen; 2542 str.ic_dp = ptr; 2543 2544 return (nss_ioctl(af, I_STR, &str)); 2545 } 2546 2547 static struct ifinfo * 2548 get_local_info(void) 2549 { 2550 int numifs; 2551 int n; 2552 char *buf = NULL; 2553 size_t needed; 2554 struct lifconf lifc; 2555 struct lifreq lifreq, *lifr; 2556 struct lifnum lifn; 2557 struct ifinfo *localinfo; 2558 2559 lifn.lifn_family = AF_UNSPEC; 2560 lifn.lifn_flags = 0; 2561 2562 getifnum: 2563 if (nss_ioctl(AF_UNSPEC, SIOCGLIFNUM, &lifn) == -1) { 2564 numifs = MAXIFS; 2565 } else { 2566 numifs = lifn.lifn_count; 2567 } 2568 2569 /* 2570 * Add a small fudge factor in case interfaces get plumbed between 2571 * the call to SIOCGLIFNUM and SIOCGLIFCONF. 2572 */ 2573 needed = (numifs + 4) * sizeof (lifreq); 2574 if (buf == NULL) 2575 buf = malloc(needed); 2576 else 2577 buf = realloc(buf, needed); 2578 if (buf == NULL) { 2579 (void) syslog(LOG_ERR, "n2a get_local_info: malloc failed: %m"); 2580 _nderror = ND_NOMEM; 2581 return (NULL); 2582 } 2583 lifc.lifc_family = AF_UNSPEC; 2584 lifc.lifc_flags = 0; 2585 lifc.lifc_len = needed; 2586 lifc.lifc_buf = buf; 2587 if (nss_ioctl(AF_UNSPEC, SIOCGLIFCONF, &lifc) == -1) { 2588 /* 2589 * IP returns EINVAL if the buffer was too small to fit 2590 * all of the entries. If that's the case, go back and 2591 * try again. 2592 */ 2593 if (errno == EINVAL) 2594 goto getifnum; 2595 2596 (void) syslog(LOG_ERR, "n2a get_local_info: " 2597 "ioctl (get interface configuration): %m"); 2598 free(buf); 2599 _nderror = ND_SYSTEM; 2600 return (NULL); 2601 } 2602 /* LINTED pointer cast */ 2603 lifr = (struct lifreq *)buf; 2604 numifs = lifc.lifc_len/sizeof (lifreq); 2605 localinfo = malloc(ifinfosize(numifs)); 2606 if (localinfo == NULL) { 2607 (void) syslog(LOG_ERR, "n2a get_local_info: malloc failed: %m"); 2608 free(buf); 2609 _nderror = ND_SYSTEM; 2610 return (NULL); 2611 } 2612 2613 /* LINTED pointer cast */ 2614 localinfo->addresses = (struct __ifaddr *) 2615 ((char *)localinfo + sizeof (struct ifinfo)); 2616 2617 for (localinfo->count = 0, n = numifs; n > 0; n--, lifr++) { 2618 int af; 2619 2620 lifreq = *lifr; 2621 af = lifreq.lifr_addr.ss_family; 2622 2623 /* Squirrel away the address */ 2624 if (ifassign(lifreq, localinfo->count, IF_ADDR) == 0) 2625 continue; 2626 2627 if (nss_ioctl(af, SIOCGLIFFLAGS, &lifreq) < 0) { 2628 (void) syslog(LOG_ERR, 2629 "n2a get_local_info: " 2630 "ioctl (get interface flags): %m"); 2631 continue; 2632 } 2633 if (!(lifreq.lifr_flags & IFF_UP)) 2634 continue; 2635 2636 if (nss_ioctl(af, SIOCGLIFNETMASK, &lifreq) < 0) { 2637 (void) syslog(LOG_ERR, 2638 "n2a get_local_info: " 2639 "ioctl (get interface netmask): %m"); 2640 continue; 2641 } 2642 2643 if (ifassign(lifreq, localinfo->count, IF_MASK) == 0) 2644 continue; 2645 2646 localinfo->count++; 2647 } 2648 2649 free(buf); 2650 return (localinfo); 2651 } 2652 2653 static int 2654 __inet_ifassign(sa_family_t af, struct __ifaddr *ifa, __ifaddr_type type, 2655 void *addr) { 2656 switch (type) { 2657 case IF_ADDR: 2658 ifa->af = af; 2659 if (af == AF_INET6) { 2660 ifa->addr.in6 = *(struct in6_addr *)addr; 2661 } else { 2662 ifa->addr.in4 = *(struct in_addr *)addr; 2663 } 2664 break; 2665 case IF_MASK: 2666 if (ifa->af == af) { 2667 if (af == AF_INET6) { 2668 ifa->mask.in6 = *(struct in6_addr *)addr; 2669 } else { 2670 ifa->mask.in4 = *(struct in_addr *)addr; 2671 } 2672 } else { 2673 return (0); 2674 } 2675 break; 2676 default: 2677 return (0); 2678 } 2679 2680 return (1); 2681 } 2682 2683 /* 2684 * Some higher-level routines for determining if an address is 2685 * on a local network. 2686 * 2687 * __inet_get_local_interfaces() - get an opaque handle with 2688 * with a list of local interfaces 2689 * __inet_address_is_local() - return 1 if an address is 2690 * on a local network; 0 otherwise 2691 * __inet_free_local_interfaces() - free handle that was 2692 * returned by __inet_get_local_interfaces() 2693 * 2694 * A typical calling sequence is: 2695 * 2696 * p = __inet_get_local_interfaces(); 2697 * if (__inet_address_is_local(p, inaddr)) { 2698 * ... 2699 * } 2700 * __inet_free_local_interfaces(p); 2701 */ 2702 2703 /* 2704 * Return an opaque pointer to a list of configured interfaces. 2705 */ 2706 void * 2707 __inet_get_local_interfaces(void) 2708 { 2709 return (get_local_info()); 2710 } 2711 2712 /* 2713 * Free memory allocated by inet_local_interfaces(). 2714 */ 2715 void 2716 __inet_free_local_interfaces(void *p) 2717 { 2718 free(p); 2719 } 2720 2721 /* 2722 * Determine if an address is on a local network. 2723 * 2724 * Might have made sense to use SIOCTONLINK, except that it doesn't 2725 * handle matching on IPv4 network addresses. 2726 */ 2727 int 2728 __inet_address_is_local_af(void *p, sa_family_t af, void *addr) { 2729 2730 struct ifinfo *localinfo = (struct ifinfo *)p; 2731 int i, a; 2732 struct in_addr v4addr; 2733 2734 if (localinfo == 0) 2735 return (0); 2736 2737 if (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr)) { 2738 IN6_V4MAPPED_TO_INADDR((struct in6_addr *)addr, &v4addr); 2739 af = AF_INET; 2740 addr = (void *)&v4addr; 2741 } 2742 2743 for (i = 0; i < localinfo->count; i++) { 2744 if (ifaf(i) == af) { 2745 if (af == AF_INET6) { 2746 struct in6_addr *a6 = (struct in6_addr *)addr; 2747 for (a = 0; a < sizeof (a6->s6_addr); a++) { 2748 if ((a6->s6_addr[a] & 2749 ifmask6(i).s6_addr[a]) != 2750 (ifaddr6(i).s6_addr[a] & 2751 ifmask6(i).s6_addr[a])) 2752 break; 2753 } 2754 if (a >= sizeof (a6->s6_addr)) 2755 return (1); 2756 } else { 2757 if ((((struct in_addr *)addr)->s_addr & 2758 ifmask4(i).s_addr) == 2759 (ifaddr4(i).s_addr & 2760 ifmask4(i).s_addr)) 2761 return (1); 2762 } 2763 } 2764 } 2765 2766 return (0); 2767 } 2768 2769 int 2770 __inet_address_is_local(void *p, struct in_addr addr) 2771 { 2772 return (__inet_address_is_local_af(p, AF_INET, &addr)); 2773 } 2774 2775 int 2776 __inet_uaddr_is_local(void *p, struct netconfig *nc, char *uaddr) 2777 { 2778 struct netbuf *taddr; 2779 sa_family_t af; 2780 int ret; 2781 2782 taddr = uaddr2taddr(nc, uaddr); 2783 if (taddr == 0) 2784 return (0); 2785 2786 /* LINTED pointer cast */ 2787 af = ((struct sockaddr *)taddr->buf)->sa_family; 2788 2789 ret = __inet_address_is_local_af(p, af, (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, "broadcast: " 2965 "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 FILE *defl; 3061 boolean_t nosort = B_FALSE; 3062 3063 3064 do { 3065 defl = fopen(__NSW_DEFAULT_FILE, "rF"); 3066 } while ((defl == NULL) && (errno == EINTR)); 3067 3068 if (defl == NULL) 3069 return (B_FALSE); 3070 3071 while (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) fclose(defl); 3080 return (nosort); 3081 } 3082