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