Esempio n. 1
0
static isc_boolean_t
checksrv(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
#ifdef USE_GETADDRINFO
	struct addrinfo hints, *ai, *cur;
	char namebuf[DNS_NAME_FORMATSIZE + 1];
	char ownerbuf[DNS_NAME_FORMATSIZE];
	int result;
	int level = ISC_LOG_ERROR;
	isc_boolean_t answer = ISC_TRUE;

	memset(&hints, 0, sizeof(hints));
	hints.ai_flags = AI_CANONNAME;
	hints.ai_family = PF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
	/*
	 * Turn off search.
	 */
	if (dns_name_countlabels(name) > 1U)
		strcat(namebuf, ".");
	dns_name_format(owner, ownerbuf, sizeof(ownerbuf));

	result = getaddrinfo(namebuf, NULL, &hints, &ai);
	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
	switch (result) {
	case 0:
		/*
		 * Work around broken getaddrinfo() implementations that
		 * fail to set ai_canonname on first entry.
		 */
		cur = ai;
		while (cur != NULL && cur->ai_canonname == NULL &&
		       cur->ai_next != NULL)
			cur = cur->ai_next;
		if (cur != NULL && cur->ai_canonname != NULL &&
		    strcasecmp(cur->ai_canonname, namebuf) != 0) {
			if ((zone_options & DNS_ZONEOPT_WARNSRVCNAME) != 0)
				level = ISC_LOG_WARNING;
			if ((zone_options & DNS_ZONEOPT_IGNORESRVCNAME) == 0) {
				if (!logged(namebuf, ERR_IS_SRVCNAME)) {
					dns_zone_log(zone, level, "%s/SRV '%s'"
						     " (out of zone) is a "
						     "CNAME '%s' (illegal)",
						     ownerbuf, namebuf,
						     cur->ai_canonname);
					add(namebuf, ERR_IS_SRVCNAME);
				}
				if (level == ISC_LOG_ERROR)
					answer = ISC_FALSE;
			}
		}
		freeaddrinfo(ai);
		return (answer);

	case EAI_NONAME:
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
	case EAI_NODATA:
#endif
		if (!logged(namebuf, ERR_NO_ADDRESSES)) {
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "%s/SRV '%s' (out of zone) "
				     "has no addresses records (A or AAAA)",
				     ownerbuf, namebuf);
			add(namebuf, ERR_NO_ADDRESSES);
		}
		/* XXX950 make fatal for 9.5.0. */
		return (ISC_TRUE);

	default:
		if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
			dns_zone_log(zone, ISC_LOG_WARNING,
				     "getaddrinfo(%s) failed: %s",
				     namebuf, gai_strerror(result));
			add(namebuf, ERR_LOOKUP_FAILURE);
		}
		return (ISC_TRUE);
	}
#else
	return (ISC_TRUE);
