res.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /*
  2. * Copyright (c) 1985, 1988, 1993
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. All advertising materials mentioning features or use of this software
  14. * must display the following acknowledgement:
  15. * This product includes software developed by the University of
  16. * California, Berkeley and its contributors.
  17. * 4. Neither the name of the University nor the names of its contributors
  18. * may be used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc.
  34. * All Rights Reserved.
  35. *
  36. * Redistribution and use in source and binary forms, with or without
  37. * modification, are permitted provided that the following conditions
  38. * are met:
  39. *
  40. * 1. Redistributions of source code must retain the above copyright
  41. * notice, this list of conditions and the following disclaimer.
  42. * 2. Redistributions in binary form must reproduce the above copyright
  43. * notice, this list of conditions and the following disclaimer in the
  44. * documentation and/or other materials provided with the distribution.
  45. * 3. Neither the name of Silicon Graphics, Inc. nor the names of its
  46. * contributors may be used to endorse or promote products derived from
  47. * this software without specific prior written permission.
  48. *
  49. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  50. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  51. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  52. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  53. * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  54. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
  55. * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  56. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  57. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  58. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  59. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  60. */
  61. #if defined (DARWIN)
  62. #define BIND_8_COMPAT
  63. #endif
  64. #include <stdio.h>
  65. #include <string.h>
  66. #include <unistd.h>
  67. #include <sys/types.h>
  68. #include <sys/socket.h>
  69. #include <netinet/in.h>
  70. #include <arpa/nameser.h>
  71. #include <resolv.h>
  72. #include <netdb.h>
  73. #include <errno.h>
  74. #include "st.h"
  75. #define MAXPACKET 1024
  76. #if !defined(NETDB_INTERNAL) && defined(h_NETDB_INTERNAL)
  77. #define NETDB_INTERNAL h_NETDB_INTERNAL
  78. #endif
  79. /* New in Solaris 7 */
  80. #if !defined(_getshort) && defined(ns_get16)
  81. #define _getshort(cp) ns_get16(cp)
  82. #endif
  83. typedef union {
  84. HEADER hdr;
  85. u_char buf[MAXPACKET];
  86. } querybuf_t;
  87. static int parse_answer(querybuf_t *ans, int len, struct in_addr *addr)
  88. {
  89. char buf[MAXPACKET];
  90. HEADER *ahp;
  91. u_char *cp, *eoa;
  92. int type, n;
  93. ahp = &ans->hdr;
  94. eoa = ans->buf + len;
  95. cp = ans->buf + sizeof(HEADER);
  96. while (ahp->qdcount > 0) {
  97. ahp->qdcount--;
  98. cp += dn_skipname(cp, eoa) + QFIXEDSZ;
  99. }
  100. while (ahp->ancount > 0 && cp < eoa) {
  101. ahp->ancount--;
  102. if ((n = dn_expand(ans->buf, eoa, cp, buf, sizeof(buf))) < 0)
  103. break;
  104. cp += n;
  105. type = _getshort(cp);
  106. cp += 8;
  107. n = _getshort(cp);
  108. cp += 2;
  109. if (type == T_CNAME) {
  110. cp += n;
  111. continue;
  112. }
  113. memcpy(addr, cp, n);
  114. return 0;
  115. }
  116. h_errno = TRY_AGAIN;
  117. return -1;
  118. }
  119. static int query_domain(st_netfd_t nfd, const char *name, struct in_addr *addr,
  120. st_utime_t timeout)
  121. {
  122. querybuf_t qbuf;
  123. u_char *buf = qbuf.buf;
  124. HEADER *hp = &qbuf.hdr;
  125. int blen = sizeof(qbuf);
  126. int i, len, id;
  127. for (i = 0; i < _res.nscount; i++) {
  128. len = res_mkquery(QUERY, name, C_IN, T_A, NULL, 0, NULL, buf, blen);
  129. if (len <= 0) {
  130. h_errno = NO_RECOVERY;
  131. return -1;
  132. }
  133. id = hp->id;
  134. if (st_sendto(nfd, buf, len, (struct sockaddr *)&(_res.nsaddr_list[i]),
  135. sizeof(struct sockaddr), timeout) != len) {
  136. h_errno = NETDB_INTERNAL;
  137. /* EINTR means interrupt by other thread, NOT by a caught signal */
  138. if (errno == EINTR)
  139. return -1;
  140. continue;
  141. }
  142. /* Wait for reply */
  143. do {
  144. len = st_recvfrom(nfd, buf, blen, NULL, NULL, timeout);
  145. if (len <= 0)
  146. break;
  147. } while (id != hp->id);
  148. if (len < HFIXEDSZ) {
  149. h_errno = NETDB_INTERNAL;
  150. if (len >= 0)
  151. errno = EMSGSIZE;
  152. else if (errno == EINTR) /* see the comment above */
  153. return -1;
  154. continue;
  155. }
  156. hp->ancount = ntohs(hp->ancount);
  157. hp->qdcount = ntohs(hp->qdcount);
  158. if ((hp->rcode != NOERROR) || (hp->ancount == 0)) {
  159. switch (hp->rcode) {
  160. case NXDOMAIN:
  161. h_errno = HOST_NOT_FOUND;
  162. break;
  163. case SERVFAIL:
  164. h_errno = TRY_AGAIN;
  165. break;
  166. case NOERROR:
  167. h_errno = NO_DATA;
  168. break;
  169. case FORMERR:
  170. case NOTIMP:
  171. case REFUSED:
  172. default:
  173. h_errno = NO_RECOVERY;
  174. }
  175. continue;
  176. }
  177. if (parse_answer(&qbuf, len, addr) == 0)
  178. return 0;
  179. }
  180. return -1;
  181. }
  182. #define CLOSE_AND_RETURN(ret) \
  183. { \
  184. n = errno; \
  185. st_netfd_close(nfd); \
  186. errno = n; \
  187. return (ret); \
  188. }
  189. int dns_getaddr(const char *host, struct in_addr *addr, st_utime_t timeout)
  190. {
  191. char name[MAXDNAME], **domain;
  192. const char *cp;
  193. int s, n, maxlen, dots;
  194. int trailing_dot, tried_as_is;
  195. st_netfd_t nfd;
  196. if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
  197. h_errno = NETDB_INTERNAL;
  198. return -1;
  199. }
  200. if (_res.options & RES_USEVC) {
  201. h_errno = NETDB_INTERNAL;
  202. errno = ENOSYS;
  203. return -1;
  204. }
  205. if (!host || *host == '\0') {
  206. h_errno = HOST_NOT_FOUND;
  207. return -1;
  208. }
  209. /* Create UDP socket */
  210. if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
  211. h_errno = NETDB_INTERNAL;
  212. return -1;
  213. }
  214. if ((nfd = st_netfd_open_socket(s)) == NULL) {
  215. h_errno = NETDB_INTERNAL;
  216. n = errno;
  217. close(s);
  218. errno = n;
  219. return -1;
  220. }
  221. maxlen = sizeof(name) - 1;
  222. n = 0;
  223. dots = 0;
  224. trailing_dot = 0;
  225. tried_as_is = 0;
  226. for (cp = host; *cp && n < maxlen; cp++) {
  227. dots += (*cp == '.');
  228. name[n++] = *cp;
  229. }
  230. if (name[n - 1] == '.')
  231. trailing_dot = 1;
  232. /*
  233. * If there are dots in the name already, let's just give it a try
  234. * 'as is'. The threshold can be set with the "ndots" option.
  235. */
  236. if (dots >= _res.ndots) {
  237. if (query_domain(nfd, host, addr, timeout) == 0)
  238. CLOSE_AND_RETURN(0);
  239. if (h_errno == NETDB_INTERNAL && errno == EINTR)
  240. CLOSE_AND_RETURN(-1);
  241. tried_as_is = 1;
  242. }
  243. /*
  244. * We do at least one level of search if
  245. * - there is no dot and RES_DEFNAME is set, or
  246. * - there is at least one dot, there is no trailing dot,
  247. * and RES_DNSRCH is set.
  248. */
  249. if ((!dots && (_res.options & RES_DEFNAMES)) ||
  250. (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
  251. name[n++] = '.';
  252. for (domain = _res.dnsrch; *domain; domain++) {
  253. strncpy(name + n, *domain, maxlen - n);
  254. if (query_domain(nfd, name, addr, timeout) == 0)
  255. CLOSE_AND_RETURN(0);
  256. if (h_errno == NETDB_INTERNAL && errno == EINTR)
  257. CLOSE_AND_RETURN(-1);
  258. if (!(_res.options & RES_DNSRCH))
  259. break;
  260. }
  261. }
  262. /*
  263. * If we have not already tried the name "as is", do that now.
  264. * note that we do this regardless of how many dots were in the
  265. * name or whether it ends with a dot.
  266. */
  267. if (!tried_as_is) {
  268. if (query_domain(nfd, host, addr, timeout) == 0)
  269. CLOSE_AND_RETURN(0);
  270. }
  271. CLOSE_AND_RETURN(-1);
  272. }