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