#endif
}
Esempio n. 2
0
isc_result_t
dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
			  dst_key_t *dstkey, isc_boolean_t generated,
			  dns_name_t *creator, isc_stdtime_t inception,
			  isc_stdtime_t expire, isc_mem_t *mctx,
			  dns_tsig_keyring_t *ring, dns_tsigkey_t **key)
{
	dns_tsigkey_t *tkey;
	isc_result_t ret;
	unsigned int refs = 0;

	REQUIRE(key == NULL || *key == NULL);
	REQUIRE(name != NULL);
	REQUIRE(algorithm != NULL);
	REQUIRE(mctx != NULL);
	REQUIRE(key != NULL || ring != NULL);

	tkey = (dns_tsigkey_t *) isc_mem_get(mctx, sizeof(dns_tsigkey_t));
	if (tkey == NULL)
		return (ISC_R_NOMEMORY);

	dns_name_init(&tkey->name, NULL);
	ret = dns_name_dup(name, mctx, &tkey->name);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_key;
	(void)dns_name_downcase(&tkey->name, &tkey->name, NULL);

	if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) {
		tkey->algorithm = DNS_TSIG_HMACMD5_NAME;
		if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACMD5) {
			ret = DNS_R_BADALG;
			goto cleanup_name;
		}
	} else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) {
		tkey->algorithm = DNS_TSIG_HMACSHA1_NAME;
		if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA1) {
			ret = DNS_R_BADALG;
			goto cleanup_name;
		}
	} else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA224_NAME)) {
		tkey->algorithm = DNS_TSIG_HMACSHA224_NAME;
		if (dstkey != NULL &&
		    dst_key_alg(dstkey) != DST_ALG_HMACSHA224) {
			ret = DNS_R_BADALG;
			goto cleanup_name;
		}
	} else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA256_NAME)) {
		tkey->algorithm = DNS_TSIG_HMACSHA256_NAME;
		if (dstkey != NULL &&
		    dst_key_alg(dstkey) != DST_ALG_HMACSHA256) {
			ret = DNS_R_BADALG;
			goto cleanup_name;
		}
	} else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA384_NAME)) {
		tkey->algorithm = DNS_TSIG_HMACSHA384_NAME;
		if (dstkey != NULL &&
		    dst_key_alg(dstkey) != DST_ALG_HMACSHA384) {
			ret = DNS_R_BADALG;
			goto cleanup_name;
		}
	} else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA512_NAME)) {
		tkey->algorithm = DNS_TSIG_HMACSHA512_NAME;
		if (dstkey != NULL &&
		    dst_key_alg(dstkey) != DST_ALG_HMACSHA512) {
			ret = DNS_R_BADALG;
			goto cleanup_name;
		}
	} else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME)) {
		tkey->algorithm = DNS_TSIG_GSSAPI_NAME;
		if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) {
			ret = DNS_R_BADALG;
			goto cleanup_name;
		}
	} else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) {
		tkey->algorithm = DNS_TSIG_GSSAPIMS_NAME;
		if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) {
			ret = DNS_R_BADALG;
			goto cleanup_name;
		}
	} else {
		if (dstkey != NULL) {
			ret = DNS_R_BADALG;
			goto cleanup_name;
		}
		tkey->algorithm = isc_mem_get(mctx, sizeof(dns_name_t));
		if (tkey->algorithm == NULL) {
			ret = ISC_R_NOMEMORY;
			goto cleanup_name;
		}
		dns_name_init(tkey->algorithm, NULL);
		ret = dns_name_dup(algorithm, mctx, tkey->algorithm);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_algorithm;
		(void)dns_name_downcase(tkey->algorithm, tkey->algorithm,
					NULL);
	}

	if (creator != NULL) {
		tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t));
		if (tkey->creator == NULL) {
			ret = ISC_R_NOMEMORY;
			goto cleanup_algorithm;
		}
		dns_name_init(tkey->creator, NULL);
		ret = dns_name_dup(creator, mctx, tkey->creator);
		if (ret != ISC_R_SUCCESS) {
			isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t));
			goto cleanup_algorithm;
		}
	} else
		tkey->creator = NULL;

	tkey->key = NULL;
	if (dstkey != NULL)
		dst_key_attach(dstkey, &tkey->key);
	tkey->ring = ring;

	if (key != NULL)
		refs = 1;
	if (ring != NULL)
		refs++;
	ret = isc_refcount_init(&tkey->refs, refs);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_creator;

	tkey->generated = generated;
	tkey->inception = inception;
	tkey->expire = expire;
	tkey->mctx = NULL;
	isc_mem_attach(mctx, &tkey->mctx);
	ISC_LINK_INIT(tkey, link);

	tkey->magic = TSIG_MAGIC;

	if (ring != NULL) {
		ret = keyring_add(ring, name, tkey);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_refs;
	}

	/*
	 * Ignore this if it's a GSS key, since the key size is meaningless.
	 */
	if (dstkey != NULL && dst_key_size(dstkey) < 64 &&
	    !dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME) &&
	    !dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) {
		char namestr[DNS_NAME_FORMATSIZE];
		dns_name_format(name, namestr, sizeof(namestr));
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
			      DNS_LOGMODULE_TSIG, ISC_LOG_INFO,
			      "the key '%s' is too short to be secure",
			      namestr);
	}

	if (key != NULL)
		*key = tkey;

	return (ISC_R_SUCCESS);

 cleanup_refs:
	tkey->magic = 0;
	while (refs-- > 0)
		isc_refcount_decrement(&tkey->refs, NULL);
	isc_refcount_destroy(&tkey->refs);
 cleanup_creator:
	if (tkey->key != NULL)
		dst_key_free(&tkey->key);
	if (tkey->creator != NULL) {
		dns_name_free(tkey->creator, mctx);
		isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t));
	}
 cleanup_algorithm:
	if (algname_is_allocated(tkey->algorithm)) {
		if (dns_name_dynamic(tkey->algorithm))
			dns_name_free(tkey->algorithm, mctx);
		isc_mem_put(mctx, tkey->algorithm, sizeof(dns_name_t));
	}
 cleanup_name:
	dns_name_free(&tkey->name, mctx);
 cleanup_key:
	isc_mem_put(mctx, tkey, sizeof(dns_tsigkey_t));

	return (ret);
}
Esempio n. 3
0
static inline isc_result_t
totext_dnskey(ARGS_TOTEXT) {
	isc_region_t sr;
	char buf[sizeof("64000")];
	unsigned int flags;
	unsigned char algorithm;
	char algbuf[DNS_NAME_FORMATSIZE];
	const char *keyinfo;

	REQUIRE(rdata->type == 48);
	REQUIRE(rdata->length != 0);

	dns_rdata_toregion(rdata, &sr);

	/* flags */
	flags = uint16_fromregion(&sr);
	isc_region_consume(&sr, 2);
	sprintf(buf, "%u", flags);
	RETERR(str_totext(buf, target));
	RETERR(str_totext(" ", target));
	if ((flags & DNS_KEYFLAG_KSK) != 0) {
		if (flags & DNS_KEYFLAG_REVOKE)
			keyinfo = "revoked KSK";
		else
			keyinfo = "KSK";
	} else
		keyinfo = "ZSK";

	/* protocol */
	sprintf(buf, "%u", sr.base[0]);
	isc_region_consume(&sr, 1);
	RETERR(str_totext(buf, target));
	RETERR(str_totext(" ", target));

	/* algorithm */
	algorithm = sr.base[0];
	sprintf(buf, "%u", algorithm);
	isc_region_consume(&sr, 1);
	RETERR(str_totext(buf, target));

	/* No Key? */
	if ((flags & 0xc000) == 0xc000)
		return (ISC_R_SUCCESS);

	if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0 &&
	     algorithm == DNS_KEYALG_PRIVATEDNS) {
		dns_name_t name;
		dns_name_init(&name, NULL);
		dns_name_fromregion(&name, &sr);
		dns_name_format(&name, algbuf, sizeof(algbuf));
	} else {
		dns_secalg_format((dns_secalg_t) algorithm, algbuf,
				  sizeof(algbuf));
	}

	/* key */
	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
		RETERR(str_totext(" (", target));
	RETERR(str_totext(tctx->linebreak, target));
	if (tctx->width == 0)   /* No splitting */
		RETERR(isc_base64_totext(&sr, 0, "", target));
	else
		RETERR(isc_base64_totext(&sr, tctx->width - 2,
					 tctx->linebreak, target));

	if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0)
		RETERR(str_totext(tctx->linebreak, target));
	else if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
		RETERR(str_totext(" ", target));

	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
		RETERR(str_totext(")", target));

	if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0) {
		isc_region_t tmpr;

		RETERR(str_totext(" ; ", target));
		RETERR(str_totext(keyinfo, target));
		RETERR(str_totext("; alg = ", target));
		RETERR(str_totext(algbuf, target));
		RETERR(str_totext("; key id = ", target));
		dns_rdata_toregion(rdata, &tmpr);
		sprintf(buf, "%u", dst_region_computeid(&tmpr, algorithm));
		RETERR(str_totext(buf, target));
	}
	return (ISC_R_SUCCESS);
}
Esempio n. 4
0
static isc_boolean_t
checkns(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner,
	dns_rdataset_t *a, dns_rdataset_t *aaaa)
{
#ifdef USE_GETADDRINFO
	dns_rdataset_t *rdataset;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	struct addrinfo hints, *ai, *cur;
	char namebuf[DNS_NAME_FORMATSIZE + 1];
	char ownerbuf[DNS_NAME_FORMATSIZE];
	char addrbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")];
	isc_boolean_t answer = ISC_TRUE;
	isc_boolean_t match;
	const char *type;
	void *ptr = NULL;
	int result;

	REQUIRE(a == NULL || !dns_rdataset_isassociated(a) ||
		a->type == dns_rdatatype_a);
	REQUIRE(aaaa == NULL || !dns_rdataset_isassociated(aaaa) ||
		aaaa->type == dns_rdatatype_aaaa);
	memset(&hints, 0, sizeof(hints));
	hints.ai_flags = AI_CANONNAME;
	hints.ai_family = PF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
	/*
	 * Turn off search.
	 */
	if (dns_name_countlabels(name) > 1U)
		strcat(namebuf, ".");
	dns_name_format(owner, ownerbuf, sizeof(ownerbuf));

	result = getaddrinfo(namebuf, NULL, &hints, &ai);
	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
	switch (result) {
	case 0:
		/*
		 * Work around broken getaddrinfo() implementations that
		 * fail to set ai_canonname on first entry.
		 */
		cur = ai;
		while (cur != NULL && cur->ai_canonname == NULL &&
		       cur->ai_next != NULL)
			cur = cur->ai_next;
		if (cur != NULL && cur->ai_canonname != NULL &&
		    strcasecmp(cur->ai_canonname, namebuf) != 0 &&
		    !logged(namebuf, ERR_IS_CNAME)) {
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "%s/NS '%s' (out of zone) "
				     "is a CNAME '%s' (illegal)",
				     ownerbuf, namebuf,
				     cur->ai_canonname);
			/* XXX950 make fatal for 9.5.0 */
			/* answer = ISC_FALSE; */
			add(namebuf, ERR_IS_CNAME);
		}
		break;
	case EAI_NONAME:
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
	case EAI_NODATA:
#endif
		if (!logged(namebuf, ERR_NO_ADDRESSES)) {
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "%s/NS '%s' (out of zone) "
				     "has no addresses records (A or AAAA)",
				     ownerbuf, namebuf);
			add(namebuf, ERR_NO_ADDRESSES);
		}
		/* XXX950 make fatal for 9.5.0 */
		return (ISC_TRUE);

	default:
		if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
			dns_zone_log(zone, ISC_LOG_WARNING,
				     "getaddrinfo(%s) failed: %s",
				     namebuf, gai_strerror(result));
			add(namebuf, ERR_LOOKUP_FAILURE);
		}
		return (ISC_TRUE);
	}
	if (a == NULL || aaaa == NULL)
		return (answer);
	/*
	 * Check that all glue records really exist.
	 */
	if (!dns_rdataset_isassociated(a))
		goto checkaaaa;
	result = dns_rdataset_first(a);
	while (result == ISC_R_SUCCESS) {
		dns_rdataset_current(a, &rdata);
		match = ISC_FALSE;
		for (cur = ai; cur != NULL; cur = cur->ai_next) {
			if (cur->ai_family != AF_INET)
				continue;
			ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
			if (memcmp(ptr, rdata.data, rdata.length) == 0) {
				match = ISC_TRUE;
				break;
			}
		}
		if (!match && !logged(namebuf, ERR_EXTRA_A)) {
			dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
				     "extra GLUE A record (%s)",
				     ownerbuf, namebuf,
				     inet_ntop(AF_INET, rdata.data,
					       addrbuf, sizeof(addrbuf)));
			add(namebuf, ERR_EXTRA_A);
			/* XXX950 make fatal for 9.5.0 */
			/* answer = ISC_FALSE; */
		}
		dns_rdata_reset(&rdata);
		result = dns_rdataset_next(a);
	}

 checkaaaa:
	if (!dns_rdataset_isassociated(aaaa))
		goto checkmissing;
	result = dns_rdataset_first(aaaa);
	while (result == ISC_R_SUCCESS) {
		dns_rdataset_current(aaaa, &rdata);
		match = ISC_FALSE;
		for (cur = ai; cur != NULL; cur = cur->ai_next) {
			if (cur->ai_family != AF_INET6)
				continue;
			ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr;
			if (memcmp(ptr, rdata.data, rdata.length) == 0) {
				match = ISC_TRUE;
				break;
			}
		}
		if (!match && !logged(namebuf, ERR_EXTRA_AAAA)) {
			dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
				     "extra GLUE AAAA record (%s)",
				     ownerbuf, namebuf,
				     inet_ntop(AF_INET6, rdata.data,
					       addrbuf, sizeof(addrbuf)));
			add(namebuf, ERR_EXTRA_AAAA);
			/* XXX950 make fatal for 9.5.0. */
			/* answer = ISC_FALSE; */
		}
		dns_rdata_reset(&rdata);
		result = dns_rdataset_next(aaaa);
	}

 checkmissing:
	/*
	 * Check that all addresses appear in the glue.
	 */
	if (!logged(namebuf, ERR_MISSING_GLUE)) {
		isc_boolean_t missing_glue = ISC_FALSE;
		for (cur = ai; cur != NULL; cur = cur->ai_next) {
			switch (cur->ai_family) {
			case AF_INET:
				rdataset = a;
				ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
				type = "A";
				break;
			case AF_INET6:
				rdataset = aaaa;
				ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr;
				type = "AAAA";
				break;
			default:
				 continue;
			}
			match = ISC_FALSE;
			if (dns_rdataset_isassociated(rdataset))
				result = dns_rdataset_first(rdataset);
			else
				result = ISC_R_FAILURE;
			while (result == ISC_R_SUCCESS && !match) {
				dns_rdataset_current(rdataset, &rdata);
				if (memcmp(ptr, rdata.data, rdata.length) == 0)
					match = ISC_TRUE;
				dns_rdata_reset(&rdata);
				result = dns_rdataset_next(rdataset);
			}
			if (!match) {
				dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
					     "missing GLUE %s record (%s)",
					     ownerbuf, namebuf, type,
					     inet_ntop(cur->ai_family, ptr,
						       addrbuf, sizeof(addrbuf)));
				/* XXX950 make fatal for 9.5.0. */
				/* answer = ISC_FALSE; */
				missing_glue = ISC_TRUE;
			}
		}
		if (missing_glue)
			add(namebuf, ERR_MISSING_GLUE);
	}
	freeaddrinfo(ai);
	return (answer);
