Example #1
0
static void
parse_rdata(isc_mem_t *mctx, char **cmdlinep, dns_rdataclass_t rdataclass,
	    dns_rdatatype_t rdatatype, dns_rdata_t *rdata)
{
	char *cmdline = *cmdlinep;
	isc_buffer_t source, *buf = NULL, *newbuf = NULL;
	isc_region_t r;
	isc_lex_t *lex = NULL;
	dns_rdatacallbacks_t callbacks;
	isc_result_t result;

	while (cmdline != NULL && *cmdline != 0 &&
	       isspace((unsigned char)*cmdline))
		cmdline++;

	if (cmdline != NULL && *cmdline != 0) {
		dns_rdatacallbacks_init(&callbacks);
		result = isc_lex_create(mctx, strlen(cmdline), &lex);
		check_result(result, "isc_lex_create");
		isc_buffer_init(&source, cmdline, strlen(cmdline));
		isc_buffer_add(&source, strlen(cmdline));
		result = isc_lex_openbuffer(lex, &source);
		check_result(result, "isc_lex_openbuffer");
		result = isc_buffer_allocate(mctx, &buf, MAXWIRE);
		check_result(result, "isc_buffer_allocate");
		result = dns_rdata_fromtext(rdata, rdataclass, rdatatype, lex,
					    dns_rootname, 0, mctx, buf,
					    &callbacks);
		isc_lex_destroy(&lex);
		if (result == ISC_R_SUCCESS) {
			isc_buffer_usedregion(buf, &r);
			result = isc_buffer_allocate(mctx, &newbuf, r.length);
			check_result(result, "isc_buffer_allocate");
			isc_buffer_putmem(newbuf, r.base, r.length);
			isc_buffer_usedregion(newbuf, &r);
			dns_rdata_reset(rdata);
			dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r);
			isc_buffer_free(&buf);
			ISC_LIST_APPEND(usedbuffers, newbuf, link);
		} else {
			fprintf(stderr, "invalid rdata format: %s\n",
				isc_result_totext(result));
			isc_buffer_free(&buf);
			exit(1);
		}
	} else {
		rdata->flags = DNS_RDATA_UPDATE;
	}
	*cmdlinep = cmdline;
}
Example #2
0
static void
print_hex(dns_dtdata_t *dt) {
	isc_buffer_t *b = NULL;
	isc_result_t result;
	size_t textlen;

	if (dt->msg == NULL) {
		return;
	}

	textlen = (dt->msgdata.length * 2) + 1;
	isc_buffer_allocate(mctx, &b, textlen);
	if (b == NULL) {
		fatal("out of memory");
	}

	result = isc_hex_totext(&dt->msgdata, 0, "", b);
	CHECKM(result, "isc_hex_totext");

	printf("%.*s\n", (int) isc_buffer_usedlength(b),
	       (char *) isc_buffer_base(b));

 cleanup:
	if (b != NULL)
		isc_buffer_free(&b);
}
Example #3
0
static void
printrdata(dns_rdata_t *rdata) {
	isc_result_t result;
	isc_buffer_t *b = NULL;
	unsigned int size = 1024;
	isc_boolean_t done = ISC_FALSE;

	if (rdata->type < N_KNOWN_RRTYPES)
		printf("%s", rtypetext[rdata->type]);
	else
		printf("rdata_%d = ", rdata->type);

	while (!done) {
		result = isc_buffer_allocate(mctx, &b, size);
		if (result != ISC_R_SUCCESS)
			check_result(result, "isc_buffer_allocate");
		result = dns_rdata_totext(rdata, NULL, b);
		if (result == ISC_R_SUCCESS) {
			printf("%.*s\n", (int)isc_buffer_usedlength(b),
			       (char *)isc_buffer_base(b));
			done = ISC_TRUE;
		} else if (result != ISC_R_NOSPACE)
			check_result(result, "dns_rdata_totext");
		isc_buffer_free(&b);
		size *= 2;
	}
}
Example #4
0
isc_result_t
dns_keytable_dump(dns_keytable_t *keytable, FILE *fp) {
	isc_result_t result;
	isc_buffer_t *text = NULL;

	REQUIRE(VALID_KEYTABLE(keytable));
	REQUIRE(fp != NULL);

	result = isc_buffer_allocate(keytable->mctx, &text, 4096);
	if (result != ISC_R_SUCCESS)
		return (result);

	result = dns_keytable_totext(keytable, &text);

	if (isc_buffer_usedlength(text) != 0) {
		(void) putstr(&text, "\n");
	} else if (result == ISC_R_SUCCESS)
		(void) putstr(&text, "none");
	else {
		(void) putstr(&text, "could not dump key table: ");
		(void) putstr(&text, isc_result_totext(result));
	}

	fprintf(fp, "%.*s", (int) isc_buffer_usedlength(text),
		(char *) isc_buffer_base(text));

	isc_buffer_free(&text);
	return (result);
}
Example #5
0
/**
 * Generate dummy string which looks like list of forwarders
 * with list_len elements. This string might be fed into cfg parser.
 *
 * Caller has to deallocate resulting dummy_string.
 */
static isc_result_t
fwd_list_gen_dummy_config_string(isc_mem_t *mctx, size_t list_len,
				 isc_buffer_t **dummy_string) {
	isc_result_t result;
	const char prefix[] = "{ ";
	const char suffix[] = "} // dummy string, please ignore";
	const char fill[] = "127.0.0.1; ";
	size_t target_size = sizeof(prefix) \
			     + list_len*sizeof(fill)
			     + sizeof(suffix)
			     + 1; /* \0 */
	isc_buffer_t *output = NULL;

	REQUIRE(dummy_string != NULL && *dummy_string == NULL);

	CHECK(isc_buffer_allocate(mctx, &output, target_size));
	isc_buffer_putstr(output, prefix);
	for (size_t i = 0; i < list_len; i++)
		isc_buffer_putstr(output, fill);
	isc_buffer_putstr(output, suffix);
	isc_buffer_putuint8(output, '\0');
	*dummy_string = output;

cleanup:
	if (result != ISC_R_SUCCESS && output != NULL)
		isc_buffer_free(&output);

	return result;
}
Example #6
0
static isc_result_t
add_rdata_to_list(dns_message_t *msg, dns_name_t *name, dns_rdata_t *rdata,
		isc_uint32_t ttl, dns_namelist_t *namelist)
{
	isc_result_t result;
	isc_region_t r, newr;
	dns_rdata_t *newrdata = NULL;
	dns_name_t *newname = NULL;
	dns_rdatalist_t *newlist = NULL;
	dns_rdataset_t *newset = NULL;
	isc_buffer_t *tmprdatabuf = NULL;

	RETERR(dns_message_gettemprdata(msg, &newrdata));

	dns_rdata_toregion(rdata, &r);
	RETERR(isc_buffer_allocate(msg->mctx, &tmprdatabuf, r.length));
	isc_buffer_availableregion(tmprdatabuf, &newr);
	memcpy(newr.base, r.base, r.length);
	dns_rdata_fromregion(newrdata, rdata->rdclass, rdata->type, &newr);
	dns_message_takebuffer(msg, &tmprdatabuf);

	RETERR(dns_message_gettempname(msg, &newname));
	dns_name_init(newname, NULL);
	RETERR(dns_name_dup(name, msg->mctx, newname));

	RETERR(dns_message_gettemprdatalist(msg, &newlist));
	newlist->rdclass = newrdata->rdclass;
	newlist->type = newrdata->type;
	newlist->covers = 0;
	newlist->ttl = ttl;
	ISC_LIST_INIT(newlist->rdata);
	ISC_LIST_APPEND(newlist->rdata, newrdata, link);

	RETERR(dns_message_gettemprdataset(msg, &newset));
	dns_rdataset_init(newset);
	RETERR(dns_rdatalist_tordataset(newlist, newset));

	ISC_LIST_INIT(newname->list);
	ISC_LIST_APPEND(newname->list, newset, link);

	ISC_LIST_APPEND(*namelist, newname, link);

	return (ISC_R_SUCCESS);

 failure:
	if (newrdata != NULL) {
		if (ISC_LINK_LINKED(newrdata, link))
			ISC_LIST_UNLINK(newlist->rdata, newrdata, link);
		dns_message_puttemprdata(msg, &newrdata);
	}
	if (newname != NULL)
		dns_message_puttempname(msg, &newname);
	if (newset != NULL) {
		dns_rdataset_disassociate(newset);
		dns_message_puttemprdataset(msg, &newset);
	}
	if (newlist != NULL)
		dns_message_puttemprdatalist(msg, &newlist);
	return (result);
}
Example #7
0
isc_result_t
dst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx,
		   dst_key_t **keyp, isc_region_t *intoken)
{
	dst_key_t *key;
	isc_result_t result;

	REQUIRE(gssctx != NULL);
	REQUIRE(keyp != NULL && *keyp == NULL);

	key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC,
			     0, dns_rdataclass_in, 0, mctx);
	if (key == NULL)
		return (ISC_R_NOMEMORY);

	if (intoken != NULL) {
		/*
		 * Keep the token for use by external ssu rules. They may need
		 * to examine the PAC in the kerberos ticket.
		 */
		RETERR(isc_buffer_allocate(key->mctx, &key->key_tkeytoken,
		       intoken->length));
		RETERR(isc_buffer_copyregion(key->key_tkeytoken, intoken));
	}

	key->keydata.gssctx = gssctx;
	*keyp = key;
	result = ISC_R_SUCCESS;
out:
	return result;
}
Example #8
0
/**
 * Generate list of all values as bracketed list.
 * This string might be fed into cfg parser.
 *
 * Caller has to deallocate resulting output buffer.
 */
isc_result_t
fwd_print_bracketed_values_buf(isc_mem_t *mctx, ldap_valuelist_t *values,
			      isc_buffer_t **string) {
	isc_result_t result;
	ldap_value_t *value;
	const char prefix[] = "{ ";
	const char suffix[] = "}";
	isc_buffer_t tmp_buf; /* hack: only the base buffer is allocated */

	REQUIRE(string != NULL && *string == NULL);

	isc_buffer_initnull(&tmp_buf);
	tmp_buf.mctx = mctx;

	buffer_append_str(&tmp_buf, prefix, 2);
	for (value = HEAD(*values);
	     value != NULL && value->value != NULL;
	     value = NEXT(value, link)) {
		buffer_append_str(&tmp_buf, value->value, strlen(value->value));
		buffer_append_str(&tmp_buf, "; ", 2);
	}
	buffer_append_str(&tmp_buf, suffix, 2);

	/* create and copy string from tmp to output buffer */
	CHECK(isc_buffer_allocate(mctx, string, tmp_buf.used));
	isc_buffer_putmem(*string, isc_buffer_base(&tmp_buf), tmp_buf.used);

cleanup:
	if (tmp_buf.base != NULL)
		isc_mem_put(mctx, tmp_buf.base, tmp_buf.length);
	return result;
}
Example #9
0
static isc_result_t
gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) {
	gssapi_ctx_t *ctx = dctx->opaque;
	isc_buffer_t *newbuffer = NULL;
	isc_region_t r;
	unsigned int length;
	isc_result_t result;

	result = isc_buffer_copyregion(ctx->buffer, data);
	if (result == ISC_R_SUCCESS)
		return (ISC_R_SUCCESS);

	length = isc_buffer_length(ctx->buffer) + data->length + BUFFER_EXTRA;

	result = isc_buffer_allocate(dctx->mctx, &newbuffer, length);
	if (result != ISC_R_SUCCESS)
		return (result);

	isc_buffer_usedregion(ctx->buffer, &r);
	(void) isc_buffer_copyregion(newbuffer, &r);
	(void) isc_buffer_copyregion(newbuffer, data);

	isc_buffer_free(&ctx->buffer);
	ctx->buffer = newbuffer;

	return (ISC_R_SUCCESS);
}
Example #10
0
static void
print_dtdata(dns_dtdata_t *dt) {
	isc_result_t result;
	isc_buffer_t *b = NULL;

	isc_buffer_allocate(mctx, &b, 2048);
	if (b == NULL)
		fatal("out of memory");

	CHECKM(dns_dt_datatotext(dt, &b), "dns_dt_datatotext");
	printf("%.*s\n", (int) isc_buffer_usedlength(b),
	       (char *) isc_buffer_base(b));

 cleanup:
	if (b != NULL)
		isc_buffer_free(&b);
}
Example #11
0
isc_result_t
isc_buffer_dup(isc_mem_t *mctx, isc_buffer_t **dstp, const isc_buffer_t *src) {
	isc_buffer_t *dst = NULL;
	isc_region_t region;
	isc_result_t result;

	REQUIRE(dstp != NULL && *dstp == NULL);
	REQUIRE(ISC_BUFFER_VALID(src));

	isc_buffer_usedregion(src, &region);

	result = isc_buffer_allocate(mctx, &dst, region.length);
	if (result != ISC_R_SUCCESS)
		return (result);

	result = isc_buffer_copyregion(dst, &region);
	RUNTIME_CHECK(result == ISC_R_SUCCESS); /* NOSPACE is impossible */
	*dstp = dst;
	return (ISC_R_SUCCESS);
}
Example #12
0
static void
build_name_from_str(const char *namestr, dns_fixedname_t *fname) {
	size_t length;
	isc_buffer_t *b = NULL;
	isc_result_t result;
	dns_name_t *name;

	length = strlen(namestr);

	result = isc_buffer_allocate(mctx, &b, length);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
	isc_buffer_putmem(b, (const unsigned char *) namestr, length);

	dns_fixedname_init(fname);
	name = dns_fixedname_name(fname);
	ATF_REQUIRE(name != NULL);
	result = dns_name_fromtext(name, b, dns_rootname, 0, NULL);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	isc_buffer_free(&b);
}
Example #13
0
static isc_result_t
gssapi_createctx(dst_key_t *key, dst_context_t *dctx) {
	gssapi_ctx_t *ctx;
	isc_result_t result;

	UNUSED(key);

	ctx = isc_mem_get(dctx->mctx, sizeof(gssapi_ctx_t));
	if (ctx == NULL)
		return (ISC_R_NOMEMORY);
	ctx->buffer = NULL;
	result = isc_buffer_allocate(dctx->mctx, &ctx->buffer,
				     INITIAL_BUFFER_SIZE);
	if (result != ISC_R_SUCCESS) {
		isc_mem_put(dctx->mctx, ctx, sizeof(gssapi_ctx_t));
		return (result);
	}
	ctx->context_id = key->opaque;
	dctx->opaque = ctx;
	return (ISC_R_SUCCESS);
}
/*%
 * Allocate a temporary "context" for use in gathering data for signing
 * or verifying.
 */
