getrrsetbyname-ldns.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /* $OpenBSD: getrrsetbyname.c,v 1.10 2005/03/30 02:58:28 tedu Exp $ */
  2. /*
  3. * Copyright (c) 2007 Simon Vallet / Genoscope <svallet@genoscope.cns.fr>
  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. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. *
  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. *
  16. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  17. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  18. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  19. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  20. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  21. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  22. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  23. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  25. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. /*
  28. * Portions Copyright (c) 1999-2001 Internet Software Consortium.
  29. *
  30. * Permission to use, copy, modify, and distribute this software for any
  31. * purpose with or without fee is hereby granted, provided that the above
  32. * copyright notice and this permission notice appear in all copies.
  33. *
  34. * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
  35. * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  36. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
  37. * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
  38. * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
  39. * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  40. * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  41. * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  42. */
  43. #include "includes.h"
  44. #if !defined (HAVE_GETRRSETBYNAME) && defined (HAVE_LDNS)
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <ldns/ldns.h>
  48. #include "getrrsetbyname.h"
  49. #include "log.h"
  50. #include "xmalloc.h"
  51. #define malloc(x) (xmalloc(x))
  52. #define calloc(x, y) (xcalloc((x),(y)))
  53. int
  54. getrrsetbyname(const char *hostname, unsigned int rdclass,
  55. unsigned int rdtype, unsigned int flags,
  56. struct rrsetinfo **res)
  57. {
  58. int result;
  59. unsigned int i, j, index_ans, index_sig;
  60. struct rrsetinfo *rrset = NULL;
  61. struct rdatainfo *rdata;
  62. size_t len;
  63. ldns_resolver *ldns_res = NULL;
  64. ldns_rdf *domain = NULL;
  65. ldns_pkt *pkt = NULL;
  66. ldns_rr_list *rrsigs = NULL, *rrdata = NULL;
  67. ldns_status err;
  68. ldns_rr *rr;
  69. /* check for invalid class and type */
  70. if (rdclass > 0xffff || rdtype > 0xffff) {
  71. result = ERRSET_INVAL;
  72. goto fail;
  73. }
  74. /* don't allow queries of class or type ANY */
  75. if (rdclass == 0xff || rdtype == 0xff) {
  76. result = ERRSET_INVAL;
  77. goto fail;
  78. }
  79. /* don't allow flags yet, unimplemented */
  80. if (flags) {
  81. result = ERRSET_INVAL;
  82. goto fail;
  83. }
  84. /* Initialize resolver from resolv.conf */
  85. domain = ldns_dname_new_frm_str(hostname);
  86. if ((err = ldns_resolver_new_frm_file(&ldns_res, NULL)) != \
  87. LDNS_STATUS_OK) {
  88. result = ERRSET_FAIL;
  89. goto fail;
  90. }
  91. #ifdef LDNS_DEBUG
  92. ldns_resolver_set_debug(ldns_res, true);
  93. #endif /* LDNS_DEBUG */
  94. ldns_resolver_set_dnssec(ldns_res, true); /* Use DNSSEC */
  95. /* make query */
  96. pkt = ldns_resolver_query(ldns_res, domain, rdtype, rdclass, LDNS_RD);
  97. /*** TODO: finer errcodes -- see original **/
  98. if (!pkt || ldns_pkt_ancount(pkt) < 1) {
  99. result = ERRSET_FAIL;
  100. goto fail;
  101. }
  102. /* initialize rrset */
  103. rrset = calloc(1, sizeof(struct rrsetinfo));
  104. if (rrset == NULL) {
  105. result = ERRSET_NOMEMORY;
  106. goto fail;
  107. }
  108. rrdata = ldns_pkt_rr_list_by_type(pkt, rdtype, LDNS_SECTION_ANSWER);
  109. rrset->rri_nrdatas = ldns_rr_list_rr_count(rrdata);
  110. if (!rrset->rri_nrdatas) {
  111. result = ERRSET_NODATA;
  112. goto fail;
  113. }
  114. /* copy name from answer section */
  115. len = ldns_rdf_size(ldns_rr_owner(ldns_rr_list_rr(rrdata, 0)));
  116. if ((rrset->rri_name = malloc(len)) == NULL) {
  117. result = ERRSET_NOMEMORY;
  118. goto fail;
  119. }
  120. memcpy(rrset->rri_name,
  121. ldns_rdf_data(ldns_rr_owner(ldns_rr_list_rr(rrdata, 0))), len);
  122. rrset->rri_rdclass = ldns_rr_get_class(ldns_rr_list_rr(rrdata, 0));
  123. rrset->rri_rdtype = ldns_rr_get_type(ldns_rr_list_rr(rrdata, 0));
  124. rrset->rri_ttl = ldns_rr_ttl(ldns_rr_list_rr(rrdata, 0));
  125. debug2("ldns: got %u answers from DNS", rrset->rri_nrdatas);
  126. /* Check for authenticated data */
  127. if (ldns_pkt_ad(pkt)) {
  128. rrset->rri_flags |= RRSET_VALIDATED;
  129. } else { /* AD is not set, try autonomous validation */
  130. ldns_rr_list * trusted_keys = ldns_rr_list_new();
  131. debug2("ldns: trying to validate RRset");
  132. /* Get eventual sigs */
  133. rrsigs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_RRSIG,
  134. LDNS_SECTION_ANSWER);
  135. rrset->rri_nsigs = ldns_rr_list_rr_count(rrsigs);
  136. debug2("ldns: got %u signature(s) (RRTYPE %u) from DNS",
  137. rrset->rri_nsigs, LDNS_RR_TYPE_RRSIG);
  138. if ((err = ldns_verify_trusted(ldns_res, rrdata, rrsigs,
  139. trusted_keys)) == LDNS_STATUS_OK) {
  140. rrset->rri_flags |= RRSET_VALIDATED;
  141. debug2("ldns: RRset is signed with a valid key");
  142. } else {
  143. debug2("ldns: RRset validation failed: %s",
  144. ldns_get_errorstr_by_id(err));
  145. }
  146. ldns_rr_list_deep_free(trusted_keys);
  147. }
  148. /* allocate memory for answers */
  149. rrset->rri_rdatas = calloc(rrset->rri_nrdatas,
  150. sizeof(struct rdatainfo));
  151. if (rrset->rri_rdatas == NULL) {
  152. result = ERRSET_NOMEMORY;
  153. goto fail;
  154. }
  155. /* allocate memory for signatures */
  156. if (rrset->rri_nsigs > 0) {
  157. rrset->rri_sigs = calloc(rrset->rri_nsigs,
  158. sizeof(struct rdatainfo));
  159. if (rrset->rri_sigs == NULL) {
  160. result = ERRSET_NOMEMORY;
  161. goto fail;
  162. }
  163. }
  164. /* copy answers & signatures */
  165. for (i=0, index_ans=0, index_sig=0; i< pkt->_header->_ancount; i++) {
  166. rdata = NULL;
  167. rr = ldns_rr_list_rr(ldns_pkt_answer(pkt), i);
  168. if (ldns_rr_get_class(rr) == rrset->rri_rdclass &&
  169. ldns_rr_get_type(rr) == rrset->rri_rdtype) {
  170. rdata = &rrset->rri_rdatas[index_ans++];
  171. }
  172. if (rr->_rr_class == rrset->rri_rdclass &&
  173. rr->_rr_type == LDNS_RR_TYPE_RRSIG &&
  174. rrset->rri_sigs) {
  175. rdata = &rrset->rri_sigs[index_sig++];
  176. }
  177. if (rdata) {
  178. size_t rdata_offset = 0;
  179. rdata->rdi_length = 0;
  180. for (j=0; j< rr->_rd_count; j++) {
  181. rdata->rdi_length +=
  182. ldns_rdf_size(ldns_rr_rdf(rr, j));
  183. }
  184. rdata->rdi_data = malloc(rdata->rdi_length);
  185. if (rdata->rdi_data == NULL) {
  186. result = ERRSET_NOMEMORY;
  187. goto fail;
  188. }
  189. /* Re-create the raw DNS RDATA */
  190. for (j=0; j< rr->_rd_count; j++) {
  191. len = ldns_rdf_size(ldns_rr_rdf(rr, j));
  192. memcpy(rdata->rdi_data + rdata_offset,
  193. ldns_rdf_data(ldns_rr_rdf(rr, j)), len);
  194. rdata_offset += len;
  195. }
  196. }
  197. }
  198. *res = rrset;
  199. result = ERRSET_SUCCESS;
  200. fail:
  201. /* freerrset(rrset); */
  202. ldns_rdf_deep_free(domain);
  203. ldns_pkt_free(pkt);
  204. ldns_rr_list_deep_free(rrsigs);
  205. ldns_rr_list_deep_free(rrdata);
  206. ldns_resolver_deep_free(ldns_res);
  207. return result;
  208. }
  209. void
  210. freerrset(struct rrsetinfo *rrset)
  211. {
  212. u_int16_t i;
  213. if (rrset == NULL)
  214. return;
  215. if (rrset->rri_rdatas) {
  216. for (i = 0; i < rrset->rri_nrdatas; i++) {
  217. if (rrset->rri_rdatas[i].rdi_data == NULL)
  218. break;
  219. free(rrset->rri_rdatas[i].rdi_data);
  220. }
  221. free(rrset->rri_rdatas);
  222. }
  223. if (rrset->rri_sigs) {
  224. for (i = 0; i < rrset->rri_nsigs; i++) {
  225. if (rrset->rri_sigs[i].rdi_data == NULL)
  226. break;
  227. free(rrset->rri_sigs[i].rdi_data);
  228. }
  229. free(rrset->rri_sigs);
  230. }
  231. if (rrset->rri_name)
  232. free(rrset->rri_name);
  233. free(rrset);
  234. }
  235. #endif /* !defined (HAVE_GETRRSETBYNAME) && defined (HAVE_LDNS) */