xref: /csrg-svn/lib/libc/net/gethostnamadr.c (revision 25386)
1 /*
2  * Copyright (c) 1985 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)gethostnamadr.c	6.2 (Berkeley) 11/04/85";
9 #endif not lint
10 
11 #include <sys/types.h>
12 #include <sys/param.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
15 #include <netdb.h>
16 #include <stdio.h>
17 #include <arpa/nameser.h>
18 #include <arpa/resolv.h>
19 
20 #define	MAXALIASES	35
21 #define MAXADDRS	35
22 
23 static char *h_addr_ptrs[MAXADDRS + 1];
24 
25 static struct hostent host;
26 static char *host_aliases[MAXALIASES];
27 static char hostbuf[BUFSIZ+1];
28 static struct in_addr host_addr;
29 
30 typedef union {
31     HEADER qb1;
32     char qb2[PACKETSZ];
33 } querybuf;
34 
35 static union {
36     long al;
37     char ac;
38 } align;
39 
40 
41 static struct hostent *
42 getanswer(msg, msglen, iquery)
43 	char *msg;
44 	int msglen, iquery;
45 {
46 	register HEADER *hp;
47 	register char *cp;
48 	register int n;
49 	querybuf answer;
50 	char *eom, *bp, **ap;
51 	int type, class, ancount, qdcount, buflen;
52 	int haveanswer, getclass;
53 	char **hap;
54 
55 	n = res_send(msg, msglen, (char *)&answer, sizeof(answer));
56 	if (n < 0) {
57 #ifdef DEBUG
58 		if (_res.options & RES_DEBUG)
59 			printf("res_send failed\n");
60 #endif
61 		return (NULL);
62 	}
63 	eom = (char *)&answer + n;
64 	/*
65 	 * find first satisfactory answer
66 	 */
67 	hp = (HEADER *) &answer;
68 	ancount = ntohs(hp->ancount);
69 	qdcount = ntohs(hp->qdcount);
70 	if (hp->rcode != NOERROR || ancount == 0) {
71 #ifdef DEBUG
72 		if (_res.options & RES_DEBUG)
73 			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
74 #endif
75 		return (NULL);
76 	}
77 	bp = hostbuf;
78 	buflen = sizeof(hostbuf);
79 	cp = (char *)&answer + sizeof(HEADER);
80 	if (qdcount) {
81 		if (iquery) {
82 			if ((n = dn_expand((char *)&answer, cp, bp, buflen)) <0)
83 				return (NULL);
84 			cp += n + QFIXEDSZ;
85 			host.h_name = bp;
86 			n = strlen(bp) + 1;
87 			bp += n;
88 			buflen -= n;
89 		} else
90 			cp += dn_skip(cp) + QFIXEDSZ;
91 		while (--qdcount > 0)
92 			cp += dn_skip(cp) + QFIXEDSZ;
93 	} else if (iquery)
94 		return (NULL);
95 	ap = host_aliases;
96 	host.h_aliases = host_aliases;
97 	hap = h_addr_ptrs;
98 #ifdef BSD4_3
99 	host.h_addr_list = h_addr_ptrs;
100 #endif
101 	haveanswer = 0;
102 	while (--ancount >= 0 && cp < eom) {
103 		if ((n = dn_expand((char *)&answer, cp, bp, buflen)) < 0)
104 			break;
105 		cp += n;
106 		type = getshort(cp);
107  		cp += sizeof(u_short);
108 		class = getshort(cp);
109  		cp += sizeof(u_short) + sizeof(u_long);
110 		n = getshort(cp);
111 		cp += sizeof(u_short);
112 		if (type == T_CNAME) {
113 			cp += n;
114 			if (ap >= &host_aliases[MAXALIASES-1])
115 				continue;
116 			*ap++ = bp;
117 			n = strlen(bp) + 1;
118 			bp += n;
119 			buflen -= n;
120 			continue;
121 		}
122 		if (type == T_PTR) {
123 			if ((n = dn_expand((char *)&answer, cp, bp, buflen)) <
124 0) {
125 				cp += n;
126 				continue;
127 			}
128 			cp += n;
129 			host.h_name = bp;
130 #ifdef BSD4_3
131 			return(&host);
132 #else
133 			haveanswer++;
134 			break;
135 #endif
136 		}
137 		if (type != T_A)  {
138 #ifdef DEBUG
139 			if (_res.options & RES_DEBUG)
140 				printf("unexpected answer type %d, size %d\n",
141 					type, n);
142 #endif
143 			cp += n;
144 			continue;
145 		}
146 		if (haveanswer) {
147 			if (n != host.h_length) {
148 				cp += n;
149 				continue;
150 			}
151 			if (class != getclass) {
152 				cp += n;
153 				continue;
154 			}
155 		} else {
156 			host.h_length = n;
157 			getclass = class;
158 			host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
159 			if (!iquery) {
160 				host.h_name = bp;
161 				bp += strlen(bp) + 1;
162 			}
163 		}
164 
165 		bp += ((u_long)bp % sizeof(align));
166 
167 		if (bp + n >= &hostbuf[sizeof(hostbuf)]) {
168 #ifdef DEBUG
169 			if (_res.options & RES_DEBUG)
170 				printf("size (%d) too big\n", n);
171 #endif
172 			break;
173 		}
174 		bcopy(cp, *hap++ = bp, n);
175 		bp +=n;
176 		cp += n;
177 		haveanswer++;
178 	}
179 	if (haveanswer) {
180 		*ap = NULL;
181 		*hap = NULL;
182 #ifndef BSD4_3
183 		host.h_addr = h_addr_ptrs[0];
184 #endif
185 		return (&host);
186 	} else
187 		return (NULL);
188 }
189 
190 struct hostent *
191 gethostbyname(name)
192 	char *name;
193 {
194 	int n;
195 	querybuf buf;
196 
197 	n = res_mkquery(QUERY, name, C_ANY, T_A, (char *)NULL, 0, NULL,
198 		(char *)&buf, sizeof(buf));
199 	if (n < 0) {
200 #ifdef DEBUG
201 		if (_res.options & RES_DEBUG)
202 			printf("res_mkquery failed\n");
203 #endif
204 		return (NULL);
205 	}
206 	return(getanswer((char *)&buf, n, 0));
207 }
208 
209 struct hostent *
210 gethostbyaddr(addr, len, type)
211 	char *addr;
212 	int len, type;
213 {
214 	int n;
215 	querybuf buf;
216 	register struct hostent *hp;
217 	char qbuf[MAXDNAME];
218 
219 	if (type != AF_INET)
220 		return (NULL);
221 	(void)sprintf(qbuf, "%d.%d.%d.%d.in-addr.arpa",
222 		(*(unsigned *)addr >> 24 & 0xff),
223 		(*(unsigned *)addr >> 16 & 0xff),
224 		(*(unsigned *)addr >> 8 & 0xff),
225 		(*(unsigned *)addr & 0xff));
226 	n = res_mkquery(QUERY, qbuf, C_IN, T_PTR, NULL, 0, NULL,
227 		(char *)&buf, sizeof(buf));
228 	if (n < 0) {
229 #ifdef DEBUG
230 		if (_res.options & RES_DEBUG)
231 			printf("res_mkquery failed\n");
232 #endif
233 		return (NULL);
234 	}
235 	if ((hp = getanswer((char *)&buf, n, 1)) == NULL)
236 		return(NULL);
237 	hp->h_addrtype = type;
238 	hp->h_length = len;
239 	h_addr_ptrs[0] = (char *)&host_addr;
240 	h_addr_ptrs[1] = (char *)0;
241 	host_addr = *(struct in_addr *)addr;
242 	return(hp);
243 }
244 
245