xref: /csrg-svn/lib/libc/net/gethostnamadr.c (revision 25355)
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.1 (Berkeley) 10/31/85";
9 #endif not lint
10 
11 #include <sys/types.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 static struct hostent *
41 getanswer(msg, msglen, iquery)
42 	char *msg;
43 	int msglen, iquery;
44 {
45 	register HEADER *hp;
46 	register char *cp;
47 	register int n;
48 	querybuf answer;
49 	char *eom, *bp, **ap;
50 	int type, class, ancount, qdcount, buflen;
51 	int haveanswer, getclass;
52 	char **hap;
53 
54 	n = res_send(msg, msglen, (char *)&answer, sizeof(answer));
55 	if (n < 0) {
56 #ifdef DEBUG
57 		if (_res.options & RES_DEBUG)
58 			printf("res_send failed\n");
59 #endif
60 		return (NULL);
61 	}
62 	eom = (char *)&answer + n;
63 	/*
64 	 * find first satisfactory answer
65 	 */
66 	hp = (HEADER *) &answer;
67 	ancount = ntohs(hp->ancount);
68 	qdcount = ntohs(hp->qdcount);
69 	if (hp->rcode != NOERROR || ancount == 0) {
70 #ifdef DEBUG
71 		if (_res.options & RES_DEBUG)
72 			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
73 #endif
74 		return (NULL);
75 	}
76 	bp = hostbuf;
77 	buflen = sizeof(hostbuf);
78 	cp = (char *)&answer + sizeof(HEADER);
79 	if (qdcount) {
80 		if (iquery) {
81 			if ((n = dn_expand((char *)&answer, cp, bp, buflen)) <
82 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 	host.h_addr_list = h_addr_ptrs;
99 	haveanswer = 0;
100 	while (--ancount >= 0 && cp < eom) {
101 		if ((n = dn_expand((char *)&answer, cp, bp, buflen)) < 0)
102 			break;
103 		cp += n;
104 		type = getshort(cp);
105  		cp += sizeof(u_short);
106 		class = getshort(cp);
107  		cp += sizeof(u_short) + sizeof(u_long);
108 		n = getshort(cp);
109 		cp += sizeof(u_short);
110 		if (type == T_CNAME) {
111 			cp += n;
112 			if (ap >= &host_aliases[MAXALIASES-1])
113 				continue;
114 			*ap++ = bp;
115 			n = strlen(bp) + 1;
116 			bp += n;
117 			buflen -= n;
118 			continue;
119 		}
120 		if (type == T_PTR) {
121 			if ((n = dn_expand((char *)&answer, cp, bp, buflen)) <
122 0) {
123 				cp += n;
124 				continue;
125 			}
126 			cp += n;
127 			host.h_name = bp;
128 			return(&host);
129 		}
130 		if (type != T_A)  {
131 #ifdef DEBUG
132 			if (_res.options & RES_DEBUG)
133 				printf("unexpected answer type %d, size %d\n",
134 					type, n);
135 #endif
136 			cp += n;
137 			continue;
138 		}
139 		if (haveanswer) {
140 			if (n != host.h_length) {
141 				cp += n;
142 				continue;
143 			}
144 			if (class != getclass) {
145 				cp += n;
146 				continue;
147 			}
148 		} else {
149 			host.h_length = n;
150 			getclass = class;
151 			host.h_addrtype = C_IN ? AF_INET : AF_UNSPEC;
152 			if (!iquery) {
153 				host.h_name = bp;
154 				bp += strlen(bp) + 1;
155 			}
156 		}
157 
158 		bp += ((u_long)bp % sizeof(align));
159 
160 		if (bp + n >= &hostbuf[sizeof(hostbuf)]) {
161 #ifdef DEBUG
162 			if (_res.options & RES_DEBUG)
163 				printf("size (%d) too big\n", n);
164 #endif
165 			break;
166 		}
167 		bcopy(cp, *hap++ = bp, n);
168 		bp +=n;
169 		cp += n;
170 		haveanswer++;
171 	}
172 	if (haveanswer) {
173 		*ap = NULL;
174 		*hap = NULL;
175 		return (&host);
176 	} else
177 		return (NULL);
178 }
179 
180 struct hostent *
181 gethostbyname(name)
182 	char *name;
183 {
184 	int n;
185 	querybuf buf;
186 
187 	n = res_mkquery(QUERY, name, C_ANY, T_A, (char *)NULL, 0, NULL,
188 		(char *)&buf, sizeof(buf));
189 	if (n < 0) {
190 #ifdef DEBUG
191 		if (_res.options & RES_DEBUG)
192 			printf("res_mkquery failed\n");
193 #endif
194 		return (NULL);
195 	}
196 	return(getanswer((char *)&buf, n, 0));
197 }
198 
199 struct hostent *
200 gethostbyaddr(addr, len, type)
201 	char *addr;
202 	int len, type;
203 {
204 	int n;
205 	querybuf buf;
206 	register struct hostent *hp;
207 	char qbuf[MAXDNAME];
208 
209 	if (type != AF_INET)
210 		return (NULL);
211 	(void)sprintf(qbuf, "%d.%d.%d.%d.in-addr.arpa",
212 		(*(unsigned *)addr >> 24 & 0xff),
213 		(*(unsigned *)addr >> 16 & 0xff),
214 		(*(unsigned *)addr >> 8 & 0xff),
215 		(*(unsigned *)addr & 0xff));
216 	n = res_mkquery(QUERY, qbuf, C_IN, T_PTR, NULL, 0, NULL,
217 		(char *)&buf, sizeof(buf));
218 	if (n < 0) {
219 #ifdef DEBUG
220 		if (_res.options & RES_DEBUG)
221 			printf("res_mkquery failed\n");
222 #endif
223 		return (NULL);
224 	}
225 	if ((hp = getanswer((char *)&buf, n, 1)) == NULL)
226 		return(NULL);
227 	hp->h_addrtype = type;
228 	hp->h_length = len;
229 	h_addr_ptrs[0] = (char *)&host_addr;
230 	h_addr_ptrs[1] = (char *)0;
231 	host_addr = *(struct in_addr *)addr;
232 	return(hp);
233 }
234 
235