static isc_result_t
gssapi_create_signverify_ctx(dst_key_t *key, dst_context_t *dctx) {
	dst_gssapi_signverifyctx_t *ctx;
	isc_result_t result;

	UNUSED(key);

	ctx = isc_mem_get(dctx->mctx, sizeof(dst_gssapi_signverifyctx_t));
	if (ctx == NULL)
		return (ISC_R_NOMEMORY);
	ctx->buffer = NULL;
	result = isc_buffer_allocate(dctx->mctx, &ctx->buffer,
				     INITIAL_BUFFER_SIZE);
	if (result != ISC_R_SUCCESS) {
		isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t));
		return (result);
	}

	dctx->ctxdata.gssctx = ctx;

	return (ISC_R_SUCCESS);
}
Example #15
0
static void
print_packet(dns_dtdata_t *dt, const dns_master_style_t *style) {
	isc_buffer_t *b = NULL;
	isc_result_t result;

	if (dt->msg != NULL) {
		size_t textlen = 2048;

		isc_buffer_allocate(mctx, &b, textlen);
		if (b == NULL)
			fatal("out of memory");

		for (;;) {
			isc_buffer_reserve(&b, textlen);
			if (b == NULL)
				fatal("out of memory");

			result = dns_message_totext(dt->msg, style, 0, b);
			if (result == ISC_R_NOSPACE) {
				textlen *= 2;
				continue;
			} else if (result == ISC_R_SUCCESS) {
				printf("%.*s",
				       (int) isc_buffer_usedlength(b),
				       (char *) isc_buffer_base(b));
				isc_buffer_free(&b);
			} else {
				isc_buffer_free(&b);
				CHECKM(result, "dns_message_totext");
			}
			break;
		}
	}

 cleanup:
	if (b != NULL)
		isc_buffer_free(&b);
}
static isc_result_t
gssapi_restore(dst_key_t *key, const char *keystr) {
	OM_uint32 major, minor;
	unsigned int len;
	isc_buffer_t *b = NULL;
	isc_region_t r;
	gss_buffer_desc gssbuffer;
	isc_result_t result;

	len = strlen(keystr);
	if ((len % 4) != 0U)
		return (ISC_R_BADBASE64);

	len = (len / 4) * 3;

	result = isc_buffer_allocate(key->mctx, &b, len);
	if (result != ISC_R_SUCCESS)
		return (result);

	result = isc_base64_decodestring(keystr, b);
	if (result != ISC_R_SUCCESS) {
		isc_buffer_free(&b);
		return (result);
	}

	isc_buffer_remainingregion(b, &r);
	REGION_TO_GBUFFER(r, gssbuffer);
	major = gss_import_sec_context(&minor, &gssbuffer,
				       &key->keydata.gssctx);
	if (major != GSS_S_COMPLETE) {
		isc_buffer_free(&b);
		return (ISC_R_FAILURE);
	}

	isc_buffer_free(&b);
	return (ISC_R_SUCCESS);
}
Example #17
0
static isc_result_t
add_tsig(dst_context_t *tsigctx, dns_tsigkey_t *key, isc_buffer_t *target) {
	dns_compress_t cctx;
	dns_rdata_any_tsig_t tsig;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	dns_rdatalist_t rdatalist;
	dns_rdataset_t rdataset;
	isc_buffer_t *dynbuf = NULL;
	isc_buffer_t databuf;
	isc_buffer_t sigbuf;
	isc_region_t r;
	isc_result_t result = ISC_R_SUCCESS;
	isc_stdtime_t now;
	unsigned char tsigbuf[1024];
	unsigned int count;
	unsigned int sigsize;
	isc_boolean_t invalidate_ctx = ISC_FALSE;

	CHECK(dns_compress_init(&cctx, -1, mctx));
	invalidate_ctx = ISC_TRUE;

	memset(&tsig, 0, sizeof(tsig));
	       tsig.common.rdclass = dns_rdataclass_any;
	tsig.common.rdtype = dns_rdatatype_tsig;
	ISC_LINK_INIT(&tsig.common, link);
	dns_name_init(&tsig.algorithm, NULL);
	dns_name_clone(key->algorithm, &tsig.algorithm);

	isc_stdtime_get(&now);
	tsig.timesigned = now;
	tsig.fudge = DNS_TSIG_FUDGE;
	tsig.originalid = 50;
	tsig.error = dns_rcode_noerror;
	tsig.otherlen = 0;
	tsig.other = NULL;

	isc_buffer_init(&databuf, tsigbuf, sizeof(tsigbuf));
	isc_buffer_putuint48(&databuf, tsig.timesigned);
	isc_buffer_putuint16(&databuf, tsig.fudge);
	isc_buffer_usedregion(&databuf, &r);
	CHECK(dst_context_adddata(tsigctx, &r));

	CHECK(dst_key_sigsize(key->key, &sigsize));
	tsig.signature = (unsigned char *) isc_mem_get(mctx, sigsize);
	if (tsig.signature == NULL)
		CHECK(ISC_R_NOMEMORY);
	isc_buffer_init(&sigbuf, tsig.signature, sigsize);
	CHECK(dst_context_sign(tsigctx, &sigbuf));
	tsig.siglen = isc_buffer_usedlength(&sigbuf);

	CHECK(isc_buffer_allocate(mctx, &dynbuf, 512));
	CHECK(dns_rdata_fromstruct(&rdata, dns_rdataclass_any,
				   dns_rdatatype_tsig, &tsig, dynbuf));
	dns_rdatalist_init(&rdatalist);
	rdatalist.rdclass = dns_rdataclass_any;
	rdatalist.type = dns_rdatatype_tsig;
	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
	dns_rdataset_init(&rdataset);
	CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
	CHECK(dns_rdataset_towire(&rdataset, &key->name, &cctx,
				  target, 0, &count));

	/*
	 * Fixup additional record count.
	 */
	((unsigned char*)target->base)[11]++;
	if (((unsigned char*)target->base)[11] == 0)
		((unsigned char*)target->base)[10]++;
 cleanup:
	if (tsig.signature != NULL)
		isc_mem_put(mctx, tsig.signature, sigsize);
	if (dynbuf != NULL)
		isc_buffer_free(&dynbuf);
	if (invalidate_ctx)
		dns_compress_invalidate(&cctx);

	return (result);
}
Example #18
0
static void
control_recvmessage(isc_task_t *task, isc_event_t *event) {
	controlconnection_t *conn;
	controllistener_t *listener;
	controlkey_t *key;
	isccc_sexpr_t *request = NULL;
	isccc_sexpr_t *response = NULL;
	isc_uint32_t algorithm;
	isccc_region_t secret;
	isc_stdtime_t now;
	isc_buffer_t b;
	isc_region_t r;
	isc_buffer_t *text;
	isc_result_t result;
	isc_result_t eresult;
	isccc_sexpr_t *_ctrl;
	isccc_time_t sent;
	isccc_time_t exp;
	isc_uint32_t nonce;
	isccc_sexpr_t *data;

	REQUIRE(event->ev_type == ISCCC_EVENT_CCMSG);

	conn = event->ev_arg;
	listener = conn->listener;
	algorithm = DST_ALG_UNKNOWN;
	secret.rstart = NULL;
	text = NULL;

	/* Is the server shutting down? */
	if (listener->controls->shuttingdown)
		goto cleanup;

	if (conn->ccmsg.result != ISC_R_SUCCESS) {
		if (conn->ccmsg.result != ISC_R_CANCELED &&
		    conn->ccmsg.result != ISC_R_EOF)
			log_invalid(&conn->ccmsg, conn->ccmsg.result);
		goto cleanup;
	}

	request = NULL;

	for (key = ISC_LIST_HEAD(listener->keys);
	     key != NULL;
	     key = ISC_LIST_NEXT(key, link))
	{
		isccc_region_t ccregion;

		ccregion.rstart = isc_buffer_base(&conn->ccmsg.buffer);
		ccregion.rend = isc_buffer_used(&conn->ccmsg.buffer);
		secret.rstart = isc_mem_get(listener->mctx, key->secret.length);
		if (secret.rstart == NULL)
			goto cleanup;
		memmove(secret.rstart, key->secret.base, key->secret.length);
		secret.rend = secret.rstart + key->secret.length;
		algorithm = key->algorithm;
		result = isccc_cc_fromwire(&ccregion, &request,
					   algorithm, &secret);
		if (result == ISC_R_SUCCESS)
			break;
		isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
		if (result != ISCCC_R_BADAUTH) {
			log_invalid(&conn->ccmsg, result);
			goto cleanup;
		}
	}

	if (key == NULL) {
		log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH);
		goto cleanup;
	}

	/* We shouldn't be getting a reply. */
	if (isccc_cc_isreply(request)) {
		log_invalid(&conn->ccmsg, ISC_R_FAILURE);
		goto cleanup_request;
	}

	isc_stdtime_get(&now);

	/*
	 * Limit exposure to replay attacks.
	 */
	_ctrl = isccc_alist_lookup(request, "_ctrl");
	if (_ctrl == NULL) {
		log_invalid(&conn->ccmsg, ISC_R_FAILURE);
		goto cleanup_request;
	}

	if (isccc_cc_lookupuint32(_ctrl, "_tim", &sent) == ISC_R_SUCCESS) {
		if ((sent + CLOCKSKEW) < now || (sent - CLOCKSKEW) > now) {
			log_invalid(&conn->ccmsg, ISCCC_R_CLOCKSKEW);
			goto cleanup_request;
		}
	} else {
		log_invalid(&conn->ccmsg, ISC_R_FAILURE);
		goto cleanup_request;
	}

	/*
	 * Expire messages that are too old.
	 */
	if (isccc_cc_lookupuint32(_ctrl, "_exp", &exp) == ISC_R_SUCCESS &&
	    now > exp) {
		log_invalid(&conn->ccmsg, ISCCC_R_EXPIRED);
		goto cleanup_request;
	}

	/*
	 * Duplicate suppression (required for UDP).
	 */
	isccc_cc_cleansymtab(listener->controls->symtab, now);
	result = isccc_cc_checkdup(listener->controls->symtab, request, now);
	if (result != ISC_R_SUCCESS) {
		if (result == ISC_R_EXISTS)
			result = ISCCC_R_DUPLICATE;
		log_invalid(&conn->ccmsg, result);
		goto cleanup_request;
	}

	if (conn->nonce != 0 &&
	    (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS ||
	     conn->nonce != nonce)) {
		log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH);
		goto cleanup_request;
	}

	result = isc_buffer_allocate(listener->mctx, &text, 2 * 2048);
	if (result != ISC_R_SUCCESS)
		goto cleanup_request;

	/*
	 * Establish nonce.
	 */
	if (conn->nonce == 0) {
		while (conn->nonce == 0)
			isc_random_get(&conn->nonce);
		eresult = ISC_R_SUCCESS;
	} else
		eresult = ns_control_docommand(request, &text);

	result = isccc_cc_createresponse(request, now, now + 60, &response);
	if (result != ISC_R_SUCCESS)
		goto cleanup_request;

	data = isccc_alist_lookup(response, "_data");
	if (data != NULL) {
		if (isccc_cc_defineuint32(data, "result", eresult) == NULL)
			goto cleanup_response;
	}

	if (eresult != ISC_R_SUCCESS) {
		if (data != NULL) {
			const char *estr = isc_result_totext(eresult);
			if (isccc_cc_definestring(data, "err", estr) == NULL)
				goto cleanup_response;
		}
	}

	if (isc_buffer_usedlength(text) > 0) {
		if (data != NULL) {
			char *str = (char *)isc_buffer_base(text);
			if (isccc_cc_definestring(data, "text", str) == NULL)
				goto cleanup_response;
		}
	}

	_ctrl = isccc_alist_lookup(response, "_ctrl");
	if (_ctrl == NULL ||
	    isccc_cc_defineuint32(_ctrl, "_nonce", conn->nonce) == NULL)
		goto cleanup_response;

	if (conn->buffer == NULL) {
		result = isc_buffer_allocate(listener->mctx,
					     &conn->buffer, 2 * 2048);
		if (result != ISC_R_SUCCESS)
			goto cleanup_response;
	}

	isc_buffer_clear(conn->buffer);
	/* Skip the length field (4 bytes) */
	isc_buffer_add(conn->buffer, 4);

	result = isccc_cc_towire(response, &conn->buffer, algorithm, &secret);
	if (result != ISC_R_SUCCESS)
		goto cleanup_response;

	isc_buffer_init(&b, conn->buffer->base, 4);
	isc_buffer_putuint32(&b, conn->buffer->used - 4);

	r.base = conn->buffer->base;
	r.length = conn->buffer->used;

	result = isc_socket_send(conn->sock, &r, task, control_senddone, conn);
	if (result != ISC_R_SUCCESS)
		goto cleanup_response;
	conn->sending = ISC_TRUE;

	isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
	isccc_sexpr_free(&request);
	isccc_sexpr_free(&response);
	isc_buffer_free(&text);
	return;

 cleanup_response:
	isccc_sexpr_free(&response);

 cleanup_request:
	isccc_sexpr_free(&request);
	isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
	if (text != NULL)
		isc_buffer_free(&text);

 cleanup:
	isc_socket_detach(&conn->sock);
	isccc_ccmsg_invalidate(&conn->ccmsg);
	conn->ccmsg_valid = ISC_FALSE;
	maybe_free_connection(conn);
	maybe_free_listener(listener);
}
Example #19
0
int
main(int argc, char *argv[]) {
	int ch, i, gai_error;
	struct addrinfo hints, *res;
	isc_textregion_t tr;
	dns_client_t *client = NULL;
	isc_result_t result;
	isc_sockaddr_t sa;
	dns_message_t *qmessage, *rmessage;
	dns_rdatatype_t type = dns_rdatatype_a;
	isc_buffer_t *outputbuf;

	while ((ch = getopt(argc, argv, "t:")) != -1) {
		switch (ch) {
		case 't':
			tr.base = optarg;
			tr.length = strlen(optarg);
			result = dns_rdatatype_fromtext(&type, &tr);
			if (result != ISC_R_SUCCESS) {
				fprintf(stderr,
					"invalid RRtype: %s\n", optarg);
				exit(1);
			}
			break;
		default:
			usage();
		}
	}

	argc -= optind;
	argv += optind;
	if (argc < 2)
		usage();

	isc_lib_register();
	result = dns_lib_init();
	if (result != ISC_R_SUCCESS) {
		fprintf(stderr, "dns_lib_init failed: %d\n", result);
		exit(1);
	}

	result = dns_client_create(&client, 0);
	if (result != ISC_R_SUCCESS) {
		fprintf(stderr, "dns_client_create failed: %d\n", result);
		exit(1);
	}

	/* Prepare message structures */
	mctx = NULL;
	qmessage = NULL;
	rmessage = NULL;

	result = isc_mem_create(0, 0, &mctx);
	if (result != ISC_R_SUCCESS) {
		fprintf(stderr, "failed to create a memory context\n");
		exit(1);
	}
	result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &qmessage);
	if (result == ISC_R_SUCCESS) {
		result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE,
					    &rmessage);
	}
	if (result != ISC_R_SUCCESS) {
		fprintf(stderr, "failed to create messages\n");
		exit(1);
	}

	/* Initialize the nameserver address */
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_DGRAM;
	hints.ai_protocol = IPPROTO_UDP;
	hints.ai_flags = AI_NUMERICHOST;
	gai_error = getaddrinfo(argv[0], "53", &hints, &res);
	if (gai_error != 0) {
		fprintf(stderr, "getaddrinfo failed: %s\n",
			gai_strerror(gai_error));
		exit(1);
	}
	INSIST(res->ai_addrlen <= sizeof(sa.type));
	memcpy(&sa.type, res->ai_addr, res->ai_addrlen);
	freeaddrinfo(res);
	sa.length = res->ai_addrlen;
	ISC_LINK_INIT(&sa, link);

	/* Construct qname */
	result = make_querymessage(qmessage, argv[1], type);
	if (result != ISC_R_SUCCESS) {
		fprintf(stderr, "failed to create a query\n");
		exit(1);
	}

	/* Send request and wait for a response */
	result = dns_client_request(client, qmessage, rmessage, &sa, 0, 0,
				    NULL, 60, 0, 3);
	if (result != ISC_R_SUCCESS) {
		fprintf(stderr, "failed to get a response: %s\n",
			dns_result_totext(result));
	}

	/* Dump the response */
	outputbuf = NULL;
	result = isc_buffer_allocate(mctx, &outputbuf, 65535);
	if (result != ISC_R_SUCCESS) {
		fprintf(stderr, "failed to allocate a result buffer\n");
		exit(1);
	}
	for (i = 0; i < DNS_SECTION_MAX; i++) {
		print_section(rmessage, i, outputbuf);
		isc_buffer_clear(outputbuf);
	}
	isc_buffer_free(&outputbuf);

	/* Cleanup */
	dns_message_destroy(&qmessage);
	dns_message_destroy(&rmessage);
	isc_mem_destroy(&mctx);
	dns_client_destroy(&client);
	dns_lib_shutdown();

	exit(0);
}
Example #20
0
isc_result_t
dns_tsig_sign(dns_message_t *msg) {
	dns_tsigkey_t *key;
	dns_rdata_any_tsig_t tsig, querytsig;
	unsigned char data[128];
	isc_buffer_t databuf, sigbuf;
	isc_buffer_t *dynbuf;
	dns_name_t *owner;
	dns_rdata_t *rdata = NULL;
	dns_rdatalist_t *datalist;
	dns_rdataset_t *dataset;
	isc_region_t r;
	isc_stdtime_t now;
	isc_mem_t *mctx;
	dst_context_t *ctx = NULL;
	isc_result_t ret;
	unsigned char badtimedata[BADTIMELEN];
	unsigned int sigsize = 0;
	isc_boolean_t response = is_response(msg);

	REQUIRE(msg != NULL);
	REQUIRE(VALID_TSIG_KEY(dns_message_gettsigkey(msg)));

	/*
	 * If this is a response, there should be a query tsig.
	 */
	if (response && msg->querytsig == NULL)
		return (DNS_R_EXPECTEDTSIG);

	dynbuf = NULL;

	mctx = msg->mctx;
	key = dns_message_gettsigkey(msg);

	tsig.mctx = mctx;
	tsig.common.rdclass = dns_rdataclass_any;
	tsig.common.rdtype = dns_rdatatype_tsig;
	ISC_LINK_INIT(&tsig.common, link);
	dns_name_init(&tsig.algorithm, NULL);
	dns_name_clone(key->algorithm, &tsig.algorithm);

	isc_stdtime_get(&now);
	tsig.timesigned = now + msg->timeadjust;
	tsig.fudge = DNS_TSIG_FUDGE;

	tsig.originalid = msg->id;

	isc_buffer_init(&databuf, data, sizeof(data));

	if (response)
		tsig.error = msg->querytsigstatus;
	else
		tsig.error = dns_rcode_noerror;

	if (tsig.error != dns_tsigerror_badtime) {
		tsig.otherlen = 0;
		tsig.other = NULL;
	} else {
		isc_buffer_t otherbuf;

		tsig.otherlen = BADTIMELEN;
		tsig.other = badtimedata;
		isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen);
		isc_buffer_putuint48(&otherbuf, tsig.timesigned);
	}

	if (key->key != NULL && tsig.error != dns_tsigerror_badsig) {
		unsigned char header[DNS_MESSAGE_HEADERLEN];
		isc_buffer_t headerbuf;
		isc_uint16_t digestbits;

		ret = dst_context_create3(key->key, mctx,
					  DNS_LOGCATEGORY_DNSSEC,
					  ISC_TRUE, &ctx);
		if (ret != ISC_R_SUCCESS)
			return (ret);

		/*
		 * If this is a response, digest the query signature.
		 */
		if (response) {
			dns_rdata_t querytsigrdata = DNS_RDATA_INIT;

			ret = dns_rdataset_first(msg->querytsig);
			if (ret != ISC_R_SUCCESS)
				goto cleanup_context;
			dns_rdataset_current(msg->querytsig, &querytsigrdata);
			ret = dns_rdata_tostruct(&querytsigrdata, &querytsig,
						 NULL);
			if (ret != ISC_R_SUCCESS)
				goto cleanup_context;
			isc_buffer_putuint16(&databuf, querytsig.siglen);
			if (isc_buffer_availablelength(&databuf) <
			    querytsig.siglen) {
				ret = ISC_R_NOSPACE;
				goto cleanup_context;
			}
			isc_buffer_putmem(&databuf, querytsig.signature,
					  querytsig.siglen);
			isc_buffer_usedregion(&databuf, &r);
			ret = dst_context_adddata(ctx, &r);
			if (ret != ISC_R_SUCCESS)
				goto cleanup_context;
		}
#if defined(__clang__)  && \
       ( __clang_major__ < 3 || \
	(__clang_major__ == 3 && __clang_minor__ < 2) || \
	(__clang_major__ == 4 && __clang_minor__ < 2))
	/* false positive: http://llvm.org/bugs/show_bug.cgi?id=14461 */
		else memset(&querytsig, 0, sizeof(querytsig));
#endif

		/*
		 * Digest the header.
		 */
		isc_buffer_init(&headerbuf, header, sizeof(header));
		dns_message_renderheader(msg, &headerbuf);
		isc_buffer_usedregion(&headerbuf, &r);
		ret = dst_context_adddata(ctx, &r);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_context;

		/*
		 * Digest the remainder of the message.
		 */
		isc_buffer_usedregion(msg->buffer, &r);
		isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
		ret = dst_context_adddata(ctx, &r);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_context;

		if (msg->tcp_continuation == 0) {
			/*
			 * Digest the name, class, ttl, alg.
			 */
			dns_name_toregion(&key->name, &r);
			ret = dst_context_adddata(ctx, &r);
			if (ret != ISC_R_SUCCESS)
				goto cleanup_context;

			isc_buffer_clear(&databuf);
			isc_buffer_putuint16(&databuf, dns_rdataclass_any);
			isc_buffer_putuint32(&databuf, 0); /* ttl */
			isc_buffer_usedregion(&databuf, &r);
			ret = dst_context_adddata(ctx, &r);
			if (ret != ISC_R_SUCCESS)
				goto cleanup_context;

			dns_name_toregion(&tsig.algorithm, &r);
			ret = dst_context_adddata(ctx, &r);
			if (ret != ISC_R_SUCCESS)
				goto cleanup_context;

		}
		/* Digest the timesigned and fudge */
		isc_buffer_clear(&databuf);
		if (tsig.error == dns_tsigerror_badtime) {
			INSIST(response);
			tsig.timesigned = querytsig.timesigned;
		}
		isc_buffer_putuint48(&databuf, tsig.timesigned);
		isc_buffer_putuint16(&databuf, tsig.fudge);
		isc_buffer_usedregion(&databuf, &r);
		ret = dst_context_adddata(ctx, &r);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_context;

		if (msg->tcp_continuation == 0) {
			/*
			 * Digest the error and other data length.
			 */
			isc_buffer_clear(&databuf);
			isc_buffer_putuint16(&databuf, tsig.error);
			isc_buffer_putuint16(&databuf, tsig.otherlen);

			isc_buffer_usedregion(&databuf, &r);
			ret = dst_context_adddata(ctx, &r);
			if (ret != ISC_R_SUCCESS)
				goto cleanup_context;

			/*
			 * Digest other data.
			 */
			if (tsig.otherlen > 0) {
				r.length = tsig.otherlen;
				r.base = tsig.other;
				ret = dst_context_adddata(ctx, &r);
				if (ret != ISC_R_SUCCESS)
					goto cleanup_context;
			}
		}

		ret = dst_key_sigsize(key->key, &sigsize);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_context;
		tsig.signature = (unsigned char *) isc_mem_get(mctx, sigsize);
		if (tsig.signature == NULL) {
			ret = ISC_R_NOMEMORY;
			goto cleanup_context;
		}

		isc_buffer_init(&sigbuf, tsig.signature, sigsize);
		ret = dst_context_sign(ctx, &sigbuf);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_signature;
		dst_context_destroy(&ctx);
		digestbits = dst_key_getbits(key->key);
		if (digestbits != 0) {
			unsigned int bytes = (digestbits + 1) / 8;
			if (response && bytes < querytsig.siglen)
				bytes = querytsig.siglen;
			if (bytes > isc_buffer_usedlength(&sigbuf))
				bytes = isc_buffer_usedlength(&sigbuf);
			tsig.siglen = bytes;
		} else
			tsig.siglen = isc_buffer_usedlength(&sigbuf);
	} else {
		tsig.siglen = 0;
		tsig.signature = NULL;
	}

	ret = dns_message_gettemprdata(msg, &rdata);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_signature;
	ret = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_rdata;
	ret = dns_rdata_fromstruct(rdata, dns_rdataclass_any,
				   dns_rdatatype_tsig, &tsig, dynbuf);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_dynbuf;

	dns_message_takebuffer(msg, &dynbuf);

	if (tsig.signature != NULL) {
		isc_mem_put(mctx, tsig.signature, sigsize);
		tsig.signature = NULL;
	}

	owner = NULL;
	ret = dns_message_gettempname(msg, &owner);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_rdata;
	dns_name_init(owner, NULL);
	ret = dns_name_dup(&key->name, msg->mctx, owner);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_owner;

	datalist = NULL;
	ret = dns_message_gettemprdatalist(msg, &datalist);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_owner;
	dataset = NULL;
	ret = dns_message_gettemprdataset(msg, &dataset);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_rdatalist;
	datalist->rdclass = dns_rdataclass_any;
	datalist->type = dns_rdatatype_tsig;
	datalist->covers = 0;
	datalist->ttl = 0;
	ISC_LIST_INIT(datalist->rdata);
	ISC_LIST_APPEND(datalist->rdata, rdata, link);
	RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset)
		      == ISC_R_SUCCESS);
	msg->tsig = dataset;
	msg->tsigname = owner;

	/* Windows does not like the tsig name being compressed. */
	msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;

	return (ISC_R_SUCCESS);

 cleanup_rdatalist:
	dns_message_puttemprdatalist(msg, &datalist);
 cleanup_owner:
	dns_message_puttempname(msg, &owner);
	goto cleanup_rdata;
 cleanup_dynbuf:
	isc_buffer_free(&dynbuf);
 cleanup_rdata:
	dns_message_puttemprdata(msg, &rdata);
 cleanup_signature:
	if (tsig.signature != NULL)
		isc_mem_put(mctx, tsig.signature, sigsize);
 cleanup_context:
	if (ctx != NULL)
		dst_context_destroy(&ctx);
	return (ret);
}
Example #21
0
File: dig.c Project: Gradwell/bind9
/*
 * Callback from dighost.c to print the reply from a server
 */
