1*5be03f8fSeric /* $OpenBSD: gethostnamadr_async.c,v 1.27 2014/03/25 19:48:11 eric Exp $ */ 2b44da627Seric /* 3b44da627Seric * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> 4b44da627Seric * 5b44da627Seric * Permission to use, copy, modify, and distribute this software for any 6b44da627Seric * purpose with or without fee is hereby granted, provided that the above 7b44da627Seric * copyright notice and this permission notice appear in all copies. 8b44da627Seric * 9b44da627Seric * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10b44da627Seric * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11b44da627Seric * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12b44da627Seric * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13b44da627Seric * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14b44da627Seric * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15b44da627Seric * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16b44da627Seric */ 1780f48568Seric 18b44da627Seric #include <sys/types.h> 19b44da627Seric #include <sys/socket.h> 20b44da627Seric #include <netinet/in.h> 21b44da627Seric #include <arpa/inet.h> 22b44da627Seric #include <arpa/nameser.h> 23262cf3f8Seric #ifdef YP 24262cf3f8Seric #include <rpc/rpc.h> 25262cf3f8Seric #include <rpcsvc/yp.h> 26262cf3f8Seric #include <rpcsvc/ypclnt.h> 27262cf3f8Seric #include "ypinternal.h" 28262cf3f8Seric #endif 29b44da627Seric 30b32de4eaSeric #include <ctype.h> 3180f48568Seric #include <err.h> 3280f48568Seric #include <errno.h> 3301b887f7Seric #include <resolv.h> /* for res_hnok */ 3480f48568Seric #include <stdlib.h> 3580f48568Seric #include <string.h> 3680f48568Seric #include <unistd.h> 3780f48568Seric 38b44da627Seric #include "asr.h" 39b44da627Seric #include "asr_private.h" 40b44da627Seric 41b44da627Seric #define MAXALIASES 16 42b44da627Seric #define MAXADDRS 16 43b44da627Seric 44cd22283fSeric struct hostent_ext { 45cd22283fSeric struct hostent h; 46cd22283fSeric char *aliases[MAXALIASES + 1]; 47cd22283fSeric char *addrs[MAXADDRS + 1]; 48cd22283fSeric char *end; 49cd22283fSeric char *pos; 50cd22283fSeric }; 51836b804aSeric 52*5be03f8fSeric static int gethostnamadr_async_run(struct asr_query *, struct asr_result *); 53cd22283fSeric static struct hostent_ext *hostent_alloc(int); 54cd22283fSeric static int hostent_set_cname(struct hostent_ext *, const char *, int); 55cd22283fSeric static int hostent_add_alias(struct hostent_ext *, const char *, int); 56cd22283fSeric static int hostent_add_addr(struct hostent_ext *, const void *, size_t); 57b32de4eaSeric static struct hostent_ext *hostent_from_addr(int, const char *, const char *); 58cd22283fSeric static struct hostent_ext *hostent_file_match(FILE *, int, int, const char *, 59cd22283fSeric int); 60cd22283fSeric static struct hostent_ext *hostent_from_packet(int, int, char *, size_t); 611b26c956Seric #ifdef YP 62cd22283fSeric static struct hostent_ext *_yp_gethostnamadr(int, const void *); 63cd22283fSeric static struct hostent_ext *hostent_from_yp(int, char *); 641b26c956Seric #endif 65b44da627Seric 66*5be03f8fSeric struct asr_query * 67*5be03f8fSeric gethostbyname_async(const char *name, void *asr) 68b44da627Seric { 69b44da627Seric return gethostbyname2_async(name, AF_INET, asr); 70b44da627Seric } 71b44da627Seric 72*5be03f8fSeric struct asr_query * 73*5be03f8fSeric gethostbyname2_async(const char *name, int af, void *asr) 74b44da627Seric { 75b44da627Seric struct asr_ctx *ac; 76*5be03f8fSeric struct asr_query *as; 77b44da627Seric 78b44da627Seric /* the original segfaults */ 79b44da627Seric if (name == NULL) { 80b44da627Seric errno = EINVAL; 81b44da627Seric return (NULL); 82b44da627Seric } 83b44da627Seric 84b44da627Seric ac = asr_use_resolver(asr); 855bd9e5c2Seric if ((as = asr_async_new(ac, ASR_GETHOSTBYNAME)) == NULL) 86b44da627Seric goto abort; /* errno set */ 87b44da627Seric as->as_run = gethostnamadr_async_run; 88b44da627Seric 89b44da627Seric as->as.hostnamadr.family = af; 90b44da627Seric if (af == AF_INET) 91b44da627Seric as->as.hostnamadr.addrlen = INADDRSZ; 92b44da627Seric else if (af == AF_INET6) 93b44da627Seric as->as.hostnamadr.addrlen = IN6ADDRSZ; 94b44da627Seric as->as.hostnamadr.name = strdup(name); 95b44da627Seric if (as->as.hostnamadr.name == NULL) 96b44da627Seric goto abort; /* errno set */ 97b44da627Seric 98b44da627Seric asr_ctx_unref(ac); 99b44da627Seric return (as); 100b44da627Seric 101b44da627Seric abort: 102b44da627Seric if (as) 1035bd9e5c2Seric asr_async_free(as); 104b44da627Seric asr_ctx_unref(ac); 105b44da627Seric return (NULL); 106b44da627Seric } 107b44da627Seric 108*5be03f8fSeric struct asr_query * 109*5be03f8fSeric gethostbyaddr_async(const void *addr, socklen_t len, int af, void *asr) 110b44da627Seric { 111b44da627Seric struct asr_ctx *ac; 112*5be03f8fSeric struct asr_query *as; 113b44da627Seric 114b44da627Seric ac = asr_use_resolver(asr); 115b44da627Seric as = gethostbyaddr_async_ctx(addr, len, af, ac); 116b44da627Seric asr_ctx_unref(ac); 117b44da627Seric 118b44da627Seric return (as); 119b44da627Seric } 120b44da627Seric 121*5be03f8fSeric struct asr_query * 122b44da627Seric gethostbyaddr_async_ctx(const void *addr, socklen_t len, int af, 123b44da627Seric struct asr_ctx *ac) 124b44da627Seric { 125*5be03f8fSeric struct asr_query *as; 126b44da627Seric 1275bd9e5c2Seric if ((as = asr_async_new(ac, ASR_GETHOSTBYADDR)) == NULL) 128b44da627Seric goto abort; /* errno set */ 129b44da627Seric as->as_run = gethostnamadr_async_run; 130b44da627Seric 131b44da627Seric as->as.hostnamadr.family = af; 132b44da627Seric as->as.hostnamadr.addrlen = len; 133b44da627Seric if (len > 0) 134b44da627Seric memmove(as->as.hostnamadr.addr, addr, (len > 16) ? 16 : len); 135b44da627Seric 136b44da627Seric return (as); 137b44da627Seric 138b44da627Seric abort: 139b44da627Seric if (as) 14064032770Seric asr_async_free(as); 141b44da627Seric return (NULL); 142b44da627Seric } 143b44da627Seric 144b44da627Seric static int 145*5be03f8fSeric gethostnamadr_async_run(struct asr_query *as, struct asr_result *ar) 146b44da627Seric { 147cd22283fSeric struct hostent_ext *h; 148cd22283fSeric int r, type, saved_errno; 149b44da627Seric FILE *f; 1506a7a3d64Seric char name[MAXDNAME], *data, addr[16], *c; 151b44da627Seric 152b44da627Seric next: 153b44da627Seric switch (as->as_state) { 154b44da627Seric 155b44da627Seric case ASR_STATE_INIT: 156b44da627Seric 157b44da627Seric if (as->as.hostnamadr.family != AF_INET && 158b44da627Seric as->as.hostnamadr.family != AF_INET6) { 159b44da627Seric ar->ar_h_errno = NETDB_INTERNAL; 160b44da627Seric ar->ar_errno = EAFNOSUPPORT; 161b44da627Seric async_set_state(as, ASR_STATE_HALT); 162b44da627Seric break; 163b44da627Seric } 164b44da627Seric 165b44da627Seric if ((as->as.hostnamadr.family == AF_INET && 166b44da627Seric as->as.hostnamadr.addrlen != INADDRSZ) || 167b44da627Seric (as->as.hostnamadr.family == AF_INET6 && 168b44da627Seric as->as.hostnamadr.addrlen != IN6ADDRSZ)) { 169b44da627Seric ar->ar_h_errno = NETDB_INTERNAL; 170b44da627Seric ar->ar_errno = EINVAL; 171b44da627Seric async_set_state(as, ASR_STATE_HALT); 172b44da627Seric break; 173b44da627Seric } 174b44da627Seric 175b32de4eaSeric /* Name might be an IP address string */ 176b32de4eaSeric if (as->as_type == ASR_GETHOSTBYNAME) { 177b32de4eaSeric for (c = as->as.hostnamadr.name; *c; c++) 178dfe5467eSderaadt if (!isdigit((unsigned char)*c) && 179dfe5467eSderaadt *c != '.' && *c != ':') 180b32de4eaSeric break; 181b32de4eaSeric if (*c == 0 && 182b32de4eaSeric inet_pton(as->as.hostnamadr.family, 183b32de4eaSeric as->as.hostnamadr.name, addr) == 1) { 184b32de4eaSeric h = hostent_from_addr(as->as.hostnamadr.family, 185b32de4eaSeric as->as.hostnamadr.name, addr); 186b32de4eaSeric if (h == NULL) { 187b32de4eaSeric ar->ar_errno = errno; 188b32de4eaSeric ar->ar_h_errno = NETDB_INTERNAL; 189b32de4eaSeric } 190b32de4eaSeric else { 191b32de4eaSeric ar->ar_hostent = &h->h; 192b32de4eaSeric ar->ar_h_errno = NETDB_SUCCESS; 193b32de4eaSeric } 194b32de4eaSeric async_set_state(as, ASR_STATE_HALT); 195b44da627Seric break; 196b44da627Seric } 197b44da627Seric } 198b44da627Seric async_set_state(as, ASR_STATE_NEXT_DB); 199b44da627Seric break; 200b44da627Seric 201b44da627Seric case ASR_STATE_NEXT_DB: 202b44da627Seric 203b44da627Seric if (asr_iter_db(as) == -1) { 204b44da627Seric async_set_state(as, ASR_STATE_NOT_FOUND); 205b44da627Seric break; 206b44da627Seric } 207b44da627Seric 208b44da627Seric switch (AS_DB(as)) { 209b44da627Seric 210b44da627Seric case ASR_DB_DNS: 211b44da627Seric 212b44da627Seric /* Create a subquery to do the DNS lookup */ 213b44da627Seric 214b44da627Seric if (as->as_type == ASR_GETHOSTBYNAME) { 215b44da627Seric type = (as->as.hostnamadr.family == AF_INET) ? 216b44da627Seric T_A : T_AAAA; 2171e1dfc0cSeric as->as.hostnamadr.subq = res_search_async_ctx( 2181e1dfc0cSeric as->as.hostnamadr.name, 219c5221d45Seric C_IN, type, as->as_ctx); 220b44da627Seric } else { 2215bd9e5c2Seric asr_addr_as_fqdn(as->as.hostnamadr.addr, 222b44da627Seric as->as.hostnamadr.family, 2236a7a3d64Seric name, sizeof(name)); 224b44da627Seric as->as.hostnamadr.subq = res_query_async_ctx( 2256a7a3d64Seric name, C_IN, T_PTR, as->as_ctx); 226b44da627Seric } 227b44da627Seric 228b44da627Seric if (as->as.hostnamadr.subq == NULL) { 229b44da627Seric ar->ar_errno = errno; 230b44da627Seric ar->ar_h_errno = NETDB_INTERNAL; 231b44da627Seric async_set_state(as, ASR_STATE_HALT); 232b44da627Seric break; 233b44da627Seric } 234b44da627Seric 235b44da627Seric async_set_state(as, ASR_STATE_SUBQUERY); 236b44da627Seric break; 237b44da627Seric 238b44da627Seric case ASR_DB_FILE: 239b44da627Seric 240b44da627Seric /* Try to find a match in the host file */ 241b44da627Seric 242b44da627Seric if ((f = fopen(as->as_ctx->ac_hostfile, "r")) == NULL) 243b44da627Seric break; 244b44da627Seric 2456a7a3d64Seric if (as->as_type == ASR_GETHOSTBYNAME) { 2466a7a3d64Seric data = asr_hostalias(as->as_ctx, 2476a7a3d64Seric as->as.hostnamadr.name, name, sizeof(name)); 2486a7a3d64Seric if (data == NULL) 2491e1dfc0cSeric data = as->as.hostnamadr.name; 2506a7a3d64Seric } 251b44da627Seric else 252b44da627Seric data = as->as.hostnamadr.addr; 253b44da627Seric 254cd22283fSeric h = hostent_file_match(f, as->as_type, 2550348accfSeric as->as.hostnamadr.family, data, 2560348accfSeric as->as.hostnamadr.addrlen); 257cd22283fSeric saved_errno = errno; 258b44da627Seric fclose(f); 259cd22283fSeric errno = saved_errno; 2600348accfSeric 261cd22283fSeric if (h == NULL) { 2620348accfSeric if (errno) { 263b44da627Seric ar->ar_errno = errno; 264b44da627Seric ar->ar_h_errno = NETDB_INTERNAL; 265b44da627Seric async_set_state(as, ASR_STATE_HALT); 2660348accfSeric } 2670348accfSeric /* otherwise not found */ 268b44da627Seric break; 269b44da627Seric } 270cd22283fSeric ar->ar_hostent = &h->h; 271b44da627Seric ar->ar_h_errno = NETDB_SUCCESS; 272b44da627Seric async_set_state(as, ASR_STATE_HALT); 273b44da627Seric break; 2741b26c956Seric #ifdef YP 2751b26c956Seric case ASR_DB_YP: 2761b26c956Seric /* IPv4 only */ 2771b26c956Seric if (as->as.hostnamadr.family != AF_INET) 2781b26c956Seric break; 2796a7a3d64Seric if (as->as_type == ASR_GETHOSTBYNAME) { 2806a7a3d64Seric data = asr_hostalias(as->as_ctx, 2816a7a3d64Seric as->as.hostnamadr.name, name, sizeof(name)); 2826a7a3d64Seric if (data == NULL) 2831e1dfc0cSeric data = as->as.hostnamadr.name; 2846a7a3d64Seric } 2851b26c956Seric else 2861b26c956Seric data = as->as.hostnamadr.addr; 287cd22283fSeric h = _yp_gethostnamadr(as->as_type, data); 288cd22283fSeric if (h == NULL) { 2891b26c956Seric if (errno) { 2901b26c956Seric ar->ar_errno = errno; 2911b26c956Seric ar->ar_h_errno = NETDB_INTERNAL; 2921b26c956Seric async_set_state(as, ASR_STATE_HALT); 2931b26c956Seric } 2941b26c956Seric /* otherwise not found */ 2951b26c956Seric break; 2961b26c956Seric } 297cd22283fSeric ar->ar_hostent = &h->h; 2981b26c956Seric ar->ar_h_errno = NETDB_SUCCESS; 2991b26c956Seric async_set_state(as, ASR_STATE_HALT); 3001b26c956Seric break; 3011b26c956Seric #endif 302b44da627Seric } 303b44da627Seric break; 304b44da627Seric 305b44da627Seric case ASR_STATE_SUBQUERY: 306b44da627Seric 307b44da627Seric /* Run the DNS subquery. */ 308b44da627Seric 309*5be03f8fSeric if ((r = asr_run(as->as.hostnamadr.subq, ar)) == ASYNC_COND) 310b44da627Seric return (ASYNC_COND); 311b44da627Seric 312b44da627Seric /* Done. */ 313b44da627Seric as->as.hostnamadr.subq = NULL; 314b44da627Seric 315b44da627Seric if (ar->ar_datalen == -1) { 316b44da627Seric async_set_state(as, ASR_STATE_NEXT_DB); 317b44da627Seric break; 318b44da627Seric } 319b44da627Seric 320b44da627Seric /* If we got a packet but no anwser, use the next DB. */ 321b44da627Seric if (ar->ar_count == 0) { 322b44da627Seric free(ar->ar_data); 3237ffb6b35Seric as->as.hostnamadr.subq_h_errno = ar->ar_h_errno; 324b44da627Seric async_set_state(as, ASR_STATE_NEXT_DB); 325b44da627Seric break; 326b44da627Seric } 327b44da627Seric 328b44da627Seric /* Read the hostent from the packet. */ 3290348accfSeric 330cd22283fSeric h = hostent_from_packet(as->as_type, 3310348accfSeric as->as.hostnamadr.family, ar->ar_data, ar->ar_datalen); 3320348accfSeric free(ar->ar_data); 333cd22283fSeric if (h == NULL) { 334b44da627Seric ar->ar_errno = errno; 335b44da627Seric ar->ar_h_errno = NETDB_INTERNAL; 336b44da627Seric async_set_state(as, ASR_STATE_HALT); 337b44da627Seric break; 338b44da627Seric } 339b44da627Seric 340b44da627Seric if (as->as_type == ASR_GETHOSTBYADDR) { 341cd22283fSeric if (hostent_add_addr(h, as->as.hostnamadr.addr, 3420348accfSeric as->as.hostnamadr.addrlen) == -1) { 343cd22283fSeric free(h); 3440348accfSeric ar->ar_errno = errno; 3450348accfSeric ar->ar_h_errno = NETDB_INTERNAL; 3460348accfSeric async_set_state(as, ASR_STATE_HALT); 3470348accfSeric break; 348b44da627Seric } 3490348accfSeric } 350b44da627Seric 351b44da627Seric /* 352b44da627Seric * No address found in the dns packet. The blocking version 353b44da627Seric * reports this as an error. 354b44da627Seric */ 3556d8f29baSeric if ((as->as_type == ASR_GETHOSTBYNAME && 3566d8f29baSeric h->h.h_addr_list[0] == NULL) || 3576d8f29baSeric (as->as_type == ASR_GETHOSTBYADDR && 3586d8f29baSeric h->h.h_name == NULL)) { 359cd22283fSeric free(h); 360b44da627Seric async_set_state(as, ASR_STATE_NEXT_DB); 361b44da627Seric break; 362b44da627Seric } 363b44da627Seric 364cd22283fSeric ar->ar_hostent = &h->h; 365b44da627Seric ar->ar_h_errno = NETDB_SUCCESS; 366b44da627Seric async_set_state(as, ASR_STATE_HALT); 367b44da627Seric break; 368b44da627Seric 369b44da627Seric case ASR_STATE_NOT_FOUND: 370b44da627Seric ar->ar_errno = 0; 3717ffb6b35Seric if (as->as.hostnamadr.subq_h_errno) 3727ffb6b35Seric ar->ar_h_errno = as->as.hostnamadr.subq_h_errno; 3731e1dfc0cSeric else 374b44da627Seric ar->ar_h_errno = HOST_NOT_FOUND; 375b44da627Seric async_set_state(as, ASR_STATE_HALT); 376b44da627Seric break; 377b44da627Seric 378b44da627Seric case ASR_STATE_HALT: 379b44da627Seric if (ar->ar_h_errno) 380b44da627Seric ar->ar_hostent = NULL; 381b44da627Seric else 382b44da627Seric ar->ar_errno = 0; 383b44da627Seric return (ASYNC_DONE); 384b44da627Seric 385b44da627Seric default: 386b44da627Seric ar->ar_errno = EOPNOTSUPP; 387b44da627Seric ar->ar_h_errno = NETDB_INTERNAL; 388b44da627Seric ar->ar_gai_errno = EAI_SYSTEM; 389b44da627Seric async_set_state(as, ASR_STATE_HALT); 390b44da627Seric break; 391b44da627Seric } 392b44da627Seric goto next; 393b44da627Seric } 394b44da627Seric 395b44da627Seric /* 396b32de4eaSeric * Create a hostent from a numeric address string. 397b32de4eaSeric */ 398b32de4eaSeric static struct hostent_ext * 399b32de4eaSeric hostent_from_addr(int family, const char *name, const char *addr) 400b32de4eaSeric { 401b32de4eaSeric struct hostent_ext *h; 402b32de4eaSeric 403b32de4eaSeric if ((h = hostent_alloc(family)) == NULL) 404b32de4eaSeric return (NULL); 405b32de4eaSeric if (hostent_set_cname(h, name, 0) == -1) 406b32de4eaSeric goto fail; 407b32de4eaSeric if (hostent_add_addr(h, addr, h->h.h_length) == -1) 408b32de4eaSeric goto fail; 409b32de4eaSeric return (h); 410b32de4eaSeric fail: 411b32de4eaSeric free(h); 412b32de4eaSeric return (NULL); 413b32de4eaSeric } 414b32de4eaSeric 415b32de4eaSeric /* 416b44da627Seric * Lookup the first matching entry in the hostfile, either by address or by 4170348accfSeric * name depending on reqtype, and build a hostent from the line. 418b44da627Seric */ 419cd22283fSeric static struct hostent_ext * 42080f48568Seric hostent_file_match(FILE *f, int reqtype, int family, const char *data, 42180f48568Seric int datalen) 422b44da627Seric { 4230348accfSeric char *tokens[MAXTOKEN], addr[16]; 424cd22283fSeric struct hostent_ext *h; 425b44da627Seric int n, i; 426b44da627Seric 427b44da627Seric for (;;) { 4280348accfSeric n = asr_parse_namedb_line(f, tokens, MAXTOKEN); 4290348accfSeric if (n == -1) { 4300348accfSeric errno = 0; /* ignore errors reading the file */ 4310348accfSeric return (NULL); 4320348accfSeric } 433b44da627Seric 4340348accfSeric if (reqtype == ASR_GETHOSTBYNAME) { 435b44da627Seric for (i = 1; i < n; i++) { 436b44da627Seric if (strcasecmp(data, tokens[i])) 437b44da627Seric continue; 438b44da627Seric if (inet_pton(family, tokens[0], addr) == 1) 4390348accfSeric goto found; 440b44da627Seric } 4410348accfSeric } else { 442cd22283fSeric if (inet_pton(family, tokens[0], addr) == 1 && 443cd22283fSeric memcmp(addr, data, datalen) == 0) 4440348accfSeric goto found; 4450348accfSeric } 446b44da627Seric } 447b44da627Seric 4480348accfSeric found: 4490348accfSeric if ((h = hostent_alloc(family)) == NULL) 4500348accfSeric return (NULL); 4510348accfSeric if (hostent_set_cname(h, tokens[1], 0) == -1) 4520348accfSeric goto fail; 4530348accfSeric for (i = 2; i < n; i ++) 4540348accfSeric if (hostent_add_alias(h, tokens[i], 0) == -1) 4550348accfSeric goto fail; 456cd22283fSeric if (hostent_add_addr(h, addr, h->h.h_length) == -1) 4570348accfSeric goto fail; 4580348accfSeric return (h); 4590348accfSeric fail: 460836b804aSeric free(h); 4610348accfSeric return (NULL); 462b44da627Seric } 463b44da627Seric 464b44da627Seric /* 465b44da627Seric * Fill the hostent from the given DNS packet. 466b44da627Seric */ 467cd22283fSeric static struct hostent_ext * 4680348accfSeric hostent_from_packet(int reqtype, int family, char *pkt, size_t pktlen) 469b44da627Seric { 470cd22283fSeric struct hostent_ext *h; 471f90bf415Seric struct asr_unpack p; 472f90bf415Seric struct asr_dns_header hdr; 473f90bf415Seric struct asr_dns_query q; 474f90bf415Seric struct asr_dns_rr rr; 4756d8f29baSeric char dname[MAXDNAME]; 4760348accfSeric 4770348accfSeric if ((h = hostent_alloc(family)) == NULL) 4780348accfSeric return (NULL); 479b44da627Seric 4805bd9e5c2Seric asr_unpack_init(&p, pkt, pktlen); 4815bd9e5c2Seric asr_unpack_header(&p, &hdr); 482b44da627Seric for (; hdr.qdcount; hdr.qdcount--) 4835bd9e5c2Seric asr_unpack_query(&p, &q); 4846d8f29baSeric strlcpy(dname, q.q_dname, sizeof(dname)); 4856d8f29baSeric 486b44da627Seric for (; hdr.ancount; hdr.ancount--) { 4875bd9e5c2Seric asr_unpack_rr(&p, &rr); 488b44da627Seric if (rr.rr_class != C_IN) 489b44da627Seric continue; 490b44da627Seric switch (rr.rr_type) { 491b44da627Seric 492b44da627Seric case T_CNAME: 4930348accfSeric if (reqtype == ASR_GETHOSTBYNAME) { 4940348accfSeric if (hostent_add_alias(h, rr.rr_dname, 1) == -1) 4950348accfSeric goto fail; 4960348accfSeric } else { 4976d8f29baSeric if (strcasecmp(rr.rr_dname, dname) == 0) 4986d8f29baSeric strlcpy(dname, rr.rr.cname.cname, 4996d8f29baSeric sizeof(dname)); 5000348accfSeric } 501b44da627Seric break; 502b44da627Seric 503b44da627Seric case T_PTR: 5040348accfSeric if (reqtype != ASR_GETHOSTBYADDR) 5050348accfSeric break; 5066d8f29baSeric if (strcasecmp(rr.rr_dname, dname) != 0) 5076d8f29baSeric continue; 5080348accfSeric if (hostent_set_cname(h, rr.rr.ptr.ptrname, 1) == -1) 509e7643b50Seric hostent_add_alias(h, rr.rr.ptr.ptrname, 1); 510b44da627Seric break; 511b44da627Seric 512b44da627Seric case T_A: 5130348accfSeric if (reqtype != ASR_GETHOSTBYNAME) 514b44da627Seric break; 5150348accfSeric if (family != AF_INET) 5160348accfSeric break; 5170348accfSeric if (hostent_set_cname(h, rr.rr_dname, 1) == -1) 5181a003af8Seric ; 5190348accfSeric if (hostent_add_addr(h, &rr.rr.in_a.addr, 4) == -1) 5200348accfSeric goto fail; 521b44da627Seric break; 522b44da627Seric 523b44da627Seric case T_AAAA: 5240348accfSeric if (reqtype != ASR_GETHOSTBYNAME) 525b44da627Seric break; 5260348accfSeric if (family != AF_INET6) 5270348accfSeric break; 5280348accfSeric if (hostent_set_cname(h, rr.rr_dname, 1) == -1) 5291a003af8Seric ; 5300348accfSeric if (hostent_add_addr(h, &rr.rr.in_aaaa.addr6, 16) == -1) 5310348accfSeric goto fail; 532b44da627Seric break; 533b44da627Seric } 534b44da627Seric } 535b44da627Seric 5360348accfSeric return (h); 5370348accfSeric fail: 538836b804aSeric free(h); 5390348accfSeric return (NULL); 540b44da627Seric } 541b44da627Seric 542cd22283fSeric static struct hostent_ext * 543b44da627Seric hostent_alloc(int family) 544b44da627Seric { 545cd22283fSeric struct hostent_ext *h; 546836b804aSeric size_t alloc; 547b44da627Seric 548cd22283fSeric alloc = sizeof(*h) + 1024; 549836b804aSeric if ((h = calloc(1, alloc)) == NULL) 550b44da627Seric return (NULL); 551b44da627Seric 552cd22283fSeric h->h.h_addrtype = family; 553cd22283fSeric h->h.h_length = (family == AF_INET) ? 4 : 16; 554cd22283fSeric h->h.h_aliases = h->aliases; 555cd22283fSeric h->h.h_addr_list = h->addrs; 556cd22283fSeric h->pos = (char *)(h) + sizeof(*h); 557cd22283fSeric h->end = h->pos + 1024; 558b44da627Seric 559b44da627Seric return (h); 560b44da627Seric } 561b44da627Seric 562b44da627Seric static int 563cd22283fSeric hostent_set_cname(struct hostent_ext *h, const char *name, int isdname) 564b44da627Seric { 565b44da627Seric char buf[MAXDNAME]; 566cd22283fSeric size_t n; 567b44da627Seric 568cd22283fSeric if (h->h.h_name) 569cd22283fSeric return (-1); 570b44da627Seric 571b44da627Seric if (isdname) { 572b44da627Seric asr_strdname(name, buf, sizeof buf); 573b44da627Seric buf[strlen(buf) - 1] = '\0'; 57401b887f7Seric if (!res_hnok(buf)) 57501b887f7Seric return (-1); 576836b804aSeric name = buf; 577b44da627Seric } 578836b804aSeric 579cd22283fSeric n = strlen(name) + 1; 580cd22283fSeric if (h->pos + n >= h->end) 581cd22283fSeric return (-1); 582b44da627Seric 583cd22283fSeric h->h.h_name = h->pos; 584cd22283fSeric memmove(h->pos, name, n); 585cd22283fSeric h->pos += n; 586b44da627Seric return (0); 587b44da627Seric } 588b44da627Seric 589b44da627Seric static int 590cd22283fSeric hostent_add_alias(struct hostent_ext *h, const char *name, int isdname) 591b44da627Seric { 592b44da627Seric char buf[MAXDNAME]; 593cd22283fSeric size_t i, n; 594b44da627Seric 595cd22283fSeric for (i = 0; i < MAXALIASES; i++) 596cd22283fSeric if (h->aliases[i] == NULL) 597b44da627Seric break; 598cd22283fSeric if (i == MAXALIASES) 599cd22283fSeric return (-1); 600b44da627Seric 601b44da627Seric if (isdname) { 602b44da627Seric asr_strdname(name, buf, sizeof buf); 603b44da627Seric buf[strlen(buf)-1] = '\0'; 60401b887f7Seric if (!res_hnok(buf)) 60501b887f7Seric return (-1); 606836b804aSeric name = buf; 607b44da627Seric } 608836b804aSeric 609cd22283fSeric n = strlen(name) + 1; 610cd22283fSeric if (h->pos + n >= h->end) 611cd22283fSeric return (-1); 612b44da627Seric 613cd22283fSeric h->aliases[i] = h->pos; 614cd22283fSeric memmove(h->pos, name, n); 615cd22283fSeric h->pos += n; 616b44da627Seric return (0); 617b44da627Seric } 618b44da627Seric 619b44da627Seric static int 620cd22283fSeric hostent_add_addr(struct hostent_ext *h, const void *addr, size_t size) 621b44da627Seric { 622b44da627Seric int i; 623b44da627Seric 624cd22283fSeric for (i = 0; i < MAXADDRS; i++) 625cd22283fSeric if (h->addrs[i] == NULL) 626b44da627Seric break; 627cd22283fSeric if (i == MAXADDRS) 628cd22283fSeric return (-1); 629b44da627Seric 630cd22283fSeric if (h->pos + size >= h->end) 631cd22283fSeric return (-1); 632836b804aSeric 633cd22283fSeric h->addrs[i] = h->pos; 634cd22283fSeric memmove(h->pos, addr, size); 635cd22283fSeric h->pos += size; 636b44da627Seric return (0); 637b44da627Seric } 638b44da627Seric 6391b26c956Seric #ifdef YP 640cd22283fSeric static struct hostent_ext * 6411b26c956Seric _yp_gethostnamadr(int type, const void *data) 6421b26c956Seric { 6431b26c956Seric static char *domain = NULL; 644cd22283fSeric struct hostent_ext *h = NULL; 6451b26c956Seric const char *name; 6461b26c956Seric char buf[MAXHOSTNAMELEN]; 6471b26c956Seric char *res = NULL; 6481b26c956Seric int r, len; 6491b26c956Seric 6501b26c956Seric if (!domain && _yp_check(&domain) == 0) { 6511b26c956Seric errno = 0; /* ignore yp_bind errors */ 6521b26c956Seric return (NULL); 6531b26c956Seric } 6541b26c956Seric 6551b26c956Seric if (type == ASR_GETHOSTBYNAME) { 6561b26c956Seric name = data; 6571b26c956Seric len = strlen(name); 6581b26c956Seric r = yp_match(domain, "hosts.byname", name, len, &res, &len); 6591b26c956Seric } 6601b26c956Seric else { 6611b26c956Seric if (inet_ntop(AF_INET, data, buf, sizeof buf) == NULL) 6621b26c956Seric return (NULL); 6631b26c956Seric len = strlen(buf); 6641b26c956Seric r = yp_match(domain, "hosts.byaddr", buf, len, &res, &len); 6651b26c956Seric } 6661b26c956Seric if (r == 0) { 6671b26c956Seric h = hostent_from_yp(AF_INET, res); 6681b26c956Seric } else { 6691b26c956Seric errno = 0; /* ignore error if not found */ 6701b26c956Seric } 6711b26c956Seric if (res) 6721b26c956Seric free(res); 6731b26c956Seric return (h); 6741b26c956Seric } 6751b26c956Seric 6761b26c956Seric static int 6771b26c956Seric strsplit(char *line, char **tokens, int ntokens) 6781b26c956Seric { 6791b26c956Seric int ntok; 6801b26c956Seric char *cp, **tp; 6811b26c956Seric 6821b26c956Seric for (cp = line, tp = tokens, ntok = 0; 6831b26c956Seric ntok < ntokens && (*tp = strsep(&cp, " \t")) != NULL; ) 6841b26c956Seric if (**tp != '\0') { 6851b26c956Seric tp++; 6861b26c956Seric ntok++; 6871b26c956Seric } 6881b26c956Seric 6891b26c956Seric return (ntok); 6901b26c956Seric } 6911b26c956Seric 692cd22283fSeric static struct hostent_ext * 6931b26c956Seric hostent_from_yp(int family, char *line) 6941b26c956Seric { 695cd22283fSeric struct hostent_ext *h; 6961b26c956Seric char *next, *tokens[10], addr[IN6ADDRSZ]; 6971b26c956Seric int i, ntok; 6981b26c956Seric 6991b26c956Seric if ((h = hostent_alloc(family)) == NULL) 7001b26c956Seric return (NULL); 7011b26c956Seric 7021b26c956Seric for (next = line; line; line = next) { 7031b26c956Seric if ((next = strchr(line, '\n'))) { 7041b26c956Seric *next = '\0'; 7051b26c956Seric next += 1; 7061b26c956Seric } 7071b26c956Seric ntok = strsplit(line, tokens, 10); 7081b26c956Seric if (ntok < 2) 7091b26c956Seric continue; 7101b26c956Seric if (inet_pton(family, tokens[0], addr) == 1) 7111b26c956Seric hostent_add_addr(h, addr, family == AF_INET ? 7121b26c956Seric INADDRSZ : IN6ADDRSZ); 7131b26c956Seric i = 2; 714cd22283fSeric if (h->h.h_name == NULL) 7151b26c956Seric hostent_set_cname(h, tokens[1], 0); 716cd22283fSeric else if (strcmp(h->h.h_name, tokens[1])) 7171b26c956Seric i = 1; 7181b26c956Seric for (; i < ntok; i++) 7191b26c956Seric hostent_add_alias(h, tokens[i], 0); 7201b26c956Seric } 7211b26c956Seric 722cd22283fSeric if (h->h.h_name == NULL) { 7231b26c956Seric free(h); 7241b26c956Seric return (NULL); 7251b26c956Seric } 7261b26c956Seric 7271b26c956Seric return (h); 7281b26c956Seric } 7291b26c956Seric #endif 730