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