2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
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,
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
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
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 */
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>
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>
80 #define MAXPACKET PACKETSZ
82 #define MAXPACKET 1024
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.
94 res_query(struct SocketBase
* libPtr
,
95 const char * name
, /* domain name */
97 int type
, /* class and type of query */
98 u_char
* answer
, /* buffer to put answer */
99 int anslen
) /* size of answer buffer */
105 #if defined(__AROS__)
106 D(bug("[AROSTCP](res_query.c) res_query()\n"));
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"));
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"));
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"));
137 writeErrnoValue(libPtr
, ENOMEM
);
141 #if defined(__AROS__)
142 D(bug("[AROSTCP](res_query.c) res_query: name: %s class: %d type %d\n", name
, class, type
));
145 printf("res_query(%s, %d, %d)\n", name
, class, type
);
147 n
= res_mkquery(libPtr
, QUERY
, name
, class, type
, (char *)NULL
, 0, NULL
,
151 #if defined(__AROS__)
152 D(bug("[AROSTCP](res_query.c) res_query: [res_mkquery] Failed\n"));
155 printf("res_query: mkquery failed\n");
157 h_errno
= NO_RECOVERY
;
161 /* TODO: NicJA - Where is CHECK_POINTER() !!!! */
162 #if !defined(__AROS__)
166 n
= res_send(libPtr
, buf
, n
, (char *)answer
, anslen
);
169 #if defined(__AROS__)
170 D(bug("[AROSTCP](res_query.c) res_query: [res_send] Failed\n"));
173 printf("res_query: send error\n");
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
)));
185 printf("rcode = %d, ancount=%d\n", hp
->rcode
,
190 #if defined(__AROS__)
191 D(bug("[AROSTCP](res_query.c) res_query: [res_send] Error: Host not found!\n"));
193 h_errno
= HOST_NOT_FOUND
;
196 #if defined(__AROS__)
197 D(bug("[AROSTCP](res_query.c) res_query: [res_send] Error: Server Fail!\n"));
202 #if defined(__AROS__)
203 D(bug("[AROSTCP](res_query.c) res_query: [res_send] Error: !IMPOSSIBLE CASE!\n"));
211 #if defined(__AROS__)
212 D(bug("[AROSTCP](res_query.c) res_query: [res_send] Error: Unknown!\n"));
214 h_errno
= NO_RECOVERY
;
222 bsd_free(buf
, M_TEMP
);
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 */
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
;
245 int n
, ret
, got_nodata
= 0;
248 #if defined(__AROS__)
249 D(bug("[AROSTCP](res_query.c) res_search('%s')\n", name
));
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"));
264 #if defined(__AROS__)
265 D(bug("[AROSTCP](res_query.c) res_search: resolver initialised. base @ %x\n", &_res
));
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"));
278 #if defined(__AROS__)
279 D(bug("[AROSTCP](res_query.c) res_search: resolver db updated\n"));
283 writeErrnoValue(libPtr
, 0);
284 h_errno
= HOST_NOT_FOUND
; /* default, if we never query */
285 for (cp
= name
, n
= 0; *cp
; cp
++)
290 if (n
== 0 && (cp
= __hostalias(name
)))
292 #if defined(__AROS__)
293 D(bug("[AROSTCP](res_query.c) res_search: returning hostalias response\n"));
295 return (res_query(cp
, class, type
, answer
, anslen
));
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"));
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"));
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
));
329 ret
= res_querydomain(libPtr
, name
, *domain
,
330 class, type
, answer
, anslen
);
333 #if defined(__AROS__)
334 D(bug("[AROSTCP](res_query.c) res_search: returning querydomain response\n"));
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
)) {
354 #if defined(__AROS__)
355 D(bug("[AROSTCP](res_query.c) res_search: resolver failed to connect, setting retry\n"));
360 if (h_errno
== NO_DATA
)
362 #if defined(__AROS__)
363 D(bug("[AROSTCP](res_query.c) res_search: resolver got no response\n"));
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"));
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
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"));
394 #if defined(__AROS__)
395 D(bug("[AROSTCP](res_query.c) res_search: finished search.\n"));
397 if (got_nodata
) h_errno
= NO_DATA
;
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
,
411 int type
, /* class and type of query */
412 u_char
* answer
, /* buffer to put answer */
413 int anslen
) /* size of answer */
416 const char * longname
;
420 #if defined(__AROS__)
421 D(bug("[AROSTCP](res_query.c) res_querydomain('%s', '%s')\n", name
, domain
));
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"));
428 writeErrnoValue(libPtr
, ENOMEM
);
433 printf("res_querydomain(%s, %s, %d, %d)\n",
434 name
, domain
, class, type
);
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
);
448 strncpy(nbuf
, name
, MAXDNAME
);
449 ptr
= nbuf
+ strlen(name
);
451 (void)strncpy(ptr
, domain
, MAXDNAME
);
452 #if defined(__AROS__)
453 D(bug("[AROSTCP](res_query.c) res_querydomain: '%s'\n", nbuf
));
457 #if defined(__AROS__)
458 D(bug("[AROSTCP](res_query.c) res_querydomain: using name '%s'\n", longname
));
460 n
= res_query(libPtr
, longname
, class, type
, answer
, anslen
);
461 bsd_free(nbuf
, M_TEMP
);
469 register const char *name
;
471 register char *C1
, *C2
;
473 char *file
, *getenv(), *strcpy(), *strncpy();
475 static char abuf
[MAXDNAME
];
477 #if defined(__AROS__)
478 D(bug("[AROSTCP](res_query.c) __hostalias('%s')\n", name
));
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"));
490 buf
[sizeof(buf
) - 1] = '\0';
491 while (fgets(buf
, sizeof(buf
), fp
)) {
492 for (C1
= buf
; *C1
&& !isspace(*C1
); ++C1
);
496 if (!strcasecmp(buf
, name
)) {
497 while (isspace(*++C1
));
500 for (C2
= C1
+ 1; *C2
&& !isspace(*C2
); ++C2
);
501 abuf
[sizeof(abuf
) - 1] = *C2
= '\0';
502 (void)strncpy(abuf
, C1
, sizeof(abuf
) - 1);
504 #if defined(__AROS__)
505 D(bug("[AROSTCP](res_query.c) __hostalias: returning %s\n", abuf
));
510 #if defined(__AROS__)
511 D(bug("[AROSTCP](res_query.c) __hostalias: bad data\n"));