diff options
Diffstat (limited to 'crypto/openssh/openbsd-compat/getrrsetbyname-ldns.c')
| -rw-r--r-- | crypto/openssh/openbsd-compat/getrrsetbyname-ldns.c | 284 | 
1 files changed, 284 insertions, 0 deletions
| diff --git a/crypto/openssh/openbsd-compat/getrrsetbyname-ldns.c b/crypto/openssh/openbsd-compat/getrrsetbyname-ldns.c new file mode 100644 index 000000000000..4647b623b862 --- /dev/null +++ b/crypto/openssh/openbsd-compat/getrrsetbyname-ldns.c @@ -0,0 +1,284 @@ +/* $OpenBSD: getrrsetbyname.c,v 1.10 2005/03/30 02:58:28 tedu Exp $ */ + +/* + * Copyright (c) 2007 Simon Vallet / Genoscope <svallet@genoscope.cns.fr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#if !defined (HAVE_GETRRSETBYNAME) && defined (HAVE_LDNS) + +#include <stdlib.h> +#include <string.h> + +#include <ldns/ldns.h> + +#include "getrrsetbyname.h" +#include "log.h" +#include "xmalloc.h" + +#define malloc(x)	(xmalloc(x)) +#define calloc(x, y)	(xcalloc((x),(y))) + +int +getrrsetbyname(const char *hostname, unsigned int rdclass, +	       unsigned int rdtype, unsigned int flags, +	       struct rrsetinfo **res) +{ +	int result; +	unsigned int i, j, index_ans, index_sig; +	struct rrsetinfo *rrset = NULL; +	struct rdatainfo *rdata; +	size_t len; +	ldns_resolver *ldns_res = NULL; +	ldns_rdf *domain = NULL; +	ldns_pkt *pkt = NULL; +	ldns_rr_list *rrsigs = NULL, *rrdata = NULL; +	ldns_status err; +	ldns_rr *rr; + +	/* check for invalid class and type */ +	if (rdclass > 0xffff || rdtype > 0xffff) { +		result = ERRSET_INVAL; +		goto fail; +	} + +	/* don't allow queries of class or type ANY */ +	if (rdclass == 0xff || rdtype == 0xff) { +		result = ERRSET_INVAL; +		goto fail; +	} + +	/* don't allow flags yet, unimplemented */ +	if (flags) { +		result = ERRSET_INVAL; +		goto fail; +	} + +	/* Initialize resolver from resolv.conf */ +	domain = ldns_dname_new_frm_str(hostname); +	if ((err = ldns_resolver_new_frm_file(&ldns_res, NULL)) != \ +	    LDNS_STATUS_OK) { +		result = ERRSET_FAIL; +		goto fail; +	} + +#ifdef LDNS_DEBUG +	ldns_resolver_set_debug(ldns_res, true); +#endif /* LDNS_DEBUG */ + +	ldns_resolver_set_dnssec(ldns_res, true); /* Use DNSSEC */ + +	/* make query */ +	pkt = ldns_resolver_query(ldns_res, domain, rdtype, rdclass, LDNS_RD); + +	/*** TODO: finer errcodes -- see original **/ +	if (!pkt || ldns_pkt_ancount(pkt) < 1) { +		result = ERRSET_FAIL; +		goto fail; +	} + +	/* initialize rrset */ +	rrset = calloc(1, sizeof(struct rrsetinfo)); +	if (rrset == NULL) { +		result = ERRSET_NOMEMORY; +		goto fail; +	} + +	rrdata = ldns_pkt_rr_list_by_type(pkt, rdtype, LDNS_SECTION_ANSWER); +	rrset->rri_nrdatas = ldns_rr_list_rr_count(rrdata); +	if (!rrset->rri_nrdatas) { +		result = ERRSET_NODATA; +		goto fail; +	} + +	/* copy name from answer section */ +	len = ldns_rdf_size(ldns_rr_owner(ldns_rr_list_rr(rrdata, 0))); +	if ((rrset->rri_name = malloc(len)) == NULL) { +		result = ERRSET_NOMEMORY; +		goto fail; +	} +	memcpy(rrset->rri_name, +	    ldns_rdf_data(ldns_rr_owner(ldns_rr_list_rr(rrdata, 0))), len); + +	rrset->rri_rdclass = ldns_rr_get_class(ldns_rr_list_rr(rrdata, 0)); +	rrset->rri_rdtype = ldns_rr_get_type(ldns_rr_list_rr(rrdata, 0)); +	rrset->rri_ttl = ldns_rr_ttl(ldns_rr_list_rr(rrdata, 0)); + +	debug2("ldns: got %u answers from DNS", rrset->rri_nrdatas); + +	/* Check for authenticated data */ +	if (ldns_pkt_ad(pkt)) { +		rrset->rri_flags |= RRSET_VALIDATED; +	} else { /* AD is not set, try autonomous validation */ +		ldns_rr_list * trusted_keys = ldns_rr_list_new(); + +		debug2("ldns: trying to validate RRset"); +		/* Get eventual sigs */ +		rrsigs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_RRSIG, +		    LDNS_SECTION_ANSWER); + +		rrset->rri_nsigs = ldns_rr_list_rr_count(rrsigs); +		debug2("ldns: got %u signature(s) (RRTYPE %u) from DNS", +		       rrset->rri_nsigs, LDNS_RR_TYPE_RRSIG); + +		if ((err = ldns_verify_trusted(ldns_res, rrdata, rrsigs, +		     trusted_keys)) == LDNS_STATUS_OK) { +			rrset->rri_flags |= RRSET_VALIDATED; +			debug2("ldns: RRset is signed with a valid key"); +		} else { +			debug2("ldns: RRset validation failed: %s", +			    ldns_get_errorstr_by_id(err)); +		} + +		ldns_rr_list_deep_free(trusted_keys); +	} + +	/* allocate memory for answers */ +	rrset->rri_rdatas = calloc(rrset->rri_nrdatas, +	   sizeof(struct rdatainfo)); + +	if (rrset->rri_rdatas == NULL) { +		result = ERRSET_NOMEMORY; +		goto fail; +	} + +	/* allocate memory for signatures */ +	if (rrset->rri_nsigs > 0) { +		rrset->rri_sigs = calloc(rrset->rri_nsigs, +		    sizeof(struct rdatainfo)); + +		if (rrset->rri_sigs == NULL) { +			result = ERRSET_NOMEMORY; +			goto fail; +		} +	} + +	/* copy answers & signatures */ +	for (i=0, index_ans=0, index_sig=0; i< pkt->_header->_ancount; i++) { +		rdata = NULL; +		rr = ldns_rr_list_rr(ldns_pkt_answer(pkt), i); + +		if (ldns_rr_get_class(rr) == rrset->rri_rdclass && +		    ldns_rr_get_type(rr) == rrset->rri_rdtype) { +			rdata = &rrset->rri_rdatas[index_ans++]; +		} + +		if (rr->_rr_class == rrset->rri_rdclass && +		    rr->_rr_type == LDNS_RR_TYPE_RRSIG && +		    rrset->rri_sigs) { +			rdata = &rrset->rri_sigs[index_sig++]; +		} + +		if (rdata) { +			size_t rdata_offset = 0; + +			rdata->rdi_length = 0; +			for (j=0; j< rr->_rd_count; j++) { +				rdata->rdi_length += +				    ldns_rdf_size(ldns_rr_rdf(rr, j)); +			} + +			rdata->rdi_data = malloc(rdata->rdi_length); +			if (rdata->rdi_data == NULL) { +				result = ERRSET_NOMEMORY; +				goto fail; +			} + +			/* Re-create the raw DNS RDATA */ +			for (j=0; j< rr->_rd_count; j++) { +				len = ldns_rdf_size(ldns_rr_rdf(rr, j)); +				memcpy(rdata->rdi_data + rdata_offset, +				       ldns_rdf_data(ldns_rr_rdf(rr, j)), len); +				rdata_offset += len; +			} +		} +	} + +	*res = rrset; +	result = ERRSET_SUCCESS; + +fail: +	/* freerrset(rrset); */ +	ldns_rdf_deep_free(domain); +	ldns_pkt_free(pkt); +	ldns_rr_list_deep_free(rrsigs); +	ldns_rr_list_deep_free(rrdata); +	ldns_resolver_deep_free(ldns_res); + +	return result; +} + + +void +freerrset(struct rrsetinfo *rrset) +{ +	u_int16_t i; + +	if (rrset == NULL) +		return; + +	if (rrset->rri_rdatas) { +		for (i = 0; i < rrset->rri_nrdatas; i++) { +			if (rrset->rri_rdatas[i].rdi_data == NULL) +				break; +			free(rrset->rri_rdatas[i].rdi_data); +		} +		free(rrset->rri_rdatas); +	} + +	if (rrset->rri_sigs) { +		for (i = 0; i < rrset->rri_nsigs; i++) { +			if (rrset->rri_sigs[i].rdi_data == NULL) +				break; +			free(rrset->rri_sigs[i].rdi_data); +		} +		free(rrset->rri_sigs); +	} + +	if (rrset->rri_name) +		free(rrset->rri_name); +	free(rrset); +} + + +#endif /* !defined (HAVE_GETRRSETBYNAME) && defined (HAVE_LDNS) */ | 
