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