1 /* $OpenBSD: gethostnamadr_async.c,v 1.42 2015/12/16 16:32:30 deraadt Exp $ */ 2 /* 3 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/socket.h> 20 #include <netinet/in.h> 21 #include <arpa/inet.h> 22 #include <arpa/nameser.h> 23 #include <netdb.h> 24 25 #include <asr.h> 26 #include <ctype.h> 27 #include <errno.h> 28 #include <resolv.h> /* for res_hnok */ 29 #include <stdlib.h> 30 #include <string.h> 31 #include <unistd.h> 32 #include <limits.h> 33 34 #include "asr_private.h" 35 36 #define MAXALIASES 35 37 #define MAXADDRS 35 38 39 struct hostent_ext { 40 struct hostent h; 41 char *aliases[MAXALIASES + 1]; 42 char *addrs[MAXADDRS + 1]; 43 char *end; 44 char *pos; 45 }; 46 47 static int gethostnamadr_async_run(struct asr_query *, struct asr_result *); 48 static struct hostent_ext *hostent_alloc(int); 49 static int hostent_set_cname(struct hostent_ext *, const char *, int); 50 static int hostent_add_alias(struct hostent_ext *, const char *, int); 51 static int hostent_add_addr(struct hostent_ext *, const void *, size_t); 52 static struct hostent_ext *hostent_from_addr(int, const char *, const char *); 53 static struct hostent_ext *hostent_file_match(FILE *, int, int, const char *, 54 int); 55 static struct hostent_ext *hostent_from_packet(int, int, char *, size_t); 56 57 struct asr_query * 58 gethostbyname_async(const char *name, void *asr) 59 { 60 return gethostbyname2_async(name, AF_INET, asr); 61 } 62 DEF_WEAK(gethostbyname_async); 63 64 struct asr_query * 65 gethostbyname2_async(const char *name, int af, void *asr) 66 { 67 struct asr_ctx *ac; 68 struct asr_query *as; 69 70 /* the original segfaults */ 71 if (name == NULL) { 72 errno = EINVAL; 73 return (NULL); 74 } 75 76 ac = _asr_use_resolver(asr); 77 if ((as = _asr_async_new(ac, ASR_GETHOSTBYNAME)) == NULL) 78 goto abort; /* errno set */ 79 as->as_run = gethostnamadr_async_run; 80 81 as->as.hostnamadr.family = af; 82 if (af == AF_INET) 83 as->as.hostnamadr.addrlen = INADDRSZ; 84 else if (af == AF_INET6) 85 as->as.hostnamadr.addrlen = IN6ADDRSZ; 86 as->as.hostnamadr.name = strdup(name); 87 if (as->as.hostnamadr.name == NULL) 88 goto abort; /* errno set */ 89 90 _asr_ctx_unref(ac); 91 return (as); 92 93 abort: 94 if (as) 95 _asr_async_free(as); 96 _asr_ctx_unref(ac); 97 return (NULL); 98 } 99 DEF_WEAK(gethostbyname2_async); 100 101 struct asr_query * 102 gethostbyaddr_async(const void *addr, socklen_t len, int af, void *asr) 103 { 104 struct asr_ctx *ac; 105 struct asr_query *as; 106 107 ac = _asr_use_resolver(asr); 108 as = _gethostbyaddr_async_ctx(addr, len, af, ac); 109 _asr_ctx_unref(ac); 110 111 return (as); 112 } 113 DEF_WEAK(gethostbyaddr_async); 114 115 struct asr_query * 116 _gethostbyaddr_async_ctx(const void *addr, socklen_t len, int af, 117 struct asr_ctx *ac) 118 { 119 struct asr_query *as; 120 121 if ((as = _asr_async_new(ac, ASR_GETHOSTBYADDR)) == NULL) 122 goto abort; /* errno set */ 123 as->as_run = gethostnamadr_async_run; 124 125 as->as.hostnamadr.family = af; 126 as->as.hostnamadr.addrlen = len; 127 if (len > 0) 128 memmove(as->as.hostnamadr.addr, addr, (len > 16) ? 16 : len); 129 130 return (as); 131 132 abort: 133 if (as) 134 _asr_async_free(as); 135 return (NULL); 136 } 137 138 static int 139 gethostnamadr_async_run(struct asr_query *as, struct asr_result *ar) 140 { 141 struct hostent_ext *h; 142 int r, type, saved_errno; 143 FILE *f; 144 char name[MAXDNAME], *data, addr[16], *c; 145 146 next: 147 switch (as->as_state) { 148 149 case ASR_STATE_INIT: 150 151 if (as->as.hostnamadr.family != AF_INET && 152 as->as.hostnamadr.family != AF_INET6) { 153 ar->ar_h_errno = NETDB_INTERNAL; 154 ar->ar_errno = EAFNOSUPPORT; 155 async_set_state(as, ASR_STATE_HALT); 156 break; 157 } 158 159 if ((as->as.hostnamadr.family == AF_INET && 160 as->as.hostnamadr.addrlen != INADDRSZ) || 161 (as->as.hostnamadr.family == AF_INET6 && 162 as->as.hostnamadr.addrlen != IN6ADDRSZ)) { 163 ar->ar_h_errno = NETDB_INTERNAL; 164 ar->ar_errno = EINVAL; 165 async_set_state(as, ASR_STATE_HALT); 166 break; 167 } 168 169 if (as->as_type == ASR_GETHOSTBYNAME) { 170 171 if (as->as.hostnamadr.name[0] == '\0') { 172 ar->ar_h_errno = NO_DATA; 173 async_set_state(as, ASR_STATE_HALT); 174 break; 175 } 176 177 /* Name might be an IP address string */ 178 for (c = as->as.hostnamadr.name; *c; c++) 179 if (!isdigit((unsigned char)*c) && 180 *c != '.' && *c != ':') 181 break; 182 if (*c == 0 && 183 inet_pton(as->as.hostnamadr.family, 184 as->as.hostnamadr.name, addr) == 1) { 185 h = hostent_from_addr(as->as.hostnamadr.family, 186 as->as.hostnamadr.name, addr); 187 if (h == NULL) { 188 ar->ar_errno = errno; 189 ar->ar_h_errno = NETDB_INTERNAL; 190 } 191 else { 192 ar->ar_hostent = &h->h; 193 ar->ar_h_errno = NETDB_SUCCESS; 194 } 195 async_set_state(as, ASR_STATE_HALT); 196 break; 197 } 198 } 199 async_set_state(as, ASR_STATE_NEXT_DB); 200 break; 201 202 case ASR_STATE_NEXT_DB: 203 204 if (_asr_iter_db(as) == -1) { 205 async_set_state(as, ASR_STATE_NOT_FOUND); 206 break; 207 } 208 209 switch (AS_DB(as)) { 210 211 case ASR_DB_DNS: 212 213 /* Create a subquery to do the DNS lookup */ 214 215 if (as->as_type == ASR_GETHOSTBYNAME) { 216 type = (as->as.hostnamadr.family == AF_INET) ? 217 T_A : T_AAAA; 218 as->as.hostnamadr.subq = _res_search_async_ctx( 219 as->as.hostnamadr.name, 220 C_IN, type, as->as_ctx); 221 } else { 222 _asr_addr_as_fqdn(as->as.hostnamadr.addr, 223 as->as.hostnamadr.family, 224 name, sizeof(name)); 225 as->as.hostnamadr.subq = _res_query_async_ctx( 226 name, C_IN, T_PTR, as->as_ctx); 227 } 228 229 if (as->as.hostnamadr.subq == NULL) { 230 ar->ar_errno = errno; 231 ar->ar_h_errno = NETDB_INTERNAL; 232 async_set_state(as, ASR_STATE_HALT); 233 break; 234 } 235 236 async_set_state(as, ASR_STATE_SUBQUERY); 237 break; 238 239 case ASR_DB_FILE: 240 241 /* Try to find a match in the host file */ 242 243 if ((f = fopen(_PATH_HOSTS, "re")) == NULL) 244 break; 245 246 if (as->as_type == ASR_GETHOSTBYNAME) 247 data = as->as.hostnamadr.name; 248 else 249 data = as->as.hostnamadr.addr; 250 251 h = hostent_file_match(f, as->as_type, 252 as->as.hostnamadr.family, data, 253 as->as.hostnamadr.addrlen); 254 saved_errno = errno; 255 fclose(f); 256 errno = saved_errno; 257 258 if (h == NULL) { 259 if (errno) { 260 ar->ar_errno = errno; 261 ar->ar_h_errno = NETDB_INTERNAL; 262 async_set_state(as, ASR_STATE_HALT); 263 } 264 /* otherwise not found */ 265 break; 266 } 267 ar->ar_hostent = &h->h; 268 ar->ar_h_errno = NETDB_SUCCESS; 269 async_set_state(as, ASR_STATE_HALT); 270 break; 271 } 272 break; 273 274 case ASR_STATE_SUBQUERY: 275 276 /* Run the DNS subquery. */ 277 278 if ((r = asr_run(as->as.hostnamadr.subq, ar)) == ASYNC_COND) 279 return (ASYNC_COND); 280 281 /* Done. */ 282 as->as.hostnamadr.subq = NULL; 283 284 if (ar->ar_datalen == -1) { 285 async_set_state(as, ASR_STATE_NEXT_DB); 286 break; 287 } 288 289 /* If we got a packet but no anwser, use the next DB. */ 290 if (ar->ar_count == 0) { 291 free(ar->ar_data); 292 as->as.hostnamadr.subq_h_errno = ar->ar_h_errno; 293 async_set_state(as, ASR_STATE_NEXT_DB); 294 break; 295 } 296 297 /* Read the hostent from the packet. */ 298 299 h = hostent_from_packet(as->as_type, 300 as->as.hostnamadr.family, ar->ar_data, ar->ar_datalen); 301 free(ar->ar_data); 302 if (h == NULL) { 303 ar->ar_errno = errno; 304 ar->ar_h_errno = NETDB_INTERNAL; 305 async_set_state(as, ASR_STATE_HALT); 306 break; 307 } 308 309 if (as->as_type == ASR_GETHOSTBYADDR) { 310 if (hostent_add_addr(h, as->as.hostnamadr.addr, 311 as->as.hostnamadr.addrlen) == -1) { 312 free(h); 313 ar->ar_errno = errno; 314 ar->ar_h_errno = NETDB_INTERNAL; 315 async_set_state(as, ASR_STATE_HALT); 316 break; 317 } 318 } 319 320 /* 321 * No valid hostname or address found in the dns packet. 322 * Ignore it. 323 */ 324 if ((as->as_type == ASR_GETHOSTBYNAME && 325 h->h.h_addr_list[0] == NULL) || 326 h->h.h_name == NULL) { 327 free(h); 328 async_set_state(as, ASR_STATE_NEXT_DB); 329 break; 330 } 331 332 ar->ar_hostent = &h->h; 333 ar->ar_h_errno = NETDB_SUCCESS; 334 async_set_state(as, ASR_STATE_HALT); 335 break; 336 337 case ASR_STATE_NOT_FOUND: 338 ar->ar_errno = 0; 339 if (as->as.hostnamadr.subq_h_errno) 340 ar->ar_h_errno = as->as.hostnamadr.subq_h_errno; 341 else 342 ar->ar_h_errno = HOST_NOT_FOUND; 343 async_set_state(as, ASR_STATE_HALT); 344 break; 345 346 case ASR_STATE_HALT: 347 if (ar->ar_h_errno) 348 ar->ar_hostent = NULL; 349 else 350 ar->ar_errno = 0; 351 return (ASYNC_DONE); 352 353 default: 354 ar->ar_errno = EOPNOTSUPP; 355 ar->ar_h_errno = NETDB_INTERNAL; 356 ar->ar_gai_errno = EAI_SYSTEM; 357 async_set_state(as, ASR_STATE_HALT); 358 break; 359 } 360 goto next; 361 } 362 363 /* 364 * Create a hostent from a numeric address string. 365 */ 366 static struct hostent_ext * 367 hostent_from_addr(int family, const char *name, const char *addr) 368 { 369 struct hostent_ext *h; 370 371 if ((h = hostent_alloc(family)) == NULL) 372 return (NULL); 373 if (hostent_set_cname(h, name, 0) == -1) 374 goto fail; 375 if (hostent_add_addr(h, addr, h->h.h_length) == -1) 376 goto fail; 377 return (h); 378 fail: 379 free(h); 380 return (NULL); 381 } 382 383 /* 384 * Lookup the first matching entry in the hostfile, either by address or by 385 * name depending on reqtype, and build a hostent from the line. 386 */ 387 static struct hostent_ext * 388 hostent_file_match(FILE *f, int reqtype, int family, const char *data, 389 int datalen) 390 { 391 char *tokens[MAXTOKEN], addr[16], buf[BUFSIZ + 1]; 392 struct hostent_ext *h; 393 int n, i; 394 395 for (;;) { 396 n = _asr_parse_namedb_line(f, tokens, MAXTOKEN, buf, sizeof(buf)); 397 if (n == -1) { 398 errno = 0; /* ignore errors reading the file */ 399 return (NULL); 400 } 401 402 /* there must be an address and at least one name */ 403 if (n < 2) 404 continue; 405 406 if (reqtype == ASR_GETHOSTBYNAME) { 407 for (i = 1; i < n; i++) { 408 if (strcasecmp(data, tokens[i])) 409 continue; 410 if (inet_pton(family, tokens[0], addr) == 1) 411 goto found; 412 } 413 } else { 414 if (inet_pton(family, tokens[0], addr) == 1 && 415 memcmp(addr, data, datalen) == 0) 416 goto found; 417 } 418 } 419 420 found: 421 if ((h = hostent_alloc(family)) == NULL) 422 return (NULL); 423 if (hostent_set_cname(h, tokens[1], 0) == -1) 424 goto fail; 425 for (i = 2; i < n; i ++) 426 if (hostent_add_alias(h, tokens[i], 0) == -1) 427 goto fail; 428 if (hostent_add_addr(h, addr, h->h.h_length) == -1) 429 goto fail; 430 return (h); 431 fail: 432 free(h); 433 return (NULL); 434 } 435 436 /* 437 * Fill the hostent from the given DNS packet. 438 */ 439 static struct hostent_ext * 440 hostent_from_packet(int reqtype, int family, char *pkt, size_t pktlen) 441 { 442 struct hostent_ext *h; 443 struct asr_unpack p; 444 struct asr_dns_header hdr; 445 struct asr_dns_query q; 446 struct asr_dns_rr rr; 447 char dname[MAXDNAME]; 448 449 if ((h = hostent_alloc(family)) == NULL) 450 return (NULL); 451 452 _asr_unpack_init(&p, pkt, pktlen); 453 _asr_unpack_header(&p, &hdr); 454 for (; hdr.qdcount; hdr.qdcount--) 455 _asr_unpack_query(&p, &q); 456 strlcpy(dname, q.q_dname, sizeof(dname)); 457 458 for (; hdr.ancount; hdr.ancount--) { 459 _asr_unpack_rr(&p, &rr); 460 if (rr.rr_class != C_IN) 461 continue; 462 switch (rr.rr_type) { 463 464 case T_CNAME: 465 if (reqtype == ASR_GETHOSTBYNAME) { 466 if (hostent_add_alias(h, rr.rr_dname, 1) == -1) 467 goto fail; 468 } else { 469 if (strcasecmp(rr.rr_dname, dname) == 0) 470 strlcpy(dname, rr.rr.cname.cname, 471 sizeof(dname)); 472 } 473 break; 474 475 case T_PTR: 476 if (reqtype != ASR_GETHOSTBYADDR) 477 break; 478 if (strcasecmp(rr.rr_dname, dname) != 0) 479 continue; 480 if (hostent_set_cname(h, rr.rr.ptr.ptrname, 1) == -1) 481 hostent_add_alias(h, rr.rr.ptr.ptrname, 1); 482 break; 483 484 case T_A: 485 if (reqtype != ASR_GETHOSTBYNAME) 486 break; 487 if (family != AF_INET) 488 break; 489 if (hostent_set_cname(h, rr.rr_dname, 1) == -1) 490 ; 491 if (hostent_add_addr(h, &rr.rr.in_a.addr, 4) == -1) 492 goto fail; 493 break; 494 495 case T_AAAA: 496 if (reqtype != ASR_GETHOSTBYNAME) 497 break; 498 if (family != AF_INET6) 499 break; 500 if (hostent_set_cname(h, rr.rr_dname, 1) == -1) 501 ; 502 if (hostent_add_addr(h, &rr.rr.in_aaaa.addr6, 16) == -1) 503 goto fail; 504 break; 505 } 506 } 507 508 return (h); 509 fail: 510 free(h); 511 return (NULL); 512 } 513 514 static struct hostent_ext * 515 hostent_alloc(int family) 516 { 517 struct hostent_ext *h; 518 size_t alloc; 519 520 alloc = sizeof(*h) + 1024; 521 if ((h = calloc(1, alloc)) == NULL) 522 return (NULL); 523 524 h->h.h_addrtype = family; 525 h->h.h_length = (family == AF_INET) ? 4 : 16; 526 h->h.h_aliases = h->aliases; 527 h->h.h_addr_list = h->addrs; 528 h->pos = (char *)(h) + sizeof(*h); 529 h->end = h->pos + 1024; 530 531 return (h); 532 } 533 534 static int 535 hostent_set_cname(struct hostent_ext *h, const char *name, int isdname) 536 { 537 char buf[MAXDNAME]; 538 size_t n; 539 540 if (h->h.h_name) 541 return (-1); 542 543 if (isdname) { 544 _asr_strdname(name, buf, sizeof buf); 545 buf[strlen(buf) - 1] = '\0'; 546 if (!res_hnok(buf)) 547 return (-1); 548 name = buf; 549 } 550 551 n = strlen(name) + 1; 552 if (h->pos + n >= h->end) 553 return (-1); 554 555 h->h.h_name = h->pos; 556 memmove(h->pos, name, n); 557 h->pos += n; 558 return (0); 559 } 560 561 static int 562 hostent_add_alias(struct hostent_ext *h, const char *name, int isdname) 563 { 564 char buf[MAXDNAME]; 565 size_t i, n; 566 567 for (i = 0; i < MAXALIASES; i++) 568 if (h->aliases[i] == NULL) 569 break; 570 if (i == MAXALIASES) 571 return (0); 572 573 if (isdname) { 574 _asr_strdname(name, buf, sizeof buf); 575 buf[strlen(buf)-1] = '\0'; 576 if (!res_hnok(buf)) 577 return (-1); 578 name = buf; 579 } 580 581 n = strlen(name) + 1; 582 if (h->pos + n >= h->end) 583 return (0); 584 585 h->aliases[i] = h->pos; 586 memmove(h->pos, name, n); 587 h->pos += n; 588 return (0); 589 } 590 591 static int 592 hostent_add_addr(struct hostent_ext *h, const void *addr, size_t size) 593 { 594 int i; 595 596 for (i = 0; i < MAXADDRS; i++) 597 if (h->addrs[i] == NULL) 598 break; 599 if (i == MAXADDRS) 600 return (0); 601 602 if (h->pos + size >= h->end) 603 return (0); 604 605 h->addrs[i] = h->pos; 606 memmove(h->pos, addr, size); 607 h->pos += size; 608 return (0); 609 } 610