source: trunk/libs/newlib/src/newlib/libc/sys/linux/net/res_query.c

Last change on this file was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 14.3 KB
Line 
1/*
2 * Copyright (c) 1988, 1993
3 *    The Regents of the University of California.  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 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/*
31 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
32 *
33 * Permission to use, copy, modify, and distribute this software for any
34 * purpose with or without fee is hereby granted, provided that the above
35 * copyright notice and this permission notice appear in all copies, and that
36 * the name of Digital Equipment Corporation not be used in advertising or
37 * publicity pertaining to distribution of the document or software without
38 * specific, written prior permission.
39 *
40 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42 * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
43 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47 * SOFTWARE.
48 */
49
50/*
51 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
52 *
53 * Permission to use, copy, modify, and distribute this software for any
54 * purpose with or without fee is hereby granted, provided that the above
55 * copyright notice and this permission notice appear in all copies.
56 *
57 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
58 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
59 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
60 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
61 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
62 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
63 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
64 * SOFTWARE.
65 */
66
67#if defined(LIBC_SCCS) && !defined(lint)
68static const char sccsid[] = "@(#)res_query.c   8.1 (Berkeley) 6/4/93";
69static const char rcsid[] = "$BINDId: res_query.c,v 8.20 2000/02/29 05:39:12 vixie Exp $";
70#endif /* LIBC_SCCS and not lint */
71
72#include <sys/types.h>
73#include <sys/param.h>
74#include <netinet/in.h>
75#include <arpa/inet.h>
76#include <arpa/nameser.h>
77#include <ctype.h>
78#include <errno.h>
79#include <netdb.h>
80#include <resolv.h>
81#include <stdio.h>
82#include <stdlib.h>
83#include <string.h>
84#include "libc-symbols.h"
85
86/* Options.  Leave them on. */
87/* #undef DEBUG */
88
89#if PACKETSZ > 65536
90#define MAXPACKET       PACKETSZ
91#else
92#define MAXPACKET       65536
93#endif
94
95#define QUERYSIZE       (HFIXEDSZ + QFIXEDSZ + MAXCDNAME + 1)
96
97static int
98__libc_res_nquerydomain(res_state statp, const char *name, const char *domain,
99                        int class, int type, u_char *answer, int anslen,
100                        u_char **answerp);
101
102/*
103 * Formulate a normal query, send, and await answer.
104 * Returned answer is placed in supplied buffer "answer".
105 * Perform preliminary check of answer, returning success only
106 * if no error is indicated and the answer count is nonzero.
107 * Return the size of the response on success, -1 on error.
108 * Error number is left in H_ERRNO.
109 *
110 * Caller must parse answer and determine whether it answers the question.
111 */
112int
113__libc_res_nquery(res_state statp,
114                  const char *name,     /* domain name */
115                  int class, int type,  /* class and type of query */
116                  u_char *answer,       /* buffer to put answer */
117                  int anslen,           /* size of answer buffer */
118                  u_char **answerp)     /* if buffer needs to be enlarged */
119{
120        u_char *buf;
121        HEADER *hp = (HEADER *) answer;
122        int n, use_malloc = 0;
123
124        hp->rcode = NOERROR;    /* default */
125
126        buf = alloca (QUERYSIZE);
127
128#ifdef DEBUG
129        if (statp->options & RES_DEBUG)
130                printf(";; res_query(%s, %d, %d)\n", name, class, type);
131#endif
132
133        n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
134                         buf, QUERYSIZE);
135        if (__builtin_expect (n <= 0, 0)) {
136                /* Retry just in case res_nmkquery failed because of too
137                   short buffer.  Shouldn't happen.  */
138                buf = malloc (MAXPACKET);
139                if (buf != NULL) {
140                        use_malloc = 1;
141                        n = res_nmkquery(statp, QUERY, name, class, type, NULL,
142                                         0, NULL, buf, MAXPACKET);
143                }
144        }
145        if (__builtin_expect (n <= 0, 0)) {
146#ifdef DEBUG
147                if (statp->options & RES_DEBUG)
148                        printf(";; res_query: mkquery failed\n");
149#endif
150                RES_SET_H_ERRNO(statp, NO_RECOVERY);
151                if (use_malloc)
152                        free (buf);
153                return (n);
154        }
155        n = __libc_res_nsend(statp, buf, n, answer, anslen, answerp);
156        if (use_malloc)
157                free (buf);
158        if (n < 0) {
159#ifdef DEBUG
160                if (statp->options & RES_DEBUG)
161                        printf(";; res_query: send error\n");
162#endif
163                RES_SET_H_ERRNO(statp, TRY_AGAIN);
164                return (n);
165        }
166
167        if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
168#ifdef DEBUG
169                if (statp->options & RES_DEBUG)
170                        printf(";; rcode = %d, ancount=%d\n", hp->rcode,
171                            ntohs(hp->ancount));
172#endif
173                switch (hp->rcode) {
174                case NXDOMAIN:
175                        RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
176                        break;
177                case SERVFAIL:
178                        RES_SET_H_ERRNO(statp, TRY_AGAIN);
179                        break;
180                case NOERROR:
181                        RES_SET_H_ERRNO(statp, NO_DATA);
182                        break;
183                case FORMERR:
184                case NOTIMP:
185                case REFUSED:
186                default:
187                        RES_SET_H_ERRNO(statp, NO_RECOVERY);
188                        break;
189                }
190                return (-1);
191        }
192        return (n);
193}
194libresolv_hidden_def (__libc_res_nquery)
195
196int
197res_nquery(res_state statp,
198           const char *name,    /* domain name */
199           int class, int type, /* class and type of query */
200           u_char *answer,      /* buffer to put answer */
201           int anslen)          /* size of answer buffer */
202{
203        return __libc_res_nquery(statp, name, class, type, answer, anslen,
204                                 NULL);
205}
206libresolv_hidden_def (res_nquery)
207
208/*
209 * Formulate a normal query, send, and retrieve answer in supplied buffer.
210 * Return the size of the response on success, -1 on error.
211 * If enabled, implement search rules until answer or unrecoverable failure
212 * is detected.  Error code, if any, is left in H_ERRNO.
213 */
214int
215__libc_res_nsearch(res_state statp,
216            const char *name,   /* domain name */
217            int class, int type,        /* class and type of query */
218            u_char *answer,     /* buffer to put answer */
219            int anslen,         /* size of answer */
220            u_char **answerp)
221{
222        const char *cp, * const *domain;
223        HEADER *hp = (HEADER *) answer;
224        char tmp[NS_MAXDNAME];
225        u_int dots;
226        int trailing_dot, ret, saved_herrno;
227        int got_nodata = 0, got_servfail = 0, root_on_list = 0;
228        int tried_as_is = 0;
229
230        __set_errno (0);
231        RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);  /* True if we never query. */
232
233        dots = 0;
234        for (cp = name; *cp != '\0'; cp++)
235                dots += (*cp == '.');
236        trailing_dot = 0;
237        if (cp > name && *--cp == '.')
238                trailing_dot++;
239
240        /* If there aren't any dots, it could be a user-level alias. */
241        if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
242                return (__libc_res_nquery(statp, cp, class, type, answer,
243                                          anslen, answerp));
244
245#ifdef DEBUG
246        if (statp->options & RES_DEBUG)
247                printf("dots=%d, statp->ndots=%d, trailing_dot=%d, name=%s\n",
248                       (int)dots,(int)statp->ndots,(int)trailing_dot,name);
249#endif
250
251        /*
252         * If there are enough dots in the name, let's just give it a
253         * try 'as is'. The threshold can be set with the "ndots" option.
254         * Also, query 'as is', if there is a trailing dot in the name.
255         */
256        saved_herrno = -1;
257        if (dots >= statp->ndots || trailing_dot) {
258                ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
259                                              answer, anslen, answerp);
260                if (ret > 0 || trailing_dot)
261                        return (ret);
262                saved_herrno = h_errno;
263                tried_as_is++;
264                if (answerp && *answerp != answer) {
265                        answer = *answerp;
266                        anslen = MAXPACKET;
267                }
268        }
269
270        /*
271         * We do at least one level of search if
272         *      - there is no dot and RES_DEFNAME is set, or
273         *      - there is at least one dot, there is no trailing dot,
274         *        and RES_DNSRCH is set.
275         */
276        if ((!dots && (statp->options & RES_DEFNAMES) != 0) ||
277            (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) {
278                int done = 0;
279
280                for (domain = (const char * const *)statp->dnsrch;
281                     *domain && !done;
282                     domain++) {
283
284                        if (domain[0][0] == '\0' ||
285                            (domain[0][0] == '.' && domain[0][1] == '\0'))
286                                root_on_list++;
287
288                        ret = __libc_res_nquerydomain(statp, name, *domain,
289                                                      class, type,
290                                                      answer, anslen, answerp);
291                        if (ret > 0)
292                                return (ret);
293
294                        if (answerp && *answerp != answer) {
295                                answer = *answerp;
296                                anslen = MAXPACKET;
297                        }
298
299                        /*
300                         * If no server present, give up.
301                         * If name isn't found in this domain,
302                         * keep trying higher domains in the search list
303                         * (if that's enabled).
304                         * On a NO_DATA error, keep trying, otherwise
305                         * a wildcard entry of another type could keep us
306                         * from finding this entry higher in the domain.
307                         * If we get some other error (negative answer or
308                         * server failure), then stop searching up,
309                         * but try the input name below in case it's
310                         * fully-qualified.
311                         */
312                        if (errno == ECONNREFUSED) {
313                                RES_SET_H_ERRNO(statp, TRY_AGAIN);
314                                return (-1);
315                        }
316
317                        switch (statp->res_h_errno) {
318                        case NO_DATA:
319                                got_nodata++;
320                                /* FALLTHROUGH */
321                        case HOST_NOT_FOUND:
322                                /* keep trying */
323                                break;
324                        case TRY_AGAIN:
325                                if (hp->rcode == SERVFAIL) {
326                                        /* try next search element, if any */
327                                        got_servfail++;
328                                        break;
329                                }
330                                /* FALLTHROUGH */
331                        default:
332                                /* anything else implies that we're done */
333                                done++;
334                        }
335
336                        /* if we got here for some reason other than DNSRCH,
337                         * we only wanted one iteration of the loop, so stop.
338                         */
339                        if ((statp->options & RES_DNSRCH) == 0)
340                                done++;
341                }
342        }
343
344        /*
345         * If the name has any dots at all, and no earlier 'as-is' query
346         * for the name, and "." is not on the search list, then try an as-is
347         * query now.
348         */
349        if (dots && !(tried_as_is || root_on_list)) {
350                ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
351                                              answer, anslen, answerp);
352                if (ret > 0)
353                        return (ret);
354        }
355
356        /* if we got here, we didn't satisfy the search.
357         * if we did an initial full query, return that query's H_ERRNO
358         * (note that we wouldn't be here if that query had succeeded).
359         * else if we ever got a nodata, send that back as the reason.
360         * else send back meaningless H_ERRNO, that being the one from
361         * the last DNSRCH we did.
362         */
363        if (saved_herrno != -1)
364                RES_SET_H_ERRNO(statp, saved_herrno);
365        else if (got_nodata)
366                RES_SET_H_ERRNO(statp, NO_DATA);
367        else if (got_servfail)
368                RES_SET_H_ERRNO(statp, TRY_AGAIN);
369        return (-1);
370}
371libresolv_hidden_def (__libc_res_nsearch)
372
373int
374res_nsearch(res_state statp,
375            const char *name,   /* domain name */
376            int class, int type,        /* class and type of query */
377            u_char *answer,     /* buffer to put answer */
378            int anslen)         /* size of answer */
379{
380        return __libc_res_nsearch(statp, name, class, type, answer,
381                                  anslen, NULL);
382}
383libresolv_hidden_def (res_nsearch)
384
385/*
386 * Perform a call on res_query on the concatenation of name and domain,
387 * removing a trailing dot from name if domain is NULL.
388 */
389static int
390__libc_res_nquerydomain(res_state statp,
391            const char *name,
392            const char *domain,
393            int class, int type,        /* class and type of query */
394            u_char *answer,             /* buffer to put answer */
395            int anslen,                 /* size of answer */
396            u_char **answerp)
397{
398        char nbuf[MAXDNAME];
399        const char *longname = nbuf;
400        int n, d;
401
402#ifdef DEBUG
403        if (statp->options & RES_DEBUG)
404                printf(";; res_nquerydomain(%s, %s, %d, %d)\n",
405                       name, domain?domain:"<Nil>", class, type);
406#endif
407        if (domain == NULL) {
408                /*
409                 * Check for trailing '.';
410                 * copy without '.' if present.
411                 */
412                n = strlen(name);
413                if (n >= MAXDNAME) {
414                        RES_SET_H_ERRNO(statp, NO_RECOVERY);
415                        return (-1);
416                }
417                n--;
418                if (n >= 0 && name[n] == '.') {
419                        strncpy(nbuf, name, n);
420                        nbuf[n] = '\0';
421                } else
422                        longname = name;
423        } else {
424                n = strlen(name);
425                d = strlen(domain);
426                if (n + d + 1 >= MAXDNAME) {
427                        RES_SET_H_ERRNO(statp, NO_RECOVERY);
428                        return (-1);
429                }
430                sprintf(nbuf, "%s.%s", name, domain);
431        }
432        return (__libc_res_nquery(statp, longname, class, type, answer,
433                                  anslen, answerp));
434}
435
436int
437res_nquerydomain(res_state statp,
438            const char *name,
439            const char *domain,
440            int class, int type,        /* class and type of query */
441            u_char *answer,             /* buffer to put answer */
442            int anslen)         /* size of answer */
443{
444        return __libc_res_nquerydomain(statp, name, domain, class, type,
445                                       answer, anslen, NULL);
446}
447libresolv_hidden_def (res_nquerydomain)
448
449const char *
450res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
451        char *file, *cp1, *cp2;
452        char buf[BUFSIZ];
453        FILE *fp;
454
455        if (statp->options & RES_NOALIASES)
456                return (NULL);
457        file = getenv("HOSTALIASES");
458        if (file == NULL || (fp = fopen(file, "r")) == NULL)
459                return (NULL);
460        setbuf(fp, NULL);
461        buf[sizeof(buf) - 1] = '\0';
462        while (fgets(buf, sizeof(buf), fp)) {
463                for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1)
464                        ;
465                if (!*cp1)
466                        break;
467                *cp1 = '\0';
468                if (ns_samename(buf, name) == 1) {
469                        while (isspace(*++cp1))
470                                ;
471                        if (!*cp1)
472                                break;
473                        for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2)
474                                ;
475                        *cp2 = '\0';
476                        strncpy(dst, cp1, siz - 1);
477                        dst[siz - 1] = '\0';
478                        fclose(fp);
479                        return (dst);
480                }
481        }
482        fclose(fp);
483        return (NULL);
484}
485libresolv_hidden_def (res_hostalias)
Note: See TracBrowser for help on using the repository browser.