158d83921SDag-Erling Smørgrav /* $OpenBSD: getrrsetbyname.c,v 1.10 2005/03/30 02:58:28 tedu Exp $ */
258d83921SDag-Erling Smørgrav 
358d83921SDag-Erling Smørgrav /*
458d83921SDag-Erling Smørgrav  * Copyright (c) 2007 Simon Vallet / Genoscope <svallet@genoscope.cns.fr>
558d83921SDag-Erling Smørgrav  *
658d83921SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
758d83921SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
858d83921SDag-Erling Smørgrav  * are met:
958d83921SDag-Erling Smørgrav  *
1058d83921SDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
1158d83921SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer.
1258d83921SDag-Erling Smørgrav  *
1358d83921SDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
1458d83921SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
1558d83921SDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
1658d83921SDag-Erling Smørgrav  *
1758d83921SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1858d83921SDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1958d83921SDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2058d83921SDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2158d83921SDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2258d83921SDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2358d83921SDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2458d83921SDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2558d83921SDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2658d83921SDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2758d83921SDag-Erling Smørgrav  */
2858d83921SDag-Erling Smørgrav 
2958d83921SDag-Erling Smørgrav /*
3058d83921SDag-Erling Smørgrav  * Portions Copyright (c) 1999-2001 Internet Software Consortium.
3158d83921SDag-Erling Smørgrav  *
3258d83921SDag-Erling Smørgrav  * Permission to use, copy, modify, and distribute this software for any
3358d83921SDag-Erling Smørgrav  * purpose with or without fee is hereby granted, provided that the above
3458d83921SDag-Erling Smørgrav  * copyright notice and this permission notice appear in all copies.
3558d83921SDag-Erling Smørgrav  *
3658d83921SDag-Erling Smørgrav  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
3758d83921SDag-Erling Smørgrav  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
3858d83921SDag-Erling Smørgrav  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
3958d83921SDag-Erling Smørgrav  * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
4058d83921SDag-Erling Smørgrav  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
4158d83921SDag-Erling Smørgrav  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
4258d83921SDag-Erling Smørgrav  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
4358d83921SDag-Erling Smørgrav  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
4458d83921SDag-Erling Smørgrav  */
4558d83921SDag-Erling Smørgrav 
4658d83921SDag-Erling Smørgrav #include "includes.h"
4758d83921SDag-Erling Smørgrav 
4858d83921SDag-Erling Smørgrav #if !defined (HAVE_GETRRSETBYNAME) && defined (HAVE_LDNS)
4958d83921SDag-Erling Smørgrav 
5058d83921SDag-Erling Smørgrav #include <stdlib.h>
5158d83921SDag-Erling Smørgrav #include <string.h>
5258d83921SDag-Erling Smørgrav 
5358d83921SDag-Erling Smørgrav #include <ldns/ldns.h>
5458d83921SDag-Erling Smørgrav 
5558d83921SDag-Erling Smørgrav #include "getrrsetbyname.h"
5658d83921SDag-Erling Smørgrav #include "log.h"
5758d83921SDag-Erling Smørgrav #include "xmalloc.h"
5858d83921SDag-Erling Smørgrav 
5958d83921SDag-Erling Smørgrav #define malloc(x)	(xmalloc(x))
6058d83921SDag-Erling Smørgrav #define calloc(x, y)	(xcalloc((x),(y)))
6158d83921SDag-Erling Smørgrav 
6258d83921SDag-Erling Smørgrav int
getrrsetbyname(const char * hostname,unsigned int rdclass,unsigned int rdtype,unsigned int flags,struct rrsetinfo ** res)6358d83921SDag-Erling Smørgrav getrrsetbyname(const char *hostname, unsigned int rdclass,
6458d83921SDag-Erling Smørgrav 	       unsigned int rdtype, unsigned int flags,
6558d83921SDag-Erling Smørgrav 	       struct rrsetinfo **res)
6658d83921SDag-Erling Smørgrav {
6758d83921SDag-Erling Smørgrav 	int result;
6858d83921SDag-Erling Smørgrav 	unsigned int i, j, index_ans, index_sig;
6958d83921SDag-Erling Smørgrav 	struct rrsetinfo *rrset = NULL;
7058d83921SDag-Erling Smørgrav 	struct rdatainfo *rdata;
7158d83921SDag-Erling Smørgrav 	size_t len;
72*bc5531deSDag-Erling Smørgrav 	ldns_resolver *ldns_res = NULL;
7358d83921SDag-Erling Smørgrav 	ldns_rdf *domain = NULL;
7458d83921SDag-Erling Smørgrav 	ldns_pkt *pkt = NULL;
7558d83921SDag-Erling Smørgrav 	ldns_rr_list *rrsigs = NULL, *rrdata = NULL;
7658d83921SDag-Erling Smørgrav 	ldns_status err;
7758d83921SDag-Erling Smørgrav 	ldns_rr *rr;
7858d83921SDag-Erling Smørgrav 
7958d83921SDag-Erling Smørgrav 	/* check for invalid class and type */
8058d83921SDag-Erling Smørgrav 	if (rdclass > 0xffff || rdtype > 0xffff) {
8158d83921SDag-Erling Smørgrav 		result = ERRSET_INVAL;
8258d83921SDag-Erling Smørgrav 		goto fail;
8358d83921SDag-Erling Smørgrav 	}
8458d83921SDag-Erling Smørgrav 
8558d83921SDag-Erling Smørgrav 	/* don't allow queries of class or type ANY */
8658d83921SDag-Erling Smørgrav 	if (rdclass == 0xff || rdtype == 0xff) {
8758d83921SDag-Erling Smørgrav 		result = ERRSET_INVAL;
8858d83921SDag-Erling Smørgrav 		goto fail;
8958d83921SDag-Erling Smørgrav 	}
9058d83921SDag-Erling Smørgrav 
9158d83921SDag-Erling Smørgrav 	/* don't allow flags yet, unimplemented */
9258d83921SDag-Erling Smørgrav 	if (flags) {
9358d83921SDag-Erling Smørgrav 		result = ERRSET_INVAL;
9458d83921SDag-Erling Smørgrav 		goto fail;
9558d83921SDag-Erling Smørgrav 	}
9658d83921SDag-Erling Smørgrav 
9758d83921SDag-Erling Smørgrav 	/* Initialize resolver from resolv.conf */
9858d83921SDag-Erling Smørgrav 	domain = ldns_dname_new_frm_str(hostname);
9958d83921SDag-Erling Smørgrav 	if ((err = ldns_resolver_new_frm_file(&ldns_res, NULL)) != \
10058d83921SDag-Erling Smørgrav 	    LDNS_STATUS_OK) {
10158d83921SDag-Erling Smørgrav 		result = ERRSET_FAIL;
10258d83921SDag-Erling Smørgrav 		goto fail;
10358d83921SDag-Erling Smørgrav 	}
10458d83921SDag-Erling Smørgrav 
10558d83921SDag-Erling Smørgrav #ifdef LDNS_DEBUG
10658d83921SDag-Erling Smørgrav 	ldns_resolver_set_debug(ldns_res, true);
10758d83921SDag-Erling Smørgrav #endif /* LDNS_DEBUG */
10858d83921SDag-Erling Smørgrav 
10958d83921SDag-Erling Smørgrav 	ldns_resolver_set_dnssec(ldns_res, true); /* Use DNSSEC */
11058d83921SDag-Erling Smørgrav 
11158d83921SDag-Erling Smørgrav 	/* make query */
11258d83921SDag-Erling Smørgrav 	pkt = ldns_resolver_query(ldns_res, domain, rdtype, rdclass, LDNS_RD);
11358d83921SDag-Erling Smørgrav 
11458d83921SDag-Erling Smørgrav 	/*** TODO: finer errcodes -- see original **/
11558d83921SDag-Erling Smørgrav 	if (!pkt || ldns_pkt_ancount(pkt) < 1) {
11658d83921SDag-Erling Smørgrav 		result = ERRSET_FAIL;
11758d83921SDag-Erling Smørgrav 		goto fail;
11858d83921SDag-Erling Smørgrav 	}
11958d83921SDag-Erling Smørgrav 
12058d83921SDag-Erling Smørgrav 	/* initialize rrset */
12158d83921SDag-Erling Smørgrav 	rrset = calloc(1, sizeof(struct rrsetinfo));
12258d83921SDag-Erling Smørgrav 	if (rrset == NULL) {
12358d83921SDag-Erling Smørgrav 		result = ERRSET_NOMEMORY;
12458d83921SDag-Erling Smørgrav 		goto fail;
12558d83921SDag-Erling Smørgrav 	}
12658d83921SDag-Erling Smørgrav 
12758d83921SDag-Erling Smørgrav 	rrdata = ldns_pkt_rr_list_by_type(pkt, rdtype, LDNS_SECTION_ANSWER);
12858d83921SDag-Erling Smørgrav 	rrset->rri_nrdatas = ldns_rr_list_rr_count(rrdata);
12958d83921SDag-Erling Smørgrav 	if (!rrset->rri_nrdatas) {
13058d83921SDag-Erling Smørgrav 		result = ERRSET_NODATA;
13158d83921SDag-Erling Smørgrav 		goto fail;
13258d83921SDag-Erling Smørgrav 	}
13358d83921SDag-Erling Smørgrav 
13458d83921SDag-Erling Smørgrav 	/* copy name from answer section */
13558d83921SDag-Erling Smørgrav 	len = ldns_rdf_size(ldns_rr_owner(ldns_rr_list_rr(rrdata, 0)));
13658d83921SDag-Erling Smørgrav 	if ((rrset->rri_name = malloc(len)) == NULL) {
13758d83921SDag-Erling Smørgrav 		result = ERRSET_NOMEMORY;
13858d83921SDag-Erling Smørgrav 		goto fail;
13958d83921SDag-Erling Smørgrav 	}
14058d83921SDag-Erling Smørgrav 	memcpy(rrset->rri_name,
14158d83921SDag-Erling Smørgrav 	    ldns_rdf_data(ldns_rr_owner(ldns_rr_list_rr(rrdata, 0))), len);
14258d83921SDag-Erling Smørgrav 
14358d83921SDag-Erling Smørgrav 	rrset->rri_rdclass = ldns_rr_get_class(ldns_rr_list_rr(rrdata, 0));
14458d83921SDag-Erling Smørgrav 	rrset->rri_rdtype = ldns_rr_get_type(ldns_rr_list_rr(rrdata, 0));
14558d83921SDag-Erling Smørgrav 	rrset->rri_ttl = ldns_rr_ttl(ldns_rr_list_rr(rrdata, 0));
14658d83921SDag-Erling Smørgrav 
14758d83921SDag-Erling Smørgrav 	debug2("ldns: got %u answers from DNS", rrset->rri_nrdatas);
14858d83921SDag-Erling Smørgrav 
14958d83921SDag-Erling Smørgrav 	/* Check for authenticated data */
15058d83921SDag-Erling Smørgrav 	if (ldns_pkt_ad(pkt)) {
15158d83921SDag-Erling Smørgrav 		rrset->rri_flags |= RRSET_VALIDATED;
15258d83921SDag-Erling Smørgrav 	} else { /* AD is not set, try autonomous validation */
15358d83921SDag-Erling Smørgrav 		ldns_rr_list * trusted_keys = ldns_rr_list_new();
15458d83921SDag-Erling Smørgrav 
15558d83921SDag-Erling Smørgrav 		debug2("ldns: trying to validate RRset");
15658d83921SDag-Erling Smørgrav 		/* Get eventual sigs */
15758d83921SDag-Erling Smørgrav 		rrsigs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_RRSIG,
15858d83921SDag-Erling Smørgrav 		    LDNS_SECTION_ANSWER);
15958d83921SDag-Erling Smørgrav 
16058d83921SDag-Erling Smørgrav 		rrset->rri_nsigs = ldns_rr_list_rr_count(rrsigs);
16158d83921SDag-Erling Smørgrav 		debug2("ldns: got %u signature(s) (RRTYPE %u) from DNS",
16258d83921SDag-Erling Smørgrav 		       rrset->rri_nsigs, LDNS_RR_TYPE_RRSIG);
16358d83921SDag-Erling Smørgrav 
16458d83921SDag-Erling Smørgrav 		if ((err = ldns_verify_trusted(ldns_res, rrdata, rrsigs,
16558d83921SDag-Erling Smørgrav 		     trusted_keys)) == LDNS_STATUS_OK) {
16658d83921SDag-Erling Smørgrav 			rrset->rri_flags |= RRSET_VALIDATED;
16758d83921SDag-Erling Smørgrav 			debug2("ldns: RRset is signed with a valid key");
16858d83921SDag-Erling Smørgrav 		} else {
16958d83921SDag-Erling Smørgrav 			debug2("ldns: RRset validation failed: %s",
17058d83921SDag-Erling Smørgrav 			    ldns_get_errorstr_by_id(err));
17158d83921SDag-Erling Smørgrav 		}
17258d83921SDag-Erling Smørgrav 
17358d83921SDag-Erling Smørgrav 		ldns_rr_list_deep_free(trusted_keys);
17458d83921SDag-Erling Smørgrav 	}
17558d83921SDag-Erling Smørgrav 
17658d83921SDag-Erling Smørgrav 	/* allocate memory for answers */
17758d83921SDag-Erling Smørgrav 	rrset->rri_rdatas = calloc(rrset->rri_nrdatas,
17858d83921SDag-Erling Smørgrav 	   sizeof(struct rdatainfo));
17958d83921SDag-Erling Smørgrav 
18058d83921SDag-Erling Smørgrav 	if (rrset->rri_rdatas == NULL) {
18158d83921SDag-Erling Smørgrav 		result = ERRSET_NOMEMORY;
18258d83921SDag-Erling Smørgrav 		goto fail;
18358d83921SDag-Erling Smørgrav 	}
18458d83921SDag-Erling Smørgrav 
18558d83921SDag-Erling Smørgrav 	/* allocate memory for signatures */
18658d83921SDag-Erling Smørgrav 	if (rrset->rri_nsigs > 0) {
18758d83921SDag-Erling Smørgrav 		rrset->rri_sigs = calloc(rrset->rri_nsigs,
18858d83921SDag-Erling Smørgrav 		    sizeof(struct rdatainfo));
18958d83921SDag-Erling Smørgrav 
19058d83921SDag-Erling Smørgrav 		if (rrset->rri_sigs == NULL) {
19158d83921SDag-Erling Smørgrav 			result = ERRSET_NOMEMORY;
19258d83921SDag-Erling Smørgrav 			goto fail;
19358d83921SDag-Erling Smørgrav 		}
19458d83921SDag-Erling Smørgrav 	}
19558d83921SDag-Erling Smørgrav 
19658d83921SDag-Erling Smørgrav 	/* copy answers & signatures */
19758d83921SDag-Erling Smørgrav 	for (i=0, index_ans=0, index_sig=0; i< pkt->_header->_ancount; i++) {
19858d83921SDag-Erling Smørgrav 		rdata = NULL;
19958d83921SDag-Erling Smørgrav 		rr = ldns_rr_list_rr(ldns_pkt_answer(pkt), i);
20058d83921SDag-Erling Smørgrav 
20158d83921SDag-Erling Smørgrav 		if (ldns_rr_get_class(rr) == rrset->rri_rdclass &&
20258d83921SDag-Erling Smørgrav 		    ldns_rr_get_type(rr) == rrset->rri_rdtype) {
20358d83921SDag-Erling Smørgrav 			rdata = &rrset->rri_rdatas[index_ans++];
20458d83921SDag-Erling Smørgrav 		}
20558d83921SDag-Erling Smørgrav 
20658d83921SDag-Erling Smørgrav 		if (rr->_rr_class == rrset->rri_rdclass &&
20758d83921SDag-Erling Smørgrav 		    rr->_rr_type == LDNS_RR_TYPE_RRSIG &&
20858d83921SDag-Erling Smørgrav 		    rrset->rri_sigs) {
20958d83921SDag-Erling Smørgrav 			rdata = &rrset->rri_sigs[index_sig++];
21058d83921SDag-Erling Smørgrav 		}
21158d83921SDag-Erling Smørgrav 
21258d83921SDag-Erling Smørgrav 		if (rdata) {
21358d83921SDag-Erling Smørgrav 			size_t rdata_offset = 0;
21458d83921SDag-Erling Smørgrav 
21558d83921SDag-Erling Smørgrav 			rdata->rdi_length = 0;
21658d83921SDag-Erling Smørgrav 			for (j=0; j< rr->_rd_count; j++) {
21758d83921SDag-Erling Smørgrav 				rdata->rdi_length +=
21858d83921SDag-Erling Smørgrav 				    ldns_rdf_size(ldns_rr_rdf(rr, j));
21958d83921SDag-Erling Smørgrav 			}
22058d83921SDag-Erling Smørgrav 
22158d83921SDag-Erling Smørgrav 			rdata->rdi_data = malloc(rdata->rdi_length);
22258d83921SDag-Erling Smørgrav 			if (rdata->rdi_data == NULL) {
22358d83921SDag-Erling Smørgrav 				result = ERRSET_NOMEMORY;
22458d83921SDag-Erling Smørgrav 				goto fail;
22558d83921SDag-Erling Smørgrav 			}
22658d83921SDag-Erling Smørgrav 
22758d83921SDag-Erling Smørgrav 			/* Re-create the raw DNS RDATA */
22858d83921SDag-Erling Smørgrav 			for (j=0; j< rr->_rd_count; j++) {
22958d83921SDag-Erling Smørgrav 				len = ldns_rdf_size(ldns_rr_rdf(rr, j));
23058d83921SDag-Erling Smørgrav 				memcpy(rdata->rdi_data + rdata_offset,
23158d83921SDag-Erling Smørgrav 				       ldns_rdf_data(ldns_rr_rdf(rr, j)), len);
23258d83921SDag-Erling Smørgrav 				rdata_offset += len;
23358d83921SDag-Erling Smørgrav 			}
23458d83921SDag-Erling Smørgrav 		}
23558d83921SDag-Erling Smørgrav 	}
23658d83921SDag-Erling Smørgrav 
23758d83921SDag-Erling Smørgrav 	*res = rrset;
23858d83921SDag-Erling Smørgrav 	result = ERRSET_SUCCESS;
23958d83921SDag-Erling Smørgrav 
24058d83921SDag-Erling Smørgrav fail:
24158d83921SDag-Erling Smørgrav 	/* freerrset(rrset); */
24258d83921SDag-Erling Smørgrav 	ldns_rdf_deep_free(domain);
24358d83921SDag-Erling Smørgrav 	ldns_pkt_free(pkt);
24458d83921SDag-Erling Smørgrav 	ldns_rr_list_deep_free(rrsigs);
24558d83921SDag-Erling Smørgrav 	ldns_rr_list_deep_free(rrdata);
24658d83921SDag-Erling Smørgrav 	ldns_resolver_deep_free(ldns_res);
24758d83921SDag-Erling Smørgrav 
24858d83921SDag-Erling Smørgrav 	return result;
24958d83921SDag-Erling Smørgrav }
25058d83921SDag-Erling Smørgrav 
25158d83921SDag-Erling Smørgrav 
25258d83921SDag-Erling Smørgrav void
freerrset(struct rrsetinfo * rrset)25358d83921SDag-Erling Smørgrav freerrset(struct rrsetinfo *rrset)
25458d83921SDag-Erling Smørgrav {
25558d83921SDag-Erling Smørgrav 	u_int16_t i;
25658d83921SDag-Erling Smørgrav 
25758d83921SDag-Erling Smørgrav 	if (rrset == NULL)
25858d83921SDag-Erling Smørgrav 		return;
25958d83921SDag-Erling Smørgrav 
26058d83921SDag-Erling Smørgrav 	if (rrset->rri_rdatas) {
26158d83921SDag-Erling Smørgrav 		for (i = 0; i < rrset->rri_nrdatas; i++) {
26258d83921SDag-Erling Smørgrav 			if (rrset->rri_rdatas[i].rdi_data == NULL)
26358d83921SDag-Erling Smørgrav 				break;
26458d83921SDag-Erling Smørgrav 			free(rrset->rri_rdatas[i].rdi_data);
26558d83921SDag-Erling Smørgrav 		}
26658d83921SDag-Erling Smørgrav 		free(rrset->rri_rdatas);
26758d83921SDag-Erling Smørgrav 	}
26858d83921SDag-Erling Smørgrav 
26958d83921SDag-Erling Smørgrav 	if (rrset->rri_sigs) {
27058d83921SDag-Erling Smørgrav 		for (i = 0; i < rrset->rri_nsigs; i++) {
27158d83921SDag-Erling Smørgrav 			if (rrset->rri_sigs[i].rdi_data == NULL)
27258d83921SDag-Erling Smørgrav 				break;
27358d83921SDag-Erling Smørgrav 			free(rrset->rri_sigs[i].rdi_data);
27458d83921SDag-Erling Smørgrav 		}
27558d83921SDag-Erling Smørgrav 		free(rrset->rri_sigs);
27658d83921SDag-Erling Smørgrav 	}
27758d83921SDag-Erling Smørgrav 
27858d83921SDag-Erling Smørgrav 	if (rrset->rri_name)
27958d83921SDag-Erling Smørgrav 		free(rrset->rri_name);
28058d83921SDag-Erling Smørgrav 	free(rrset);
28158d83921SDag-Erling Smørgrav }
28258d83921SDag-Erling Smørgrav 
28358d83921SDag-Erling Smørgrav 
28458d83921SDag-Erling Smørgrav #endif /* !defined (HAVE_GETRRSETBYNAME) && defined (HAVE_LDNS) */
285