1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 *
26 * Copyright 2016 Joyent, Inc.
27 *
28 * This file defines and implements the re-entrant getipnodebyname(),
29 * getipnodebyaddr(), and freehostent() routines for IPv6. These routines
30 * follow use the netdir_getbyYY() (see netdir_inet.c).
31 *
32 * lib/libnsl/nss/getipnodeby.c
33 */
34
35 #include "mt.h"
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <stropts.h>
39 #include <ctype.h>
40 #include <string.h>
41 #include <strings.h>
42 #include <netdb.h>
43 #include <stdio.h>
44 #include <arpa/inet.h>
45 #include <nss_dbdefs.h>
46 #include <netinet/in.h>
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49 #include <nss_netdir.h>
50 #include <net/if.h>
51 #include <netinet/in.h>
52 #include <netdir.h>
53 #include <thread.h>
54 #include <synch.h>
55 #include <fcntl.h>
56 #include <sys/time.h>
57 #include "nss.h"
58
59 #define IPV6_LITERAL_CHAR ':'
60
61 /*
62 * The number of nanoseconds getipnodebyname() waits before getting
63 * fresh interface count information with SIOCGLIFNUM. The default is
64 * five minutes.
65 */
66 #define IFNUM_TIMEOUT ((hrtime_t)300 * NANOSEC)
67
68 /*
69 * Bits in the bitfield returned by getipnodebyname_processflags().
70 *
71 * IPNODE_WANTIPV6 The user wants IPv6 addresses returned.
72 * IPNODE_WANTIPV4 The user wants IPv4 addresses returned.
73 * IPNODE_IPV4IFNOIPV6 The user only wants IPv4 addresses returned if no IPv6
74 * addresses are returned.
75 * IPNODE_LOOKUPIPNODES getipnodebyname() needs to lookup the name in ipnodes.
76 * IPNODE_LOOKUPHOSTS getipnodebyname() needs to lookup the name in hosts.
77 * IPNODE_ISLITERAL The name supplied is a literal address string.
78 * IPNODE_UNMAP The user doesn't want v4 mapped addresses if no IPv6
79 * interfaces are plumbed on the system.
80 */
81 #define IPNODE_WANTIPV6 0x00000001u
82 #define IPNODE_WANTIPV4 0x00000002u
83 #define IPNODE_IPV4IFNOIPV6 0x00000004u
84 #define IPNODE_LOOKUPIPNODES 0x00000008u
85 #define IPNODE_LOOKUPHOSTS 0x00000010u
86 #define IPNODE_LITERAL 0x00000020u
87 #define IPNODE_UNMAP 0x00000040u
88 #define IPNODE_IPV4 (IPNODE_WANTIPV4 | IPNODE_IPV4IFNOIPV6)
89
90 /*
91 * The private flag between libsocket and libnsl. See
92 * lib/libsocket/inet/getaddrinfo.c for more information.
93 */
94 #define AI_ADDRINFO 0x8000
95
96 /*
97 * The default set of bits corresponding to a getipnodebyname() flags
98 * argument of AI_DEFAULT.
99 */
100 #define IPNODE_DEFAULT (IPNODE_WANTIPV6 | IPNODE_IPV4 | \
101 IPNODE_LOOKUPIPNODES | IPNODE_LOOKUPHOSTS)
102
103 extern struct netconfig *__rpc_getconfip(char *);
104
105 static struct hostent *__mapv4tov6(struct hostent *, struct hostent *,
106 nss_XbyY_buf_t *, int);
107 struct hostent *__mappedtov4(struct hostent *, int *);
108 static struct hostent *__filter_addresses(int, struct hostent *);
109 static int __find_mapped(struct hostent *, int);
110 static nss_XbyY_buf_t *__IPv6_alloc(int);
111 static void __IPv6_cleanup(nss_XbyY_buf_t *);
112 static int __ai_addrconfig(int, boolean_t);
113
114
115 #ifdef PIC
116 struct hostent *
_uncached_getipnodebyname(const char * nam,struct hostent * result,char * buffer,int buflen,int af_family,int flags,int * h_errnop)117 _uncached_getipnodebyname(const char *nam, struct hostent *result,
118 char *buffer, int buflen, int af_family, int flags, int *h_errnop)
119 {
120 return (_switch_getipnodebyname_r(nam, result, buffer, buflen,
121 af_family, flags, h_errnop));
122 }
123
124 struct hostent *
_uncached_getipnodebyaddr(const char * addr,int length,int type,struct hostent * result,char * buffer,int buflen,int * h_errnop)125 _uncached_getipnodebyaddr(const char *addr, int length, int type,
126 struct hostent *result, char *buffer, int buflen, int *h_errnop)
127 {
128 if (type == AF_INET)
129 return (_switch_gethostbyaddr_r(addr, length, type,
130 result, buffer, buflen, h_errnop));
131 else if (type == AF_INET6)
132 return (_switch_getipnodebyaddr_r(addr, length, type,
133 result, buffer, buflen, h_errnop));
134 return (NULL);
135 }
136 #endif
137
138 /*
139 * Given a name, an address family, and a set of flags, return a
140 * bitfield that getipnodebyname() will use.
141 */
142 static uint_t
getipnodebyname_processflags(const char * name,int af,int flags)143 getipnodebyname_processflags(const char *name, int af, int flags)
144 {
145 uint_t ipnode_bits = IPNODE_DEFAULT;
146 boolean_t ipv6configured = B_FALSE;
147 boolean_t ipv4configured = B_FALSE;
148
149 /*
150 * If AI_ADDRCONFIG is specified, we need to determine the number of
151 * addresses of each address family configured on the system as
152 * appropriate.
153 *
154 * When trying to determine which addresses should be used for
155 * addrconfig, we first ignore loopback devices. This generally makes
156 * sense as policy, as most of these queries will be trying to go
157 * off-box and one should not have an IPv6 loopback address suggest that
158 * we can now send IPv6 traffic off the box or the equivalent with IPv4.
159 * However, it's possible that no non-loopback interfaces are up on the
160 * box. In those cases, we then check which interfaces are up and
161 * consider loopback devices. While this isn't to the letter of RFC 3493
162 * (which itself is a bit vague in this case, as is SUS), it matches
163 * expected user behavior in these situations.
164 */
165 if (flags & AI_ADDRCONFIG) {
166 boolean_t hv4, hv6;
167
168 hv4 = __ai_addrconfig(AF_INET, B_FALSE) > 0;
169 hv6 = __ai_addrconfig(AF_INET6, B_FALSE) > 0;
170
171 if (hv4 == B_FALSE && hv6 == B_FALSE) {
172 hv4 = __ai_addrconfig(AF_INET, B_TRUE) > 0;
173 hv6 = __ai_addrconfig(AF_INET6, B_TRUE) > 0;
174 }
175
176 ipv6configured = (af == AF_INET6 && hv6);
177 ipv4configured = (af == AF_INET || (flags & AI_V4MAPPED)) &&
178 hv4;
179 }
180
181 /*
182 * Determine what kinds of addresses the user is interested
183 * in getting back.
184 */
185 switch (af) {
186 case AF_INET6:
187 if ((flags & AI_ADDRCONFIG) && !ipv6configured)
188 ipnode_bits &= ~IPNODE_WANTIPV6;
189
190 if (flags & AI_V4MAPPED) {
191 if ((flags & AI_ADDRCONFIG) && !ipv4configured) {
192 ipnode_bits &= ~IPNODE_IPV4;
193 } else if (flags & AI_ALL) {
194 ipnode_bits &= ~IPNODE_IPV4IFNOIPV6;
195 }
196 if ((flags & AI_ADDRCONFIG) && !ipv6configured &&
197 (flags & AI_ADDRINFO)) {
198 ipnode_bits |= IPNODE_UNMAP;
199 }
200 } else {
201 ipnode_bits &= ~IPNODE_IPV4;
202 }
203 break;
204 case AF_INET:
205 if ((flags & AI_ADDRCONFIG) && !ipv4configured)
206 ipnode_bits &= ~IPNODE_IPV4;
207 ipnode_bits &= ~IPNODE_WANTIPV6;
208 ipnode_bits &= ~IPNODE_IPV4IFNOIPV6;
209 break;
210 default:
211 ipnode_bits = 0;
212 break;
213 }
214
215 /*
216 * If we're not looking for IPv4 addresses, don't bother looking
217 * in hosts.
218 */
219 if (!(ipnode_bits & IPNODE_WANTIPV4))
220 ipnode_bits &= ~IPNODE_LOOKUPHOSTS;
221
222 /*
223 * Determine if name is a literal IP address. This will
224 * further narrow down what type of lookup we're going to do.
225 */
226 if (strchr(name, IPV6_LITERAL_CHAR) != NULL) {
227 /* Literal IPv6 address */
228 ipnode_bits |= IPNODE_LITERAL;
229 /*
230 * In s9 we accepted the literal without filtering independent
231 * of what family was passed in hints. We continue to do
232 * this.
233 */
234 ipnode_bits |= (IPNODE_WANTIPV6 | IPNODE_WANTIPV4);
235 ipnode_bits &= ~IPNODE_LOOKUPHOSTS;
236 } else if (inet_addr(name) != 0xffffffffU) {
237 /* Literal IPv4 address */
238 ipnode_bits |= (IPNODE_LITERAL | IPNODE_WANTIPV4);
239 ipnode_bits &= ~IPNODE_WANTIPV6;
240 ipnode_bits &= ~IPNODE_LOOKUPIPNODES;
241 }
242 return (ipnode_bits);
243 }
244
245 struct hostent *
getipnodebyname(const char * name,int af,int flags,int * error_num)246 getipnodebyname(const char *name, int af, int flags, int *error_num)
247 {
248 struct hostent *hp = NULL;
249 nss_XbyY_buf_t *buf4 = NULL;
250 nss_XbyY_buf_t *buf6 = NULL;
251 struct netconfig *nconf;
252 struct nss_netdirbyname_in nssin;
253 union nss_netdirbyname_out nssout;
254 int ret;
255 uint_t ipnode_bits;
256
257 if ((nconf = __rpc_getconfip("udp")) == NULL &&
258 (nconf = __rpc_getconfip("tcp")) == NULL) {
259 *error_num = NO_RECOVERY;
260 return (NULL);
261 }
262
263 ipnode_bits = getipnodebyname_processflags(name, af, flags);
264
265 /* Make sure we have something to look up. */
266 if (!(ipnode_bits & (IPNODE_WANTIPV6 | IPNODE_WANTIPV4))) {
267 *error_num = HOST_NOT_FOUND;
268 goto cleanup;
269 }
270
271 /*
272 * Perform the requested lookups. We always look through
273 * ipnodes first for both IPv4 and IPv6 addresses. Depending
274 * on what was returned and what was needed, we either filter
275 * out the garbage, or ask for more using hosts.
276 */
277 if (ipnode_bits & IPNODE_LOOKUPIPNODES) {
278 if ((buf6 = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == NULL) {
279 *error_num = NO_RECOVERY;
280 goto cleanup;
281 }
282 nssin.op_t = NSS_HOST6;
283 nssin.arg.nss.host6.name = name;
284 nssin.arg.nss.host6.buf = buf6->buffer;
285 nssin.arg.nss.host6.buflen = buf6->buflen;
286 nssin.arg.nss.host6.af_family = af;
287 nssin.arg.nss.host6.flags = flags;
288 nssout.nss.host.hent = buf6->result;
289 nssout.nss.host.herrno_p = error_num;
290 ret = _get_hostserv_inetnetdir_byname(nconf, &nssin, &nssout);
291 if (ret != ND_OK) {
292 __IPv6_cleanup(buf6);
293 buf6 = NULL;
294 } else if (ipnode_bits & IPNODE_WANTIPV4) {
295 /*
296 * buf6 may have all that we need if we either
297 * only wanted IPv4 addresses if there were no
298 * IPv6 addresses returned, or if there are
299 * IPv4-mapped addresses in buf6. If either
300 * of these are true, then there's no need to
301 * look in hosts.
302 */
303 if (ipnode_bits & IPNODE_IPV4IFNOIPV6 ||
304 __find_mapped(buf6->result, 0) != 0) {
305 ipnode_bits &= ~IPNODE_LOOKUPHOSTS;
306 } else if (!(ipnode_bits & IPNODE_WANTIPV6)) {
307 /*
308 * If all we're looking for are IPv4
309 * addresses and there are none in
310 * buf6 then buf6 is now useless.
311 */
312 __IPv6_cleanup(buf6);
313 buf6 = NULL;
314 }
315 }
316 }
317 if (ipnode_bits & IPNODE_LOOKUPHOSTS) {
318 if ((buf4 = __IPv6_alloc(NSS_BUFLEN_HOSTS)) == NULL) {
319 *error_num = NO_RECOVERY;
320 goto cleanup;
321 }
322 nssin.op_t = NSS_HOST;
323 nssin.arg.nss.host.name = name;
324 nssin.arg.nss.host.buf = buf4->buffer;
325 nssin.arg.nss.host.buflen = buf4->buflen;
326 nssout.nss.host.hent = buf4->result;
327 nssout.nss.host.herrno_p = error_num;
328 ret = _get_hostserv_inetnetdir_byname(nconf, &nssin, &nssout);
329 if (ret != ND_OK) {
330 __IPv6_cleanup(buf4);
331 buf4 = NULL;
332 }
333 }
334
335 if (buf6 == NULL && buf4 == NULL) {
336 *error_num = HOST_NOT_FOUND;
337 goto cleanup;
338 }
339
340 /* Extract the appropriate addresses from the returned buffer(s). */
341 switch (af) {
342 case AF_INET6: {
343 if (buf4 != NULL) {
344 nss_XbyY_buf_t *mergebuf;
345
346 /*
347 * The IPv4 results we have need to be
348 * converted to IPv4-mapped addresses,
349 * conditionally merged with the IPv6
350 * results, and the end result needs to be
351 * re-ordered.
352 */
353 mergebuf = __IPv6_alloc(NSS_BUFLEN_IPNODES);
354 if (mergebuf == NULL) {
355 *error_num = NO_RECOVERY;
356 goto cleanup;
357 }
358 hp = __mapv4tov6(buf4->result,
359 ((buf6 != NULL) ? buf6->result : NULL),
360 mergebuf, 1);
361 if (hp != NULL)
362 order_haddrlist_af(AF_INET6, hp->h_addr_list);
363 else
364 *error_num = NO_RECOVERY;
365 free(mergebuf);
366 }
367
368 if (buf4 == NULL && buf6 != NULL) {
369 hp = buf6->result;
370
371 /*
372 * We have what we need in buf6, but we may need
373 * to filter out some addresses depending on what
374 * is being asked for.
375 */
376 if (!(ipnode_bits & IPNODE_WANTIPV4))
377 hp = __filter_addresses(AF_INET, buf6->result);
378 else if (!(ipnode_bits & IPNODE_WANTIPV6))
379 hp = __filter_addresses(AF_INET6, buf6->result);
380
381 /*
382 * We've been asked to unmap v4 addresses. This
383 * situation implies IPNODE_WANTIPV4 and
384 * !IPNODE_WANTIPV6.
385 */
386 if (hp != NULL && (ipnode_bits & IPNODE_UNMAP)) {
387 /*
388 * Just set hp to a new value, cleanup: will
389 * free the old one
390 */
391 hp = __mappedtov4(hp, error_num);
392 } else if (hp == NULL)
393 *error_num = NO_ADDRESS;
394 }
395
396 break;
397 }
398
399 case AF_INET:
400 /* We could have results in buf6 or buf4, not both */
401 if (buf6 != NULL) {
402 /*
403 * Extract the IPv4-mapped addresses from buf6
404 * into hp.
405 */
406 hp = __mappedtov4(buf6->result, error_num);
407 } else {
408 /* We have what we need in buf4. */
409 hp = buf4->result;
410 if (ipnode_bits & IPNODE_LITERAL) {
411 /*
412 * There is a special case here for literal
413 * IPv4 address strings. The hosts
414 * front-end sets h_aliases to a one
415 * element array containing a single NULL
416 * pointer (in ndaddr2hent()), while
417 * getipnodebyname() requires h_aliases to
418 * be a NULL pointer itself. We're not
419 * going to change the front-end since it
420 * needs to remain backward compatible for
421 * gethostbyname() and friends. Just set
422 * h_aliases to NULL here instead.
423 */
424 hp->h_aliases = NULL;
425 }
426 }
427
428 break;
429
430 default:
431 break;
432 }
433
434 cleanup:
435 /*
436 * Free the memory we allocated, but make sure we don't free
437 * the memory we're returning to the caller.
438 */
439 if (buf6 != NULL) {
440 if (buf6->result == hp)
441 buf6->result = NULL;
442 __IPv6_cleanup(buf6);
443 }
444 if (buf4 != NULL) {
445 if (buf4->result == hp)
446 buf4->result = NULL;
447 __IPv6_cleanup(buf4);
448 }
449 (void) freenetconfigent(nconf);
450
451 return (hp);
452 }
453
454 /*
455 * This is the IPv6 interface for "gethostbyaddr".
456 */
457 struct hostent *
getipnodebyaddr(const void * src,size_t len,int type,int * error_num)458 getipnodebyaddr(const void *src, size_t len, int type, int *error_num)
459 {
460 struct in6_addr *addr6 = 0;
461 struct in_addr *addr4 = 0;
462 nss_XbyY_buf_t *buf = 0;
463 nss_XbyY_buf_t *res = 0;
464 struct netconfig *nconf;
465 struct hostent *hp = 0;
466 struct nss_netdirbyaddr_in nssin;
467 union nss_netdirbyaddr_out nssout;
468 int neterr;
469 char tmpbuf[64];
470
471 if (type == AF_INET6) {
472 if ((addr6 = (struct in6_addr *)src) == NULL) {
473 *error_num = HOST_NOT_FOUND;
474 return (NULL);
475 }
476 } else if (type == AF_INET) {
477 if ((addr4 = (struct in_addr *)src) == NULL) {
478 *error_num = HOST_NOT_FOUND;
479 return (NULL);
480 }
481 } else {
482 *error_num = HOST_NOT_FOUND;
483 return (NULL);
484 }
485 /*
486 * Specific case: query for "::"
487 */
488 if (type == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(addr6)) {
489 *error_num = HOST_NOT_FOUND;
490 return (NULL);
491 }
492 /*
493 * Step 1: IPv4-mapped address or IPv4 Compat
494 */
495 if ((type == AF_INET6 && len == 16) &&
496 ((IN6_IS_ADDR_V4MAPPED(addr6)) ||
497 (IN6_IS_ADDR_V4COMPAT(addr6)))) {
498 if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
499 *error_num = NO_RECOVERY;
500 return (NULL);
501 }
502 if ((nconf = __rpc_getconfip("udp")) == NULL &&
503 (nconf = __rpc_getconfip("tcp")) == NULL) {
504 *error_num = NO_RECOVERY;
505 __IPv6_cleanup(buf);
506 return (NULL);
507 }
508 nssin.op_t = NSS_HOST6;
509 if (IN6_IS_ADDR_V4COMPAT(addr6)) {
510 (void) memcpy(tmpbuf, addr6, sizeof (*addr6));
511 tmpbuf[10] = 0xffU;
512 tmpbuf[11] = 0xffU;
513 nssin.arg.nss.host.addr = (const char *)tmpbuf;
514 } else {
515 nssin.arg.nss.host.addr = (const char *)addr6;
516 }
517 nssin.arg.nss.host.len = sizeof (struct in6_addr);
518 nssin.arg.nss.host.type = AF_INET6;
519 nssin.arg.nss.host.buf = buf->buffer;
520 nssin.arg.nss.host.buflen = buf->buflen;
521
522 nssout.nss.host.hent = buf->result;
523 nssout.nss.host.herrno_p = error_num;
524 /*
525 * We pass in nconf and let the implementation of the
526 * long-named func decide whether to use the switch based on
527 * nc_nlookups.
528 */
529 neterr =
530 _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);
531
532 (void) freenetconfigent(nconf);
533 if (neterr != ND_OK) {
534 /* Failover case, try hosts db for v4 address */
535 if (!gethostbyaddr_r(((char *)addr6) + 12,
536 sizeof (in_addr_t), AF_INET, buf->result,
537 buf->buffer, buf->buflen, error_num)) {
538 __IPv6_cleanup(buf);
539 return (NULL);
540 }
541 /* Found one, now format it into mapped/compat addr */
542 if ((res = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
543 __IPv6_cleanup(buf);
544 *error_num = NO_RECOVERY;
545 return (NULL);
546 }
547 /* Convert IPv4 to mapped/compat address w/name */
548 hp = res->result;
549 (void) __mapv4tov6(buf->result, 0, res,
550 IN6_IS_ADDR_V4MAPPED(addr6));
551 __IPv6_cleanup(buf);
552 free(res);
553 return (hp);
554 }
555 /*
556 * At this point, we'll have a v4mapped hostent. If that's
557 * what was passed in, just return. If the request was a compat,
558 * twiggle the two bytes to make the mapped address a compat.
559 */
560 hp = buf->result;
561 if (IN6_IS_ADDR_V4COMPAT(addr6)) {
562 /* LINTED pointer cast */
563 addr6 = (struct in6_addr *)hp->h_addr_list[0];
564 addr6->s6_addr[10] = 0;
565 addr6->s6_addr[11] = 0;
566 }
567 free(buf);
568 return (hp);
569 }
570 /*
571 * Step 2: AF_INET, v4 lookup. Since we're going to search the
572 * ipnodes (v6) path first, we need to treat this as a v4mapped
573 * address. nscd(1m) caches v4 from ipnodes as mapped v6's. The
574 * switch backend knows to lookup v4's (not v4mapped) from the
575 * name services.
576 */
577 if (type == AF_INET) {
578 struct in6_addr v4mapbuf;
579 addr6 = &v4mapbuf;
580
581 IN6_INADDR_TO_V4MAPPED(addr4, addr6);
582 if ((nconf = __rpc_getconfip("udp")) == NULL &&
583 (nconf = __rpc_getconfip("tcp")) == NULL) {
584 *error_num = NO_RECOVERY;
585 return (NULL);
586 }
587 if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
588 *error_num = NO_RECOVERY;
589 freenetconfigent(nconf);
590 return (NULL);
591 }
592 nssin.op_t = NSS_HOST6;
593 nssin.arg.nss.host.addr = (const char *)addr6;
594 nssin.arg.nss.host.len = sizeof (struct in6_addr);
595 nssin.arg.nss.host.type = AF_INET6;
596 nssin.arg.nss.host.buf = buf->buffer;
597 nssin.arg.nss.host.buflen = buf->buflen;
598
599 nssout.nss.host.hent = buf->result;
600 nssout.nss.host.herrno_p = error_num;
601 /*
602 * We pass in nconf and let the implementation of the
603 * long-named func decide whether to use the switch based on
604 * nc_nlookups.
605 */
606 neterr =
607 _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);
608
609 (void) freenetconfigent(nconf);
610 if (neterr != ND_OK) {
611 /* Failover case, try hosts db for v4 address */
612 hp = buf->result;
613 if (!gethostbyaddr_r(src, len, type, buf->result,
614 buf->buffer, buf->buflen, error_num)) {
615 __IPv6_cleanup(buf);
616 return (NULL);
617 }
618 free(buf);
619 return (hp);
620 }
621 if ((hp = __mappedtov4(buf->result, error_num)) == NULL) {
622 __IPv6_cleanup(buf);
623 return (NULL);
624 }
625 __IPv6_cleanup(buf);
626 return (hp);
627 }
628 /*
629 * Step 3: AF_INET6, plain vanilla v6 getipnodebyaddr() call.
630 */
631 if (type == AF_INET6) {
632 if ((nconf = __rpc_getconfip("udp")) == NULL &&
633 (nconf = __rpc_getconfip("tcp")) == NULL) {
634 *error_num = NO_RECOVERY;
635 return (NULL);
636 }
637 if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
638 *error_num = NO_RECOVERY;
639 freenetconfigent(nconf);
640 return (NULL);
641 }
642 nssin.op_t = NSS_HOST6;
643 nssin.arg.nss.host.addr = (const char *)addr6;
644 nssin.arg.nss.host.len = len;
645 nssin.arg.nss.host.type = type;
646 nssin.arg.nss.host.buf = buf->buffer;
647 nssin.arg.nss.host.buflen = buf->buflen;
648
649 nssout.nss.host.hent = buf->result;
650 nssout.nss.host.herrno_p = error_num;
651 /*
652 * We pass in nconf and let the implementation of the
653 * long-named func decide whether to use the switch based on
654 * nc_nlookups.
655 */
656 neterr =
657 _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);
658
659 (void) freenetconfigent(nconf);
660 if (neterr != ND_OK) {
661 __IPv6_cleanup(buf);
662 return (NULL);
663 }
664 free(buf);
665 return (nssout.nss.host.hent);
666 }
667 /*
668 * If we got here, unknown type.
669 */
670 *error_num = HOST_NOT_FOUND;
671 return (NULL);
672 }
673
674 void
freehostent(struct hostent * hent)675 freehostent(struct hostent *hent)
676 {
677 free(hent);
678 }
679
680 static int
__ai_addrconfig(int af,boolean_t loopback)681 __ai_addrconfig(int af, boolean_t loopback)
682 {
683 struct lifnum lifn;
684 struct lifconf lifc;
685 struct lifreq *lifp, *buf = NULL;
686 size_t bufsize;
687 hrtime_t now, *then;
688 static hrtime_t then4, then6; /* the last time we updated ifnum# */
689 static int ifnum4 = -1, ifnum6 = -1, iflb4 = 0, iflb6 = 0;
690 int *num, *lb;
691 int nlifr, count = 0;
692
693
694 switch (af) {
695 case AF_INET:
696 num = &ifnum4;
697 then = &then4;
698 lb = &iflb4;
699 break;
700 case AF_INET6:
701 num = &ifnum6;
702 then = &then6;
703 lb = &iflb6;
704 break;
705 default:
706 return (0);
707 }
708
709 /*
710 * We don't need to check this every time someone does a name
711 * lookup. Do it every IFNUM_TIMEOUT for each address family.
712 *
713 * There's no need to protect all of this with a lock. The
714 * worst that can happen is that we update the interface count
715 * twice instead of once. That's no big deal.
716 */
717 now = gethrtime();
718 if (*num == -1 || ((now - *then) >= IFNUM_TIMEOUT)) {
719 lifn.lifn_family = af;
720 /*
721 * We want to determine if this machine knows anything
722 * at all about the address family; the status of the
723 * interface is less important. Hence, set
724 * 'lifn_flags' to zero.
725 */
726 lifn.lifn_flags = 0;
727 again:
728 if (nss_ioctl(af, SIOCGLIFNUM, &lifn) < 0)
729 goto fail;
730
731 if (lifn.lifn_count == 0) {
732 *lb = 0;
733 *num = 0;
734 *then = now;
735 return (*num);
736 }
737
738 /*
739 * Pad the interface count to detect when additional
740 * interfaces have been configured between SIOCGLIFNUM
741 * and SIOCGLIFCONF.
742 */
743 lifn.lifn_count += 4;
744
745 bufsize = lifn.lifn_count * sizeof (struct lifreq);
746 if ((buf = realloc(buf, bufsize)) == NULL)
747 goto fail;
748
749 lifc.lifc_family = af;
750 lifc.lifc_flags = 0;
751 lifc.lifc_len = bufsize;
752 lifc.lifc_buf = (caddr_t)buf;
753 if (nss_ioctl(af, SIOCGLIFCONF, &lifc) < 0)
754 goto fail;
755
756 nlifr = lifc.lifc_len / sizeof (struct lifreq);
757 if (nlifr >= lifn.lifn_count)
758 goto again;
759 /*
760 * Do not include any loopback addresses, 127.0.0.1 for AF_INET
761 * and ::1 for AF_INET6, while counting the number of available
762 * IPv4 or IPv6 addresses. (RFC 3493 requires this, whenever
763 * AI_ADDRCONFIG flag is set) However, if the loopback flag is
764 * set to true we'll include it in the output.
765 */
766 for (lifp = buf; lifp < buf + nlifr; lifp++) {
767 switch (af) {
768 case AF_INET: {
769 struct sockaddr_in *in;
770
771 in = (struct sockaddr_in *)&lifp->lifr_addr;
772 if (ntohl(in->sin_addr.s_addr) ==
773 INADDR_LOOPBACK) {
774 count++;
775 }
776 break;
777 }
778 case AF_INET6: {
779 struct sockaddr_in6 *in6;
780
781 in6 = (struct sockaddr_in6 *)&lifp->lifr_addr;
782 if (IN6_IS_ADDR_LOOPBACK(&in6->sin6_addr))
783 count++;
784 break;
785 }
786 }
787 }
788 *num = nlifr - count;
789 *lb = count;
790 *then = now;
791 free(buf);
792 }
793 if (loopback == B_TRUE)
794 return (*num + *lb);
795 else
796 return (*num);
797 fail:
798 free(buf);
799 /*
800 * If the process is running without the NET_ACCESS basic privilege,
801 * pretend we still have inet/inet6 interfaces.
802 */
803 if (errno == EACCES)
804 return (1);
805 return (-1);
806 }
807
808 /*
809 * This routine will either convert an IPv4 address to a mapped or compat
810 * IPv6 (if he6 == NULL) or merge IPv6 (he6) addresses with mapped
811 * v4 (he4) addresses. In either case, the results are returned in res.
812 * Caller must provide all buffers.
813 * Inputs:
814 * he4 pointer to IPv4 buffer
815 * he6 pointer to IPv6 buffer (NULL if not merging v4/v6
816 * res pointer to results buffer
817 * mapped mapped == 1, map IPv4 : mapped == 0, compat IPv4
818 * mapped flag is ignored if he6 != NULL
819 *
820 * The results are packed into the res->buffer as follows:
821 * <--------------- buffer + buflen -------------------------------------->
822 * |-----------------|-----------------|----------------|----------------|
823 * | pointers vector | pointers vector | aliases grow | addresses grow |
824 * | for addresses | for aliases | | |
825 * | this way -> | this way -> | <- this way |<- this way |
826 * |-----------------|-----------------|----------------|----------------|
827 * | grows in PASS 1 | grows in PASS2 | grows in PASS2 | grows in PASS 1|
828 */
829 static struct hostent *
__mapv4tov6(struct hostent * he4,struct hostent * he6,nss_XbyY_buf_t * res,int mapped)830 __mapv4tov6(struct hostent *he4, struct hostent *he6, nss_XbyY_buf_t *res,
831 int mapped)
832 {
833 char *buffer, *limit;
834 int buflen = res->buflen;
835 struct in6_addr *addr6p;
836 char *buff_locp;
837 struct hostent *host;
838 int count = 0, len, i;
839 char *h_namep;
840
841 if (he4 == NULL || res == NULL) {
842 return (NULL);
843 }
844 limit = res->buffer + buflen;
845 host = (struct hostent *)res->result;
846 buffer = res->buffer;
847
848 buff_locp = (char *)ROUND_DOWN(limit, sizeof (struct in6_addr));
849 host->h_addr_list = (char **)ROUND_UP(buffer, sizeof (char **));
850 if ((char *)host->h_addr_list >= limit ||
851 buff_locp <= (char *)host->h_addr_list) {
852 return (NULL);
853 }
854 if (he6 == NULL) {
855 /*
856 * If he6==NULL, map the v4 address into the v6 address format.
857 * This is used for getipnodebyaddr() (single address, mapped or
858 * compatible) or for v4 mapped for getipnodebyname(), which
859 * could be multiple addresses. This could also be a literal
860 * address string, which is why there is a inet_addr() call.
861 */
862 for (i = 0; he4->h_addr_list[i] != NULL; i++) {
863 buff_locp -= sizeof (struct in6_addr);
864 if (buff_locp <=
865 (char *)&(host->h_addr_list[count + 1])) {
866 /*
867 * Has to be room for the pointer to the address we're
868 * about to add, as well as the final NULL ptr.
869 */
870 return (NULL);
871 }
872 /* LINTED pointer cast */
873 addr6p = (struct in6_addr *)buff_locp;
874 host->h_addr_list[count] = (char *)addr6p;
875 bzero(addr6p->s6_addr, sizeof (struct in6_addr));
876 if (mapped) {
877 addr6p->s6_addr[10] = 0xff;
878 addr6p->s6_addr[11] = 0xff;
879 }
880 bcopy((char *)he4->h_addr_list[i],
881 &addr6p->s6_addr[12], sizeof (struct in_addr));
882 ++count;
883 }
884 /*
885 * Set last array element to NULL and add cname as first alias
886 */
887 host->h_addr_list[count] = NULL;
888 host->h_aliases = host->h_addr_list + count + 1;
889 count = 0;
890 if ((int)(inet_addr(he4->h_name)) != -1) {
891 /*
892 * Literal address string, since we're mapping, we need the IPv6
893 * V4 mapped literal address string for h_name.
894 */
895 char tmpstr[128];
896 (void) inet_ntop(AF_INET6, host->h_addr_list[0], tmpstr,
897 sizeof (tmpstr));
898 buff_locp -= (len = strlen(tmpstr) + 1);
899 h_namep = tmpstr;
900 if (buff_locp <= (char *)(host->h_aliases))
901 return (NULL);
902 bcopy(h_namep, buff_locp, len);
903 host->h_name = buff_locp;
904 host->h_aliases = NULL; /* no aliases for literal */
905 host->h_length = sizeof (struct in6_addr);
906 host->h_addrtype = AF_INET6;
907 return (host); /* we're done, return result */
908 }
909 /*
910 * Not a literal address string, so just copy h_name.
911 */
912 buff_locp -= (len = strlen(he4->h_name) + 1);
913 h_namep = he4->h_name;
914 if (buff_locp <= (char *)(host->h_aliases))
915 return (NULL);
916 bcopy(h_namep, buff_locp, len);
917 host->h_name = buff_locp;
918 /*
919 * Pass 2 (IPv4 aliases):
920 */
921 for (i = 0; he4->h_aliases[i] != NULL; i++) {
922 buff_locp -= (len = strlen(he4->h_aliases[i]) + 1);
923 if (buff_locp <=
924 (char *)&(host->h_aliases[count + 1])) {
925 /*
926 * Has to be room for the pointer to the address we're
927 * about to add, as well as the final NULL ptr.
928 */
929 return (NULL);
930 }
931 host->h_aliases[count] = buff_locp;
932 bcopy((char *)he4->h_aliases[i], buff_locp, len);
933 ++count;
934 }
935 host->h_aliases[count] = NULL;
936 host->h_length = sizeof (struct in6_addr);
937 host->h_addrtype = AF_INET6;
938 return (host);
939 } else {
940 /*
941 * Merge IPv4 mapped addresses with IPv6 addresses. The
942 * IPv6 address will go in first, followed by the v4 mapped.
943 *
944 * Pass 1 (IPv6 addresses):
945 */
946 for (i = 0; he6->h_addr_list[i] != NULL; i++) {
947 buff_locp -= sizeof (struct in6_addr);
948 if (buff_locp <=
949 (char *)&(host->h_addr_list[count + 1])) {
950 /*
951 * Has to be room for the pointer to the address we're
952 * about to add, as well as the final NULL ptr.
953 */
954 return (NULL);
955 }
956 host->h_addr_list[count] = buff_locp;
957 bcopy((char *)he6->h_addr_list[i], buff_locp,
958 sizeof (struct in6_addr));
959 ++count;
960 }
961 /*
962 * Pass 1 (IPv4 mapped addresses):
963 */
964 for (i = 0; he4->h_addr_list[i] != NULL; i++) {
965 buff_locp -= sizeof (struct in6_addr);
966 if (buff_locp <=
967 (char *)&(host->h_addr_list[count + 1])) {
968 /*
969 * Has to be room for the pointer to the address we're
970 * about to add, as well as the final NULL ptr.
971 */
972 return (NULL);
973 }
974 /* LINTED pointer cast */
975 addr6p = (struct in6_addr *)buff_locp;
976 host->h_addr_list[count] = (char *)addr6p;
977 bzero(addr6p->s6_addr, sizeof (struct in6_addr));
978 addr6p->s6_addr[10] = 0xff;
979 addr6p->s6_addr[11] = 0xff;
980 bcopy(he4->h_addr_list[i], &addr6p->s6_addr[12],
981 sizeof (struct in_addr));
982 ++count;
983 }
984 /*
985 * Pass 2 (IPv6 aliases, host name first). We start h_aliases
986 * one after where h_addr_list array ended. This is where cname
987 * is put, followed by all aliases. Reset count to 0, for index
988 * in the h_aliases array.
989 */
990 host->h_addr_list[count] = NULL;
991 host->h_aliases = host->h_addr_list + count + 1;
992 count = 0;
993 buff_locp -= (len = strlen(he6->h_name) + 1);
994 if (buff_locp <= (char *)(host->h_aliases))
995 return (NULL);
996 bcopy(he6->h_name, buff_locp, len);
997 host->h_name = buff_locp;
998 for (i = 0; he6->h_aliases[i] != NULL; i++) {
999 buff_locp -= (len = strlen(he6->h_aliases[i]) + 1);
1000 if (buff_locp <=
1001 (char *)&(host->h_aliases[count + 1])) {
1002 /*
1003 * Has to be room for the pointer to the address we're
1004 * about to add, as well as the final NULL ptr.
1005 */
1006 return (NULL);
1007 }
1008 host->h_aliases[count] = buff_locp;
1009 bcopy((char *)he6->h_aliases[i], buff_locp, len);
1010 ++count;
1011 }
1012 /*
1013 * Pass 2 (IPv4 aliases):
1014 */
1015 for (i = 0; he4->h_aliases[i] != NULL; i++) {
1016 buff_locp -= (len = strlen(he4->h_aliases[i]) + 1);
1017 if (buff_locp <=
1018 (char *)&(host->h_aliases[count + 1])) {
1019 /*
1020 * Has to be room for the pointer to the address we're
1021 * about to add, as well as the final NULL ptr.
1022 */
1023 return (NULL);
1024 }
1025 host->h_aliases[count] = buff_locp;
1026 bcopy((char *)he4->h_aliases[i], buff_locp, len);
1027 ++count;
1028 }
1029 host->h_aliases[count] = NULL;
1030 host->h_length = sizeof (struct in6_addr);
1031 host->h_addrtype = AF_INET6;
1032 return (host);
1033 }
1034 }
1035
1036 /*
1037 * This routine will convert a mapped v4 hostent (AF_INET6) to a
1038 * AF_INET hostent. If no mapped addrs found, then a NULL is returned.
1039 * If mapped addrs found, then a new buffer is alloc'd and all the v4 mapped
1040 * addresses are extracted and copied to it. On sucess, a pointer to a new
1041 * hostent is returned.
1042 * There are two possible errors in which case a NULL is returned.
1043 * One of two error codes are returned:
1044 *
1045 * NO_RECOVERY - a malloc failed or the like for which there's no recovery.
1046 * NO_ADDRESS - after filtering all the v4, there was nothing left!
1047 *
1048 * Inputs:
1049 * he pointer to hostent with mapped v4 addresses
1050 * filter_error pointer to return error code
1051 * Return:
1052 * pointer to a malloc'd hostent with v4 addresses.
1053 *
1054 * The results are packed into the res->buffer as follows:
1055 * <--------------- buffer + buflen -------------------------------------->
1056 * |-----------------|-----------------|----------------|----------------|
1057 * | pointers vector | pointers vector | aliases grow | addresses grow |
1058 * | for addresses | for aliases | | |
1059 * | this way -> | this way -> | <- this way |<- this way |
1060 * |-----------------|-----------------|----------------|----------------|
1061 * | grows in PASS 1 | grows in PASS2 | grows in PASS2 | grows in PASS 1|
1062 */
1063 struct hostent *
__mappedtov4(struct hostent * he,int * extract_error)1064 __mappedtov4(struct hostent *he, int *extract_error)
1065 {
1066 char *buffer, *limit;
1067 nss_XbyY_buf_t *res;
1068 int buflen = NSS_BUFLEN_HOSTS;
1069 struct in_addr *addr4p;
1070 char *buff_locp;
1071 struct hostent *host;
1072 int count = 0, len, i;
1073 char *h_namep;
1074
1075 if (he == NULL) {
1076 *extract_error = NO_ADDRESS;
1077 return (NULL);
1078 }
1079 if ((__find_mapped(he, 0)) == 0) {
1080 *extract_error = NO_ADDRESS;
1081 return (NULL);
1082 }
1083 if ((res = __IPv6_alloc(NSS_BUFLEN_HOSTS)) == 0) {
1084 *extract_error = NO_RECOVERY;
1085 return (NULL);
1086 }
1087 limit = res->buffer + buflen;
1088 host = (struct hostent *)res->result;
1089 buffer = res->buffer;
1090
1091 buff_locp = (char *)ROUND_DOWN(limit, sizeof (struct in_addr));
1092 host->h_addr_list = (char **)ROUND_UP(buffer, sizeof (char **));
1093 if ((char *)host->h_addr_list >= limit ||
1094 buff_locp <= (char *)host->h_addr_list)
1095 goto cleanup;
1096 /*
1097 * "Unmap" the v4 mapped address(es) into a v4 hostent format.
1098 * This is used for getipnodebyaddr() (single address) or for
1099 * v4 mapped for getipnodebyname(), which could be multiple
1100 * addresses. This could also be a literal address string,
1101 * which is why there is a inet_addr() call.
1102 */
1103 for (i = 0; he->h_addr_list[i] != NULL; i++) {
1104 /* LINTED pointer cast */
1105 if (!IN6_IS_ADDR_V4MAPPED((struct in6_addr *)
1106 he->h_addr_list[i]))
1107 continue;
1108 buff_locp -= sizeof (struct in6_addr);
1109 /*
1110 * Has to be room for the pointer to the address we're
1111 * about to add, as well as the final NULL ptr.
1112 */
1113 if (buff_locp <=
1114 (char *)&(host->h_addr_list[count + 1]))
1115 goto cleanup;
1116 /* LINTED pointer cast */
1117 addr4p = (struct in_addr *)buff_locp;
1118 host->h_addr_list[count] = (char *)addr4p;
1119 bzero((char *)&addr4p->s_addr,
1120 sizeof (struct in_addr));
1121 /* LINTED pointer cast */
1122 IN6_V4MAPPED_TO_INADDR(
1123 (struct in6_addr *)he->h_addr_list[i], addr4p);
1124 ++count;
1125 }
1126 /*
1127 * Set last array element to NULL and add cname as first alias
1128 */
1129 host->h_addr_list[count] = NULL;
1130 host->h_aliases = host->h_addr_list + count + 1;
1131 count = 0;
1132 /* Copy official host name */
1133 buff_locp -= (len = strlen(he->h_name) + 1);
1134 h_namep = he->h_name;
1135 if (buff_locp <= (char *)(host->h_aliases))
1136 goto cleanup;
1137 bcopy(h_namep, buff_locp, len);
1138 host->h_name = buff_locp;
1139 /*
1140 * Pass 2 (IPv4 aliases):
1141 */
1142 if (he->h_aliases != NULL) {
1143 for (i = 0; he->h_aliases[i] != NULL; i++) {
1144 buff_locp -= (len = strlen(he->h_aliases[i]) + 1);
1145 /*
1146 * Has to be room for the pointer to the address we're
1147 * about to add, as well as the final NULL ptr.
1148 */
1149 if (buff_locp <=
1150 (char *)&(host->h_aliases[count + 1]))
1151 goto cleanup;
1152 host->h_aliases[count] = buff_locp;
1153 bcopy((char *)he->h_aliases[i], buff_locp, len);
1154 ++count;
1155 }
1156 }
1157 host->h_aliases[count] = NULL;
1158 host->h_length = sizeof (struct in_addr);
1159 host->h_addrtype = AF_INET;
1160 free(res);
1161 return (host);
1162 cleanup:
1163 *extract_error = NO_RECOVERY;
1164 (void) __IPv6_cleanup(res);
1165 return (NULL);
1166 }
1167
1168 /*
1169 * This routine takes as input a pointer to a hostent and filters out
1170 * the type of addresses specified by the af argument. AF_INET
1171 * indicates that the caller wishes to filter out IPv4-mapped
1172 * addresses, and AF_INET6 indicates that the caller wishes to filter
1173 * out IPv6 addresses which aren't IPv4-mapped. If filtering would
1174 * result in all addresses being filtered out, a NULL pointer is returned.
1175 * Otherwise, the he pointer passed in is returned, even if no addresses
1176 * were filtered out.
1177 */
1178 static struct hostent *
__filter_addresses(int af,struct hostent * he)1179 __filter_addresses(int af, struct hostent *he)
1180 {
1181 struct in6_addr **in6addrlist, **in6addr;
1182 boolean_t isipv4mapped;
1183 int i = 0;
1184
1185 if (he == NULL)
1186 return (NULL);
1187
1188 in6addrlist = (struct in6_addr **)he->h_addr_list;
1189 for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) {
1190 isipv4mapped = IN6_IS_ADDR_V4MAPPED(*in6addr);
1191
1192 if ((af == AF_INET && !isipv4mapped) ||
1193 (af == AF_INET6 && isipv4mapped)) {
1194 if (in6addrlist[i] != *in6addr)
1195 in6addrlist[i] = *in6addr;
1196 i++;
1197 }
1198 }
1199
1200 if (i == 0) {
1201 /* We filtered everything out. */
1202 return (NULL);
1203 } else {
1204 /* NULL terminate the list and return the hostent */
1205 in6addrlist[i] = NULL;
1206 return (he);
1207 }
1208 }
1209
1210 /*
1211 * This routine searches a hostent for v4 mapped IPv6 addresses.
1212 * he hostent structure to seach
1213 * find_both flag indicating if only want mapped or both map'd and v6
1214 * return values:
1215 * 0 = No mapped addresses
1216 * 1 = Mapped v4 address found (returns on first one found)
1217 * 2 = Both v6 and v4 mapped are present
1218 *
1219 * If hostent passed in with no addresses, zero will be returned.
1220 */
1221
1222 static int
__find_mapped(struct hostent * he,int find_both)1223 __find_mapped(struct hostent *he, int find_both)
1224 {
1225 int i;
1226 int mapd_found = 0;
1227 int v6_found = 0;
1228
1229 for (i = 0; he->h_addr_list[i] != NULL; i++) {
1230 /* LINTED pointer cast */
1231 if (IN6_IS_ADDR_V4MAPPED(
1232 (struct in6_addr *)he->h_addr_list[i])) {
1233 if (find_both)
1234 mapd_found = 1;
1235 else
1236 return (1);
1237 } else {
1238 v6_found = 1;
1239 }
1240 /* save some iterations once both found */
1241 if (mapd_found && v6_found)
1242 return (2);
1243 }
1244 return (mapd_found);
1245 }
1246
1247 /*
1248 * This routine was added specifically for the IPv6 getipnodeby*() APIs. This
1249 * separates the result pointer (ptr to hostent+data buf) from the
1250 * nss_XbyY_buf_t ptr (required for nsswitch API). The returned hostent ptr
1251 * can be passed to freehostent() and freed independently.
1252 *
1253 * bufp->result bufp->buffer
1254 * | |
1255 * V V
1256 * ------------------------------------------------...--
1257 * |struct hostent |addresses aliases |
1258 * ------------------------------------------------...--
1259 * | |<--------bufp->buflen-------------->|
1260 */
1261
1262 #define ALIGN(x) ((((long)(x)) + sizeof (long) - 1) & ~(sizeof (long) - 1))
1263
1264 static nss_XbyY_buf_t *
__IPv6_alloc(int bufsz)1265 __IPv6_alloc(int bufsz)
1266 {
1267 nss_XbyY_buf_t *bufp;
1268
1269 if ((bufp = malloc(sizeof (nss_XbyY_buf_t))) == NULL)
1270 return (NULL);
1271
1272 if ((bufp->result = malloc(ALIGN(sizeof (struct hostent)) + bufsz)) ==
1273 NULL) {
1274 free(bufp);
1275 return (NULL);
1276 }
1277 bufp->buffer = (char *)(bufp->result) + sizeof (struct hostent);
1278 bufp->buflen = bufsz;
1279 return (bufp);
1280 }
1281
1282 /*
1283 * This routine is use only for error return cleanup. This will free the
1284 * hostent pointer, so don't use for successful returns.
1285 */
1286 static void
__IPv6_cleanup(nss_XbyY_buf_t * bufp)1287 __IPv6_cleanup(nss_XbyY_buf_t *bufp)
1288 {
1289 if (bufp == NULL)
1290 return;
1291 if (bufp->result != NULL)
1292 free(bufp->result);
1293 free(bufp);
1294 }
1295