source: rtems/cpukit/libnetworking/libc/res_query.c @ 96b39164

4.104.114.84.95
Last change on this file since 96b39164 was ff0f694d, checked in by Joel Sherrill <joel.sherrill@…>, on 08/20/98 at 21:47:37

Fixed many warnings.

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