isc_result_t
printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
	isc_result_t result;
	dns_messagetextflag_t flags;
	isc_buffer_t *buf = NULL;
	unsigned int len = OUTPUTBUF;
	dns_master_style_t *style = NULL;
	unsigned int styleflags = 0;

	styleflags |= DNS_STYLEFLAG_REL_OWNER;
	if (query->lookup->comments)
		styleflags |= DNS_STYLEFLAG_COMMENT;
	if (rrcomments)
		styleflags |= DNS_STYLEFLAG_RRCOMMENT;
	if (nottl)
		styleflags |= DNS_STYLEFLAG_NO_TTL;
	if (noclass)
		styleflags |= DNS_STYLEFLAG_NO_CLASS;
	if (multiline) {
		styleflags |= DNS_STYLEFLAG_OMIT_OWNER;
		styleflags |= DNS_STYLEFLAG_OMIT_CLASS;
		styleflags |= DNS_STYLEFLAG_REL_DATA;
		styleflags |= DNS_STYLEFLAG_OMIT_TTL;
		styleflags |= DNS_STYLEFLAG_TTL;
		styleflags |= DNS_STYLEFLAG_MULTILINE;
		styleflags |= DNS_STYLEFLAG_RRCOMMENT;
	}
	if (multiline || (nottl && noclass))
		result = dns_master_stylecreate2(&style, styleflags,
						 24, 24, 24, 32, 80, 8,
						 splitwidth, mctx);
	else if (nottl || noclass)
		result = dns_master_stylecreate2(&style, styleflags,
						 24, 24, 32, 40, 80, 8,
						 splitwidth, mctx);
	else
		result = dns_master_stylecreate2(&style, styleflags,
						 24, 32, 40, 48, 80, 8,
						 splitwidth, mctx);
	check_result(result, "dns_master_stylecreate");

	if (query->lookup->cmdline[0] != 0) {
		if (!short_form)
			fputs(query->lookup->cmdline, stdout);
		query->lookup->cmdline[0]=0;
	}
	debug("printmessage(%s %s %s)", headers ? "headers" : "noheaders",
	      query->lookup->comments ? "comments" : "nocomments",
	      short_form ? "short_form" : "long_form");

	flags = 0;
	if (!headers) {
		flags |= DNS_MESSAGETEXTFLAG_NOHEADERS;
		flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS;
	}
	if (onesoa && query->lookup->rdtype == dns_rdatatype_axfr)
		flags |= (query->msg_count == 0) ? DNS_MESSAGETEXTFLAG_ONESOA :
						   DNS_MESSAGETEXTFLAG_OMITSOA;
	if (!query->lookup->comments)
		flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS;

	result = isc_buffer_allocate(mctx, &buf, len);
	check_result(result, "isc_buffer_allocate");

	if (query->lookup->comments && !short_form) {
		if (query->lookup->cmdline[0] != 0)
			printf("; %s\n", query->lookup->cmdline);
		if (msg == query->lookup->sendmsg)
			printf(";; Sending:\n");
		else
			printf(";; Got answer:\n");

		if (headers) {
			printf(";; ->>HEADER<<- opcode: %s, status: %s, "
			       "id: %u\n",
			       opcodetext[msg->opcode],
			       rcode_totext(msg->rcode),
			       msg->id);
			printf(";; flags:");
			if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
				printf(" qr");
			if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
				printf(" aa");
			if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
				printf(" tc");
			if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
				printf(" rd");
			if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
				printf(" ra");
			if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
				printf(" ad");
			if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
				printf(" cd");
			if ((msg->flags & 0x0040U) != 0)
				printf("; MBZ: 0x4");

			printf("; QUERY: %u, ANSWER: %u, "
			       "AUTHORITY: %u, ADDITIONAL: %u\n",
			       msg->counts[DNS_SECTION_QUESTION],
			       msg->counts[DNS_SECTION_ANSWER],
			       msg->counts[DNS_SECTION_AUTHORITY],
			       msg->counts[DNS_SECTION_ADDITIONAL]);

			if (msg != query->lookup->sendmsg &&
			    (msg->flags & DNS_MESSAGEFLAG_RD) != 0 &&
			    (msg->flags & DNS_MESSAGEFLAG_RA) == 0)
				printf(";; WARNING: recursion requested "
				       "but not available\n");
		}
		if (msg != query->lookup->sendmsg &&
		    query->lookup->edns != -1 && msg->opt == NULL &&
		    (msg->rcode == dns_rcode_formerr ||
		     msg->rcode == dns_rcode_notimp))
			printf("\n;; WARNING: EDNS query returned status "
			       "%s - retry with '+noedns'\n",
			       rcode_totext(msg->rcode));
		if (msg != query->lookup->sendmsg && extrabytes != 0U)
			printf(";; WARNING: Messages has %u extra byte%s at "
			       "end\n", extrabytes, extrabytes != 0 ? "s" : "");
	}

