1*cd373078Sop /* $OpenBSD: gethostnamadr_async.c,v 1.50 2024/09/03 18:20:35 op 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> 23d216d6b1Seric #include <netdb.h> 24b44da627Seric 25d216d6b1Seric #include <asr.h> 26b32de4eaSeric #include <ctype.h> 2780f48568Seric #include <errno.h> 2801b887f7Seric #include <resolv.h> /* for res_hnok */ 2980f48568Seric #include <stdlib.h> 3080f48568Seric #include <string.h> 3180f48568Seric #include <unistd.h> 32e7e445a1Sderaadt #include <limits.h> 33e7e445a1Sderaadt 34b44da627Seric #include "asr_private.h" 35b44da627Seric 365712b4f1Sbrynet #define MAXALIASES 35 375712b4f1Sbrynet #define MAXADDRS 35 38b44da627Seric 39cd22283fSeric struct hostent_ext { 40cd22283fSeric struct hostent h; 41cd22283fSeric char *aliases[MAXALIASES + 1]; 42cd22283fSeric char *addrs[MAXADDRS + 1]; 43cd22283fSeric char *end; 44cd22283fSeric char *pos; 45cd22283fSeric }; 46836b804aSeric 47b5afe704Sschwarze struct netent_ext { 48b5afe704Sschwarze struct netent n; 49b5afe704Sschwarze char *aliases[MAXALIASES + 1]; 50b5afe704Sschwarze char *end; 51b5afe704Sschwarze char *pos; 52b5afe704Sschwarze }; 53b5afe704Sschwarze 545be03f8fSeric static int gethostnamadr_async_run(struct asr_query *, struct asr_result *); 55cd22283fSeric static struct hostent_ext *hostent_alloc(int); 56cd22283fSeric static int hostent_set_cname(struct hostent_ext *, const char *, int); 57cd22283fSeric static int hostent_add_alias(struct hostent_ext *, const char *, int); 58cd22283fSeric static int hostent_add_addr(struct hostent_ext *, const void *, size_t); 59b32de4eaSeric static struct hostent_ext *hostent_from_addr(int, const char *, const char *); 60cd22283fSeric static struct hostent_ext *hostent_file_match(FILE *, int, int, const char *, 61cd22283fSeric int); 62cd22283fSeric static struct hostent_ext *hostent_from_packet(int, int, char *, size_t); 63b5afe704Sschwarze static void netent_from_hostent(struct asr_result *ar); 64b44da627Seric 655be03f8fSeric struct asr_query * 665be03f8fSeric gethostbyname_async(const char *name, void *asr) 67b44da627Seric { 68b44da627Seric return gethostbyname2_async(name, AF_INET, asr); 69b44da627Seric } 705826fd8cSguenther DEF_WEAK(gethostbyname_async); 71b44da627Seric 725be03f8fSeric struct asr_query * 735be03f8fSeric gethostbyname2_async(const char *name, int af, void *asr) 74b44da627Seric { 75b44da627Seric struct asr_ctx *ac; 765be03f8fSeric struct asr_query *as; 77b44da627Seric 78b44da627Seric /* the original segfaults */ 79b44da627Seric if (name == NULL) { 80b44da627Seric errno = EINVAL; 81b44da627Seric return (NULL); 82b44da627Seric } 83b44da627Seric 84253ef892Sderaadt ac = _asr_use_resolver(asr); 85253ef892Sderaadt 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 98253ef892Sderaadt _asr_ctx_unref(ac); 99b44da627Seric return (as); 100b44da627Seric 101b44da627Seric abort: 102b44da627Seric if (as) 103253ef892Sderaadt _asr_async_free(as); 104253ef892Sderaadt _asr_ctx_unref(ac); 105b44da627Seric return (NULL); 106b44da627Seric } 1075826fd8cSguenther DEF_WEAK(gethostbyname2_async); 108b44da627Seric 1095be03f8fSeric struct asr_query * 1105be03f8fSeric gethostbyaddr_async(const void *addr, socklen_t len, int af, void *asr) 111b44da627Seric { 112b44da627Seric struct asr_ctx *ac; 1135be03f8fSeric struct asr_query *as; 114b44da627Seric 115253ef892Sderaadt ac = _asr_use_resolver(asr); 116253ef892Sderaadt as = _gethostbyaddr_async_ctx(addr, len, af, ac); 117253ef892Sderaadt _asr_ctx_unref(ac); 118b44da627Seric 119b44da627Seric return (as); 120b44da627Seric } 1215826fd8cSguenther DEF_WEAK(gethostbyaddr_async); 122b44da627Seric 1235be03f8fSeric struct asr_query * 124253ef892Sderaadt _gethostbyaddr_async_ctx(const void *addr, socklen_t len, int af, 125b44da627Seric struct asr_ctx *ac) 126b44da627Seric { 1275be03f8fSeric struct asr_query *as; 128b44da627Seric 129253ef892Sderaadt if ((as = _asr_async_new(ac, ASR_GETHOSTBYADDR)) == NULL) 130b44da627Seric goto abort; /* errno set */ 131b44da627Seric as->as_run = gethostnamadr_async_run; 132b44da627Seric 133b44da627Seric as->as.hostnamadr.family = af; 134b44da627Seric as->as.hostnamadr.addrlen = len; 135b44da627Seric if (len > 0) 136b44da627Seric memmove(as->as.hostnamadr.addr, addr, (len > 16) ? 16 : len); 137b44da627Seric 138b44da627Seric return (as); 139b44da627Seric 140b44da627Seric abort: 141b44da627Seric if (as) 142253ef892Sderaadt _asr_async_free(as); 143b44da627Seric return (NULL); 144b44da627Seric } 145b44da627Seric 146b44da627Seric static int 1475be03f8fSeric gethostnamadr_async_run(struct asr_query *as, struct asr_result *ar) 148b44da627Seric { 149cd22283fSeric struct hostent_ext *h; 150cd22283fSeric int r, type, saved_errno; 151b44da627Seric FILE *f; 1526a7a3d64Seric char name[MAXDNAME], *data, addr[16], *c; 153b44da627Seric 154b44da627Seric next: 155b44da627Seric switch (as->as_state) { 156b44da627Seric 157b44da627Seric case ASR_STATE_INIT: 158b44da627Seric 159b44da627Seric if (as->as.hostnamadr.family != AF_INET && 160b44da627Seric as->as.hostnamadr.family != AF_INET6) { 161b44da627Seric ar->ar_h_errno = NETDB_INTERNAL; 162b44da627Seric ar->ar_errno = EAFNOSUPPORT; 163b44da627Seric async_set_state(as, ASR_STATE_HALT); 164b44da627Seric break; 165b44da627Seric } 166b44da627Seric 167b44da627Seric if ((as->as.hostnamadr.family == AF_INET && 168b44da627Seric as->as.hostnamadr.addrlen != INADDRSZ) || 169b44da627Seric (as->as.hostnamadr.family == AF_INET6 && 170b44da627Seric as->as.hostnamadr.addrlen != IN6ADDRSZ)) { 171b44da627Seric ar->ar_h_errno = NETDB_INTERNAL; 172b44da627Seric ar->ar_errno = EINVAL; 173b44da627Seric async_set_state(as, ASR_STATE_HALT); 174b44da627Seric break; 175b44da627Seric } 176b44da627Seric 177b32de4eaSeric if (as->as_type == ASR_GETHOSTBYNAME) { 178ab50be5eSeric 179ab50be5eSeric if (as->as.hostnamadr.name[0] == '\0') { 180ab50be5eSeric ar->ar_h_errno = NO_DATA; 181ab50be5eSeric async_set_state(as, ASR_STATE_HALT); 182ab50be5eSeric break; 183ab50be5eSeric } 184ab50be5eSeric 185ab50be5eSeric /* Name might be an IP address string */ 186b32de4eaSeric for (c = as->as.hostnamadr.name; *c; c++) 187dfe5467eSderaadt if (!isdigit((unsigned char)*c) && 188dfe5467eSderaadt *c != '.' && *c != ':') 189b32de4eaSeric break; 190b32de4eaSeric if (*c == 0 && 191b32de4eaSeric inet_pton(as->as.hostnamadr.family, 192b32de4eaSeric as->as.hostnamadr.name, addr) == 1) { 193b32de4eaSeric h = hostent_from_addr(as->as.hostnamadr.family, 194b32de4eaSeric as->as.hostnamadr.name, addr); 195b32de4eaSeric if (h == NULL) { 196b32de4eaSeric ar->ar_errno = errno; 197b32de4eaSeric ar->ar_h_errno = NETDB_INTERNAL; 198b32de4eaSeric } 199b32de4eaSeric else { 200b32de4eaSeric ar->ar_hostent = &h->h; 201b32de4eaSeric ar->ar_h_errno = NETDB_SUCCESS; 202b32de4eaSeric } 203b32de4eaSeric async_set_state(as, ASR_STATE_HALT); 204b44da627Seric break; 205b8fce260Sflorian } 206b8fce260Sflorian 2071b04c78cSflorian if (!hnok_lenient(as->as.hostnamadr.name)) { 20806579650Sflorian ar->ar_h_errno = NETDB_INTERNAL; 20906579650Sflorian ar->ar_errno = EINVAL; 2101b04c78cSflorian async_set_state(as, ASR_STATE_HALT); 211b8fce260Sflorian break; 212b44da627Seric } 213373da8abSflorian 214373da8abSflorian /* 215373da8abSflorian * If hostname is "localhost" or falls within the 216373da8abSflorian * ".localhost." domain, use local address. 217373da8abSflorian * RFC 6761, 6.3: 218373da8abSflorian * 3. Name resolution APIs and libraries SHOULD 219373da8abSflorian * recognize localhost names as special and SHOULD 220373da8abSflorian * always return the IP loopback address for address 221373da8abSflorian * queries and negative responses for all other query 222373da8abSflorian * types. Name resolution APIs SHOULD NOT send queries 223373da8abSflorian * for localhost names to their configured caching DNS 224373da8abSflorian * server(s). 225373da8abSflorian */ 226373da8abSflorian 227373da8abSflorian if (_asr_is_localhost(as->as.hostnamadr.name)) { 228373da8abSflorian inet_pton(as->as.hostnamadr.family, 229373da8abSflorian as->as.hostnamadr.family == AF_INET ? 230373da8abSflorian "127.0.0.1" : "::1", addr); 231373da8abSflorian h = hostent_from_addr(as->as.hostnamadr.family, 232373da8abSflorian as->as.hostnamadr.name, addr); 233373da8abSflorian if (h == NULL) { 234373da8abSflorian ar->ar_errno = errno; 235373da8abSflorian ar->ar_h_errno = NETDB_INTERNAL; 236373da8abSflorian } 237373da8abSflorian else { 238373da8abSflorian ar->ar_hostent = &h->h; 239373da8abSflorian ar->ar_h_errno = NETDB_SUCCESS; 240373da8abSflorian } 241373da8abSflorian async_set_state(as, ASR_STATE_HALT); 242373da8abSflorian break; 243373da8abSflorian } 244b44da627Seric } 245b44da627Seric async_set_state(as, ASR_STATE_NEXT_DB); 246b44da627Seric break; 247b44da627Seric 248b44da627Seric case ASR_STATE_NEXT_DB: 249b44da627Seric 250253ef892Sderaadt if (_asr_iter_db(as) == -1) { 251b44da627Seric async_set_state(as, ASR_STATE_NOT_FOUND); 252b44da627Seric break; 253b44da627Seric } 254b44da627Seric 255b44da627Seric switch (AS_DB(as)) { 256b44da627Seric 257b44da627Seric case ASR_DB_DNS: 258b44da627Seric 259b44da627Seric /* Create a subquery to do the DNS lookup */ 260b44da627Seric 261b44da627Seric if (as->as_type == ASR_GETHOSTBYNAME) { 262b44da627Seric type = (as->as.hostnamadr.family == AF_INET) ? 263b44da627Seric T_A : T_AAAA; 264f6f51dadSeric as->as_subq = _res_search_async_ctx( 2651e1dfc0cSeric as->as.hostnamadr.name, 266c5221d45Seric C_IN, type, as->as_ctx); 267b44da627Seric } else { 268253ef892Sderaadt _asr_addr_as_fqdn(as->as.hostnamadr.addr, 269b44da627Seric as->as.hostnamadr.family, 2706a7a3d64Seric name, sizeof(name)); 271f6f51dadSeric as->as_subq = _res_query_async_ctx( 2726a7a3d64Seric name, C_IN, T_PTR, as->as_ctx); 273b44da627Seric } 274b44da627Seric 275f6f51dadSeric if (as->as_subq == NULL) { 276b44da627Seric ar->ar_errno = errno; 277b44da627Seric ar->ar_h_errno = NETDB_INTERNAL; 278b44da627Seric async_set_state(as, ASR_STATE_HALT); 279b44da627Seric break; 280b44da627Seric } 281b44da627Seric 282b44da627Seric async_set_state(as, ASR_STATE_SUBQUERY); 283b44da627Seric break; 284b44da627Seric 285b44da627Seric case ASR_DB_FILE: 286b44da627Seric 287b44da627Seric /* Try to find a match in the host file */ 288b44da627Seric 289d2d7f9c9Seric if ((f = fopen(_PATH_HOSTS, "re")) == NULL) 290b44da627Seric break; 291b44da627Seric 292c126605fSderaadt if (as->as_type == ASR_GETHOSTBYNAME) 2931e1dfc0cSeric data = as->as.hostnamadr.name; 294b44da627Seric else 295b44da627Seric data = as->as.hostnamadr.addr; 296b44da627Seric 297cd22283fSeric h = hostent_file_match(f, as->as_type, 2980348accfSeric as->as.hostnamadr.family, data, 2990348accfSeric as->as.hostnamadr.addrlen); 300cd22283fSeric saved_errno = errno; 301b44da627Seric fclose(f); 302cd22283fSeric errno = saved_errno; 3030348accfSeric 304cd22283fSeric if (h == NULL) { 3050348accfSeric if (errno) { 306b44da627Seric ar->ar_errno = errno; 307b44da627Seric ar->ar_h_errno = NETDB_INTERNAL; 308b44da627Seric async_set_state(as, ASR_STATE_HALT); 3090348accfSeric } 3100348accfSeric /* otherwise not found */ 311b44da627Seric break; 312b44da627Seric } 313cd22283fSeric ar->ar_hostent = &h->h; 314b44da627Seric ar->ar_h_errno = NETDB_SUCCESS; 315b44da627Seric async_set_state(as, ASR_STATE_HALT); 316b44da627Seric break; 317b44da627Seric } 318b44da627Seric break; 319b44da627Seric 320b44da627Seric case ASR_STATE_SUBQUERY: 321b44da627Seric 322b44da627Seric /* Run the DNS subquery. */ 323b44da627Seric 324f6f51dadSeric if ((r = asr_run(as->as_subq, ar)) == ASYNC_COND) 325b44da627Seric return (ASYNC_COND); 326b44da627Seric 327b44da627Seric /* Done. */ 328f6f51dadSeric as->as_subq = NULL; 329b44da627Seric 330e45d70c8Smartijn /* 331e45d70c8Smartijn * We either got no packet or a packet without an answer. 332*cd373078Sop * Safeguard the h_errno and use the next DB. 333e45d70c8Smartijn */ 334b44da627Seric if (ar->ar_count == 0) { 335b44da627Seric free(ar->ar_data); 3367ffb6b35Seric as->as.hostnamadr.subq_h_errno = ar->ar_h_errno; 337b44da627Seric async_set_state(as, ASR_STATE_NEXT_DB); 338b44da627Seric break; 339b44da627Seric } 340b44da627Seric 341b44da627Seric /* Read the hostent from the packet. */ 3420348accfSeric 343cd22283fSeric h = hostent_from_packet(as->as_type, 3440348accfSeric as->as.hostnamadr.family, ar->ar_data, ar->ar_datalen); 3450348accfSeric free(ar->ar_data); 346cd22283fSeric if (h == NULL) { 347b44da627Seric ar->ar_errno = errno; 348b44da627Seric ar->ar_h_errno = NETDB_INTERNAL; 349b44da627Seric async_set_state(as, ASR_STATE_HALT); 350b44da627Seric break; 351b44da627Seric } 352b44da627Seric 353b44da627Seric if (as->as_type == ASR_GETHOSTBYADDR) { 354cd22283fSeric if (hostent_add_addr(h, as->as.hostnamadr.addr, 3550348accfSeric as->as.hostnamadr.addrlen) == -1) { 356cd22283fSeric free(h); 3570348accfSeric ar->ar_errno = errno; 3580348accfSeric ar->ar_h_errno = NETDB_INTERNAL; 3590348accfSeric async_set_state(as, ASR_STATE_HALT); 3600348accfSeric break; 361b44da627Seric } 3620348accfSeric } 363b44da627Seric 364b44da627Seric /* 3650d7b84a8Seric * No valid hostname or address found in the dns packet. 3660d7b84a8Seric * Ignore it. 367b44da627Seric */ 3686d8f29baSeric if ((as->as_type == ASR_GETHOSTBYNAME && 3696d8f29baSeric h->h.h_addr_list[0] == NULL) || 3700d7b84a8Seric h->h.h_name == NULL) { 371cd22283fSeric free(h); 372b44da627Seric async_set_state(as, ASR_STATE_NEXT_DB); 373b44da627Seric break; 374b44da627Seric } 375b44da627Seric 376cd22283fSeric ar->ar_hostent = &h->h; 377b44da627Seric ar->ar_h_errno = NETDB_SUCCESS; 378b44da627Seric async_set_state(as, ASR_STATE_HALT); 379b44da627Seric break; 380b44da627Seric 381b44da627Seric case ASR_STATE_NOT_FOUND: 382b44da627Seric ar->ar_errno = 0; 3837ffb6b35Seric if (as->as.hostnamadr.subq_h_errno) 3847ffb6b35Seric ar->ar_h_errno = as->as.hostnamadr.subq_h_errno; 3851e1dfc0cSeric else 386b44da627Seric ar->ar_h_errno = HOST_NOT_FOUND; 387b44da627Seric async_set_state(as, ASR_STATE_HALT); 388b44da627Seric break; 389b44da627Seric 390b44da627Seric case ASR_STATE_HALT: 391b5afe704Sschwarze if (ar->ar_h_errno == NETDB_SUCCESS && 392b5afe704Sschwarze as->as_flags & ASYNC_GETNET) 393b5afe704Sschwarze netent_from_hostent(ar); 394b5afe704Sschwarze if (ar->ar_h_errno) { 395b44da627Seric ar->ar_hostent = NULL; 396b5afe704Sschwarze ar->ar_netent = NULL; 397b5afe704Sschwarze } else 398b44da627Seric ar->ar_errno = 0; 399b44da627Seric return (ASYNC_DONE); 400b44da627Seric 401b44da627Seric default: 402b44da627Seric ar->ar_errno = EOPNOTSUPP; 403b44da627Seric ar->ar_h_errno = NETDB_INTERNAL; 404b44da627Seric ar->ar_gai_errno = EAI_SYSTEM; 405b44da627Seric async_set_state(as, ASR_STATE_HALT); 406b44da627Seric break; 407b44da627Seric } 408b44da627Seric goto next; 409b44da627Seric } 410b44da627Seric 411b44da627Seric /* 412b32de4eaSeric * Create a hostent from a numeric address string. 413b32de4eaSeric */ 414b32de4eaSeric static struct hostent_ext * 415b32de4eaSeric hostent_from_addr(int family, const char *name, const char *addr) 416b32de4eaSeric { 417b32de4eaSeric struct hostent_ext *h; 418b32de4eaSeric 419b32de4eaSeric if ((h = hostent_alloc(family)) == NULL) 420b32de4eaSeric return (NULL); 421b32de4eaSeric if (hostent_set_cname(h, name, 0) == -1) 422b32de4eaSeric goto fail; 423b32de4eaSeric if (hostent_add_addr(h, addr, h->h.h_length) == -1) 424b32de4eaSeric goto fail; 425b32de4eaSeric return (h); 426b32de4eaSeric fail: 427b32de4eaSeric free(h); 428b32de4eaSeric return (NULL); 429b32de4eaSeric } 430b32de4eaSeric 431b32de4eaSeric /* 432b44da627Seric * Lookup the first matching entry in the hostfile, either by address or by 4330348accfSeric * name depending on reqtype, and build a hostent from the line. 434b44da627Seric */ 435cd22283fSeric static struct hostent_ext * 43680f48568Seric hostent_file_match(FILE *f, int reqtype, int family, const char *data, 43780f48568Seric int datalen) 438b44da627Seric { 439f108579bSeric char *tokens[MAXTOKEN], addr[16], buf[BUFSIZ + 1]; 440cd22283fSeric struct hostent_ext *h; 441b44da627Seric int n, i; 442b44da627Seric 443b44da627Seric for (;;) { 444253ef892Sderaadt n = _asr_parse_namedb_line(f, tokens, MAXTOKEN, buf, sizeof(buf)); 4450348accfSeric if (n == -1) { 4460348accfSeric errno = 0; /* ignore errors reading the file */ 4470348accfSeric return (NULL); 4480348accfSeric } 449b44da627Seric 450f94f01beSeric /* there must be an address and at least one name */ 451f94f01beSeric if (n < 2) 452f94f01beSeric continue; 453f94f01beSeric 4540348accfSeric if (reqtype == ASR_GETHOSTBYNAME) { 455b44da627Seric for (i = 1; i < n; i++) { 456b44da627Seric if (strcasecmp(data, tokens[i])) 457b44da627Seric continue; 458b44da627Seric if (inet_pton(family, tokens[0], addr) == 1) 4590348accfSeric goto found; 460b44da627Seric } 4610348accfSeric } else { 462cd22283fSeric if (inet_pton(family, tokens[0], addr) == 1 && 463cd22283fSeric memcmp(addr, data, datalen) == 0) 4640348accfSeric goto found; 4650348accfSeric } 466b44da627Seric } 467b44da627Seric 4680348accfSeric found: 4690348accfSeric if ((h = hostent_alloc(family)) == NULL) 4700348accfSeric return (NULL); 4710348accfSeric if (hostent_set_cname(h, tokens[1], 0) == -1) 4720348accfSeric goto fail; 4730348accfSeric for (i = 2; i < n; i ++) 4740348accfSeric if (hostent_add_alias(h, tokens[i], 0) == -1) 4750348accfSeric goto fail; 476cd22283fSeric if (hostent_add_addr(h, addr, h->h.h_length) == -1) 4770348accfSeric goto fail; 4780348accfSeric return (h); 4790348accfSeric fail: 480836b804aSeric free(h); 4810348accfSeric return (NULL); 482b44da627Seric } 483b44da627Seric 484b44da627Seric /* 485b44da627Seric * Fill the hostent from the given DNS packet. 486b44da627Seric */ 487cd22283fSeric static struct hostent_ext * 4880348accfSeric hostent_from_packet(int reqtype, int family, char *pkt, size_t pktlen) 489b44da627Seric { 490cd22283fSeric struct hostent_ext *h; 491f90bf415Seric struct asr_unpack p; 492f90bf415Seric struct asr_dns_header hdr; 493f90bf415Seric struct asr_dns_query q; 494f90bf415Seric struct asr_dns_rr rr; 4956d8f29baSeric char dname[MAXDNAME]; 4960348accfSeric 4970348accfSeric if ((h = hostent_alloc(family)) == NULL) 4980348accfSeric return (NULL); 499b44da627Seric 500253ef892Sderaadt _asr_unpack_init(&p, pkt, pktlen); 501253ef892Sderaadt _asr_unpack_header(&p, &hdr); 502b44da627Seric for (; hdr.qdcount; hdr.qdcount--) 503253ef892Sderaadt _asr_unpack_query(&p, &q); 5046d8f29baSeric strlcpy(dname, q.q_dname, sizeof(dname)); 5056d8f29baSeric 506b44da627Seric for (; hdr.ancount; hdr.ancount--) { 507253ef892Sderaadt _asr_unpack_rr(&p, &rr); 508b44da627Seric if (rr.rr_class != C_IN) 509b44da627Seric continue; 510b44da627Seric switch (rr.rr_type) { 511b44da627Seric 512b44da627Seric case T_CNAME: 5130348accfSeric if (reqtype == ASR_GETHOSTBYNAME) { 5140348accfSeric if (hostent_add_alias(h, rr.rr_dname, 1) == -1) 5150348accfSeric goto fail; 5160348accfSeric } else { 5176d8f29baSeric if (strcasecmp(rr.rr_dname, dname) == 0) 5186d8f29baSeric strlcpy(dname, rr.rr.cname.cname, 5196d8f29baSeric sizeof(dname)); 5200348accfSeric } 521b44da627Seric break; 522b44da627Seric 523b44da627Seric case T_PTR: 5240348accfSeric if (reqtype != ASR_GETHOSTBYADDR) 5250348accfSeric break; 5266d8f29baSeric if (strcasecmp(rr.rr_dname, dname) != 0) 5276d8f29baSeric continue; 5280348accfSeric if (hostent_set_cname(h, rr.rr.ptr.ptrname, 1) == -1) 529e7643b50Seric hostent_add_alias(h, rr.rr.ptr.ptrname, 1); 530b44da627Seric break; 531b44da627Seric 532b44da627Seric case T_A: 5330348accfSeric if (reqtype != ASR_GETHOSTBYNAME) 534b44da627Seric break; 5350348accfSeric if (family != AF_INET) 5360348accfSeric break; 5370348accfSeric if (hostent_set_cname(h, rr.rr_dname, 1) == -1) 5381a003af8Seric ; 5390348accfSeric if (hostent_add_addr(h, &rr.rr.in_a.addr, 4) == -1) 5400348accfSeric goto fail; 541b44da627Seric break; 542b44da627Seric 543b44da627Seric case T_AAAA: 5440348accfSeric if (reqtype != ASR_GETHOSTBYNAME) 545b44da627Seric break; 5460348accfSeric if (family != AF_INET6) 5470348accfSeric break; 5480348accfSeric if (hostent_set_cname(h, rr.rr_dname, 1) == -1) 5491a003af8Seric ; 5500348accfSeric if (hostent_add_addr(h, &rr.rr.in_aaaa.addr6, 16) == -1) 5510348accfSeric goto fail; 552b44da627Seric break; 553b44da627Seric } 554b44da627Seric } 555b44da627Seric 5560348accfSeric return (h); 5570348accfSeric fail: 558836b804aSeric free(h); 5590348accfSeric return (NULL); 560b44da627Seric } 561b44da627Seric 562cd22283fSeric static struct hostent_ext * 563b44da627Seric hostent_alloc(int family) 564b44da627Seric { 565cd22283fSeric struct hostent_ext *h; 566836b804aSeric size_t alloc; 567b44da627Seric 568cd22283fSeric alloc = sizeof(*h) + 1024; 569836b804aSeric if ((h = calloc(1, alloc)) == NULL) 570b44da627Seric return (NULL); 571b44da627Seric 572cd22283fSeric h->h.h_addrtype = family; 573cd22283fSeric h->h.h_length = (family == AF_INET) ? 4 : 16; 574cd22283fSeric h->h.h_aliases = h->aliases; 575cd22283fSeric h->h.h_addr_list = h->addrs; 576cd22283fSeric h->pos = (char *)(h) + sizeof(*h); 577cd22283fSeric h->end = h->pos + 1024; 578b44da627Seric 579b44da627Seric return (h); 580b44da627Seric } 581b44da627Seric 582b44da627Seric static int 583cd22283fSeric hostent_set_cname(struct hostent_ext *h, const char *name, int isdname) 584b44da627Seric { 585b44da627Seric char buf[MAXDNAME]; 586cd22283fSeric size_t n; 587b44da627Seric 588cd22283fSeric if (h->h.h_name) 589cd22283fSeric return (-1); 590b44da627Seric 591b44da627Seric if (isdname) { 592253ef892Sderaadt _asr_strdname(name, buf, sizeof buf); 593b44da627Seric buf[strlen(buf) - 1] = '\0'; 59401b887f7Seric if (!res_hnok(buf)) 59501b887f7Seric return (-1); 596836b804aSeric name = buf; 597b44da627Seric } 598836b804aSeric 599cd22283fSeric n = strlen(name) + 1; 600cd22283fSeric if (h->pos + n >= h->end) 601cd22283fSeric return (-1); 602b44da627Seric 603cd22283fSeric h->h.h_name = h->pos; 604cd22283fSeric memmove(h->pos, name, n); 605cd22283fSeric h->pos += n; 606b44da627Seric return (0); 607b44da627Seric } 608b44da627Seric 609b44da627Seric static int 610cd22283fSeric hostent_add_alias(struct hostent_ext *h, const char *name, int isdname) 611b44da627Seric { 612b44da627Seric char buf[MAXDNAME]; 613cd22283fSeric size_t i, n; 614b44da627Seric 615cd22283fSeric for (i = 0; i < MAXALIASES; i++) 616cd22283fSeric if (h->aliases[i] == NULL) 617b44da627Seric break; 618cd22283fSeric if (i == MAXALIASES) 6195712b4f1Sbrynet return (0); 620b44da627Seric 621b44da627Seric if (isdname) { 622253ef892Sderaadt _asr_strdname(name, buf, sizeof buf); 623b44da627Seric buf[strlen(buf)-1] = '\0'; 62401b887f7Seric if (!res_hnok(buf)) 62501b887f7Seric return (-1); 626836b804aSeric name = buf; 627b44da627Seric } 628836b804aSeric 629cd22283fSeric n = strlen(name) + 1; 630cd22283fSeric if (h->pos + n >= h->end) 6315712b4f1Sbrynet return (0); 632b44da627Seric 633cd22283fSeric h->aliases[i] = h->pos; 634cd22283fSeric memmove(h->pos, name, n); 635cd22283fSeric h->pos += n; 636b44da627Seric return (0); 637b44da627Seric } 638b44da627Seric 639b44da627Seric static int 640cd22283fSeric hostent_add_addr(struct hostent_ext *h, const void *addr, size_t size) 641b44da627Seric { 642b44da627Seric int i; 643b44da627Seric 644cd22283fSeric for (i = 0; i < MAXADDRS; i++) 645cd22283fSeric if (h->addrs[i] == NULL) 646b44da627Seric break; 647cd22283fSeric if (i == MAXADDRS) 6485712b4f1Sbrynet return (0); 649b44da627Seric 650cd22283fSeric if (h->pos + size >= h->end) 6515712b4f1Sbrynet return (0); 652836b804aSeric 653cd22283fSeric h->addrs[i] = h->pos; 654cd22283fSeric memmove(h->pos, addr, size); 655cd22283fSeric h->pos += size; 656b44da627Seric return (0); 657b44da627Seric } 658b5afe704Sschwarze 659b5afe704Sschwarze static void 660b5afe704Sschwarze netent_from_hostent(struct asr_result *ar) 661b5afe704Sschwarze { 662b5afe704Sschwarze struct in_addr *addr; 663b5afe704Sschwarze struct netent_ext *n; 664b5afe704Sschwarze struct hostent_ext *h; 665b5afe704Sschwarze char **na, **ha; 666b5afe704Sschwarze size_t sz; 667b5afe704Sschwarze 668b5afe704Sschwarze /* Allocate and initialize the output. */ 669b5afe704Sschwarze if ((n = calloc(1, sizeof(*n) + 1024)) == NULL) { 670b5afe704Sschwarze ar->ar_h_errno = NETDB_INTERNAL; 671b5afe704Sschwarze ar->ar_errno = errno; 672b5afe704Sschwarze goto out; 673b5afe704Sschwarze } 674b5afe704Sschwarze n->pos = (char *)(n) + sizeof(*n); 675b5afe704Sschwarze n->end = n->pos + 1024; 676b5afe704Sschwarze n->n.n_name = n->pos; 677b5afe704Sschwarze n->n.n_aliases = n->aliases; 678b5afe704Sschwarze 679b5afe704Sschwarze /* Copy the fixed-size data. */ 680b5afe704Sschwarze h = (struct hostent_ext *)ar->ar_hostent; 681b5afe704Sschwarze addr = (struct in_addr *)h->h.h_addr; 682b5afe704Sschwarze n->n.n_net = ntohl(addr->s_addr); 683b5afe704Sschwarze n->n.n_addrtype = h->h.h_addrtype; 684b5afe704Sschwarze 685b5afe704Sschwarze /* Copy the network name. */ 686b5afe704Sschwarze sz = strlen(h->h.h_name) + 1; 687b5afe704Sschwarze memcpy(n->pos, h->h.h_name, sz); 688b5afe704Sschwarze n->pos += sz; 689b5afe704Sschwarze 690b5afe704Sschwarze /* 691b5afe704Sschwarze * Copy the aliases. 692b5afe704Sschwarze * No overflow check is needed because we are merely copying 693b5afe704Sschwarze * a part of the data from a structure of the same size. 694b5afe704Sschwarze */ 695b5afe704Sschwarze na = n->aliases; 696b5afe704Sschwarze for (ha = h->aliases; *ha != NULL; ha++) { 697b5afe704Sschwarze sz = strlen(*ha) + 1; 698b5afe704Sschwarze memcpy(n->pos, *ha, sz); 699b5afe704Sschwarze *na++ = n->pos; 700b5afe704Sschwarze n->pos += sz; 701b5afe704Sschwarze } 702b5afe704Sschwarze *na = NULL; 703b5afe704Sschwarze 704b5afe704Sschwarze /* Handle the return values. */ 705b5afe704Sschwarze ar->ar_netent = &n->n; 706b5afe704Sschwarze out: 707b5afe704Sschwarze free(ar->ar_hostent); 708b5afe704Sschwarze ar->ar_hostent = NULL; 709b5afe704Sschwarze } 710