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 62 int 63 getrrsetbyname(const char *hostname, unsigned int rdclass, 64 unsigned int rdtype, unsigned int flags, 65 struct rrsetinfo **res) 66 { 67 int result; 68 unsigned int i, j, index_ans, index_sig; 69 struct rrsetinfo *rrset = NULL; 70 struct rdatainfo *rdata; 71 size_t len; 72 ldns_resolver *ldns_res; 73 ldns_rdf *domain = NULL; 74 ldns_pkt *pkt = NULL; 75 ldns_rr_list *rrsigs = NULL, *rrdata = NULL; 76 ldns_status err; 77 ldns_rr *rr; 78 79 /* check for invalid class and type */ 80 if (rdclass > 0xffff || rdtype > 0xffff) { 81 result = ERRSET_INVAL; 82 goto fail; 83 } 84 85 /* don't allow queries of class or type ANY */ 86 if (rdclass == 0xff || rdtype == 0xff) { 87 result = ERRSET_INVAL; 88 goto fail; 89 } 90 91 /* don't allow flags yet, unimplemented */ 92 if (flags) { 93 result = ERRSET_INVAL; 94 goto fail; 95 } 96 97 /* Initialize resolver from resolv.conf */ 98 domain = ldns_dname_new_frm_str(hostname); 99 if ((err = ldns_resolver_new_frm_file(&ldns_res, NULL)) != \ 100 LDNS_STATUS_OK) { 101 result = ERRSET_FAIL; 102 goto fail; 103 } 104 105 #ifdef LDNS_DEBUG 106 ldns_resolver_set_debug(ldns_res, true); 107 #endif /* LDNS_DEBUG */ 108 109 ldns_resolver_set_dnssec(ldns_res, true); /* Use DNSSEC */ 110 111 /* make query */ 112 pkt = ldns_resolver_query(ldns_res, domain, rdtype, rdclass, LDNS_RD); 113 114 /*** TODO: finer errcodes -- see original **/ 115 if (!pkt || ldns_pkt_ancount(pkt) < 1) { 116 result = ERRSET_FAIL; 117 goto fail; 118 } 119 120 /* initialize rrset */ 121 rrset = calloc(1, sizeof(struct rrsetinfo)); 122 if (rrset == NULL) { 123 result = ERRSET_NOMEMORY; 124 goto fail; 125 } 126 127 rrdata = ldns_pkt_rr_list_by_type(pkt, rdtype, LDNS_SECTION_ANSWER); 128 rrset->rri_nrdatas = ldns_rr_list_rr_count(rrdata); 129 if (!rrset->rri_nrdatas) { 130 result = ERRSET_NODATA; 131 goto fail; 132 } 133 134 /* copy name from answer section */ 135 len = ldns_rdf_size(ldns_rr_owner(ldns_rr_list_rr(rrdata, 0))); 136 if ((rrset->rri_name = malloc(len)) == NULL) { 137 result = ERRSET_NOMEMORY; 138 goto fail; 139 } 140 memcpy(rrset->rri_name, 141 ldns_rdf_data(ldns_rr_owner(ldns_rr_list_rr(rrdata, 0))), len); 142 143 rrset->rri_rdclass = ldns_rr_get_class(ldns_rr_list_rr(rrdata, 0)); 144 rrset->rri_rdtype = ldns_rr_get_type(ldns_rr_list_rr(rrdata, 0)); 145 rrset->rri_ttl = ldns_rr_ttl(ldns_rr_list_rr(rrdata, 0)); 146 147 debug2("ldns: got %u answers from DNS", rrset->rri_nrdatas); 148 149 /* Check for authenticated data */ 150 if (ldns_pkt_ad(pkt)) { 151 rrset->rri_flags |= RRSET_VALIDATED; 152 } else { /* AD is not set, try autonomous validation */ 153 ldns_rr_list * trusted_keys = ldns_rr_list_new(); 154 155 debug2("ldns: trying to validate RRset"); 156 /* Get eventual sigs */ 157 rrsigs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_RRSIG, 158 LDNS_SECTION_ANSWER); 159 160 rrset->rri_nsigs = ldns_rr_list_rr_count(rrsigs); 161 debug2("ldns: got %u signature(s) (RRTYPE %u) from DNS", 162 rrset->rri_nsigs, LDNS_RR_TYPE_RRSIG); 163 164 if ((err = ldns_verify_trusted(ldns_res, rrdata, rrsigs, 165 trusted_keys)) == LDNS_STATUS_OK) { 166 rrset->rri_flags |= RRSET_VALIDATED; 167 debug2("ldns: RRset is signed with a valid key"); 168 } else { 169 debug2("ldns: RRset validation failed: %s", 170 ldns_get_errorstr_by_id(err)); 171 } 172 173 ldns_rr_list_deep_free(trusted_keys); 174 } 175 176 /* allocate memory for answers */ 177 rrset->rri_rdatas = calloc(rrset->rri_nrdatas, 178 sizeof(struct rdatainfo)); 179 180 if (rrset->rri_rdatas == NULL) { 181 result = ERRSET_NOMEMORY; 182 goto fail; 183 } 184 185 /* allocate memory for signatures */ 186 if (rrset->rri_nsigs > 0) { 187 rrset->rri_sigs = calloc(rrset->rri_nsigs, 188 sizeof(struct rdatainfo)); 189 190 if (rrset->rri_sigs == NULL) { 191 result = ERRSET_NOMEMORY; 192 goto fail; 193 } 194 } 195 196 /* copy answers & signatures */ 197 for (i=0, index_ans=0, index_sig=0; i< pkt->_header->_ancount; i++) { 198 rdata = NULL; 199 rr = ldns_rr_list_rr(ldns_pkt_answer(pkt), i); 200 201 if (ldns_rr_get_class(rr) == rrset->rri_rdclass && 202 ldns_rr_get_type(rr) == rrset->rri_rdtype) { 203 rdata = &rrset->rri_rdatas[index_ans++]; 204 } 205 206 if (rr->_rr_class == rrset->rri_rdclass && 207 rr->_rr_type == LDNS_RR_TYPE_RRSIG && 208 rrset->rri_sigs) { 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 240 fail: 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 252 void 253 freerrset(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