repopulate_buffer:

	if (query->lookup->comments && headers && !short_form) {
		result = dns_message_pseudosectiontotext(msg,
			 DNS_PSEUDOSECTION_OPT,
			 style, flags, buf);
		if (result == ISC_R_NOSPACE) {
buftoosmall:
			len += OUTPUTBUF;
			isc_buffer_free(&buf);
			result = isc_buffer_allocate(mctx, &buf, len);
			if (result == ISC_R_SUCCESS)
				goto repopulate_buffer;
			else
				goto cleanup;
		}
		check_result(result,
		     "dns_message_pseudosectiontotext");
	}

	if (query->lookup->section_question && headers) {
		if (!short_form) {
			result = dns_message_sectiontotext(msg,
						       DNS_SECTION_QUESTION,
						       style, flags, buf);
			if (result == ISC_R_NOSPACE)
				goto buftoosmall;
			check_result(result, "dns_message_sectiontotext");
		}
	}
	if (query->lookup->section_answer) {
		if (!short_form) {
			result = dns_message_sectiontotext(msg,
						       DNS_SECTION_ANSWER,
						       style, flags, buf);
			if (result == ISC_R_NOSPACE)
				goto buftoosmall;
			check_result(result, "dns_message_sectiontotext");
		} else {
			result = short_answer(msg, flags, buf, query);
			if (result == ISC_R_NOSPACE)
				goto buftoosmall;
			check_result(result, "short_answer");
		}
	}
	if (query->lookup->section_authority) {
		if (!short_form) {
			result = dns_message_sectiontotext(msg,
						       DNS_SECTION_AUTHORITY,
						       style, flags, buf);
			if (result == ISC_R_NOSPACE)
				goto buftoosmall;
			check_result(result, "dns_message_sectiontotext");
		}
	}
	if (query->lookup->section_additional) {
		if (!short_form) {
			result = dns_message_sectiontotext(msg,
						      DNS_SECTION_ADDITIONAL,
						      style, flags, buf);
			if (result == ISC_R_NOSPACE)
				goto buftoosmall;
			check_result(result, "dns_message_sectiontotext");
			/*
			 * Only print the signature on the first record.
			 */
			if (headers) {
				result = dns_message_pseudosectiontotext(
						   msg,
						   DNS_PSEUDOSECTION_TSIG,
						   style, flags, buf);
				if (result == ISC_R_NOSPACE)
					goto buftoosmall;
				check_result(result,
					  "dns_message_pseudosectiontotext");
				result = dns_message_pseudosectiontotext(
						   msg,
						   DNS_PSEUDOSECTION_SIG0,
						   style, flags, buf);
				if (result == ISC_R_NOSPACE)
					goto buftoosmall;
				check_result(result,
					   "dns_message_pseudosectiontotext");
			}
		}
	}

	if (headers && query->lookup->comments && !short_form)
		printf("\n");

	printf("%.*s", (int)isc_buffer_usedlength(buf),
	       (char *)isc_buffer_base(buf));
	isc_buffer_free(&buf);