#else
	return (ISC_TRUE);
#endif
}
Esempio n. 5
0
isc_boolean_t
dst_gssapi_identitymatchesrealmkrb5(dns_name_t *signer, dns_name_t *name,
				    dns_name_t *realm)
{
#ifdef GSSAPI
	char sbuf[DNS_NAME_FORMATSIZE];
	char nbuf[DNS_NAME_FORMATSIZE];
	char rbuf[DNS_NAME_FORMATSIZE];
	char *sname;
	char *rname;
	isc_buffer_t buffer;
	isc_result_t result;

	/*
	 * It is far, far easier to write the names we are looking at into
	 * a string, and do string operations on them.
	 */
	isc_buffer_init(&buffer, sbuf, sizeof(sbuf));
	result = dns_name_toprincipal(signer, &buffer);
	RUNTIME_CHECK(result == ISC_R_SUCCESS);
	isc_buffer_putuint8(&buffer, 0);
	if (name != NULL)
		dns_name_format(name, nbuf, sizeof(nbuf));
	dns_name_format(realm, rbuf, sizeof(rbuf));

	/*
	 * Find the realm portion.  This is the part after the @.  If it
	 * does not exist, we don't have something we like, so we fail our
	 * compare.
	 */
	rname = strchr(sbuf, '@');
	if (rname == NULL)
		return (isc_boolean_false);
	*rname = '\0';
	rname++;

	/*
	 * Find the host portion of the signer's name.	We do this by
	 * searching for the first / character.  We then check to make
	 * certain the instance name is "host"
	 *
	 * This will work for
	 *    host/[email protected]
	 */
	sname = strchr(sbuf, '/');
	if (sname == NULL)
		return (isc_boolean_false);
	*sname = '\0';
	sname++;
	if (strcmp(sbuf, "host") != 0)
		return (isc_boolean_false);

	/*
	 * Now, we do a simple comparison between the name and the realm.
	 */
	if (name != NULL) {
		if ((strcasecmp(sname, nbuf) == 0)
		    && (strcmp(rname, rbuf) == 0))
			return (isc_boolean_true);
	} else {
		if (strcmp(rname, rbuf) == 0)
			return (isc_boolean_true);
	}

	return (isc_boolean_false);
#else
	UNUSED(signer);
	UNUSED(name);
	UNUSED(realm);
	return (isc_boolean_false);
#endif
}
Esempio n. 6
0
isc_boolean_t
dst_gssapi_identitymatchesrealmms(dns_name_t *signer, dns_name_t *name,
				  dns_name_t *realm)
{
#ifdef GSSAPI
	char sbuf[DNS_NAME_FORMATSIZE];
	char nbuf[DNS_NAME_FORMATSIZE];
	char rbuf[DNS_NAME_FORMATSIZE];
	char *sname;
	char *nname;
	char *rname;
	isc_buffer_t buffer;
	isc_result_t result;

	/*
	 * It is far, far easier to write the names we are looking at into
	 * a string, and do string operations on them.
	 */
	isc_buffer_init(&buffer, sbuf, sizeof(sbuf));
	result = dns_name_toprincipal(signer, &buffer);
	RUNTIME_CHECK(result == ISC_R_SUCCESS);
	isc_buffer_putuint8(&buffer, 0);
	if (name != NULL)
		dns_name_format(name, nbuf, sizeof(nbuf));
	dns_name_format(realm, rbuf, sizeof(rbuf));

	/*
	 * Find the realm portion.  This is the part after the @.  If it
	 * does not exist, we don't have something we like, so we fail our
	 * compare.
	 */
	rname = strchr(sbuf, '@');
	if (rname == NULL)
		return (isc_boolean_false);
	sname = strchr(sbuf, '$');
	if (sname == NULL)
		return (isc_boolean_false);

	/*
	 * Verify that the $ and @ follow one another.
	 */
	if (rname - sname != 1)
		return (isc_boolean_false);

	/*
	 * Find the host portion of the signer's name.	Zero out the $ so
	 * it terminates the signer's name, and skip past the @ for
	 * the realm.
	 *
	 * All service principals in Microsoft format seem to be in
	 *    [email protected]
	 * format.
	 */
	rname++;
	*sname = '\0';
	sname = sbuf;

	/*
	 * Find the first . in the target name, and make it the end of
	 * the string.	 The rest of the name has to match the realm.
	 */
	if (name != NULL) {
		nname = strchr(nbuf, '.');
		if (nname == NULL)
			return (isc_boolean_false);
		*nname++ = '\0';
	}

	/*
	 * Now, we do a simple comparison between the name and the realm.
	 */
	if (name != NULL) {
		if ((strcasecmp(sname, nbuf) == 0)
		    && (strcmp(rname, rbuf) == 0)
		    && (strcasecmp(nname, rbuf) == 0))
			return (isc_boolean_true);
	} else {
		if (strcmp(rname, rbuf) == 0)
			return (isc_boolean_true);
	}


	return (isc_boolean_false);
#else
	UNUSED(signer);
	UNUSED(name);
	UNUSED(realm);
	return (isc_boolean_false);
#endif
}
Esempio n. 7
0
void
ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) {
	isc_result_t result;
	dns_name_t *question_name;
	dns_rdataset_t *question_rdataset;
	dns_zone_t *zone = NULL;
	dns_db_t *db = NULL;
	dns_dbversion_t *ver = NULL;
	dns_rdataclass_t question_class;
	rrstream_t *soa_stream = NULL;
	rrstream_t *data_stream = NULL;
	rrstream_t *stream = NULL;
	dns_difftuple_t *current_soa_tuple = NULL;
	dns_name_t *soa_name;
	dns_rdataset_t *soa_rdataset;
	dns_rdata_t soa_rdata = DNS_RDATA_INIT;
	isc_boolean_t have_soa = ISC_FALSE;
	const char *mnemonic = NULL;
	isc_mem_t *mctx = client->mctx;
	dns_message_t *request = client->message;
	xfrout_ctx_t *xfr = NULL;
	isc_quota_t *quota = NULL;
	dns_transfer_format_t format = client->view->transfer_format;
	isc_netaddr_t na;
	dns_peer_t *peer = NULL;
	isc_buffer_t *tsigbuf = NULL;
	char *journalfile;
	char msg[NS_CLIENT_ACLMSGSIZE("zone transfer")];
	char keyname[DNS_NAME_FORMATSIZE];
	isc_boolean_t is_poll = ISC_FALSE;
	isc_boolean_t is_dlz = ISC_FALSE;

	switch (reqtype) {
	case dns_rdatatype_axfr:
		mnemonic = "AXFR";
		break;
	case dns_rdatatype_ixfr:
		mnemonic = "IXFR";
		break;
	default:
		INSIST(0);
		break;
	}

	ns_client_log(client,
		      DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT,
		      ISC_LOG_DEBUG(6), "%s request", mnemonic);
	/*
	 * Apply quota.
	 */
	result = isc_quota_attach(&ns_g_server->xfroutquota, &quota);
	if (result != ISC_R_SUCCESS) {
		isc_log_write(XFROUT_COMMON_LOGARGS, ISC_LOG_WARNING,
			      "%s request denied: %s", mnemonic,
			      isc_result_totext(result));
		goto failure;
	}

	/*
	 * Interpret the question section.
	 */
	result = dns_message_firstname(request, DNS_SECTION_QUESTION);
	INSIST(result == ISC_R_SUCCESS);

	/*
	 * The question section must contain exactly one question, and
	 * it must be for AXFR/IXFR as appropriate.
	 */
	question_name = NULL;
	dns_message_currentname(request, DNS_SECTION_QUESTION, &question_name);
	question_rdataset = ISC_LIST_HEAD(question_name->list);
	question_class = question_rdataset->rdclass;
	INSIST(question_rdataset->type == reqtype);
	if (ISC_LIST_NEXT(question_rdataset, link) != NULL)
		FAILC(DNS_R_FORMERR, "multiple questions");
	result = dns_message_nextname(request, DNS_SECTION_QUESTION);
	if (result != ISC_R_NOMORE)
		FAILC(DNS_R_FORMERR, "multiple questions");

	result = dns_zt_find(client->view->zonetable, question_name, 0, NULL,
			     &zone);

	if (result != ISC_R_SUCCESS) {
		/*
		 * Normal zone table does not have a match.
		 * Try the DLZ database
		 */
		if (client->view->dlzdatabase != NULL) {
			result = dns_dlzallowzonexfr(client->view,
						     question_name,
						     &client->peeraddr,
						     &db);

			if (result == ISC_R_NOPERM) {
				char _buf1[DNS_NAME_FORMATSIZE];
				char _buf2[DNS_RDATACLASS_FORMATSIZE];

				result = DNS_R_REFUSED;
				dns_name_format(question_name, _buf1,
						sizeof(_buf1));
				dns_rdataclass_format(question_class,
						      _buf2, sizeof(_buf2));
				ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
					      NS_LOGMODULE_XFER_OUT,
					      ISC_LOG_ERROR,
					      "zone transfer '%s/%s' denied",
					      _buf1, _buf2);
				goto failure;
			}
			if (result != ISC_R_SUCCESS)
				FAILQ(DNS_R_NOTAUTH, "non-authoritative zone",
				      question_name, question_class);
			is_dlz = ISC_TRUE;
			/*
			 * DLZ only support full zone transfer, not incremental
			 */
			if (reqtype != dns_rdatatype_axfr) {
				mnemonic = "AXFR-style IXFR";
				reqtype = dns_rdatatype_axfr;
			}

		} else {
			/*
			 * not DLZ and not in normal zone table, we are
			 * not authoritative
			 */
			FAILQ(DNS_R_NOTAUTH, "non-authoritative zone",
			      question_name, question_class);
		}
	} else {
		/* zone table has a match */
		switch(dns_zone_gettype(zone)) {
			case dns_zone_master:
			case dns_zone_slave:
			case dns_zone_dlz:
				break;	/* Master and slave zones are OK for transfer. */
			default:
				FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", question_name, question_class);
			}
		CHECK(dns_zone_getdb(zone, &db));
		dns_db_currentversion(db, &ver);
	}

	xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6),
		    "%s question section OK", mnemonic);

	/*
	 * Check the authority section.  Look for a SOA record with
	 * the same name and class as the question.
	 */
	for (result = dns_message_firstname(request, DNS_SECTION_AUTHORITY);
	     result == ISC_R_SUCCESS;
	     result = dns_message_nextname(request, DNS_SECTION_AUTHORITY))
	{
		soa_name = NULL;
		dns_message_currentname(request, DNS_SECTION_AUTHORITY,
					&soa_name);

		/*
		 * Ignore data whose owner name is not the zone apex.
		 */
		if (! dns_name_equal(soa_name, question_name))
			continue;

		for (soa_rdataset = ISC_LIST_HEAD(soa_name->list);
		     soa_rdataset != NULL;
		     soa_rdataset = ISC_LIST_NEXT(soa_rdataset, link))
		{
			/*
			 * Ignore non-SOA data.
			 */
			if (soa_rdataset->type != dns_rdatatype_soa)
				continue;
			if (soa_rdataset->rdclass != question_class)
				continue;

			CHECK(dns_rdataset_first(soa_rdataset));
			dns_rdataset_current(soa_rdataset, &soa_rdata);
			result = dns_rdataset_next(soa_rdataset);
			if (result == ISC_R_SUCCESS)
				FAILC(DNS_R_FORMERR,
				      "IXFR authority section "
				      "has multiple SOAs");
			have_soa = ISC_TRUE;
			goto got_soa;
		}
	}
 got_soa:
	if (result != ISC_R_NOMORE)
		CHECK(result);

	xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6),
		    "%s authority section OK", mnemonic);

	/*
	 * If not a DLZ zone, decide whether to allow this transfer.
	 */
	if (!is_dlz) {
		ns_client_aclmsg("zone transfer", question_name, reqtype,
				 client->view->rdclass, msg, sizeof(msg));
		CHECK(ns_client_checkacl(client, NULL, msg,
					 dns_zone_getxfracl(zone),
					 ISC_TRUE, ISC_LOG_ERROR));
	}

	/*
	 * AXFR over UDP is not possible.
	 */
	if (reqtype == dns_rdatatype_axfr &&
	    (client->attributes & NS_CLIENTATTR_TCP) == 0)
		FAILC(DNS_R_FORMERR, "attempted AXFR over UDP");

	/*
	 * Look up the requesting server in the peer table.
	 */
	isc_netaddr_fromsockaddr(&na, &client->peeraddr);
	(void)dns_peerlist_peerbyaddr(client->view->peers, &na, &peer);

	/*
	 * Decide on the transfer format (one-answer or many-answers).
	 */
	if (peer != NULL)
		(void)dns_peer_gettransferformat(peer, &format);

	/*
	 * Get a dynamically allocated copy of the current SOA.
	 */
	if (is_dlz)
		dns_db_currentversion(db, &ver);

	CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS,
				    &current_soa_tuple));

	if (reqtype == dns_rdatatype_ixfr) {
		isc_uint32_t begin_serial, current_serial;
		isc_boolean_t provide_ixfr;

		/*
		 * Outgoing IXFR may have been disabled for this peer
		 * or globally.
		 */
		provide_ixfr = client->view->provideixfr;
		if (peer != NULL)
			(void) dns_peer_getprovideixfr(peer, &provide_ixfr);
		if (provide_ixfr == ISC_FALSE)
			goto axfr_fallback;

		if (! have_soa)
			FAILC(DNS_R_FORMERR,
			      "IXFR request missing SOA");

		begin_serial = dns_soa_getserial(&soa_rdata);
		current_serial = dns_soa_getserial(&current_soa_tuple->rdata);

		/*
		 * RFC1995 says "If an IXFR query with the same or
		 * newer version number than that of the server
		 * is received, it is replied to with a single SOA
		 * record of the server's current version, just as
		 * in AXFR".  The claim about AXFR is incorrect,
		 * but other than that, we do as the RFC says.
		 *
		 * Sending a single SOA record is also how we refuse
		 * IXFR over UDP (currently, we always do).
		 */
		if (DNS_SERIAL_GE(begin_serial, current_serial) ||
		    (client->attributes & NS_CLIENTATTR_TCP) == 0)
		{
			CHECK(soa_rrstream_create(mctx, db, ver, &stream));
			is_poll = ISC_TRUE;
			goto have_stream;
		}
		journalfile = dns_zone_getjournal(zone);
		if (journalfile != NULL)
			result = ixfr_rrstream_create(mctx,
						      journalfile,
						      begin_serial,
						      current_serial,
						      &data_stream);
		else
			result = ISC_R_NOTFOUND;
		if (result == ISC_R_NOTFOUND ||
		    result == ISC_R_RANGE) {
			xfrout_log1(client, question_name, question_class,
				    ISC_LOG_DEBUG(4),
				    "IXFR version not in journal, "
				    "falling back to AXFR");
			mnemonic = "AXFR-style IXFR";
			goto axfr_fallback;
		}
		CHECK(result);
	} else {
	axfr_fallback:
		CHECK(axfr_rrstream_create(mctx, db, ver,
					   &data_stream));
	}

	/*
	 * Bracket the data stream with SOAs.
	 */
	CHECK(soa_rrstream_create(mctx, db, ver, &soa_stream));
	CHECK(compound_rrstream_create(mctx, &soa_stream, &data_stream,
				       &stream));
	soa_stream = NULL;
	data_stream = NULL;

 have_stream:
	CHECK(dns_message_getquerytsig(request, mctx, &tsigbuf));
	/*
	 * Create the xfrout context object.  This transfers the ownership
	 * of "stream", "db", "ver", and "quota" to the xfrout context object.
	 */



	if (is_dlz)
		CHECK(xfrout_ctx_create(mctx, client, request->id,
					question_name, reqtype, question_class,
					zone, db, ver, quota, stream,
					dns_message_gettsigkey(request),
					tsigbuf,
					3600,
					3600,
					(format == dns_many_answers) ?
					ISC_TRUE : ISC_FALSE,
					&xfr));
	else
		CHECK(xfrout_ctx_create(mctx, client, request->id,
					question_name, reqtype, question_class,
					zone, db, ver, quota, stream,
					dns_message_gettsigkey(request),
					tsigbuf,
					dns_zone_getmaxxfrout(zone),
					dns_zone_getidleout(zone),
					(format == dns_many_answers) ?
					ISC_TRUE : ISC_FALSE,
					&xfr));

	xfr->mnemonic = mnemonic;
	stream = NULL;
	quota = NULL;

	CHECK(xfr->stream->methods->first(xfr->stream));

	if (xfr->tsigkey != NULL)
		dns_name_format(&xfr->tsigkey->name, keyname, sizeof(keyname));
	else
		keyname[0] = '\0';
	if (is_poll)
		xfrout_log1(client, question_name, question_class,
			    ISC_LOG_DEBUG(1), "IXFR poll up to date%s%s",
			    (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname);
	else
		xfrout_log1(client, question_name, question_class,
			    ISC_LOG_INFO, "%s started%s%s", mnemonic,
			    (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname);

	/*
	 * Hand the context over to sendstream().  Set xfr to NULL;
	 * sendstream() is responsible for either passing the
	 * context on to a later event handler or destroying it.
	 */
	sendstream(xfr);
	xfr = NULL;

	result = ISC_R_SUCCESS;

 failure:
	if (result == DNS_R_REFUSED)
		inc_stats(zone, dns_nsstatscounter_xfrrej);
	if (quota != NULL)
		isc_quota_detach(&quota);
	if (current_soa_tuple != NULL)
		dns_difftuple_free(&current_soa_tuple);
	if (stream != NULL)
		stream->methods->destroy(&stream);
	if (soa_stream != NULL)
		soa_stream->methods->destroy(&soa_stream);
	if (data_stream != NULL)
		data_stream->methods->destroy(&data_stream);
	if (ver != NULL)
		dns_db_closeversion(db, &ver, ISC_FALSE);
	if (db != NULL)
		dns_db_detach(&db);
	if (zone != NULL)
		dns_zone_detach(&zone);
	/* XXX kludge */
	if (xfr != NULL) {
		xfrout_fail(xfr, result, "setting up zone transfer");
	} else if (result != ISC_R_SUCCESS) {
		ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT,
			      NS_LOGMODULE_XFER_OUT,
			      ISC_LOG_DEBUG(3), "zone transfer setup failed");
		ns_client_error(client, result);
	}
}
Esempio n. 8
0
/*
 * Perform an update-policy rule check against an external application
 * over a socket.
 *
 * This currently only supports local: for unix domain datagram sockets.
 *
 * Note that by using a datagram socket and creating a new socket each
 * time we avoid the need for locking and allow for parallel access to
 * the authorization server.
 */
