source: trunk/athena/bin/hostinfo/res_query.c @ 9858

Revision 9858, 7.6 KB checked in by ghudson, 28 years ago (diff)
Make some arguments const to agree with prototypes on Solaris. This whole situation of redefining libc functions is bad business, and hostinfo needs a serious overhaul at some point. But not during a release cycle.
Line 
1/*
2 * Copyright (c) 1988 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley.  The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17
18#if defined(LIBC_SCCS) && !defined(lint)
19static char sccsid[] = "@(#)res_query.c 5.5 (Berkeley) 9/21/88";
20#endif /* LIBC_SCCS and not lint */
21
22#ifdef _IBMR2
23#define BIT_ZERO_ON_LEFT
24#endif
25
26#ifdef _AUX_SOURCE
27#include <sys/types.h>
28#endif
29
30#include <sys/param.h>
31#include <sys/socket.h>
32#include <netinet/in.h>
33#include <ctype.h>
34#include <netdb.h>
35#include <stdio.h>
36#include <errno.h>
37#include <string.h>
38#include <arpa/inet.h>
39#include <arpa/nameser.h>
40#include <resolv.h>
41
42#if !defined NO_DATA
43#define NO_DATA NO_ADDRESS
44#endif
45
46#if PACKETSZ > 1024
47#define MAXPACKET       PACKETSZ
48#else
49#define MAXPACKET       1024
50#endif
51
52extern int server_specified;
53extern struct in_addr server_addr;
54extern int errno;
55int h_errno;
56
57/*
58 * Formulate a normal query, send, and await answer.
59 * Returned answer is placed in supplied buffer "answer".
60 * Perform preliminary check of answer, returning success only
61 * if no error is indicated and the answer count is nonzero.
62 * Return the size of the response on success, -1 on error.
63 * Error number is left in h_errno.
64 * Caller must parse answer and determine whether it answers the question.
65 */
66res_query(name, class, type, answer, anslen)
67        const char *name;       /* domain name */
68        int class, type;        /* class and type of query */
69        u_char *answer;         /* buffer to put answer */
70        int anslen;             /* size of answer buffer */
71{
72        char buf[MAXPACKET];
73        HEADER *hp;
74        int n;
75
76        if ((_res.options & RES_INIT) == 0 && res_init() == -1)
77                return (-1);
78
79        if(server_specified)
80          _res.nsaddr.sin_addr = server_addr;
81         
82#ifdef DEBUG
83        if (_res.options & RES_DEBUG)
84                printf("res_query(%s, %d, %d)\n", name, class, type);
85#endif
86        n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL,
87            buf, sizeof(buf));
88
89        if (n <= 0) {
90#ifdef DEBUG
91                if (_res.options & RES_DEBUG)
92                        printf("res_query: mkquery failed\n");
93#endif
94                h_errno = NO_RECOVERY;
95                return (n);
96        }
97        n = res_send(buf, n, answer, anslen);
98        if (n < 0) {
99#ifdef DEBUG
100                if (_res.options & RES_DEBUG)
101                        printf("res_query: send error\n");
102#endif
103                h_errno = TRY_AGAIN;
104                return(n);
105        }
106
107        hp = (HEADER *) answer;
108        if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
109#ifdef DEBUG
110                if (_res.options & RES_DEBUG)
111                        printf("rcode = %d, ancount=%d\n", hp->rcode,
112                            ntohs(hp->ancount));
113#endif
114                switch (hp->rcode) {
115                        case NXDOMAIN:
116                                h_errno = HOST_NOT_FOUND;
117                                break;
118                        case SERVFAIL:
119                                h_errno = TRY_AGAIN;
120                                break;
121                        case NOERROR:
122                                h_errno = NO_DATA;
123                                break;
124                        case FORMERR:
125                        case NOTIMP:
126                        case REFUSED:
127                        default:
128                                h_errno = NO_RECOVERY;
129                                break;
130                }
131                return (-1);
132        }
133        return(n);
134}
135
136/*
137 * Formulate a normal query, send, and retrieve answer in supplied buffer.
138 * Return the size of the response on success, -1 on error.
139 * If enabled, implement search rules until answer or unrecoverable failure
140 * is detected.  Error number is left in h_errno.
141 * Only useful for queries in the same name hierarchy as the local host
142 * (not, for example, for host address-to-name lookups in domain in-addr.arpa).
143 */
144res_search(name, class, type, answer, anslen)
145        const char *name;       /* domain name */
146        int class, type;        /* class and type of query */
147        u_char *answer;         /* buffer to put answer */
148        int anslen;             /* size of answer */
149{
150        register char *cp, **domain;
151        int n, ret, got_nodata = 0;
152        char *hostalias();
153
154        if ((_res.options & RES_INIT) == 0 && res_init() == -1)
155                return (-1);
156
157        errno = 0;
158        h_errno = HOST_NOT_FOUND;               /* default, if we never query */
159        for (cp = name, n = 0; *cp; cp++)
160                if (*cp == '.')
161                        n++;
162        if (n == 0 && (cp = hostalias(name)))
163                return (res_query(cp, class, type, answer, anslen));
164
165        /*
166         * We do at least one level of search if
167         *      - there is no dot and RES_DEFNAME is set, or
168         *      - there is at least one dot, there is no trailing dot,
169         *        and RES_DNSRCH is set.
170         */
171        if ((n == 0 && _res.options & RES_DEFNAMES) ||
172           (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH))
173             for (domain = _res.dnsrch; *domain; domain++) {
174                ret = res_querydomain(name, *domain, class, type,
175                    answer, anslen);
176                if (ret > 0)
177                        return (ret);
178                /*
179                 * If no server present, give up.
180                 * If name isn't found in this domain,
181                 * keep trying higher domains in the search list
182                 * (if that's enabled).
183                 * On a NO_DATA error, keep trying, otherwise
184                 * a wildcard entry of another type could keep us
185                 * from finding this entry higher in the domain.
186                 * If we get some other error (negative answer or
187                 * server failure), then stop searching up,
188                 * but try the input name below in case it's fully-qualified.
189                 */
190                if (errno == ECONNREFUSED) {
191                        h_errno = TRY_AGAIN;
192                        return (-1);
193                }
194                if (h_errno == NO_DATA)
195                        got_nodata++;
196                if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) ||
197                    (_res.options & RES_DNSRCH) == 0)
198                        break;
199        }
200        /*
201         * If the search/default failed, try the name as fully-qualified,
202         * but only if it contained at least one dot (even trailing).
203         * This is purely a heuristic; we assume that any reasonable query
204         * about a top-level domain (for servers, SOA, etc) will not use
205         * res_search.
206         */
207        if (n && (ret = res_querydomain(name, (char *)NULL, class, type,
208            answer, anslen)) > 0)
209                return (ret);
210        if (got_nodata)
211                h_errno = NO_DATA;
212        return (-1);
213}
214
215/*
216 * Perform a call on res_query on the concatenation of name and domain,
217 * removing a trailing dot from name if domain is NULL.
218 */
219res_querydomain(name, domain, class, type, answer, anslen)
220        const char *name, *domain;
221        int class, type;        /* class and type of query */
222        u_char *answer;         /* buffer to put answer */
223        int anslen;             /* size of answer */
224{
225        char nbuf[2*MAXDNAME+2];
226        char *longname = nbuf;
227        int n;
228
229#ifdef DEBUG
230        if (_res.options & RES_DEBUG)
231                printf("res_querydomain(%s, %s, %d, %d)\n",
232                    name, domain, class, type);
233#endif
234        if (domain == NULL) {
235                /*
236                 * Check for trailing '.';
237                 * copy without '.' if present.
238                 */
239                n = strlen(name) - 1;
240                if (name[n] == '.' && n < sizeof(nbuf) - 1) {
241                        memcpy(nbuf, name, n);
242                        nbuf[n] = '\0';
243                } else
244                        longname = name;
245        } else
246                (void)sprintf(nbuf, "%.*s.%.*s",
247                    MAXDNAME, name, MAXDNAME, domain);
248
249        return (res_query(longname, class, type, answer, anslen));
250}
251
252char *
253hostalias(name)
254        const char *name;
255{
256        register char *C1, *C2;
257        FILE *fp;
258#ifndef _IBMR2
259        char *file, *getenv(), *strcpy(), *strncpy();
260#else
261        char *file;
262#endif
263        char buf[BUFSIZ];
264        static char abuf[MAXDNAME];
265
266        file = getenv("HOSTALIASES");
267        if (file == NULL || (fp = fopen(file, "r")) == NULL)
268                return (NULL);
269        buf[sizeof(buf) - 1] = '\0';
270        while (fgets(buf, sizeof(buf), fp)) {
271                for (C1 = buf; *C1 && !isspace(*C1); ++C1);
272                if (!*C1)
273                        break;
274                *C1 = '\0';
275                if (!strcasecmp(buf, name)) {
276                        while (isspace(*++C1));
277                        if (!*C1)
278                                break;
279                        for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
280                        abuf[sizeof(abuf) - 1] = *C2 = '\0';
281                        (void)strncpy(abuf, C1, sizeof(abuf) - 1);
282                        fclose(fp);
283                        return (abuf);
284                }
285        }
286        fclose(fp);
287        return (NULL);
288}
Note: See TracBrowser for help on using the repository browser.