cleanup:
	if (style != NULL)
		dns_master_styledestroy(&style, mctx);
	return (result);
}
Example #22
0
isc_result_t
dns_tsig_sign(dns_message_t *msg) {
	dns_tsigkey_t *key;
	dns_rdata_any_tsig_t tsig, querytsig;
	unsigned char data[128];
	isc_buffer_t databuf, sigbuf;
	isc_buffer_t *dynbuf;
	dns_name_t *owner;
	dns_rdata_t *rdata;
	dns_rdatalist_t *datalist;
	dns_rdataset_t *dataset;
	isc_region_t r;
	isc_stdtime_t now;
	isc_mem_t *mctx;
	dst_context_t *ctx = NULL;
	isc_result_t ret;
	unsigned char badtimedata[BADTIMELEN];
	unsigned int sigsize = 0;

	REQUIRE(msg != NULL);
	REQUIRE(VALID_TSIG_KEY(dns_message_gettsigkey(msg)));

	/*
	 * If this is a response, there should be a query tsig.
	 */
	if (is_response(msg) && msg->querytsig == NULL)
		return (DNS_R_EXPECTEDTSIG);

	dynbuf = NULL;

	mctx = msg->mctx;
	key = dns_message_gettsigkey(msg);

	tsig.mctx = mctx;
	tsig.common.rdclass = dns_rdataclass_any;
	tsig.common.rdtype = dns_rdatatype_tsig;
	ISC_LINK_INIT(&tsig.common, link);
	dns_name_init(&tsig.algorithm, NULL);
	dns_name_clone(key->algorithm, &tsig.algorithm);

	isc_stdtime_get(&now);
	tsig.timesigned = now + msg->timeadjust;
	tsig.fudge = DNS_TSIG_FUDGE;

	tsig.originalid = msg->id;

	isc_buffer_init(&databuf, data, sizeof(data));

	if (is_response(msg))
		tsig.error = msg->querytsigstatus;
	else
		tsig.error = dns_rcode_noerror;

	if (tsig.error != dns_tsigerror_badtime) {
		tsig.otherlen = 0;
		tsig.other = NULL;
	} else {
		isc_buffer_t otherbuf;

		tsig.otherlen = BADTIMELEN;
		tsig.other = badtimedata;
		isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen);
		buffer_putuint48(&otherbuf, tsig.timesigned);
	}

	if (key->key != NULL && tsig.error != dns_tsigerror_badsig) {
		unsigned char header[DNS_MESSAGE_HEADERLEN];
		isc_buffer_t headerbuf;

		ret = dst_context_create(key->key, mctx, &ctx);
		if (ret != ISC_R_SUCCESS)
			return (ret);

		/*
		 * If this is a response, digest the query signature.
		 */
		if (is_response(msg)) {
			dns_rdata_t querytsigrdata = DNS_RDATA_INIT;

			ret = dns_rdataset_first(msg->querytsig);
			if (ret != ISC_R_SUCCESS)
				goto cleanup_context;
			dns_rdataset_current(msg->querytsig, &querytsigrdata);
			ret = dns_rdata_tostruct(&querytsigrdata, &querytsig,
						 NULL);
			if (ret != ISC_R_SUCCESS)
				goto cleanup_context;
			isc_buffer_putuint16(&databuf, querytsig.siglen);
			if (isc_buffer_availablelength(&databuf) <
			    querytsig.siglen)
			{
				ret = ISC_R_NOSPACE;
				goto cleanup_context;
			}
			isc_buffer_putmem(&databuf, querytsig.signature,
					  querytsig.siglen);
			isc_buffer_usedregion(&databuf, &r);
			ret = dst_context_adddata(ctx, &r);
			if (ret != ISC_R_SUCCESS)
				goto cleanup_context;
		}

		/*
		 * Digest the header.
		 */
		isc_buffer_init(&headerbuf, header, sizeof(header));
		dns_message_renderheader(msg, &headerbuf);
		isc_buffer_usedregion(&headerbuf, &r);
		ret = dst_context_adddata(ctx, &r);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_context;

		/*
		 * Digest the remainder of the message.
		 */
		isc_buffer_usedregion(msg->buffer, &r);
		isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
		ret = dst_context_adddata(ctx, &r);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_context;

		if (msg->tcp_continuation == 0) {
			/*
			 * Digest the name, class, ttl, alg.
			 */
			dns_name_toregion(&key->name, &r);
			ret = dst_context_adddata(ctx, &r);
			if (ret != ISC_R_SUCCESS)
				goto cleanup_context;

			isc_buffer_clear(&databuf);
			isc_buffer_putuint16(&databuf, dns_rdataclass_any);
			isc_buffer_putuint32(&databuf, 0); /* ttl */
			isc_buffer_usedregion(&databuf, &r);
			ret = dst_context_adddata(ctx, &r);
			if (ret != ISC_R_SUCCESS)
				goto cleanup_context;

			dns_name_toregion(&tsig.algorithm, &r);
			ret = dst_context_adddata(ctx, &r);
			if (ret != ISC_R_SUCCESS)
				goto cleanup_context;

		}
		/* Digest the timesigned and fudge */
		isc_buffer_clear(&databuf);
		if (tsig.error == dns_tsigerror_badtime)
			tsig.timesigned = querytsig.timesigned;
		buffer_putuint48(&databuf, tsig.timesigned);
		isc_buffer_putuint16(&databuf, tsig.fudge);
		isc_buffer_usedregion(&databuf, &r);
		ret = dst_context_adddata(ctx, &r);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_context;

		if (msg->tcp_continuation == 0) {
			/*
			 * Digest the error and other data length.
			 */
			isc_buffer_clear(&databuf);
			isc_buffer_putuint16(&databuf, tsig.error);
			isc_buffer_putuint16(&databuf, tsig.otherlen);

			isc_buffer_usedregion(&databuf, &r);
			ret = dst_context_adddata(ctx, &r);
			if (ret != ISC_R_SUCCESS)
				goto cleanup_context;

			/*
			 * Digest the error and other data.
			 */
			if (tsig.otherlen > 0) {
				r.length = tsig.otherlen;
				r.base = tsig.other;
				ret = dst_context_adddata(ctx, &r);
				if (ret != ISC_R_SUCCESS)
					goto cleanup_context;
			}
		}

		ret = dst_key_sigsize(key->key, &sigsize);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_context;
		tsig.signature = (unsigned char *) isc_mem_get(mctx, sigsize);
		if (tsig.signature == NULL) {
			ret = ISC_R_NOMEMORY;
			goto cleanup_context;
		}

		isc_buffer_init(&sigbuf, tsig.signature, sigsize);
		ret = dst_context_sign(ctx, &sigbuf);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_signature;
		dst_context_destroy(&ctx);
		tsig.siglen = isc_buffer_usedlength(&sigbuf);
	} else {
		tsig.siglen = 0;
		tsig.signature = NULL;
	}

	rdata = NULL;
	ret = dns_message_gettemprdata(msg, &rdata);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_signature;
	ret = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_signature;
	ret = dns_rdata_fromstruct(rdata, dns_rdataclass_any,
				   dns_rdatatype_tsig, &tsig, dynbuf);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_dynbuf;

	dns_message_takebuffer(msg, &dynbuf);

	if (tsig.signature != NULL) {
		isc_mem_put(mctx, tsig.signature, sigsize);
		tsig.signature = NULL;
	}

	owner = NULL;
	ret = dns_message_gettempname(msg, &owner);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_dynbuf;
	dns_name_init(owner, NULL);
	ret = dns_name_dup(&key->name, msg->mctx, owner);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_owner;

	datalist = NULL;
	ret = dns_message_gettemprdatalist(msg, &datalist);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_owner;
	datalist->rdclass = dns_rdataclass_any;
	datalist->type = dns_rdatatype_tsig;
	datalist->covers = 0;
	datalist->ttl = 0;
	ISC_LIST_INIT(datalist->rdata);
	ISC_LIST_APPEND(datalist->rdata, rdata, link);
	dataset = NULL;
	ret = dns_message_gettemprdataset(msg, &dataset);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_owner;
	dns_rdataset_init(dataset);
	RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset)
		      == ISC_R_SUCCESS);
	msg->tsig = dataset;
	msg->tsigname = owner;

	return (ISC_R_SUCCESS);

cleanup_owner:
	if (owner != NULL)
		dns_message_puttempname(msg, &owner);
cleanup_dynbuf:
	if (dynbuf != NULL)
		isc_buffer_free(&dynbuf);
cleanup_signature:
	if (tsig.signature != NULL)
		isc_mem_put(mctx, tsig.signature, sigsize);
cleanup_context:
	if (ctx != NULL)
		dst_context_destroy(&ctx);
	return (ret);
}
Example #23
0
/*
 * we asked for, and got a CNAME of some kind.
 */
