aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libc/dns/gethnamaddr.c1329
-rw-r--r--libc/dns/include/hostent.h93
-rw-r--r--libc/dns/net/sethostent.c266
-rw-r--r--libc/include/netdb.h2
-rw-r--r--tests/netdb_test.cpp126
5 files changed, 1260 insertions, 556 deletions
diff --git a/libc/dns/gethnamaddr.c b/libc/dns/gethnamaddr.c
index 736858ff..63a6a60d 100644
--- a/libc/dns/gethnamaddr.c
+++ b/libc/dns/gethnamaddr.c
@@ -1,4 +1,4 @@
1/* $NetBSD: gethnamaddr.c,v 1.70 2006/03/22 00:03:51 christos Exp $ */ 1/* $NetBSD: gethnamaddr.c,v 1.91 2014/06/19 15:08:18 christos Exp $ */
2 2
3/* 3/*
4 * ++Copyright++ 1985, 1988, 1993 4 * ++Copyright++ 1985, 1988, 1993
@@ -88,6 +88,31 @@
88#include <stdlib.h> 88#include <stdlib.h>
89#include <string.h> 89#include <string.h>
90 90
91#include "hostent.h"
92
93#define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \
94 (ok)(nm) != 0)
95#define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok)
96#define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok)
97
98#define addalias(d, s, arr, siz) do { \
99 if (d >= &arr[siz]) { \
100 char **xptr = realloc(arr, (siz + 10) * sizeof(*arr)); \
101 if (xptr == NULL) \
102 goto nospc; \
103 d = xptr + (d - arr); \
104 arr = xptr; \
105 siz += 10; \
106 } \
107 *d++ = s; \
108} while (/*CONSTCOND*/0)
109
110#define setup(arr, siz) do { \
111 arr = malloc((siz = 10) * sizeof(*arr)); \
112 if (arr == NULL) \
113 goto nospc; \
114} while (/*CONSTCOND*/0)
115
91// This should be synchronized to ResponseCode.h 116// This should be synchronized to ResponseCode.h
92static const int DnsProxyQueryResult = 222; 117static const int DnsProxyQueryResult = 222;
93 118
@@ -107,18 +132,15 @@ typedef union {
107} align; 132} align;
108 133
109#ifdef DEBUG 134#ifdef DEBUG
110static void dprintf(const char *, res_state, ...) 135static void debugprintf(const char *, res_state, ...)
111 __attribute__((__format__(__printf__, 1, 3))); 136 __attribute__((__format__(__printf__, 1, 3)));
112#endif 137#endif
113static struct hostent *getanswer(const querybuf *, int, const char *, int, 138static struct hostent *getanswer(const querybuf *, int, const char *, int,
114 res_state); 139 res_state, struct hostent *, char *, size_t, int *);
115static void map_v4v6_address(const char *, char *); 140static void map_v4v6_address(const char *, char *);
116static void map_v4v6_hostent(struct hostent *, char **, char *); 141static void map_v4v6_hostent(struct hostent *, char **, char *);
117static void addrsort(char **, int, res_state); 142static void addrsort(char **, int, res_state);
118 143
119static void _sethtent(int);
120static void _endhtent(void);
121static struct hostent *_gethtent(void);
122void ht_sethostent(int); 144void ht_sethostent(int);
123void ht_endhostent(void); 145void ht_endhostent(void);
124struct hostent *ht_gethostbyname(char *); 146struct hostent *ht_gethostbyname(char *);
@@ -126,13 +148,13 @@ struct hostent *ht_gethostbyaddr(const char *, int, int);
126void dns_service(void); 148void dns_service(void);
127#undef dn_skipname 149#undef dn_skipname
128int dn_skipname(const u_char *, const u_char *); 150int dn_skipname(const u_char *, const u_char *);
129static int _gethtbyaddr(void *, void *, va_list);
130static int _gethtbyname(void *, void *, va_list);
131static struct hostent *_gethtbyname2(const char *, int);
132static int _dns_gethtbyaddr(void *, void *, va_list); 151static int _dns_gethtbyaddr(void *, void *, va_list);
133static int _dns_gethtbyname(void *, void *, va_list); 152static int _dns_gethtbyname(void *, void *, va_list);
134 153
135static struct hostent *gethostbyname_internal(const char *, int, res_state, unsigned, unsigned); 154static struct hostent *gethostbyname_internal(const char *, int, res_state,
155 struct hostent *, char *, size_t, int *, unsigned, unsigned);
156static struct hostent* android_gethostbyaddrfornet_proxy_internal(const void*, socklen_t,
157 int, struct hostent *, char *, size_t, int *, unsigned, unsigned);
136 158
137static const ns_src default_dns_files[] = { 159static const ns_src default_dns_files[] = {
138 { NSSRC_FILES, NS_SUCCESS }, 160 { NSSRC_FILES, NS_SUCCESS },
@@ -143,9 +165,9 @@ static const ns_src default_dns_files[] = {
143 165
144#ifdef DEBUG 166#ifdef DEBUG
145static void 167static void
146dprintf(const char *msg, res_state res, ...) 168debugprintf(const char *msg, res_state res, ...)
147{ 169{
148 assert(msg != NULL); 170 _DIAGASSERT(msg != NULL);
149 171
150 if (res->options & RES_DEBUG) { 172 if (res->options & RES_DEBUG) {
151 int save = errno; 173 int save = errno;
@@ -159,48 +181,47 @@ dprintf(const char *msg, res_state res, ...)
159 } 181 }
160} 182}
161#else 183#else
162# define dprintf(msg, res, num) ((void)0) /*nada*/ 184# define debugprintf(msg, res, num) /*nada*/
163#endif 185#endif
164 186
165#define BOUNDED_INCR(x) \ 187#define BOUNDED_INCR(x) \
166 do { \ 188 do { \
167 cp += (x); \ 189 cp += (x); \
168 if (cp > eom) { \ 190 if (cp > eom) \
169 h_errno = NO_RECOVERY; \ 191 goto no_recovery; \
170 return NULL; \
171 } \
172 } while (/*CONSTCOND*/0) 192 } while (/*CONSTCOND*/0)
173 193
174#define BOUNDS_CHECK(ptr, count) \ 194#define BOUNDS_CHECK(ptr, count) \
175 do { \ 195 do { \
176 if ((ptr) + (count) > eom) { \ 196 if ((ptr) + (count) > eom) \
177 h_errno = NO_RECOVERY; \ 197 goto no_recovery; \
178 return NULL; \
179 } \
180 } while (/*CONSTCOND*/0) 198 } while (/*CONSTCOND*/0)
181 199
182static struct hostent * 200static struct hostent *
183getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, 201getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
184 res_state res) 202 res_state res, struct hostent *hent, char *buf, size_t buflen, int *he)
185{ 203{
186 const HEADER *hp; 204 const HEADER *hp;
187 const u_char *cp; 205 const u_char *cp;
188 int n; 206 int n;
207 size_t qlen;
189 const u_char *eom, *erdata; 208 const u_char *eom, *erdata;
190 char *bp, **ap, **hap, *ep; 209 char *bp, **ap, **hap, *ep;
191 int type, class, ancount, qdcount; 210 int type, class, ancount, qdcount;
192 int haveanswer, had_error; 211 int haveanswer, had_error;
193 int toobig = 0; 212 int toobig = 0;
194 char tbuf[MAXDNAME]; 213 char tbuf[MAXDNAME];
214 char **aliases;
215 size_t maxaliases;
216 char *addr_ptrs[MAXADDRS];
195 const char *tname; 217 const char *tname;
196 int (*name_ok)(const char *); 218 int (*name_ok)(const char *);
197 res_static rs = __res_get_static();
198 219
199 assert(answer != NULL); 220 _DIAGASSERT(answer != NULL);
200 assert(qname != NULL); 221 _DIAGASSERT(qname != NULL);
201 222
202 tname = qname; 223 tname = qname;
203 rs->host.h_name = NULL; 224 hent->h_name = NULL;
204 eom = answer->buf + anslen; 225 eom = answer->buf + anslen;
205 switch (qtype) { 226 switch (qtype) {
206 case T_A: 227 case T_A:
@@ -211,54 +232,51 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
211 name_ok = res_dnok; 232 name_ok = res_dnok;
212 break; 233 break;
213 default: 234 default:
235 *he = NO_RECOVERY;
214 return NULL; /* XXX should be abort(); */ 236 return NULL; /* XXX should be abort(); */
215 } 237 }
238
239 setup(aliases, maxaliases);
216 /* 240 /*
217 * find first satisfactory answer 241 * find first satisfactory answer
218 */ 242 */
219 hp = &answer->hdr; 243 hp = &answer->hdr;
220 ancount = ntohs(hp->ancount); 244 ancount = ntohs(hp->ancount);
221 qdcount = ntohs(hp->qdcount); 245 qdcount = ntohs(hp->qdcount);
222 bp = rs->hostbuf; 246 bp = buf;
223 ep = rs->hostbuf + sizeof rs->hostbuf; 247 ep = buf + buflen;
224 cp = answer->buf; 248 cp = answer->buf;
225 BOUNDED_INCR(HFIXEDSZ); 249 BOUNDED_INCR(HFIXEDSZ);
226 if (qdcount != 1) { 250 if (qdcount != 1)
227 h_errno = NO_RECOVERY; 251 goto no_recovery;
228 return NULL; 252
229 } 253 n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
230 n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 254 if ((n < 0) || !maybe_ok(res, bp, name_ok))
231 if ((n < 0) || !(*name_ok)(bp)) { 255 goto no_recovery;
232 h_errno = NO_RECOVERY; 256
233 return NULL;
234 }
235 BOUNDED_INCR(n + QFIXEDSZ); 257 BOUNDED_INCR(n + QFIXEDSZ);
236 if (qtype == T_A || qtype == T_AAAA) { 258 if (qtype == T_A || qtype == T_AAAA) {
237 /* res_send() has already verified that the query name is the 259 /* res_send() has already verified that the query name is the
238 * same as the one we sent; this just gets the expanded name 260 * same as the one we sent; this just gets the expanded name
239 * (i.e., with the succeeding search-domain tacked on). 261 * (i.e., with the succeeding search-domain tacked on).
240 */ 262 */
241 n = strlen(bp) + 1; /* for the \0 */ 263 n = (int)strlen(bp) + 1; /* for the \0 */
242 if (n >= MAXHOSTNAMELEN) { 264 if (n >= MAXHOSTNAMELEN)
243 h_errno = NO_RECOVERY; 265 goto no_recovery;
244 return NULL; 266 hent->h_name = bp;
245 }
246 rs->host.h_name = bp;
247 bp += n; 267 bp += n;
248 /* The qname can be abbreviated, but h_name is now absolute. */ 268 /* The qname can be abbreviated, but h_name is now absolute. */
249 qname = rs->host.h_name; 269 qname = hent->h_name;
250 } 270 }
251 ap = rs->host_aliases; 271 hent->h_aliases = ap = aliases;
272 hent->h_addr_list = hap = addr_ptrs;
252 *ap = NULL; 273 *ap = NULL;
253 rs->host.h_aliases = rs->host_aliases;
254 hap = rs->h_addr_ptrs;
255 *hap = NULL; 274 *hap = NULL;
256 rs->host.h_addr_list = rs->h_addr_ptrs;
257 haveanswer = 0; 275 haveanswer = 0;
258 had_error = 0; 276 had_error = 0;
259 while (ancount-- > 0 && cp < eom && !had_error) { 277 while (ancount-- > 0 && cp < eom && !had_error) {
260 n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 278 n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
261 if ((n < 0) || !(*name_ok)(bp)) { 279 if ((n < 0) || !maybe_ok(res, bp, name_ok)) {
262 had_error++; 280 had_error++;
263 continue; 281 continue;
264 } 282 }
@@ -278,50 +296,46 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
278 continue; /* XXX - had_error++ ? */ 296 continue; /* XXX - had_error++ ? */
279 } 297 }
280 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { 298 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
281 if (ap >= &rs->host_aliases[MAXALIASES-1]) 299 n = dn_expand(answer->buf, eom, cp, tbuf,
282 continue; 300 (int)sizeof tbuf);
283 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 301 if ((n < 0) || !maybe_ok(res, tbuf, name_ok)) {
284 if ((n < 0) || !(*name_ok)(tbuf)) {
285 had_error++; 302 had_error++;
286 continue; 303 continue;
287 } 304 }
288 cp += n; 305 cp += n;
289 if (cp != erdata) { 306 if (cp != erdata)
290 h_errno = NO_RECOVERY; 307 goto no_recovery;
291 return NULL;
292 }
293 /* Store alias. */ 308 /* Store alias. */
294 *ap++ = bp; 309 addalias(ap, bp, aliases, maxaliases);
295 n = strlen(bp) + 1; /* for the \0 */ 310 n = (int)strlen(bp) + 1; /* for the \0 */
296 if (n >= MAXHOSTNAMELEN) { 311 if (n >= MAXHOSTNAMELEN) {
297 had_error++; 312 had_error++;
298 continue; 313 continue;
299 } 314 }
300 bp += n; 315 bp += n;
301 /* Get canonical name. */ 316 /* Get canonical name. */
302 n = strlen(tbuf) + 1; /* for the \0 */ 317 n = (int)strlen(tbuf) + 1; /* for the \0 */
303 if (n > ep - bp || n >= MAXHOSTNAMELEN) { 318 if (n > ep - bp || n >= MAXHOSTNAMELEN) {
304 had_error++; 319 had_error++;
305 continue; 320 continue;
306 } 321 }
307 strlcpy(bp, tbuf, (size_t)(ep - bp)); 322 strlcpy(bp, tbuf, (size_t)(ep - bp));
308 rs->host.h_name = bp; 323 hent->h_name = bp;
309 bp += n; 324 bp += n;
310 continue; 325 continue;
311 } 326 }
312 if (qtype == T_PTR && type == T_CNAME) { 327 if (qtype == T_PTR && type == T_CNAME) {
313 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 328 n = dn_expand(answer->buf, eom, cp, tbuf,
314 if (n < 0 || !res_dnok(tbuf)) { 329 (int)sizeof tbuf);
330 if (n < 0 || !maybe_dnok(res, tbuf)) {
315 had_error++; 331 had_error++;
316 continue; 332 continue;
317 } 333 }
318 cp += n; 334 cp += n;
319 if (cp != erdata) { 335 if (cp != erdata)
320 h_errno = NO_RECOVERY; 336 goto no_recovery;
321 return NULL;
322 }
323 /* Get canonical name. */ 337 /* Get canonical name. */
324 n = strlen(tbuf) + 1; /* for the \0 */ 338 n = (int)strlen(tbuf) + 1; /* for the \0 */
325 if (n > ep - bp || n >= MAXHOSTNAMELEN) { 339 if (n > ep - bp || n >= MAXHOSTNAMELEN) {
326 had_error++; 340 had_error++;
327 continue; 341 continue;
@@ -348,25 +362,21 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
348 cp += n; 362 cp += n;
349 continue; /* XXX - had_error++ ? */ 363 continue; /* XXX - had_error++ ? */
350 } 364 }
351 n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 365 n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
352 if ((n < 0) || !res_hnok(bp)) { 366 if ((n < 0) || !maybe_hnok(res, bp)) {
353 had_error++; 367 had_error++;
354 break; 368 break;
355 } 369 }
356#if MULTI_PTRS_ARE_ALIASES 370#if MULTI_PTRS_ARE_ALIASES
357 cp += n; 371 cp += n;
358 if (cp != erdata) { 372 if (cp != erdata)
359 h_errno = NO_RECOVERY; 373 goto no_recovery;
360 return NULL;
361 }
362 if (!haveanswer) 374 if (!haveanswer)
363 rs->host.h_name = bp; 375 hent->h_name = bp;
364 else if (ap < &rs->host_aliases[MAXALIASES-1])
365 *ap++ = bp;
366 else 376 else
367 n = -1; 377 addalias(ap, bp, aliases, maxaliases);
368 if (n != -1) { 378 if (n != -1) {
369 n = strlen(bp) + 1; /* for the \0 */ 379 n = (int)strlen(bp) + 1; /* for the \0 */
370 if (n >= MAXHOSTNAMELEN) { 380 if (n >= MAXHOSTNAMELEN) {
371 had_error++; 381 had_error++;
372 break; 382 break;
@@ -375,7 +385,7 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
375 } 385 }
376 break; 386 break;
377#else 387#else
378 rs->host.h_name = bp; 388 hent->h_name = bp;
379 if (res->options & RES_USE_INET6) { 389 if (res->options & RES_USE_INET6) {
380 n = strlen(bp) + 1; /* for the \0 */ 390 n = strlen(bp) + 1; /* for the \0 */
381 if (n >= MAXHOSTNAMELEN) { 391 if (n >= MAXHOSTNAMELEN) {
@@ -383,26 +393,25 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
383 break; 393 break;
384 } 394 }
385 bp += n; 395 bp += n;
386 map_v4v6_hostent(&rs->host, &bp, ep); 396 map_v4v6_hostent(hent, &bp, ep);
387 } 397 }
388 h_errno = NETDB_SUCCESS; 398 goto success;
389 return &rs->host;
390#endif 399#endif
391 case T_A: 400 case T_A:
392 case T_AAAA: 401 case T_AAAA:
393 if (strcasecmp(rs->host.h_name, bp) != 0) { 402 if (strcasecmp(hent->h_name, bp) != 0) {
394 syslog(LOG_NOTICE|LOG_AUTH, 403 syslog(LOG_NOTICE|LOG_AUTH,
395 AskedForGot, rs->host.h_name, bp); 404 AskedForGot, hent->h_name, bp);
396 cp += n; 405 cp += n;
397 continue; /* XXX - had_error++ ? */ 406 continue; /* XXX - had_error++ ? */
398 } 407 }
399 if (n != rs->host.h_length) { 408 if (n != hent->h_length) {
400 cp += n; 409 cp += n;
401 continue; 410 continue;
402 } 411 }
403 if (type == T_AAAA) { 412 if (type == T_AAAA) {
404 struct in6_addr in6; 413 struct in6_addr in6;
405 memcpy(&in6, cp, IN6ADDRSZ); 414 memcpy(&in6, cp, NS_IN6ADDRSZ);
406 if (IN6_IS_ADDR_V4MAPPED(&in6)) { 415 if (IN6_IS_ADDR_V4MAPPED(&in6)) {
407 cp += n; 416 cp += n;
408 continue; 417 continue;
@@ -411,33 +420,32 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
411 if (!haveanswer) { 420 if (!haveanswer) {
412 int nn; 421 int nn;
413 422
414 rs->host.h_name = bp; 423 hent->h_name = bp;
415 nn = strlen(bp) + 1; /* for the \0 */ 424 nn = (int)strlen(bp) + 1; /* for the \0 */
416 bp += nn; 425 bp += nn;
417 } 426 }
418 427
419 bp += sizeof(align) - 428 bp += sizeof(align) -
420 (size_t)((u_long)bp % sizeof(align)); 429 (size_t)((u_long)bp % sizeof(align));
421 430
422 if (bp + n >= &rs->hostbuf[sizeof rs->hostbuf]) { 431 if (bp + n >= ep) {
423 dprintf("size (%d) too big\n", res, n); 432 debugprintf("size (%d) too big\n", res, n);
424 had_error++; 433 had_error++;
425 continue; 434 continue;
426 } 435 }
427 if (hap >= &rs->h_addr_ptrs[MAXADDRS-1]) { 436 if (hap >= &addr_ptrs[MAXADDRS - 1]) {
428 if (!toobig++) 437 if (!toobig++) {
429 dprintf("Too many addresses (%d)\n", 438 debugprintf("Too many addresses (%d)\n",
430 res, MAXADDRS); 439 res, MAXADDRS);
440 }
431 cp += n; 441 cp += n;
432 continue; 442 continue;
433 } 443 }
434 (void)memcpy(*hap++ = bp, cp, (size_t)n); 444 (void)memcpy(*hap++ = bp, cp, (size_t)n);
435 bp += n; 445 bp += n;
436 cp += n; 446 cp += n;
437 if (cp != erdata) { 447 if (cp != erdata)
438 h_errno = NO_RECOVERY; 448 goto no_recovery;
439 return NULL;
440 }
441 break; 449 break;
442 default: 450 default:
443 abort(); 451 abort();
@@ -454,83 +462,103 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
454 * address in that case, not some random one 462 * address in that case, not some random one
455 */ 463 */
456 if (res->nsort && haveanswer > 1 && qtype == T_A) 464 if (res->nsort && haveanswer > 1 && qtype == T_A)
457 addrsort(rs->h_addr_ptrs, haveanswer, res); 465 addrsort(addr_ptrs, haveanswer, res);
458 if (!rs->host.h_name) { 466 if (!hent->h_name) {
459 n = strlen(qname) + 1; /* for the \0 */ 467 n = (int)strlen(qname) + 1; /* for the \0 */
460 if (n > ep - bp || n >= MAXHOSTNAMELEN) 468 if (n > ep - bp || n >= MAXHOSTNAMELEN)
461 goto no_recovery; 469 goto no_recovery;
462 strlcpy(bp, qname, (size_t)(ep - bp)); 470 strlcpy(bp, qname, (size_t)(ep - bp));
463 rs->host.h_name = bp; 471 hent->h_name = bp;
464 bp += n; 472 bp += n;
465 } 473 }
466 if (res->options & RES_USE_INET6) 474 if (res->options & RES_USE_INET6)
467 map_v4v6_hostent(&rs->host, &bp, ep); 475 map_v4v6_hostent(hent, &bp, ep);
468 h_errno = NETDB_SUCCESS; 476 goto success;
469 return &rs->host;
470 } 477 }
471 no_recovery: 478no_recovery:
472 h_errno = NO_RECOVERY; 479 free(aliases);
480 *he = NO_RECOVERY;
481 return NULL;
482success:
483 bp = (char *)ALIGN(bp);
484 n = (int)(ap - aliases);
485 qlen = (n + 1) * sizeof(*hent->h_aliases);
486 if ((size_t)(ep - bp) < qlen)
487 goto nospc;
488 hent->h_aliases = (void *)bp;
489 memcpy(bp, aliases, qlen);
490 free(aliases);
491 aliases = NULL;
492
493 bp += qlen;
494 n = (int)(hap - addr_ptrs);
495 qlen = (n + 1) * sizeof(*hent->h_addr_list);
496 if ((size_t)(ep - bp) < qlen)
497 goto nospc;
498 hent->h_addr_list = (void *)bp;
499 memcpy(bp, addr_ptrs, qlen);
500 *he = NETDB_SUCCESS;
501 return hent;
502nospc:
503 free(aliases);
504 errno = ENOSPC;
505 *he = NETDB_INTERNAL;
473 return NULL; 506 return NULL;
474} 507}
475 508
509/* The prototype of gethostbyname_r is from glibc, not that in netbsd. */
476int 510int
477gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen, 511gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen,
478 struct hostent**result, int *errorp) 512 struct hostent **result, int *errorp)
479{
480 struct hostent *res;
481
482 res = gethostbyname(name);
483 *errorp = h_errno;
484 if (res == NULL) {
485 *result = NULL;
486 return -1;
487 }
488 memcpy(hp, res, sizeof *hp);
489 *result = hp;
490 return 0;
491}
492
493struct hostent *
494gethostbyname(const char *name)
495{ 513{
496 struct hostent *hp;
497 res_state res = __res_get_state(); 514 res_state res = __res_get_state();
498 515
499 if (res == NULL) 516 if (res == NULL) {
500 return NULL; 517 *result = NULL;
518 *errorp = NETDB_INTERNAL;
519 return -1;
520 }
501 521
502 assert(name != NULL); 522 _DIAGASSERT(name != NULL);
503 523
504 /* try IPv6 first - if that fails do IPv4 */
505 if (res->options & RES_USE_INET6) { 524 if (res->options & RES_USE_INET6) {
506 hp = gethostbyname_internal(name, AF_INET6, res, NETID_UNSET, MARK_UNSET); 525 *result = gethostbyname_internal(name, AF_INET6, res, hp, buf, buflen, errorp, NETID_UNSET,
507 if (hp) { 526 MARK_UNSET);
527 if (*result) {
508 __res_put_state(res); 528 __res_put_state(res);
509 return hp; 529 return 0;
510 } 530 }
511 } 531 }
512 hp = gethostbyname_internal(name, AF_INET, res, NETID_UNSET, MARK_UNSET); 532 *result = gethostbyname_internal(name, AF_INET, res, hp, buf, buflen, errorp, NETID_UNSET,
533 MARK_UNSET);
513 __res_put_state(res); 534 __res_put_state(res);
514 return hp; 535 if (!*result && errno == ENOSPC) {
515} 536 errno = ERANGE;
516 537 return ERANGE; /* Return error as in linux manual page. */
517struct hostent * 538 }
518gethostbyname2(const char *name, int af) 539 return (*result) ? 0 : -1;
519{
520 return android_gethostbynamefornet(name, af, NETID_UNSET, MARK_UNSET);
521} 540}
522 541
523struct hostent * 542/* The prototype of gethostbyname2_r is from glibc, not that in netbsd. */
524android_gethostbynamefornet(const char *name, int af, unsigned netid, unsigned mark) 543int
544gethostbyname2_r(const char *name, int af, struct hostent *hp, char *buf,
545 size_t buflen, struct hostent **result, int *errorp)
525{ 546{
526 struct hostent *hp;
527 res_state res = __res_get_state(); 547 res_state res = __res_get_state();
528 548
529 if (res == NULL) 549 if (res == NULL) {
530 return NULL; 550 *result = NULL;
531 hp = gethostbyname_internal(name, af, res, netid, mark); 551 *errorp = NETDB_INTERNAL;
552 return -1;
553 }
554 *result = gethostbyname_internal(name, af, res, hp, buf, buflen, errorp, NETID_UNSET,
555 MARK_UNSET);
532 __res_put_state(res); 556 __res_put_state(res);
533 return hp; 557 if (!*result && errno == ENOSPC) {
558 errno = ERANGE;
559 return ERANGE;
560 }
561 return (*result) ? 0 : -1;
534} 562}
535 563
536__LIBC_HIDDEN__ FILE* android_open_proxy() { 564__LIBC_HIDDEN__ FILE* android_open_proxy() {
@@ -562,7 +590,7 @@ __LIBC_HIDDEN__ FILE* android_open_proxy() {
562} 590}
563 591
564static struct hostent * 592static struct hostent *
565android_read_hostent(FILE* proxy) 593android_read_hostent(FILE* proxy, struct hostent* hp, char* hbuf, size_t hbuflen, int *he)
566{ 594{
567 uint32_t size; 595 uint32_t size;
568 char buf[4]; 596 char buf[4];
@@ -573,21 +601,27 @@ android_read_hostent(FILE* proxy)
573 int result_code = strtol(buf, NULL, 10); 601 int result_code = strtol(buf, NULL, 10);
574 if (result_code != DnsProxyQueryResult) { 602 if (result_code != DnsProxyQueryResult) {
575 fread(&size, 1, sizeof(size), proxy); 603 fread(&size, 1, sizeof(size), proxy);
604 *he = HOST_NOT_FOUND;
576 return NULL; 605 return NULL;
577 } 606 }
578 607
579 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL; 608 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
580 size = ntohl(size); 609 size = ntohl(size);
581 res_static rs = __res_get_static();
582 memset(&rs->host, 0, sizeof(rs->host));
583 char *ptr = rs->hostbuf;
584 610
611 memset(hp, 0, sizeof(*hp));
612 char *ptr = hbuf;
613 char *hbuf_end = hbuf + hbuflen;
614
615 if (ptr + size > hbuf_end) {
616 goto nospc;
617 }
585 if (fread(ptr, 1, size, proxy) != size) return NULL; 618 if (fread(ptr, 1, size, proxy) != size) return NULL;
619 hp->h_name = ptr;
586 ptr += size; 620 ptr += size;
587 rs->host.h_name = rs->hostbuf;
588 621
589 char **aliases = rs->host_aliases; 622 char *aliases_ptrs[MAXALIASES];
590 rs->host.h_aliases = rs->host_aliases; 623 char **aliases = &aliases_ptrs[0];
624
591 while (1) { 625 while (1) {
592 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL; 626 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
593 size = ntohl(size); 627 size = ntohl(size);
@@ -596,74 +630,107 @@ android_read_hostent(FILE* proxy)
596 *aliases = NULL; 630 *aliases = NULL;
597 break; 631 break;
598 } 632 }
633 if (ptr + size > hbuf_end) {
634 goto nospc;
635 }
599 if (fread(ptr, 1, size, proxy) != size) return NULL; 636 if (fread(ptr, 1, size, proxy) != size) return NULL;
600 *aliases++ = ptr; 637 if (aliases < &aliases_ptrs[MAXALIASES - 1]) {
638 *aliases++ = ptr;
639 }
601 ptr += size; 640 ptr += size;
602 } 641 }
603 642
643 int aliases_len = ((int)(aliases - aliases_ptrs) + 1) * sizeof(*hp->h_aliases);
644 if (ptr + aliases_len > hbuf_end) {
645 goto nospc;
646 }
647 hp->h_aliases = (void*)ptr;
648 memcpy(ptr, aliases_ptrs, aliases_len);
649 ptr += aliases_len;
650
604 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL; 651 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
605 rs->host.h_addrtype = ntohl(size); 652 hp->h_addrtype = ntohl(size);
606 653
607 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL; 654 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
608 rs->host.h_length = ntohl(size); 655 hp->h_length = ntohl(size);
656
657 char *addr_ptrs[MAXADDRS];
658 char **addr_p = &addr_ptrs[0];
609 659
610 char **addrs = rs->h_addr_ptrs;
611 rs->host.h_addr_list = rs->h_addr_ptrs;
612 while (1) { 660 while (1) {
613 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL; 661 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
614 size = ntohl(size); 662 size = ntohl(size);
615 if (size == 0) { 663 if (size == 0) {
616 *addrs = NULL; 664 *addr_p = NULL;
617 break; 665 break;
618 } 666 }
667 if (ptr + size > hbuf_end) {
668 goto nospc;
669 }
619 if (fread(ptr, 1, size, proxy) != size) return NULL; 670 if (fread(ptr, 1, size, proxy) != size) return NULL;
620 *addrs++ = ptr; 671 if (addr_p < &addr_ptrs[MAXADDRS - 1]) {
672 *addr_p++ = ptr;
673 }
621 ptr += size; 674 ptr += size;
622 } 675 }
623 676
624 return &rs->host; 677 int addrs_len = ((int)(addr_p - addr_ptrs) + 1) * sizeof(*hp->h_addr_list);
625} 678 if (ptr + addrs_len > hbuf_end) {
679 goto nospc;
680 }
681 hp->h_addr_list = (void*)ptr;
682 memcpy(ptr, addr_ptrs, addrs_len);
683 *he = NETDB_SUCCESS;
684 return hp;
626 685
686nospc:
687 *he = NETDB_INTERNAL;
688 errno = ENOSPC;
689 return NULL;
690}
627 691
628static struct hostent * 692static struct hostent *
629gethostbyname_internal_real(const char *name, int af, res_state res) 693gethostbyname_internal_real(const char *name, int af, res_state res, struct hostent *hp, char *buf,
694 size_t buflen, int *he)
630{ 695{
631 const char *cp; 696 const char *cp;
632 char *bp, *ep; 697 struct getnamaddr info;
633 int size; 698 char hbuf[MAXHOSTNAMELEN];
634 struct hostent *hp; 699 size_t size;
635 res_static rs = __res_get_static();
636
637 static const ns_dtab dtab[] = { 700 static const ns_dtab dtab[] = {
638 NS_FILES_CB(_gethtbyname, NULL) 701 NS_FILES_CB(_hf_gethtbyname, NULL)
639 { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */ 702 { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */
640 { 0, 0, 0 } 703 NS_NIS_CB(_yp_gethtbyname, NULL)
704 NS_NULL_CB
641 }; 705 };
642 706
643 assert(name != NULL); 707 _DIAGASSERT(name != NULL);
644 708
645 switch (af) { 709 switch (af) {
646 case AF_INET: 710 case AF_INET:
647 size = INADDRSZ; 711 size = NS_INADDRSZ;
648 break; 712 break;
649 case AF_INET6: 713 case AF_INET6:
650 size = IN6ADDRSZ; 714 size = NS_IN6ADDRSZ;
651 break; 715 break;
652 default: 716 default:
653 h_errno = NETDB_INTERNAL; 717 *he = NETDB_INTERNAL;
654 errno = EAFNOSUPPORT; 718 errno = EAFNOSUPPORT;
655 return NULL; 719 return NULL;
656 } 720 }
721 if (buflen < size)
722 goto nospc;
657 723
658 rs->host.h_addrtype = af; 724 hp->h_addrtype = af;
659 rs->host.h_length = size; 725 hp->h_length = (int)size;
660 726
661 /* 727 /*
662 * if there aren't any dots, it could be a user-level alias. 728 * if there aren't any dots, it could be a user-level alias.
663 * this is also done in res_nquery() since we are not the only 729 * this is also done in res_nquery() since we are not the only
664 * function that looks up host names. 730 * function that looks up host names.
665 */ 731 */
666 if (!strchr(name, '.') && (cp = __hostalias(name))) 732 if (!strchr(name, '.') && (cp = res_hostalias(res, name,
733 hbuf, sizeof(hbuf))))
667 name = cp; 734 name = cp;
668 735
669 /* 736 /*
@@ -680,25 +747,7 @@ gethostbyname_internal_real(const char *name, int af, res_state res)
680 * Fake up a hostent as if we'd actually 747 * Fake up a hostent as if we'd actually
681 * done a lookup. 748 * done a lookup.
682 */ 749 */
683 if (inet_pton(af, name, 750 goto fake;
684 (char *)(void *)rs->host_addr) <= 0) {
685 h_errno = HOST_NOT_FOUND;
686 return NULL;
687 }
688 strncpy(rs->hostbuf, name, MAXDNAME);
689 rs->hostbuf[MAXDNAME] = '\0';
690 bp = rs->hostbuf + MAXDNAME;
691 ep = rs->hostbuf + sizeof rs->hostbuf;
692 rs->host.h_name = rs->hostbuf;
693 rs->host.h_aliases = rs->host_aliases;
694 rs->host_aliases[0] = NULL;
695 rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
696 rs->h_addr_ptrs[1] = NULL;
697 rs->host.h_addr_list = rs->h_addr_ptrs;
698 if (res->options & RES_USE_INET6)
699 map_v4v6_hostent(&rs->host, &bp, ep);
700 h_errno = NETDB_SUCCESS;
701 return &rs->host;
702 } 751 }
703 if (!isdigit((u_char) *cp) && *cp != '.') 752 if (!isdigit((u_char) *cp) && *cp != '.')
704 break; 753 break;
@@ -714,49 +763,60 @@ gethostbyname_internal_real(const char *name, int af, res_state res)
714 * Fake up a hostent as if we'd actually 763 * Fake up a hostent as if we'd actually
715 * done a lookup. 764 * done a lookup.
716 */ 765 */
717 if (inet_pton(af, name, 766 goto fake;
718 (char *)(void *)rs->host_addr) <= 0) {
719 h_errno = HOST_NOT_FOUND;
720 return NULL;
721 }
722 strncpy(rs->hostbuf, name, MAXDNAME);
723 rs->hostbuf[MAXDNAME] = '\0';
724 bp = rs->hostbuf + MAXDNAME;
725 ep = rs->hostbuf + sizeof rs->hostbuf;
726 rs->host.h_name = rs->hostbuf;
727 rs->host.h_aliases = rs->host_aliases;
728 rs->host_aliases[0] = NULL;
729 rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
730 rs->h_addr_ptrs[1] = NULL;
731 rs->host.h_addr_list = rs->h_addr_ptrs;
732 h_errno = NETDB_SUCCESS;
733 return &rs->host;
734 } 767 }
735 if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.') 768 if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.')
736 break; 769 break;
737 } 770 }
738 771
739 hp = NULL; 772 *he = NETDB_INTERNAL;
740 h_errno = NETDB_INTERNAL; 773 info.hp = hp;
741 if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname", 774 info.buf = buf;
742 default_dns_files, name, strlen(name), af) != NS_SUCCESS) { 775 info.buflen = buflen;
776 info.he = he;
777 if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyname",
778 default_dns_files, name, strlen(name), af) != NS_SUCCESS)
779 return NULL;
780 *he = NETDB_SUCCESS;
781 return hp;
782nospc:
783 *he = NETDB_INTERNAL;
784 errno = ENOSPC;
785 return NULL;
786fake:
787 HENT_ARRAY(hp->h_addr_list, 1, buf, buflen);
788 HENT_ARRAY(hp->h_aliases, 0, buf, buflen);
789
790 hp->h_aliases[0] = NULL;
791 if (size > buflen)
792 goto nospc;
793
794 if (inet_pton(af, name, buf) <= 0) {
795 *he = HOST_NOT_FOUND;
743 return NULL; 796 return NULL;
744 } 797 }
745 h_errno = NETDB_SUCCESS; 798 hp->h_addr_list[0] = buf;
799 hp->h_addr_list[1] = NULL;
800 buf += size;
801 buflen -= size;
802 HENT_SCOPY(hp->h_name, name, buf, buflen);
803 if (res->options & RES_USE_INET6)
804 map_v4v6_hostent(hp, &buf, buf + buflen);
805 *he = NETDB_SUCCESS;
746 return hp; 806 return hp;
747} 807}
748 808
749
750// very similar in proxy-ness to android_getaddrinfo_proxy 809// very similar in proxy-ness to android_getaddrinfo_proxy
751static struct hostent * 810static struct hostent *
752gethostbyname_internal(const char *name, int af, res_state res, unsigned netid, unsigned mark) 811gethostbyname_internal(const char *name, int af, res_state res, struct hostent *hp, char *hbuf,
812 size_t hbuflen, int *errorp, unsigned netid, unsigned mark)
753{ 813{
754 FILE* proxy = android_open_proxy(); 814 FILE* proxy = android_open_proxy();
755 if (proxy == NULL) { 815 if (proxy == NULL) {
756 // Either we're not supposed to be using the proxy or the proxy is unavailable. 816 // Either we're not supposed to be using the proxy or the proxy is unavailable.
757 res_setnetid(res, netid); 817 res_setnetid(res, netid);
758 res_setmark(res, mark); 818 res_setmark(res, mark);
759 return gethostbyname_internal_real(name, af, res); 819 return gethostbyname_internal_real(name, af, res, hp, hbuf, hbuflen, errorp);
760 } 820 }
761 821
762 netid = __netdClientDispatch.netIdForResolv(netid); 822 netid = __netdClientDispatch.netIdForResolv(netid);
@@ -776,29 +836,44 @@ gethostbyname_internal(const char *name, int af, res_state res, unsigned netid,
776 return NULL; 836 return NULL;
777 } 837 }
778 838
779 struct hostent* result = android_read_hostent(proxy); 839 struct hostent* result = android_read_hostent(proxy, hp, hbuf, hbuflen, errorp);
780 fclose(proxy); 840 fclose(proxy);
781 return result; 841 return result;
782} 842}
783 843
844/* The prototype of gethostbyaddr_r is from glibc, not that in netbsd. */
845int gethostbyaddr_r(const void *addr, socklen_t len, int af, struct hostent *hp, char *buf,
846 size_t buflen, struct hostent **result, int *h_errnop)
847{
848 *result = android_gethostbyaddrfornet_proxy_internal(addr, len, af, hp, buf, buflen, h_errnop,
849 NETID_UNSET, MARK_UNSET);
850 if (!*result && errno == ENOSPC) {
851 errno = ERANGE;
852 return ERANGE;
853 }
854 return (*result) ? 0 : -1;
855}
784 856
785static struct hostent * 857static struct hostent *
786android_gethostbyaddrfornet_real(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark) { 858android_gethostbyaddrfornet_real(const void *addr, socklen_t len, int af, struct hostent *hp,
859 char *buf, size_t buflen, int *he, unsigned netid, unsigned mark)
860{
787 const u_char *uaddr = (const u_char *)addr; 861 const u_char *uaddr = (const u_char *)addr;
788 socklen_t size; 862 socklen_t size;
789 struct hostent *hp; 863 struct getnamaddr info;
790 static const ns_dtab dtab[] = { 864 static const ns_dtab dtab[] = {
791 NS_FILES_CB(_gethtbyaddr, NULL) 865 NS_FILES_CB(_hf_gethtbyaddr, NULL)
792 { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */ 866 { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */
793 { 0, 0, 0 } 867 NS_NIS_CB(_yp_gethtbyaddr, NULL)
868 NS_NULL_CB
794 }; 869 };
795 870
796 assert(addr != NULL); 871 _DIAGASSERT(addr != NULL);
797 872
798 if (af == AF_INET6 && len == NS_IN6ADDRSZ && 873 if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
799 (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr) || 874 (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr) ||
800 IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)addr))) { 875 IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)addr))) {
801 h_errno = HOST_NOT_FOUND; 876 *he = HOST_NOT_FOUND;
802 return NULL; 877 return NULL;
803 } 878 }
804 if (af == AF_INET6 && len == NS_IN6ADDRSZ && 879 if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
@@ -819,29 +894,35 @@ android_gethostbyaddrfornet_real(const void *addr, socklen_t len, int af, unsign
819 break; 894 break;
820 default: 895 default:
821 errno = EAFNOSUPPORT; 896 errno = EAFNOSUPPORT;
822 h_errno = NETDB_INTERNAL; 897 *he = NETDB_INTERNAL;
823 return NULL; 898 return NULL;
824 } 899 }
825 if (size != len) { 900 if (size != len) {
826 errno = EINVAL; 901 errno = EINVAL;
827 h_errno = NETDB_INTERNAL; 902 *he = NETDB_INTERNAL;
828 return NULL; 903 return NULL;
829 } 904 }
830 hp = NULL; 905 info.hp = hp;
831 h_errno = NETDB_INTERNAL; 906 info.buf = buf;
832 if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr", 907 info.buflen = buflen;
833 default_dns_files, uaddr, len, af, netid, mark) != NS_SUCCESS) 908 info.he = he;
909 *he = NETDB_INTERNAL;
910 if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyaddr",
911 default_dns_files, uaddr, len, af, netid, mark) != NS_SUCCESS)
834 return NULL; 912 return NULL;
835 h_errno = NETDB_SUCCESS; 913 *he = NETDB_SUCCESS;
836 return hp; 914 return hp;
837} 915}
838 916
839__LIBC_HIDDEN__ struct hostent* 917static struct hostent*
840android_gethostbyaddrfornet_proxy(const void* addr, socklen_t len, int af, unsigned netid, unsigned mark) { 918android_gethostbyaddrfornet_proxy_internal(const void* addr, socklen_t len, int af,
919 struct hostent *hp, char *hbuf, size_t hbuflen, int *he,
920 unsigned netid, unsigned mark)
921{
841 FILE* proxy = android_open_proxy(); 922 FILE* proxy = android_open_proxy();
842 if (proxy == NULL) { 923 if (proxy == NULL) {
843 // Either we're not supposed to be using the proxy or the proxy is unavailable. 924 // Either we're not supposed to be using the proxy or the proxy is unavailable.
844 return android_gethostbyaddrfornet_real(addr,len, af, netid, mark); 925 return android_gethostbyaddrfornet_real(addr,len, af, hp, hbuf, hbuflen, he, netid, mark);
845 } 926 }
846 927
847 char buf[INET6_ADDRSTRLEN]; //big enough for IPv4 and IPv6 928 char buf[INET6_ADDRSTRLEN]; //big enough for IPv4 and IPv6
@@ -864,302 +945,144 @@ android_gethostbyaddrfornet_proxy(const void* addr, socklen_t len, int af, unsig
864 return NULL; 945 return NULL;
865 } 946 }
866 947
867 struct hostent *result = android_read_hostent(proxy); 948 struct hostent *result = android_read_hostent(proxy, hp, hbuf, hbuflen, he);
868 fclose(proxy); 949 fclose(proxy);
869 return result; 950 return result;
870} 951}
871 952
872struct hostent * 953struct hostent*
873android_gethostbyaddrfornet(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark) 954netbsd_gethostent_r(FILE *hf, struct hostent *hent, char *buf, size_t buflen, int *he)
874{ 955{
875 return android_gethostbyaddrfornet_proxy(addr, len, af, netid, mark); 956 char *p, *name;
876}
877
878struct hostent *
879gethostbyaddr(const void *addr, socklen_t len, int af)
880{
881 return android_gethostbyaddrfornet(addr, len, af, NETID_UNSET, MARK_UNSET);
882}
883
884
885static void
886_sethtent(int f)
887{
888 res_static rs = __res_get_static();
889 if (rs == NULL) return;
890 if (!rs->hostf)
891 rs->hostf = fopen(_PATH_HOSTS, "re" );
892 else
893 rewind(rs->hostf);
894 rs->stayopen = f;
895}
896
897static void
898_endhtent(void)
899{
900 res_static rs = __res_get_static();
901 if (rs == NULL) return;
902
903 if (rs->hostf && !rs->stayopen) {
904 (void) fclose(rs->hostf);
905 rs->hostf = NULL;
906 }
907}
908
909static struct hostent *
910_gethtent(void)
911{
912 char *p;
913 char *cp, **q; 957 char *cp, **q;
914 int af, len; 958 int af, len;
915 res_static rs = __res_get_static(); 959 size_t anum;
960 char **aliases;
961 size_t maxaliases;
962 struct in6_addr host_addr;
916 963
917 if (!rs->hostf && !(rs->hostf = fopen(_PATH_HOSTS, "re" ))) { 964 if (hf == NULL) {
918 h_errno = NETDB_INTERNAL; 965 *he = NETDB_INTERNAL;
966 errno = EINVAL;
919 return NULL; 967 return NULL;
920 } 968 }
921 again: 969 p = NULL;
922 if (!(p = fgets(rs->hostbuf, sizeof rs->hostbuf, rs->hostf))) { 970 setup(aliases, maxaliases);
923 h_errno = HOST_NOT_FOUND; 971
924 return NULL; 972 /* Allocate a new space to read file lines like upstream does.
973 * To keep reentrancy we cannot use __res_get_static()->hostbuf here,
974 * as the buffer may be used to store content for a previous hostent
975 * returned by non-reentrant functions like gethostbyname().
976 */
977 const size_t line_buf_size = sizeof(__res_get_static()->hostbuf);
978 if ((p = malloc(line_buf_size)) == NULL) {
979 goto nospc;
925 } 980 }
926 if (*p == '#') 981 for (;;) {
927 goto again; 982 if (!fgets(p, line_buf_size, hf)) {
928 if (!(cp = strpbrk(p, "#\n"))) 983 free(p);
929 goto again; 984 free(aliases);
930 *cp = '\0'; 985 *he = HOST_NOT_FOUND;
931 if (!(cp = strpbrk(p, " \t")))
932 goto again;
933 *cp++ = '\0';
934 if (inet_pton(AF_INET6, p, (char *)(void *)rs->host_addr) > 0) {
935 af = AF_INET6;
936 len = IN6ADDRSZ;
937 } else if (inet_pton(AF_INET, p, (char *)(void *)rs->host_addr) > 0) {
938 res_state res = __res_get_state();
939 if (res == NULL)
940 return NULL; 986 return NULL;
941 if (res->options & RES_USE_INET6) { 987 }
942 map_v4v6_address((char *)(void *)rs->host_addr, 988 if (*p == '#') {
943 (char *)(void *)rs->host_addr);
944 af = AF_INET6;
945 len = IN6ADDRSZ;
946 } else {
947 af = AF_INET;
948 len = INADDRSZ;
949 }
950 __res_put_state(res);
951 } else {
952 goto again;
953 }
954 /* if this is not something we're looking for, skip it. */
955 if (rs->host.h_addrtype != 0 && rs->host.h_addrtype != af)
956 goto again;
957 if (rs->host.h_length != 0 && rs->host.h_length != len)
958 goto again;
959 rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
960 rs->h_addr_ptrs[1] = NULL;
961 rs->host.h_addr_list = rs->h_addr_ptrs;
962 rs->host.h_length = len;
963 rs->host.h_addrtype = af;
964 while (*cp == ' ' || *cp == '\t')
965 cp++;
966 rs->host.h_name = cp;
967 q = rs->host.h_aliases = rs->host_aliases;
968 if ((cp = strpbrk(cp, " \t")) != NULL)
969 *cp++ = '\0';
970 while (cp && *cp) {
971 if (*cp == ' ' || *cp == '\t') {
972 cp++;
973 continue; 989 continue;
974 } 990 }
975 if (q < &rs->host_aliases[MAXALIASES - 1]) 991 if (!(cp = strpbrk(p, "#\n"))) {
976 *q++ = cp;
977 if ((cp = strpbrk(cp, " \t")) != NULL)
978 *cp++ = '\0';
979 }
980 *q = NULL;
981 h_errno = NETDB_SUCCESS;
982 return &rs->host;
983}
984
985/*ARGSUSED*/
986int
987_gethtbyname(void *rv, void *cb_data, va_list ap)
988{
989 struct hostent *hp;
990 const char *name;
991 int af;
992
993 assert(rv != NULL);
994
995 name = va_arg(ap, char *);
996 /* NOSTRICT skip len */(void)va_arg(ap, int);
997 af = va_arg(ap, int);
998
999 hp = NULL;
1000#if 0
1001 {
1002 res_state res = __res_get_state();
1003 if (res == NULL)
1004 return NS_NOTFOUND;
1005 if (res->options & RES_USE_INET6)
1006 hp = _gethtbyname2(name, AF_INET6);
1007 if (hp==NULL)
1008 hp = _gethtbyname2(name, AF_INET);
1009 __res_put_state(res);
1010 }
1011#else
1012 hp = _gethtbyname2(name, af);
1013#endif
1014 *((struct hostent **)rv) = hp;
1015 if (hp == NULL) {
1016 h_errno = HOST_NOT_FOUND;
1017 return NS_NOTFOUND;
1018 }
1019 return NS_SUCCESS;
1020}
1021
1022static struct hostent *
1023_gethtbyname2(const char *name, int af)
1024{
1025 struct hostent *p;
1026 char *tmpbuf, *ptr, **cp;
1027 int num;
1028 size_t len;
1029 res_static rs = __res_get_static();
1030
1031 assert(name != NULL);
1032
1033 _sethtent(rs->stayopen);
1034 ptr = tmpbuf = NULL;
1035 num = 0;
1036 while ((p = _gethtent()) != NULL && num < MAXADDRS) {
1037 if (p->h_addrtype != af)
1038 continue; 992 continue;
1039 if (strcasecmp(p->h_name, name) != 0) {
1040 for (cp = p->h_aliases; *cp != NULL; cp++)
1041 if (strcasecmp(*cp, name) == 0)
1042 break;
1043 if (*cp == NULL) continue;
1044 } 993 }
994 *cp = '\0';
995 if (!(cp = strpbrk(p, " \t")))
996 continue;
997 *cp++ = '\0';
998 if (inet_pton(AF_INET6, p, &host_addr) > 0) {
999 af = AF_INET6;
1000 len = NS_IN6ADDRSZ;
1001 } else {
1002 if (inet_pton(AF_INET, p, &host_addr) <= 0)
1003 continue;
1045 1004
1046 if (num == 0) { 1005 res_state res = __res_get_state();
1047 size_t bufsize; 1006 if (res == NULL)
1048 char *src; 1007 goto nospc;
1049 1008 if (res->options & RES_USE_INET6) {
1050 bufsize = strlen(p->h_name) + 2 + 1009 map_v4v6_address(buf, buf);
1051 MAXADDRS * p->h_length + 1010 af = AF_INET6;
1052 ALIGNBYTES; 1011 len = NS_IN6ADDRSZ;
1053 for (cp = p->h_aliases; *cp != NULL; cp++) 1012 } else {
1054 bufsize += strlen(*cp) + 1; 1013 af = AF_INET;
1055 1014 len = NS_INADDRSZ;
1056 if ((tmpbuf = malloc(bufsize)) == NULL) {
1057 h_errno = NETDB_INTERNAL;
1058 return NULL;
1059 }
1060
1061 ptr = tmpbuf;
1062 src = p->h_name;
1063 while ((*ptr++ = *src++) != '\0');
1064 for (cp = p->h_aliases; *cp != NULL; cp++) {
1065 src = *cp;
1066 while ((*ptr++ = *src++) != '\0');
1067 } 1015 }
1068 *ptr++ = '\0'; 1016 __res_put_state(res);
1069
1070 ptr = (char *)(void *)ALIGN(ptr);
1071 } 1017 }
1072 1018
1073 (void)memcpy(ptr, p->h_addr_list[0], (size_t)p->h_length); 1019 /* if this is not something we're looking for, skip it. */
1074 ptr += p->h_length; 1020 if (hent->h_addrtype != 0 && hent->h_addrtype != af)
1075 num++; 1021 continue;
1076 } 1022 if (hent->h_length != 0 && hent->h_length != len)
1077 _endhtent(); 1023 continue;
1078 if (num == 0) return NULL;
1079
1080 len = ptr - tmpbuf;
1081 if (len > (sizeof(rs->hostbuf) - ALIGNBYTES)) {
1082 free(tmpbuf);
1083 errno = ENOSPC;
1084 h_errno = NETDB_INTERNAL;
1085 return NULL;
1086 }
1087 ptr = memcpy((void *)ALIGN(rs->hostbuf), tmpbuf, len);
1088 free(tmpbuf);
1089
1090 rs->host.h_name = ptr;
1091 while (*ptr++);
1092
1093 cp = rs->host_aliases;
1094 while (*ptr) {
1095 *cp++ = ptr;
1096 while (*ptr++);
1097 }
1098 ptr++;
1099 *cp = NULL;
1100
1101 ptr = (char *)(void *)ALIGN(ptr);
1102 cp = rs->h_addr_ptrs;
1103 while (num--) {
1104 *cp++ = ptr;
1105 ptr += rs->host.h_length;
1106 }
1107 *cp = NULL;
1108
1109 return &rs->host;
1110}
1111
1112/*ARGSUSED*/
1113static int
1114_gethtbyaddr(void *rv, void *cb_data, va_list ap)
1115{
1116 struct hostent *p;
1117 const unsigned char *addr;
1118 int len, af;
1119 res_static rs = __res_get_static();
1120
1121 assert(rv != NULL);
1122
1123 addr = va_arg(ap, unsigned char *);
1124 len = va_arg(ap, int);
1125 af = va_arg(ap, int);
1126
1127 rs->host.h_length = len;
1128 rs->host.h_addrtype = af;
1129 1024
1130 _sethtent(rs->stayopen); 1025 while (*cp == ' ' || *cp == '\t')
1131 while ((p = _gethtent()) != NULL) 1026 cp++;
1132 if (p->h_addrtype == af && !memcmp(p->h_addr, addr, 1027 if ((cp = strpbrk(name = cp, " \t")) != NULL)
1133 (size_t)len)) 1028 *cp++ = '\0';
1134 break; 1029 q = aliases;
1135 _endhtent(); 1030 while (cp && *cp) {
1136 *((struct hostent **)rv) = p; 1031 if (*cp == ' ' || *cp == '\t') {
1137 if (p==NULL) { 1032 cp++;
1138 h_errno = HOST_NOT_FOUND; 1033 continue;
1139 return NS_NOTFOUND; 1034 }
1035 addalias(q, cp, aliases, maxaliases);
1036 if ((cp = strpbrk(cp, " \t")) != NULL)
1037 *cp++ = '\0';
1038 }
1039 break;
1140 } 1040 }
1141 return NS_SUCCESS; 1041 hent->h_length = len;
1042 hent->h_addrtype = af;
1043 HENT_ARRAY(hent->h_addr_list, 1, buf, buflen);
1044 anum = (size_t)(q - aliases);
1045 HENT_ARRAY(hent->h_aliases, anum, buf, buflen);
1046 HENT_COPY(hent->h_addr_list[0], &host_addr, hent->h_length, buf,
1047 buflen);
1048 hent->h_addr_list[1] = NULL;
1049
1050 HENT_SCOPY(hent->h_name, name, buf, buflen);
1051 for (size_t i = 0; i < anum; i++)
1052 HENT_SCOPY(hent->h_aliases[i], aliases[i], buf, buflen);
1053 hent->h_aliases[anum] = NULL;
1054
1055 *he = NETDB_SUCCESS;
1056 free(p);
1057 free(aliases);
1058 return hent;
1059nospc:
1060 free(p);
1061 free(aliases);
1062 errno = ENOSPC;
1063 *he = NETDB_INTERNAL;
1064 return NULL;
1142} 1065}
1143 1066
1144static void 1067static void
1145map_v4v6_address(const char *src, char *dst) 1068map_v4v6_address(const char *src, char *dst)
1146{ 1069{
1147 u_char *p = (u_char *)dst; 1070 u_char *p = (u_char *)dst;
1148 char tmp[INADDRSZ]; 1071 char tmp[NS_INADDRSZ];
1149 int i; 1072 int i;
1150 1073
1151 assert(src != NULL); 1074 _DIAGASSERT(src != NULL);
1152 assert(dst != NULL); 1075 _DIAGASSERT(dst != NULL);
1153 1076
1154 /* Stash a temporary copy so our caller can update in place. */ 1077 /* Stash a temporary copy so our caller can update in place. */
1155 (void)memcpy(tmp, src, INADDRSZ); 1078 (void)memcpy(tmp, src, NS_INADDRSZ);
1156 /* Mark this ipv6 addr as a mapped ipv4. */ 1079 /* Mark this ipv6 addr as a mapped ipv4. */
1157 for (i = 0; i < 10; i++) 1080 for (i = 0; i < 10; i++)
1158 *p++ = 0x00; 1081 *p++ = 0x00;
1159 *p++ = 0xff; 1082 *p++ = 0xff;
1160 *p++ = 0xff; 1083 *p++ = 0xff;
1161 /* Retrieve the saved copy and we're done. */ 1084 /* Retrieve the saved copy and we're done. */
1162 (void)memcpy((void *)p, tmp, INADDRSZ); 1085 (void)memcpy(p, tmp, NS_INADDRSZ);
1163} 1086}
1164 1087
1165static void 1088static void
@@ -1167,18 +1090,19 @@ map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep)
1167{ 1090{
1168 char **ap; 1091 char **ap;
1169 1092
1170 assert(hp != NULL); 1093 _DIAGASSERT(hp != NULL);
1171 assert(bpp != NULL); 1094 _DIAGASSERT(bpp != NULL);
1172 assert(ep != NULL); 1095 _DIAGASSERT(ep != NULL);
1173 1096
1174 if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ) 1097 if (hp->h_addrtype != AF_INET || hp->h_length != NS_INADDRSZ)
1175 return; 1098 return;
1176 hp->h_addrtype = AF_INET6; 1099 hp->h_addrtype = AF_INET6;
1177 hp->h_length = IN6ADDRSZ; 1100 hp->h_length = NS_IN6ADDRSZ;
1178 for (ap = hp->h_addr_list; *ap; ap++) { 1101 for (ap = hp->h_addr_list; *ap; ap++) {
1179 int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align)); 1102 int i = (int)(sizeof(align) -
1103 (size_t)((u_long)*bpp % sizeof(align)));
1180 1104
1181 if (ep - *bpp < (i + IN6ADDRSZ)) { 1105 if (ep - *bpp < (i + NS_IN6ADDRSZ)) {
1182 /* Out of memory. Truncate address list here. XXX */ 1106 /* Out of memory. Truncate address list here. XXX */
1183 *ap = NULL; 1107 *ap = NULL;
1184 return; 1108 return;
@@ -1186,7 +1110,7 @@ map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep)
1186 *bpp += i; 1110 *bpp += i;
1187 map_v4v6_address(*ap, *bpp); 1111 map_v4v6_address(*ap, *bpp);
1188 *ap = *bpp; 1112 *ap = *bpp;
1189 *bpp += IN6ADDRSZ; 1113 *bpp += NS_IN6ADDRSZ;
1190 } 1114 }
1191} 1115}
1192 1116
@@ -1198,7 +1122,7 @@ addrsort(char **ap, int num, res_state res)
1198 short aval[MAXADDRS]; 1122 short aval[MAXADDRS];
1199 int needsort = 0; 1123 int needsort = 0;
1200 1124
1201 assert(ap != NULL); 1125 _DIAGASSERT(ap != NULL);
1202 1126
1203 p = ap; 1127 p = ap;
1204 for (i = 0; i < num; i++, p++) { 1128 for (i = 0; i < num; i++, p++) {
@@ -1233,15 +1157,6 @@ addrsort(char **ap, int num, res_state res)
1233 } 1157 }
1234} 1158}
1235 1159
1236struct hostent *
1237gethostent(void)
1238{
1239 res_static rs = __res_get_static();
1240 rs->host.h_addrtype = 0;
1241 rs->host.h_length = 0;
1242 return _gethtent();
1243}
1244
1245/*ARGSUSED*/ 1160/*ARGSUSED*/
1246static int 1161static int
1247_dns_gethtbyname(void *rv, void *cb_data, va_list ap) 1162_dns_gethtbyname(void *rv, void *cb_data, va_list ap)
@@ -1250,20 +1165,22 @@ _dns_gethtbyname(void *rv, void *cb_data, va_list ap)
1250 int n, type; 1165 int n, type;
1251 struct hostent *hp; 1166 struct hostent *hp;
1252 const char *name; 1167 const char *name;
1253 int af;
1254 res_state res; 1168 res_state res;
1169 struct getnamaddr *info = rv;
1255 1170
1256 assert(rv != NULL); 1171 _DIAGASSERT(rv != NULL);
1257 1172
1258 name = va_arg(ap, char *); 1173 name = va_arg(ap, char *);
1259 /* NOSTRICT skip len */(void)va_arg(ap, int); 1174 /* NOSTRICT skip string len */(void)va_arg(ap, int);
1260 af = va_arg(ap, int); 1175 info->hp->h_addrtype = va_arg(ap, int);
1261 1176
1262 switch (af) { 1177 switch (info->hp->h_addrtype) {
1263 case AF_INET: 1178 case AF_INET:
1179 info->hp->h_length = NS_INADDRSZ;
1264 type = T_A; 1180 type = T_A;
1265 break; 1181 break;
1266 case AF_INET6: 1182 case AF_INET6:
1183 info->hp->h_length = NS_IN6ADDRSZ;
1267 type = T_AAAA; 1184 type = T_AAAA;
1268 break; 1185 break;
1269 default: 1186 default:
@@ -1271,7 +1188,7 @@ _dns_gethtbyname(void *rv, void *cb_data, va_list ap)
1271 } 1188 }
1272 buf = malloc(sizeof(*buf)); 1189 buf = malloc(sizeof(*buf));
1273 if (buf == NULL) { 1190 if (buf == NULL) {
1274 h_errno = NETDB_INTERNAL; 1191 *info->he = NETDB_INTERNAL;
1275 return NS_NOTFOUND; 1192 return NS_NOTFOUND;
1276 } 1193 }
1277 res = __res_get_state(); 1194 res = __res_get_state();
@@ -1279,14 +1196,15 @@ _dns_gethtbyname(void *rv, void *cb_data, va_list ap)
1279 free(buf); 1196 free(buf);
1280 return NS_NOTFOUND; 1197 return NS_NOTFOUND;
1281 } 1198 }
1282 n = res_nsearch(res, name, C_IN, type, buf->buf, sizeof(buf->buf)); 1199 n = res_nsearch(res, name, C_IN, type, buf->buf, (int)sizeof(buf->buf));
1283 if (n < 0) { 1200 if (n < 0) {
1284 free(buf); 1201 free(buf);
1285 dprintf("res_nsearch failed (%d)\n", res, n); 1202 debugprintf("res_nsearch failed (%d)\n", res, n);
1286 __res_put_state(res); 1203 __res_put_state(res);
1287 return NS_NOTFOUND; 1204 return NS_NOTFOUND;
1288 } 1205 }
1289 hp = getanswer(buf, n, name, type, res); 1206 hp = getanswer(buf, n, name, type, res, info->hp, info->buf,
1207 info->buflen, info->he);
1290 free(buf); 1208 free(buf);
1291 __res_put_state(res); 1209 __res_put_state(res);
1292 if (hp == NULL) 1210 if (hp == NULL)
@@ -1298,7 +1216,6 @@ _dns_gethtbyname(void *rv, void *cb_data, va_list ap)
1298 default: 1216 default:
1299 return NS_UNAVAIL; 1217 return NS_UNAVAIL;
1300 } 1218 }
1301 *((struct hostent **)rv) = hp;
1302 return NS_SUCCESS; 1219 return NS_SUCCESS;
1303} 1220}
1304 1221
@@ -1311,20 +1228,22 @@ _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap)
1311 querybuf *buf; 1228 querybuf *buf;
1312 struct hostent *hp; 1229 struct hostent *hp;
1313 const unsigned char *uaddr; 1230 const unsigned char *uaddr;
1314 int len, af, advance; 1231 int advance;
1315 res_state res; 1232 res_state res;
1233 char *bf;
1234 size_t blen;
1235 struct getnamaddr *info = rv;
1316 unsigned netid, mark; 1236 unsigned netid, mark;
1317 res_static rs = __res_get_static();
1318 1237
1319 assert(rv != NULL); 1238 _DIAGASSERT(rv != NULL);
1320 1239
1321 uaddr = va_arg(ap, unsigned char *); 1240 uaddr = va_arg(ap, unsigned char *);
1322 len = va_arg(ap, int); 1241 info->hp->h_length = va_arg(ap, int);
1323 af = va_arg(ap, int); 1242 info->hp->h_addrtype = va_arg(ap, int);
1324 netid = va_arg(ap, unsigned); 1243 netid = va_arg(ap, unsigned);
1325 mark = va_arg(ap, unsigned); 1244 mark = va_arg(ap, unsigned);
1326 1245
1327 switch (af) { 1246 switch (info->hp->h_addrtype) {
1328 case AF_INET: 1247 case AF_INET:
1329 (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa", 1248 (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa",
1330 (uaddr[3] & 0xff), (uaddr[2] & 0xff), 1249 (uaddr[3] & 0xff), (uaddr[2] & 0xff),
@@ -1334,29 +1253,29 @@ _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap)
1334 case AF_INET6: 1253 case AF_INET6:
1335 qp = qbuf; 1254 qp = qbuf;
1336 ep = qbuf + sizeof(qbuf) - 1; 1255 ep = qbuf + sizeof(qbuf) - 1;
1337 for (n = IN6ADDRSZ - 1; n >= 0; n--) { 1256 for (n = NS_IN6ADDRSZ - 1; n >= 0; n--) {
1338 advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.", 1257 advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.",
1339 uaddr[n] & 0xf, 1258 uaddr[n] & 0xf,
1340 ((unsigned int)uaddr[n] >> 4) & 0xf); 1259 ((unsigned int)uaddr[n] >> 4) & 0xf);
1341 if (advance > 0 && qp + advance < ep) 1260 if (advance > 0 && qp + advance < ep)
1342 qp += advance; 1261 qp += advance;
1343 else { 1262 else {
1344 h_errno = NETDB_INTERNAL; 1263 *info->he = NETDB_INTERNAL;
1345 return NS_NOTFOUND; 1264 return NS_NOTFOUND;
1346 } 1265 }
1347 } 1266 }
1348 if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) { 1267 if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
1349 h_errno = NETDB_INTERNAL; 1268 *info->he = NETDB_INTERNAL;
1350 return NS_NOTFOUND; 1269 return NS_NOTFOUND;
1351 } 1270 }
1352 break; 1271 break;
1353 default: 1272 default:
1354 abort(); 1273 return NS_UNAVAIL;
1355 } 1274 }
1356 1275
1357 buf = malloc(sizeof(*buf)); 1276 buf = malloc(sizeof(*buf));
1358 if (buf == NULL) { 1277 if (buf == NULL) {
1359 h_errno = NETDB_INTERNAL; 1278 *info->he = NETDB_INTERNAL;
1360 return NS_NOTFOUND; 1279 return NS_NOTFOUND;
1361 } 1280 }
1362 res = __res_get_state(); 1281 res = __res_get_state();
@@ -1366,18 +1285,19 @@ _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap)
1366 } 1285 }
1367 res_setnetid(res, netid); 1286 res_setnetid(res, netid);
1368 res_setmark(res, mark); 1287 res_setmark(res, mark);
1369 n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf)); 1288 n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, (int)sizeof(buf->buf));
1370 if (n < 0) { 1289 if (n < 0) {
1371 free(buf); 1290 free(buf);
1372 dprintf("res_nquery failed (%d)\n", res, n); 1291 debugprintf("res_nquery failed (%d)\n", res, n);
1373 __res_put_state(res); 1292 __res_put_state(res);
1374 return NS_NOTFOUND; 1293 return NS_NOTFOUND;
1375 } 1294 }
1376 hp = getanswer(buf, n, qbuf, T_PTR, res); 1295 hp = getanswer(buf, n, qbuf, T_PTR, res, info->hp, info->buf,
1296 info->buflen, info->he);
1377 free(buf); 1297 free(buf);
1378 if (hp == NULL) { 1298 if (hp == NULL) {
1379 __res_put_state(res); 1299 __res_put_state(res);
1380 switch (h_errno) { 1300 switch (*info->he) {
1381 case HOST_NOT_FOUND: 1301 case HOST_NOT_FOUND:
1382 return NS_NOTFOUND; 1302 return NS_NOTFOUND;
1383 case TRY_AGAIN: 1303 case TRY_AGAIN:
@@ -1386,20 +1306,325 @@ _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap)
1386 return NS_UNAVAIL; 1306 return NS_UNAVAIL;
1387 } 1307 }
1388 } 1308 }
1389 hp->h_addrtype = af; 1309
1390 hp->h_length = len; 1310 bf = (void *)(hp->h_addr_list + 2);
1391 (void)memcpy(rs->host_addr, uaddr, (size_t)len); 1311 blen = (size_t)(bf - info->buf);
1392 rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr; 1312 if (blen + info->hp->h_length > info->buflen)
1393 rs->h_addr_ptrs[1] = NULL; 1313 goto nospc;
1394 if (af == AF_INET && (res->options & RES_USE_INET6)) { 1314 hp->h_addr_list[0] = bf;
1395 map_v4v6_address((char *)(void *)rs->host_addr, 1315 hp->h_addr_list[1] = NULL;
1396 (char *)(void *)rs->host_addr); 1316 (void)memcpy(bf, uaddr, (size_t)info->hp->h_length);
1317 if (info->hp->h_addrtype == AF_INET && (res->options & RES_USE_INET6)) {
1318 if (blen + NS_IN6ADDRSZ > info->buflen)
1319 goto nospc;
1320 map_v4v6_address(bf, bf);
1397 hp->h_addrtype = AF_INET6; 1321 hp->h_addrtype = AF_INET6;
1398 hp->h_length = IN6ADDRSZ; 1322 hp->h_length = NS_IN6ADDRSZ;
1399 } 1323 }
1400 1324
1401 __res_put_state(res); 1325 __res_put_state(res);
1402 *((struct hostent **)rv) = hp; 1326 *info->he = NETDB_SUCCESS;
1403 h_errno = NETDB_SUCCESS; 1327 return NS_SUCCESS;
1328nospc:
1329 *info->he = NETDB_INTERNAL;
1330 return NS_UNAVAIL;
1331}
1332
1333#ifdef YP
1334/*ARGSUSED*/
1335static struct hostent *
1336_yp_hostent(char *line, int af, struct getnamaddr *info)
1337{
1338 struct in6_addr host_addrs[MAXADDRS];
1339 char **aliases;
1340 size_t maxaliases;
1341 char *p = line;
1342 char *cp, **q, *ptr;
1343 size_t len, anum, i;
1344 int addrok;
1345 int more;
1346 size_t naddrs;
1347 struct hostent *hp = info->hp;
1348
1349 _DIAGASSERT(line != NULL);
1350
1351 hp->h_name = NULL;
1352 hp->h_addrtype = af;
1353 switch (af) {
1354 case AF_INET:
1355 hp->h_length = NS_INADDRSZ;
1356 break;
1357 case AF_INET6:
1358 hp->h_length = NS_IN6ADDRSZ;
1359 break;
1360 default:
1361 return NULL;
1362 }
1363 setup(aliases, maxaliases);
1364 naddrs = 0;
1365 q = aliases;
1366
1367nextline:
1368 /* check for host_addrs overflow */
1369 if (naddrs >= __arraycount(host_addrs))
1370 goto done;
1371
1372 more = 0;
1373 cp = strpbrk(p, " \t");
1374 if (cp == NULL)
1375 goto done;
1376 *cp++ = '\0';
1377
1378 /* p has should have an address */
1379 addrok = inet_pton(af, p, &host_addrs[naddrs]);
1380 if (addrok != 1) {
1381 /* skip to the next line */
1382 while (cp && *cp) {
1383 if (*cp == '\n') {
1384 cp++;
1385 goto nextline;
1386 }
1387 cp++;
1388 }
1389 goto done;
1390 }
1391 naddrs++;
1392
1393 while (*cp == ' ' || *cp == '\t')
1394 cp++;
1395 p = cp;
1396 cp = strpbrk(p, " \t\n");
1397 if (cp != NULL) {
1398 if (*cp == '\n')
1399 more = 1;
1400 *cp++ = '\0';
1401 }
1402 if (!hp->h_name)
1403 hp->h_name = p;
1404 else if (strcmp(hp->h_name, p) == 0)
1405 ;
1406 else
1407 addalias(q, p, aliases, maxaliases);
1408 p = cp;
1409 if (more)
1410 goto nextline;
1411
1412 while (cp && *cp) {
1413 if (*cp == ' ' || *cp == '\t') {
1414 cp++;
1415 continue;
1416 }
1417 if (*cp == '\n') {
1418 cp++;
1419 goto nextline;
1420 }
1421 addalias(q, cp, aliases, maxaliases);
1422 cp = strpbrk(cp, " \t");
1423 if (cp != NULL)
1424 *cp++ = '\0';
1425 }
1426
1427done:
1428 if (hp->h_name == NULL) {
1429 free(aliases);
1430 return NULL;
1431 }
1432
1433 ptr = info->buf;
1434 len = info->buflen;
1435
1436 anum = (size_t)(q - aliases);
1437 HENT_ARRAY(hp->h_addr_list, naddrs, ptr, len);
1438 HENT_ARRAY(hp->h_aliases, anum, ptr, len);
1439
1440 for (i = 0; i < naddrs; i++)
1441 HENT_COPY(hp->h_addr_list[i], &host_addrs[i], hp->h_length,
1442 ptr, len);
1443 hp->h_addr_list[naddrs] = NULL;
1444
1445 HENT_SCOPY(hp->h_name, hp->h_name, ptr, len);
1446
1447 for (i = 0; i < anum; i++)
1448 HENT_SCOPY(hp->h_aliases[i], aliases[i], ptr, len);
1449 hp->h_aliases[anum] = NULL;
1450 free(aliases);
1451
1452 return hp;
1453nospc:
1454 free(aliases);
1455 *info->he = NETDB_INTERNAL;
1456 errno = ENOSPC;
1457 return NULL;
1458}
1459
1460/*ARGSUSED*/
1461int
1462_yp_gethtbyaddr(void *rv, void *cb_data, va_list ap)
1463{
1464 struct hostent *hp = NULL;
1465 char *ypcurrent;
1466 int ypcurrentlen, r;
1467 char name[INET6_ADDRSTRLEN]; /* XXX enough? */
1468 const unsigned char *uaddr;
1469 int af;
1470 const char *map;
1471 struct getnamaddr *info = rv;
1472
1473 _DIAGASSERT(rv != NULL);
1474
1475 uaddr = va_arg(ap, unsigned char *);
1476 /* NOSTRICT skip len */(void)va_arg(ap, int);
1477 af = va_arg(ap, int);
1478
1479 if (!__ypdomain) {
1480 if (_yp_check(&__ypdomain) == 0)
1481 return NS_UNAVAIL;
1482 }
1483 /*
1484 * XXX unfortunately, we cannot support IPv6 extended scoped address
1485 * notation here. gethostbyaddr() is not scope-aware. too bad.
1486 */
1487 if (inet_ntop(af, uaddr, name, (socklen_t)sizeof(name)) == NULL)
1488 return NS_UNAVAIL;
1489 switch (af) {
1490 case AF_INET:
1491 map = "hosts.byaddr";
1492 break;
1493 default:
1494 map = "ipnodes.byaddr";
1495 break;
1496 }
1497 ypcurrent = NULL;
1498 r = yp_match(__ypdomain, map, name,
1499 (int)strlen(name), &ypcurrent, &ypcurrentlen);
1500 if (r == 0)
1501 hp = _yp_hostent(ypcurrent, af, info);
1502 else
1503 hp = NULL;
1504 free(ypcurrent);
1505 if (hp == NULL) {
1506 *info->he = HOST_NOT_FOUND;
1507 return NS_NOTFOUND;
1508 }
1509 return NS_SUCCESS;
1510}
1511
1512/*ARGSUSED*/
1513int
1514_yp_gethtbyname(void *rv, void *cb_data, va_list ap)
1515{
1516 struct hostent *hp;
1517 char *ypcurrent;
1518 int ypcurrentlen, r;
1519 const char *name;
1520 int af;
1521 const char *map;
1522 struct getnamaddr *info = rv;
1523
1524 _DIAGASSERT(rv != NULL);
1525
1526 name = va_arg(ap, char *);
1527 /* NOSTRICT skip string len */(void)va_arg(ap, int);
1528 af = va_arg(ap, int);
1529
1530 if (!__ypdomain) {
1531 if (_yp_check(&__ypdomain) == 0)
1532 return NS_UNAVAIL;
1533 }
1534 switch (af) {
1535 case AF_INET:
1536 map = "hosts.byname";
1537 break;
1538 default:
1539 map = "ipnodes.byname";
1540 break;
1541 }
1542 ypcurrent = NULL;
1543 r = yp_match(__ypdomain, map, name,
1544 (int)strlen(name), &ypcurrent, &ypcurrentlen);
1545 if (r == 0)
1546 hp = _yp_hostent(ypcurrent, af, info);
1547 else
1548 hp = NULL;
1549 free(ypcurrent);
1550 if (hp == NULL) {
1551 *info->he = HOST_NOT_FOUND;
1552 return NS_NOTFOUND;
1553 }
1404 return NS_SUCCESS; 1554 return NS_SUCCESS;
1405} 1555}
1556#endif
1557
1558/*
1559 * Non-reentrant versions.
1560 */
1561
1562struct hostent *
1563gethostbyname(const char *name)
1564{
1565 struct hostent *result = NULL;
1566 res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
1567
1568 gethostbyname_r(name, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &result, &h_errno);
1569 return result;
1570}
1571
1572struct hostent *
1573gethostbyname2(const char *name, int af)
1574{
1575 struct hostent *result = NULL;
1576 res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
1577
1578 gethostbyname2_r(name, af, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &result, &h_errno);
1579 return result;
1580}
1581
1582struct hostent *
1583android_gethostbynamefornet(const char *name, int af, unsigned netid, unsigned mark)
1584{
1585 struct hostent *hp;
1586 res_state res = __res_get_state();
1587 if (res == NULL)
1588 return NULL;
1589 res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
1590 hp = gethostbyname_internal(name, af, res, &rs->host, rs->hostbuf, sizeof(rs->hostbuf),
1591 &h_errno, netid, mark);
1592 __res_put_state(res);
1593 return hp;
1594}
1595
1596struct hostent *
1597gethostbyaddr(const void *addr, socklen_t len, int af)
1598{
1599 return android_gethostbyaddrfornet_proxy(addr, len, af, NETID_UNSET, MARK_UNSET);
1600}
1601
1602struct hostent *
1603android_gethostbyaddrfornet(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark)
1604{
1605 return android_gethostbyaddrfornet_proxy(addr, len, af, netid, mark);
1606}
1607
1608__LIBC_HIDDEN__ struct hostent*
1609android_gethostbyaddrfornet_proxy(const void* addr, socklen_t len, int af,
1610 unsigned netid, unsigned mark)
1611{
1612 res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
1613 return android_gethostbyaddrfornet_proxy_internal(addr, len, af, &rs->host, rs->hostbuf,
1614 sizeof(rs->hostbuf), &h_errno, netid, mark);
1615}
1616
1617struct hostent *
1618gethostent(void)
1619{
1620 res_static rs = __res_get_static();
1621 if (!rs->hostf) {
1622 sethostent_r(&rs->hostf);
1623 if (!rs->hostf) {
1624 h_errno = NETDB_INTERNAL;
1625 return NULL;
1626 }
1627 }
1628 memset(&rs->host, 0, sizeof(rs->host));
1629 return netbsd_gethostent_r(rs->hostf, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &h_errno);
1630}
diff --git a/libc/dns/include/hostent.h b/libc/dns/include/hostent.h
new file mode 100644
index 00000000..8b9a637c
--- /dev/null
+++ b/libc/dns/include/hostent.h
@@ -0,0 +1,93 @@
1/* $NetBSD: hostent.h,v 1.2 2013/08/27 09:56:12 christos Exp $ */
2
3/*-
4 * Copyright (c) 2013 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31#ifndef _DNS_NET_HOSTENT_H
32#define _DNS_NET_HOSTENT_H
33
34#include <stdio.h>
35#include <netdb.h>
36#include <stdarg.h>
37
38/*
39 * These are not being advertised because the interfaces are non-standard.
40 * There are versions by linux, aix, qnx, sun, etc. Our versions are used
41 * internally to provide thread safety; they mostly resemble qnx.
42 */
43void sethostent_r(FILE **);
44struct hostent *netbsd_gethostent_r(FILE *, struct hostent *, char *, size_t, int *);
45void endhostent_r(FILE **);
46
47/*
48 * The following are internal API's and are used only for testing.
49 */
50struct getnamaddr {
51 struct hostent *hp;
52 char *buf;
53 size_t buflen;
54 int *he;
55};
56
57/* /etc/hosts lookup */
58int _hf_gethtbyaddr(void *, void *, va_list);
59int _hf_gethtbyname(void *, void *, va_list);
60
61#ifdef YP
62/* NIS lookup */
63int _yp_gethtbyaddr(void *, void *, va_list);
64int _yp_gethtbyname(void *, void *, va_list);
65#endif
66
67#define HENT_ARRAY(dst, anum, ptr, len) \
68 do { \
69 size_t _len = (anum + 1) * sizeof(*dst); \
70 if (_len > len) \
71 goto nospc; \
72 dst = (void *)ptr; \
73 ptr += _len; \
74 len -= _len; \
75 } while (/*CONSTCOND*/0)
76
77#define HENT_COPY(dst, src, slen, ptr, len) \
78 do { \
79 if ((size_t)slen > len) \
80 goto nospc; \
81 memcpy(ptr, src, (size_t)slen); \
82 dst = ptr; \
83 ptr += slen; \
84 len -= slen; \
85 } while (/* CONSTCOND */0)
86
87#define HENT_SCOPY(dst, src, ptr, len) \
88 do { \
89 size_t _len = strlen(src) + 1; \
90 HENT_COPY(dst, src, _len, ptr, len); \
91 } while (/* CONSTCOND */0)
92
93#endif /* _DNS_NET_HOSTENT_H */
diff --git a/libc/dns/net/sethostent.c b/libc/dns/net/sethostent.c
new file mode 100644
index 00000000..f501c8b5
--- /dev/null
+++ b/libc/dns/net/sethostent.c
@@ -0,0 +1,266 @@
1/* $NetBSD: sethostent.c,v 1.20 2014/03/17 13:24:23 christos Exp $ */
2
3/*
4 * Copyright (c) 1985, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33#if defined(LIBC_SCCS) && !defined(lint)
34#if 0
35static char sccsid[] = "@(#)sethostent.c 8.1 (Berkeley) 6/4/93";
36static char rcsid[] = "Id: sethostent.c,v 8.5 1996/09/28 06:51:07 vixie Exp ";
37#else
38__RCSID("$NetBSD: sethostent.c,v 1.20 2014/03/17 13:24:23 christos Exp $");
39#endif
40#endif /* LIBC_SCCS and not lint */
41
42#include "namespace.h"
43#include <sys/param.h>
44#include <netinet/in.h>
45#include <arpa/nameser.h>
46#include <arpa/inet.h>
47#include <assert.h>
48#include <string.h>
49#include <nsswitch.h>
50#include <netdb.h>
51#include <resolv.h>
52#include <errno.h>
53#include <stdlib.h>
54
55#include "hostent.h"
56#include "resolv_private.h"
57
58#define ALIGNBYTES (sizeof(uintptr_t) - 1)
59#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
60
61#ifndef _REENTRANT
62void res_close(void);
63#endif
64
65static struct hostent *_hf_gethtbyname2(const char *, int, struct getnamaddr *);
66
67static const char *_h_hosts = _PATH_HOSTS;
68
69void
70sethostent_r(FILE **hf)
71{
72 if (!*hf)
73 *hf = fopen(_h_hosts, "re");
74 else
75 rewind(*hf);
76}
77
78void
79endhostent_r(FILE **hf)
80{
81 if (*hf) {
82 (void)fclose(*hf);
83 *hf = NULL;
84 }
85}
86
87/*ARGSUSED*/
88int
89_hf_gethtbyname(void *rv, void *cb_data, va_list ap)
90{
91 struct hostent *hp;
92 const char *name;
93 int af;
94 struct getnamaddr *info = rv;
95
96 _DIAGASSERT(rv != NULL);
97
98 name = va_arg(ap, char *);
99 /* NOSTRICT skip string len */(void)va_arg(ap, int);
100 af = va_arg(ap, int);
101
102#if 0
103 {
104 res_state res = __res_get_state();
105 if (res == NULL)
106 return NS_NOTFOUND;
107 if (res->options & RES_USE_INET6)
108 hp = _hf_gethtbyname2(name, AF_INET6, info);
109 else
110 hp = NULL;
111 if (hp == NULL)
112 hp = _hf_gethtbyname2(name, AF_INET, info);
113 __res_put_state(res);
114 }
115#else
116 hp = _hf_gethtbyname2(name, af, info);
117#endif
118 if (hp == NULL) {
119 *info->he = HOST_NOT_FOUND;
120 return NS_NOTFOUND;
121 }
122 return NS_SUCCESS;
123}
124
125static struct hostent *
126_hf_gethtbyname2(const char *name, int af, struct getnamaddr *info)
127{
128 struct hostent *hp, hent;
129 char *buf, *ptr;
130 size_t len, anum, num, i;
131 FILE *hf;
132 char *aliases[MAXALIASES];
133 char *addr_ptrs[MAXADDRS];
134
135 _DIAGASSERT(name != NULL);
136
137 hf = NULL;
138 sethostent_r(&hf);
139 if (hf == NULL) {
140 errno = EINVAL;
141 *info->he = NETDB_INTERNAL;
142 return NULL;
143 }
144
145 if ((ptr = buf = malloc(len = info->buflen)) == NULL) {
146 endhostent_r(&hf);
147 *info->he = NETDB_INTERNAL;
148 return NULL;
149 }
150
151 anum = 0; /* XXX: gcc */
152 hent.h_name = NULL; /* XXX: gcc */
153 hent.h_addrtype = 0; /* XXX: gcc */
154 hent.h_length = 0; /* XXX: gcc */
155
156 for (num = 0; num < MAXADDRS;) {
157 info->hp->h_addrtype = af;
158 info->hp->h_length = 0;
159
160 hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen,
161 info->he);
162 if (hp == NULL)
163 break;
164
165 if (strcasecmp(hp->h_name, name) != 0) {
166 char **cp;
167 for (cp = hp->h_aliases; *cp != NULL; cp++)
168 if (strcasecmp(*cp, name) == 0)
169 break;
170 if (*cp == NULL) continue;
171 }
172
173 if (num == 0) {
174 hent.h_addrtype = af = hp->h_addrtype;
175 hent.h_length = hp->h_length;
176
177 HENT_SCOPY(hent.h_name, hp->h_name, ptr, len);
178 for (anum = 0; hp->h_aliases[anum]; anum++) {
179 if (anum >= MAXALIASES)
180 goto nospc;
181 HENT_SCOPY(aliases[anum], hp->h_aliases[anum],
182 ptr, len);
183 }
184 ptr = (void *)ALIGN(ptr);
185 if ((size_t)(ptr - buf) >= info->buflen)
186 goto nospc;
187 }
188
189 if (num >= MAXADDRS)
190 goto nospc;
191 HENT_COPY(addr_ptrs[num], hp->h_addr_list[0], hp->h_length, ptr,
192 len);
193 num++;
194 }
195 endhostent_r(&hf);
196
197 if (num == 0) {
198 *info->he = HOST_NOT_FOUND;
199 free(buf);
200 return NULL;
201 }
202
203 hp = info->hp;
204 ptr = info->buf;
205 len = info->buflen;
206
207 hp->h_addrtype = hent.h_addrtype;
208 hp->h_length = hent.h_length;
209
210 HENT_ARRAY(hp->h_aliases, anum, ptr, len);
211 HENT_ARRAY(hp->h_addr_list, num, ptr, len);
212
213 for (i = 0; i < num; i++)
214 HENT_COPY(hp->h_addr_list[i], addr_ptrs[i], hp->h_length, ptr,
215 len);
216 hp->h_addr_list[num] = NULL;
217
218 HENT_SCOPY(hp->h_name, hent.h_name, ptr, len);
219
220 for (i = 0; i < anum; i++)
221 HENT_SCOPY(hp->h_aliases[i], aliases[i], ptr, len);
222 hp->h_aliases[anum] = NULL;
223
224 free(buf);
225 return hp;
226nospc:
227 endhostent_r(&hf);
228 *info->he = NETDB_INTERNAL;
229 free(buf);
230 errno = ENOSPC;
231 return NULL;
232}
233
234/*ARGSUSED*/
235int
236_hf_gethtbyaddr(void *rv, void *cb_data, va_list ap)
237{
238 struct hostent *hp;
239 const unsigned char *addr;
240 struct getnamaddr *info = rv;
241 FILE *hf;
242
243 _DIAGASSERT(rv != NULL);
244
245 addr = va_arg(ap, unsigned char *);
246 info->hp->h_length = va_arg(ap, int);
247 info->hp->h_addrtype = va_arg(ap, int);
248
249 hf = NULL;
250 sethostent_r(&hf);
251 if (hf == NULL) {
252 *info->he = NETDB_INTERNAL;
253 return NS_UNAVAIL;
254 }
255 while ((hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen,
256 info->he)) != NULL)
257 if (!memcmp(hp->h_addr_list[0], addr, (size_t)hp->h_length))
258 break;
259 endhostent_r(&hf);
260
261 if (hp == NULL) {
262 *info->he = HOST_NOT_FOUND;
263 return NS_NOTFOUND;
264 }
265 return NS_SUCCESS;
266}
diff --git a/libc/include/netdb.h b/libc/include/netdb.h
index 527d5c19..e1653762 100644
--- a/libc/include/netdb.h
+++ b/libc/include/netdb.h
@@ -209,7 +209,7 @@ void endprotoent(void);
209void endservent(void); 209void endservent(void);
210void freehostent(struct hostent *); 210void freehostent(struct hostent *);
211struct hostent *gethostbyaddr(const void *, socklen_t, int); 211struct hostent *gethostbyaddr(const void *, socklen_t, int);
212int gethostbyaddr_r(const void *, int, int, struct hostent *, char *, size_t, struct hostent **, int *); 212int gethostbyaddr_r(const void *, socklen_t, int, struct hostent *, char *, size_t, struct hostent **, int *);
213struct hostent *gethostbyname(const char *); 213struct hostent *gethostbyname(const char *);
214int gethostbyname_r(const char *, struct hostent *, char *, size_t, struct hostent **, int *); 214int gethostbyname_r(const char *, struct hostent *, char *, size_t, struct hostent **, int *);
215struct hostent *gethostbyname2(const char *, int); 215struct hostent *gethostbyname2(const char *, int);
diff --git a/tests/netdb_test.cpp b/tests/netdb_test.cpp
index 0cebe4e8..ab5b4875 100644
--- a/tests/netdb_test.cpp
+++ b/tests/netdb_test.cpp
@@ -14,11 +14,13 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17#include <netdb.h>
18
17#include <gtest/gtest.h> 19#include <gtest/gtest.h>
18 20
21#include <arpa/inet.h>
19#include <sys/types.h> 22#include <sys/types.h>
20#include <sys/socket.h> 23#include <sys/socket.h>
21#include <netdb.h>
22#include <netinet/in.h> 24#include <netinet/in.h>
23 25
24TEST(netdb, getaddrinfo_NULL_host) { 26TEST(netdb, getaddrinfo_NULL_host) {
@@ -114,8 +116,7 @@ TEST(netdb, getnameinfo_salen) {
114 ASSERT_EQ(EAI_FAMILY, getnameinfo(sa, too_little, tmp, sizeof(tmp), NULL, 0, NI_NUMERICHOST)); 116 ASSERT_EQ(EAI_FAMILY, getnameinfo(sa, too_little, tmp, sizeof(tmp), NULL, 0, NI_NUMERICHOST));
115} 117}
116 118
117TEST(netdb, gethostbyname) { 119void VerifyLocalhost(hostent *hent) {
118 hostent* hent = gethostbyname("localhost");
119 ASSERT_TRUE(hent != NULL); 120 ASSERT_TRUE(hent != NULL);
120 ASSERT_EQ(hent->h_addrtype, AF_INET); 121 ASSERT_EQ(hent->h_addrtype, AF_INET);
121 ASSERT_EQ(hent->h_addr[0], 127); 122 ASSERT_EQ(hent->h_addr[0], 127);
@@ -124,6 +125,125 @@ TEST(netdb, gethostbyname) {
124 ASSERT_EQ(hent->h_addr[3], 1); 125 ASSERT_EQ(hent->h_addr[3], 1);
125} 126}
126 127
128TEST(netdb, gethostbyname) {
129 hostent* hp = gethostbyname("localhost");
130 VerifyLocalhost(hp);
131}
132
133TEST(netdb, gethostbyname2) {
134 hostent* hp = gethostbyname2("localhost", AF_INET);
135 VerifyLocalhost(hp);
136}
137
138TEST(netdb, gethostbyname_r) {
139 hostent hent;
140 hostent *hp;
141 char buf[512];
142 int err;
143 int result = gethostbyname_r("localhost", &hent, buf, sizeof(buf), &hp, &err);
144 ASSERT_EQ(0, result);
145 VerifyLocalhost(hp);
146
147 // Change hp->h_addr to test reentrancy.
148 hp->h_addr[0] = 0;
149
150 hostent hent2;
151 hostent *hp2;
152 char buf2[512];
153 result = gethostbyname_r("localhost", &hent2, buf2, sizeof(buf2), &hp2, &err);
154 ASSERT_EQ(0, result);
155 VerifyLocalhost(hp2);
156
157 ASSERT_EQ(0, hp->h_addr[0]);
158}
159
160TEST(netdb, gethostbyname2_r) {
161 hostent hent;
162 hostent *hp;
163 char buf[512];
164 int err;
165 int result = gethostbyname2_r("localhost", AF_INET, &hent, buf, sizeof(buf), &hp, &err);
166 ASSERT_EQ(0, result);
167 VerifyLocalhost(hp);
168
169 // Change hp->h_addr to test reentrancy.
170 hp->h_addr[0] = 0;
171
172 hostent hent2;
173 hostent *hp2;
174 char buf2[512];
175 result = gethostbyname2_r("localhost", AF_INET, &hent2, buf2, sizeof(buf2), &hp2, &err);
176 ASSERT_EQ(0, result);
177 VerifyLocalhost(hp2);
178
179 ASSERT_EQ(0, hp->h_addr[0]);
180}
181
182TEST(netdb, gethostbyaddr) {
183 char addr[4];
184 ASSERT_EQ(1, inet_pton(AF_INET, "127.0.0.1", addr));
185 hostent *hp = gethostbyaddr(addr, sizeof(addr), AF_INET);
186 VerifyLocalhost(hp);
187}
188
189TEST(netdb, gethostbyaddr_r) {
190 char addr[4];
191 ASSERT_EQ(1, inet_pton(AF_INET, "127.0.0.1", addr));
192
193 hostent hent;
194 hostent *hp;
195 char buf[512];
196 int err;
197 int result = gethostbyaddr_r(addr, sizeof(addr), AF_INET, &hent, buf, sizeof(buf), &hp, &err);
198 ASSERT_EQ(0, result);
199 VerifyLocalhost(hp);
200
201 // Change hp->h_addr to test reentrancy.
202 hp->h_addr[0] = 0;
203
204 hostent hent2;
205 hostent *hp2;
206 char buf2[512];
207 result = gethostbyaddr_r(addr, sizeof(addr), AF_INET, &hent2, buf2, sizeof(buf2), &hp2, &err);
208 ASSERT_EQ(0, result);
209 VerifyLocalhost(hp2);
210
211 ASSERT_EQ(0, hp->h_addr[0]);
212}
213
214TEST(netdb, gethostbyname_r_ERANGE) {
215 hostent hent;
216 hostent *hp;
217 char buf[4]; // Use too small buffer.
218 int err;
219 int result = gethostbyname_r("localhost", &hent, buf, sizeof(buf), &hp, &err);
220 ASSERT_EQ(ERANGE, result);
221 ASSERT_EQ(NULL, hp);
222}
223
224TEST(netdb, gethostbyname2_r_ERANGE) {
225 hostent hent;
226 hostent *hp;
227 char buf[4]; // Use too small buffer.
228 int err;
229 int result = gethostbyname2_r("localhost", AF_INET, &hent, buf, sizeof(buf), &hp, &err);
230 ASSERT_EQ(ERANGE, result);
231 ASSERT_EQ(NULL, hp);
232}
233
234TEST(netdb, gethostbyaddr_r_ERANGE) {
235 char addr[4];
236 ASSERT_EQ(1, inet_pton(AF_INET, "127.0.0.1", addr));
237
238 hostent hent;
239 hostent *hp;
240 char buf[4]; // Use too small buffer.
241 int err;
242 int result = gethostbyaddr_r(addr, sizeof(addr), AF_INET, &hent, buf, sizeof(buf), &hp, &err);
243 ASSERT_EQ(ERANGE, result);
244 ASSERT_EQ(NULL, hp);
245}
246
127TEST(netdb, getservbyname) { 247TEST(netdb, getservbyname) {
128 // smtp is TCP-only, so we know we'll get 25/tcp back. 248 // smtp is TCP-only, so we know we'll get 25/tcp back.
129 servent* s = getservbyname("smtp", NULL); 249 servent* s = getservbyname("smtp", NULL);