]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ntp/arlib/arlib.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ntp / arlib / arlib.c
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
8 static  char    sccsid[] = "@(#)arlib.c 1.9 6/5/93 (C)opyright 1992 Darren \
9 Reed. 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
25 extern  int     errno, h_errno;
26 static  char    ar_hostbuf[65], ar_domainname[65];
27 static  char    ar_dot[] = ".";
28 static  int     ar_resfd = -1, ar_vc = 0;
29 static  struct  reslist *ar_last, *ar_first;
30
31 /*
32  * Statistics structure.
33  */
34 static  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
45 static int do_query_name(/* struct resinfo *, char *, struct reslist * */);
46 static int do_query_number(/* struct resinfo *, char *, struct reslist * */);
47 static 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  */
58 int     ar_init(op)
59 int     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  */
96 int     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  */
156 void    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  */
169 static  int     ar_add_request(new)
170 struct  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  */
195 static  int     ar_remrequest(old)
196 struct  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  */
249 static  struct  reslist *ar_make_request(resi)
250 register 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  */
282 long    ar_timeout(now, info, size)
283 time_t  now;
284 char    *info;
285 int     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  */
336 static  int     ar_send_res_msg(msg, len, rcount)
337 char    *msg;
338 int     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  */
382 static  struct  reslist *ar_find_id(id)
383 int     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  */
400 int     ar_delete(ptr, size)
401 char    *ptr;
402 int     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  */
427 static  int     ar_query_name(name, class, type, rptr)
428 char    *name;
429 int     class, type;
430 struct  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  */
467 int     ar_gethostbyname(name, info, size)
468 char    *name;
469 char    *info;
470 int     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
492 static  int     do_query_name(resi, name, rptr)
493 struct  resinfo *resi;
494 char    *name;
495 register 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  */
539 int     ar_gethostbyaddr(addr, info, size)
540 char    *addr;
541 char    *info;
542 int     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  */
565 static  int     do_query_number(resi, numb, rptr)
566 struct  resinfo *resi;
567 char    *numb;
568 register 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  */
600 static  int     ar_resend_query(rptr)
601 struct  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  */
627 static  int     ar_procanswer(rptr, hptr, buf, eob)
628 struct  reslist *rptr;
629 char    *buf, *eob;
630 HEADER  *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  */
762 struct  hostent *ar_answer(reip, size)
763 char    *reip;
764 int     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
982 getres_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
1006 void ar_dump_hostent(prefix, hp)
1007 char *prefix;
1008 struct 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
1043 void 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