Initial import, 0.1 + pk 0.2.4-B1
[unix-history] / lib / libc / net / res_query.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1988 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#if defined(LIBC_SCCS) && !defined(lint)
35static char sccsid[] = "@(#)res_query.c 5.11 (Berkeley) 3/6/91";
36#endif /* LIBC_SCCS and not lint */
37
38#include <sys/param.h>
39#include <netinet/in.h>
40#include <arpa/inet.h>
41#include <arpa/nameser.h>
42#include <netdb.h>
43#include <resolv.h>
44#include <stdio.h>
45#include <ctype.h>
46#include <errno.h>
47#include <stdlib.h>
48#include <string.h>
49
50#if PACKETSZ > 1024
51#define MAXPACKET PACKETSZ
52#else
53#define MAXPACKET 1024
54#endif
55
56int h_errno;
57
58/*
59 * Formulate a normal query, send, and await answer.
60 * Returned answer is placed in supplied buffer "answer".
61 * Perform preliminary check of answer, returning success only
62 * if no error is indicated and the answer count is nonzero.
63 * Return the size of the response on success, -1 on error.
64 * Error number is left in h_errno.
65 * Caller must parse answer and determine whether it answers the question.
66 */
67res_query(name, class, type, answer, anslen)
68 char *name; /* domain name */
69 int class, type; /* class and type of query */
70 u_char *answer; /* buffer to put answer */
71 int anslen; /* size of answer buffer */
72{
73 char buf[MAXPACKET];
74 HEADER *hp;
75 int n;
76
77 if ((_res.options & RES_INIT) == 0 && res_init() == -1)
78 return (-1);
79#ifdef DEBUG
80 if (_res.options & RES_DEBUG)
81 printf("res_query(%s, %d, %d)\n", name, class, type);
82#endif
83 n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL,
84 buf, sizeof(buf));
85
86 if (n <= 0) {
87#ifdef DEBUG
88 if (_res.options & RES_DEBUG)
89 printf("res_query: mkquery failed\n");
90#endif
91 h_errno = NO_RECOVERY;
92 return (n);
93 }
94 n = res_send(buf, n, (char *)answer, anslen);
95 if (n < 0) {
96#ifdef DEBUG
97 if (_res.options & RES_DEBUG)
98 printf("res_query: send error\n");
99#endif
100 h_errno = TRY_AGAIN;
101 return(n);
102 }
103
104 hp = (HEADER *) answer;
105 if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
106#ifdef DEBUG
107 if (_res.options & RES_DEBUG)
108 printf("rcode = %d, ancount=%d\n", hp->rcode,
109 ntohs(hp->ancount));
110#endif
111 switch (hp->rcode) {
112 case NXDOMAIN:
113 h_errno = HOST_NOT_FOUND;
114 break;
115 case SERVFAIL:
116 h_errno = TRY_AGAIN;
117 break;
118 case NOERROR:
119 h_errno = NO_DATA;
120 break;
121 case FORMERR:
122 case NOTIMP:
123 case REFUSED:
124 default:
125 h_errno = NO_RECOVERY;
126 break;
127 }
128 return (-1);
129 }
130 return(n);
131}
132
133/*
134 * Formulate a normal query, send, and retrieve answer in supplied buffer.
135 * Return the size of the response on success, -1 on error.
136 * If enabled, implement search rules until answer or unrecoverable failure
137 * is detected. Error number is left in h_errno.
138 * Only useful for queries in the same name hierarchy as the local host
139 * (not, for example, for host address-to-name lookups in domain in-addr.arpa).
140 */
141res_search(name, class, type, answer, anslen)
142 char *name; /* domain name */
143 int class, type; /* class and type of query */
144 u_char *answer; /* buffer to put answer */
145 int anslen; /* size of answer */
146{
147 register char *cp, **domain;
148 int n, ret, got_nodata = 0;
149 char *__hostalias();
150
151 if ((_res.options & RES_INIT) == 0 && res_init() == -1)
152 return (-1);
153
154 errno = 0;
155 h_errno = HOST_NOT_FOUND; /* default, if we never query */
156 for (cp = name, n = 0; *cp; cp++)
157 if (*cp == '.')
158 n++;
159 if (n == 0 && (cp = __hostalias(name)))
160 return (res_query(cp, class, type, answer, anslen));
161
162 /*
163 * We do at least one level of search if
164 * - there is no dot and RES_DEFNAME is set, or
165 * - there is at least one dot, there is no trailing dot,
166 * and RES_DNSRCH is set.
167 */
168 if ((n == 0 && _res.options & RES_DEFNAMES) ||
169 (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH))
170 for (domain = _res.dnsrch; *domain; domain++) {
171 ret = res_querydomain(name, *domain, class, type,
172 answer, anslen);
173 if (ret > 0)
174 return (ret);
175 /*
176 * If no server present, give up.
177 * If name isn't found in this domain,
178 * keep trying higher domains in the search list
179 * (if that's enabled).
180 * On a NO_DATA error, keep trying, otherwise
181 * a wildcard entry of another type could keep us
182 * from finding this entry higher in the domain.
183 * If we get some other error (negative answer or
184 * server failure), then stop searching up,
185 * but try the input name below in case it's fully-qualified.
186 */
187 if (errno == ECONNREFUSED) {
188 h_errno = TRY_AGAIN;
189 return (-1);
190 }
191 if (h_errno == NO_DATA)
192 got_nodata++;
193 if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) ||
194 (_res.options & RES_DNSRCH) == 0)
195 break;
196 }
197 /*
198 * If the search/default failed, try the name as fully-qualified,
199 * but only if it contained at least one dot (even trailing).
200 * This is purely a heuristic; we assume that any reasonable query
201 * about a top-level domain (for servers, SOA, etc) will not use
202 * res_search.
203 */
204 if (n && (ret = res_querydomain(name, (char *)NULL, class, type,
205 answer, anslen)) > 0)
206 return (ret);
207 if (got_nodata)
208 h_errno = NO_DATA;
209 return (-1);
210}
211
212/*
213 * Perform a call on res_query on the concatenation of name and domain,
214 * removing a trailing dot from name if domain is NULL.
215 */
216res_querydomain(name, domain, class, type, answer, anslen)
217 char *name, *domain;
218 int class, type; /* class and type of query */
219 u_char *answer; /* buffer to put answer */
220 int anslen; /* size of answer */
221{
222 char nbuf[2*MAXDNAME+2];
223 char *longname = nbuf;
224 int n;
225
226#ifdef DEBUG
227 if (_res.options & RES_DEBUG)
228 printf("res_querydomain(%s, %s, %d, %d)\n",
229 name, domain, class, type);
230#endif
231 if (domain == NULL) {
232 /*
233 * Check for trailing '.';
234 * copy without '.' if present.
235 */
236 n = strlen(name) - 1;
237 if (name[n] == '.' && n < sizeof(nbuf) - 1) {
238 bcopy(name, nbuf, n);
239 nbuf[n] = '\0';
240 } else
241 longname = name;
242 } else
243 (void)sprintf(nbuf, "%.*s.%.*s",
244 MAXDNAME, name, MAXDNAME, domain);
245
246 return (res_query(longname, class, type, answer, anslen));
247}
248
249char *
250__hostalias(name)
251 register const char *name;
252{
253 register char *C1, *C2;
254 FILE *fp;
255 char *file, *getenv(), *strcpy(), *strncpy();
256 char buf[BUFSIZ];
257 static char abuf[MAXDNAME];
258
259 file = getenv("HOSTALIASES");
260 if (file == NULL || (fp = fopen(file, "r")) == NULL)
261 return (NULL);
262 buf[sizeof(buf) - 1] = '\0';
263 while (fgets(buf, sizeof(buf), fp)) {
264 for (C1 = buf; *C1 && !isspace(*C1); ++C1);
265 if (!*C1)
266 break;
267 *C1 = '\0';
268 if (!strcasecmp(buf, name)) {
269 while (isspace(*++C1));
270 if (!*C1)
271 break;
272 for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
273 abuf[sizeof(abuf) - 1] = *C2 = '\0';
274 (void)strncpy(abuf, C1, sizeof(abuf) - 1);
275 fclose(fp);
276 return (abuf);
277 }
278 }
279 fclose(fp);
280 return (NULL);
281}