17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5cb5caa98Sdjl * Common Development and Distribution License (the "License").
6cb5caa98Sdjl * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
2298a55d33SStacey Marshall * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23cb5caa98Sdjl * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
25e48cae6fSRobert Mustacchi /*
26e48cae6fSRobert Mustacchi * Copyright (c) 2013, Joyent, Inc. All rights reserved.
27*778e4551SAndy Fiddaman * Copyright 2023 Oxide Computer Company
28e48cae6fSRobert Mustacchi */
297c478bd9Sstevel@tonic-gate
30cb5caa98Sdjl /*
31cb5caa98Sdjl * dns_common.c
32cb5caa98Sdjl */
337c478bd9Sstevel@tonic-gate
347c478bd9Sstevel@tonic-gate #include "dns_common.h"
35e48cae6fSRobert Mustacchi #include <sys/types.h>
36e48cae6fSRobert Mustacchi #include <sys/socket.h>
37e48cae6fSRobert Mustacchi #include <ifaddrs.h>
38e48cae6fSRobert Mustacchi #include <net/if.h>
397c478bd9Sstevel@tonic-gate
40cb5caa98Sdjl #pragma weak dn_expand
41cb5caa98Sdjl #pragma weak res_ninit
420e50326aSStacey Marshall #pragma weak res_ndestroy
43cb5caa98Sdjl #pragma weak res_nsearch
44cb5caa98Sdjl #pragma weak res_nclose
45cb5caa98Sdjl #pragma weak ns_get16
46cb5caa98Sdjl #pragma weak ns_get32
47cb5caa98Sdjl #pragma weak __ns_get16
48cb5caa98Sdjl #pragma weak __ns_get32
49cb5caa98Sdjl
507c478bd9Sstevel@tonic-gate #define DNS_ALIASES 0
517c478bd9Sstevel@tonic-gate #define DNS_ADDRLIST 1
527c478bd9Sstevel@tonic-gate #define DNS_MAPDLIST 2
537c478bd9Sstevel@tonic-gate
54940a40eaSsm #ifndef tolower
55940a40eaSsm #define tolower(c) ((c) >= 'A' && (c) <= 'Z' ? (c) | 0x20 : (c))
56940a40eaSsm #endif
57940a40eaSsm
587c478bd9Sstevel@tonic-gate static int
dns_netdb_aliases(char ** from_list,char ** to_list,char ** aliaspp,int type,int * count,int af_type)59*778e4551SAndy Fiddaman dns_netdb_aliases(char **from_list, char **to_list, char **aliaspp, int type,
60*778e4551SAndy Fiddaman int *count, int af_type)
617c478bd9Sstevel@tonic-gate {
627c478bd9Sstevel@tonic-gate char *fstr;
637c478bd9Sstevel@tonic-gate int cnt = 0;
647c478bd9Sstevel@tonic-gate size_t len;
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate *count = 0;
677c478bd9Sstevel@tonic-gate if ((char *)to_list >= *aliaspp)
687c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE);
697c478bd9Sstevel@tonic-gate
707c478bd9Sstevel@tonic-gate for (fstr = from_list[cnt]; fstr != NULL; fstr = from_list[cnt]) {
71*778e4551SAndy Fiddaman if (type == DNS_ALIASES) {
727c478bd9Sstevel@tonic-gate len = strlen(fstr) + 1;
73*778e4551SAndy Fiddaman } else {
74*778e4551SAndy Fiddaman len = (af_type == AF_INET) ? sizeof (struct in_addr) :
75*778e4551SAndy Fiddaman sizeof (struct in6_addr);
76*778e4551SAndy Fiddaman }
777c478bd9Sstevel@tonic-gate *aliaspp -= len;
787c478bd9Sstevel@tonic-gate to_list[cnt] = *aliaspp;
797c478bd9Sstevel@tonic-gate if (*aliaspp <= (char *)&to_list[cnt+1])
807c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE);
817c478bd9Sstevel@tonic-gate if (type == DNS_MAPDLIST) {
82cb5caa98Sdjl /* LINTED: E_BAD_PTR_CAST_ALIGN */
83cb5caa98Sdjl struct in6_addr *addr6p = (struct in6_addr *)*aliaspp;
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate (void) memset(addr6p, '\0', sizeof (struct in6_addr));
867c478bd9Sstevel@tonic-gate (void) memcpy(&addr6p->s6_addr[12], fstr,
87*778e4551SAndy Fiddaman sizeof (struct in_addr));
887c478bd9Sstevel@tonic-gate addr6p->s6_addr[10] = 0xffU;
897c478bd9Sstevel@tonic-gate addr6p->s6_addr[11] = 0xffU;
907c478bd9Sstevel@tonic-gate ++cnt;
917c478bd9Sstevel@tonic-gate } else {
927c478bd9Sstevel@tonic-gate (void) memcpy (*aliaspp, fstr, len);
937c478bd9Sstevel@tonic-gate ++cnt;
947c478bd9Sstevel@tonic-gate }
957c478bd9Sstevel@tonic-gate }
967c478bd9Sstevel@tonic-gate to_list[cnt] = NULL;
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate *count = cnt;
997c478bd9Sstevel@tonic-gate if (cnt == 0)
1007c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE);
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS);
1037c478bd9Sstevel@tonic-gate }
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate int
ent2result(struct hostent * he,nss_XbyY_args_t * argp,int af_type)107*778e4551SAndy Fiddaman ent2result(struct hostent *he, nss_XbyY_args_t *argp, int af_type)
1087c478bd9Sstevel@tonic-gate {
1097c478bd9Sstevel@tonic-gate char *buffer, *limit;
1107c478bd9Sstevel@tonic-gate int buflen = argp->buf.buflen;
1117c478bd9Sstevel@tonic-gate int ret, count;
1127c478bd9Sstevel@tonic-gate size_t len;
113*778e4551SAndy Fiddaman struct hostent *host;
1147c478bd9Sstevel@tonic-gate struct in_addr *addrp;
1157c478bd9Sstevel@tonic-gate struct in6_addr *addrp6;
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate limit = argp->buf.buffer + buflen;
118cb5caa98Sdjl host = (struct hostent *)argp->buf.result;
1197c478bd9Sstevel@tonic-gate buffer = argp->buf.buffer;
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate /* h_addrtype and h_length */
1227c478bd9Sstevel@tonic-gate host->h_addrtype = af_type;
123*778e4551SAndy Fiddaman host->h_length = (af_type == AF_INET) ? sizeof (struct in_addr) :
124*778e4551SAndy Fiddaman sizeof (struct in6_addr);
1257c478bd9Sstevel@tonic-gate
1267c478bd9Sstevel@tonic-gate /* h_name */
1277c478bd9Sstevel@tonic-gate len = strlen(he->h_name) + 1;
1287c478bd9Sstevel@tonic-gate host->h_name = buffer;
1297c478bd9Sstevel@tonic-gate if (host->h_name + len >= limit)
1307c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE);
1317c478bd9Sstevel@tonic-gate (void) memcpy(host->h_name, he->h_name, len);
1327c478bd9Sstevel@tonic-gate buffer += len;
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate /* h_addr_list */
1357c478bd9Sstevel@tonic-gate if (af_type == AF_INET) {
136cb5caa98Sdjl addrp = (struct in_addr *)ROUND_DOWN(limit, sizeof (*addrp));
137*778e4551SAndy Fiddaman host->h_addr_list = (char **)ROUND_UP(buffer, sizeof (char **));
1387c478bd9Sstevel@tonic-gate ret = dns_netdb_aliases(he->h_addr_list, host->h_addr_list,
139*778e4551SAndy Fiddaman (char **)&addrp, DNS_ADDRLIST, &count, af_type);
1407c478bd9Sstevel@tonic-gate if (ret != NSS_STR_PARSE_SUCCESS)
1417c478bd9Sstevel@tonic-gate return (ret);
1427c478bd9Sstevel@tonic-gate /* h_aliases */
1437c478bd9Sstevel@tonic-gate host->h_aliases = host->h_addr_list + count + 1;
1447c478bd9Sstevel@tonic-gate ret = dns_netdb_aliases(he->h_aliases, host->h_aliases,
145*778e4551SAndy Fiddaman (char **)&addrp, DNS_ALIASES, &count, af_type);
1467c478bd9Sstevel@tonic-gate } else {
147*778e4551SAndy Fiddaman addrp6 = (struct in6_addr *)ROUND_DOWN(limit, sizeof (*addrp6));
148*778e4551SAndy Fiddaman host->h_addr_list = (char **)ROUND_UP(buffer, sizeof (char **));
1497c478bd9Sstevel@tonic-gate if (he->h_addrtype == AF_INET && af_type == AF_INET6) {
1507c478bd9Sstevel@tonic-gate ret = dns_netdb_aliases(he->h_addr_list,
151*778e4551SAndy Fiddaman host->h_addr_list, (char **)&addrp6,
152*778e4551SAndy Fiddaman DNS_MAPDLIST, &count, af_type);
1537c478bd9Sstevel@tonic-gate } else {
1547c478bd9Sstevel@tonic-gate ret = dns_netdb_aliases(he->h_addr_list,
155*778e4551SAndy Fiddaman host->h_addr_list, (char **)&addrp6,
156*778e4551SAndy Fiddaman DNS_ADDRLIST, &count, af_type);
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate if (ret != NSS_STR_PARSE_SUCCESS)
1597c478bd9Sstevel@tonic-gate return (ret);
1607c478bd9Sstevel@tonic-gate /* h_aliases */
1617c478bd9Sstevel@tonic-gate host->h_aliases = host->h_addr_list + count + 1;
1627c478bd9Sstevel@tonic-gate ret = dns_netdb_aliases(he->h_aliases, host->h_aliases,
163*778e4551SAndy Fiddaman (char **)&addrp6, DNS_ALIASES, &count, af_type);
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate if (ret == NSS_STR_PARSE_PARSE)
1667c478bd9Sstevel@tonic-gate ret = NSS_STR_PARSE_SUCCESS;
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate return (ret);
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate
171cb5caa98Sdjl /*
172cb5caa98Sdjl * Convert the hostent structure into string in the following
173cb5caa98Sdjl * format:
174cb5caa98Sdjl *
175cb5caa98Sdjl * IP-address official-host-name nicknames ...
176cb5caa98Sdjl *
177cb5caa98Sdjl * If more than one IP-addresses matches the official-host-name,
178cb5caa98Sdjl * the above line will be followed by:
179cb5caa98Sdjl * IP-address-1 official-host-name
180cb5caa98Sdjl * IP-address-2 official-host-name
181cb5caa98Sdjl * ...
182cb5caa98Sdjl *
183cb5caa98Sdjl * This is so that the str2hostent function in libnsl
184cb5caa98Sdjl * can convert the string back to the original hostent
185cb5caa98Sdjl * data.
186cb5caa98Sdjl */
187cb5caa98Sdjl int
ent2str(struct hostent * hp,nss_XbyY_args_t * ap,int af_type)188*778e4551SAndy Fiddaman ent2str(struct hostent *hp, nss_XbyY_args_t *ap, int af_type)
189cb5caa98Sdjl {
190cb5caa98Sdjl char **p;
191cb5caa98Sdjl char obuf[INET6_ADDRSTRLEN];
192cb5caa98Sdjl void *addr;
193cb5caa98Sdjl struct in_addr in4;
194cb5caa98Sdjl int af;
195cb5caa98Sdjl int n;
196cb5caa98Sdjl const char *res;
197cb5caa98Sdjl char **q;
198cb5caa98Sdjl int l = ap->buf.buflen;
199cb5caa98Sdjl char *s = ap->buf.buffer;
200cb5caa98Sdjl
201cb5caa98Sdjl /*
202cb5caa98Sdjl * for "hosts" lookup, we only want address type of
203cb5caa98Sdjl * AF_INET. For "ipnodes", we can have both AF_INET
204cb5caa98Sdjl * and AF_INET6.
205cb5caa98Sdjl */
206cb5caa98Sdjl if (af_type == AF_INET && hp->h_addrtype != AF_INET)
207cb5caa98Sdjl return (NSS_STR_PARSE_PARSE);
208cb5caa98Sdjl
209cb5caa98Sdjl for (p = hp->h_addr_list; *p != 0; p++) {
210cb5caa98Sdjl
211cb5caa98Sdjl if (p != hp->h_addr_list) {
212cb5caa98Sdjl *s = '\n';
213cb5caa98Sdjl s++;
214cb5caa98Sdjl l--;
215cb5caa98Sdjl }
216cb5caa98Sdjl
217cb5caa98Sdjl if (hp->h_addrtype == AF_INET6) {
218cb5caa98Sdjl /* LINTED: E_BAD_PTR_CAST_ALIGN */
219cb5caa98Sdjl if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)*p)) {
220cb5caa98Sdjl /* LINTED: E_BAD_PTR_CAST_ALIGN */
221cb5caa98Sdjl IN6_V4MAPPED_TO_INADDR((struct in6_addr *)*p,
22280b80bf0Smichen &in4);
223cb5caa98Sdjl af = AF_INET;
224cb5caa98Sdjl addr = &in4;
225cb5caa98Sdjl } else {
226cb5caa98Sdjl af = AF_INET6;
227cb5caa98Sdjl addr = *p;
228cb5caa98Sdjl }
229cb5caa98Sdjl } else {
230cb5caa98Sdjl af = AF_INET;
231cb5caa98Sdjl addr = *p;
232cb5caa98Sdjl }
233cb5caa98Sdjl res = inet_ntop(af, addr, obuf, sizeof (obuf));
234cb5caa98Sdjl if (res == NULL)
235cb5caa98Sdjl return (NSS_STR_PARSE_PARSE);
236cb5caa98Sdjl
23780b80bf0Smichen if ((n = snprintf(s, l, "%s", res)) >= l)
238cb5caa98Sdjl return (NSS_STR_PARSE_ERANGE);
239cb5caa98Sdjl l -= n;
240cb5caa98Sdjl s += n;
24180b80bf0Smichen if (hp->h_name != NULL && *hp->h_name != '\0') {
24280b80bf0Smichen if ((n = snprintf(s, l, " %s", hp->h_name)) >= l)
24380b80bf0Smichen return (NSS_STR_PARSE_ERANGE);
24480b80bf0Smichen l -= n;
24580b80bf0Smichen s += n;
24680b80bf0Smichen }
247cb5caa98Sdjl if (p == hp->h_addr_list) {
248cb5caa98Sdjl for (q = hp->h_aliases; q && *q; q++) {
249cb5caa98Sdjl if ((n = snprintf(s, l, " %s", *q)) >= l)
250cb5caa98Sdjl return (NSS_STR_PARSE_ERANGE);
251cb5caa98Sdjl l -= n;
252cb5caa98Sdjl s += n;
253cb5caa98Sdjl }
254cb5caa98Sdjl }
255cb5caa98Sdjl }
256cb5caa98Sdjl
257cb5caa98Sdjl ap->returnlen = s - ap->buf.buffer;
258cb5caa98Sdjl return (NSS_STR_PARSE_SUCCESS);
259cb5caa98Sdjl }
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate nss_backend_t *
_nss_dns_constr(dns_backend_op_t ops[],int n_ops)2627c478bd9Sstevel@tonic-gate _nss_dns_constr(dns_backend_op_t ops[], int n_ops)
2637c478bd9Sstevel@tonic-gate {
2647c478bd9Sstevel@tonic-gate dns_backend_ptr_t be;
2657c478bd9Sstevel@tonic-gate
266cb5caa98Sdjl if ((be = (dns_backend_ptr_t)malloc(sizeof (*be))) == 0)
2677c478bd9Sstevel@tonic-gate return (0);
2687c478bd9Sstevel@tonic-gate
2697c478bd9Sstevel@tonic-gate be->ops = ops;
2707c478bd9Sstevel@tonic-gate be->n_ops = n_ops;
271cb5caa98Sdjl return ((nss_backend_t *)be);
272cb5caa98Sdjl }
273cb5caa98Sdjl
274940a40eaSsm /*
275940a40eaSsm * name_is_alias(aliases_ptr, name_ptr)
276940a40eaSsm * Verify name matches an alias in the provided aliases list.
277940a40eaSsm *
278940a40eaSsm * Within DNS there should be only one canonical name, aliases should
279940a40eaSsm * all refer to the one canonical. However alias chains do occur and
280940a40eaSsm * pre BIND 9 servers may also respond with multiple CNAMEs. This
281940a40eaSsm * routine checks if a given name has been provided as a CNAME in the
282940a40eaSsm * response. This assumes that the chains have been sent in-order.
283940a40eaSsm *
284940a40eaSsm * INPUT:
285940a40eaSsm * aliases_ptr: space separated list of alias names.
286940a40eaSsm * name_ptr: name to look for in aliases_ptr list.
28798a55d33SStacey Marshall * RETURNS: NSS_SUCCESS or NSS_NOTFOUND
288940a40eaSsm * NSS_SUCCESS indicates that the name is listed in the collected aliases.
289940a40eaSsm */
290940a40eaSsm static nss_status_t
name_is_alias(char * aliases_ptr,char * name_ptr)291*778e4551SAndy Fiddaman name_is_alias(char *aliases_ptr, char *name_ptr)
292*778e4551SAndy Fiddaman {
293940a40eaSsm char *host_ptr;
294940a40eaSsm /* Loop through alias string and compare it against host string. */
295940a40eaSsm while (*aliases_ptr != '\0') {
296940a40eaSsm host_ptr = name_ptr;
297940a40eaSsm
298940a40eaSsm /* Compare name with alias. */
299940a40eaSsm while (tolower(*host_ptr) == tolower(*aliases_ptr) &&
300940a40eaSsm *host_ptr != '\0') {
301940a40eaSsm host_ptr++;
302940a40eaSsm aliases_ptr++;
303940a40eaSsm }
304940a40eaSsm
305940a40eaSsm /*
306940a40eaSsm * If name was exhausted and the next character in the
307940a40eaSsm * alias is either the end-of-string or space
308940a40eaSsm * character then we have a match.
309940a40eaSsm */
310940a40eaSsm if (*host_ptr == '\0' &&
311940a40eaSsm (*aliases_ptr == '\0' || *aliases_ptr == ' ')) {
312940a40eaSsm return (NSS_SUCCESS);
313940a40eaSsm }
314940a40eaSsm
315940a40eaSsm /* Alias did not match, step over remainder of alias. */
316940a40eaSsm while (*aliases_ptr != ' ' && *aliases_ptr != '\0')
317940a40eaSsm aliases_ptr++;
318940a40eaSsm /* Step over separator character. */
319940a40eaSsm while (*aliases_ptr == ' ') aliases_ptr++;
320940a40eaSsm }
32198a55d33SStacey Marshall return (NSS_NOTFOUND);
322940a40eaSsm }
323940a40eaSsm
324e48cae6fSRobert Mustacchi static int
_nss_has_interfaces(boolean_t * v4,boolean_t * v6)325e48cae6fSRobert Mustacchi _nss_has_interfaces(boolean_t *v4, boolean_t *v6)
326e48cae6fSRobert Mustacchi {
327e48cae6fSRobert Mustacchi struct ifaddrs *ifp, *i;
328e48cae6fSRobert Mustacchi struct in_addr in4;
329e48cae6fSRobert Mustacchi struct in6_addr in6;
330e48cae6fSRobert Mustacchi const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
331e48cae6fSRobert Mustacchi
332e48cae6fSRobert Mustacchi *v4 = *v6 = B_FALSE;
333e48cae6fSRobert Mustacchi
334e48cae6fSRobert Mustacchi if (getifaddrs(&ifp) != 0)
335e48cae6fSRobert Mustacchi return (-1);
336e48cae6fSRobert Mustacchi
337e48cae6fSRobert Mustacchi for (i = ifp; i != NULL; i = i->ifa_next) {
338e48cae6fSRobert Mustacchi if (i->ifa_flags & IFF_LOOPBACK)
339e48cae6fSRobert Mustacchi continue;
340e48cae6fSRobert Mustacchi if ((i->ifa_flags & IFF_UP) == 0)
341e48cae6fSRobert Mustacchi continue;
342e48cae6fSRobert Mustacchi
343e48cae6fSRobert Mustacchi if (i->ifa_addr->sa_family == AF_INET) {
344e48cae6fSRobert Mustacchi if (*v4 != B_FALSE)
345e48cae6fSRobert Mustacchi continue;
346e48cae6fSRobert Mustacchi
347e48cae6fSRobert Mustacchi if (((struct sockaddr_in *)i->ifa_addr)->
348e48cae6fSRobert Mustacchi sin_addr.s_addr == INADDR_ANY)
349e48cae6fSRobert Mustacchi continue;
350e48cae6fSRobert Mustacchi *v4 = B_TRUE;
351e48cae6fSRobert Mustacchi }
352e48cae6fSRobert Mustacchi
353e48cae6fSRobert Mustacchi if (i->ifa_addr->sa_family == AF_INET6) {
354e48cae6fSRobert Mustacchi if (*v6 != B_FALSE)
355e48cae6fSRobert Mustacchi continue;
356e48cae6fSRobert Mustacchi
357e48cae6fSRobert Mustacchi if (memcmp(&in6addr_any,
358e48cae6fSRobert Mustacchi &((struct sockaddr_in6 *)i->ifa_addr)->sin6_addr,
359e48cae6fSRobert Mustacchi sizeof (struct in6_addr)) == 0)
360e48cae6fSRobert Mustacchi continue;
361e48cae6fSRobert Mustacchi *v6 = B_TRUE;
362e48cae6fSRobert Mustacchi }
363e48cae6fSRobert Mustacchi }
364e48cae6fSRobert Mustacchi
365e48cae6fSRobert Mustacchi freeifaddrs(ifp);
366e48cae6fSRobert Mustacchi return (0);
367e48cae6fSRobert Mustacchi }
368e48cae6fSRobert Mustacchi
369cb5caa98Sdjl /*
370cb5caa98Sdjl * nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode)
371cb5caa98Sdjl * nss2 get hosts/ipnodes with ttl backend DNS search engine.
372cb5caa98Sdjl *
373cb5caa98Sdjl * This API is given a pointer to a packed buffer, and the buffer size
374cb5caa98Sdjl * It's job is to perform the appropriate res_nsearch, extract the
375cb5caa98Sdjl * results and build a unmarshalled hosts/ipnodes result buffer.
376cb5caa98Sdjl * Additionally in the extended results a nssuint_t ttl is placed.
377cb5caa98Sdjl * This ttl is the lessor of the ttl's extracted from the result.
378cb5caa98Sdjl *
379cb5caa98Sdjl * RETURNS: NSS_SUCCESS or NSS_ERROR
380cb5caa98Sdjl * If an NSS_ERROR result is returned, nscd is expected
381cb5caa98Sdjl * to resubmit the gethosts request using the old style
382cb5caa98Sdjl * nsswitch lookup format.
383cb5caa98Sdjl */
384cb5caa98Sdjl
385cb5caa98Sdjl nss_status_t
_nss_dns_gethost_withttl(void * buffer,size_t bufsize,int ipnode)386cb5caa98Sdjl _nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode)
387cb5caa98Sdjl {
388cb5caa98Sdjl /* nss buffer variables */
389cb5caa98Sdjl nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
390cb5caa98Sdjl nss_XbyY_args_t arg;
391cb5caa98Sdjl char *dbname;
392cb5caa98Sdjl int dbop;
393cb5caa98Sdjl nss_status_t sret;
394cb5caa98Sdjl size_t bsize, blen;
395cb5caa98Sdjl char *bptr;
396cb5caa98Sdjl /* resolver query variables */
397c70a8a3bSmichen struct __res_state stat, *statp; /* dns state block */
398c70a8a3bSmichen union msg {
399c70a8a3bSmichen uchar_t buf[NS_MAXMSG]; /* max legal DNS answer size */
400c70a8a3bSmichen HEADER h;
401c70a8a3bSmichen } resbuf;
402c70a8a3bSmichen char aliases[NS_MAXMSG]; /* set of aliases */
403cb5caa98Sdjl const char *name;
404cb5caa98Sdjl int qtype;
405cb5caa98Sdjl /* answer parsing variables */
406cb5caa98Sdjl HEADER *hp;
407cb5caa98Sdjl uchar_t *cp; /* current location in message */
408cb5caa98Sdjl uchar_t *bom; /* start of message */
409cb5caa98Sdjl uchar_t *eom; /* end of message */
410cb5caa98Sdjl uchar_t *eor; /* end of record */
411cb5caa98Sdjl int ancount, qdcount;
412cb5caa98Sdjl int type, class;
413cb5caa98Sdjl nssuint_t nttl, ttl, *pttl; /* The purpose of this API */
414cb5caa98Sdjl int n, ret;
415cb5caa98Sdjl const char *np;
416cb5caa98Sdjl /* temporary buffers */
417cb5caa98Sdjl char nbuf[INET6_ADDRSTRLEN]; /* address parser */
418cb5caa98Sdjl char host[MAXHOSTNAMELEN]; /* result host name */
419cb5caa98Sdjl char ans[MAXHOSTNAMELEN]; /* record name */
420cb5caa98Sdjl char aname[MAXHOSTNAMELEN]; /* alias result (C_NAME) */
421cb5caa98Sdjl /* misc variables */
422cb5caa98Sdjl int af;
423cb5caa98Sdjl char *ap, *apc;
42498a55d33SStacey Marshall int hlen = 0, alen, iplen, len, isans;
425e48cae6fSRobert Mustacchi boolean_t has_v4 = B_FALSE, has_v6 = B_FALSE;
426e48cae6fSRobert Mustacchi int flags, family, pass2 = 0;
427cb5caa98Sdjl
428c70a8a3bSmichen statp = &stat;
429c70a8a3bSmichen (void) memset(statp, '\0', sizeof (struct __res_state));
430e48cae6fSRobert Mustacchi if (res_ninit(statp) == -1) {
431c70a8a3bSmichen return (NSS_ERROR);
432e48cae6fSRobert Mustacchi }
433c70a8a3bSmichen
434c70a8a3bSmichen ap = apc = (char *)aliases;
435cb5caa98Sdjl alen = 0;
436cb5caa98Sdjl ttl = (nssuint_t)0xFFFFFFF; /* start w/max, find smaller */
437cb5caa98Sdjl
438cb5caa98Sdjl /* save space for ttl otherwise, why bother... */
439cb5caa98Sdjl bsize = pbuf->data_len - sizeof (nssuint_t);
440cb5caa98Sdjl bptr = (char *)buffer + pbuf->data_off;
441cb5caa98Sdjl blen = 0;
442cb5caa98Sdjl sret = nss_packed_getkey(buffer, bufsize, &dbname, &dbop, &arg);
443cb5caa98Sdjl if (sret != NSS_SUCCESS) {
4440e50326aSStacey Marshall res_ndestroy(statp);
445cb5caa98Sdjl return (NSS_ERROR);
446cb5caa98Sdjl }
447cb5caa98Sdjl
448e48cae6fSRobert Mustacchi /*
449e48cae6fSRobert Mustacchi * There may be flags set when we are handling ipnode. There are three
450e48cae6fSRobert Mustacchi * different values for flags:
451e48cae6fSRobert Mustacchi *
452e48cae6fSRobert Mustacchi * o AI_V4MAPPED
453e48cae6fSRobert Mustacchi * o AI_ALL
454e48cae6fSRobert Mustacchi * o AI_ADDRCONFIG
455e48cae6fSRobert Mustacchi *
456e48cae6fSRobert Mustacchi * The first two only have a meaning when af_family is ipv6. The latter
457e48cae6fSRobert Mustacchi * means something in both cases. These flags are documented in
458e48cae6fSRobert Mustacchi * getipnodebyname(3SOCKET), though the combinations leave a little
459e48cae6fSRobert Mustacchi * something to be desired. It would be great if we could actually use
460e48cae6fSRobert Mustacchi * getipnodebyname directly here since it already knows how to handle
461e48cae6fSRobert Mustacchi * this kind of logic; however, we're not quite so lucky. Ideally we
462e48cae6fSRobert Mustacchi * would add such an interface to libresolv.so.2 to handle this kind of
463e48cae6fSRobert Mustacchi * thing, but that's rather painful as well. We'll summarize what has to
464e48cae6fSRobert Mustacchi * happen below:
465e48cae6fSRobert Mustacchi *
466e48cae6fSRobert Mustacchi * AI_ALL is only meaningful when AI_V4MAPPED is also specified. Both
467e48cae6fSRobert Mustacchi * are ignored if the family is not AF_INET6
468e48cae6fSRobert Mustacchi *
469e48cae6fSRobert Mustacchi * family == AF_INET, flags | AI_ADDRCONFIG
470e48cae6fSRobert Mustacchi * - lookup A records iff we have v4 plumbed
471e48cae6fSRobert Mustacchi * family == AF_INET, !(flags | AI_ADDRCONFIG)
472e48cae6fSRobert Mustacchi * - lookup A records
473e48cae6fSRobert Mustacchi * family == AF_INET6, flags == 0 || flags == AI_ALL
474e48cae6fSRobert Mustacchi * - lookup AAAA records
475e48cae6fSRobert Mustacchi * family == AF_INET6, flags | AI_V4MAPPED
476e48cae6fSRobert Mustacchi * - lookup AAAA, if none, lookup A
477e48cae6fSRobert Mustacchi * family == AF_INET6, flags | AI_ADDRCONFIG
478e48cae6fSRobert Mustacchi * - lookup AAAA records if ipv6
479e48cae6fSRobert Mustacchi * family == AF_INET6, flags | AI_V4MAPPED && flags | AI_ALL
480e48cae6fSRobert Mustacchi * - lookup AAAA records, lookup A records
481e48cae6fSRobert Mustacchi * family == AF_INET6, flags | AI_V4MAPPED && flags | AI_ADDRCONFIG
482e48cae6fSRobert Mustacchi * - lookup AAAA records if ipv6
483e48cae6fSRobert Mustacchi * - If no AAAA && ipv4 exists, lookup A
484e48cae6fSRobert Mustacchi * family == AF_INET6, flags | AI_V4MAPPED && flags | AI_ADDRCONFIG &&
485e48cae6fSRobert Mustacchi * flags | AI_ALL
486e48cae6fSRobert Mustacchi * - lookup AAAA records if ipv6
487e48cae6fSRobert Mustacchi * - loookup A records if ipv4
488e48cae6fSRobert Mustacchi */
489cb5caa98Sdjl if (ipnode) {
490cb5caa98Sdjl /* initially only handle the simple cases */
491cb5caa98Sdjl name = arg.key.ipnode.name;
492e48cae6fSRobert Mustacchi flags = arg.key.ipnode.flags;
493e48cae6fSRobert Mustacchi family = arg.key.ipnode.af_family;
494e48cae6fSRobert Mustacchi if (flags != 0) {
495e48cae6fSRobert Mustacchi /*
496e48cae6fSRobert Mustacchi * Figure out our first pass. We'll determine if we need
497e48cae6fSRobert Mustacchi * to do a second pass afterwards once we successfully
498e48cae6fSRobert Mustacchi * finish our first pass.
499e48cae6fSRobert Mustacchi */
500e48cae6fSRobert Mustacchi if ((flags & AI_ADDRCONFIG) != 0) {
501e48cae6fSRobert Mustacchi if (_nss_has_interfaces(&has_v4, &has_v6) !=
502e48cae6fSRobert Mustacchi 0) {
503e48cae6fSRobert Mustacchi res_ndestroy(statp);
504e48cae6fSRobert Mustacchi return (NSS_ERROR);
505e48cae6fSRobert Mustacchi }
506e48cae6fSRobert Mustacchi /* Impossible situations... */
507e48cae6fSRobert Mustacchi if (family == AF_INET && has_v4 == B_FALSE) {
508e48cae6fSRobert Mustacchi res_ndestroy(statp);
509e48cae6fSRobert Mustacchi return (NSS_NOTFOUND);
510e48cae6fSRobert Mustacchi }
511e48cae6fSRobert Mustacchi if (family == AF_INET6 && has_v6 == B_FALSE &&
512e48cae6fSRobert Mustacchi !(flags & AI_V4MAPPED)) {
513e48cae6fSRobert Mustacchi res_ndestroy(statp);
514e48cae6fSRobert Mustacchi return (NSS_NOTFOUND);
515e48cae6fSRobert Mustacchi }
516e48cae6fSRobert Mustacchi if (family == AF_INET6 && has_v6)
517e48cae6fSRobert Mustacchi qtype = T_AAAA;
518e48cae6fSRobert Mustacchi if (family == AF_INET || (family == AF_INET6 &&
519e48cae6fSRobert Mustacchi has_v6 == B_FALSE && flags & AI_V4MAPPED))
520e48cae6fSRobert Mustacchi qtype = T_A;
521e48cae6fSRobert Mustacchi } else {
522e48cae6fSRobert Mustacchi has_v4 = has_v6 = B_TRUE;
523e48cae6fSRobert Mustacchi if (family == AF_INET6)
524e48cae6fSRobert Mustacchi qtype = T_AAAA;
525e48cae6fSRobert Mustacchi else
526e48cae6fSRobert Mustacchi qtype = T_A;
527e48cae6fSRobert Mustacchi }
528e48cae6fSRobert Mustacchi } else {
529e48cae6fSRobert Mustacchi if (family == AF_INET6)
530e48cae6fSRobert Mustacchi qtype = T_AAAA;
531e48cae6fSRobert Mustacchi else
532e48cae6fSRobert Mustacchi qtype = T_A;
533e48cae6fSRobert Mustacchi }
534cb5caa98Sdjl } else {
535cb5caa98Sdjl name = arg.key.name;
536cb5caa98Sdjl qtype = T_A;
537cb5caa98Sdjl }
538e48cae6fSRobert Mustacchi
539e48cae6fSRobert Mustacchi searchagain:
540c70a8a3bSmichen ret = res_nsearch(statp, name, C_IN, qtype, resbuf.buf, NS_MAXMSG);
541cb5caa98Sdjl if (ret == -1) {
542e48cae6fSRobert Mustacchi /*
543e48cae6fSRobert Mustacchi * We want to continue on unless we got NO_RECOVERY. Otherwise,
544e48cae6fSRobert Mustacchi * HOST_NOT_FOUND, TRY_AGAIN, and NO_DATA all suggest to me that
545e48cae6fSRobert Mustacchi * we should keep going.
546e48cae6fSRobert Mustacchi */
547e48cae6fSRobert Mustacchi if (statp->res_h_errno == NO_RECOVERY) {
548e48cae6fSRobert Mustacchi /* else lookup error - handle in general code */
549e48cae6fSRobert Mustacchi res_ndestroy(statp);
550e48cae6fSRobert Mustacchi return (NSS_ERROR);
551e48cae6fSRobert Mustacchi }
552e48cae6fSRobert Mustacchi
553e48cae6fSRobert Mustacchi /*
554e48cae6fSRobert Mustacchi * We found something on our first pass. Make sure that we do
555e48cae6fSRobert Mustacchi * not clobber this information. This ultimately means that we
556e48cae6fSRobert Mustacchi * were successful.
557e48cae6fSRobert Mustacchi */
558e48cae6fSRobert Mustacchi if (pass2 == 2)
559e48cae6fSRobert Mustacchi goto out;
560e48cae6fSRobert Mustacchi
561e48cae6fSRobert Mustacchi /*
562e48cae6fSRobert Mustacchi * If we're on the second pass (eg. we need to check both for A
563e48cae6fSRobert Mustacchi * and AAAA records), or we were only ever doing a search for
564e48cae6fSRobert Mustacchi * one type of record and are not supposed to do a second pass,
565e48cae6fSRobert Mustacchi * then we need to return that we couldn't find anything to the
566e48cae6fSRobert Mustacchi * user.
567e48cae6fSRobert Mustacchi */
568e48cae6fSRobert Mustacchi if (pass2 == 1 || flags == 0 || family == AF_INET ||
569e48cae6fSRobert Mustacchi (family == AF_INET6 && !(flags & AI_V4MAPPED))) {
570cb5caa98Sdjl pbuf->p_herrno = HOST_NOT_FOUND;
571cb5caa98Sdjl pbuf->p_status = NSS_NOTFOUND;
572cb5caa98Sdjl pbuf->data_len = 0;
5730e50326aSStacey Marshall res_ndestroy(statp);
574cb5caa98Sdjl return (NSS_NOTFOUND);
575cb5caa98Sdjl }
576e48cae6fSRobert Mustacchi
577e48cae6fSRobert Mustacchi /*
578e48cae6fSRobert Mustacchi * If we were only requested to search for flags on an IPv6
579e48cae6fSRobert Mustacchi * interface or we have no IPv4 interface, we stick to only
580e48cae6fSRobert Mustacchi * doing a single pass and bail now.
581e48cae6fSRobert Mustacchi */
582e48cae6fSRobert Mustacchi if ((flags & AI_ADDRCONFIG) && !(flags & AI_ALL) &&
583e48cae6fSRobert Mustacchi has_v4 == B_FALSE) {
584e48cae6fSRobert Mustacchi pbuf->p_herrno = HOST_NOT_FOUND;
585e48cae6fSRobert Mustacchi pbuf->p_status = NSS_NOTFOUND;
586e48cae6fSRobert Mustacchi pbuf->data_len = 0;
587e48cae6fSRobert Mustacchi res_ndestroy(statp);
588e48cae6fSRobert Mustacchi return (NSS_NOTFOUND);
589e48cae6fSRobert Mustacchi }
590e48cae6fSRobert Mustacchi qtype = T_A;
591e48cae6fSRobert Mustacchi flags = 0;
592e48cae6fSRobert Mustacchi pass2 = 1;
593e48cae6fSRobert Mustacchi goto searchagain;
594cb5caa98Sdjl }
595cb5caa98Sdjl
596c70a8a3bSmichen cp = resbuf.buf;
597c70a8a3bSmichen hp = (HEADER *)&resbuf.h;
598cb5caa98Sdjl bom = cp;
599cb5caa98Sdjl eom = cp + ret;
600cb5caa98Sdjl
601cb5caa98Sdjl ancount = ntohs(hp->ancount);
602cb5caa98Sdjl qdcount = ntohs(hp->qdcount);
603cb5caa98Sdjl cp += HFIXEDSZ;
604c70a8a3bSmichen if (qdcount != 1) {
6050e50326aSStacey Marshall res_ndestroy(statp);
606cb5caa98Sdjl return (NSS_ERROR);
607c70a8a3bSmichen }
608cb5caa98Sdjl n = dn_expand(bom, eom, cp, host, MAXHOSTNAMELEN);
609cb5caa98Sdjl if (n < 0) {
6100e50326aSStacey Marshall res_ndestroy(statp);
611cb5caa98Sdjl return (NSS_ERROR);
612cb5caa98Sdjl } else
613cb5caa98Sdjl hlen = strlen(host);
61480b80bf0Smichen /* no host name is an error, return */
61580b80bf0Smichen if (hlen <= 0) {
6160e50326aSStacey Marshall res_ndestroy(statp);
61780b80bf0Smichen return (NSS_ERROR);
61880b80bf0Smichen }
619cb5caa98Sdjl cp += n + QFIXEDSZ;
620c70a8a3bSmichen if (cp > eom) {
6210e50326aSStacey Marshall res_ndestroy(statp);
622cb5caa98Sdjl return (NSS_ERROR);
623c70a8a3bSmichen }
624cb5caa98Sdjl while (ancount-- > 0 && cp < eom && blen < bsize) {
625cb5caa98Sdjl n = dn_expand(bom, eom, cp, ans, MAXHOSTNAMELEN);
626cb5caa98Sdjl if (n > 0) {
627940a40eaSsm /*
628940a40eaSsm * Check that the expanded name is either the
629940a40eaSsm * name we asked for or a learned alias.
630940a40eaSsm */
63198a55d33SStacey Marshall if ((isans = strncasecmp(host, ans, hlen)) != 0 &&
63298a55d33SStacey Marshall (alen == 0 || name_is_alias(aliases, ans)
63398a55d33SStacey Marshall == NSS_NOTFOUND)) {
6340e50326aSStacey Marshall res_ndestroy(statp);
635cb5caa98Sdjl return (NSS_ERROR); /* spoof? */
636c70a8a3bSmichen }
637cb5caa98Sdjl }
638cb5caa98Sdjl cp += n;
639cb5caa98Sdjl /* bounds check */
640cb5caa98Sdjl type = ns_get16(cp); /* type */
641cb5caa98Sdjl cp += INT16SZ;
642cb5caa98Sdjl class = ns_get16(cp); /* class */
643cb5caa98Sdjl cp += INT16SZ;
64498a55d33SStacey Marshall nttl = (nssuint_t)ns_get32(cp); /* ttl in sec */
645cb5caa98Sdjl if (nttl < ttl)
646cb5caa98Sdjl ttl = nttl;
647cb5caa98Sdjl cp += INT32SZ;
648cb5caa98Sdjl n = ns_get16(cp); /* len */
649cb5caa98Sdjl cp += INT16SZ;
650cb5caa98Sdjl if (class != C_IN) {
651cb5caa98Sdjl cp += n;
652cb5caa98Sdjl continue;
653cb5caa98Sdjl }
654cb5caa98Sdjl eor = cp + n;
655cb5caa98Sdjl if (type == T_CNAME) {
656940a40eaSsm /*
65798a55d33SStacey Marshall * The name looked up is really an alias and the
65898a55d33SStacey Marshall * canonical name should be in the RDATA.
65998a55d33SStacey Marshall * A canonical name may have several aliases but an
66098a55d33SStacey Marshall * alias should only have one canonical name.
66198a55d33SStacey Marshall * However multiple CNAMEs and CNAME chains do exist!
66298a55d33SStacey Marshall *
66398a55d33SStacey Marshall * Just error out on attempted buffer overflow exploit,
66498a55d33SStacey Marshall * generic code will syslog.
66598a55d33SStacey Marshall *
666940a40eaSsm */
667cb5caa98Sdjl n = dn_expand(bom, eor, cp, aname, MAXHOSTNAMELEN);
66898a55d33SStacey Marshall if (n > 0 && (len = strlen(aname)) > 0) {
66998a55d33SStacey Marshall if (isans == 0) { /* host matched ans. */
670cb5caa98Sdjl /*
67198a55d33SStacey Marshall * Append host to alias list.
672cb5caa98Sdjl */
67398a55d33SStacey Marshall if (alen + hlen + 2 > NS_MAXMSG) {
6740e50326aSStacey Marshall res_ndestroy(statp);
675cb5caa98Sdjl return (NSS_ERROR);
676458d6ca5Smichen }
677cb5caa98Sdjl *apc++ = ' ';
678cb5caa98Sdjl alen++;
67998a55d33SStacey Marshall (void) strlcpy(apc, host,
68098a55d33SStacey Marshall NS_MAXMSG - alen);
68198a55d33SStacey Marshall alen += hlen;
68298a55d33SStacey Marshall apc += hlen;
68398a55d33SStacey Marshall }
68498a55d33SStacey Marshall /*
68598a55d33SStacey Marshall * Overwrite host with canonical name.
68698a55d33SStacey Marshall */
68798a55d33SStacey Marshall if (strlcpy(host, aname, MAXHOSTNAMELEN) >=
68898a55d33SStacey Marshall MAXHOSTNAMELEN) {
6890e50326aSStacey Marshall res_ndestroy(statp);
69098a55d33SStacey Marshall return (NSS_ERROR);
691cb5caa98Sdjl }
69298a55d33SStacey Marshall hlen = len;
693cb5caa98Sdjl }
694cb5caa98Sdjl cp += n;
695cb5caa98Sdjl continue;
696cb5caa98Sdjl }
697cb5caa98Sdjl if (type != qtype) {
698cb5caa98Sdjl cp += n;
699cb5caa98Sdjl continue;
700cb5caa98Sdjl }
701cb5caa98Sdjl /* check data size */
702cb5caa98Sdjl if ((type == T_A && n != INADDRSZ) ||
703cb5caa98Sdjl (type == T_AAAA && n != IN6ADDRSZ)) {
704cb5caa98Sdjl cp += n;
705cb5caa98Sdjl continue;
706cb5caa98Sdjl }
707cb5caa98Sdjl af = (type == T_A ? AF_INET : AF_INET6);
708cb5caa98Sdjl np = inet_ntop(af, (void *)cp, nbuf, INET6_ADDRSTRLEN);
709c70a8a3bSmichen if (np == NULL) {
7100e50326aSStacey Marshall res_ndestroy(statp);
711cb5caa98Sdjl return (NSS_ERROR);
712c70a8a3bSmichen }
713cb5caa98Sdjl cp += n;
714cb5caa98Sdjl /* append IP host aliases to results */
715cb5caa98Sdjl iplen = strlen(np);
716cb5caa98Sdjl /* ip <SP> hostname [<SP>][aliases] */
717cb5caa98Sdjl len = iplen + 2 + hlen + alen;
718cb5caa98Sdjl if (alen > 0)
719cb5caa98Sdjl len++;
720458d6ca5Smichen if (blen + len > bsize) {
7210e50326aSStacey Marshall res_ndestroy(statp);
722cb5caa98Sdjl return (NSS_ERROR);
723458d6ca5Smichen }
724cb5caa98Sdjl (void) strlcpy(bptr, np, bsize - blen);
725cb5caa98Sdjl blen += iplen;
726cb5caa98Sdjl bptr += iplen;
727cb5caa98Sdjl *bptr++ = ' ';
728cb5caa98Sdjl blen++;
729cb5caa98Sdjl (void) strlcpy(bptr, host, bsize - blen);
730cb5caa98Sdjl blen += hlen;
731cb5caa98Sdjl bptr += hlen;
732cb5caa98Sdjl if (alen > 0) {
733cb5caa98Sdjl *bptr++ = ' ';
734cb5caa98Sdjl blen++;
735cb5caa98Sdjl (void) strlcpy(bptr, ap, bsize - blen);
736cb5caa98Sdjl blen += alen;
737cb5caa98Sdjl bptr += alen;
738cb5caa98Sdjl }
739cb5caa98Sdjl *bptr++ = '\n';
740cb5caa98Sdjl blen++;
741cb5caa98Sdjl }
742e48cae6fSRobert Mustacchi
743e48cae6fSRobert Mustacchi /* Depending on our flags we may need to go back another time. */
744e48cae6fSRobert Mustacchi if (qtype == T_AAAA && family == AF_INET6 &&
745e48cae6fSRobert Mustacchi ((flags & AI_V4MAPPED) != 0) && ((flags & AI_ALL) != 0) &&
746e48cae6fSRobert Mustacchi has_v4 == B_TRUE) {
747e48cae6fSRobert Mustacchi qtype = T_A;
748e48cae6fSRobert Mustacchi pass2 = 2; /* Indicate that we found data this pass */
749e48cae6fSRobert Mustacchi goto searchagain;
750e48cae6fSRobert Mustacchi }
751e48cae6fSRobert Mustacchi
752*778e4551SAndy Fiddaman out:
753cb5caa98Sdjl /* Presumably the buffer is now filled. */
754cb5caa98Sdjl len = ROUND_UP(blen, sizeof (nssuint_t));
755cb5caa98Sdjl /* still room? */
756cb5caa98Sdjl if (len + sizeof (nssuint_t) > pbuf->data_len) {
757cb5caa98Sdjl /* sigh, no, what happened? */
7580e50326aSStacey Marshall res_ndestroy(statp);
759cb5caa98Sdjl return (NSS_ERROR);
760cb5caa98Sdjl }
761*778e4551SAndy Fiddaman
762cb5caa98Sdjl pbuf->ext_off = pbuf->data_off + len;
763cb5caa98Sdjl pbuf->ext_len = sizeof (nssuint_t);
764cb5caa98Sdjl pbuf->data_len = blen;
765cb5caa98Sdjl pttl = (nssuint_t *)((void *)((char *)pbuf + pbuf->ext_off));
766cb5caa98Sdjl *pttl = ttl;
7670e50326aSStacey Marshall res_ndestroy(statp);
768cb5caa98Sdjl return (NSS_SUCCESS);
7697c478bd9Sstevel@tonic-gate }
770