Watt-32 tcp/ip  2.2 dev-rel.10
res_quer.c
Go to the documentation of this file.
1 
5 /*
6  * ++Copyright++ 1988, 1993
7  * -
8  * Copyright (c) 1988, 1993
9  * The Regents of the University of California. All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in the
18  * documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  * must display the following acknowledgement:
21  * This product includes software developed by the University of
22  * California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  * may be used to endorse or promote products derived from this software
25  * without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  * -
39  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
40  *
41  * Permission to use, copy, modify, and distribute this software for any
42  * purpose with or without fee is hereby granted, provided that the above
43  * copyright notice and this permission notice appear in all copies, and that
44  * the name of Digital Equipment Corporation not be used in advertising or
45  * publicity pertaining to distribution of the document or software without
46  * specific, written prior permission.
47  *
48  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
49  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
50  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
51  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
52  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
53  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
54  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
55  * SOFTWARE.
56  * -
57  * --Copyright--
58  */
59 
60 #include "resolver.h"
61 
62 #if defined(USE_BIND)
63 
64 #if (PACKETSZ > 1024)
65  #define MAX_PACKET PACKETSZ
66 #else
67  #define MAX_PACKET 1024
68 #endif
69 
70 /*
71  * Formulate a normal query, send, and await answer.
72  * Returned answer is placed in supplied buffer "answer".
73  * Perform preliminary check of answer, returning success only
74  * if no error is indicated and the answer count is nonzero.
75  * Return the size of the response on success, -1 on error.
76  * Error number is left in h_errno.
77  *
78  * Caller must parse answer and determine whether it answers the question.
79  */
80 int W32_CALL res_query (const char *name, int Class, int type,
81  u_char *answer, int anslen)
82 {
83  u_char buf[MAX_PACKET];
84  HEADER *hp = (HEADER*) answer;
85  int n;
86 
87  hp->rcode = NOERROR; /* default */
88 
89  if ((_res.options & RES_INIT) == 0 && res_init() == -1)
90  {
91  h_errno = NETDB_INTERNAL;
92  return (-1);
93  }
94 
95  if (_res.options & RES_DEBUG)
96  (*_printf) (";; res_query(%s, %d, %d)\n", name, Class, type);
97 
98  n = res_mkquery (QUERY, name, Class, type, NULL, 0, NULL,
99  buf, sizeof(buf));
100  if (n <= 0)
101  {
102  if (_res.options & RES_DEBUG)
103  (*_printf) (";; res_query: mkquery failed\n");
104 
105  h_errno = NO_RECOVERY;
106  return (n);
107  }
108  n = res_send (buf, n, answer, anslen);
109  if (n < 0)
110  {
111  if (_res.options & RES_DEBUG)
112  (*_printf) (";; res_query: send error\n");
113 
114  h_errno = TRY_AGAIN;
115  return (n);
116  }
117 
118  if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0)
119  {
120  if (_res.options & RES_DEBUG)
121  (*_printf) (";; rcode = %d, ancount=%d\n",
122  hp->rcode, ntohs(hp->ancount));
123 
124  switch (hp->rcode)
125  {
126  case NXDOMAIN:
127  h_errno = HOST_NOT_FOUND;
128  break;
129  case SERVFAIL:
130  h_errno = TRY_AGAIN;
131  break;
132  case NOERROR:
133  h_errno = NO_DATA;
134  break;
135  case FORMERR:
136  case NOTIMP:
137  case REFUSED:
138  default:
139  h_errno = NO_RECOVERY;
140  break;
141  }
142  return (-1);
143  }
144  return (n);
145 }
146 
147 /*
148  * Formulate a normal query, send, and retrieve answer in supplied buffer.
149  * Return the size of the response on success, -1 on error.
150  * If enabled, implement search rules until answer or unrecoverable failure
151  * is detected. Error code, if any, is left in h_errno.
152  */
153 int W32_CALL res_search (const char *name, int Class, int type,
154  u_char *answer, int anslen)
155 {
156  #define RDBG(x) (*_printf) ("res_search() = %d at line %u\n", x, __LINE__)
157 
158  const char *cp;
159  const char *const *domain;
160  HEADER *hp = (HEADER *) answer;
161  u_int dots;
162  int trailing_dot, ret = -1;
163  int saved_herrno;
164  int got_nodata = 0;
165  int got_servfail = 0;
166  int tried_as_is = 0;
167  int done = 0;
168 
169  if ((_res.options & RES_INIT) == 0 && res_init() == -1)
170  {
171  h_errno = NETDB_INTERNAL;
172  RDBG (-1);
173  return (-1);
174  }
175 
176  SOCK_ERRNO (0);
177  h_errno = 0; /* default, if we never query */
178  dots = 0;
179 
180  for (cp = name; *cp; cp++)
181  dots += (*cp == '.');
182 
183  trailing_dot = 0;
184  if (cp > name && *--cp == '.')
185  trailing_dot++;
186 
187  /* if there aren't any dots, it could be a user-level alias
188  */
189  if (!dots && (cp = __hostalias(name)) != NULL)
190  {
191  int rc = res_query (cp, Class, type, answer, anslen);
192  RDBG (rc);
193  return (rc);
194  }
195 
196  /* If there are dots in the name already, let's just give it a try
197  * 'as is'. The threshold can be set with the "ndots" option.
198  */
199  saved_herrno = -1;
200  if (dots >= _res.ndots)
201  {
202  ret = res_querydomain (name, NULL, Class, type, answer, anslen);
203  if (ret > 0)
204  {
205  RDBG (ret);
206  return (ret);
207  }
208  saved_herrno = h_errno;
209  tried_as_is++;
210  }
211 
212  /*
213  * We do at least one level of search if
214  * - there is no dot and RES_DEFNAME is set, or
215  * - there is at least one dot, there is no trailing dot,
216  * and RES_DNSRCH is set.
217  */
218  if ((!dots && (_res.options & RES_DEFNAMES)) ||
219  (dots && !trailing_dot && (_res.options & RES_DNSRCH)))
220  {
221  for (domain = (const char * const*)_res.dnsrch; *domain && !done; domain++)
222  {
223  ret = res_querydomain (name, *domain, Class, type, answer, anslen);
224  if (ret > 0)
225  {
226  RDBG (ret);
227  return (ret);
228  }
229 
230  /*
231  * If no server present, give up.
232  * If name isn't found in this domain,
233  * keep trying higher domains in the search list
234  * (if that's enabled).
235  * On a NO_DATA error, keep trying, otherwise
236  * a wildcard entry of another type could keep us
237  * from finding this entry higher in the domain.
238  * If we get some other error (negative answer or
239  * server failure), then stop searching up,
240  * but try the input name below in case it's
241  * fully-qualified.
242  */
243  if (errno == ECONNREFUSED)
244  {
245  h_errno = TRY_AGAIN;
246  RDBG (-1);
247  return (-1);
248  }
249 
250  switch (h_errno)
251  {
252  case NO_DATA:
253  got_nodata++;
254  /* fallthrough */
255  case HOST_NOT_FOUND:
256  /* keep trying */
257  break;
258  case TRY_AGAIN:
259  if (hp->rcode == SERVFAIL)
260  {
261  /* try next search element, if any */
262  got_servfail++;
263  break;
264  }
265  /* fallthrough */
266  default:
267  /* anything else implies that we're done */
268  done++;
269  }
270 
271  /* if we got here for some reason other than DNSRCH,
272  * we only wanted one iteration of the loop, so stop.
273  */
274  if (!(_res.options & RES_DNSRCH))
275  done++;
276  }
277  }
278 
279  /* if we have not already tried the name "as is", do that now.
280  * note that we do this regardless of how many dots were in the
281  * name or whether it ends with a dot.
282  */
283  if (!tried_as_is)
284  {
285  ret = res_querydomain (name, NULL, Class, type, answer, anslen);
286  if (ret > 0)
287  {
288  RDBG (ret);
289  return (ret);
290  }
291  }
292 
293  /* if we got here, we didn't satisfy the search.
294  * if we did an initial full query, return that query's h_errno
295  * (note that we wouldn't be here if that query had succeeded).
296  * else if we ever got a nodata, send that back as the reason.
297  * else send back meaningless h_errno, that being the one from
298  * the last DNSRCH we did.
299  */
300  if (saved_herrno != -1)
301  h_errno = saved_herrno;
302 
303  else if (got_nodata)
304  h_errno = NO_DATA;
305 
306  else if (got_servfail)
307  h_errno = TRY_AGAIN;
308 
309  if (done || h_errno == 0)
310  return (1);
311 
312  TCP_CONSOLE_MSG (1, ("res_search() / h_errno = %d\n", h_errno));
313  RDBG (-1);
314  return (-1);
315 }
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  */
322 int W32_CALL res_querydomain (const char *name, const char *domain, int Class,
323  int type, u_char *answer, int anslen)
324 {
325  char nbuf [2*MAXDNAME+2];
326  const char *longname = nbuf;
327 
328  if ((_res.options & RES_INIT) == 0 && res_init() == -1)
329  {
330  h_errno = NETDB_INTERNAL;
331  return (-1);
332  }
333 
334  if (_res.options & RES_DEBUG)
335  (*_printf) (";; res_querydomain(%s, %s, %d, %d)\n",
336  name, domain ? domain : "<Nil>", Class, type);
337 
338  if (!domain)
339  {
340  /* Check for trailing '.'; copy without '.' if present.
341  */
342  size_t len = strlen (name) - 1;
343 
344  if (len < sizeof(nbuf)-1 && name[len] == '.')
345  {
346  memcpy (nbuf, name, len);
347  nbuf [len] = '\0';
348  }
349  else
350  longname = name;
351  }
352  else
353  {
354  /* won't overflow
355  */
356  sprintf (nbuf, "%.*s.%.*s", MAXDNAME, name, MAXDNAME, domain);
357  }
358 
359  return res_query (longname, Class, type, answer, anslen);
360 }
361 
362 /*
363  * Open and parse hostalias file. Lines may have comments ('#' or ';').
364  * Line format is:
365  * [ ].host[ ]*alias{#}.[\r\n]
366  */
367 char * W32_CALL __hostalias (const char *name)
368 {
369  const char *file;
370  char buf[BUFSIZ], *tok_buf = NULL;
371  static char abuf[MAXDNAME];
372  FILE *fp;
373 
374  if (_res.options & RES_NOALIASES)
375  return (NULL);
376 
377  file = getenv ("HOSTALIASES");
378  if (!file)
379  file = res_cfg_aliases;
380 
381  if (!file || (fp = fopen(file, "r")) == NULL)
382  return (NULL);
383 
384  abuf[0] = '\0';
385 
386  while (fgets(buf, sizeof(buf), fp))
387  {
388  char *p, *host, *alias;
389 
390  p = strltrim (buf);
391  if (!*p || *p == '\n' || *p == '#' || *p == ';')
392  continue;
393 
394  host = strtok_r (p, " \t", &tok_buf);
395  alias = strtok_r (NULL, " \t\n", &tok_buf);
396  if (!host || !alias)
397  continue;
398 
399  if (!stricmp(host, name))
400  {
401  _strlcpy (abuf, alias, sizeof(abuf)-1);
402  break;
403  }
404  }
405  fclose (fp);
406  return (abuf[0] ? abuf : NULL);
407 }
408 #endif /* USE_BIND */
409 
char * strltrim(const char *s)
Return pointer to first non-blank (space/tab) in a string.
Definition: strings.c:243
char * _strlcpy(char *dst, const char *src, size_t len)
Similar to strncpy(), but always returns 'dst' with 0-termination.
Definition: strings.c:226
int W32_CALL res_mkquery(int op, const char *dname, int Class, int type, const u_char *data, int datalen, const u_char *newrr_in, u_char *buf, int buflen)
Definition: res_mkqu.c:67