static void process_step_cname(dnskey_glob *gs,
			       dnskey_lookup *dl,
			       struct rrsetinfo *ans,
			       int success)
{
	struct rdatainfo *ri;
	isc_region_t  region;
	dns_rdata_t   rd;
	dns_rdata_cname_t cn;
	char simplebuf[80];
	isc_buffer_t *cname_text;
	char cname_buf[DNS_NAME_MAXTEXT];
	/* char cname_buf2[DNS_NAME_MAXTEXT]; */

	switch(success) {
	case ERRSET_NONAME:
	case ERRSET_NODATA:
		/* no, no CNAME found, thing isn't there */
		snprintf(simplebuf, sizeof(simplebuf),
			 "RR of type %s for %s was not found (tried CNAMEs)",
			 dl->wantedtype_name,
			 dl->fqdn);
		output_transaction_line(gs, dl->tracking_id, 0, "RETRY", 
					simplebuf);
		dl->step = dkl_done;
		return;
		
	case 0:
		/* aha! found a CNAME */
		break;

	default:
	fatal:
		/* some other error */
		snprintf(simplebuf, sizeof(simplebuf), "err=%d", success);
		output_transaction_line(gs, dl->tracking_id, 0, "FATAL", simplebuf);
		dl->step = dkl_done;
		return;
	}

	/*
	 * now process out the CNAMEs, and look them up, one by one...
	 * there should be only one... We just use the first one that works.
	 */

	if(ans->rri_flags & RRSET_VALIDATED) {
		output_transaction_line(gs, dl->tracking_id, 0, "DNSSEC", "OKAY");
	} else {
		output_transaction_line(gs, dl->tracking_id, 0, "DNSSEC", "not present");
	}

	if(ans->rri_nrdatas != 1) {
		/* we got a number of CNAMEs different from 1! */
		success=0;
		snprintf(simplebuf, sizeof(simplebuf), "illegal number of CNAMES: %d", ans->rri_nrdatas);
		output_transaction_line(gs, dl->tracking_id, 0, "FATAL", simplebuf);
		dl->step = dkl_done;
		return;
	}

	/* process first CNAME record */
	ri= &ans->rri_rdatas[0];

	memset(&region, 0, sizeof(region));
	memset(&rd,     0, sizeof(rd));
	
	region.base   =  ri->rdi_data;
	region.length =  ri->rdi_length;

	dns_rdata_fromregion(&rd, dns_rdataclass_in,
			     dns_rdatatype_cname, &region);
	
	/* we set mctx to NULL, which means that the tenure for
	 * the stuff pointed to by cn will persist only as long
	 * as rd persists.
	 */
	if(dns_rdata_tostruct(&rd, &cn, NULL) != ISC_R_SUCCESS) {
		/* failed, try next return error */
		success=0;
		goto fatal;
	}

	cname_text=NULL;
	if(isc_buffer_allocate(gs->iscmem, &cname_text, DNS_NAME_MAXTEXT)) {
		success=0;
		goto fatal;
	}

	if(dns_name_totext(&cn.cname, ISC_TRUE, cname_text) !=
	   ISC_R_SUCCESS) {
		success=0;
		goto fatal;
	}
	
	cname_buf[0]='\0';
	strncat(cname_buf,
		isc_buffer_base(cname_text),
		isc_buffer_usedlength(cname_text));

	/* free up buffer */
	isc_buffer_free(&cname_text);
	
	{
		/* add a trailing . */
		char *end;
		end = &cname_buf[strlen(cname_buf)];
		if(*end != '.') {
			strncat(cname_buf, ".", sizeof(cname_buf));
		}
	}
	
	/* format out a text version */
	output_transaction_line(gs, dl->tracking_id, 0, "CNAME", cname_buf);
	output_transaction_line(gs, dl->tracking_id, 0, "CNAMEFROM", dl->fqdn);
	
	/* check for loops in the CNAMEs! */
	if(dns_name_equal(&dl->last_cname, &cn.cname) == ISC_TRUE) {
		/* damn, we found a loop! */
		dl->step = dkl_done;
		return;
	}

	/* send new request. */
	/* okay, so look this new thing up */		
	success = lwres_getrrsetbyname_init(cname_buf, dns_rdataclass_in,
					    dl->wantedtype, 0 /*flags*/,
					    gs->lwctx, &dl->las);

	if(success != ERRSET_SUCCESS) {
		return;
	}

	lwres_getrrsetbyname_xmit(gs->lwctx, &dl->las);

	dl->step = dkl_second;
}
Example #24
0
static isc_result_t
configure_dnsseckeys(irs_dnsconf_t *conf, cfg_obj_t *cfgobj,
		     dns_rdataclass_t rdclass)
{
	isc_mem_t *mctx = conf->mctx;
	const cfg_obj_t *keys = NULL;
	const cfg_obj_t *key, *keylist;
	dns_fixedname_t fkeyname;
	dns_name_t *keyname_base, *keyname;
	const cfg_listelt_t *element, *element2;
	isc_result_t result;
	isc_uint32_t flags, proto, alg;
	const char *keystr, *keynamestr;
	unsigned char keydata[4096];
	isc_buffer_t keydatabuf_base, *keydatabuf;
	dns_rdata_dnskey_t keystruct;
	unsigned char rrdata[4096];
	isc_buffer_t rrdatabuf;
	isc_region_t r;
	isc_buffer_t namebuf;
	irs_dnsconf_dnskey_t *keyent;

	cfg_map_get(cfgobj, "trusted-keys", &keys);
	if (keys == NULL)
		return (ISC_R_SUCCESS);

	for (element = cfg_list_first(keys);
	     element != NULL;
	     element = cfg_list_next(element)) {
		keylist = cfg_listelt_value(element);
		for (element2 = cfg_list_first(keylist);
		     element2 != NULL;
		     element2 = cfg_list_next(element2))
		{
			keydatabuf = NULL;
			keyname = NULL;

			key = cfg_listelt_value(element2);

			flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
			proto = cfg_obj_asuint32(cfg_tuple_get(key,
							       "protocol"));
			alg = cfg_obj_asuint32(cfg_tuple_get(key,
							     "algorithm"));
			keynamestr = cfg_obj_asstring(cfg_tuple_get(key,
								    "name"));

			keystruct.common.rdclass = rdclass;
			keystruct.common.rdtype = dns_rdatatype_dnskey;
			keystruct.mctx = NULL;
			ISC_LINK_INIT(&keystruct.common, link);

			if (flags > 0xffff)
				return (ISC_R_RANGE);
			if (proto > 0xff)
				return (ISC_R_RANGE);
			if (alg > 0xff)
				return (ISC_R_RANGE);
			keystruct.flags = (isc_uint16_t)flags;
			keystruct.protocol = (isc_uint8_t)proto;
			keystruct.algorithm = (isc_uint8_t)alg;

			isc_buffer_init(&keydatabuf_base, keydata,
					sizeof(keydata));
			isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));

			/* Configure key value */
			keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
			result = isc_base64_decodestring(keystr,
							 &keydatabuf_base);
			if (result != ISC_R_SUCCESS)
				return (result);
			isc_buffer_usedregion(&keydatabuf_base, &r);
			keystruct.datalen = r.length;
			keystruct.data = r.base;

			result = dns_rdata_fromstruct(NULL,
						      keystruct.common.rdclass,
						      keystruct.common.rdtype,
						      &keystruct, &rrdatabuf);
			if (result != ISC_R_SUCCESS)
				return (result);
			isc_buffer_usedregion(&rrdatabuf, &r);
			result = isc_buffer_allocate(mctx, &keydatabuf,
						     r.length);
			if (result != ISC_R_SUCCESS)
				return (result);
			result = isc_buffer_copyregion(keydatabuf, &r);
			if (result != ISC_R_SUCCESS)
				goto cleanup;

			/* Configure key name */
			dns_fixedname_init(&fkeyname);
			keyname_base = dns_fixedname_name(&fkeyname);
			isc_buffer_constinit(&namebuf, keynamestr,
					     strlen(keynamestr));
			isc_buffer_add(&namebuf, strlen(keynamestr));
			result = dns_name_fromtext(keyname_base, &namebuf,
						   dns_rootname, 0, NULL);
			if (result != ISC_R_SUCCESS)
				return (result);
			keyname = isc_mem_get(mctx, sizeof(*keyname));
			if (keyname == NULL) {
				result = ISC_R_NOMEMORY;
				goto cleanup;
			}
			dns_name_init(keyname, NULL);
			result = dns_name_dup(keyname_base, mctx, keyname);
			if (result != ISC_R_SUCCESS)
				goto cleanup;

			/* Add the key data to the list */
			keyent = isc_mem_get(mctx, sizeof(*keyent));
			if (keyent == NULL) {
				dns_name_free(keyname, mctx);
				result = ISC_R_NOMEMORY;
				goto cleanup;
			}
			keyent->keyname = keyname;
			keyent->keydatabuf = keydatabuf;

			ISC_LIST_APPEND(conf->trusted_keylist, keyent, link);
		}
	}

	return (ISC_R_SUCCESS);

 cleanup:
	if (keydatabuf != NULL)
		isc_buffer_free(&keydatabuf);
	if (keyname != NULL)
		isc_mem_put(mctx, keyname, sizeof(*keyname));

	return (result);
}
Example #25
0
static isc_result_t
process_dhtkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name,
	       dns_rdata_tkey_t *tkeyin, dns_tkeyctx_t *tctx,
	       dns_rdata_tkey_t *tkeyout,
	       dns_tsig_keyring_t *ring, dns_namelist_t *namelist)
{
	isc_result_t result = ISC_R_SUCCESS;
	dns_name_t *keyname, ourname;
	dns_rdataset_t *keyset = NULL;
	dns_rdata_t keyrdata = DNS_RDATA_INIT, ourkeyrdata = DNS_RDATA_INIT;
	isc_boolean_t found_key = ISC_FALSE, found_incompatible = ISC_FALSE;
	dst_key_t *pubkey = NULL;
	isc_buffer_t ourkeybuf, *shared = NULL;
	isc_region_t r, r2, ourkeyr;
	unsigned char keydata[DST_KEY_MAXSIZE];
	unsigned int sharedsize;
	isc_buffer_t secret;
	unsigned char *randomdata = NULL, secretdata[256];
	dns_ttl_t ttl = 0;

	if (tctx->dhkey == NULL) {
		tkey_log("process_dhtkey: tkey-dhkey not defined");
		tkeyout->error = dns_tsigerror_badalg;
		return (DNS_R_REFUSED);
	}

	if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_HMACMD5_NAME)) {
		tkey_log("process_dhtkey: algorithms other than "
			 "hmac-md5 are not supported");
		tkeyout->error = dns_tsigerror_badalg;
		return (ISC_R_SUCCESS);
	}

	/*
	 * Look for a DH KEY record that will work with ours.
	 */
	for (result = dns_message_firstname(msg, DNS_SECTION_ADDITIONAL);
	     result == ISC_R_SUCCESS && !found_key;
	     result = dns_message_nextname(msg, DNS_SECTION_ADDITIONAL)) {
		keyname = NULL;
		dns_message_currentname(msg, DNS_SECTION_ADDITIONAL, &keyname);
		keyset = NULL;
		result = dns_message_findtype(keyname, dns_rdatatype_key, 0,
					      &keyset);
		if (result != ISC_R_SUCCESS)
			continue;

		for (result = dns_rdataset_first(keyset);
		     result == ISC_R_SUCCESS && !found_key;
		     result = dns_rdataset_next(keyset)) {
			dns_rdataset_current(keyset, &keyrdata);
			pubkey = NULL;
			result = dns_dnssec_keyfromrdata(keyname, &keyrdata,
							 msg->mctx, &pubkey);
			if (result != ISC_R_SUCCESS) {
				dns_rdata_reset(&keyrdata);
				continue;
			}
			if (dst_key_alg(pubkey) == DNS_KEYALG_DH) {
				if (dst_key_paramcompare(pubkey, tctx->dhkey))
				{
					found_key = ISC_TRUE;
					ttl = keyset->ttl;
					break;
				} else
					found_incompatible = ISC_TRUE;
			}
			dst_key_free(&pubkey);
			dns_rdata_reset(&keyrdata);
		}
	}

	if (!found_key) {
		if (found_incompatible) {
			tkey_log("process_dhtkey: found an incompatible key");
			tkeyout->error = dns_tsigerror_badkey;
			return (ISC_R_SUCCESS);
		} else {
			tkey_log("process_dhtkey: failed to find a key");
			return (DNS_R_FORMERR);
		}
	}

	RETERR(add_rdata_to_list(msg, keyname, &keyrdata, ttl, namelist));

	isc_buffer_init(&ourkeybuf, keydata, sizeof(keydata));
	RETERR(dst_key_todns(tctx->dhkey, &ourkeybuf));
	isc_buffer_usedregion(&ourkeybuf, &ourkeyr);
	dns_rdata_fromregion(&ourkeyrdata, dns_rdataclass_any,
			     dns_rdatatype_key, &ourkeyr);

	dns_name_init(&ourname, NULL);
	dns_name_clone(dst_key_name(tctx->dhkey), &ourname);

	/*
	 * XXXBEW The TTL should be obtained from the database, if it exists.
	 */
	RETERR(add_rdata_to_list(msg, &ourname, &ourkeyrdata, 0, namelist));

	RETERR(dst_key_secretsize(tctx->dhkey, &sharedsize));
	RETERR(isc_buffer_allocate(msg->mctx, &shared, sharedsize));

	result = dst_key_computesecret(pubkey, tctx->dhkey, shared);
	if (result != ISC_R_SUCCESS) {
		tkey_log("process_dhtkey: failed to compute shared secret: %s",
			 isc_result_totext(result));
		goto failure;
	}
	dst_key_free(&pubkey);

	isc_buffer_init(&secret, secretdata, sizeof(secretdata));

	randomdata = isc_mem_get(tkeyout->mctx, TKEY_RANDOM_AMOUNT);
	if (randomdata == NULL)
		goto failure;

	result = dst__entropy_getdata(randomdata, TKEY_RANDOM_AMOUNT,
				      ISC_FALSE);
	if (result != ISC_R_SUCCESS) {
		tkey_log("process_dhtkey: failed to obtain entropy: %s",
			 isc_result_totext(result));
		goto failure;
	}

	r.base = randomdata;
	r.length = TKEY_RANDOM_AMOUNT;
	r2.base = tkeyin->key;
	r2.length = tkeyin->keylen;
	RETERR(compute_secret(shared, &r2, &r, &secret));
	isc_buffer_free(&shared);

	RETERR(dns_tsigkey_create(name, &tkeyin->algorithm,
				  isc_buffer_base(&secret),
				  isc_buffer_usedlength(&secret),
				  ISC_TRUE, signer, tkeyin->inception,
				  tkeyin->expire, ring->mctx, ring, NULL));

	/* This key is good for a long time */
	tkeyout->inception = tkeyin->inception;
	tkeyout->expire = tkeyin->expire;

	tkeyout->key = randomdata;
	tkeyout->keylen = TKEY_RANDOM_AMOUNT;

	return (ISC_R_SUCCESS);

 failure:
	if (!ISC_LIST_EMPTY(*namelist))
		free_namelist(msg, namelist);
	if (shared != NULL)
		isc_buffer_free(&shared);
	if (pubkey != NULL)
		dst_key_free(&pubkey);
	if (randomdata != NULL)
		isc_mem_put(tkeyout->mctx, randomdata, TKEY_RANDOM_AMOUNT);
	return (result);
}
Example #26
0
isc_result_t
dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
	dns_rdata_sig_t sig;	/* SIG(0) */
	unsigned char data[512];
	unsigned char header[DNS_MESSAGE_HEADERLEN];
	isc_buffer_t headerbuf, databuf, sigbuf;
	unsigned int sigsize;
	isc_buffer_t *dynbuf = NULL;
	dns_rdata_t *rdata;
	dns_rdatalist_t *datalist;
	dns_rdataset_t *dataset;
	isc_region_t r;
	isc_stdtime_t now;
	dst_context_t *ctx = NULL;
	isc_mem_t *mctx;
	isc_result_t result;
	isc_boolean_t signeedsfree = ISC_TRUE;

	REQUIRE(msg != NULL);
	REQUIRE(key != NULL);

	if (is_response(msg))
		REQUIRE(msg->query.base != NULL);

	mctx = msg->mctx;

	memset(&sig, 0, sizeof(sig));

	sig.mctx = mctx;
	sig.common.rdclass = dns_rdataclass_any;
	sig.common.rdtype = dns_rdatatype_sig;	/* SIG(0) */
	ISC_LINK_INIT(&sig.common, link);

	sig.covered = 0;
	sig.algorithm = dst_key_alg(key);
	sig.labels = 0; /* the root name */
	sig.originalttl = 0;

	isc_stdtime_get(&now);
	sig.timesigned = now - DNS_TSIG_FUDGE;
	sig.timeexpire = now + DNS_TSIG_FUDGE;

	sig.keyid = dst_key_id(key);

	dns_name_init(&sig.signer, NULL);
	dns_name_clone(dst_key_name(key), &sig.signer);

	sig.siglen = 0;
	sig.signature = NULL;

	isc_buffer_init(&databuf, data, sizeof(data));

	RETERR(dst_context_create(key, mctx, &ctx));

	/*
	 * Digest the fields of the SIG - we can cheat and use
	 * dns_rdata_fromstruct.  Since siglen is 0, the digested data
	 * is identical to dns format.
	 */
	RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
				    dns_rdatatype_sig /* SIG(0) */,
				    &sig, &databuf));
	isc_buffer_usedregion(&databuf, &r);
	RETERR(dst_context_adddata(ctx, &r));

	/*
	 * If this is a response, digest the query.
	 */
	if (is_response(msg))
		RETERR(dst_context_adddata(ctx, &msg->query));

	/*
	 * Digest the header.
	 */
	isc_buffer_init(&headerbuf, header, sizeof(header));
	dns_message_renderheader(msg, &headerbuf);
	isc_buffer_usedregion(&headerbuf, &r);
	RETERR(dst_context_adddata(ctx, &r));

	/*
	 * Digest the remainder of the message.
	 */
	isc_buffer_usedregion(msg->buffer, &r);
	isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
	RETERR(dst_context_adddata(ctx, &r));

	RETERR(dst_key_sigsize(key, &sigsize));
	sig.siglen = sigsize;
	sig.signature = (unsigned char *) isc_mem_get(mctx, sig.siglen);
	if (sig.signature == NULL) {
		result = ISC_R_NOMEMORY;
		goto failure;
	}

	isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
	RETERR(dst_context_sign(ctx, &sigbuf));
	dst_context_destroy(&ctx);

	rdata = NULL;
	RETERR(dns_message_gettemprdata(msg, &rdata));
	RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024));
	RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
				    dns_rdatatype_sig /* SIG(0) */,
				    &sig, dynbuf));

	isc_mem_put(mctx, sig.signature, sig.siglen);
	signeedsfree = ISC_FALSE;

	dns_message_takebuffer(msg, &dynbuf);

	datalist = NULL;
	RETERR(dns_message_gettemprdatalist(msg, &datalist));
	datalist->rdclass = dns_rdataclass_any;
	datalist->type = dns_rdatatype_sig;	/* SIG(0) */
	datalist->covers = 0;
	datalist->ttl = 0;
	ISC_LIST_INIT(datalist->rdata);
	ISC_LIST_APPEND(datalist->rdata, rdata, link);
	dataset = NULL;
	RETERR(dns_message_gettemprdataset(msg, &dataset));
	dns_rdataset_init(dataset);
	RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS);
	msg->sig0 = dataset;

	return (ISC_R_SUCCESS);

