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