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