res_query.c
上传用户:baixin
上传日期:2008-03-13
资源大小:4795k
文件大小:11k
开发平台:

MultiPlatform

  1. /* res_query.c - DNS Client query module */
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. /*
  4.  * Copyright (c) 1988 Regents of the University of California.
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  * 1. Redistributions of source code must retain the above copyright
  11.  *    notice, this list of conditions and the following disclaimer.
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in the
  14.  *    documentation and/or other materials provided with the distribution.
  15.  * 3. All advertising materials mentioning features or use of this software
  16.  *    must display the following acknowledgement:
  17.  * This product includes software developed by the University of
  18.  * California, Berkeley and its contributors.
  19.  * 4. Neither the name of the University nor the names of its contributors
  20.  *    may be used to endorse or promote products derived from this software
  21.  *    without specific prior written permission.
  22.  *
  23.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  24.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  27.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33.  * SUCH DAMAGE.
  34.  */
  35. /*
  36. modification history
  37. --------------------
  38. 01b,17sep01,vvv  fixed compilation warnings
  39. 01a,13dec96,jag  Eliminated call to initialization and support for the file
  40.                  HOSTALIASES.
  41. */
  42. #include <resolvLib.h>
  43. #include <stdio.h>
  44. #include <ctype.h>
  45. #include <errno.h>
  46. #include <stdlib.h>
  47. #include <string.h>
  48. #if PACKETSZ > 1024
  49. #define MAXPACKET PACKETSZ
  50. #else
  51. #define MAXPACKET 1024
  52. #endif
  53. #ifdef ORG_RESOLVER
  54. char *__hostalias __P((const char *));
  55. #endif /* ORG_RESOLVER */
  56. #ifdef ORG_RESOLVER
  57. int h_errno;
  58. #endif
  59. /* locals */
  60. int res_querydomain (char *name, char *domain, int class, int type,
  61.      u_char *answer, int anslen);
  62. /*
  63.  * Formulate a normal query, send, and await answer.
  64.  * Returned answer is placed in supplied buffer "answer".
  65.  * Perform preliminary check of answer, returning success only
  66.  * if no error is indicated and the answer count is nonzero.
  67.  * Return the size of the response on success, ERROR on error.
  68.  * Error number is left in h_errno.
  69.  * Caller must parse answer and determine whether it answers the question.
  70.  */
  71. int
  72. resolvQuery(name, class, type, answer, anslen)
  73. char *name; /* domain name */
  74. int class, type; /* class and type of query */
  75. u_char *answer; /* buffer to put answer */
  76. int anslen; /* size of answer buffer */
  77. {
  78. char buf[MAXPACKET];
  79. HEADER *hp;
  80. int n;
  81. #ifdef ORG_RESOLVER
  82. /* 
  83.  * Unecessary test under VxWorks; initialization is done from
  84.  * usrNetwork.c
  85.  */
  86. if ((_res.options & RES_INIT) == 0 && res_init() == -1)
  87. return (ERROR);
  88. #endif /* ORG_RESOLVER */
  89. #ifdef DEBUG
  90. if (_res.options & RES_DEBUG)
  91. printf(";; resolvQuery(%s, %d, %d)n", name, class, type);
  92. #endif
  93. n = resolvMkQuery(QUERY, name, class, type, (char *)NULL, 0, NULL,
  94.     buf, sizeof(buf));
  95. if (n == ERROR) {
  96. #ifdef DEBUG
  97. if (_res.options & RES_DEBUG)
  98. printf(";; resolvQuery: mkquery failedn");
  99. #endif
  100. errno = S_resolvLib_NO_RECOVERY;
  101. return (n);
  102. }
  103. n = resolvSend(buf, n, (char *)answer, anslen);
  104. if (n == ERROR) {
  105. #ifdef DEBUG
  106. if (_res.options & RES_DEBUG)
  107. printf(";; resolvQuery: send errorn");
  108. #endif
  109. errno = S_resolvLib_TRY_AGAIN;
  110. return (n);
  111. }
  112. hp = (HEADER *) answer;
  113. if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
  114. #ifdef DEBUG
  115. if (_res.options & RES_DEBUG)
  116. printf(";; rcode = %d, ancount=%dn", hp->rcode,
  117.     ntohs(hp->ancount));
  118. #endif
  119. switch (hp->rcode) {
  120. case NXDOMAIN:
  121. errno = S_resolvLib_HOST_NOT_FOUND;
  122. break;
  123. case SERVFAIL:
  124. errno = S_resolvLib_TRY_AGAIN;
  125. break;
  126. case NOERROR:
  127. errno = S_resolvLib_NO_DATA;
  128. break;
  129. case FORMERR:
  130. case NOTIMP:
  131. case REFUSED:
  132. default:
  133. errno = S_resolvLib_NO_RECOVERY;
  134. break;
  135. }
  136. return (ERROR);
  137. }
  138. return (n);
  139. }
  140. /*
  141.  * Formulate a normal query, send, and retrieve answer in supplied buffer.
  142.  * Return the size of the response on success, -1 on error.
  143.  * If enabled, implement search rules until answer or unrecoverable failure
  144.  * is detected.  Error number is left in h_errno.
  145.  * Only useful for queries in the same name hierarchy as the local host
  146.  * (not, for example, for host address-to-name lookups in domain in-addr.arpa).
  147.  */
  148. int
  149. resSearch(name, class, type, answer, anslen)
  150. const char *name; /* domain name */
  151. int class, type; /* class and type of query */
  152. u_char *answer; /* buffer to put answer */
  153. int anslen; /* size of answer */
  154. {
  155. register char *cp, **domain;
  156. int dots, trailing_dot, ret, got_nodata, saved_herrno, tried_as_is;
  157. #if ORG_RESOLVER
  158. /* Unecessary test under VxWorks */
  159. if ((_res.options & RES_INIT) == 0 && res_init() == -1)
  160. return (-1);
  161. #endif /* ORG_RESOLVER */
  162. got_nodata = 0;
  163. #ifdef ORG_RESOLVER
  164. errno = 0;
  165. #endif /* ORG_RESOLVER */
  166. errno = S_resolvLib_HOST_NOT_FOUND; /* default, if we never query */
  167. dots = 0;
  168. for (cp = (char *)name; *cp; cp++) {
  169. if (*cp == '.')
  170. dots++;
  171. }
  172. trailing_dot = 0;
  173. if ((cp > name) && (*--cp == '.'))
  174. trailing_dot++;
  175. #ifdef ORG_RESOLVER
  176. /* In VxWorks we don't support the HOSTALIASES environment variable
  177.  * or the file pointed by HOSTALIASES.  This concept is described in
  178.  * the BSD man page for hostname. For now we just ignore this option.
  179.  */
  180. /*
  181.  * if there aren't any dots, it could be a user-level alias
  182.  */
  183. if (!dots && (cp = __hostalias(name)))
  184. return (resolvQuery(cp, class, type, answer, anslen));
  185. #endif /* ORG_RESOLVER */
  186. /*
  187.  * If there are dots in the name already, let's just give it a try
  188.  * 'as is'.  The threshold can be set with the "ndots" option.
  189.  */
  190. saved_herrno = -1;
  191. tried_as_is = 0;
  192. if (dots >= _res.ndots) {
  193. ret = res_querydomain((char *)name, NULL, class, type, answer, 
  194.       anslen);
  195. if (ret > 0)
  196. return (ret);
  197. saved_herrno = errno;
  198. tried_as_is++;
  199. }
  200. /*
  201.  * We do at least one level of search if
  202.  * - there is no dot and RES_DEFNAME is set, or
  203.  * - there is at least one dot, there is no trailing dot,
  204.  *   and RES_DNSRCH is set.
  205.  */
  206. if ((!dots && (_res.options & RES_DEFNAMES)) ||
  207.     (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
  208. for (domain = _res.dnsrch; *domain; domain++) {
  209. int done = 0;
  210. ret = res_querydomain((char *)name, *domain, class, type,
  211.     answer, anslen);
  212. if (ret > 0)
  213. return (ret);
  214. /*
  215.  * If no server present, give up.
  216.  * If name isn't found in this domain,
  217.  * keep trying higher domains in the search list
  218.  * (if that's enabled).
  219.  * On a NO_DATA error, keep trying, otherwise
  220.  * a wildcard entry of another type could keep us
  221.  * from finding this entry higher in the domain.
  222.  * If we get some other error (negative answer or
  223.  * server failure), then stop searching up,
  224.  * but try the input name below in case it's
  225.  * fully-qualified.
  226.  */
  227. if (errno == ECONNREFUSED) {
  228. errno = S_resolvLib_TRY_AGAIN;
  229. return (-1);
  230. }
  231. switch (errno) {
  232. case NO_DATA:
  233. got_nodata++;
  234. /* FALLTHROUGH */
  235. case HOST_NOT_FOUND:
  236. /* keep trying */
  237. break;
  238. default:
  239. /* anything else implies that we're done */
  240. done++;
  241. }
  242. /*
  243.  * if we got here for some reason other than DNSRCH,
  244.  * we only wanted one iteration of the loop, so stop.
  245.  */
  246. if (!(_res.options & RES_DNSRCH))
  247.         done++;
  248. if (done)
  249. break;
  250. }
  251. }
  252. /*
  253.  * if we have not already tried the name "as is", do that now.
  254.  * note that we do this regardless of how many dots were in the
  255.  * name or whether it ends with a dot.
  256.  */
  257. if (!tried_as_is) {
  258. ret = res_querydomain((char *)name, NULL, class, type, answer, 
  259.       anslen);
  260. if (ret > 0)
  261. return (ret);
  262. saved_herrno = errno;
  263. }
  264. /*
  265.  * if we got here, we didn't satisfy the search.
  266.  * if we did an initial full query, return that query's h_errno
  267.  * (note that we wouldn't be here if that query had succeeded).
  268.  * else if we ever got a nodata, send that back as the reason.
  269.  * else send back meaningless h_errno, that being the one from
  270.  * the last DNSRCH we did.
  271.  */
  272. if (saved_herrno != -1)
  273. errno = saved_herrno;
  274. else if (got_nodata)
  275. errno = S_resolvLib_NO_DATA;
  276. return (-1);
  277. }
  278. /*
  279.  * Perform a call on resolvQuery on the concatenation of name and domain,
  280.  * removing a trailing dot from name if domain is NULL.
  281.  */
  282. int
  283. res_querydomain(name, domain, class, type, answer, anslen)
  284. char *name, *domain;
  285. int class, type; /* class and type of query */
  286. u_char *answer; /* buffer to put answer */
  287. int anslen; /* size of answer */
  288. {
  289. char nbuf[2*MAXDNAME+2];
  290. char *longname = nbuf;
  291. int n;
  292. #ifdef DEBUG
  293. if (_res.options & RES_DEBUG)
  294. printf(";; res_querydomain(%s, %s, %d, %d)n",
  295.     name, domain, class, type);
  296. #endif
  297. if (domain == NULL) {
  298. /*
  299.  * Check for trailing '.';
  300.  * copy without '.' if present.
  301.  */
  302. n = strlen(name) - 1;
  303. if (n != (0 - 1) && name[n] == '.' && n < sizeof(nbuf) - 1) {
  304. bcopy(name, nbuf, n);
  305. nbuf[n] = '';
  306. } else
  307. longname = name;
  308. } else
  309. (void)sprintf(nbuf, "%.*s.%.*s",
  310.     MAXDNAME, name, MAXDNAME, domain);
  311. return (resolvQuery(longname, class, type, answer, anslen));
  312. }
  313. #ifdef ORG_RESOLVER
  314. /* In VxWorks we don't support the HOSTALIASES environment variable
  315.  * or the file pointed by HOSTALIASES.  This concept is described in
  316.  * the BSD man page for hostname. For now we just ignore this option.  This
  317.  * function is only invoked in this module.
  318.  */
  319. char *
  320. __hostalias(name)
  321. register const char *name;
  322. {
  323. register char *cp1, *cp2;
  324. FILE *fp;
  325. char *file, *getenv(), *strcpy(), *strncpy();
  326. char buf[BUFSIZ];
  327. static char abuf[MAXDNAME];
  328. file = getenv("HOSTALIASES");
  329. if (file == NULL || (fp = fopen(file, "r")) == NULL)
  330. return (NULL);
  331. buf[sizeof(buf) - 1] = '';
  332. while (fgets(buf, sizeof(buf), fp)) {
  333. for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1);
  334. if (!*cp1)
  335. break;
  336. *cp1 = '';
  337. if (!strcasecmp(buf, name)) {
  338. while (isspace(*++cp1));
  339. if (!*cp1)
  340. break;
  341. for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2);
  342. abuf[sizeof(abuf) - 1] = *cp2 = '';
  343. (void)strncpy(abuf, cp1, sizeof(abuf) - 1);
  344. fclose(fp);
  345. return (abuf);
  346. }
  347. }
  348. fclose(fp);
  349. return (NULL);
  350. }
  351. #endif /* ORG_RESOLVER */