1239844Sdes/* $OpenBSD: getrrsetbyname.c,v 1.10 2005/03/30 02:58:28 tedu Exp $ */ 2239844Sdes 3239844Sdes/* 4239844Sdes * Copyright (c) 2007 Simon Vallet / Genoscope <svallet@genoscope.cns.fr> 5239844Sdes * 6239844Sdes * Redistribution and use in source and binary forms, with or without 7239844Sdes * modification, are permitted provided that the following conditions 8239844Sdes * are met: 9239844Sdes * 10239844Sdes * 1. Redistributions of source code must retain the above copyright 11239844Sdes * notice, this list of conditions and the following disclaimer. 12239844Sdes * 13239844Sdes * 2. Redistributions in binary form must reproduce the above copyright 14239844Sdes * notice, this list of conditions and the following disclaimer in the 15239844Sdes * documentation and/or other materials provided with the distribution. 16239844Sdes * 17239844Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18239844Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19239844Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20239844Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21239844Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22239844Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23239844Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24239844Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25239844Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26239844Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27239844Sdes */ 28239844Sdes 29239844Sdes/* 30239844Sdes * Portions Copyright (c) 1999-2001 Internet Software Consortium. 31239844Sdes * 32239844Sdes * Permission to use, copy, modify, and distribute this software for any 33239844Sdes * purpose with or without fee is hereby granted, provided that the above 34239844Sdes * copyright notice and this permission notice appear in all copies. 35239844Sdes * 36239844Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM 37239844Sdes * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 38239844Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 39239844Sdes * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 40239844Sdes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING 41239844Sdes * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 42239844Sdes * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 43239844Sdes * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 44239844Sdes */ 45239844Sdes 46239844Sdes#include "includes.h" 47239844Sdes 48239844Sdes#if !defined (HAVE_GETRRSETBYNAME) && defined (HAVE_LDNS) 49239844Sdes 50239844Sdes#include <stdlib.h> 51239844Sdes#include <string.h> 52239844Sdes 53239844Sdes#include <ldns/ldns.h> 54239844Sdes 55239844Sdes#include "getrrsetbyname.h" 56239844Sdes#include "log.h" 57239844Sdes#include "xmalloc.h" 58239844Sdes 59239844Sdes#define malloc(x) (xmalloc(x)) 60239844Sdes#define calloc(x, y) (xcalloc((x),(y))) 61239844Sdes 62239844Sdesint 63239844Sdesgetrrsetbyname(const char *hostname, unsigned int rdclass, 64239844Sdes unsigned int rdtype, unsigned int flags, 65239844Sdes struct rrsetinfo **res) 66239844Sdes{ 67239844Sdes int result; 68239844Sdes unsigned int i, j, index_ans, index_sig; 69239844Sdes struct rrsetinfo *rrset = NULL; 70239844Sdes struct rdatainfo *rdata; 71239844Sdes size_t len; 72295367Sdes ldns_resolver *ldns_res = NULL; 73239844Sdes ldns_rdf *domain = NULL; 74239844Sdes ldns_pkt *pkt = NULL; 75239844Sdes ldns_rr_list *rrsigs = NULL, *rrdata = NULL; 76239844Sdes ldns_status err; 77239844Sdes ldns_rr *rr; 78239844Sdes 79239844Sdes /* check for invalid class and type */ 80239844Sdes if (rdclass > 0xffff || rdtype > 0xffff) { 81239844Sdes result = ERRSET_INVAL; 82239844Sdes goto fail; 83239844Sdes } 84239844Sdes 85239844Sdes /* don't allow queries of class or type ANY */ 86239844Sdes if (rdclass == 0xff || rdtype == 0xff) { 87239844Sdes result = ERRSET_INVAL; 88239844Sdes goto fail; 89239844Sdes } 90239844Sdes 91239844Sdes /* don't allow flags yet, unimplemented */ 92239844Sdes if (flags) { 93239844Sdes result = ERRSET_INVAL; 94239844Sdes goto fail; 95239844Sdes } 96239844Sdes 97239844Sdes /* Initialize resolver from resolv.conf */ 98239844Sdes domain = ldns_dname_new_frm_str(hostname); 99239844Sdes if ((err = ldns_resolver_new_frm_file(&ldns_res, NULL)) != \ 100239844Sdes LDNS_STATUS_OK) { 101239844Sdes result = ERRSET_FAIL; 102239844Sdes goto fail; 103239844Sdes } 104239844Sdes 105239844Sdes#ifdef LDNS_DEBUG 106239844Sdes ldns_resolver_set_debug(ldns_res, true); 107239844Sdes#endif /* LDNS_DEBUG */ 108239844Sdes 109239844Sdes ldns_resolver_set_dnssec(ldns_res, true); /* Use DNSSEC */ 110239844Sdes 111239844Sdes /* make query */ 112239844Sdes pkt = ldns_resolver_query(ldns_res, domain, rdtype, rdclass, LDNS_RD); 113239844Sdes 114239844Sdes /*** TODO: finer errcodes -- see original **/ 115239844Sdes if (!pkt || ldns_pkt_ancount(pkt) < 1) { 116239844Sdes result = ERRSET_FAIL; 117239844Sdes goto fail; 118239844Sdes } 119239844Sdes 120239844Sdes /* initialize rrset */ 121239844Sdes rrset = calloc(1, sizeof(struct rrsetinfo)); 122239844Sdes if (rrset == NULL) { 123239844Sdes result = ERRSET_NOMEMORY; 124239844Sdes goto fail; 125239844Sdes } 126239844Sdes 127239844Sdes rrdata = ldns_pkt_rr_list_by_type(pkt, rdtype, LDNS_SECTION_ANSWER); 128239844Sdes rrset->rri_nrdatas = ldns_rr_list_rr_count(rrdata); 129239844Sdes if (!rrset->rri_nrdatas) { 130239844Sdes result = ERRSET_NODATA; 131239844Sdes goto fail; 132239844Sdes } 133239844Sdes 134239844Sdes /* copy name from answer section */ 135239844Sdes len = ldns_rdf_size(ldns_rr_owner(ldns_rr_list_rr(rrdata, 0))); 136239844Sdes if ((rrset->rri_name = malloc(len)) == NULL) { 137239844Sdes result = ERRSET_NOMEMORY; 138239844Sdes goto fail; 139239844Sdes } 140239844Sdes memcpy(rrset->rri_name, 141239844Sdes ldns_rdf_data(ldns_rr_owner(ldns_rr_list_rr(rrdata, 0))), len); 142239844Sdes 143239844Sdes rrset->rri_rdclass = ldns_rr_get_class(ldns_rr_list_rr(rrdata, 0)); 144239844Sdes rrset->rri_rdtype = ldns_rr_get_type(ldns_rr_list_rr(rrdata, 0)); 145239844Sdes rrset->rri_ttl = ldns_rr_ttl(ldns_rr_list_rr(rrdata, 0)); 146239844Sdes 147239844Sdes debug2("ldns: got %u answers from DNS", rrset->rri_nrdatas); 148239844Sdes 149239844Sdes /* Check for authenticated data */ 150239844Sdes if (ldns_pkt_ad(pkt)) { 151239844Sdes rrset->rri_flags |= RRSET_VALIDATED; 152239844Sdes } else { /* AD is not set, try autonomous validation */ 153239844Sdes ldns_rr_list * trusted_keys = ldns_rr_list_new(); 154239844Sdes 155239844Sdes debug2("ldns: trying to validate RRset"); 156239844Sdes /* Get eventual sigs */ 157239844Sdes rrsigs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_RRSIG, 158239844Sdes LDNS_SECTION_ANSWER); 159239844Sdes 160239844Sdes rrset->rri_nsigs = ldns_rr_list_rr_count(rrsigs); 161239844Sdes debug2("ldns: got %u signature(s) (RRTYPE %u) from DNS", 162239844Sdes rrset->rri_nsigs, LDNS_RR_TYPE_RRSIG); 163239844Sdes 164239844Sdes if ((err = ldns_verify_trusted(ldns_res, rrdata, rrsigs, 165239844Sdes trusted_keys)) == LDNS_STATUS_OK) { 166239844Sdes rrset->rri_flags |= RRSET_VALIDATED; 167239844Sdes debug2("ldns: RRset is signed with a valid key"); 168239844Sdes } else { 169239844Sdes debug2("ldns: RRset validation failed: %s", 170239844Sdes ldns_get_errorstr_by_id(err)); 171239844Sdes } 172239844Sdes 173239844Sdes ldns_rr_list_deep_free(trusted_keys); 174239844Sdes } 175239844Sdes 176239844Sdes /* allocate memory for answers */ 177239844Sdes rrset->rri_rdatas = calloc(rrset->rri_nrdatas, 178239844Sdes sizeof(struct rdatainfo)); 179239844Sdes 180239844Sdes if (rrset->rri_rdatas == NULL) { 181239844Sdes result = ERRSET_NOMEMORY; 182239844Sdes goto fail; 183239844Sdes } 184239844Sdes 185239844Sdes /* allocate memory for signatures */ 186239844Sdes if (rrset->rri_nsigs > 0) { 187239844Sdes rrset->rri_sigs = calloc(rrset->rri_nsigs, 188239844Sdes sizeof(struct rdatainfo)); 189239844Sdes 190239844Sdes if (rrset->rri_sigs == NULL) { 191239844Sdes result = ERRSET_NOMEMORY; 192239844Sdes goto fail; 193239844Sdes } 194239844Sdes } 195239844Sdes 196239844Sdes /* copy answers & signatures */ 197239844Sdes for (i=0, index_ans=0, index_sig=0; i< pkt->_header->_ancount; i++) { 198239844Sdes rdata = NULL; 199239844Sdes rr = ldns_rr_list_rr(ldns_pkt_answer(pkt), i); 200239844Sdes 201239844Sdes if (ldns_rr_get_class(rr) == rrset->rri_rdclass && 202239844Sdes ldns_rr_get_type(rr) == rrset->rri_rdtype) { 203239844Sdes rdata = &rrset->rri_rdatas[index_ans++]; 204239844Sdes } 205239844Sdes 206239844Sdes if (rr->_rr_class == rrset->rri_rdclass && 207239849Sdes rr->_rr_type == LDNS_RR_TYPE_RRSIG && 208239849Sdes rrset->rri_sigs) { 209239844Sdes rdata = &rrset->rri_sigs[index_sig++]; 210239844Sdes } 211239844Sdes 212239844Sdes if (rdata) { 213239844Sdes size_t rdata_offset = 0; 214239844Sdes 215239844Sdes rdata->rdi_length = 0; 216239844Sdes for (j=0; j< rr->_rd_count; j++) { 217239844Sdes rdata->rdi_length += 218239844Sdes ldns_rdf_size(ldns_rr_rdf(rr, j)); 219239844Sdes } 220239844Sdes 221239844Sdes rdata->rdi_data = malloc(rdata->rdi_length); 222239844Sdes if (rdata->rdi_data == NULL) { 223239844Sdes result = ERRSET_NOMEMORY; 224239844Sdes goto fail; 225239844Sdes } 226239844Sdes 227239844Sdes /* Re-create the raw DNS RDATA */ 228239844Sdes for (j=0; j< rr->_rd_count; j++) { 229239844Sdes len = ldns_rdf_size(ldns_rr_rdf(rr, j)); 230239844Sdes memcpy(rdata->rdi_data + rdata_offset, 231239844Sdes ldns_rdf_data(ldns_rr_rdf(rr, j)), len); 232239844Sdes rdata_offset += len; 233239844Sdes } 234239844Sdes } 235239844Sdes } 236239844Sdes 237239844Sdes *res = rrset; 238239844Sdes result = ERRSET_SUCCESS; 239239844Sdes 240239844Sdesfail: 241239844Sdes /* freerrset(rrset); */ 242239844Sdes ldns_rdf_deep_free(domain); 243239844Sdes ldns_pkt_free(pkt); 244239844Sdes ldns_rr_list_deep_free(rrsigs); 245239844Sdes ldns_rr_list_deep_free(rrdata); 246239844Sdes ldns_resolver_deep_free(ldns_res); 247239844Sdes 248239844Sdes return result; 249239844Sdes} 250239844Sdes 251239844Sdes 252239844Sdesvoid 253239844Sdesfreerrset(struct rrsetinfo *rrset) 254239844Sdes{ 255239844Sdes u_int16_t i; 256239844Sdes 257239844Sdes if (rrset == NULL) 258239844Sdes return; 259239844Sdes 260239844Sdes if (rrset->rri_rdatas) { 261239844Sdes for (i = 0; i < rrset->rri_nrdatas; i++) { 262239844Sdes if (rrset->rri_rdatas[i].rdi_data == NULL) 263239844Sdes break; 264239844Sdes free(rrset->rri_rdatas[i].rdi_data); 265239844Sdes } 266239844Sdes free(rrset->rri_rdatas); 267239844Sdes } 268239844Sdes 269239844Sdes if (rrset->rri_sigs) { 270239844Sdes for (i = 0; i < rrset->rri_nsigs; i++) { 271239844Sdes if (rrset->rri_sigs[i].rdi_data == NULL) 272239844Sdes break; 273239844Sdes free(rrset->rri_sigs[i].rdi_data); 274239844Sdes } 275239844Sdes free(rrset->rri_sigs); 276239844Sdes } 277239844Sdes 278239844Sdes if (rrset->rri_name) 279239844Sdes free(rrset->rri_name); 280239844Sdes free(rrset); 281239844Sdes} 282239844Sdes 283239844Sdes 284239844Sdes#endif /* !defined (HAVE_GETRRSETBYNAME) && defined (HAVE_LDNS) */ 285