source: rtems/cpukit/libnetworking/libc/res_query.c @ 029c374c

4.104.114.95
Last change on this file since 029c374c was 029c374c, checked in by Ralf Corsepius <ralf.corsepius@…>, on 09/01/08 at 07:02:00

Stop using old-style function definitions.

  • Property mode set to 100644
File size: 11.7 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 * 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/*
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
54/*
55 * Portions Copyright (c) 1996 by Internet Software Consortium.
56 *
57 * Permission to use, copy, modify, and distribute this software for any
58 * purpose with or without fee is hereby granted, provided that the above
59 * copyright notice and this permission notice appear in all copies.
60 *
61 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
62 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
63 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
64 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
65 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
66 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
67 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
68 * SOFTWARE.
69 */
70
71#if HAVE_CONFIG_H
72#include "config.h"
73#endif
74
75#include <sys/types.h>
76#include <sys/param.h>
77#include <netinet/in.h>
78#include <arpa/inet.h>
79#include <arpa/nameser.h>
80#include <ctype.h>
81#include <errno.h>
82#include <netdb.h>
83#include <resolv.h>
84#include <stdio.h>
85#include <stdlib.h>
86#include <string.h>
87
88#include "res_config.h"
89
90#if PACKETSZ > 1024
91#define MAXPACKET       PACKETSZ
92#else
93#define MAXPACKET       1024
94#endif
95
96/*
97 * Formulate a normal query, send, and await answer.
98 * Returned answer is placed in supplied buffer "answer".
99 * Perform preliminary check of answer, returning success only
100 * if no error is indicated and the answer count is nonzero.
101 * Return the size of the response on success, -1 on error.
102 * Error number is left in h_errno.
103 *
104 * Caller must parse answer and determine whether it answers the question.
105 */
106int
107res_query(
108        const char *name,       /* domain name */
109        int class, int type,    /* class and type of query */
110        u_char *answer,         /* buffer to put answer */
111        int anslen)             /* size of answer buffer */
112{
113        u_char buf[MAXPACKET];
114        HEADER *hp = (HEADER *) answer;
115        int n;
116
117        hp->rcode = NOERROR;    /* default */
118
119        if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
120                h_errno = NETDB_INTERNAL;
121                return (-1);
122        }
123#ifdef DEBUG
124        if (_res.options & RES_DEBUG)
125                printf(";; res_query(%s, %d, %d)\n", name, class, type);
126#endif
127
128        n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
129                        buf, sizeof(buf));
130        if (n <= 0) {
131#ifdef DEBUG
132                if (_res.options & RES_DEBUG)
133                        printf(";; res_query: mkquery failed\n");
134#endif
135                h_errno = NO_RECOVERY;
136                return (n);
137        }
138        n = res_send(buf, n, answer, anslen);
139        if (n < 0) {
140#ifdef DEBUG
141                if (_res.options & RES_DEBUG)
142                        printf(";; res_query: send error\n");
143#endif
144                h_errno = TRY_AGAIN;
145                return (n);
146        }
147
148        if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
149#ifdef DEBUG
150                if (_res.options & RES_DEBUG)
151                        printf(";; rcode = %d, ancount=%d\n", hp->rcode,
152                            ntohs(hp->ancount));
153#endif
154                switch (hp->rcode) {
155                case NXDOMAIN:
156                        h_errno = HOST_NOT_FOUND;
157                        break;
158                case SERVFAIL:
159                        h_errno = TRY_AGAIN;
160                        break;
161                case NOERROR:
162                        h_errno = NO_DATA;
163                        break;
164                case FORMERR:
165                case NOTIMP:
166                case REFUSED:
167                default:
168                        h_errno = NO_RECOVERY;
169                        break;
170                }
171                return (-1);
172        }
173        return (n);
174}
175
176/*
177 * Formulate a normal query, send, and retrieve answer in supplied buffer.
178 * Return the size of the response on success, -1 on error.
179 * If enabled, implement search rules until answer or unrecoverable failure
180 * is detected.  Error code, if any, is left in h_errno.
181 */
182int
183res_search(
184        const char *name,       /* domain name */
185        int class, int type,    /* class and type of query */
186        u_char *answer,         /* buffer to put answer */
187        int anslen)             /* size of answer */
188{
189        const char *cp, * const *domain;
190        HEADER *hp = (HEADER *) answer;
191        u_int dots;
192        int trailing_dot, ret, saved_herrno;
193        int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
194
195        if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
196                h_errno = NETDB_INTERNAL;
197                return (-1);
198        }
199        errno = 0;
200        h_errno = HOST_NOT_FOUND;       /* default, if we never query */
201        dots = 0;
202        for (cp = name; *cp; cp++)
203                dots += (*cp == '.');
204        trailing_dot = 0;
205        if (cp > name && *--cp == '.')
206                trailing_dot++;
207
208        /* If there aren't any dots, it could be a user-level alias */
209        if (!dots && (cp = hostalias(name)) != NULL)
210                return (res_query(cp, class, type, answer, anslen));
211
212        /*
213         * If there are dots in the name already, let's just give it a try
214         * 'as is'.  The threshold can be set with the "ndots" option.
215         */
216        saved_herrno = -1;
217        if (dots >= _res.ndots) {
218                ret = res_querydomain(name, NULL, class, type, answer, anslen);
219                if (ret > 0)
220                        return (ret);
221                saved_herrno = h_errno;
222                tried_as_is++;
223        }
224
225        /*
226         * We do at least one level of search if
227         *      - there is no dot and RES_DEFNAME is set, or
228         *      - there is at least one dot, there is no trailing dot,
229         *        and RES_DNSRCH is set.
230         */
231        if ((!dots && (_res.options & RES_DEFNAMES)) ||
232            (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
233                int done = 0;
234
235                for (domain = (const char * const *)_res.dnsrch;
236                     *domain && !done;
237                     domain++) {
238
239                        ret = res_querydomain(name, *domain, class, type,
240                                              answer, anslen);
241                        if (ret > 0)
242                                return (ret);
243
244                        /*
245                         * If no server present, give up.
246                         * If name isn't found in this domain,
247                         * keep trying higher domains in the search list
248                         * (if that's enabled).
249                         * On a NO_DATA error, keep trying, otherwise
250                         * a wildcard entry of another type could keep us
251                         * from finding this entry higher in the domain.
252                         * If we get some other error (negative answer or
253                         * server failure), then stop searching up,
254                         * but try the input name below in case it's
255                         * fully-qualified.
256                         */
257                        if (errno == ECONNREFUSED) {
258                                h_errno = TRY_AGAIN;
259                                return (-1);
260                        }
261
262                        switch (h_errno) {
263                        case NO_DATA:
264                                got_nodata++;
265                                /* FALLTHROUGH */
266                        case HOST_NOT_FOUND:
267                                /* keep trying */
268                                break;
269                        case TRY_AGAIN:
270                                if (hp->rcode == SERVFAIL) {
271                                        /* try next search element, if any */
272                                        got_servfail++;
273                                        break;
274                                }
275                                /* FALLTHROUGH */
276                        default:
277                                /* anything else implies that we're done */
278                                done++;
279                        }
280
281                        /* if we got here for some reason other than DNSRCH,
282                         * we only wanted one iteration of the loop, so stop.
283                         */
284                        if (!(_res.options & RES_DNSRCH))
285                                done++;
286                }
287        }
288
289        /*
290         * If we have not already tried the name "as is", do that now.
291         * note that we do this regardless of how many dots were in the
292         * name or whether it ends with a dot unless NOTLDQUERY is set.
293         */
294        if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) {
295                ret = res_querydomain(name, NULL, class, type, answer, anslen);
296                if (ret > 0)
297                        return (ret);
298        }
299
300        /* if we got here, we didn't satisfy the search.
301         * if we did an initial full query, return that query's h_errno
302         * (note that we wouldn't be here if that query had succeeded).
303         * else if we ever got a nodata, send that back as the reason.
304         * else send back meaningless h_errno, that being the one from
305         * the last DNSRCH we did.
306         */
307        if (saved_herrno != -1)
308                h_errno = saved_herrno;
309        else if (got_nodata)
310                h_errno = NO_DATA;
311        else if (got_servfail)
312                h_errno = TRY_AGAIN;
313        return (-1);
314}
315
316/*
317 * Perform a call on res_query on the concatenation of name and domain,
318 * removing a trailing dot from name if domain is NULL.
319 */
320int
321res_querydomain(
322        const char *name, const char *domain,
323        int class, int type,    /* class and type of query */
324        u_char *answer,         /* buffer to put answer */
325        int anslen)             /* size of answer */
326{
327        char nbuf[MAXDNAME];
328        const char *longname = nbuf;
329        int n, d;
330
331        if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
332                h_errno = NETDB_INTERNAL;
333                return (-1);
334        }
335#ifdef DEBUG
336        if (_res.options & RES_DEBUG)
337                printf(";; res_querydomain(%s, %s, %d, %d)\n",
338                       name, domain?domain:"<Nil>", class, type);
339#endif
340        if (domain == NULL) {
341                /*
342                 * Check for trailing '.';
343                 * copy without '.' if present.
344                 */
345                n = strlen(name);
346                if (n >= MAXDNAME) {
347                        h_errno = NO_RECOVERY;
348                        return (-1);
349                }
350                n--;
351                if (n >= 0 && name[n] == '.') {
352                        strncpy(nbuf, name, n);
353                        nbuf[n] = '\0';
354                } else
355                        longname = name;
356        } else {
357                n = strlen(name);
358                d = strlen(domain);
359                if (n + d + 1 >= MAXDNAME) {
360                        h_errno = NO_RECOVERY;
361                        return (-1);
362                }
363                sprintf(nbuf, "%s.%s", name, domain);
364        }
365        return (res_query(longname, class, type, answer, anslen));
366}
367
368const char *
369hostalias(const char *name)
370{
371        register char *cp1, *cp2;
372        FILE *fp;
373        char *file;
374        char buf[BUFSIZ];
375        static char abuf[MAXDNAME];
376
377        if (_res.options & RES_NOALIASES)
378                return (NULL);
379        if (issetugid())
380                return (NULL);
381        file = getenv("HOSTALIASES");
382        if (file == NULL || (fp = fopen(file, "r")) == NULL)
383                return (NULL);
384        setbuf(fp, NULL);
385        buf[sizeof(buf) - 1] = '\0';
386        while (fgets(buf, sizeof(buf), fp)) {
387                for (cp1 = buf; *cp1 && !isspace((int)*cp1); ++cp1)
388                        ;
389                if (!*cp1)
390                        break;
391                *cp1 = '\0';
392                if (!strcasecmp(buf, name)) {
393                        while (isspace((int)*++cp1))
394                                ;
395                        if (!*cp1)
396                                break;
397                        for (cp2 = cp1 + 1; *cp2 && !isspace((int)*cp2); ++cp2)
398                                ;
399                        abuf[sizeof(abuf) - 1] = *cp2 = '\0';
400                        strncpy(abuf, cp1, sizeof(abuf) - 1);
401                        fclose(fp);
402                        return (abuf);
403                }
404        }
405        fclose(fp);
406        return (NULL);
407}
Note: See TracBrowser for help on using the repository browser.