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.
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.
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]
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.
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
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
50 * Goes without saying that most of the future bugs in gethost/servbyYY
51 * and netdir_getbyYY are lurking somewhere here.
61 #include <sys/types.h>
62 #include <sys/byteorder.h>
63 #include <sys/ioctl.h>
64 #include <sys/param.h>
70 #include <sys/utsname.h>
72 #include <netconfig.h>
75 #include <sys/socket.h>
76 #include <sys/sockio.h>
77 #include <netinet/in.h>
78 #include <arpa/inet.h>
81 #include <inet/ip6_asp.h>
83 #include <nss_dbdefs.h>
84 #include <nss_netdir.h>
90 #define UDPDEV "/dev/udp"
91 #define UDP6DEV "/dev/udp6"
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
98 #define DONT_SORT "SORT_ADDRS=NO"
99 #define DONT_SORT2 "SORT_ADDRS=FALSE"
103 * constant values of addresses for HOST_SELF_BIND, HOST_SELF_CONNECT
106 * The following variables are static to the extent that they should
107 * not be visible outside of this file.
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
};
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
};
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
};
130 #define LOCALHOST "localhost"
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
*,
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
*,
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);
161 * Top Level Interfaces that gethost/serv/netdir funnel through.
165 inetdir_free(int ret
, struct in_addr
*inaddrs
, char **baddrlist
)
174 * gethost/servbyname always call this function; if they call
175 * with nametoaddr libs in nconf, we call netdir_getbyname
176 * implementation: __classic_netdir_getbyname, otherwise nsswitch.
178 * netdir_getbyname calls this only if nametoaddr libs are NOT
179 * specified for inet transports; i.e. it's supposed to follow
180 * the name service switch.
183 _get_hostserv_inetnetdir_byname(struct netconfig
*nconf
,
184 struct nss_netdirbyname_in
*args
, union nss_netdirbyname_out
*res
)
187 int *servp
= &server_port
;
189 uint32_t dotnameaddr
;
190 char *dotnamelist
[2];
191 struct in_addr
*inaddrs
= NULL
;
192 struct in6_addr v6nameaddr
;
193 char **baddrlist
= NULL
;
196 _nderror
= ND_BADARG
;
201 * 1. gethostbyname()/netdir_getbyname() special cases:
203 switch (args
->op_t
) {
207 * Worth the performance gain -- assuming a lot of inet apps
208 * actively use "localhost".
210 if (strcmp(args
->arg
.nss
.host
.name
, LOCALHOST
) == 0) {
212 (void) mutex_lock(&nd_addr_lock
);
213 IN_SET_LOOPBACK_ADDR(&sa_con
);
214 _nderror
= ndaddr2hent(AF_INET
, args
->arg
.nss
.host
.name
,
215 &nd_conaddrlist
, res
->nss
.host
.hent
,
216 args
->arg
.nss
.host
.buf
,
217 args
->arg
.nss
.host
.buflen
);
218 (void) mutex_unlock(&nd_addr_lock
);
219 if (_nderror
!= ND_OK
)
220 *(res
->nss
.host
.herrno_p
) =
225 * If the caller passed in a dot separated IP notation to
226 * gethostbyname, return that back as the address.
227 * The nd_addr_lock mutex was added to be truely re-entrant.
229 if (inet_aton(args
->arg
.nss
.host
.name
,
230 (struct in_addr
*)&dotnameaddr
)) {
231 (void) mutex_lock(&nd_addr_lock
);
232 (void) memset(&sa_con
, 0, sizeof (sa_con
));
233 sa_con
.sin_family
= AF_INET
;
234 sa_con
.sin_addr
.s_addr
= dotnameaddr
;
235 _nderror
= ndaddr2hent(AF_INET
, args
->arg
.nss
.host
.name
,
236 &nd_conaddrlist
, res
->nss
.host
.hent
,
237 args
->arg
.nss
.host
.buf
,
238 args
->arg
.nss
.host
.buflen
);
239 (void) mutex_unlock(&nd_addr_lock
);
240 if (_nderror
!= ND_OK
)
241 *(res
->nss
.host
.herrno_p
) =
249 * Handle case of literal address string.
251 if (strchr(args
->arg
.nss
.host6
.name
, ':') != NULL
&&
252 (inet_pton(AF_INET6
, args
->arg
.nss
.host6
.name
,
253 &v6nameaddr
) != 0)) {
256 (void) mutex_lock(&nd6_addr_lock
);
257 (void) memset(&sa6_con
, 0, sizeof (sa6_con
));
258 sa6_con
.sin6_family
= AF_INET6
;
259 (void) memcpy(&(sa6_con
.sin6_addr
.s6_addr
),
260 &v6nameaddr
, sizeof (struct in6_addr
));
261 ret
= ndaddr2hent(AF_INET6
,
262 args
->arg
.nss
.host6
.name
,
263 &nd6_conaddrlist
, res
->nss
.host
.hent
,
264 args
->arg
.nss
.host6
.buf
,
265 args
->arg
.nss
.host6
.buflen
);
266 (void) mutex_unlock(&nd6_addr_lock
);
268 *(res
->nss
.host
.herrno_p
) = nd2herrno(ret
);
270 res
->nss
.host
.hent
->h_aliases
= NULL
;
276 if (args
->arg
.nd_hs
== 0) {
277 _nderror
= ND_BADARG
;
281 * If servname is NULL, return 0 as the port number
282 * If servname is rpcbind, return 111 as the port number
283 * If servname is a number, return it back as the port
286 if (args
->arg
.nd_hs
->h_serv
== 0) {
288 } else if (strcmp(args
->arg
.nd_hs
->h_serv
,
291 } else if (strspn(args
->arg
.nd_hs
->h_serv
,
293 strlen(args
->arg
.nd_hs
->h_serv
)) {
294 *servp
= htons(atoi(args
->arg
.nd_hs
->h_serv
));
296 /* i.e. need to call a name service on this */
301 * If the hostname is HOST_SELF_BIND, we return 0.0.0.0
302 * so the binding can be contacted through all
303 * interfaces. If the hostname is HOST_SELF_CONNECT,
304 * we return 127.0.0.1 so the address can be connected
305 * to locally. If the hostname is HOST_ANY, we return
306 * no addresses because IP doesn't know how to specify
307 * a service without a host. And finally if we specify
308 * HOST_BROADCAST then we ask a tli fd to tell us what
309 * the broadcast addresses are for any udp
310 * interfaces on this machine.
312 if (args
->arg
.nd_hs
->h_host
== 0) {
313 _nderror
= ND_NOHOST
;
315 } else if ((strcmp(args
->arg
.nd_hs
->h_host
,
316 HOST_SELF_BIND
) == 0)) {
317 haddrlist
= localaddr
;
318 } else if ((strcmp(args
->arg
.nd_hs
->h_host
,
319 HOST_SELF_CONNECT
) == 0)) {
320 haddrlist
= connectaddr
;
321 } else if ((strcmp(args
->arg
.nd_hs
->h_host
,
323 haddrlist
= connectaddr
;
324 } else if ((int)(dotnameaddr
=
325 inet_addr(args
->arg
.nd_hs
->h_host
)) != -1) {
327 * If the caller passed in a dot separated IP
328 * notation to netdir_getbyname, convert that
332 dotnamelist
[0] = (char *)&dotnameaddr
;
333 dotnamelist
[1] = NULL
;
334 haddrlist
= dotnamelist
;
335 } else if ((strcmp(args
->arg
.nd_hs
->h_host
,
336 HOST_BROADCAST
) == 0)) {
338 * Now that inaddrs and baddrlist are
339 * dynamically allocated, care must be
340 * taken in freeing up the
341 * memory at each 'return()' point.
343 * Early return protection (using
344 * inetdir_free()) is needed only in NETDIR_BY
345 * cases because dynamic allocation is used
346 * when args->op_t == NETDIR_BY.
348 * Early return protection is not needed in
349 * haddrlist==0 conditionals because dynamic
350 * allocation guarantees haddrlist!=0.
352 * Early return protection is not needed in most
353 * servp!=0 conditionals because this is handled
354 * (and returned) first.
358 bnets
= getbroadcastnets(nconf
, &inaddrs
);
360 _nderror
= ND_NOHOST
;
363 baddrlist
= malloc((bnets
+1)*sizeof (char *));
364 if (baddrlist
== NULL
)
365 return (inetdir_free(ND_NOMEM
, inaddrs
,
367 for (i
= 0; i
< bnets
; i
++)
368 baddrlist
[i
] = (char *)&inaddrs
[i
];
370 haddrlist
= baddrlist
;
372 /* i.e. need to call a name service on this */
376 if (haddrlist
&& servp
) {
379 * Convert h_addr_list into nd_addrlist.
380 * malloc's will be done, freed using
383 ret
= hent2ndaddr(AF_INET
, haddrlist
, servp
,
385 return (inetdir_free(ret
, inaddrs
, baddrlist
));
391 if (args
->arg
.nd_hs
== 0) {
392 _nderror
= ND_BADARG
;
396 * If servname is NULL, return 0 as the port number.
397 * If servname is rpcbind, return 111 as the port number
398 * If servname is a number, return it back as the port
401 if (args
->arg
.nd_hs
->h_serv
== 0) {
403 } else if (strcmp(args
->arg
.nd_hs
->h_serv
,
406 } else if (strspn(args
->arg
.nd_hs
->h_serv
, "0123456789")
407 == strlen(args
->arg
.nd_hs
->h_serv
)) {
408 *servp
= htons(atoi(args
->arg
.nd_hs
->h_serv
));
410 /* i.e. need to call a name service on this */
415 * If the hostname is HOST_SELF_BIND, we return ipv6
416 * localaddress so the binding can be contacted through
418 * If the hostname is HOST_SELF_CONNECT, we return
419 * ipv6 loopback address so the address can be connected
421 * If the hostname is HOST_ANY, we return no addresses
422 * because IP doesn't know how to specify a service
424 * And finally if we specify HOST_BROADCAST then we
425 * disallow since IPV6 does not have any
428 if (args
->arg
.nd_hs
->h_host
== 0) {
430 } else if ((strcmp(args
->arg
.nd_hs
->h_host
,
431 HOST_SELF_BIND
) == 0)) {
432 haddrlist
= localaddr6
;
433 } else if ((strcmp(args
->arg
.nd_hs
->h_host
,
434 HOST_SELF_CONNECT
) == 0)) {
435 haddrlist
= connectaddr6
;
436 } else if ((strcmp(args
->arg
.nd_hs
->h_host
,
438 haddrlist
= connectaddr6
;
439 } else if (strchr(args
->arg
.nd_hs
->h_host
, ':')
443 * If the caller passed in a dot separated IP notation
444 * to netdir_getbyname, convert that back into address.
447 if ((inet_pton(AF_INET6
,
448 args
->arg
.nd_hs
->h_host
,
449 &v6nameaddr
)) != 0) {
450 dotnamelist
[0] = (char *)&v6nameaddr
;
451 dotnamelist
[1] = NULL
;
452 haddrlist
= dotnamelist
;
455 /* not sure what to return */
458 } else if ((strcmp(args
->arg
.nd_hs
->h_host
,
459 HOST_BROADCAST
) == 0)) {
461 * Don't support broadcast in
466 /* i.e. need to call a name service on this */
470 if (haddrlist
&& servp
) {
473 * Convert h_addr_list into nd_addrlist.
474 * malloc's will be done, freed
477 ret
= hent2ndaddr(AF_INET6
, haddrlist
,
478 servp
, res
->nd_alist
);
479 return (inetdir_free(ret
, inaddrs
, baddrlist
));
487 * 2. Most common scenario. This is the way we ship /etc/netconfig.
488 * Emphasis on improving performance in the "if" part.
490 if (nconf
->nc_nlookups
== 0) {
491 struct hostent
*he
= NULL
, *tmphe
;
494 nss_XbyY_buf_t
*ndbuf4switch
= 0;
496 switch (args
->op_t
) {
500 he
= DOOR_GETHOSTBYNAME_R(args
->arg
.nss
.host
.name
,
501 res
->nss
.host
.hent
, args
->arg
.nss
.host
.buf
,
502 args
->arg
.nss
.host
.buflen
,
503 res
->nss
.host
.herrno_p
);
505 return (_nderror
= ND_NOHOST
);
506 return (_nderror
= ND_OK
);
510 he
= DOOR_GETIPNODEBYNAME_R(args
->arg
.nss
.host6
.name
,
511 res
->nss
.host
.hent
, args
->arg
.nss
.host
.buf
,
512 args
->arg
.nss
.host6
.buflen
,
513 args
->arg
.nss
.host6
.af_family
,
514 args
->arg
.nss
.host6
.flags
,
515 res
->nss
.host
.herrno_p
);
518 return (_nderror
= ND_NOHOST
);
519 return (_nderror
= ND_OK
);
523 se
= _switch_getservbyname_r(args
->arg
.nss
.serv
.name
,
524 args
->arg
.nss
.serv
.proto
,
525 res
->nss
.serv
, args
->arg
.nss
.serv
.buf
,
526 args
->arg
.nss
.serv
.buflen
);
530 _nderror
= ND_NOSERV
;
536 char *proto
= (strcmp(nconf
->nc_proto
,
537 NC_TCP
) == 0) ? NC_TCP
: NC_UDP
;
540 * We go through all this for just one port number,
541 * which is most often constant. How about linking in
542 * an indexed database of well-known ports in the name
545 ndbuf4switch
= _nss_XbyY_buf_alloc(
546 sizeof (struct servent
), NSS_BUFLEN_SERVICES
);
547 if (ndbuf4switch
== 0)
548 return (inetdir_free(ND_NOMEM
, inaddrs
,
550 se
= _switch_getservbyname_r(args
->arg
.nd_hs
->h_serv
,
551 proto
, ndbuf4switch
->result
,
552 ndbuf4switch
->buffer
, ndbuf4switch
->buflen
);
554 NSS_XbyY_FREE(&ndbuf4switch
);
555 return (inetdir_free(ND_NOSERV
, inaddrs
,
558 server_port
= se
->s_port
;
559 NSS_XbyY_FREE(&ndbuf4switch
);
562 if (haddrlist
== 0) {
565 ndbuf4switch
= _nss_XbyY_buf_alloc(
566 sizeof (struct hostent
),
568 if (ndbuf4switch
== 0) {
573 * Search the ipnodes (v6) path first,
574 * search will return the v4 addresses
575 * as v4mapped addresses.
577 if ((tmphe
= DOOR_GETIPNODEBYNAME_R(
578 args
->arg
.nd_hs
->h_host
,
579 ndbuf4switch
->result
, ndbuf4switch
->buffer
,
580 ndbuf4switch
->buflen
, args
->arg
.nss
.host6
.af_family
,
581 args
->arg
.nss
.host6
.flags
, &h_errnop
)) != NULL
)
582 he
= __mappedtov4(tmphe
, &h_errnop
);
585 /* Failover case, try hosts db for v4 address */
586 he
= DOOR_GETHOSTBYNAME_R(
587 args
->arg
.nd_hs
->h_host
,
588 ndbuf4switch
->result
, ndbuf4switch
->buffer
,
589 ndbuf4switch
->buflen
, &h_errnop
);
591 NSS_XbyY_FREE(&ndbuf4switch
);
592 _nderror
= __herrno2netdir(h_errnop
);
596 * Convert h_addr_list into nd_addrlist.
597 * malloc's will be done, freed using
600 ret
= hent2ndaddr(AF_INET
, he
->h_addr_list
,
601 &server_port
, res
->nd_alist
);
604 * Convert h_addr_list into nd_addrlist.
605 * malloc's will be done, freed using
608 ret
= hent2ndaddr(AF_INET
, he
->h_addr_list
,
609 &server_port
, res
->nd_alist
);
614 NSS_XbyY_FREE(&ndbuf4switch
);
619 * Convert h_addr_list into nd_addrlist.
620 * malloc's will be done, freed using netdir_free.
622 ret
= hent2ndaddr(AF_INET
, haddrlist
,
623 &server_port
, res
->nd_alist
);
624 return (inetdir_free(ret
, inaddrs
, baddrlist
));
631 char *proto
= (strcmp(nconf
->nc_proto
,
632 NC_TCP
) == 0) ? NC_TCP
: NC_UDP
;
635 * We go through all this for just
637 * which is most often constant.
638 * How about linking in
639 * an indexed database of well-known
643 ndbuf4switch
= _nss_XbyY_buf_alloc(
644 sizeof (struct servent
),
645 NSS_BUFLEN_SERVICES
);
646 if (ndbuf4switch
== 0)
647 return (inetdir_free(ND_NOMEM
, inaddrs
,
649 se
= _switch_getservbyname_r(
650 args
->arg
.nd_hs
->h_serv
,
651 proto
, ndbuf4switch
->result
,
652 ndbuf4switch
->buffer
, ndbuf4switch
->buflen
);
654 NSS_XbyY_FREE(&ndbuf4switch
);
655 return (inetdir_free(ND_NOSERV
, inaddrs
,
658 server_port
= se
->s_port
;
659 NSS_XbyY_FREE(&ndbuf4switch
);
662 if (haddrlist
== 0) {
665 ndbuf4switch
= _nss_XbyY_buf_alloc(
666 sizeof (struct hostent
),
668 if (ndbuf4switch
== 0) {
672 he
= DOOR_GETIPNODEBYNAME_R(
673 args
->arg
.nd_hs
->h_host
,
674 ndbuf4switch
->result
, ndbuf4switch
->buffer
,
675 ndbuf4switch
->buflen
,
676 args
->arg
.nss
.host6
.af_family
,
677 args
->arg
.nss
.host6
.flags
, &h_errnop
);
679 NSS_XbyY_FREE(&ndbuf4switch
);
680 _nderror
= __herrno2netdir(h_errnop
);
684 * Convert h_addr_list into nd_addrlist.
685 * malloc's will be done,
686 * freed using netdir_free.
688 ret
= hent2ndaddr(AF_INET6
,
690 (ndbuf4switch
->result
))->h_addr_list
,
691 &server_port
, res
->nd_alist
);
693 NSS_XbyY_FREE(&ndbuf4switch
);
698 * Convert h_addr_list into nd_addrlist.
699 * malloc's will be done,
700 * freed using netdir_free.
702 ret
= hent2ndaddr(AF_INET6
, haddrlist
,
703 &server_port
, res
->nd_alist
);
704 return (inetdir_free(ret
, inaddrs
, baddrlist
));
708 _nderror
= ND_BADARG
;
709 return (ND_BADARG
); /* should never happen */
713 /* haddrlist is no longer used, so clean up */
719 * 3. We come this far only if nametoaddr libs are specified for
720 * inet transports and we are called by gethost/servbyname only.
722 switch (args
->op_t
) {
723 struct nd_hostserv service
;
724 struct nd_addrlist
*addrs
;
729 service
.h_host
= (char *)args
->arg
.nss
.host
.name
;
730 service
.h_serv
= NULL
;
731 if ((_nderror
= __classic_netdir_getbyname(nconf
,
732 &service
, &addrs
)) != ND_OK
) {
733 *(res
->nss
.host
.herrno_p
) = nd2herrno(_nderror
);
737 * convert addresses back into sockaddr for gethostbyname.
739 ret
= ndaddr2hent(AF_INET
, service
.h_host
, addrs
,
740 res
->nss
.host
.hent
, args
->arg
.nss
.host
.buf
,
741 args
->arg
.nss
.host
.buflen
);
743 *(res
->nss
.host
.herrno_p
) = nd2herrno(ret
);
744 netdir_free((char *)addrs
, ND_ADDRLIST
);
750 if (args
->arg
.nss
.serv
.proto
== NULL
) {
752 * A similar HACK showed up in Solaris 2.3.
753 * The caller wild-carded proto -- i.e. will
754 * accept a match using tcp or udp for the port
755 * number. Since we have no hope of getting
756 * directly to a name service switch backend
757 * from here that understands this semantics,
758 * we try calling the netdir interfaces first
759 * with "tcp" and then "udp".
761 args
->arg
.nss
.serv
.proto
= "tcp";
762 _nderror
= _get_hostserv_inetnetdir_byname(nconf
, args
,
764 if (_nderror
!= ND_OK
) {
765 args
->arg
.nss
.serv
.proto
= "udp";
767 _get_hostserv_inetnetdir_byname(nconf
,
774 * Third-parties should optimize their nametoaddr
775 * libraries for the HOST_SELF case.
777 service
.h_host
= HOST_SELF
;
778 service
.h_serv
= (char *)args
->arg
.nss
.serv
.name
;
779 if ((_nderror
= __classic_netdir_getbyname(nconf
,
780 &service
, &addrs
)) != ND_OK
) {
784 * convert addresses back into servent for getservbyname.
786 _nderror
= ndaddr2srent(service
.h_serv
,
787 args
->arg
.nss
.serv
.proto
,
788 /* LINTED pointer cast */
789 ((struct sockaddr_in
*)addrs
->n_addrs
->buf
)->sin_port
,
791 args
->arg
.nss
.serv
.buf
, args
->arg
.nss
.serv
.buflen
);
792 netdir_free((char *)addrs
, ND_ADDRLIST
);
796 _nderror
= ND_BADARG
;
797 return (ND_BADARG
); /* should never happen */
802 * gethostbyaddr/servbyport always call this function; if they call
803 * with nametoaddr libs in nconf, we call netdir_getbyaddr
804 * implementation __classic_netdir_getbyaddr, otherwise nsswitch.
806 * netdir_getbyaddr calls this only if nametoaddr libs are NOT
807 * specified for inet transports; i.e. it's supposed to follow
808 * the name service switch.
811 _get_hostserv_inetnetdir_byaddr(struct netconfig
*nconf
,
812 struct nss_netdirbyaddr_in
*args
, union nss_netdirbyaddr_out
*res
)
815 _nderror
= ND_BADARG
;
820 * 1. gethostbyaddr()/netdir_getbyaddr() special cases:
822 switch (args
->op_t
) {
826 * Worth the performance gain: assuming a lot of inet apps
827 * actively use "127.0.0.1".
829 /* LINTED pointer cast */
830 if (*(uint32_t *)(args
->arg
.nss
.host
.addr
) ==
831 htonl(INADDR_LOOPBACK
)) {
832 (void) mutex_lock(&nd_addr_lock
);
833 IN_SET_LOOPBACK_ADDR(&sa_con
);
834 _nderror
= ndaddr2hent(AF_INET
, LOCALHOST
,
835 &nd_conaddrlist
, res
->nss
.host
.hent
,
836 args
->arg
.nss
.host
.buf
,
837 args
->arg
.nss
.host
.buflen
);
838 (void) mutex_unlock(&nd_addr_lock
);
839 if (_nderror
!= ND_OK
)
840 *(res
->nss
.host
.herrno_p
) =
847 case NETDIR_BY_NOSRV
:
849 struct sockaddr_in
*sin
;
851 if (args
->arg
.nd_nbuf
== NULL
) {
852 _nderror
= ND_BADARG
;
857 * Validate the address which was passed
860 /* LINTED pointer cast */
861 sin
= (struct sockaddr_in
*)args
->arg
.nd_nbuf
->buf
;
863 if ((args
->arg
.nd_nbuf
->len
!=
864 sizeof (struct sockaddr_in
)) ||
865 (sin
->sin_family
!= AF_INET
)) {
866 _nderror
= ND_BADARG
;
873 case NETDIR_BY_NOSRV6
:
875 struct sockaddr_in6
*sin6
;
877 if (args
->arg
.nd_nbuf
== NULL
) {
878 _nderror
= ND_BADARG
;
883 * Validate the address which was passed
886 /* LINTED pointer cast */
887 sin6
= (struct sockaddr_in6
*)args
->arg
.nd_nbuf
->buf
;
889 if ((args
->arg
.nd_nbuf
->len
!=
890 sizeof (struct sockaddr_in6
)) ||
891 (sin6
->sin6_family
!= AF_INET6
)) {
892 _nderror
= ND_BADARG
;
901 * 2. Most common scenario. This is the way we ship /etc/netconfig.
902 * Emphasis on improving performance in the "if" part.
904 if (nconf
->nc_nlookups
== 0) {
905 struct hostent
*he
= NULL
, *tmphe
;
906 struct servent
*se
= NULL
;
907 nss_XbyY_buf_t
*ndbuf4host
= 0;
908 nss_XbyY_buf_t
*ndbuf4serv
= 0;
910 (strcmp(nconf
->nc_proto
, NC_TCP
) == 0) ? NC_TCP
: NC_UDP
;
911 struct sockaddr_in
*sa
;
912 struct sockaddr_in6
*sin6
;
913 struct in_addr
*addr4
= 0;
914 struct in6_addr v4mapbuf
;
917 switch (args
->op_t
) {
921 he
= DOOR_GETHOSTBYADDR_R(args
->arg
.nss
.host
.addr
,
922 args
->arg
.nss
.host
.len
, args
->arg
.nss
.host
.type
,
923 res
->nss
.host
.hent
, args
->arg
.nss
.host
.buf
,
924 args
->arg
.nss
.host
.buflen
,
925 res
->nss
.host
.herrno_p
);
927 _nderror
= ND_NOHOST
;
934 he
= DOOR_GETIPNODEBYADDR_R(args
->arg
.nss
.host
.addr
,
935 args
->arg
.nss
.host
.len
, args
->arg
.nss
.host
.type
,
936 res
->nss
.host
.hent
, args
->arg
.nss
.host
.buf
,
937 args
->arg
.nss
.host
.buflen
,
938 res
->nss
.host
.herrno_p
);
947 se
= _switch_getservbyport_r(args
->arg
.nss
.serv
.port
,
948 args
->arg
.nss
.serv
.proto
,
949 res
->nss
.serv
, args
->arg
.nss
.serv
.buf
,
950 args
->arg
.nss
.serv
.buflen
);
953 _nderror
= ND_NOSERV
;
959 case NETDIR_BY_NOSRV
:
961 ndbuf4serv
= _nss_XbyY_buf_alloc(sizeof (struct servent
),
962 NSS_BUFLEN_SERVICES
);
963 if (ndbuf4serv
== 0) {
967 /* LINTED pointer cast */
968 sa
= (struct sockaddr_in
*)(args
->arg
.nd_nbuf
->buf
);
969 addr4
= (struct in_addr
*)&(sa
->sin_addr
);
972 * if NETDIR_BY_NOSRV or port == 0 skip the service
975 if (args
->op_t
!= NETDIR_BY_NOSRV
&& sa
->sin_port
!= 0) {
976 se
= _switch_getservbyport_r(sa
->sin_port
, proto
,
977 ndbuf4serv
->result
, ndbuf4serv
->buffer
,
980 NSS_XbyY_FREE(&ndbuf4serv
);
982 * We can live with this - i.e. the address
984 * belong to a well known service. The caller
985 * traditionally accepts a stringified port
987 * as the service name. The state of se is used
988 * ahead to indicate the same.
989 * However, we do not tolerate this nonsense
990 * when we cannot get a host name. See below.
995 ndbuf4host
= _nss_XbyY_buf_alloc(sizeof (struct hostent
),
997 if (ndbuf4host
== 0) {
999 NSS_XbyY_FREE(&ndbuf4serv
);
1000 _nderror
= ND_NOMEM
;
1005 * Since we're going to search the ipnodes (v6) path first,
1006 * we need to treat the address as a v4mapped address.
1009 IN6_INADDR_TO_V4MAPPED(addr4
, &v4mapbuf
);
1010 if ((tmphe
= DOOR_GETIPNODEBYADDR_R((char *)&v4mapbuf
,
1011 16, AF_INET6
, ndbuf4host
->result
,
1013 ndbuf4host
->buflen
, &h_errnop
)) != NULL
)
1014 he
= __mappedtov4(tmphe
, &h_errnop
);
1017 /* Failover case, try hosts db for v4 address */
1018 he
= DOOR_GETHOSTBYADDR_R((char *)
1019 &(sa
->sin_addr
.s_addr
), 4,
1020 sa
->sin_family
, ndbuf4host
->result
,
1021 ndbuf4host
->buffer
, ndbuf4host
->buflen
,
1024 NSS_XbyY_FREE(&ndbuf4host
);
1026 NSS_XbyY_FREE(&ndbuf4serv
);
1027 _nderror
= __herrno2netdir(h_errnop
);
1031 * Convert host names and service names into hostserv
1032 * pairs. malloc's will be done, freed using
1035 h_errnop
= hsents2ndhostservs(he
, se
,
1036 sa
->sin_port
, res
->nd_hslist
);
1039 * Convert host names and service names into hostserv
1040 * pairs. malloc's will be done, freed using
1043 h_errnop
= hsents2ndhostservs(he
, se
,
1044 sa
->sin_port
, res
->nd_hslist
);
1048 NSS_XbyY_FREE(&ndbuf4host
);
1050 NSS_XbyY_FREE(&ndbuf4serv
);
1051 _nderror
= __herrno2netdir(h_errnop
);
1055 case NETDIR_BY_NOSRV6
:
1057 ndbuf4serv
= _nss_XbyY_buf_alloc(sizeof (struct servent
),
1058 NSS_BUFLEN_SERVICES
);
1059 if (ndbuf4serv
== 0) {
1060 _nderror
= ND_NOMEM
;
1063 /* LINTED pointer cast */
1064 sin6
= (struct sockaddr_in6
*)(args
->arg
.nd_nbuf
->buf
);
1067 * if NETDIR_BY_NOSRV6 or port == 0 skip the service
1070 if (args
->op_t
!= NETDIR_BY_NOSRV6
&& sin6
->sin6_port
== 0) {
1071 se
= _switch_getservbyport_r(sin6
->sin6_port
, proto
,
1072 ndbuf4serv
->result
, ndbuf4serv
->buffer
,
1073 ndbuf4serv
->buflen
);
1075 NSS_XbyY_FREE(&ndbuf4serv
);
1077 * We can live with this - i.e. the address does
1078 * not * belong to a well known service. The
1079 * caller traditionally accepts a stringified
1081 * as the service name. The state of se is used
1082 * ahead to indicate the same.
1083 * However, we do not tolerate this nonsense
1084 * when we cannot get a host name. See below.
1089 ndbuf4host
= _nss_XbyY_buf_alloc(sizeof (struct hostent
),
1091 if (ndbuf4host
== 0) {
1093 NSS_XbyY_FREE(&ndbuf4serv
);
1094 _nderror
= ND_NOMEM
;
1097 he
= DOOR_GETIPNODEBYADDR_R((char *)&(sin6
->sin6_addr
),
1098 16, sin6
->sin6_family
, ndbuf4host
->result
,
1100 ndbuf4host
->buflen
, &h_errnop
);
1102 NSS_XbyY_FREE(&ndbuf4host
);
1104 NSS_XbyY_FREE(&ndbuf4serv
);
1105 _nderror
= __herrno2netdir(h_errnop
);
1109 * Convert host names and service names into hostserv
1110 * pairs. malloc's will be done, freed using netdir_free.
1112 h_errnop
= hsents2ndhostservs(he
, se
,
1113 sin6
->sin6_port
, res
->nd_hslist
);
1115 NSS_XbyY_FREE(&ndbuf4host
);
1117 NSS_XbyY_FREE(&ndbuf4serv
);
1118 _nderror
= __herrno2netdir(h_errnop
);
1122 _nderror
= ND_BADARG
;
1123 return (_nderror
); /* should never happen */
1128 * 3. We come this far only if nametoaddr libs are specified for
1129 * inet transports and we are called by gethost/servbyname only.
1131 switch (args
->op_t
) {
1133 struct nd_hostservlist
*addrs
;
1134 struct sockaddr_in sa
;
1138 /* LINTED pointer cast */
1139 sa
.sin_addr
.s_addr
= *(uint32_t *)args
->arg
.nss
.host
.addr
;
1140 sa
.sin_family
= AF_INET
;
1141 /* Hopefully, third-parties get this optimization */
1143 nbuf
.buf
= (char *)&sa
;
1144 nbuf
.len
= nbuf
.maxlen
= sizeof (sa
);
1145 if ((_nderror
= __classic_netdir_getbyaddr(nconf
,
1146 &addrs
, &nbuf
)) != 0) {
1147 *(res
->nss
.host
.herrno_p
) = nd2herrno(_nderror
);
1151 * convert the host-serv pairs into h_aliases and hent.
1153 _nderror
= ndhostserv2hent(&nbuf
, addrs
, res
->nss
.host
.hent
,
1154 args
->arg
.nss
.host
.buf
, args
->arg
.nss
.host
.buflen
);
1155 if (_nderror
!= ND_OK
)
1156 *(res
->nss
.host
.herrno_p
) = nd2herrno(_nderror
);
1157 netdir_free((char *)addrs
, ND_HOSTSERVLIST
);
1162 if (args
->arg
.nss
.serv
.proto
== NULL
) {
1164 * A similar HACK showed up in Solaris 2.3.
1165 * The caller wild-carded proto -- i.e. will
1166 * accept a match on tcp or udp for the port
1167 * number. Since we have no hope of getting
1168 * directly to a name service switch backend
1169 * from here that understands this semantics,
1170 * we try calling the netdir interfaces first
1171 * with "tcp" and then "udp".
1173 args
->arg
.nss
.serv
.proto
= "tcp";
1174 _nderror
= _get_hostserv_inetnetdir_byaddr(nconf
, args
,
1176 if (_nderror
!= ND_OK
) {
1177 args
->arg
.nss
.serv
.proto
= "udp";
1179 _get_hostserv_inetnetdir_byaddr(nconf
,
1186 * Third-party nametoaddr_libs should be optimized for
1187 * this case. It also gives a special semantics twist to
1188 * netdir_getbyaddr. Only for the INADDR_ANY case, it gives
1189 * higher priority to service lookups (over host lookups).
1190 * If service lookup fails, the backend returns ND_NOSERV to
1191 * facilitate lookup in the "next" naming service.
1194 sa
.sin_addr
.s_addr
= INADDR_ANY
;
1195 sa
.sin_family
= AF_INET
;
1196 sa
.sin_port
= (ushort_t
)args
->arg
.nss
.serv
.port
;
1197 sa
.sin_zero
[0] = '\0';
1198 nbuf
.buf
= (char *)&sa
;
1199 nbuf
.len
= nbuf
.maxlen
= sizeof (sa
);
1200 if ((_nderror
= __classic_netdir_getbyaddr(nconf
,
1201 &addrs
, &nbuf
)) != ND_OK
) {
1205 * convert the host-serv pairs into s_aliases and servent.
1207 _nderror
= ndhostserv2srent(args
->arg
.nss
.serv
.port
,
1208 args
->arg
.nss
.serv
.proto
, addrs
, res
->nss
.serv
,
1209 args
->arg
.nss
.serv
.buf
, args
->arg
.nss
.serv
.buflen
);
1210 netdir_free((char *)addrs
, ND_HOSTSERVLIST
);
1214 _nderror
= ND_BADARG
;
1215 return (_nderror
); /* should never happen */
1220 * Part II: Name Service Switch interfacing routines.
1223 static DEFINE_NSS_DB_ROOT(db_root_hosts
);
1224 static DEFINE_NSS_DB_ROOT(db_root_ipnodes
);
1225 static DEFINE_NSS_DB_ROOT(db_root_services
);
1229 * There is a copy of __nss2herrno() in nsswitch/files/gethostent.c.
1230 * It is there because /etc/lib/nss_files.so.1 cannot call
1231 * routines in libnsl. Care should be taken to keep the two copies
1232 * in sync (except that case NSS_NISSERVDNS_TRYAGAIN is not needed in
1236 __nss2herrno(nss_status_t nsstat
)
1240 /* no macro-defined success code for h_errno */
1243 return (HOST_NOT_FOUND
);
1247 return (NO_RECOVERY
);
1248 case NSS_NISSERVDNS_TRYAGAIN
:
1252 return (NO_RECOVERY
);
1256 _herrno2nss(int h_errno
)
1260 return (NSS_SUCCESS
);
1262 return (NSS_TRYAGAIN
);
1264 case NETDB_INTERNAL
:
1265 return (NSS_UNAVAIL
);
1266 case HOST_NOT_FOUND
:
1269 return (NSS_NOTFOUND
);
1274 __herrno2netdir(int h_errnop
)
1279 case HOST_NOT_FOUND
:
1282 return (ND_TRY_AGAIN
);
1284 case NETDB_INTERNAL
:
1285 return (ND_NO_RECOVERY
);
1287 return (ND_NO_DATA
);
1294 * The _switch_getXXbyYY_r() routines should be static. They used to
1295 * be exported in SunOS 5.3, and in fact publicised as work-around
1296 * interfaces for getting CNAME/aliases, and therefore, we preserve
1297 * their signatures here. Just in case.
1301 _switch_gethostbyname_r(const char *name
, struct hostent
*result
, char *buffer
,
1302 int buflen
, int *h_errnop
)
1304 nss_XbyY_args_t arg
;
1307 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2hostent
);
1308 arg
.key
.name
= name
;
1310 res
= nss_search(&db_root_hosts
, _nss_initf_hosts
,
1311 NSS_DBOP_HOSTS_BYNAME
, &arg
);
1313 if (res
!= NSS_SUCCESS
)
1314 *h_errnop
= arg
.h_errno
? arg
.h_errno
: __nss2herrno(res
);
1315 if (arg
.returnval
!= NULL
)
1316 order_haddrlist_af(result
->h_addrtype
, result
->h_addr_list
);
1317 return ((struct hostent
*)NSS_XbyY_FINI(&arg
));
1321 _switch_getipnodebyname_r(const char *name
, struct hostent
*result
,
1322 char *buffer
, int buflen
, int af_family
, int flags
, int *h_errnop
)
1324 nss_XbyY_args_t arg
;
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
;
1332 res
= nss_search(&db_root_ipnodes
, _nss_initf_ipnodes
,
1333 NSS_DBOP_IPNODES_BYNAME
, &arg
);
1335 if (res
!= NSS_SUCCESS
)
1336 *h_errnop
= arg
.h_errno
? arg
.h_errno
: __nss2herrno(res
);
1337 if (arg
.returnval
!= NULL
)
1338 order_haddrlist_af(result
->h_addrtype
, result
->h_addr_list
);
1339 return ((struct hostent
*)NSS_XbyY_FINI(&arg
));
1343 _switch_gethostbyaddr_r(const char *addr
, int len
, int type
,
1344 struct hostent
*result
, char *buffer
, int buflen
, int *h_errnop
)
1346 nss_XbyY_args_t arg
;
1349 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2hostent
);
1350 arg
.key
.hostaddr
.addr
= addr
;
1351 arg
.key
.hostaddr
.len
= len
;
1352 arg
.key
.hostaddr
.type
= type
;
1354 res
= nss_search(&db_root_hosts
, _nss_initf_hosts
,
1355 NSS_DBOP_HOSTS_BYADDR
, &arg
);
1357 if (res
!= NSS_SUCCESS
)
1358 *h_errnop
= arg
.h_errno
? arg
.h_errno
: __nss2herrno(res
);
1359 return (struct hostent
*)NSS_XbyY_FINI(&arg
);
1363 _switch_getipnodebyaddr_r(const char *addr
, int len
, int type
,
1364 struct hostent
*result
, char *buffer
, int buflen
, int *h_errnop
)
1366 nss_XbyY_args_t arg
;
1369 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2hostent6
);
1370 arg
.key
.hostaddr
.addr
= addr
;
1371 arg
.key
.hostaddr
.len
= len
;
1372 arg
.key
.hostaddr
.type
= type
;
1374 res
= nss_search(&db_root_ipnodes
, _nss_initf_ipnodes
,
1375 NSS_DBOP_IPNODES_BYADDR
, &arg
);
1377 if (res
!= NSS_SUCCESS
)
1378 *h_errnop
= arg
.h_errno
? arg
.h_errno
: __nss2herrno(res
);
1379 return (struct hostent
*)NSS_XbyY_FINI(&arg
);
1383 _nss_initf_services(nss_db_params_t
*p
)
1385 p
->name
= NSS_DBNAM_SERVICES
;
1386 p
->default_config
= NSS_DEFCONF_SERVICES
;
1390 _switch_getservbyname_r(const char *name
, const char *proto
,
1391 struct servent
*result
, char *buffer
, int buflen
)
1393 nss_XbyY_args_t arg
;
1396 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2servent
);
1397 arg
.key
.serv
.serv
.name
= name
;
1398 arg
.key
.serv
.proto
= proto
;
1400 res
= nss_search(&db_root_services
, _nss_initf_services
,
1401 NSS_DBOP_SERVICES_BYNAME
, &arg
);
1403 return ((struct servent
*)NSS_XbyY_FINI(&arg
));
1407 _switch_getservbyport_r(int port
, const char *proto
, struct servent
*result
,
1408 char *buffer
, int buflen
)
1410 nss_XbyY_args_t arg
;
1413 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2servent
);
1414 arg
.key
.serv
.serv
.port
= port
;
1415 arg
.key
.serv
.proto
= proto
;
1417 res
= nss_search(&db_root_services
, _nss_initf_services
,
1418 NSS_DBOP_SERVICES_BYPORT
, &arg
);
1420 return ((struct servent
*)NSS_XbyY_FINI(&arg
));
1425 * Return values: 0 = success, 1 = parse error, 2 = erange ...
1426 * The structure pointer passed in is a structure in the caller's space
1427 * wherein the field pointers would be set to areas in the buffer if
1428 * need be. instring and buffer should be separate areas.
1430 * Defined here because we need it and we (libnsl) cannot have a dependency
1431 * on libsocket (however, libsocket always depends on libnsl).
1434 str2servent(const char *instr
, int lenstr
, void *ent
, char *buffer
, int buflen
)
1436 struct servent
*serv
= (struct servent
*)ent
;
1437 const char *p
, *fieldstart
, *limit
, *namestart
;
1438 ssize_t fieldlen
, namelen
= 0;
1442 if ((instr
>= buffer
&& (buffer
+ buflen
) > instr
) ||
1443 (buffer
>= instr
&& (instr
+ lenstr
) > buffer
)) {
1444 return (NSS_STR_PARSE_PARSE
);
1450 while (p
< limit
&& isspace(*p
)) {
1454 while (p
< limit
&& !isspace(*p
)) {
1455 p
++; /* Skip over the canonical name */
1457 namelen
= p
- namestart
;
1459 if (buflen
<= namelen
) { /* not enough buffer */
1460 return (NSS_STR_PARSE_ERANGE
);
1462 (void) memcpy(buffer
, namestart
, namelen
);
1463 buffer
[namelen
] = '\0';
1464 serv
->s_name
= buffer
;
1466 while (p
< limit
&& isspace(*p
)) {
1472 if (p
> limit
|| isspace(*p
)) {
1473 /* Syntax error -- no port/proto */
1474 return (NSS_STR_PARSE_PARSE
);
1476 } while (*p
++ != '/');
1477 fieldlen
= p
- fieldstart
- 1;
1478 if (fieldlen
== 0 || fieldlen
>= sizeof (numbuf
)) {
1479 /* Syntax error -- supposed number is empty or too long */
1480 return (NSS_STR_PARSE_PARSE
);
1482 (void) memcpy(numbuf
, fieldstart
, fieldlen
);
1483 numbuf
[fieldlen
] = '\0';
1484 serv
->s_port
= htons((int)strtol(numbuf
, &numend
, 10));
1485 if (*numend
!= '\0') {
1486 /* Syntax error -- port number isn't a number */
1487 return (NSS_STR_PARSE_PARSE
);
1491 while (p
< limit
&& !isspace(*p
)) {
1492 p
++; /* Scan the protocol name */
1494 fieldlen
= p
- fieldstart
+ 1; /* Include '\0' this time */
1495 if (fieldlen
> buflen
- namelen
- 1) {
1496 return (NSS_STR_PARSE_ERANGE
);
1498 serv
->s_proto
= buffer
+ namelen
+ 1;
1499 (void) memcpy(serv
->s_proto
, fieldstart
, fieldlen
- 1);
1500 serv
->s_proto
[fieldlen
- 1] = '\0';
1502 while (p
< limit
&& isspace(*p
)) {
1506 * Although nss_files_XY_all calls us with # stripped,
1507 * we should be able to deal with it here in order to
1510 if (p
>= limit
|| *p
== '#') { /* no aliases, no problem */
1513 ptr
= (char **)ROUND_UP(buffer
+ namelen
+ 1 + fieldlen
,
1515 if ((char *)ptr
>= buffer
+ buflen
) {
1516 /* hope they don't try to peek in */
1517 serv
->s_aliases
= 0;
1518 return (NSS_STR_PARSE_ERANGE
);
1521 serv
->s_aliases
= ptr
;
1522 return (NSS_STR_PARSE_SUCCESS
);
1525 serv
->s_aliases
= _nss_netdb_aliases(p
, (int)(lenstr
- (p
- instr
)),
1526 buffer
+ namelen
+ 1 + fieldlen
,
1527 (int)(buflen
- namelen
- 1 - fieldlen
));
1528 return (NSS_STR_PARSE_SUCCESS
);
1532 * Part III: All `n sundry routines that are useful only in this
1533 * module. In the interest of keeping this source file shorter,
1534 * we would create them a new module only if the linker allowed
1535 * "library-static" functions.
1537 * Routines to order addresses based on local interfaces and netmasks,
1538 * to get and check reserved ports, and to get broadcast nets.
1542 struct in6_addr in6
;
1548 union __v4v6addr addr
;
1549 union __v4v6addr mask
;
1554 struct __ifaddr
*addresses
;
1557 typedef enum {ADDR_ONLINK
= 0, ADDR_OFFLINK
} addr_class_t
;
1558 #define ADDR_NUMCLASSES 2
1560 typedef enum {IF_ADDR
, IF_MASK
} __ifaddr_type
;
1561 static int __inet_ifassign(sa_family_t
, struct __ifaddr
*, __ifaddr_type
,
1563 int __inet_address_is_local_af(void *, sa_family_t
, void *);
1565 #define ifaf(index) (localinfo->addresses[index].af)
1566 #define ifaddr4(index) (localinfo->addresses[index].addr.in4)
1567 #define ifaddr6(index) (localinfo->addresses[index].addr.in6)
1568 #define ifmask4(index) (localinfo->addresses[index].mask.in4)
1569 #define ifmask6(index) (localinfo->addresses[index].mask.in6)
1570 #define ifinfosize(n) (sizeof (struct ifinfo) + (n)*sizeof (struct __ifaddr))
1572 #define lifraddrp(lifr) ((lifr.lifr_addr.ss_family == AF_INET6) ? \
1573 (void *)&((struct sockaddr_in6 *)&lifr.lifr_addr)->sin6_addr : \
1574 (void *)&((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr)
1576 #define ifassign(lifr, index, type) \
1577 __inet_ifassign(lifr.lifr_addr.ss_family, \
1578 &localinfo->addresses[index], type, \
1582 * The number of nanoseconds the order_haddrlist_inet() function waits
1583 * to retreive IP interface information. The default is five minutes.
1585 #define IFINFOTIMEOUT ((hrtime_t)300 * NANOSEC)
1588 * Sort the addresses in haddrlist. Since the sorting algorithms are
1589 * address-family specific, the work is done in the address-family
1590 * specific order_haddrlist_<family> functions.
1592 * Do not sort addresses if SORT_ADDRS variable is set to NO or FALSE
1593 * in the configuration file /etc/default/nss. This is useful in case
1594 * the order of addresses returned by the nameserver needs to be
1595 * maintained. (DNS round robin feature is one example)
1598 order_haddrlist_af(sa_family_t af
, char **haddrlist
)
1602 static boolean_t checksortcfg
= B_TRUE
;
1603 static boolean_t nosort
= B_FALSE
;
1604 static mutex_t checksortcfg_lock
= DEFAULTMUTEX
;
1606 if (haddrlist
== NULL
)
1610 * Check if SORT_ADDRS is set to NO or FALSE in the configuration
1611 * file. We do not have to sort addresses in that case.
1613 (void) mutex_lock(&checksortcfg_lock
);
1614 if (checksortcfg
== B_TRUE
) {
1615 checksortcfg
= B_FALSE
;
1616 nosort
= _read_nsw_file();
1618 (void) mutex_unlock(&checksortcfg_lock
);
1623 /* Count the addresses to sort */
1625 for (addrptr
= haddrlist
; *addrptr
!= NULL
; addrptr
++)
1629 * If there's only one address or no addresses to sort, then
1630 * there's nothing for us to do.
1635 /* Call the address-family specific sorting functions. */
1638 order_haddrlist_inet(haddrlist
, addrcount
);
1641 order_haddrlist_inet6(haddrlist
, addrcount
);
1649 * Move any local (on-link) addresses toward the beginning of haddrlist.
1650 * The order within these two classes is preserved.
1652 * The interface list is retrieved no more often than every
1653 * IFINFOTIMEOUT nanoseconds. Access to the interface list is
1654 * protected by an RW lock.
1656 * If this function encounters an error, haddrlist is unaltered.
1659 order_haddrlist_inet(char **haddrlist
, size_t addrcount
)
1661 static struct ifinfo
*localinfo
= NULL
;
1662 static hrtime_t then
= 0; /* the last time localinfo was updated */
1664 static rwlock_t localinfo_lock
= DEFAULTRWLOCK
;
1666 size_t sortbuf_size
;
1667 struct in_addr
**inaddrlist
= (struct in_addr
**)haddrlist
;
1668 struct in_addr
**sorted
;
1669 struct in_addr
**classnext
[ADDR_NUMCLASSES
];
1670 uint_t classcount
[ADDR_NUMCLASSES
];
1671 addr_class_t
*sortclass
;
1677 * The classes in the sortclass array correspond to the class
1678 * of the address in the haddrlist list of the same index.
1681 * ADDR_ONLINK on-link address
1682 * ADDR_OFFLINK off-link address
1684 sortbuf_size
= addrcount
*
1685 (sizeof (struct in_addr
*) + sizeof (addr_class_t
));
1686 if ((sortbuf
= malloc(sortbuf_size
)) == NULL
)
1688 /* LINTED pointer cast */
1689 sorted
= (struct in_addr
**)sortbuf
;
1690 /* LINTED pointer cast */
1691 sortclass
= (addr_class_t
*)(sortbuf
+
1692 (addrcount
* sizeof (struct in_addr
*)));
1695 * Get a read lock, and check if the interface information
1698 (void) rw_rdlock(&localinfo_lock
);
1700 if (localinfo
== NULL
|| ((now
- then
) > IFINFOTIMEOUT
)) {
1701 /* Need to update I/F info. Upgrade to write lock. */
1702 (void) rw_unlock(&localinfo_lock
);
1703 (void) rw_wrlock(&localinfo_lock
);
1705 * Another thread might have updated "then" between
1706 * the rw_unlock() and rw_wrlock() calls above, so
1707 * re-check the timeout.
1709 if (localinfo
== NULL
|| ((now
- then
) > IFINFOTIMEOUT
)) {
1711 if ((localinfo
= get_local_info()) == NULL
) {
1712 (void) rw_unlock(&localinfo_lock
);
1718 /* Downgrade to read lock */
1719 (void) rw_unlock(&localinfo_lock
);
1720 (void) rw_rdlock(&localinfo_lock
);
1722 * Another thread may have updated the I/F info,
1723 * so verify that the 'localinfo' pointer still
1726 if (localinfo
== NULL
) {
1727 (void) rw_unlock(&localinfo_lock
);
1734 * Classify the addresses. We also maintain the classcount
1735 * array to keep track of the number of addresses in each
1738 (void) memset(classcount
, 0, sizeof (classcount
));
1739 for (i
= 0; i
< addrcount
; i
++) {
1740 if (__inet_address_is_local_af(localinfo
, AF_INET
,
1742 sortclass
[i
] = ADDR_ONLINK
;
1744 sortclass
[i
] = ADDR_OFFLINK
;
1745 classcount
[sortclass
[i
]]++;
1748 /* Don't need the interface list anymore in this call */
1749 (void) rw_unlock(&localinfo_lock
);
1752 * Each element in the classnext array points to the next
1753 * element for that class in the sorted address list. 'rc' is
1754 * the running count of elements as we sum the class
1757 for (rc
= 0, i
= 0; i
< ADDR_NUMCLASSES
; i
++) {
1758 classnext
[i
] = &sorted
[rc
];
1759 rc
+= classcount
[i
];
1762 /* Now for the actual rearrangement of the addresses */
1763 for (i
= 0; i
< addrcount
; i
++) {
1764 *(classnext
[sortclass
[i
]]) = inaddrlist
[i
];
1765 classnext
[sortclass
[i
]]++;
1768 /* Copy the sorted list to inaddrlist */
1769 (void) memcpy(inaddrlist
, sorted
,
1770 addrcount
* sizeof (struct in_addr
*));
1775 * This function implements the IPv6 Default Address Selection's
1776 * destination address ordering mechanism. The algorithm is described
1777 * in getaddrinfo(3SOCKET).
1780 order_haddrlist_inet6(char **haddrlist
, size_t addrcount
)
1782 struct dstinforeq
*dinfo
, *dinfoptr
;
1783 struct in6_addr
**in6addrlist
= (struct in6_addr
**)haddrlist
;
1784 struct in6_addr
**in6addr
;
1786 if ((dinfo
= calloc(addrcount
, sizeof (struct dstinforeq
))) == NULL
)
1789 /* Initialize the dstinfo array we'll use for SIOCGDSTINFO */
1791 for (in6addr
= in6addrlist
; *in6addr
!= NULL
; in6addr
++) {
1792 dinfoptr
->dir_daddr
= **in6addr
;
1796 if (nss_strioctl(AF_INET6
, SIOCGDSTINFO
, dinfo
,
1797 addrcount
* sizeof (struct dstinforeq
)) < 0) {
1802 /* Sort the dinfo array */
1803 qsort(dinfo
, addrcount
, sizeof (struct dstinforeq
), dstcmp
);
1805 /* Copy the addresses back into in6addrlist */
1807 for (in6addr
= in6addrlist
; *in6addr
!= NULL
; in6addr
++) {
1808 **in6addr
= dinfoptr
->dir_daddr
;
1816 * Determine number of leading bits that are common between two addresses.
1817 * Only consider bits which fall within the prefix length plen.
1820 ip_addr_commonbits_v6(const in6_addr_t
*a1
, const in6_addr_t
*a2
)
1824 uint32_t diff
; /* Bits that differ */
1826 for (i
= 0; i
< 4; i
++) {
1827 if (a1
->_S6_un
._S6_u32
[i
] != a2
->_S6_un
._S6_u32
[i
])
1832 if (bits
== IPV6_ABITS
)
1833 return (IPV6_ABITS
);
1836 * Find number of leading common bits in the word which might
1837 * have some common bits by searching for the first one from the left
1838 * in the xor of the two addresses.
1840 diff
= ntohl(a1
->_S6_un
._S6_u32
[i
] ^ a2
->_S6_un
._S6_u32
[i
]);
1841 if (diff
& 0xffff0000ul
)
1861 * We don't need to shift and check for the last bit. The
1862 * check for IPV6_ABITS above would have caught that.
1870 * The following group of functions named rule_*() are individual
1871 * sorting rules for the AF_INET6 address sorting algorithm. The
1872 * functions compare two addresses (described by two dstinforeq
1873 * structures), and determines if one is "greater" than the other, or
1874 * if the two are equal according to that rule.
1876 typedef int (*rulef_t
)(const struct dstinforeq
*, const struct dstinforeq
*);
1879 * These values of these constants are no accident. Since qsort()
1880 * implements the AF_INET6 address sorting, the comparison function
1881 * must return an integer less than, equal to, or greater than zero to
1882 * indicate if the first address is considered "less than", "equal
1883 * to", or "greater than" the second one. Since we want the best
1884 * addresses first on the list, "less than" is considered preferrable.
1886 #define RULE_PREFER_DA -1
1887 #define RULE_PREFER_DB 1
1888 #define RULE_EQUAL 0
1890 /* Prefer the addresses that is reachable. */
1892 rule_reachable(const struct dstinforeq
*da
, const struct dstinforeq
*db
)
1894 if (da
->dir_dreachable
== db
->dir_dreachable
)
1895 return (RULE_EQUAL
);
1896 if (da
->dir_dreachable
)
1897 return (RULE_PREFER_DA
);
1898 return (RULE_PREFER_DB
);
1901 /* Prefer the address whose scope matches that of its source address. */
1903 rule_matchscope(const struct dstinforeq
*da
, const struct dstinforeq
*db
)
1905 boolean_t da_scope_match
, db_scope_match
;
1907 da_scope_match
= da
->dir_dscope
== da
->dir_sscope
;
1908 db_scope_match
= db
->dir_dscope
== db
->dir_sscope
;
1910 if (da_scope_match
== db_scope_match
)
1911 return (RULE_EQUAL
);
1913 return (RULE_PREFER_DA
);
1914 return (RULE_PREFER_DB
);
1917 /* Avoid the address with the link local source address. */
1919 rule_avoidlinklocal(const struct dstinforeq
*da
, const struct dstinforeq
*db
)
1921 if (da
->dir_sscope
== IP6_SCOPE_LINKLOCAL
&&
1922 da
->dir_dscope
!= IP6_SCOPE_LINKLOCAL
&&
1923 db
->dir_sscope
!= IP6_SCOPE_LINKLOCAL
)
1924 return (RULE_PREFER_DB
);
1925 if (db
->dir_sscope
== IP6_SCOPE_LINKLOCAL
&&
1926 db
->dir_dscope
!= IP6_SCOPE_LINKLOCAL
&&
1927 da
->dir_sscope
!= IP6_SCOPE_LINKLOCAL
)
1928 return (RULE_PREFER_DA
);
1929 return (RULE_EQUAL
);
1932 /* Prefer the address whose source address isn't deprecated. */
1934 rule_deprecated(const struct dstinforeq
*da
, const struct dstinforeq
*db
)
1936 if (da
->dir_sdeprecated
== db
->dir_sdeprecated
)
1937 return (RULE_EQUAL
);
1938 if (db
->dir_sdeprecated
)
1939 return (RULE_PREFER_DA
);
1940 return (RULE_PREFER_DB
);
1943 /* Prefer the address whose label matches that of its source address. */
1945 rule_label(const struct dstinforeq
*da
, const struct dstinforeq
*db
)
1947 if (da
->dir_labelmatch
== db
->dir_labelmatch
)
1948 return (RULE_EQUAL
);
1949 if (da
->dir_labelmatch
)
1950 return (RULE_PREFER_DA
);
1951 return (RULE_PREFER_DB
);
1954 /* Prefer the address with the higher precedence. */
1956 rule_precedence(const struct dstinforeq
*da
, const struct dstinforeq
*db
)
1958 if (da
->dir_precedence
== db
->dir_precedence
)
1959 return (RULE_EQUAL
);
1960 if (da
->dir_precedence
> db
->dir_precedence
)
1961 return (RULE_PREFER_DA
);
1962 return (RULE_PREFER_DB
);
1965 /* Prefer the address whose output interface isn't an IP tunnel */
1967 rule_native(const struct dstinforeq
*da
, const struct dstinforeq
*db
)
1969 boolean_t isatun
, isbtun
;
1971 /* Get the common case out of the way early */
1972 if (da
->dir_dmactype
== db
->dir_dmactype
)
1973 return (RULE_EQUAL
);
1975 isatun
= da
->dir_dmactype
== DL_IPV4
|| da
->dir_dmactype
== DL_IPV6
;
1976 isbtun
= db
->dir_dmactype
== DL_IPV4
|| db
->dir_dmactype
== DL_IPV6
;
1978 if (isatun
== isbtun
)
1979 return (RULE_EQUAL
);
1981 return (RULE_PREFER_DA
);
1982 return (RULE_PREFER_DB
);
1985 /* Prefer the address with the smaller scope. */
1987 rule_scope(const struct dstinforeq
*da
, const struct dstinforeq
*db
)
1989 if (da
->dir_dscope
== db
->dir_dscope
)
1990 return (RULE_EQUAL
);
1991 if (da
->dir_dscope
< db
->dir_dscope
)
1992 return (RULE_PREFER_DA
);
1993 return (RULE_PREFER_DB
);
1997 * Prefer the address that has the most leading bits in common with its
2001 rule_prefix(const struct dstinforeq
*da
, const struct dstinforeq
*db
)
2003 uint_t da_commonbits
, db_commonbits
;
2004 boolean_t da_isipv4
, db_isipv4
;
2006 da_isipv4
= IN6_IS_ADDR_V4MAPPED(&da
->dir_daddr
);
2007 db_isipv4
= IN6_IS_ADDR_V4MAPPED(&db
->dir_daddr
);
2010 * At this point, the order doesn't matter if the two addresses
2011 * aren't of the same address family.
2013 if (da_isipv4
!= db_isipv4
)
2014 return (RULE_EQUAL
);
2016 da_commonbits
= ip_addr_commonbits_v6(&da
->dir_daddr
, &da
->dir_saddr
);
2017 db_commonbits
= ip_addr_commonbits_v6(&db
->dir_daddr
, &db
->dir_saddr
);
2019 if (da_commonbits
> db_commonbits
)
2020 return (RULE_PREFER_DA
);
2021 if (da_commonbits
< db_commonbits
)
2022 return (RULE_PREFER_DB
);
2023 return (RULE_EQUAL
);
2027 * This is the function passed to qsort() that does the AF_INET6
2028 * address comparisons. It compares two addresses using a list of
2029 * rules. The rules are applied in order until one prefers one
2030 * address over the other.
2033 dstcmp(const void *da
, const void *db
)
2039 rule_avoidlinklocal
,
2050 for (index
= 0; rules
[index
] != NULL
; index
++) {
2051 result
= (rules
[index
])(da
, db
);
2052 if (result
!= RULE_EQUAL
)
2060 * Given haddrlist and a port number, mallocs and populates a new
2061 * nd_addrlist. The new nd_addrlist maintains the order of the addresses
2062 * in haddrlist, which have already been sorted by order_haddrlist_inet()
2063 * or order_haddrlist_inet6(). For IPv6 this function filters out
2064 * IPv4-mapped IPv6 addresses.
2067 hent2ndaddr(int af
, char **haddrlist
, int *servp
, struct nd_addrlist
**nd_alist
)
2069 struct nd_addrlist
*result
;
2072 struct sockaddr_in
*sinbuf
, *sin
;
2073 struct sockaddr_in6
*sin6buf
, *sin6
;
2074 struct in_addr
**inaddr
, **inaddrlist
;
2075 struct in6_addr
**in6addr
, **in6addrlist
;
2079 if (af
== AF_INET6
) {
2080 in6addrlist
= (struct in6_addr
**)haddrlist
;
2083 * Exclude IPv4-mapped IPv6 addresses from the count, as
2084 * these are not included in the nd_addrlist we return.
2086 for (in6addr
= in6addrlist
; *in6addr
!= NULL
; in6addr
++)
2087 if (!IN6_IS_ADDR_V4MAPPED(*in6addr
))
2090 inaddrlist
= (struct in_addr
**)haddrlist
;
2092 for (inaddr
= inaddrlist
; *inaddr
!= NULL
; inaddr
++)
2098 result
= malloc(sizeof (struct nd_addrlist
));
2102 result
->n_cnt
= num
;
2103 result
->n_addrs
= calloc(num
, sizeof (struct netbuf
));
2104 if (result
->n_addrs
== 0) {
2109 na
= result
->n_addrs
;
2110 if (af
== AF_INET
) {
2111 sinbuf
= calloc(num
, sizeof (struct sockaddr_in
));
2112 if (sinbuf
== NULL
) {
2113 free(result
->n_addrs
);
2119 for (inaddr
= inaddrlist
; *inaddr
!= NULL
; inaddr
++) {
2120 na
->len
= na
->maxlen
= sizeof (struct sockaddr_in
);
2121 na
->buf
= (char *)sin
;
2122 sin
->sin_family
= AF_INET
;
2123 sin
->sin_addr
= **inaddr
;
2124 sin
->sin_port
= *servp
;
2128 } else if (af
== AF_INET6
) {
2129 sin6buf
= calloc(num
, sizeof (struct sockaddr_in6
));
2130 if (sin6buf
== NULL
) {
2131 free(result
->n_addrs
);
2137 for (in6addr
= in6addrlist
; *in6addr
!= NULL
; in6addr
++) {
2138 if (IN6_IS_ADDR_V4MAPPED(*in6addr
))
2141 na
->len
= na
->maxlen
= sizeof (struct sockaddr_in6
);
2142 na
->buf
= (char *)sin6
;
2143 sin6
->sin6_family
= AF_INET6
;
2144 sin6
->sin6_addr
= **in6addr
;
2145 sin6
->sin6_port
= *servp
;
2150 *(nd_alist
) = result
;
2155 * Given a hostent and a servent, mallocs and populates
2156 * a new nd_hostservlist with host and service names.
2158 * We could be passed in a NULL servent, in which case stringify port.
2161 hsents2ndhostservs(struct hostent
*he
, struct servent
*se
,
2162 ushort_t port
, struct nd_hostservlist
**hslist
)
2164 struct nd_hostservlist
*result
;
2165 struct nd_hostserv
*hs
;
2166 int hosts
, servs
, i
, j
;
2169 if ((result
= malloc(sizeof (struct nd_hostservlist
))) == 0)
2173 * We initialize the counters to 1 rather than zero because
2174 * we have to count the "official" name as well as the aliases.
2176 for (hn
= he
->h_aliases
, hosts
= 1; hn
&& *hn
; hn
++, hosts
++) {};
2178 for (sn
= se
->s_aliases
, servs
= 1; sn
&& *sn
; sn
++, servs
++) {
2183 if ((hs
= calloc(hosts
* servs
, sizeof (struct nd_hostserv
))) == 0) {
2188 result
->h_cnt
= servs
* hosts
;
2189 result
->h_hostservs
= hs
;
2191 for (i
= 0, hn
= he
->h_aliases
; i
< hosts
; i
++) {
2192 sn
= se
? se
->s_aliases
: NULL
;
2194 for (j
= 0; j
< servs
; j
++) {
2196 hs
->h_host
= strdup(he
->h_name
);
2198 hs
->h_host
= strdup(*hn
);
2201 hs
->h_serv
= strdup(se
->s_name
);
2203 /* Convert to a number string */
2206 (void) sprintf(stmp
, "%d", port
);
2207 hs
->h_serv
= strdup(stmp
);
2210 hs
->h_serv
= strdup(*sn
++);
2212 if ((hs
->h_host
== 0) || (hs
->h_serv
== 0)) {
2213 free(result
->h_hostservs
);
2227 * Process results from nd_addrlist ( returned by netdir_getbyname)
2228 * into a hostent using buf.
2229 * *** ASSUMES that nd_addrlist->n_addrs->buf contains IP addresses in
2233 ndaddr2hent(int af
, const char *nam
, struct nd_addrlist
*addrs
,
2234 struct hostent
*result
, char *buffer
, int buflen
)
2237 struct in_addr
*addrp
;
2238 struct in6_addr
*addr6p
;
2243 result
->h_name
= buffer
;
2244 result
->h_addrtype
= af
;
2245 result
->h_length
= (af
== AF_INET
) ? sizeof (*addrp
):
2249 * Build addrlist at start of buffer (after name); store the
2250 * addresses themselves at the end of the buffer.
2252 len
= strlen(nam
) + 1;
2253 addrvec
= (char **)ROUND_UP(buffer
+ len
, sizeof (*addrvec
));
2254 result
->h_addr_list
= addrvec
;
2256 if (af
== AF_INET
) {
2257 addrp
= (struct in_addr
*)ROUND_DOWN(buffer
+ buflen
,
2260 count
= addrs
->n_cnt
;
2261 if ((char *)(&addrvec
[count
+ 1]) > (char *)(&addrp
[-count
]))
2264 (void) memcpy(buffer
, nam
, len
);
2266 for (na
= addrs
->n_addrs
, i
= 0; i
< count
; na
++, i
++) {
2268 (void) memcpy(addrp
,
2269 /* LINTED pointer cast */
2270 &((struct sockaddr_in
*)na
->buf
)->sin_addr
,
2272 *addrvec
++ = (char *)addrp
;
2275 addr6p
= (struct in6_addr
*)ROUND_DOWN(buffer
+ buflen
,
2278 count
= addrs
->n_cnt
;
2279 if ((char *)(&addrvec
[count
+ 1]) > (char *)(&addr6p
[-count
]))
2282 (void) memcpy(buffer
, nam
, len
);
2284 for (na
= addrs
->n_addrs
, i
= 0; i
< count
; na
++, i
++) {
2286 (void) memcpy(addr6p
,
2287 /* LINTED pointer cast */
2288 &((struct sockaddr_in6
*)na
->buf
)->sin6_addr
,
2290 *addrvec
++ = (char *)addr6p
;
2294 result
->h_aliases
= addrvec
;
2300 * Process results from nd_addrlist ( returned by netdir_getbyname)
2301 * into a servent using buf.
2304 ndaddr2srent(const char *name
, const char *proto
, ushort_t port
,
2305 struct servent
*result
, char *buffer
, int buflen
)
2308 char *bufend
= (buffer
+ buflen
);
2310 result
->s_port
= (int)port
;
2313 (char **)ROUND_UP(buffer
, sizeof (char *));
2314 result
->s_aliases
[0] = NULL
;
2315 buffer
= (char *)&result
->s_aliases
[1];
2316 result
->s_name
= buffer
;
2317 i
= strlen(name
) + 1;
2318 if ((buffer
+ i
) > bufend
)
2320 (void) memcpy(buffer
, name
, i
);
2323 result
->s_proto
= buffer
;
2324 i
= strlen(proto
) + 1;
2325 if ((buffer
+ i
) > bufend
)
2327 (void) memcpy(buffer
, proto
, i
);
2334 * Process results from nd_hostservlist ( returned by netdir_getbyaddr)
2335 * into a hostent using buf.
2336 * *** ASSUMES that nd_buf->buf is a sockaddr_in ***
2339 ndhostserv2hent(struct netbuf
*nbuf
, struct nd_hostservlist
*addrs
,
2340 struct hostent
*result
, char *buffer
, int buflen
)
2345 struct sockaddr_in
*sa
;
2346 struct nd_hostserv
*hs
;
2350 /* First, give the lonely address a specious home in h_addr_list. */
2351 aliasp
= (char *)ROUND_UP(buffer
, sizeof (sa
->sin_addr
));
2352 /* LINTED pointer cast */
2353 sa
= (struct sockaddr_in
*)nbuf
->buf
;
2354 (void) memcpy(aliasp
, &(sa
->sin_addr
), sizeof (sa
->sin_addr
));
2355 aliasvec
= (char **)ROUND_UP(aliasp
+ sizeof (sa
->sin_addr
),
2356 sizeof (*aliasvec
));
2357 result
->h_addr_list
= aliasvec
;
2358 *aliasvec
++ = aliasp
;
2362 * Build h_aliases at start of buffer (after addr and h_addr_list);
2363 * store the alias strings at the end of the buffer (before h_name).
2366 aliasp
= buffer
+ buflen
;
2368 result
->h_aliases
= aliasvec
;
2370 hs
= addrs
->h_hostservs
;
2374 length
= strlen(hs
->h_host
) + 1;
2376 if ((char *)(&aliasvec
[1]) > aliasp
)
2378 (void) memcpy(aliasp
, hs
->h_host
, length
);
2380 result
->h_name
= aliasp
;
2381 result
->h_addrtype
= AF_INET
;
2382 result
->h_length
= sizeof (sa
->sin_addr
);
2385 * Assumption: the netdir nametoaddr_libs
2386 * sort the vector of (host, serv) pairs in such a way that
2387 * all pairs with the same host name are contiguous.
2390 count
= addrs
->h_cnt
;
2391 for (i
= 0; i
< count
; i
++, hs
++)
2392 if (strcmp(la
, hs
->h_host
) != 0) {
2393 size_t len
= strlen(hs
->h_host
) + 1;
2396 if ((char *)(&aliasvec
[2]) > aliasp
)
2398 (void) memcpy(aliasp
, hs
->h_host
, len
);
2399 *aliasvec
++ = aliasp
;
2408 * Process results from nd_hostservlist ( returned by netdir_getbyaddr)
2409 * into a servent using buf.
2412 ndhostserv2srent(int port
, const char *proto
, struct nd_hostservlist
*addrs
,
2413 struct servent
*result
, char *buffer
, int buflen
)
2418 struct nd_hostserv
*hs
;
2419 const char *host_cname
;
2422 result
->s_port
= port
;
2424 * Build s_aliases at start of buffer;
2425 * store proto and aliases at the end of the buffer (before h_name).
2428 aliasp
= buffer
+ buflen
;
2429 aliasvec
= (char **)ROUND_UP(buffer
, sizeof (char *));
2431 result
->s_aliases
= aliasvec
;
2433 hs
= addrs
->h_hostservs
;
2436 host_cname
= hs
->h_host
;
2438 leni
= strlen(proto
) + 1;
2439 lenj
= strlen(hs
->h_serv
) + 1;
2440 if ((char *)(&aliasvec
[2]) > (aliasp
- leni
- lenj
))
2444 (void) memcpy(aliasp
, proto
, leni
);
2445 result
->s_proto
= aliasp
;
2448 (void) memcpy(aliasp
, hs
->h_serv
, lenj
);
2449 result
->s_name
= aliasp
;
2452 * Assumption: the netdir nametoaddr_libs
2453 * do a host aliases first and serv aliases next
2454 * enumeration for creating the list of hostserv
2457 count
= addrs
->h_cnt
;
2459 i
< count
&& hs
->h_serv
&& strcmp(hs
->h_host
, host_cname
) == 0;
2461 size_t len
= strlen(hs
->h_serv
) + 1;
2464 if ((char *)(&aliasvec
[2]) > aliasp
)
2466 (void) memcpy(aliasp
, hs
->h_serv
, len
);
2467 *aliasvec
++ = aliasp
;
2483 case ND_NO_RECOVERY
:
2486 return (NO_RECOVERY
);
2491 return (HOST_NOT_FOUND
);
2493 return (NO_RECOVERY
);
2498 * This is a utility function so that various parts of libnsl can
2499 * easily send ioctls down to ip.
2503 nss_ioctl(int af
, int cmd
, void *arg
)
2518 if ((fd
= open(devpath
, O_RDONLY
)) < 0) {
2521 while ((retv
= ioctl(fd
, cmd
, arg
)) == -1) {
2530 nss_strioctl(int af
, int cmd
, void *ptr
, int ilen
)
2532 struct strioctl str
;
2539 return (nss_ioctl(af
, I_STR
, &str
));
2542 static struct ifinfo
*
2543 get_local_info(void)
2549 struct lifconf lifc
;
2550 struct lifreq lifreq
, *lifr
;
2552 struct ifinfo
*localinfo
;
2554 lifn
.lifn_family
= AF_UNSPEC
;
2555 lifn
.lifn_flags
= 0;
2558 if (nss_ioctl(AF_UNSPEC
, SIOCGLIFNUM
, &lifn
) == -1) {
2561 numifs
= lifn
.lifn_count
;
2565 * Add a small fudge factor in case interfaces get plumbed between
2566 * the call to SIOCGLIFNUM and SIOCGLIFCONF.
2568 needed
= (numifs
+ 4) * sizeof (lifreq
);
2570 buf
= malloc(needed
);
2572 buf
= realloc(buf
, needed
);
2574 (void) syslog(LOG_ERR
, "n2a get_local_info: malloc failed: %m");
2575 _nderror
= ND_NOMEM
;
2578 lifc
.lifc_family
= AF_UNSPEC
;
2579 lifc
.lifc_flags
= 0;
2580 lifc
.lifc_len
= needed
;
2581 lifc
.lifc_buf
= buf
;
2582 if (nss_ioctl(AF_UNSPEC
, SIOCGLIFCONF
, &lifc
) == -1) {
2584 * IP returns EINVAL if the buffer was too small to fit
2585 * all of the entries. If that's the case, go back and
2588 if (errno
== EINVAL
)
2591 (void) syslog(LOG_ERR
, "n2a get_local_info: "
2592 "ioctl (get interface configuration): %m");
2594 _nderror
= ND_SYSTEM
;
2597 /* LINTED pointer cast */
2598 lifr
= (struct lifreq
*)buf
;
2599 numifs
= lifc
.lifc_len
/sizeof (lifreq
);
2600 localinfo
= malloc(ifinfosize(numifs
));
2601 if (localinfo
== NULL
) {
2602 (void) syslog(LOG_ERR
, "n2a get_local_info: malloc failed: %m");
2604 _nderror
= ND_SYSTEM
;
2608 /* LINTED pointer cast */
2609 localinfo
->addresses
= (struct __ifaddr
*)
2610 ((char *)localinfo
+ sizeof (struct ifinfo
));
2612 for (localinfo
->count
= 0, n
= numifs
; n
> 0; n
--, lifr
++) {
2616 af
= lifreq
.lifr_addr
.ss_family
;
2618 /* Squirrel away the address */
2619 if (ifassign(lifreq
, localinfo
->count
, IF_ADDR
) == 0)
2622 if (nss_ioctl(af
, SIOCGLIFFLAGS
, &lifreq
) < 0) {
2623 (void) syslog(LOG_ERR
,
2624 "n2a get_local_info: "
2625 "ioctl (get interface flags): %m");
2628 if (!(lifreq
.lifr_flags
& IFF_UP
))
2631 if (nss_ioctl(af
, SIOCGLIFNETMASK
, &lifreq
) < 0) {
2632 (void) syslog(LOG_ERR
,
2633 "n2a get_local_info: "
2634 "ioctl (get interface netmask): %m");
2638 if (ifassign(lifreq
, localinfo
->count
, IF_MASK
) == 0)
2649 __inet_ifassign(sa_family_t af
, struct __ifaddr
*ifa
, __ifaddr_type type
,
2654 if (af
== AF_INET6
) {
2655 ifa
->addr
.in6
= *(struct in6_addr
*)addr
;
2657 ifa
->addr
.in4
= *(struct in_addr
*)addr
;
2661 if (ifa
->af
== af
) {
2662 if (af
== AF_INET6
) {
2663 ifa
->mask
.in6
= *(struct in6_addr
*)addr
;
2665 ifa
->mask
.in4
= *(struct in_addr
*)addr
;
2679 * Some higher-level routines for determining if an address is
2680 * on a local network.
2682 * __inet_get_local_interfaces() - get an opaque handle with
2683 * with a list of local interfaces
2684 * __inet_address_is_local() - return 1 if an address is
2685 * on a local network; 0 otherwise
2686 * __inet_free_local_interfaces() - free handle that was
2687 * returned by __inet_get_local_interfaces()
2689 * A typical calling sequence is:
2691 * p = __inet_get_local_interfaces();
2692 * if (__inet_address_is_local(p, inaddr)) {
2695 * __inet_free_local_interfaces(p);
2699 * Return an opaque pointer to a list of configured interfaces.
2702 __inet_get_local_interfaces(void)
2704 return (get_local_info());
2708 * Free memory allocated by inet_local_interfaces().
2711 __inet_free_local_interfaces(void *p
)
2717 * Determine if an address is on a local network.
2719 * Might have made sense to use SIOCTONLINK, except that it doesn't
2720 * handle matching on IPv4 network addresses.
2723 __inet_address_is_local_af(void *p
, sa_family_t af
, void *addr
) {
2725 struct ifinfo
*localinfo
= (struct ifinfo
*)p
;
2727 struct in_addr v4addr
;
2732 if (af
== AF_INET6
&& IN6_IS_ADDR_V4MAPPED((struct in6_addr
*)addr
)) {
2733 IN6_V4MAPPED_TO_INADDR((struct in6_addr
*)addr
, &v4addr
);
2735 addr
= (void *)&v4addr
;
2738 for (i
= 0; i
< localinfo
->count
; i
++) {
2739 if (ifaf(i
) == af
) {
2740 if (af
== AF_INET6
) {
2741 struct in6_addr
*a6
= (struct in6_addr
*)addr
;
2742 for (a
= 0; a
< sizeof (a6
->s6_addr
); a
++) {
2743 if ((a6
->s6_addr
[a
] &
2744 ifmask6(i
).s6_addr
[a
]) !=
2745 (ifaddr6(i
).s6_addr
[a
] &
2746 ifmask6(i
).s6_addr
[a
]))
2749 if (a
>= sizeof (a6
->s6_addr
))
2752 if ((((struct in_addr
*)addr
)->s_addr
&
2753 ifmask4(i
).s_addr
) ==
2754 (ifaddr4(i
).s_addr
&
2765 __inet_address_is_local(void *p
, struct in_addr addr
)
2767 return (__inet_address_is_local_af(p
, AF_INET
, &addr
));
2771 __inet_uaddr_is_local(void *p
, struct netconfig
*nc
, char *uaddr
)
2773 struct netbuf
*taddr
;
2777 taddr
= uaddr2taddr(nc
, uaddr
);
2781 /* LINTED pointer cast */
2782 af
= ((struct sockaddr
*)taddr
->buf
)->sa_family
;
2784 ret
= __inet_address_is_local_af(p
, af
, (af
== AF_INET6
) ?
2785 /* LINTED pointer cast */
2786 (void *)&((struct sockaddr_in6
*)taddr
->buf
)->sin6_addr
:
2787 /* LINTED pointer cast */
2788 (void *)&((struct sockaddr_in
*)taddr
->buf
)->sin_addr
);
2790 netdir_free(taddr
, ND_ADDR
);
2796 __inet_address_count(void *p
)
2798 struct ifinfo
*lp
= (struct ifinfo
*)p
;
2808 __inet_get_addr(void *p
, int n
)
2810 struct ifinfo
*localinfo
= (struct ifinfo
*)p
;
2812 if (localinfo
== 0 || n
>= localinfo
->count
|| ifaf(n
) != AF_INET
)
2815 return (ifaddr4(n
).s_addr
);
2819 __inet_get_network(void *p
, int n
)
2821 struct ifinfo
*localinfo
= (struct ifinfo
*)p
;
2823 if (localinfo
== 0 || n
>= localinfo
->count
|| ifaf(n
) != AF_INET
)
2826 return (ifaddr4(n
).s_addr
& ifmask4(n
).s_addr
);
2830 __inet_get_uaddr(void *p
, struct netconfig
*nc
, int n
)
2832 struct ifinfo
*localinfo
= (struct ifinfo
*)p
;
2834 struct sockaddr_in sin4
;
2835 struct sockaddr_in6 sin6
;
2838 if (localinfo
== 0 || nc
== 0 || n
>= localinfo
->count
)
2841 if (ifaf(n
) == AF_INET6
) {
2842 if (strcmp(NC_INET6
, nc
->nc_protofmly
) != 0)
2844 (void) memset(&sin6
, 0, sizeof (sin6
));
2845 sin6
.sin6_family
= AF_INET6
;
2846 sin6
.sin6_addr
= ifaddr6(n
);
2847 nb
.buf
= (char *)&sin6
;
2848 nb
.len
= sizeof (sin6
);
2850 if (strcmp(NC_INET
, nc
->nc_protofmly
) != 0)
2852 (void) memset(&sin4
, 0, sizeof (sin4
));
2853 sin4
.sin_family
= AF_INET
;
2854 sin4
.sin_addr
= ifaddr4(n
);
2855 nb
.buf
= (char *)&sin4
;
2856 nb
.len
= sizeof (sin4
);
2861 uaddr
= taddr2uaddr(nc
, &nb
);
2866 __inet_get_networka(void *p
, int n
)
2868 struct ifinfo
*localinfo
= (struct ifinfo
*)p
;
2870 if (localinfo
== 0 || n
>= localinfo
->count
)
2873 if (ifaf(n
) == AF_INET6
) {
2874 char buf
[INET6_ADDRSTRLEN
];
2875 struct in6_addr in6
;
2878 for (i
= 0; i
< sizeof (in6
.s6_addr
); i
++) {
2879 in6
.s6_addr
[i
] = ifaddr6(n
).s6_addr
[i
] &
2880 ifmask6(n
).s6_addr
[i
];
2882 return (strdup(inet_ntop(AF_INET6
, &in6
, buf
, sizeof (buf
))));
2886 in4
.s_addr
= ifaddr4(n
).s_addr
& ifmask4(n
).s_addr
;
2887 return (strdup(inet_ntoa(in4
)));
2892 in_list(struct in_addr
*addrs
, int n
, struct in_addr a
)
2896 for (i
= 0; i
< n
; i
++) {
2897 if (addrs
[i
].s_addr
== a
.s_addr
)
2904 getbroadcastnets(struct netconfig
*tp
, struct in_addr
**addrs
)
2907 struct ifreq ifreq
, *ifr
;
2908 struct sockaddr_in
*sin
;
2913 int use_loopback
= 0;
2915 _nderror
= ND_SYSTEM
;
2916 fd
= open(tp
->nc_device
, O_RDONLY
);
2918 (void) syslog(LOG_ERR
,
2919 "broadcast: open to get interface configuration: %m");
2922 if (ioctl(fd
, SIOCGIFNUM
, (char *)&numifs
) < 0)
2924 buf
= malloc(numifs
* sizeof (struct ifreq
));
2926 (void) syslog(LOG_ERR
, "broadcast: malloc failed: %m");
2930 *addrs
= malloc(numifs
* sizeof (struct in_addr
));
2931 if (*addrs
== NULL
) {
2932 (void) syslog(LOG_ERR
, "broadcast: malloc failed: %m");
2937 ifc
.ifc_len
= numifs
* (int)sizeof (struct ifreq
);
2940 * Ideally, this ioctl should also tell me, how many bytes were
2941 * finally allocated, but it doesnt.
2943 if (ioctl(fd
, SIOCGIFCONF
, (char *)&ifc
) < 0) {
2944 (void) syslog(LOG_ERR
,
2945 "broadcast: ioctl (get interface configuration): %m");
2953 /* LINTED pointer cast */
2954 ifr
= (struct ifreq
*)buf
;
2955 for (i
= 0, n
= ifc
.ifc_len
/ (int)sizeof (struct ifreq
);
2956 n
> 0; n
--, ifr
++) {
2958 if (ioctl(fd
, SIOCGIFFLAGS
, (char *)&ifreq
) < 0) {
2959 (void) syslog(LOG_ERR
, "broadcast: "
2960 "ioctl (get interface flags): %m");
2963 if (!(ifreq
.ifr_flags
& IFF_UP
) ||
2964 (ifr
->ifr_addr
.sa_family
!= AF_INET
))
2966 if (ifreq
.ifr_flags
& IFF_BROADCAST
) {
2967 /* LINTED pointer cast */
2968 sin
= (struct sockaddr_in
*)&ifr
->ifr_addr
;
2969 if (ioctl(fd
, SIOCGIFBRDADDR
, (char *)&ifreq
) < 0) {
2970 /* May not work with other implementation */
2972 inet_netof(sin
->sin_addr
),
2974 if (!in_list(*addrs
, i
, a
))
2977 /* LINTED pointer cast */
2978 a
= ((struct sockaddr_in
*)
2979 &ifreq
.ifr_addr
)->sin_addr
;
2980 if (!in_list(*addrs
, i
, a
))
2985 if (use_loopback
&& (ifreq
.ifr_flags
& IFF_LOOPBACK
)) {
2986 /* LINTED pointer cast */
2987 sin
= (struct sockaddr_in
*)&ifr
->ifr_addr
;
2989 if (!in_list(*addrs
, i
, a
))
2993 if (ifreq
.ifr_flags
& IFF_POINTOPOINT
) {
2994 if (ioctl(fd
, SIOCGIFDSTADDR
, (char *)&ifreq
) < 0)
2996 /* LINTED pointer cast */
2997 a
= ((struct sockaddr_in
*)
2998 &ifreq
.ifr_addr
)->sin_addr
;
2999 if (!in_list(*addrs
, i
, a
))
3004 if (i
== 0 && !use_loopback
) {
3018 * This is lifted straight from libsocket/inet/inet_mkaddr.c.
3019 * Copied here to avoid our dependency on libsocket. More importantly,
3020 * to make sure partially static apps that use libnsl, but not
3021 * libsocket, don't get screwed up.
3022 * If you understand the above paragraph, try to get rid of
3023 * this copy of inet_makeaddr; if you don;t, leave it alone.
3025 * Formulate an Internet address from network + host. Used in
3026 * building addresses stored in the ifnet structure.
3028 static struct in_addr
3029 _inet_makeaddr(in_addr_t net
, in_addr_t host
)
3032 struct in_addr inaddr
;
3035 addr
= (net
<< IN_CLASSA_NSHIFT
) | (host
& IN_CLASSA_HOST
);
3036 else if (net
< 65536)
3037 addr
= (net
<< IN_CLASSB_NSHIFT
) | (host
& IN_CLASSB_HOST
);
3038 else if (net
< 16777216L)
3039 addr
= (net
<< IN_CLASSC_NSHIFT
) | (host
& IN_CLASSC_HOST
);
3042 inaddr
.s_addr
= htonl(addr
);
3047 * Routine to read the default configuration file and check if SORT_ADDRS
3048 * is set to NO or FALSE. This routine is called by order_haddrlist_af()
3049 * to determine if the addresses need to be sorted.
3052 _read_nsw_file(void)
3054 char defval
[LINESIZE
];
3056 boolean_t nosort
= B_FALSE
;
3060 defl
= fopen(__NSW_DEFAULT_FILE
, "rF");
3061 } while ((defl
== NULL
) && (errno
== EINTR
));
3066 while (fgets(defval
, sizeof (defval
), defl
) != NULL
) {
3067 if ((strncmp(DONT_SORT
, defval
, sizeof (DONT_SORT
) - 1) == 0) ||
3068 (strncmp(DONT_SORT2
, defval
,
3069 sizeof (DONT_SORT2
) - 1) == 0)) {
3074 (void) fclose(defl
);