sockaddr's now require length (K. Sklower);
[unix-history] / usr / src / lib / libc / net / res_query.c
CommitLineData
345feb69
KB
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
3ec8dabc
MK
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.
345feb69
KB
16 */
17
18#if defined(LIBC_SCCS) && !defined(lint)
3ec8dabc 19static char sccsid[] = "@(#)res_query.c 5.5 (Berkeley) %G%";
345feb69
KB
20#endif /* LIBC_SCCS and not lint */
21
22#include <sys/param.h>
23#include <sys/socket.h>
24#include <netinet/in.h>
25#include <ctype.h>
26#include <netdb.h>
27#include <stdio.h>
28#include <errno.h>
29#include <strings.h>
30#include <arpa/inet.h>
31#include <arpa/nameser.h>
32#include <resolv.h>
33
34#if PACKETSZ > 1024
35#define MAXPACKET PACKETSZ
36#else
37#define MAXPACKET 1024
38#endif
39
40extern int errno;
41int h_errno;
42
43/*
44 * Formulate a normal query, send, and await answer.
45 * Returned answer is placed in supplied buffer "answer".
46 * Perform preliminary check of answer, returning success only
47 * if no error is indicated and the answer count is nonzero.
48 * Return the size of the response on success, -1 on error.
49 * Error number is left in h_errno.
a5e08740 50 * Caller must parse answer and determine whether it answers the question.
345feb69
KB
51 */
52res_query(name, class, type, answer, anslen)
53 char *name; /* domain name */
54 int class, type; /* class and type of query */
55 u_char *answer; /* buffer to put answer */
56 int anslen; /* size of answer buffer */
57{
58 char buf[MAXPACKET];
59 HEADER *hp;
60 int n;
61
62 if ((_res.options & RES_INIT) == 0 && res_init() == -1)
63 return (-1);
64#ifdef DEBUG
65 if (_res.options & RES_DEBUG)
66 printf("res_query(%s, %d, %d)\n", name, class, type);
67#endif
68 n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL,
69 buf, sizeof(buf));
70
71 if (n <= 0) {
72#ifdef DEBUG
73 if (_res.options & RES_DEBUG)
74 printf("res_query: mkquery failed\n");
75#endif
76 h_errno = NO_RECOVERY;
77 return (n);
78 }
79 n = res_send(buf, n, answer, anslen);
80 if (n < 0) {
81#ifdef DEBUG
82 if (_res.options & RES_DEBUG)
83 printf("res_query: send error\n");
84#endif
85 h_errno = TRY_AGAIN;
86 return(n);
87 }
88
89 hp = (HEADER *) answer;
90 if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
91#ifdef DEBUG
92 if (_res.options & RES_DEBUG)
93 printf("rcode = %d, ancount=%d\n", hp->rcode,
94 ntohs(hp->ancount));
95#endif
96 switch (hp->rcode) {
97 case NXDOMAIN:
a5e08740 98 h_errno = HOST_NOT_FOUND;
345feb69
KB
99 break;
100 case SERVFAIL:
101 h_errno = TRY_AGAIN;
102 break;
103 case NOERROR:
d7ec9b41 104 h_errno = NO_DATA;
345feb69
KB
105 break;
106 case FORMERR:
107 case NOTIMP:
108 case REFUSED:
a5e08740 109 default:
345feb69 110 h_errno = NO_RECOVERY;
a5e08740 111 break;
345feb69
KB
112 }
113 return (-1);
114 }
115 return(n);
116}
117
118/*
119 * Formulate a normal query, send, and retrieve answer in supplied buffer.
120 * Return the size of the response on success, -1 on error.
121 * If enabled, implement search rules until answer or unrecoverable failure
122 * is detected. Error number is left in h_errno.
123 * Only useful for queries in the same name hierarchy as the local host
124 * (not, for example, for host address-to-name lookups in domain in-addr.arpa).
125 */
126res_search(name, class, type, answer, anslen)
127 char *name; /* domain name */
128 int class, type; /* class and type of query */
129 u_char *answer; /* buffer to put answer */
130 int anslen; /* size of answer */
131{
132 register char *cp, **domain;
d7ec9b41 133 int n, ret, got_nodata = 0;
345feb69
KB
134 char *hostalias();
135
136 if ((_res.options & RES_INIT) == 0 && res_init() == -1)
137 return (-1);
138
139 errno = 0;
d7ec9b41 140 h_errno = HOST_NOT_FOUND; /* default, if we never query */
345feb69
KB
141 for (cp = name, n = 0; *cp; cp++)
142 if (*cp == '.')
143 n++;
144 if (n == 0 && (cp = hostalias(name)))
145 return (res_query(cp, class, type, answer, anslen));
146
3ec8dabc
MK
147 /*
148 * We do at least one level of search if
149 * - there is no dot and RES_DEFNAME is set, or
150 * - there is at least one dot, there is no trailing dot,
151 * and RES_DNSRCH is set.
152 */
153 if ((n == 0 && _res.options & RES_DEFNAMES) ||
154 (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH))
155 for (domain = _res.dnsrch; *domain; domain++) {
345feb69
KB
156 ret = res_querydomain(name, *domain, class, type,
157 answer, anslen);
158 if (ret > 0)
159 return (ret);
160 /*
161 * If no server present, give up.
162 * If name isn't found in this domain,
163 * keep trying higher domains in the search list
164 * (if that's enabled).
d7ec9b41 165 * On a NO_DATA error, keep trying, otherwise
345feb69
KB
166 * a wildcard entry of another type could keep us
167 * from finding this entry higher in the domain.
3ec8dabc
MK
168 * If we get some other error (negative answer or
169 * server failure), then stop searching up,
345feb69
KB
170 * but try the input name below in case it's fully-qualified.
171 */
172 if (errno == ECONNREFUSED) {
173 h_errno = TRY_AGAIN;
174 return (-1);
175 }
d7ec9b41
MK
176 if (h_errno == NO_DATA)
177 got_nodata++;
178 if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) ||
345feb69
KB
179 (_res.options & RES_DNSRCH) == 0)
180 break;
345feb69
KB
181 }
182 /*
183 * If the search/default failed, try the name as fully-qualified,
184 * but only if it contained at least one dot (even trailing).
3ec8dabc
MK
185 * This is purely a heuristic; we assume that any reasonable query
186 * about a top-level domain (for servers, SOA, etc) will not use
187 * res_search.
345feb69 188 */
3ec8dabc
MK
189 if (n && (ret = res_querydomain(name, (char *)NULL, class, type,
190 answer, anslen)) > 0)
191 return (ret);
d7ec9b41
MK
192 if (got_nodata)
193 h_errno = NO_DATA;
345feb69
KB
194 return (-1);
195}
196
197/*
198 * Perform a call on res_query on the concatenation of name and domain,
199 * removing a trailing dot from name if domain is NULL.
200 */
201res_querydomain(name, domain, class, type, answer, anslen)
202 char *name, *domain;
203 int class, type; /* class and type of query */
204 u_char *answer; /* buffer to put answer */
205 int anslen; /* size of answer */
206{
207 char nbuf[2*MAXDNAME+2];
208 char *longname = nbuf;
209 int n;
210
d7ec9b41
MK
211#ifdef DEBUG
212 if (_res.options & RES_DEBUG)
213 printf("res_querydomain(%s, %s, %d, %d)\n",
214 name, domain, class, type);
215#endif
345feb69
KB
216 if (domain == NULL) {
217 /*
218 * Check for trailing '.';
219 * copy without '.' if present.
220 */
221 n = strlen(name) - 1;
222 if (name[n] == '.' && n < sizeof(nbuf) - 1) {
223 bcopy(name, nbuf, n);
224 nbuf[n] = '\0';
225 } else
226 longname = name;
227 } else
228 (void)sprintf(nbuf, "%.*s.%.*s",
229 MAXDNAME, name, MAXDNAME, domain);
230
231 return (res_query(longname, class, type, answer, anslen));
232}
233
234char *
235hostalias(name)
236 register char *name;
237{
238 register char *C1, *C2;
239 FILE *fp;
240 char *file, *getenv(), *strcpy(), *strncpy();
241 char buf[BUFSIZ];
242 static char abuf[MAXDNAME];
243
244 file = getenv("HOSTALIASES");
245 if (file == NULL || (fp = fopen(file, "r")) == NULL)
246 return (NULL);
247 buf[sizeof(buf) - 1] = '\0';
248 while (fgets(buf, sizeof(buf), fp)) {
249 for (C1 = buf; *C1 && !isspace(*C1); ++C1);
250 if (!*C1)
251 break;
252 *C1 = '\0';
253 if (!strcasecmp(buf, name)) {
254 while (isspace(*++C1));
255 if (!*C1)
256 break;
257 for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
258 abuf[sizeof(abuf) - 1] = *C2 = '\0';
259 (void)strncpy(abuf, C1, sizeof(abuf) - 1);
260 fclose(fp);
261 return (abuf);
262 }
263 }
264 fclose(fp);
265 return (NULL);
266}