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