failure:
	if (dynbuf != NULL)
		isc_buffer_free(&dynbuf);
	if (signeedsfree)
		isc_mem_put(mctx, sig.signature, sig.siglen);
	if (ctx != NULL)
		dst_context_destroy(&ctx);

	return (result);
}
Example #27
0
isc_result_t
dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
		isc_stdtime_t *inception, isc_stdtime_t *expire,
		isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata)
{
	dns_rdata_rrsig_t sig;
	dns_rdata_t tmpsigrdata;
	dns_rdata_t *rdatas;
	int nrdatas, i;
	isc_buffer_t sigbuf, envbuf;
	isc_region_t r;
	dst_context_t *ctx = NULL;
	isc_result_t ret;
	isc_buffer_t *databuf = NULL;
	char data[256 + 8];
	isc_uint32_t flags;
	unsigned int sigsize;
	dns_fixedname_t fnewname;

	REQUIRE(name != NULL);
	REQUIRE(dns_name_countlabels(name) <= 255);
	REQUIRE(set != NULL);
	REQUIRE(key != NULL);
	REQUIRE(inception != NULL);
	REQUIRE(expire != NULL);
	REQUIRE(mctx != NULL);
	REQUIRE(sigrdata != NULL);

	if (*inception >= *expire)
		return (DNS_R_INVALIDTIME);

	/*
	 * Is the key allowed to sign data?
	 */
	flags = dst_key_flags(key);
	if (flags & DNS_KEYTYPE_NOAUTH)
		return (DNS_R_KEYUNAUTHORIZED);
	if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
		return (DNS_R_KEYUNAUTHORIZED);

	sig.mctx = mctx;
	sig.common.rdclass = set->rdclass;
	sig.common.rdtype = dns_rdatatype_rrsig;
	ISC_LINK_INIT(&sig.common, link);

	dns_name_init(&sig.signer, NULL);
	dns_name_clone(dst_key_name(key), &sig.signer);

	sig.covered = set->type;
	sig.algorithm = dst_key_alg(key);
	sig.labels = dns_name_countlabels(name) - 1;
	if (dns_name_iswildcard(name))
		sig.labels--;
	sig.originalttl = set->ttl;
	sig.timesigned = *inception;
	sig.timeexpire = *expire;
	sig.keyid = dst_key_id(key);
	ret = dst_key_sigsize(key, &sigsize);
	if (ret != ISC_R_SUCCESS)
		return (ret);
	sig.siglen = sigsize;
	/*
	 * The actual contents of sig.signature are not important yet, since
	 * they're not used in digest_sig().
	 */
	sig.signature = isc_mem_get(mctx, sig.siglen);
	if (sig.signature == NULL)
		return (ISC_R_NOMEMORY);

	ret = isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_signature;

	dns_rdata_init(&tmpsigrdata);
	ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass,
				   sig.common.rdtype, &sig, databuf);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_databuf;

	ret = dst_context_create(key, mctx, &ctx);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_databuf;

	/*
	 * Digest the SIG rdata.
	 */
	ret = digest_sig(ctx, &tmpsigrdata, &sig);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_context;

	dns_fixedname_init(&fnewname);
	RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
					NULL) == ISC_R_SUCCESS);
	dns_name_toregion(dns_fixedname_name(&fnewname), &r);

	/*
	 * Create an envelope for each rdata: <name|type|class|ttl>.
	 */
	isc_buffer_init(&envbuf, data, sizeof(data));
	memcpy(data, r.base, r.length);
	isc_buffer_add(&envbuf, r.length);
	isc_buffer_putuint16(&envbuf, set->type);
	isc_buffer_putuint16(&envbuf, set->rdclass);
	isc_buffer_putuint32(&envbuf, set->ttl);

	ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_context;
	isc_buffer_usedregion(&envbuf, &r);

	for (i = 0; i < nrdatas; i++) {
		isc_uint16_t len;
		isc_buffer_t lenbuf;
		isc_region_t lenr;

		/*
		 * Skip duplicates.
		 */
		if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
		    continue;

		/*
		 * Digest the envelope.
		 */
		ret = dst_context_adddata(ctx, &r);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_array;

		/*
		 * Digest the length of the rdata.
		 */
		isc_buffer_init(&lenbuf, &len, sizeof(len));
		INSIST(rdatas[i].length < 65536);
		isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
		isc_buffer_usedregion(&lenbuf, &lenr);
		ret = dst_context_adddata(ctx, &lenr);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_array;

		/*
		 * Digest the rdata.
		 */
		ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_array;
	}

	isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
	ret = dst_context_sign(ctx, &sigbuf);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_array;
	isc_buffer_usedregion(&sigbuf, &r);
	if (r.length != sig.siglen) {
		ret = ISC_R_NOSPACE;
		goto cleanup_array;
	}
	memcpy(sig.signature, r.base, sig.siglen);

	ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass,
				  sig.common.rdtype, &sig, buffer);

cleanup_array:
	isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
cleanup_context:
	dst_context_destroy(&ctx);
cleanup_databuf:
	isc_buffer_free(&databuf);
