1/* 2 * arlib.c (C)opyright 1993 Darren Reed. All rights reserved. 3 * This file may not be distributed without the author's permission in any 4 * shape or form. The author takes no responsibility for any damage or loss 5 * of property which results from the use of this software. 6 */ 7#ifndef lint 8static char sccsid[] = "@(#)arlib.c 1.9 6/5/93 (C)opyright 1992 Darren \ 9Reed. ASYNC DNS"; 10#endif 11 12#include <stdio.h> 13#include <fcntl.h> 14#include <signal.h> 15#include <sys/types.h> 16#include <sys/time.h> 17#include <sys/socket.h> 18#include <netinet/in.h> 19#include "netdb.h" 20#include "arpa/nameser.h" 21#include <resolv.h> 22#include "arlib.h" 23#include "arplib.h" 24 25extern int errno, h_errno; 26static char ar_hostbuf[65], ar_domainname[65]; 27static char ar_dot[] = "."; 28static int ar_resfd = -1, ar_vc = 0; 29static struct reslist *ar_last, *ar_first; 30 31/* 32 * Statistics structure. 33 */ 34static struct resstats { 35 int re_errors; 36 int re_nu_look; 37 int re_na_look; 38 int re_replies; 39 int re_requests; 40 int re_resends; 41 int re_sent; 42 int re_timeouts; 43} ar_reinfo; 44 45static int do_query_name(/* struct resinfo *, char *, struct reslist * */); 46static int do_query_number(/* struct resinfo *, char *, struct reslist * */); 47static int ar_resend_query(/* struct reslist * */); 48 49/* 50 * ar_init 51 * 52 * Initializes the various ARLIB internal varilables and related DNS 53 * options for res_init(). 54 * 55 * Returns 0 or the socket opened for use with talking to name servers 56 * if 0 is passed or ARES_INITSOCK is set. 57 */ 58int ar_init(op) 59int op; 60{ 61 int ret = 0; 62 63 if (op & ARES_INITLIST) 64 { 65 bzero(&ar_reinfo, sizeof(ar_reinfo)); 66 ar_first = ar_last = NULL; 67 } 68 69 if (op & ARES_CALLINIT && !(_res.options & RES_INIT)) 70 { 71 ret = res_init(); 72 (void)strcpy(ar_domainname, ar_dot); 73 (void)strncat(ar_domainname, _res.defdname, 74 sizeof(ar_domainname)-2); 75 } 76 77 if (op & ARES_INITSOCK) 78 ret = ar_resfd = ar_open(); 79 80 if (op & ARES_INITDEBG) 81 _res.options |= RES_DEBUG; 82 83 if (op == 0) 84 ret = ar_resfd; 85 86 return ret; 87} 88 89 90/* 91 * ar_open 92 * 93 * Open a socket to talk to a name server with. 94 * Check _res.options to see if we use a TCP or UDP socket. 95 */ 96int ar_open() 97{ 98 if (ar_resfd == -1) 99 { 100 if (_res.options & RES_USEVC) 101 { 102 struct sockaddr_in *sip; 103 int i; 104 105 sip = _res.NS_ADDR_LIST; /* was _res.nsaddr_list */ 106 ar_vc = 1; 107 ar_resfd = socket(AF_INET, SOCK_STREAM, 0); 108 109 /* 110 * Try each name server listed in sequence until we 111 * succeed or run out. 112 */ 113 while (connect(ar_resfd, (struct sockaddr *)sip++, 114 sizeof(struct sockaddr))) 115 { 116 (void)close(ar_resfd); 117 ar_resfd = -1; 118 if (i >= _res.nscount) 119 break; 120 ar_resfd = socket(AF_INET, SOCK_STREAM, 0); 121 } 122 } 123 else 124 ar_resfd = socket(AF_INET, SOCK_DGRAM, 0); 125 } 126 if (ar_resfd >= 0) 127 { /* Need one of these two here - and it MUST work!! */ 128 int flags; 129 130 if ((flags = fcntl(ar_resfd, F_GETFL, 0)) != -1) 131#ifdef O_NONBLOCK 132 if (fcntl(ar_resfd, F_SETFL, flags|O_NONBLOCK) == -1) 133#else 134# ifdef O_NDELAY 135 if (fcntl(ar_resfd, F_SETFL, flags|O_NDELAY) == -1) 136# else 137# ifdef FNDELAY 138 if (fcntl(ar_resfd, F_SETFL, flags|FNDELAY) == -1) 139# endif 140# endif 141#endif 142 { 143 (void)close(ar_resfd); 144 ar_resfd = -1; 145 } 146 } 147 return ar_resfd; 148} 149 150 151/* 152 * ar_close 153 * 154 * Closes and flags the ARLIB socket as closed. 155 */ 156void ar_close() 157{ 158 (void)close(ar_resfd); 159 ar_resfd = -1; 160 return; 161} 162 163 164/* 165 * ar_add_request 166 * 167 * Add a new DNS query to the end of the query list. 168 */ 169static int ar_add_request(new) 170struct reslist *new; 171{ 172 if (!new) 173 return -1; 174 if (!ar_first) 175 ar_first = ar_last = new; 176 else { 177 ar_last->re_next = new; 178 ar_last = new; 179 } 180 new->re_next = NULL; 181 ar_reinfo.re_requests++; 182 return 0; 183} 184 185 186/* 187 * ar_remrequest 188 * 189 * Remove a request from the list. This must also free any memory that has 190 * been allocated for temporary storage of DNS results. 191 * 192 * Returns -1 if there are anyy problems removing the requested structure 193 * or 0 if the remove is successful. 194 */ 195static int ar_remrequest(old) 196struct reslist *old; 197{ 198 register struct reslist *rptr, *r2ptr; 199 register char **s; 200 201 if (!old) 202 return -1; 203 for (rptr = ar_first, r2ptr = NULL; rptr; rptr = rptr->re_next) 204 { 205 if (rptr == old) 206 break; 207 r2ptr = rptr; 208 } 209 210 if (!rptr) 211 return -1; 212 if (rptr == ar_first) 213 ar_first = ar_first->re_next; 214 else if (rptr == ar_last) 215 { 216 if (ar_last = r2ptr) 217 ar_last->re_next = NULL; 218 } 219 else 220 r2ptr->re_next = rptr->re_next; 221 222 if (!ar_first) 223 ar_last = ar_first; 224 225#ifdef ARLIB_DEBUG 226 ar_dump_hostent("ar_remrequest:", rptr->re_he); 227#endif 228 229 if (rptr->re_he.h_name) 230 (void)free(rptr->re_he.h_name); 231 if (s = rptr->re_he.h_aliases) 232 for (; *s; s++) 233 (void)free(*s); 234 if (rptr->re_rinfo.ri_ptr) 235 (void)free(rptr->re_rinfo.ri_ptr); 236 (void)free(rptr); 237 238 return 0; 239} 240 241 242/* 243 * ar_make_request 244 * 245 * Create a DNS query recorded for the request being made and place it on the 246 * current list awaiting replies. Initialization of the record with set 247 * values should also be done. 248 */ 249static struct reslist *ar_make_request(resi) 250register struct resinfo *resi; 251{ 252 register struct reslist *rptr; 253 register struct resinfo *rp; 254 255 rptr = (struct reslist *)calloc(1, sizeof(struct reslist)); 256 rp = &rptr->re_rinfo; 257 258 rptr->re_next = NULL; /* where NULL is non-zero ;) */ 259 rptr->re_sentat = time(NULL); 260 rptr->re_retries = _res.retry; 261 rptr->re_sends = 1; 262 rptr->re_resend = 1; 263 rptr->re_timeout = rptr->re_sentat + _res.retrans; 264 rptr->re_he.h_name = NULL; 265 rptr->re_he.h_addrtype = AF_INET; 266 rptr->re_he.h_aliases[0] = NULL; 267 rp->ri_ptr = resi->ri_ptr; 268 rp->ri_size = resi->ri_size; 269 270 (void)ar_add_request(rptr); 271 272 return rptr; 273} 274 275 276/* 277 * ar_timeout 278 * 279 * Remove queries from the list which have been there too long without 280 * being resolved. 281 */ 282long ar_timeout(now, info, size) 283time_t now; 284char *info; 285int size; 286{ 287 register struct reslist *rptr, *r2ptr; 288 register long next = 0; 289 290 for (rptr = ar_first, r2ptr = NULL; rptr; rptr = r2ptr) 291 { 292 r2ptr = rptr->re_next; 293 if (now >= rptr->re_timeout) 294 { 295 /* 296 * If the timeout for the query has been exceeded, 297 * then resend the query if we still have some 298 * 'retry credit' and reset the timeout. If we have 299 * used it all up, then remove the request. 300 */ 301 if (--rptr->re_retries <= 0) 302 { 303 ar_reinfo.re_timeouts++; 304 if (info && rptr->re_rinfo.ri_ptr) 305 bcopy(rptr->re_rinfo.ri_ptr, info, 306 MIN(rptr->re_rinfo.ri_size, 307 size)); 308 (void)ar_remrequest(rptr); 309 return now; 310 } 311 else 312 { 313 rptr->re_sends++; 314 rptr->re_sentat = now; 315 rptr->re_timeout = now + _res.retrans; 316 (void)ar_resend_query(rptr); 317 } 318 } 319 if (!next || rptr->re_timeout < next) 320 next = rptr->re_timeout; 321 } 322 return next; 323} 324 325 326/* 327 * ar_send_res_msg 328 * 329 * When sending queries to nameservers listed in the resolv.conf file, 330 * don't send a query to every one, but increase the number sent linearly 331 * to match the number of resends. This increase only occurs if there are 332 * multiple nameserver entries in the resolv.conf file. 333 * The return value is the number of messages successfully sent to 334 * nameservers or -1 if no successful sends. 335 */ 336static int ar_send_res_msg(msg, len, rcount) 337char *msg; 338int len, rcount; 339{ 340 register int i; 341 int sent = 0; 342 343 if (!msg) 344 return -1; 345 346 rcount = (_res.nscount > rcount) ? rcount : _res.nscount; 347 if (_res.options & RES_PRIMARY) 348 rcount = 1; 349 350 if (ar_vc) 351 { 352 ar_reinfo.re_sent++; 353 sent++; 354 if (write(ar_resfd, msg, len) == -1) 355 { 356 int errtmp = errno; 357 (void)close(ar_resfd); 358 errno = errtmp; 359 ar_resfd = -1; 360 } 361 } 362 else 363 for (i = 0; i < rcount; i++) 364 { 365 if (sendto(ar_resfd, msg, len, 0, 366 (struct sockaddr *)&(_res.NS_ADDR_LIST[i]), 367 sizeof(struct sockaddr_in)) == len) 368 { 369 ar_reinfo.re_sent++; 370 sent++; 371 } 372 } 373 return (sent) ? sent : -1; 374} 375 376 377/* 378 * ar_find_id 379 * 380 * find a dns query record by the id (id is determined by dn_mkquery) 381 */ 382static struct reslist *ar_find_id(id) 383int id; 384{ 385 register struct reslist *rptr; 386 387 for (rptr = ar_first; rptr; rptr = rptr->re_next) 388 if (rptr->re_id == id) 389 return rptr; 390 return NULL; 391} 392 393 394/* 395 * ar_delete 396 * 397 * Delete a request from the waiting list if it has a data pointer which 398 * matches the one passed. 399 */ 400int ar_delete(ptr, size) 401char *ptr; 402int size; 403{ 404 register struct reslist *rptr; 405 register struct reslist *r2ptr; 406 int removed = 0; 407 408 for (rptr = ar_first; rptr; rptr = r2ptr) 409 { 410 r2ptr = rptr->re_next; 411 if (rptr->re_rinfo.ri_ptr && ptr && size && 412 bcmp(rptr->re_rinfo.ri_ptr, ptr, size) == 0) 413 { 414 (void)ar_remrequest(rptr); 415 removed++; 416 } 417 } 418 return removed; 419} 420 421 422/* 423 * ar_query_name 424 * 425 * generate a query based on class, type and name. 426 */ 427static int ar_query_name(name, class, type, rptr) 428char *name; 429int class, type; 430struct reslist *rptr; 431{ 432 static char buf[MAXPACKET]; 433 int r,s,a; 434 HEADER *hptr; 435 436 bzero(buf, sizeof(buf)); 437 r = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, 438 buf, sizeof(buf)); 439 if (r <= 0) 440 { 441 h_errno = NO_RECOVERY; 442 return r; 443 } 444 hptr = (HEADER *)buf; 445 rptr->re_id = ntohs(hptr->id); 446 447 s = ar_send_res_msg(buf, r, rptr->re_sends); 448 449 if (s == -1) 450 { 451 h_errno = TRY_AGAIN; 452 return -1; 453 } 454 else 455 rptr->re_sent += s; 456 return 0; 457} 458 459 460/* 461 * ar_gethostbyname 462 * 463 * Replacement library function call to gethostbyname(). This one, however, 464 * doesn't return the record being looked up but just places the query in the 465 * queue to await answers. 466 */ 467int ar_gethostbyname(name, info, size) 468char *name; 469char *info; 470int size; 471{ 472 char host[65]; 473 struct resinfo resi; 474 register struct resinfo *rp = &resi; 475 476 if (size && info) 477 { 478 rp->ri_ptr = (char *)malloc(size); 479 bcopy(info, rp->ri_ptr, size); 480 rp->ri_size = size; 481 } 482 else 483 bzero((char *)rp, sizeof(resi)); 484 ar_reinfo.re_na_look++; 485 (void)strncpy(host, name, 64); 486 host[64] = '\0'; 487 488 return (do_query_name(rp, host, NULL)); 489} 490 491 492static int do_query_name(resi, name, rptr) 493struct resinfo *resi; 494char *name; 495register struct reslist *rptr; 496{ 497 char hname[65]; 498 int len; 499 500 len = strlen((char *)strncpy(hname, name, sizeof(hname)-1)); 501 502 if (rptr && (hname[len-1] != '.')) 503 { 504 (void)strncat(hname, ar_dot, sizeof(hname)-len-1); 505 /* 506 * NOTE: The logical relationship between DNSRCH and DEFNAMES 507 * is implies. ie no DEFNAES, no DNSRCH. 508 */ 509 if (_res.options & (RES_DEFNAMES|RES_DNSRCH) == 510 (RES_DEFNAMES|RES_DNSRCH)) 511 { 512 if (_res.dnsrch[rptr->re_srch]) 513 (void)strncat(hname, _res.dnsrch[rptr->re_srch], 514 sizeof(hname) - ++len -1); 515 } 516 else if (_res.options & RES_DEFNAMES) 517 (void)strncat(hname, ar_domainname, sizeof(hname) - len -1); 518 } 519 520 /* 521 * Store the name passed as the one to lookup and generate other host 522 * names to pass onto the nameserver(s) for lookups. 523 */ 524 if (!rptr) 525 { 526 rptr = ar_make_request(resi); 527 rptr->re_type = T_A; 528 (void)strncpy(rptr->re_name, name, sizeof(rptr->re_name)-1); 529 } 530 return (ar_query_name(hname, C_IN, T_A, rptr)); 531} 532 533 534/* 535 * ar_gethostbyaddr 536 * 537 * Generates a query for a given IP address. 538 */ 539int ar_gethostbyaddr(addr, info, size) 540char *addr; 541char *info; 542int size; 543{ 544 struct resinfo resi; 545 register struct resinfo *rp = &resi; 546 547 if (size && info) 548 { 549 rp->ri_ptr = (char *)malloc(size); 550 bcopy(info, rp->ri_ptr, size); 551 rp->ri_size = size; 552 } 553 else 554 bzero((char *)rp, sizeof(resi)); 555 ar_reinfo.re_nu_look++; 556 return (do_query_number(rp, addr, NULL)); 557} 558 559 560/* 561 * do_query_number 562 * 563 * Use this to do reverse IP# lookups. 564 */ 565static int do_query_number(resi, numb, rptr) 566struct resinfo *resi; 567char *numb; 568register struct reslist *rptr; 569{ 570 register unsigned char *cp; 571 static char ipbuf[32]; 572 573 /* 574 * Generate name in the "in-addr.arpa" domain. No addings bits to this 575 * name to get more names to query!. 576 */ 577 cp = (unsigned char *)numb; 578 (void)sprintf(ipbuf,"%u.%u.%u.%u.in-addr.arpa.", 579 (unsigned int)(cp[3]), (unsigned int)(cp[2]), 580 (unsigned int)(cp[1]), (unsigned int)(cp[0])); 581 582 if (!rptr) 583 { 584 rptr = ar_make_request(resi); 585 rptr->re_type = T_PTR; 586 rptr->re_he.h_length = sizeof(struct in_addr); 587 bcopy(numb, (char *)&rptr->re_addr, rptr->re_he.h_length); 588 bcopy(numb, (char *)&rptr->re_he.h_addr_list[0].s_addr, 589 rptr->re_he.h_length); 590 } 591 return (ar_query_name(ipbuf, C_IN, T_PTR, rptr)); 592} 593 594 595/* 596 * ar_resent_query 597 * 598 * resends a query. 599 */ 600static int ar_resend_query(rptr) 601struct reslist *rptr; 602{ 603 if (!rptr->re_resend) 604 return -1; 605 606 switch(rptr->re_type) 607 { 608 case T_PTR: 609 ar_reinfo.re_resends++; 610 return do_query_number(NULL, &rptr->re_addr, rptr); 611 case T_A: 612 ar_reinfo.re_resends++; 613 return do_query_name(NULL, rptr->re_name, rptr); 614 default: 615 break; 616 } 617 618 return -1; 619} 620 621 622/* 623 * ar_procanswer 624 * 625 * process an answer received from a nameserver. 626 */ 627static int ar_procanswer(rptr, hptr, buf, eob) 628struct reslist *rptr; 629char *buf, *eob; 630HEADER *hptr; 631{ 632 char *cp, **alias, *s; 633 int class, type, dlen, len, ans = 0, n, i; 634 u_int32_t ttl, dr, *adr; 635 struct hent *hp; 636 637 cp = buf + sizeof(HEADER); 638 adr = (u_int32_t *)rptr->re_he.h_addr_list; 639 640 while (*adr) 641 adr++; 642 643 alias = rptr->re_he.h_aliases; 644 while (*alias) 645 alias++; 646 647 hp = &rptr->re_he; 648 649 650 /* 651 * Skip over the original question. 652 */ 653 while (hptr->qdcount-- > 0) 654 cp += dn_skipname(cp, eob) + QFIXEDSZ; 655 /* 656 * proccess each answer sent to us. blech. 657 */ 658 while (hptr->ancount-- > 0 && cp < eob) { 659 n = dn_expand(buf, eob, cp, ar_hostbuf, sizeof(ar_hostbuf)); 660 cp += n; 661 if (n <= 0) 662 return ans; 663 664 ans++; 665 /* 666 * 'skip' past the general dns crap (ttl, class, etc) to get 667 * the pointer to the right spot. Some of thse are actually 668 * useful so its not a good idea to skip past in one big jump. 669 */ 670 type = (int)_getshort(cp); 671 cp += sizeof(short); 672 class = (int)_getshort(cp); 673 cp += sizeof(short); 674 ttl = (u_int32_t)_getlong(cp); 675 cp += sizeof(u_int32_t); 676 dlen = (int)_getshort(cp); 677 cp += sizeof(short); 678 rptr->re_type = type; 679 680 switch(type) 681 { 682 case T_A : 683 rptr->re_he.h_length = dlen; 684 if (ans == 1) 685 rptr->re_he.h_addrtype=(class == C_IN) ? 686 AF_INET : AF_UNSPEC; 687 if (dlen != sizeof(dr)) 688 { 689 h_errno = TRY_AGAIN; 690 continue; 691 } 692 bcopy(cp, &dr, dlen); 693 *adr++ = dr; 694 *adr = 0; 695 cp += dlen; 696 len = strlen(ar_hostbuf); 697 if (!rptr->re_he.h_name) 698 { 699 rptr->re_he.h_name = (char *)malloc(len+1); 700 if (!rptr->re_he.h_name) 701 break; 702 (void)strcpy(rptr->re_he.h_name, ar_hostbuf); 703 } 704 break; 705 case T_PTR : 706 if ((n = dn_expand(buf, eob, cp, ar_hostbuf, 707 sizeof(ar_hostbuf) )) < 0) 708 { 709 cp += n; 710 continue; 711 } 712 cp += n; 713 len = strlen(ar_hostbuf)+1; 714 /* 715 * copy the returned hostname into the host name 716 * or alias field if there is a known hostname 717 * already. 718 */ 719 if (!rptr->re_he.h_name) 720 { 721 rptr->re_he.h_name = (char *)malloc(len); 722 if (!rptr->re_he.h_name) 723 break; 724 (void)strcpy(rptr->re_he.h_name, ar_hostbuf); 725 } 726 else 727 { 728 *alias = (char *)malloc(len); 729 if (!*alias) 730 return -1; 731 (void)strcpy(*alias++, ar_hostbuf); 732 *alias = NULL; 733 } 734 break; 735 case T_CNAME : 736 cp += dlen; 737 if (alias >= &(rptr->re_he.h_aliases[MAXALIASES-1])) 738 continue; 739 n = strlen(ar_hostbuf)+1; 740 *alias = (char *)malloc(n); 741 if (!*alias) 742 return -1; 743 (void)strcpy(*alias++, ar_hostbuf); 744 *alias = NULL; 745 break; 746 default : 747 break; 748 } 749 } 750 751 return ans; 752} 753 754 755/* 756 * ar_answer 757 * 758 * Get an answer from a DNS server and process it. If a query is found to 759 * which no answer has been given to yet, copy its 'info' structure back 760 * to where "reip" points and return a pointer to the hostent structure. 761 */ 762struct hostent *ar_answer(reip, size) 763char *reip; 764int size; 765{ 766 static char ar_rcvbuf[sizeof(HEADER) + MAXPACKET]; 767 static struct hostent ar_host; 768 769 register HEADER *hptr; 770 register struct reslist *rptr = NULL; 771 register struct hostent *hp; 772 register char **s; 773 unsigned long *adr; 774 int rc, i, n, a; 775 776 rc = recv(ar_resfd, ar_rcvbuf, sizeof(ar_rcvbuf), 0); 777 if (rc <= 0) 778 goto getres_err; 779 780 ar_reinfo.re_replies++; 781 hptr = (HEADER *)ar_rcvbuf; 782 /* 783 * convert things to be in the right order. 784 */ 785 hptr->id = ntohs(hptr->id); 786 hptr->ancount = ntohs(hptr->ancount); 787 hptr->arcount = ntohs(hptr->arcount); 788 hptr->nscount = ntohs(hptr->nscount); 789 hptr->qdcount = ntohs(hptr->qdcount); 790 /* 791 * response for an id which we have already received an answer for 792 * just ignore this response. 793 */ 794 rptr = ar_find_id(hptr->id); 795 if (!rptr) 796 goto getres_err; 797 798 if ((hptr->rcode != NOERROR) || (hptr->ancount == 0)) 799 { 800 switch (hptr->rcode) 801 { 802 case NXDOMAIN: 803 h_errno = HOST_NOT_FOUND; 804 break; 805 case SERVFAIL: 806 h_errno = TRY_AGAIN; 807 break; 808 case NOERROR: 809 h_errno = NO_DATA; 810 break; 811 case FORMERR: 812 case NOTIMP: 813 case REFUSED: 814 default: 815 h_errno = NO_RECOVERY; 816 break; 817 } 818 ar_reinfo.re_errors++; 819 /* 820 ** If a bad error was returned, we stop here and dont send 821 ** send any more (no retries granted). 822 */ 823 if (h_errno != TRY_AGAIN) 824 { 825 rptr->re_resend = 0; 826 rptr->re_retries = 0; 827 } 828 goto getres_err; 829 } 830 831 a = ar_procanswer(rptr, hptr, ar_rcvbuf, ar_rcvbuf+rc); 832 833 if ((rptr->re_type == T_PTR) && (_res.options & RES_CHECKPTR)) 834 { 835 /* 836 * For reverse lookups on IP#'s, lookup the name that is given 837 * for the ip# and return with that as the official result. 838 * -avalon 839 */ 840 rptr->re_type = T_A; 841 /* 842 * Clean out the list of addresses already set, even though 843 * there should only be one :) 844 */ 845 adr = (unsigned long *)rptr->re_he.h_addr_list; 846 while (*adr) 847 *adr++ = 0L; 848 /* 849 * Lookup the name that we were given for the ip# 850 */ 851 ar_reinfo.re_na_look++; 852 (void)strncpy(rptr->re_name, rptr->re_he.h_name, 853 sizeof(rptr->re_name)-1); 854 rptr->re_he.h_name = NULL; 855 rptr->re_retries = _res.retry; 856 rptr->re_sends = 1; 857 rptr->re_resend = 1; 858 rptr->re_he.h_name = NULL; 859 ar_reinfo.re_na_look++; 860 (void)ar_query_name(rptr->re_name, C_IN, T_A, rptr); 861 return NULL; 862 } 863 864 if (reip && rptr->re_rinfo.ri_ptr && size) 865 bcopy(rptr->re_rinfo.ri_ptr, reip, 866 MIN(rptr->re_rinfo.ri_size, size)); 867 /* 868 * Clean up structure from previous usage. 869 */ 870 hp = &ar_host; 871#ifdef ARLIB_DEBUG 872 ar_dump_hostent("ar_answer: previous usage", hp); 873#endif 874 875 if (hp->h_name) 876 (void)free(hp->h_name); 877 if (s = hp->h_aliases) 878 { 879 while (*s) 880 (void)free(*s++); 881 (void)free(hp->h_aliases); 882 } 883 if (s = hp->h_addr_list) 884 { 885 /* 886 * Only free once since we allocated space for 887 * address in one big chunk. 888 */ 889 (void)free(*s); 890 (void)free(hp->h_addr_list); 891 } 892 bzero((char *)hp, sizeof(*hp)); 893 894 /* 895 * Setup and copy details for the structure we return a pointer to. 896 */ 897 hp->h_addrtype = AF_INET; 898 hp->h_length = sizeof(struct in_addr); 899 if(rptr->re_he.h_name) 900 { 901 hp->h_name = (char *)malloc(strlen(rptr->re_he.h_name)+1); 902 if(!hp->h_name) 903 { 904#ifdef ARLIB_DEBUG 905 fprintf(stderr, "no memory for hostname\n"); 906#endif 907 h_errno = TRY_AGAIN; 908 goto getres_err; 909 } 910 (void)strcpy(hp->h_name, rptr->re_he.h_name); 911 } 912#ifdef ARLIB_DEBUG 913 ar_dump_hostent("ar_answer: (snap) store name", hp); 914#endif 915 916 /* 917 * Count IP#'s. 918 */ 919 for (i = 0, n = 0; i < MAXADDRS; i++, n++) 920 if (!rptr->re_he.h_addr_list[i].s_addr) 921 break; 922 s = hp->h_addr_list = (char **)malloc((n + 1) * sizeof(char *)); 923 if (n) 924 { 925 *s = (char *)malloc(n * sizeof(struct in_addr)); 926 if(!*s) 927 { 928#ifdef ARLIB_DEBUG 929 fprintf(stderr, "no memory for IP#'s (%d)\n", n); 930#endif 931 h_errno = TRY_AGAIN; 932 goto getres_err; 933 } 934 bcopy((char *)&rptr->re_he.h_addr_list[0].s_addr, *s, 935 sizeof(struct in_addr)); 936 s++; 937 for (i = 1; i < n; i++, s++) 938 { 939 *s = hp->h_addr + i * sizeof(struct in_addr); 940 bcopy((char *)&rptr->re_he.h_addr_list[i].s_addr, *s, 941 sizeof(struct in_addr)); 942 } 943 } 944 *s = NULL; 945#ifdef ARLIB_DEBUG 946 ar_dump_hostent("ar_answer: (snap) store IP#'s", hp); 947#endif 948 949 /* 950 * Count CNAMEs 951 */ 952 for (i = 0, n = 0; i < MAXADDRS; i++, n++) 953 if (!rptr->re_he.h_aliases[i]) 954 break; 955 s = hp->h_aliases = (char **)malloc((n + 1) * sizeof(char *)); 956 if (!s) 957 { 958#ifdef ARLIB_DEBUG 959 fprintf(stderr, "no memory for aliases (%d)\n", n); 960#endif 961 h_errno = TRY_AGAIN; 962 goto getres_err; 963 } 964 for (i = 0; i < n; i++) 965 { 966 *s++ = rptr->re_he.h_aliases[i]; 967 rptr->re_he.h_aliases[i] = NULL; 968 } 969 *s = NULL; 970#ifdef ARLIB_DEBUG 971 ar_dump_hostent("ar_answer: (snap) store CNAMEs", hp); 972 ar_dump_hostent("ar_answer: new one", hp); 973#endif 974 975 if (a > 0) 976 (void)ar_remrequest(rptr); 977 else 978 if (!rptr->re_sent) 979 (void)ar_remrequest(rptr); 980 return hp; 981 982getres_err: 983 if (rptr) 984 { 985 if (reip && rptr->re_rinfo.ri_ptr && size) 986 bcopy(rptr->re_rinfo.ri_ptr, reip, 987 MIN(rptr->re_rinfo.ri_size, size)); 988 if ((h_errno != TRY_AGAIN) && 989 (_res.options & (RES_DNSRCH|RES_DEFNAMES) == 990 (RES_DNSRCH|RES_DEFNAMES) )) 991 if (_res.dnsrch[rptr->re_srch]) 992 { 993 rptr->re_retries = _res.retry; 994 rptr->re_sends = 1; 995 rptr->re_resend = 1; 996 (void)ar_resend_query(rptr); 997 rptr->re_srch++; 998 } 999 return NULL; 1000 } 1001 return NULL; 1002} 1003 1004 1005#ifdef ARLIB_DEBUG 1006void ar_dump_hostent(prefix, hp) 1007char *prefix; 1008struct hostent *hp; 1009{ 1010 register char **s; 1011 1012 fflush(stdout); 1013 1014 fprintf(stderr, "%s\n", prefix); 1015 fprintf(stderr, " hp %p\n", hp); 1016 fprintf(stderr, " h_name %p '%s'\n", 1017 hp->h_name, hp->h_name); 1018 if (s = hp->h_aliases) 1019 { 1020 fprintf(stderr, " h_aliases %p\n", 1021 hp->h_aliases); 1022 while (*s) 1023 { 1024 fprintf(stderr, " element %p\n", *s); 1025 s++; 1026 } 1027 } 1028 if (s = hp->h_addr_list) 1029 { 1030 fprintf(stderr, " h_addr_list %p\n", 1031 hp->h_addr_list); 1032 while (*s) 1033 { 1034 fprintf(stderr, " element %p\n", *s); 1035 s++; 1036 } 1037 } 1038 1039 fflush(stderr); 1040} 1041 1042 1043void ar_dump_reslist(FILE* fp) 1044{ 1045 register struct reslist *rptr; 1046 int c; 1047 1048 c = 0; 1049 for (rptr = ar_first; rptr; rptr = rptr->re_next) 1050 { 1051 fprintf(fp, "%4d [%p] %4d [%p]: %s\n", rptr->re_id, rptr, 1052 *(rptr->re_rinfo.ri_ptr), rptr->re_rinfo.ri_ptr, 1053 rptr->re_name); 1054 } 1055} 1056#endif 1057