diff options
author | deraadt <> | 1995-10-18 08:42:23 +0000 |
---|---|---|
committer | deraadt <> | 1995-10-18 08:42:23 +0000 |
commit | 0527d29da443886d92e9a418180c5b25a5f8d270 (patch) | |
tree | 86b3a64928451a669cefa27900e5884036b4e349 /src/lib/libc/net/res_query.c | |
download | openbsd-0527d29da443886d92e9a418180c5b25a5f8d270.tar.gz openbsd-0527d29da443886d92e9a418180c5b25a5f8d270.tar.bz2 openbsd-0527d29da443886d92e9a418180c5b25a5f8d270.zip |
initial import of NetBSD tree
Diffstat (limited to 'src/lib/libc/net/res_query.c')
-rw-r--r-- | src/lib/libc/net/res_query.c | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/src/lib/libc/net/res_query.c b/src/lib/libc/net/res_query.c new file mode 100644 index 0000000000..7649462e56 --- /dev/null +++ b/src/lib/libc/net/res_query.c | |||
@@ -0,0 +1,366 @@ | |||
1 | /* $NetBSD: res_query.c,v 1.9 1995/02/25 06:58:58 cgd Exp $ */ | ||
2 | |||
3 | /*- | ||
4 | * Copyright (c) 1988, 1993 | ||
5 | * The Regents of the University of California. All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * 2. Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in the | ||
14 | * documentation and/or other materials provided with the distribution. | ||
15 | * 3. All advertising materials mentioning features or use of this software | ||
16 | * must display the following acknowledgement: | ||
17 | * This product includes software developed by the University of | ||
18 | * California, Berkeley and its contributors. | ||
19 | * 4. Neither the name of the University nor the names of its contributors | ||
20 | * may be used to endorse or promote products derived from this software | ||
21 | * without specific prior written permission. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
33 | * SUCH DAMAGE. | ||
34 | * - | ||
35 | * Portions Copyright (c) 1993 by Digital Equipment Corporation. | ||
36 | * | ||
37 | * Permission to use, copy, modify, and distribute this software for any | ||
38 | * purpose with or without fee is hereby granted, provided that the above | ||
39 | * copyright notice and this permission notice appear in all copies, and that | ||
40 | * the name of Digital Equipment Corporation not be used in advertising or | ||
41 | * publicity pertaining to distribution of the document or software without | ||
42 | * specific, written prior permission. | ||
43 | * | ||
44 | * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL | ||
45 | * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES | ||
46 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT | ||
47 | * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | ||
48 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR | ||
49 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | ||
50 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | ||
51 | * SOFTWARE. | ||
52 | * - | ||
53 | * --Copyright-- | ||
54 | */ | ||
55 | |||
56 | #if defined(LIBC_SCCS) && !defined(lint) | ||
57 | #if 0 | ||
58 | static char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93"; | ||
59 | static char rcsid[] = "$Id: res_query.c,v 1.1 1993/06/01 09:42:14 vixie Exp vixie "; | ||
60 | #else | ||
61 | static char rcsid[] = "$NetBSD: res_query.c,v 1.9 1995/02/25 06:58:58 cgd Exp $"; | ||
62 | #endif | ||
63 | #endif /* LIBC_SCCS and not lint */ | ||
64 | |||
65 | #include <sys/param.h> | ||
66 | #include <netinet/in.h> | ||
67 | #include <arpa/inet.h> | ||
68 | #include <arpa/nameser.h> | ||
69 | #include <netdb.h> | ||
70 | #include <resolv.h> | ||
71 | #include <stdio.h> | ||
72 | #include <ctype.h> | ||
73 | #include <errno.h> | ||
74 | #include <stdlib.h> | ||
75 | #include <string.h> | ||
76 | |||
77 | #if PACKETSZ > 1024 | ||
78 | #define MAXPACKET PACKETSZ | ||
79 | #else | ||
80 | #define MAXPACKET 1024 | ||
81 | #endif | ||
82 | |||
83 | char *__hostalias __P((const char *)); | ||
84 | int h_errno; | ||
85 | |||
86 | /* | ||
87 | * Formulate a normal query, send, and await answer. | ||
88 | * Returned answer is placed in supplied buffer "answer". | ||
89 | * Perform preliminary check of answer, returning success only | ||
90 | * if no error is indicated and the answer count is nonzero. | ||
91 | * Return the size of the response on success, -1 on error. | ||
92 | * Error number is left in h_errno. | ||
93 | * Caller must parse answer and determine whether it answers the question. | ||
94 | */ | ||
95 | res_query(name, class, type, answer, anslen) | ||
96 | char *name; /* domain name */ | ||
97 | int class, type; /* class and type of query */ | ||
98 | u_char *answer; /* buffer to put answer */ | ||
99 | int anslen; /* size of answer buffer */ | ||
100 | { | ||
101 | char buf[MAXPACKET]; | ||
102 | HEADER *hp; | ||
103 | int n; | ||
104 | |||
105 | if ((_res.options & RES_INIT) == 0 && res_init() == -1) | ||
106 | return (-1); | ||
107 | #ifdef DEBUG | ||
108 | if (_res.options & RES_DEBUG) | ||
109 | printf(";; res_query(%s, %d, %d)\n", name, class, type); | ||
110 | #endif | ||
111 | n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL, | ||
112 | buf, sizeof(buf)); | ||
113 | |||
114 | if (n <= 0) { | ||
115 | #ifdef DEBUG | ||
116 | if (_res.options & RES_DEBUG) | ||
117 | printf(";; res_query: mkquery failed\n"); | ||
118 | #endif | ||
119 | h_errno = NO_RECOVERY; | ||
120 | return (n); | ||
121 | } | ||
122 | n = res_send(buf, n, (char *)answer, anslen); | ||
123 | if (n < 0) { | ||
124 | #ifdef DEBUG | ||
125 | if (_res.options & RES_DEBUG) | ||
126 | printf(";; res_query: send error\n"); | ||
127 | #endif | ||
128 | h_errno = TRY_AGAIN; | ||
129 | return (n); | ||
130 | } | ||
131 | |||
132 | hp = (HEADER *) answer; | ||
133 | if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { | ||
134 | #ifdef DEBUG | ||
135 | if (_res.options & RES_DEBUG) | ||
136 | printf(";; rcode = %d, ancount=%d\n", hp->rcode, | ||
137 | ntohs(hp->ancount)); | ||
138 | #endif | ||
139 | switch (hp->rcode) { | ||
140 | case NXDOMAIN: | ||
141 | h_errno = HOST_NOT_FOUND; | ||
142 | break; | ||
143 | case SERVFAIL: | ||
144 | h_errno = TRY_AGAIN; | ||
145 | break; | ||
146 | case NOERROR: | ||
147 | h_errno = NO_DATA; | ||
148 | break; | ||
149 | case FORMERR: | ||
150 | case NOTIMP: | ||
151 | case REFUSED: | ||
152 | default: | ||
153 | h_errno = NO_RECOVERY; | ||
154 | break; | ||
155 | } | ||
156 | return (-1); | ||
157 | } | ||
158 | return (n); | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * Formulate a normal query, send, and retrieve answer in supplied buffer. | ||
163 | * Return the size of the response on success, -1 on error. | ||
164 | * If enabled, implement search rules until answer or unrecoverable failure | ||
165 | * is detected. Error number is left in h_errno. | ||
166 | * Only useful for queries in the same name hierarchy as the local host | ||
167 | * (not, for example, for host address-to-name lookups in domain in-addr.arpa). | ||
168 | */ | ||
169 | int | ||
170 | res_search(name, class, type, answer, anslen) | ||
171 | const char *name; /* domain name */ | ||
172 | int class, type; /* class and type of query */ | ||
173 | u_char *answer; /* buffer to put answer */ | ||
174 | int anslen; /* size of answer */ | ||
175 | { | ||
176 | register char *cp, **domain; | ||
177 | int dots, trailing_dot, ret, got_nodata, saved_herrno, tried_as_is; | ||
178 | |||
179 | if ((_res.options & RES_INIT) == 0 && res_init() == -1) | ||
180 | return (-1); | ||
181 | |||
182 | got_nodata = 0; | ||
183 | errno = 0; | ||
184 | h_errno = HOST_NOT_FOUND; /* default, if we never query */ | ||
185 | dots = 0; | ||
186 | for (cp = (char *)name; *cp; cp++) { | ||
187 | if (*cp == '.') | ||
188 | dots++; | ||
189 | } | ||
190 | trailing_dot = 0; | ||
191 | if ((cp > name) && (*--cp == '.')) | ||
192 | trailing_dot++; | ||
193 | |||
194 | /* | ||
195 | * if there aren't any dots, it could be a user-level alias | ||
196 | */ | ||
197 | if (!dots && (cp = __hostalias(name))) | ||
198 | return (res_query(cp, class, type, answer, anslen)); | ||
199 | |||
200 | /* | ||
201 | * If there are dots in the name already, let's just give it a try | ||
202 | * 'as is'. The threshold can be set with the "ndots" option. | ||
203 | */ | ||
204 | saved_herrno = -1; | ||
205 | tried_as_is = 0; | ||
206 | if (dots >= _res.ndots) { | ||
207 | ret = res_querydomain(name, NULL, class, type, answer, anslen); | ||
208 | if (ret > 0) | ||
209 | return (ret); | ||
210 | saved_herrno = h_errno; | ||
211 | tried_as_is++; | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * We do at least one level of search if | ||
216 | * - there is no dot and RES_DEFNAME is set, or | ||
217 | * - there is at least one dot, there is no trailing dot, | ||
218 | * and RES_DNSRCH is set. | ||
219 | */ | ||
220 | if ((!dots && (_res.options & RES_DEFNAMES)) || | ||
221 | (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { | ||
222 | for (domain = _res.dnsrch; *domain; domain++) { | ||
223 | int done = 0; | ||
224 | |||
225 | ret = res_querydomain(name, *domain, class, type, | ||
226 | answer, anslen); | ||
227 | if (ret > 0) | ||
228 | return (ret); | ||
229 | /* | ||
230 | * If no server present, give up. | ||
231 | * If name isn't found in this domain, | ||
232 | * keep trying higher domains in the search list | ||
233 | * (if that's enabled). | ||
234 | * On a NO_DATA error, keep trying, otherwise | ||
235 | * a wildcard entry of another type could keep us | ||
236 | * from finding this entry higher in the domain. | ||
237 | * If we get some other error (negative answer or | ||
238 | * server failure), then stop searching up, | ||
239 | * but try the input name below in case it's | ||
240 | * fully-qualified. | ||
241 | */ | ||
242 | if (errno == ECONNREFUSED) { | ||
243 | h_errno = TRY_AGAIN; | ||
244 | return (-1); | ||
245 | } | ||
246 | |||
247 | switch (h_errno) { | ||
248 | case NO_DATA: | ||
249 | got_nodata++; | ||
250 | /* FALLTHROUGH */ | ||
251 | case HOST_NOT_FOUND: | ||
252 | /* keep trying */ | ||
253 | break; | ||
254 | default: | ||
255 | /* anything else implies that we're done */ | ||
256 | done++; | ||
257 | } | ||
258 | /* | ||
259 | * if we got here for some reason other than DNSRCH, | ||
260 | * we only wanted one iteration of the loop, so stop. | ||
261 | */ | ||
262 | if (!(_res.options & RES_DNSRCH)) | ||
263 | done++; | ||
264 | |||
265 | if (done) | ||
266 | break; | ||
267 | } | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * if we have not already tried the name "as is", do that now. | ||
272 | * note that we do this regardless of how many dots were in the | ||
273 | * name or whether it ends with a dot. | ||
274 | */ | ||
275 | if (!tried_as_is) { | ||
276 | ret = res_querydomain(name, NULL, class, type, answer, anslen); | ||
277 | if (ret > 0) | ||
278 | return (ret); | ||
279 | saved_herrno = h_errno; | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | * if we got here, we didn't satisfy the search. | ||
284 | * if we did an initial full query, return that query's h_errno | ||
285 | * (note that we wouldn't be here if that query had succeeded). | ||
286 | * else if we ever got a nodata, send that back as the reason. | ||
287 | * else send back meaningless h_errno, that being the one from | ||
288 | * the last DNSRCH we did. | ||
289 | */ | ||
290 | if (saved_herrno != -1) | ||
291 | h_errno = saved_herrno; | ||
292 | else if (got_nodata) | ||
293 | h_errno = NO_DATA; | ||
294 | return (-1); | ||
295 | } | ||
296 | |||
297 | /* | ||
298 | * Perform a call on res_query on the concatenation of name and domain, | ||
299 | * removing a trailing dot from name if domain is NULL. | ||
300 | */ | ||
301 | res_querydomain(name, domain, class, type, answer, anslen) | ||
302 | char *name, *domain; | ||
303 | int class, type; /* class and type of query */ | ||
304 | u_char *answer; /* buffer to put answer */ | ||
305 | int anslen; /* size of answer */ | ||
306 | { | ||
307 | char nbuf[2*MAXDNAME+2]; | ||
308 | char *longname = nbuf; | ||
309 | int n; | ||
310 | |||
311 | #ifdef DEBUG | ||
312 | if (_res.options & RES_DEBUG) | ||
313 | printf(";; res_querydomain(%s, %s, %d, %d)\n", | ||
314 | name, domain, class, type); | ||
315 | #endif | ||
316 | if (domain == NULL) { | ||
317 | /* | ||
318 | * Check for trailing '.'; | ||
319 | * copy without '.' if present. | ||
320 | */ | ||
321 | n = strlen(name) - 1; | ||
322 | if (n != (0 - 1) && name[n] == '.' && n < sizeof(nbuf) - 1) { | ||
323 | bcopy(name, nbuf, n); | ||
324 | nbuf[n] = '\0'; | ||
325 | } else | ||
326 | longname = name; | ||
327 | } else | ||
328 | (void)sprintf(nbuf, "%.*s.%.*s", | ||
329 | MAXDNAME, name, MAXDNAME, domain); | ||
330 | |||
331 | return (res_query(longname, class, type, answer, anslen)); | ||
332 | } | ||
333 | |||
334 | char * | ||
335 | __hostalias(name) | ||
336 | register const char *name; | ||
337 | { | ||
338 | register char *cp1, *cp2; | ||
339 | FILE *fp; | ||
340 | char *file, *getenv(), *strcpy(), *strncpy(); | ||
341 | char buf[BUFSIZ]; | ||
342 | static char abuf[MAXDNAME]; | ||
343 | |||
344 | file = getenv("HOSTALIASES"); | ||
345 | if (file == NULL || (fp = fopen(file, "r")) == NULL) | ||
346 | return (NULL); | ||
347 | buf[sizeof(buf) - 1] = '\0'; | ||
348 | while (fgets(buf, sizeof(buf), fp)) { | ||
349 | for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1); | ||
350 | if (!*cp1) | ||
351 | break; | ||
352 | *cp1 = '\0'; | ||
353 | if (!strcasecmp(buf, name)) { | ||
354 | while (isspace(*++cp1)); | ||
355 | if (!*cp1) | ||
356 | break; | ||
357 | for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2); | ||
358 | abuf[sizeof(abuf) - 1] = *cp2 = '\0'; | ||
359 | (void)strncpy(abuf, cp1, sizeof(abuf) - 1); | ||
360 | fclose(fp); | ||
361 | return (abuf); | ||
362 | } | ||
363 | } | ||
364 | fclose(fp); | ||
365 | return (NULL); | ||
366 | } | ||