dnsres.c 8.8 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. #include "stx.h"
  62. #define MAXPACKET 1024
  63. #if !defined(NETDB_INTERNAL) && defined(h_NETDB_INTERNAL)
  64. #define NETDB_INTERNAL h_NETDB_INTERNAL
  65. #endif
  66. /* New in Solaris 7 */
  67. #if !defined(_getshort) && defined(ns_get16)
  68. #define _getshort(cp) ns_get16(cp)
  69. #define _getlong(cp) ns_get32(cp)
  70. #endif
  71. typedef union {
  72. HEADER hdr;
  73. u_char buf[MAXPACKET];
  74. } querybuf_t;
  75. int _stx_dns_ttl;
  76. static int parse_answer(querybuf_t *ans, int len, struct in_addr *addrs,
  77. int *num_addrs)
  78. {
  79. char buf[MAXPACKET];
  80. HEADER *ahp;
  81. u_char *cp, *eoa;
  82. int type, n, i;
  83. ahp = &ans->hdr;
  84. eoa = ans->buf + len;
  85. cp = ans->buf + sizeof(HEADER);
  86. h_errno = TRY_AGAIN;
  87. _stx_dns_ttl = -1;
  88. i = 0;
  89. while (ahp->qdcount > 0) {
  90. ahp->qdcount--;
  91. cp += dn_skipname(cp, eoa) + QFIXEDSZ;
  92. }
  93. while (ahp->ancount > 0 && cp < eoa && i < *num_addrs) {
  94. ahp->ancount--;
  95. if ((n = dn_expand(ans->buf, eoa, cp, buf, sizeof(buf))) < 0)
  96. return -1;
  97. cp += n;
  98. if (cp + 4 + 4 + 2 >= eoa)
  99. return -1;
  100. type = _getshort(cp);
  101. cp += 4;
  102. if (type == T_A)
  103. _stx_dns_ttl = _getlong(cp);
  104. cp += 4;
  105. n = _getshort(cp);
  106. cp += 2;
  107. if (type == T_A) {
  108. if (n > sizeof(*addrs) || cp + n > eoa)
  109. return -1;
  110. memcpy(&addrs[i++], cp, n);
  111. }
  112. cp += n;
  113. }
  114. *num_addrs = i;
  115. return 0;
  116. }
  117. static int query_domain(st_netfd_t nfd, const char *name,
  118. struct in_addr *addrs, int *num_addrs,
  119. st_utime_t timeout)
  120. {
  121. querybuf_t qbuf;
  122. u_char *buf = qbuf.buf;
  123. HEADER *hp = &qbuf.hdr;
  124. int blen = sizeof(qbuf);
  125. int i, len, id;
  126. for (i = 0; i < _res.nscount; i++) {
  127. len = res_mkquery(QUERY, name, C_IN, T_A, NULL, 0, NULL, buf, blen);
  128. if (len <= 0) {
  129. h_errno = NO_RECOVERY;
  130. return -1;
  131. }
  132. id = hp->id;
  133. if (st_sendto(nfd, buf, len, (struct sockaddr *)&(_res.nsaddr_list[i]),
  134. sizeof(struct sockaddr), timeout) != len) {
  135. h_errno = NETDB_INTERNAL;
  136. /* EINTR means interrupt by other thread, NOT by a caught signal */
  137. if (errno == EINTR)
  138. return -1;
  139. continue;
  140. }
  141. /* Wait for reply */
  142. do {
  143. len = st_recvfrom(nfd, buf, blen, NULL, NULL, timeout);
  144. if (len <= 0)
  145. break;
  146. } while (id != hp->id);
  147. if (len < HFIXEDSZ) {
  148. h_errno = NETDB_INTERNAL;
  149. if (len >= 0)
  150. errno = EMSGSIZE;
  151. else if (errno == EINTR) /* see the comment above */
  152. return -1;
  153. continue;
  154. }
  155. hp->ancount = ntohs(hp->ancount);
  156. hp->qdcount = ntohs(hp->qdcount);
  157. if ((hp->rcode != NOERROR) || (hp->ancount == 0)) {
  158. switch (hp->rcode) {
  159. case NXDOMAIN:
  160. h_errno = HOST_NOT_FOUND;
  161. break;
  162. case SERVFAIL:
  163. h_errno = TRY_AGAIN;
  164. break;
  165. case NOERROR:
  166. h_errno = NO_DATA;
  167. break;
  168. case FORMERR:
  169. case NOTIMP:
  170. case REFUSED:
  171. default:
  172. h_errno = NO_RECOVERY;
  173. }
  174. continue;
  175. }
  176. if (parse_answer(&qbuf, len, addrs, num_addrs) == 0)
  177. return 0;
  178. }
  179. return -1;
  180. }
  181. #define CLOSE_AND_RETURN(ret) \
  182. { \
  183. n = errno; \
  184. st_netfd_close(nfd); \
  185. errno = n; \
  186. return (ret); \
  187. }
  188. int _stx_dns_getaddrlist(const char *host, struct in_addr *addrs,
  189. int *num_addrs, 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, addrs, num_addrs, 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, addrs, num_addrs, 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, addrs, num_addrs, timeout) == 0)
  269. CLOSE_AND_RETURN(0);
  270. }
  271. CLOSE_AND_RETURN(-1);
  272. }