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 rrset->rri_sigs) { 210 rdata = &rrset->rri_sigs[index_sig++]; 211 } 212 213 if (rdata) { 214 size_t rdata_offset = 0; 215 216 rdata->rdi_length = 0; 217 for (j=0; j< rr->_rd_count; j++) { 218 rdata->rdi_length += 219 ldns_rdf_size(ldns_rr_rdf(rr, j)); 220 } 221 222 rdata->rdi_data = malloc(rdata->rdi_length); 223 if (rdata->rdi_data == NULL) { 224 result = ERRSET_NOMEMORY; 225 goto fail; 226 } 227 228 /* Re-create the raw DNS RDATA */ 229 for (j=0; j< rr->_rd_count; j++) { 230 len = ldns_rdf_size(ldns_rr_rdf(rr, j)); 231 memcpy(rdata->rdi_data + rdata_offset, 232 ldns_rdf_data(ldns_rr_rdf(rr, j)), len); 233 rdata_offset += len; 234 } 235 } 236 } 237 238 *res = rrset; 239 result = ERRSET_SUCCESS; 240 241fail: 242 /* freerrset(rrset); */ 243 ldns_rdf_deep_free(domain); 244 ldns_pkt_free(pkt); 245 ldns_rr_list_deep_free(rrsigs); 246 ldns_rr_list_deep_free(rrdata); 247 ldns_resolver_deep_free(ldns_res); 248 249 return result; 250} 251 252 253void 254freerrset(struct rrsetinfo *rrset) 255{ 256 u_int16_t i; 257 258 if (rrset == NULL) 259 return; 260 261 if (rrset->rri_rdatas) { 262 for (i = 0; i < rrset->rri_nrdatas; i++) { 263 if (rrset->rri_rdatas[i].rdi_data == NULL) 264 break; 265 free(rrset->rri_rdatas[i].rdi_data); 266 } 267 free(rrset->rri_rdatas); 268 } 269 270 if (rrset->rri_sigs) { 271 for (i = 0; i < rrset->rri_nsigs; i++) { 272 if (rrset->rri_sigs[i].rdi_data == NULL) 273 break; 274 free(rrset->rri_sigs[i].rdi_data); 275 } 276 free(rrset->rri_sigs); 277 } 278 279 if (rrset->rri_name) 280 free(rrset->rri_name); 281 free(rrset); 282} 283 284 285#endif /* !defined (HAVE_GETRRSETBYNAME) && defined (HAVE_LDNS) */ 286