isc_boolean_t
dns_ssu_external_match (dns_name_t * identity,
                        dns_name_t * signer, dns_name_t * name,
                        isc_netaddr_t * tcpaddr, dns_rdatatype_t type, const dst_key_t * key, isc_mem_t * mctx)
{
    char b_identity[DNS_NAME_FORMATSIZE];

    char b_signer[DNS_NAME_FORMATSIZE];

    char b_name[DNS_NAME_FORMATSIZE];

    char b_addr[ISC_NETADDR_FORMATSIZE];

    char b_type[DNS_RDATATYPE_FORMATSIZE];

    char b_key[DST_KEY_FORMATSIZE];

    isc_buffer_t *tkey_token = NULL;

    int fd;

    const char *sock_path;

    size_t req_len;

    isc_region_t token_region;

    unsigned char *data;

    isc_buffer_t buf;

    isc_uint32_t token_len = 0;

    isc_uint32_t reply;

    ssize_t ret;

    /* The identity contains local:/path/to/socket */
    dns_name_format (identity, b_identity, sizeof (b_identity));

    /* For now only local: is supported */
    if (strncmp (b_identity, "local:", 6) != 0)
    {
        ssu_e_log (3, "ssu_external: invalid socket path '%s'", b_identity);
        return (ISC_FALSE);
    }
    sock_path = &b_identity[6];

    fd = ux_socket_connect (sock_path);
    if (fd == -1)
        return (ISC_FALSE);

    if (key != NULL)
    {
        dst_key_format (key, b_key, sizeof (b_key));
        tkey_token = dst_key_tkeytoken (key);
    }
    else
        b_key[0] = 0;

    if (tkey_token != NULL)
    {
        isc_buffer_region (tkey_token, &token_region);
        token_len = token_region.length;
    }

    /* Format the request elements */
    if (signer != NULL)
        dns_name_format (signer, b_signer, sizeof (b_signer));
    else
        b_signer[0] = 0;

    dns_name_format (name, b_name, sizeof (b_name));

    if (tcpaddr != NULL)
        isc_netaddr_format (tcpaddr, b_addr, sizeof (b_addr));
    else
        b_addr[0] = 0;

    dns_rdatatype_format (type, b_type, sizeof (b_type));

    /* Work out how big the request will be */
    req_len = sizeof (isc_uint32_t) +    /* Format version */
        sizeof (isc_uint32_t) +    /* Length */
        strlen (b_signer) + 1 +    /* Signer */
        strlen (b_name) + 1 +    /* Name */
        strlen (b_addr) + 1 +    /* Address */
        strlen (b_type) + 1 +    /* Type */
        strlen (b_key) + 1 +    /* Key */
        sizeof (isc_uint32_t) +    /* tkey_token length */
        token_len;                /* tkey_token */


    /* format the buffer */
    data = isc_mem_allocate (mctx, req_len);
    if (data == NULL)
    {
        close (fd);
        return (ISC_FALSE);
    }

    isc_buffer_init (&buf, data, req_len);
    isc_buffer_putuint32 (&buf, SSU_EXTERNAL_VERSION);
    isc_buffer_putuint32 (&buf, req_len);

    /* Strings must be null-terminated */
    isc_buffer_putstr (&buf, b_signer);
    isc_buffer_putuint8 (&buf, 0);
    isc_buffer_putstr (&buf, b_name);
    isc_buffer_putuint8 (&buf, 0);
    isc_buffer_putstr (&buf, b_addr);
    isc_buffer_putuint8 (&buf, 0);
    isc_buffer_putstr (&buf, b_type);
    isc_buffer_putuint8 (&buf, 0);
    isc_buffer_putstr (&buf, b_key);
    isc_buffer_putuint8 (&buf, 0);

    isc_buffer_putuint32 (&buf, token_len);
    if (tkey_token && token_len != 0)
        isc_buffer_putmem (&buf, token_region.base, token_len);

    ENSURE (isc_buffer_availablelength (&buf) == 0);

    /* Send the request */
    ret = write (fd, data, req_len);
    isc_mem_free (mctx, data);
    if (ret != (ssize_t) req_len)
    {
        char strbuf[ISC_STRERRORSIZE];

        isc__strerror (errno, strbuf, sizeof (strbuf));
        ssu_e_log (3, "ssu_external: unable to send request - %s", strbuf);
        close (fd);
        return (ISC_FALSE);
    }

    /* Receive the reply */
    ret = read (fd, &reply, sizeof (isc_uint32_t));
    if (ret != (ssize_t) sizeof (isc_uint32_t))
    {
        char strbuf[ISC_STRERRORSIZE];

        isc__strerror (errno, strbuf, sizeof (strbuf));
        ssu_e_log (3, "ssu_external: unable to receive reply - %s", strbuf);
        close (fd);
        return (ISC_FALSE);
    }

    close (fd);

    reply = ntohl (reply);

    if (reply == 0)
    {
        ssu_e_log (3, "ssu_external: denied external auth for '%s'", b_name);
        return (ISC_FALSE);
    }
    else if (reply == 1)
    {
        ssu_e_log (3, "ssu_external: allowed external auth for '%s'", b_name);
        return (ISC_TRUE);
    }

    ssu_e_log (3, "ssu_external: invalid reply 0x%08x", reply);

    return (ISC_FALSE);
}
Esempio n. 9
0
static isc_result_t
detailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers,
              dns_section_t section) {
    isc_result_t result, loopresult;
    dns_name_t *name;
    dns_rdataset_t *rdataset = NULL;
    dns_rdata_t rdata = DNS_RDATA_INIT;
    char namebuf[DNS_NAME_FORMATSIZE];

    UNUSED(query);

    debug("detailsection()");

    if (headers) {
        switch (section) {
        case DNS_SECTION_QUESTION:
            puts("    QUESTIONS:");
            break;
        case DNS_SECTION_ANSWER:
            puts("    ANSWERS:");
            break;
        case DNS_SECTION_AUTHORITY:
            puts("    AUTHORITY RECORDS:");
            break;
        case DNS_SECTION_ADDITIONAL:
            puts("    ADDITIONAL RECORDS:");
            break;
        }
    }

    result = dns_message_firstname(msg, section);
    if (result == ISC_R_NOMORE)
        return (ISC_R_SUCCESS);
    else if (result != ISC_R_SUCCESS)
        return (result);
    for (;;) {
        name = NULL;
        dns_message_currentname(msg, section,
                                &name);
        for (rdataset = ISC_LIST_HEAD(name->list);
                rdataset != NULL;
                rdataset = ISC_LIST_NEXT(rdataset, link)) {
            if (section == DNS_SECTION_QUESTION) {
                dns_name_format(name, namebuf,
                                sizeof(namebuf));
                printf("\t%s, ", namebuf);
                dns_rdatatype_format(rdataset->type,
                                     namebuf,
                                     sizeof(namebuf));
                printf("type = %s, ", namebuf);
                dns_rdataclass_format(rdataset->rdclass,
                                      namebuf,
                                      sizeof(namebuf));
                printf("class = %s\n", namebuf);
            }
            loopresult = dns_rdataset_first(rdataset);
            while (loopresult == ISC_R_SUCCESS) {
                dns_rdataset_current(rdataset, &rdata);

                dns_name_format(name, namebuf,
                                sizeof(namebuf));
                printf("    ->  %s\n", namebuf);

                switch (rdata.type) {
                case dns_rdatatype_soa:
                    printsoa(&rdata);
                    break;
                default:
                    printf("\t");
                    printrdata(&rdata);
                }
                dns_rdata_reset(&rdata);
                printf("\tttl = %u\n", rdataset->ttl);
                loopresult = dns_rdataset_next(rdataset);
            }
        }
        result = dns_message_nextname(msg, section);
        if (result == ISC_R_NOMORE)
            break;
        else if (result != ISC_R_SUCCESS) {
            return (result);
        }
    }
    return (ISC_R_SUCCESS);
}
Esempio n. 10
0
static isc_result_t
printdata(dns_rdataset_t *rdataset, dns_name_t *owner,
	  dns_master_style_t *style)
{
	isc_result_t result = ISC_R_SUCCESS;
	static dns_trust_t trust;
	static isc_boolean_t first = ISC_TRUE;
	isc_buffer_t target;
	isc_region_t r;
	char *t = NULL;
	int len = 2048;

	if (!dns_rdataset_isassociated(rdataset)) {
		char namebuf[DNS_NAME_FORMATSIZE];
		dns_name_format(owner, namebuf, sizeof(namebuf));
		delv_log(ISC_LOG_DEBUG(4),
			  "WARN: empty rdataset %s", namebuf);
		return (ISC_R_SUCCESS);
	}

	if (!showdnssec && rdataset->type == dns_rdatatype_rrsig)
		return (ISC_R_SUCCESS);

	if (first || rdataset->trust != trust) {
		if (!first && showtrust && !short_form)
			putchar('\n');
		print_status(rdataset);
		trust = rdataset->trust;
		first = ISC_FALSE;
	}

	do {
		t = isc_mem_get(mctx, len);
		if (t == NULL)
			return (ISC_R_NOMEMORY);

		isc_buffer_init(&target, t, len);
		if (short_form) {
			dns_rdata_t rdata = DNS_RDATA_INIT;
			for (result = dns_rdataset_first(rdataset);
			     result == ISC_R_SUCCESS;
			     result = dns_rdataset_next(rdataset))
			{
				if ((rdataset->attributes &
				     DNS_RDATASETATTR_NEGATIVE) != 0)
					continue;

				dns_rdataset_current(rdataset, &rdata);
				result = dns_rdata_tofmttext(&rdata,
							     dns_rootname,
							     styleflags, 0,
							     splitwidth, " ",
							     &target);
				if (result != ISC_R_SUCCESS)
					break;

				if (isc_buffer_availablelength(&target) < 1) {
					result = ISC_R_NOSPACE;
					break;
				}

				isc_buffer_putstr(&target, "\n");

				dns_rdata_reset(&rdata);
			}
		} else {
			if ((rdataset->attributes &
			     DNS_RDATASETATTR_NEGATIVE) != 0)
				isc_buffer_putstr(&target, "; ");

			result = dns_master_rdatasettotext(owner, rdataset,
							   style, &target);
		}

		if (result == ISC_R_NOSPACE) {
			isc_mem_put(mctx, t, len);
			len += 1024;
		} else if (result == ISC_R_NOMORE)
			result = ISC_R_SUCCESS;
		else
			CHECK(result);
	} while (result == ISC_R_NOSPACE);

	isc_buffer_usedregion(&target, &r);
	printf("%.*s", (int)r.length, (char *)r.base);

 cleanup:
	if (t != NULL)
		isc_mem_put(mctx, t, len);

	return (ISC_R_SUCCESS);
}
Esempio n. 11
0
static isc_result_t
printsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers,
             dns_section_t section) {
    isc_result_t result, loopresult;
    dns_name_t *name;
    dns_rdataset_t *rdataset = NULL;
    dns_rdata_t rdata = DNS_RDATA_INIT;
    char namebuf[DNS_NAME_FORMATSIZE];

    UNUSED(query);
    UNUSED(headers);

    debug("printsection()");

    result = dns_message_firstname(msg, section);
    if (result == ISC_R_NOMORE)
        return (ISC_R_SUCCESS);
    else if (result != ISC_R_SUCCESS)
        return (result);
    for (;;) {
        name = NULL;
        dns_message_currentname(msg, section,
                                &name);
        for (rdataset = ISC_LIST_HEAD(name->list);
                rdataset != NULL;
                rdataset = ISC_LIST_NEXT(rdataset, link)) {
            loopresult = dns_rdataset_first(rdataset);
            while (loopresult == ISC_R_SUCCESS) {
                dns_rdataset_current(rdataset, &rdata);
                switch (rdata.type) {
                case dns_rdatatype_a:
                    if (section != DNS_SECTION_ANSWER)
                        goto def_short_section;
                    dns_name_format(name, namebuf,
                                    sizeof(namebuf));
                    printf("Name:\t%s\n", namebuf);
                    printa(&rdata);
                    break;
                case dns_rdatatype_soa:
                    dns_name_format(name, namebuf,
                                    sizeof(namebuf));
                    printf("%s\n", namebuf);
                    printsoa(&rdata);
                    break;
                default:
def_short_section:
                    dns_name_format(name, namebuf,
                                    sizeof(namebuf));
                    printf("%s\t", namebuf);
                    printrdata(&rdata);
                    break;
                }
                dns_rdata_reset(&rdata);
                loopresult = dns_rdataset_next(rdataset);
            }
        }
        result = dns_message_nextname(msg, section);
        if (result == ISC_R_NOMORE)
            break;
        else if (result != ISC_R_SUCCESS) {
            return (result);
        }
    }
    return (ISC_R_SUCCESS);
}
Esempio n. 12
0
int
main(int argc, char **argv) {
	char		*algname = NULL, *nametype = NULL, *type = NULL;
	char		*classname = NULL;
	char		*endp;
	dst_key_t	*key = NULL, *oldkey;
	dns_fixedname_t	fname;
	dns_name_t	*name;
	isc_uint16_t	flags = 0, ksk = 0;
	dns_secalg_t	alg;
	isc_boolean_t	null_key = ISC_FALSE;
	isc_mem_t	*mctx = NULL;
	int		ch;
	int		protocol = -1, signatory = 0;
	isc_result_t	ret;
	isc_textregion_t r;
	char		filename[255];
	isc_buffer_t	buf;
	isc_log_t	*log = NULL;
	isc_entropy_t	*ectx = NULL;
	dns_rdataclass_t rdclass;
	int		options = DST_TYPE_PRIVATE | DST_TYPE_PUBLIC;
	char		*label = NULL;

	if (argc == 1)
		usage();

	RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);

	dns_result_register();

	isc_commandline_errprint = ISC_FALSE;

	while ((ch = isc_commandline_parse(argc, argv,
					 "a:c:f:kl:n:p:t:v:h")) != -1)
	{
	    switch (ch) {
		case 'a':
			algname = isc_commandline_argument;
			break;
		case 'c':
			classname = isc_commandline_argument;
			break;
		case 'f':
			if (strcasecmp(isc_commandline_argument, "KSK") == 0)
				ksk = DNS_KEYFLAG_KSK;
			else
				fatal("unknown flag '%s'",
				      isc_commandline_argument);
			break;
		case 'k':
			options |= DST_TYPE_KEY;
			break;
		case 'l':
			label = isc_commandline_argument;
			break;
		case 'n':
			nametype = isc_commandline_argument;
			break;
		case 'p':
			protocol = strtol(isc_commandline_argument, &endp, 10);
			if (*endp != '\0' || protocol < 0 || protocol > 255)
				fatal("-p must be followed by a number "
				      "[0..255]");
			break;
		case 't':
			type = isc_commandline_argument;
			break;
		case 'v':
			verbose = strtol(isc_commandline_argument, &endp, 0);
			if (*endp != '\0')
				fatal("-v must be followed by a number");
			break;

		case '?':
			if (isc_commandline_option != '?')
				fprintf(stderr, "%s: invalid argument -%c\n",
					program, isc_commandline_option);
		case 'h':
			usage();

		default:
			fprintf(stderr, "%s: unhandled option -%c\n",
				program, isc_commandline_option);
			exit(1);
		}
	}

	if (ectx == NULL)
		setup_entropy(mctx, NULL, &ectx);
	ret = dst_lib_init(mctx, ectx,
			   ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY);
	if (ret != ISC_R_SUCCESS)
		fatal("could not initialize dst");

	setup_logging(verbose, mctx, &log);

	if (label == NULL)
		fatal("the key label was not specified");
	if (argc < isc_commandline_index + 1)
		fatal("the key name was not specified");
	if (argc > isc_commandline_index + 1)
		fatal("extraneous arguments");

	if (algname == NULL)
		fatal("no algorithm was specified");
	if (strcasecmp(algname, "RSA") == 0) {
		fprintf(stderr, "The use of RSA (RSAMD5) is not recommended.\n"
				"If you still wish to use RSA (RSAMD5) please "
				"specify \"-a RSAMD5\"\n");
		return (1);
	} else {
		r.base = algname;
		r.length = strlen(algname);
		ret = dns_secalg_fromtext(&alg, &r);
		if (ret != ISC_R_SUCCESS)
			fatal("unknown algorithm %s", algname);
		if (alg == DST_ALG_DH)
			options |= DST_TYPE_KEY;
	}

	if (type != NULL && (options & DST_TYPE_KEY) != 0) {
		if (strcasecmp(type, "NOAUTH") == 0)
			flags |= DNS_KEYTYPE_NOAUTH;
		else if (strcasecmp(type, "NOCONF") == 0)
			flags |= DNS_KEYTYPE_NOCONF;
		else if (strcasecmp(type, "NOAUTHCONF") == 0) {
			flags |= (DNS_KEYTYPE_NOAUTH | DNS_KEYTYPE_NOCONF);
		}
		else if (strcasecmp(type, "AUTHCONF") == 0)
			/* nothing */;
		else
			fatal("invalid type %s", type);
	}

	if (nametype == NULL) {
		if ((options & DST_TYPE_KEY) != 0) /* KEY */
			fatal("no nametype specified");
		flags |= DNS_KEYOWNER_ZONE;	/* DNSKEY */
	} else if (strcasecmp(nametype, "zone") == 0)
		flags |= DNS_KEYOWNER_ZONE;
	else if ((options & DST_TYPE_KEY) != 0)	{ /* KEY */
		if (strcasecmp(nametype, "host") == 0 ||
			 strcasecmp(nametype, "entity") == 0)
			flags |= DNS_KEYOWNER_ENTITY;
		else if (strcasecmp(nametype, "user") == 0)
			flags |= DNS_KEYOWNER_USER;
		else
			fatal("invalid KEY nametype %s", nametype);
	} else if (strcasecmp(nametype, "other") != 0) /* DNSKEY */
		fatal("invalid DNSKEY nametype %s", nametype);

	rdclass = strtoclass(classname);

	if ((options & DST_TYPE_KEY) != 0)  /* KEY */
		flags |= signatory;
	else if ((flags & DNS_KEYOWNER_ZONE) != 0) /* DNSKEY */
		flags |= ksk;

	if (protocol == -1)
		protocol = DNS_KEYPROTO_DNSSEC;
	else if ((options & DST_TYPE_KEY) == 0 &&
		 protocol != DNS_KEYPROTO_DNSSEC)
		fatal("invalid DNSKEY protocol: %d", protocol);

	if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) {
		if ((flags & DNS_KEYFLAG_SIGNATORYMASK) != 0)
			fatal("specified null key with signing authority");
	}

	if ((flags & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE &&
	    alg == DNS_KEYALG_DH)
		fatal("a key with algorithm '%s' cannot be a zone key",
		      algname);

	dns_fixedname_init(&fname);
	name = dns_fixedname_name(&fname);
	isc_buffer_init(&buf, argv[isc_commandline_index],
			strlen(argv[isc_commandline_index]));
	isc_buffer_add(&buf, strlen(argv[isc_commandline_index]));
	ret = dns_name_fromtext(name, &buf, dns_rootname, ISC_FALSE, NULL);
	if (ret != ISC_R_SUCCESS)
		fatal("invalid key name %s: %s", argv[isc_commandline_index],
		      isc_result_totext(ret));

	if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY)
		null_key = ISC_TRUE;

	isc_buffer_init(&buf, filename, sizeof(filename) - 1);

	/* associate the key */
	ret = dst_key_fromlabel(name, alg, flags, protocol,
				rdclass, "", label, NULL, mctx, &key);
	isc_entropy_stopcallbacksources(ectx);

	if (ret != ISC_R_SUCCESS) {
		char namestr[DNS_NAME_FORMATSIZE];
		char algstr[ALG_FORMATSIZE];
		dns_name_format(name, namestr, sizeof(namestr));
		alg_format(alg, algstr, sizeof(algstr));
		fatal("failed to generate key %s/%s: %s\n",
		      namestr, algstr, isc_result_totext(ret));
		exit(-1);
	}

	/*
	 * Try to read a key with the same name, alg and id from disk.
	 * If there is one we must continue generating a new one
	 * unless we were asked to generate a null key, in which
	 * case we return failure.
	 */
	ret = dst_key_fromfile(name, dst_key_id(key), alg,
			       DST_TYPE_PRIVATE, NULL, mctx, &oldkey);
	/* do not overwrite an existing key  */
	if (ret == ISC_R_SUCCESS) {
		isc_buffer_clear(&buf);
		ret = dst_key_buildfilename(key, 0, NULL, &buf);
		fprintf(stderr, "%s: %s already exists\n",
			program, filename);
		dst_key_free(&key);
		exit (1);
	}

	ret = dst_key_tofile(key, options, NULL);
	if (ret != ISC_R_SUCCESS) {
		char keystr[KEY_FORMATSIZE];
		key_format(key, keystr, sizeof(keystr));
		fatal("failed to write key %s: %s\n", keystr,
		      isc_result_totext(ret));
	}

	isc_buffer_clear(&buf);
	ret = dst_key_buildfilename(key, 0, NULL, &buf);
	printf("%s\n", filename);
	dst_key_free(&key);

	cleanup_logging(&log);
	cleanup_entropy(&ectx);
	dst_lib_destroy();
	dns_name_destroy();
	if (verbose > 10)
		isc_mem_stats(mctx, stdout);
	isc_mem_destroy(&mctx);

	return (0);
}
Esempio n. 13
0
void
ns_notify_start(ns_client_t *client) {
	dns_message_t *request = client->message;
	isc_result_t result;
	dns_name_t *zonename;
	dns_rdataset_t *zone_rdataset;
	dns_zone_t *zone = NULL;
	char namebuf[DNS_NAME_FORMATSIZE];
	char tsigbuf[DNS_NAME_FORMATSIZE + sizeof(": TSIG ''")];
	dns_tsigkey_t *tsigkey;

	/*
	 * Interpret the question section.
	 */
	result = dns_message_firstname(request, DNS_SECTION_QUESTION);
	if (result != ISC_R_SUCCESS) {
		notify_log(client, ISC_LOG_NOTICE,
			   "notify question section empty");
		goto formerr;
	}

	/*
	 * The question section must contain exactly one question.
	 */
	zonename = NULL;
	dns_message_currentname(request, DNS_SECTION_QUESTION, &zonename);
	zone_rdataset = ISC_LIST_HEAD(zonename->list);
	if (ISC_LIST_NEXT(zone_rdataset, link) != NULL) {
		notify_log(client, ISC_LOG_NOTICE,
			   "notify question section contains multiple RRs");
		goto formerr;
	}

	/* The zone section must have exactly one name. */
	result = dns_message_nextname(request, DNS_SECTION_ZONE);
	if (result != ISC_R_NOMORE) {
		notify_log(client, ISC_LOG_NOTICE,
			   "notify question section contains multiple RRs");
		goto formerr;
	}

	/* The one rdataset must be an SOA. */
	if (zone_rdataset->type != dns_rdatatype_soa) {
		notify_log(client, ISC_LOG_NOTICE,
			   "notify question section contains no SOA");
		goto formerr;
	}

	tsigkey = dns_message_gettsigkey(request);
	if (tsigkey != NULL) {
		dns_name_format(&tsigkey->name, namebuf, sizeof(namebuf));

		if (tsigkey->generated) {
			char cnamebuf[DNS_NAME_FORMATSIZE];
			dns_name_format(tsigkey->creator, cnamebuf,
					sizeof(cnamebuf));
			snprintf(tsigbuf, sizeof(tsigbuf), ": TSIG '%s' (%s)",
				 namebuf, cnamebuf);
		} else {
			snprintf(tsigbuf, sizeof(tsigbuf), ": TSIG '%s'",
				 namebuf);
		}
	} else
		tsigbuf[0] = '\0';
	dns_name_format(zonename, namebuf, sizeof(namebuf));
	result = dns_zt_find(client->view->zonetable, zonename, 0, NULL,
			     &zone);
	if (result != ISC_R_SUCCESS)
		goto notauth;

	switch (dns_zone_gettype(zone)) {
	case dns_zone_master:
	case dns_zone_slave:
	case dns_zone_stub:	/* Allow dialup passive to work. */
		notify_log(client, ISC_LOG_INFO,
			   "received notify for zone '%s'%s", namebuf, tsigbuf);
		respond(client, dns_zone_notifyreceive(zone,
			ns_client_getsockaddr(client), request));
		break;
	default:
		goto notauth;
	}
	dns_zone_detach(&zone);
	return;

 notauth:
	notify_log(client, ISC_LOG_NOTICE,
		   "received notify for zone '%s'%s: not authoritative",
		   namebuf, tsigbuf);
	result = DNS_R_NOTAUTH;
	goto failure;

 formerr:
	result = DNS_R_FORMERR;

 failure:
	if (zone != NULL)
		dns_zone_detach(&zone);
	respond(client, result);
}
Esempio n. 14
0
isc_result_t
ns_stats_dump(ns_server_t *server, FILE *fp) {
	isc_stdtime_t now;
	isc_result_t result;
	dns_view_t *view;
	dns_zone_t *zone, *next;
	stats_dumparg_t dumparg;

	RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS);

	/* Set common fields */
	dumparg.type = statsformat_file;
	dumparg.arg = fp;

	isc_stdtime_get(&now);
	fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now);

	fprintf(fp, "++ Incoming Requests ++\n");
	dns_opcodestats_dump(server->opcodestats, opcodestat_dump, &dumparg, 0);

	fprintf(fp, "++ Incoming Queries ++\n");
	dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump,
				&dumparg, 0);

	fprintf(fp, "++ Outgoing Queries ++\n");
	for (view = ISC_LIST_HEAD(server->viewlist);
	     view != NULL;
	     view = ISC_LIST_NEXT(view, link)) {
		if (view->resquerystats == NULL)
			continue;
		if (strcmp(view->name, "_default") == 0)
			fprintf(fp, "[View: default]\n");
		else
			fprintf(fp, "[View: %s]\n", view->name);
		dns_rdatatypestats_dump(view->resquerystats, rdtypestat_dump,
					&dumparg, 0);
	}

	fprintf(fp, "++ Name Server Statistics ++\n");
	dumparg.desc = nsstats_desc;
	dumparg.ncounters = dns_nsstatscounter_max;
	dns_generalstats_dump(server->nsstats, generalstat_dump, &dumparg, 0);
	fprintf(fp, "++ Zone Maintenance Statistics ++\n");
	dumparg.desc = zonestats_desc;
	dumparg.ncounters = dns_zonestatscounter_max;
	dns_generalstats_dump(server->zonestats, generalstat_dump, &dumparg, 0);

	fprintf(fp, "++ Resolver Statistics ++\n");
	fprintf(fp, "[Common]\n");
	dumparg.desc = resstats_desc;
	dumparg.ncounters = dns_resstatscounter_max;
	dns_generalstats_dump(server->resolverstats, generalstat_dump, &dumparg,
			      0);
	for (view = ISC_LIST_HEAD(server->viewlist);
	     view != NULL;
	     view = ISC_LIST_NEXT(view, link)) {
		if (view->resstats == NULL)
			continue;
		if (strcmp(view->name, "_default") == 0)
			fprintf(fp, "[View: default]\n");
		else
			fprintf(fp, "[View: %s]\n", view->name);
		dns_generalstats_dump(view->resstats, generalstat_dump,
				      &dumparg, 0);
	}

	fprintf(fp, "++ Cache DB RRsets ++\n");
	for (view = ISC_LIST_HEAD(server->viewlist);
	     view != NULL;
	     view = ISC_LIST_NEXT(view, link)) {
		dns_stats_t *cachestats;

		cachestats = dns_db_getrrsetstats(view->cachedb);
		if (cachestats == NULL)
			continue;
		if (strcmp(view->name, "_default") == 0)
			fprintf(fp, "[View: default]\n");
		else
			fprintf(fp, "[View: %s]\n", view->name);
		dns_rdatasetstats_dump(cachestats, rdatasetstats_dump, &dumparg,
				       0);
	}

	fprintf(fp, "++ Per Zone Query Statistics ++\n");
	zone = NULL;
	for (result = dns_zone_first(server->zonemgr, &zone);
	     result == ISC_R_SUCCESS;
	     next = NULL, result = dns_zone_next(zone, &next), zone = next)
	{
		dns_stats_t *zonestats = dns_zone_getrequeststats(zone);
		if (zonestats != NULL) {
			char zonename[DNS_NAME_FORMATSIZE];

			dns_name_format(dns_zone_getorigin(zone),
					zonename, sizeof(zonename));
			view = dns_zone_getview(zone);

			fprintf(fp, "[%s", zonename);
			if (strcmp(view->name, "_default") != 0)
				fprintf(fp, " (view: %s)", view->name);
			fprintf(fp, "]\n");

			dumparg.desc = nsstats_desc;
			dumparg.ncounters = dns_nsstatscounter_max;
			dns_generalstats_dump(zonestats, generalstat_dump,
					      &dumparg, 0);
		}
	}

	fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now);

	return (ISC_R_SUCCESS);	/* this function currently always succeeds */
}
Esempio n. 15
0
void
dns_root_checkhints(dns_view_t *view, dns_db_t *hints, dns_db_t *db) {
	isc_result_t result;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	dns_rdata_ns_t ns;
	dns_rdataset_t hintns, rootns;
	const char *viewname = "", *sep = "";
	isc_stdtime_t now;
	dns_name_t *name;
	dns_fixedname_t fixed;

	REQUIRE(hints != NULL);
	REQUIRE(db != NULL);
	REQUIRE(view != NULL);

	isc_stdtime_get(&now);

	if (strcmp(view->name, "_bind") != 0 &&
	    strcmp(view->name, "_default") != 0) {
		viewname = view->name;
		sep = ": view ";
	}

	dns_rdataset_init(&hintns);
	dns_rdataset_init(&rootns);
	dns_fixedname_init(&fixed);
	name = dns_fixedname_name(&fixed);

	result = dns_db_find(hints, dns_rootname, NULL, dns_rdatatype_ns, 0,
			     now, NULL, name, &hintns, NULL);
	if (result != ISC_R_SUCCESS) {
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
			      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
			      "checkhints%s%s: unable to get root NS rrset "
			      "from hints: %s", sep, viewname,
			      dns_result_totext(result));
		goto cleanup;
	}

	result = dns_db_find(db, dns_rootname, NULL, dns_rdatatype_ns, 0,
			     now, NULL, name, &rootns, NULL);
	if (result != ISC_R_SUCCESS) {
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
			      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
			      "checkhints%s%s: unable to get root NS rrset "
			      "from cache: %s", sep, viewname,
			      dns_result_totext(result));
		goto cleanup;
	}

	/*
	 * Look for missing root NS names.
	 */
	result = dns_rdataset_first(&rootns);
	while (result == ISC_R_SUCCESS) {
		dns_rdataset_current(&rootns, &rdata);
		result = dns_rdata_tostruct(&rdata, &ns, NULL);
		RUNTIME_CHECK(result == ISC_R_SUCCESS);
		result = in_rootns(&hintns, &ns.name);
		if (result != ISC_R_SUCCESS) {
			char namebuf[DNS_NAME_FORMATSIZE];
			/* missing from hints */
			dns_name_format(&ns.name, namebuf, sizeof(namebuf));
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
				      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
				      "checkhints%s%s: unable to find root "
				      "NS '%s' in hints", sep, viewname,
				      namebuf);
		} else
			check_address_records(view, hints, db, &ns.name, now);
		dns_rdata_reset(&rdata);
		result = dns_rdataset_next(&rootns);
	}
	if (result != ISC_R_NOMORE) {
		goto cleanup;
	}

	/*
	 * Look for extra root NS names.
	 */
	result = dns_rdataset_first(&hintns);
	while (result == ISC_R_SUCCESS) {
		dns_rdataset_current(&hintns, &rdata);
		result = dns_rdata_tostruct(&rdata, &ns, NULL);
		RUNTIME_CHECK(result == ISC_R_SUCCESS);
		result = in_rootns(&rootns, &ns.name);
		if (result != ISC_R_SUCCESS) {
			char namebuf[DNS_NAME_FORMATSIZE];
			/* extra entry in hints */
			dns_name_format(&ns.name, namebuf, sizeof(namebuf));
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
				      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
				      "checkhints%s%s: extra NS '%s' in hints",
				      sep, viewname, namebuf);
		}
		dns_rdata_reset(&rdata);
		result = dns_rdataset_next(&hintns);
	}
	if (result != ISC_R_NOMORE) {
		goto cleanup;
	}

 cleanup:
	if (dns_rdataset_isassociated(&rootns))
		dns_rdataset_disassociate(&rootns);
	if (dns_rdataset_isassociated(&hintns))
		dns_rdataset_disassociate(&hintns);
}