cleanup_signature:
	isc_mem_put(mctx, sig.signature, sig.siglen);

	return (ret);
}
Example #28
0
ATF_TC_BODY(totext, tc) {
	isc_result_t result;
	dns_dthandle_t handle;
	isc_uint8_t *data;
	size_t dsize;
	FILE *fp = NULL;

	UNUSED(tc);

	result = dns_test_begin(NULL, ISC_TRUE);
	ATF_REQUIRE(result == ISC_R_SUCCESS);

	result = dns_dt_open(TAPSAVED, dns_dtmode_file, &handle);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	result = isc_stdio_open(TAPTEXT, "r", &fp);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	/* make sure text conversion gets the right local time */
	setenv("TZ", "MST7", 1);

	while (dns_dt_getframe(&handle, &data, &dsize) == ISC_R_SUCCESS) {
		dns_dtdata_t *dtdata = NULL;
		isc_buffer_t *b = NULL;
		isc_region_t r;
		char s[BUFSIZ], *p;

		r.base = data;
		r.length = dsize;

		/* read the corresponding line of text */
		p = fgets(s, sizeof(s), fp);
		ATF_CHECK_EQ(p, s);
		if (p == NULL)
			break;

		p = strchr(p, '\n');
		if (p != NULL)
			*p = '\0';

		/* parse dnstap frame */
		result = dns_dt_parse(mctx, &r, &dtdata);
		ATF_CHECK_EQ(result, ISC_R_SUCCESS);
		if (result != ISC_R_SUCCESS)
			continue;

		isc_buffer_allocate(mctx, &b, 2048);
		ATF_CHECK(b != NULL);
		if (b == NULL)
			break;

		/* convert to text and compare */
		result = dns_dt_datatotext(dtdata, &b);
		ATF_CHECK_EQ(result, ISC_R_SUCCESS);

		ATF_CHECK_STREQ((char *) isc_buffer_base(b), s);

		dns_dtdata_free(&dtdata);
		isc_buffer_free(&b);
	}

	dns_dt_close(&handle);
	cleanup();

	dns_test_end();
}
Example #29
0
isc_result_t
dst_gssapi_acceptctx(gss_cred_id_t cred,
		     const char *gssapi_keytab,
		     isc_region_t *intoken, isc_buffer_t **outtoken,
		     gss_ctx_id_t *ctxout, dns_name_t *principal,
		     isc_mem_t *mctx)
{
#ifdef GSSAPI
	isc_region_t r;
	isc_buffer_t namebuf;
	gss_buffer_desc gnamebuf = GSS_C_EMPTY_BUFFER, gintoken,
			gouttoken = GSS_C_EMPTY_BUFFER;
	OM_uint32 gret, minor;
	gss_ctx_id_t context = GSS_C_NO_CONTEXT;
	gss_name_t gname = NULL;
	isc_result_t result;
	char buf[1024];

	REQUIRE(outtoken != NULL && *outtoken == NULL);

	log_cred(cred);

	REGION_TO_GBUFFER(*intoken, gintoken);

	if (*ctxout == NULL)
		context = GSS_C_NO_CONTEXT;
	else
		context = *ctxout;

	if (gssapi_keytab != NULL) {
#ifdef ISC_PLATFORM_GSSAPI_KRB5_HEADER
		gret = gsskrb5_register_acceptor_identity(gssapi_keytab);
		if (gret != GSS_S_COMPLETE) {
			gss_log(3, "failed "
				"gsskrb5_register_acceptor_identity(%s): %s",
				gssapi_keytab,
				gss_error_tostring(gret, minor,
						   buf, sizeof(buf)));
			return (DNS_R_INVALIDTKEY);
		}
#else
		/*
		 * Minimize memory leakage by only setting KRB5_KTNAME
		 * if it needs to change.
		 */
		const char *old = getenv("KRB5_KTNAME");
		if (old == NULL || strcmp(old, gssapi_keytab) != 0) {
			char *kt = malloc(strlen(gssapi_keytab) + 13);
			if (kt == NULL)
				return (ISC_R_NOMEMORY);
			sprintf(kt, "KRB5_KTNAME=%s", gssapi_keytab);
			if (putenv(kt) != 0)
				return (ISC_R_NOMEMORY);
		}
#endif
	}

	gret = gss_accept_sec_context(&minor, &context, cred, &gintoken,
				      GSS_C_NO_CHANNEL_BINDINGS, &gname,
				      NULL, &gouttoken, NULL, NULL, NULL);

	result = ISC_R_FAILURE;

	switch (gret) {
	case GSS_S_COMPLETE:
		result = ISC_R_SUCCESS;
		break;
	case GSS_S_CONTINUE_NEEDED:
		result = DNS_R_CONTINUE;
		break;
	case GSS_S_DEFECTIVE_TOKEN:
	case GSS_S_DEFECTIVE_CREDENTIAL:
	case GSS_S_BAD_SIG:
	case GSS_S_DUPLICATE_TOKEN:
	case GSS_S_OLD_TOKEN:
	case GSS_S_NO_CRED:
	case GSS_S_CREDENTIALS_EXPIRED:
	case GSS_S_BAD_BINDINGS:
	case GSS_S_NO_CONTEXT:
	case GSS_S_BAD_MECH:
	case GSS_S_FAILURE:
		result = DNS_R_INVALIDTKEY;
		/* fall through */
	default:
		gss_log(3, "failed gss_accept_sec_context: %s",
			gss_error_tostring(gret, minor, buf, sizeof(buf)));
		return (result);
	}

	if (gouttoken.length > 0) {
		RETERR(isc_buffer_allocate(mctx, outtoken, gouttoken.length));
		GBUFFER_TO_REGION(gouttoken, r);
		RETERR(isc_buffer_copyregion(*outtoken, &r));
		(void)gss_release_buffer(&minor, &gouttoken);
	}

	if (gret == GSS_S_COMPLETE) {
		gret = gss_display_name(&minor, gname, &gnamebuf, NULL);
		if (gret != GSS_S_COMPLETE) {
			gss_log(3, "failed gss_display_name: %s",
				gss_error_tostring(gret, minor,
						   buf, sizeof(buf)));
			RETERR(ISC_R_FAILURE);
		}

		/*
		 * Compensate for a bug in Solaris8's implementation
		 * of gss_display_name().  Should be harmless in any
		 * case, since principal names really should not
		 * contain null characters.
		 */
		if (gnamebuf.length > 0 &&
		    ((char *)gnamebuf.value)[gnamebuf.length - 1] == '\0')
			gnamebuf.length--;

		gss_log(3, "gss-api source name (accept) is %.*s",
			(int)gnamebuf.length, (char *)gnamebuf.value);

		GBUFFER_TO_REGION(gnamebuf, r);
		isc_buffer_init(&namebuf, r.base, r.length);
		isc_buffer_add(&namebuf, r.length);

		RETERR(dns_name_fromtext(principal, &namebuf, dns_rootname,
					 0, NULL));

		if (gnamebuf.length != 0) {
			gret = gss_release_buffer(&minor, &gnamebuf);
			if (gret != GSS_S_COMPLETE)
				gss_log(3, "failed gss_release_buffer: %s",
					gss_error_tostring(gret, minor, buf,
							   sizeof(buf)));
		}
	}

	*ctxout = context;

 out:
	if (gname != NULL) {
		gret = gss_release_name(&minor, &gname);
		if (gret != GSS_S_COMPLETE)
			gss_log(3, "failed gss_release_name: %s",
				gss_error_tostring(gret, minor, buf,
						   sizeof(buf)));
	}

	return (result);
#else
	UNUSED(cred);
	UNUSED(gssapi_keytab);
	UNUSED(intoken);
	UNUSED(outtoken);
	UNUSED(ctxout);
	UNUSED(principal);
	UNUSED(mctx);

	return (ISC_R_NOTIMPLEMENTED);
#endif
}
Example #30
0
ATF_TC_BODY(tsig_tcp, tc) {
	const dns_name_t *tsigowner = NULL;
	dns_fixedname_t fkeyname;
	dns_message_t *msg = NULL;
	dns_name_t *keyname;
	dns_tsig_keyring_t *ring = NULL;
	dns_tsigkey_t *key = NULL;
	isc_buffer_t *buf = NULL;
	isc_buffer_t *querytsig = NULL;
	isc_buffer_t *tsigin = NULL;
	isc_buffer_t *tsigout = NULL;
	isc_result_t result;
	unsigned char secret[16] = { 0 };
	dst_context_t *tsigctx = NULL;
	dst_context_t *outctx = NULL;

	UNUSED(tc);

	result = dns_test_begin(stderr, ISC_TRUE);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	/* isc_log_setdebuglevel(lctx, 99); */

	dns_fixedname_init(&fkeyname);
	keyname = dns_fixedname_name(&fkeyname);
	result = dns_name_fromstring(keyname, "test", 0, NULL);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	result = dns_tsigkeyring_create(mctx, &ring);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	result = dns_tsigkey_create(keyname, dns_tsig_hmacsha256_name,
				    secret, sizeof(secret), ISC_FALSE,
				    NULL, 0, 0, mctx, ring, &key);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	/*
	 * Create request.
	 */
	result = isc_buffer_allocate(mctx, &buf, 65535);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
	render(buf, 0, key, &tsigout, &querytsig, NULL);
	isc_buffer_free(&buf);

	/*
	 * Create response message 1.
	 */
	result = isc_buffer_allocate(mctx, &buf, 65535);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
	render(buf, DNS_MESSAGEFLAG_QR, key, &querytsig, &tsigout, NULL);

	/*
	 * Process response message 1.
	 */
	result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_message_create: %s",
			 dns_result_totext(result));

	result = dns_message_settsigkey(msg, key);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_message_settsigkey: %s",
			 dns_result_totext(result));

	result = dns_message_parse(msg, buf, 0);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_message_parse: %s",
			 dns_result_totext(result));

	printmessage(msg);

	result = dns_message_setquerytsig(msg, querytsig);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_message_setquerytsig: %s",
			 dns_result_totext(result));

	result = dns_tsig_verify(buf, msg, NULL, NULL);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_tsig_verify: %s",
			 dns_result_totext(result));
	ATF_CHECK_EQ(msg->verified_sig, 1);
	ATF_CHECK_EQ(msg->tsigstatus, dns_rcode_noerror);

	/*
	 * Check that we have a TSIG in the first message.
	 */
	ATF_REQUIRE(dns_message_gettsig(msg, &tsigowner) != NULL);

	result = dns_message_getquerytsig(msg, mctx, &tsigin);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_message_getquerytsig: %s",
			 dns_result_totext(result));

	tsigctx = msg->tsigctx;
	msg->tsigctx = NULL;
	isc_buffer_free(&buf);
	dns_message_destroy(&msg);

	result = dst_context_create3(key->key, mctx, DNS_LOGCATEGORY_DNSSEC,
				     ISC_FALSE, &outctx);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	/*
	 * Start digesting.
	 */
	result = add_mac(outctx, tsigout);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	/*
	 * Create response message 2.
	 */
	result = isc_buffer_allocate(mctx, &buf, 65535);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
	render(buf, DNS_MESSAGEFLAG_QR, key, &tsigout, &tsigout, outctx);

	/*
	 * Process response message 2.
	 */
	result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_message_create: %s",
			 dns_result_totext(result));

	msg->tcp_continuation = 1;
	msg->tsigctx = tsigctx;
	tsigctx = NULL;

	result = dns_message_settsigkey(msg, key);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_message_settsigkey: %s",
			 dns_result_totext(result));

	result = dns_message_parse(msg, buf, 0);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_message_parse: %s",
			 dns_result_totext(result));

	printmessage(msg);

	result = dns_message_setquerytsig(msg, tsigin);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_message_setquerytsig: %s",
			 dns_result_totext(result));

	result = dns_tsig_verify(buf, msg, NULL, NULL);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_tsig_verify: %s",
			 dns_result_totext(result));
	ATF_CHECK_EQ(msg->verified_sig, 1);
	ATF_CHECK_EQ(msg->tsigstatus, dns_rcode_noerror);

	/*
	 * Check that we don't have a TSIG in the second message.
	 */
	tsigowner = NULL;
	ATF_REQUIRE(dns_message_gettsig(msg, &tsigowner) == NULL);

	tsigctx = msg->tsigctx;
	msg->tsigctx = NULL;
	isc_buffer_free(&buf);
	dns_message_destroy(&msg);

	/*
	 * Create response message 3.
	 */
	result = isc_buffer_allocate(mctx, &buf, 65535);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
	render(buf, DNS_MESSAGEFLAG_QR, key, &tsigout, &tsigout, outctx);

	result = add_tsig(outctx, key, buf);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "add_tsig: %s",
			 dns_result_totext(result));

	/*
	 * Process response message 3.
	 */
	result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_message_create: %s",
			 dns_result_totext(result));

	msg->tcp_continuation = 1;
	msg->tsigctx = tsigctx;
	tsigctx = NULL;

	result = dns_message_settsigkey(msg, key);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_message_settsigkey: %s",
			 dns_result_totext(result));

	result = dns_message_parse(msg, buf, 0);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_message_parse: %s",
			 dns_result_totext(result));

	printmessage(msg);

	/*
	 * Check that we had a TSIG in the third message.
	 */
	ATF_REQUIRE(dns_message_gettsig(msg, &tsigowner) != NULL);

	result = dns_message_setquerytsig(msg, tsigin);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_message_setquerytsig: %s",
			 dns_result_totext(result));

	result = dns_tsig_verify(buf, msg, NULL, NULL);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_tsig_verify: %s",
			 dns_result_totext(result));
	ATF_CHECK_EQ(msg->verified_sig, 1);
	ATF_CHECK_EQ(msg->tsigstatus, dns_rcode_noerror);

	if (tsigin != NULL)
		isc_buffer_free(&tsigin);

	result = dns_message_getquerytsig(msg, mctx, &tsigin);
	ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
			 "dns_message_getquerytsig: %s",
			 dns_result_totext(result));

	isc_buffer_free(&buf);
	dns_message_destroy(&msg);

	if (outctx != NULL)
		dst_context_destroy(&outctx);
	if (querytsig != NULL)
		isc_buffer_free(&querytsig);
	if (tsigin != NULL)
		isc_buffer_free(&tsigin);
	if (tsigout != NULL)
		isc_buffer_free(&tsigout);
	if (buf != NULL)
		isc_buffer_free(&buf);
	if (msg != NULL)
		dns_message_destroy(&msg);
	if (key != NULL)
		dns_tsigkey_detach(&key);
	if (ring != NULL)
		dns_tsigkeyring_detach(&ring);
	dns_test_end();
}