revert between 56095 -> 55830 in arch
[AROS.git] / workbench / network / stacks / AROSTCP / bsdsocket / api / res_query.c
blob1aecef53cef3be785a4f2a53d8b715e599314705
1 /*
2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
4 * All rights reserved.
5 * Copyright (C) 2005 - 2007 The AROS Dev Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 * MA 02111-1307, USA.
24 * Copyright (c) 1988 Regents of the University of California.
25 * All rights reserved.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
56 #if defined(LIBC_SCCS) && !defined(lint)
57 static char sccsid[] = "@(#)res_query.c 5.11 (Berkeley) 3/6/91";
58 #endif /* LIBC_SCCS and not lint */
60 #include <conf.h>
62 #include <sys/param.h>
63 #include <sys/malloc.h>
64 #include <netinet/in.h>
65 /* #include <arpa/inet.h> */
66 #include <arpa/nameser.h>
67 #include <api/resolv.h>
68 #include <netdb.h>
69 #ifndef AMITCP
70 #include <ctype.h>
71 #endif
72 #include <sys/errno.h>
74 #include <kern/amiga_includes.h>
75 #include <kern/amiga_subr.h>
76 #include <api/amiga_api.h>
77 #include <kern/amiga_netdb.h>
79 #if PACKETSZ > 1024
80 #define MAXPACKET PACKETSZ
81 #else
82 #define MAXPACKET 1024
83 #endif
86 * Formulate a normal query, send, and await answer.
87 * Returned answer is placed in supplied buffer "answer".
88 * Perform preliminary check of answer, returning success only
89 * if no error is indicated and the answer count is nonzero.
90 * Return the size of the response on success, -1 on error.
91 * Caller must parse answer and determine whether it answers the question.
93 int
94 res_query(struct SocketBase * libPtr,
95 const char * name, /* domain name */
96 int class,
97 int type, /* class and type of query */
98 u_char * answer, /* buffer to put answer */
99 int anslen) /* size of answer buffer */
101 char *buf;
102 HEADER *hp;
103 int n;
105 #if defined(__AROS__)
106 D(bug("[AROSTCP](res_query.c) res_query()\n"));
107 #endif
109 if ((_res.options & RES_INIT) == 0 && res_init(&_res) == -1)
111 #if defined(__AROS__)
112 D(bug("[AROSTCP](res_query.c) res_query: resolver not initialised/failed to init\n"));
113 #endif
114 return (-1);
117 if ((_res.dbserial != ndb_Serial) && res_update_db(&_res) == -1)
119 #if defined(__AROS__)
120 D(bug("[AROSTCP](res_query.c) res_query: resolver failed to update\n"));
121 #endif
122 return (-1);
126 /* an idea to remove reduntant bsd_mallocs and bsd_frees. let's make
127 a new structure in gethostby(name|addr) and put libPrt->buffer
128 point to it (first item in new structure is old value of that
129 buffer). that structure holds pointers to all needed character
130 buffers and is initialized to NULL. at end gethostby... bsd_frees
131 all buffers that are pointed there */
133 if ((buf = bsd_malloc(MAXPACKET, M_TEMP, M_WAITOK)) == NULL) {
134 #if defined(__AROS__)
135 D(bug("[AROSTCP](res_query.c) res_query: Failed to allocate query entry\n"));
136 #endif
137 writeErrnoValue(libPtr, ENOMEM);
138 return -1;
141 #if defined(__AROS__)
142 D(bug("[AROSTCP](res_query.c) res_query: name: %s class: %d type %d\n", name, class, type));
143 #endif
144 #ifdef RES_DEBUG
145 printf("res_query(%s, %d, %d)\n", name, class, type);
146 #endif
147 n = res_mkquery(libPtr, QUERY, name, class, type, (char *)NULL, 0, NULL,
148 buf, MAXPACKET);
150 if (n <= 0) {
151 #if defined(__AROS__)
152 D(bug("[AROSTCP](res_query.c) res_query: [res_mkquery] Failed\n"));
153 #endif
154 #ifdef RES_DEBUG
155 printf("res_query: mkquery failed\n");
156 #endif
157 h_errno = NO_RECOVERY;
158 goto Return;
161 /* TODO: NicJA - Where is CHECK_POINTER() !!!! */
162 #if !defined(__AROS__)
163 CHECK_POINTER(buf);
164 #endif
166 n = res_send(libPtr, buf, n, (char *)answer, anslen);
168 if (n < 0) {
169 #if defined(__AROS__)
170 D(bug("[AROSTCP](res_query.c) res_query: [res_send] Failed\n"));
171 #endif
172 #ifdef RES_DEBUG
173 printf("res_query: send error\n");
174 #endif
175 h_errno = TRY_AGAIN;
176 goto Return;
179 hp = (HEADER *) answer;
180 if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
181 #if defined(__AROS__)
182 D(bug("[AROSTCP](res_query.c) res_query: [res_send] Error: rcode = %d, ancount = %d\n", hp->rcode, ntohs(hp->ancount)));
183 #endif
184 #ifdef RES_DEBUG
185 printf("rcode = %d, ancount=%d\n", hp->rcode,
186 ntohs(hp->ancount));
187 #endif
188 switch (hp->rcode) {
189 case NXDOMAIN:
190 #if defined(__AROS__)
191 D(bug("[AROSTCP](res_query.c) res_query: [res_send] Error: Host not found!\n"));
192 #endif
193 h_errno = HOST_NOT_FOUND;
194 break;
195 case SERVFAIL:
196 #if defined(__AROS__)
197 D(bug("[AROSTCP](res_query.c) res_query: [res_send] Error: Server Fail!\n"));
198 #endif
199 h_errno = TRY_AGAIN;
200 break;
201 case NOERROR:
202 #if defined(__AROS__)
203 D(bug("[AROSTCP](res_query.c) res_query: [res_send] Error: !IMPOSSIBLE CASE!\n"));
204 #endif
205 h_errno = NO_DATA;
206 break;
207 case FORMERR:
208 case NOTIMP:
209 case REFUSED:
210 default:
211 #if defined(__AROS__)
212 D(bug("[AROSTCP](res_query.c) res_query: [res_send] Error: Unknown!\n"));
213 #endif
214 h_errno = NO_RECOVERY;
215 break;
217 n = -1;
218 goto Return;
221 Return:
222 bsd_free(buf, M_TEMP);
223 return(n);
227 * Formulate a normal query, send, and retrieve answer in supplied buffer.
228 * Return the size of the response on success, -1 on error.
229 * If enabled, implement search rules until answer or unrecoverable failure
230 * is detected. Error number is left in h_errno.
231 * Only useful for queries in the same name hierarchy as the local host
232 * (not, for example, for host address-to-name lookups in domain in-addr.arpa).
235 res_search(struct SocketBase * libPtr,
236 const char * name, /* domain name */
237 int class,
238 int type, /* class and type of query */
239 u_char * answer, /* buffer to put answer */
240 int anslen) /* size of answer */
242 register const char *cp;
243 char **domain;
245 int n, ret, got_nodata = 0;
246 int tmp_errno;
248 #if defined(__AROS__)
249 D(bug("[AROSTCP](res_query.c) res_search('%s')\n", name));
250 #endif
252 #ifndef AMICTP
253 char *__hostalias();
254 #endif /* ! AMITCP */
255 if ((_res.options & RES_INIT) == 0 && res_init(&_res) == -1)
257 #if defined(__AROS__)
258 D(bug("[AROSTCP](res_query.c) res_search: resolver not initialised/failed to init\n"));
259 #endif
260 return (-1);
262 else
264 #if defined(__AROS__)
265 D(bug("[AROSTCP](res_query.c) res_search: resolver initialised. base @ %x\n", &_res));
266 #endif
269 if ((_res.dbserial != ndb_Serial) && res_update_db(&_res) == -1)
271 #if defined(__AROS__)
272 D(bug("[AROSTCP](res_query.c) res_search: resolver failed to update\n"));
273 #endif
274 return (-1);
276 else
278 #if defined(__AROS__)
279 D(bug("[AROSTCP](res_query.c) res_search: resolver db updated\n"));
280 #endif
283 writeErrnoValue(libPtr, 0);
284 h_errno = HOST_NOT_FOUND; /* default, if we never query */
285 for (cp = name, n = 0; *cp; cp++)
286 if (*cp == '.')
287 n++;
289 #ifndef AMITCP
290 if (n == 0 && (cp = __hostalias(name)))
292 #if defined(__AROS__)
293 D(bug("[AROSTCP](res_query.c) res_search: returning hostalias response\n"));
294 #endif
295 return (res_query(cp, class, type, answer, anslen));
297 #endif /* !AMITCP */
300 * We do at least one level of search if
301 * - there is no dot and RES_DEFNAME is set, or
302 * - there is at least one dot, there is no trailing dot,
303 * and RES_DNSRCH is set.
305 #if defined(__AROS__) && defined(DEBUG)
306 D(bug("[AROSTCP](res_query.c) res_search: n =%d\n", n));
307 if (_res.options & RES_DEFNAMES)
309 D(bug("[AROSTCP](res_query.c) res_search: OPTION:Search local domain\n"));
312 if (_res.options & RES_DNSRCH)
314 D(bug("[AROSTCP](res_query.c) res_search: OPTION:Search using DNS\n"));
316 #endif
318 if ((n == 0 && _res.options & RES_DEFNAMES) ||
319 (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH))
321 #if defined(__AROS__)
322 D(bug("[AROSTCP](res_query.c) res_search: Querying DNS servers .. \n"));
323 #endif
324 for (domain = _res.dnsrch; *domain; domain++)
326 #if defined(__AROS__)
327 D(bug("[AROSTCP](res_query.c) res_search: resolver querying domain '%s'\n", *domain));
328 #endif
329 ret = res_querydomain(libPtr, name, *domain,
330 class, type, answer, anslen);
331 if (ret > 0)
333 #if defined(__AROS__)
334 D(bug("[AROSTCP](res_query.c) res_search: returning querydomain response\n"));
335 #endif
336 return (ret);
339 * If no server present, give up.
340 * If name isn't found in this domain,
341 * keep trying higher domains in the search list
342 * (if that's enabled).
343 * On a NO_DATA error, keep trying, otherwise
344 * a wildcard entry of another type could keep us
345 * from finding this entry higher in the domain.
346 * If we get some other error (negative answer or
347 * server failure), then stop searching up,
348 * but try the input name below in case it's fully-qualified.
350 tmp_errno = readErrnoValue(libPtr);
351 if ((tmp_errno == ECONNREFUSED) || (tmp_errno == ETIMEDOUT) || (tmp_errno == EINTR)) {
352 h_errno = TRY_AGAIN;
354 #if defined(__AROS__)
355 D(bug("[AROSTCP](res_query.c) res_search: resolver failed to connect, setting retry\n"));
356 #endif
357 return (-1);
360 if (h_errno == NO_DATA)
362 #if defined(__AROS__)
363 D(bug("[AROSTCP](res_query.c) res_search: resolver got no response\n"));
364 #endif
365 got_nodata++;
368 if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) ||
369 (_res.options & RES_DNSRCH) == 0)
371 #if defined(__AROS__)
372 D(bug("[AROSTCP](res_query.c) res_search: resolver got response\n"));
373 #endif
374 break;
379 * If the search/default failed, try the name as fully-qualified,
380 * but only if it contained at least one dot (even trailing).
381 * This is purely a heuristic; we assume that any reasonable query
382 * about a top-level domain (for servers, SOA, etc) will not use
383 * res_search.
386 if (n && (ret = res_querydomain(libPtr, name, (char *)NULL,
387 class, type, answer, anslen)) > 0)
389 #if defined(__AROS__)
390 D(bug("[AROSTCP](res_query.c) res_search: returning querydomain.2 result\n"));
391 #endif
392 return (ret);
394 #if defined(__AROS__)
395 D(bug("[AROSTCP](res_query.c) res_search: finished search.\n"));
396 #endif
397 if (got_nodata) h_errno = NO_DATA;
399 return (-1);
403 * Perform a call on res_query on the concatenation of name and domain,
404 * removing a trailing dot from name if domain is NULL.
407 res_querydomain(struct SocketBase * libPtr,
408 const char * name,
409 const char * domain,
410 int class,
411 int type, /* class and type of query */
412 u_char * answer, /* buffer to put answer */
413 int anslen) /* size of answer */
415 char * nbuf;
416 const char * longname;
417 char * ptr;
418 int n;
420 #if defined(__AROS__)
421 D(bug("[AROSTCP](res_query.c) res_querydomain('%s', '%s')\n", name, domain));
422 #endif
424 if ((nbuf = bsd_malloc(2*MAXDNAME+2, M_TEMP, M_WAITOK)) == NULL) {
425 #if defined(__AROS__)
426 D(bug("[AROSTCP](res_query.c) res_querydomain: failed to allocate buffer\n"));
427 #endif
428 writeErrnoValue(libPtr, ENOMEM);
429 return -1;
431 longname = nbuf;
432 #ifdef RES_DEBUG
433 printf("res_querydomain(%s, %s, %d, %d)\n",
434 name, domain, class, type);
435 #endif
436 if (domain == NULL) {
438 * Check for trailing '.';
439 * copy without '.' if present.
441 n = strlen(name) - 1;
442 if (name[n] == '.' && n < (2*MAXDNAME+2) - 1) {
443 bcopy(name, nbuf, n);
444 nbuf[n] = '\0';
445 } else
446 longname = name;
447 } else {
448 strncpy(nbuf, name, MAXDNAME);
449 ptr = nbuf + strlen(name);
450 *ptr++ = '.';
451 (void)strncpy(ptr, domain, MAXDNAME);
452 #if defined(__AROS__)
453 D(bug("[AROSTCP](res_query.c) res_querydomain: '%s'\n", nbuf));
454 #endif
457 #if defined(__AROS__)
458 D(bug("[AROSTCP](res_query.c) res_querydomain: using name '%s'\n", longname));
459 #endif
460 n = res_query(libPtr, longname, class, type, answer, anslen);
461 bsd_free(nbuf, M_TEMP);
462 return n;
465 #ifndef AMITCP
467 char *
468 __hostalias(name)
469 register const char *name;
471 register char *C1, *C2;
472 FILE *fp;
473 char *file, *getenv(), *strcpy(), *strncpy();
474 char buf[BUFSIZ];
475 static char abuf[MAXDNAME];
477 #if defined(__AROS__)
478 D(bug("[AROSTCP](res_query.c) __hostalias('%s')\n", name));
479 #endif
481 file = getenv("HOSTALIASES");
482 if (file == NULL || (fp = fopen(file, "r")) == NULL)
484 #if defined(__AROS__)
485 D(bug("[AROSTCP](res_query.c) __hostalias: failed to find env setting\n"));
486 #endif
487 return (NULL);
490 buf[sizeof(buf) - 1] = '\0';
491 while (fgets(buf, sizeof(buf), fp)) {
492 for (C1 = buf; *C1 && !isspace(*C1); ++C1);
493 if (!*C1)
494 break;
495 *C1 = '\0';
496 if (!strcasecmp(buf, name)) {
497 while (isspace(*++C1));
498 if (!*C1)
499 break;
500 for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
501 abuf[sizeof(abuf) - 1] = *C2 = '\0';
502 (void)strncpy(abuf, C1, sizeof(abuf) - 1);
503 fclose(fp);
504 #if defined(__AROS__)
505 D(bug("[AROSTCP](res_query.c) __hostalias: returning %s\n", abuf));
506 #endif
507 return (abuf);
510 #if defined(__AROS__)
511 D(bug("[AROSTCP](res_query.c) __hostalias: bad data\n"));
512 #endif
513 fclose(fp);
514 return (NULL);
517 #endif /* !AMITCP */