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