static void
buildquery(void) {
	isc_result_t result;
	dns_rdataset_t *question = NULL;
	dns_name_t *qname = NULL;
	isc_region_t r, inr;
	dns_message_t *query;
	char nametext[] = "host.example";
	isc_buffer_t namesrc, namedst;
	unsigned char namedata[256];
	isc_sockaddr_t sa;
	dns_compress_t cctx;

	query = NULL;
	result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &query);
	CHECK("dns_message_create", result);
	result = dns_message_setsig0key(query, key);
	CHECK("dns_message_setsig0key", result);

	result = dns_message_gettemprdataset(query, &question);
	CHECK("dns_message_gettemprdataset", result);
	dns_rdataset_init(question);
	dns_rdataset_makequestion(question, dns_rdataclass_in,
				  dns_rdatatype_a);
	result = dns_message_gettempname(query, &qname);
	CHECK("dns_message_gettempname", result);
	isc_buffer_init(&namesrc, nametext, strlen(nametext));
	isc_buffer_add(&namesrc, strlen(nametext));
	isc_buffer_init(&namedst, namedata, sizeof(namedata));
	dns_name_init(qname, NULL);
	result = dns_name_fromtext(qname, &namesrc, dns_rootname, 0, &namedst);
	CHECK("dns_name_fromtext", result);
	ISC_LIST_APPEND(qname->list, question, link);
	dns_message_addname(query, qname, DNS_SECTION_QUESTION);

	isc_buffer_init(&qbuffer, qdata, sizeof(qdata));

	result = dns_compress_init(&cctx, -1, mctx);
	CHECK("dns_compress_init", result);
	result = dns_message_renderbegin(query, &cctx, &qbuffer);
	CHECK("dns_message_renderbegin", result);
	result = dns_message_rendersection(query, DNS_SECTION_QUESTION, 0);
	CHECK("dns_message_rendersection(question)", result);
	result = dns_message_rendersection(query, DNS_SECTION_ANSWER, 0);
	CHECK("dns_message_rendersection(answer)", result);
	result = dns_message_rendersection(query, DNS_SECTION_AUTHORITY, 0);
	CHECK("dns_message_rendersection(auth)", result);
	result = dns_message_rendersection(query, DNS_SECTION_ADDITIONAL, 0);
	CHECK("dns_message_rendersection(add)", result);
	result = dns_message_renderend(query);
	CHECK("dns_message_renderend", result);
	dns_compress_invalidate(&cctx);

	isc_buffer_init(&outbuf, output, sizeof(output));
	result = dns_message_totext(query, style, 0, &outbuf);
	CHECK("dns_message_totext", result);
	printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf),
	       (char *)isc_buffer_base(&outbuf));

	isc_buffer_usedregion(&qbuffer, &r);
	isc_sockaddr_any(&sa);
	result = isc_socket_bind(s, &sa, 0);
	CHECK("isc_socket_bind", result);
	result = isc_socket_sendto(s, &r, task1, senddone, NULL, &address,
				   NULL);
	CHECK("isc_socket_sendto", result);

	inr.base = rdata;
	inr.length = sizeof(rdata);
	result = isc_socket_recv(s, &inr, 1, task1, recvdone, NULL);
	CHECK("isc_socket_recv", result);
	dns_message_destroy(&query);
}
Exemple #2
0
static isc_result_t
process_gsstkey(dns_name_t *name, dns_rdata_tkey_t *tkeyin,
		dns_tkeyctx_t *tctx, dns_rdata_tkey_t *tkeyout,
		dns_tsig_keyring_t *ring)
{
	isc_result_t result = ISC_R_SUCCESS;
	dst_key_t *dstkey = NULL;
	dns_tsigkey_t *tsigkey = NULL;
	dns_fixedname_t principal;
	isc_stdtime_t now;
	isc_region_t intoken;
	isc_buffer_t *outtoken = NULL;
	gss_ctx_id_t gss_ctx = NULL;

	/*
	 * You have to define either a gss credential (principal) to
	 * accept with tkey-gssapi-credential, or you have to
	 * configure a specific keytab (with tkey-gssapi-keytab) in
	 * order to use gsstkey
	 */
	if (tctx->gsscred == NULL && tctx->gssapi_keytab == NULL) {
		tkey_log("process_gsstkey(): no tkey-gssapi-credential "
			 "or tkey-gssapi-keytab configured");
		return (ISC_R_NOPERM);
	}

	if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPI_NAME) &&
	    !dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPIMS_NAME)) {
		tkeyout->error = dns_tsigerror_badalg;
		tkey_log("process_gsstkey(): dns_tsigerror_badalg");	/* XXXSRA */
		return (ISC_R_SUCCESS);
	}

	/*
	 * XXXDCL need to check for key expiry per 4.1.1
	 * XXXDCL need a way to check fully established, perhaps w/key_flags
	 */

	intoken.base = tkeyin->key;
	intoken.length = tkeyin->keylen;

	result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm, ring);
	if (result == ISC_R_SUCCESS)
		gss_ctx = dst_key_getgssctx(tsigkey->key);

	dns_fixedname_init(&principal);

	/*
	 * Note that tctx->gsscred may be NULL if tctx->gssapi_keytab is set
	 */
	result = dst_gssapi_acceptctx(tctx->gsscred, tctx->gssapi_keytab,
				      &intoken,
				      &outtoken, &gss_ctx,
				      dns_fixedname_name(&principal),
				      tctx->mctx);
	if (result == DNS_R_INVALIDTKEY) {
		if (tsigkey != NULL)
			dns_tsigkey_detach(&tsigkey);
		tkeyout->error = dns_tsigerror_badkey;
		tkey_log("process_gsstkey(): dns_tsigerror_badkey");    /* XXXSRA */
		return (ISC_R_SUCCESS);
	}
	if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS)
		goto failure;
	/*
	 * XXXDCL Section 4.1.3: Limit GSS_S_CONTINUE_NEEDED to 10 times.
	 */

	isc_stdtime_get(&now);

	if (tsigkey == NULL) {
#ifdef GSSAPI
		OM_uint32 gret, minor, lifetime;
#endif
		isc_uint32_t expire;

		RETERR(dst_key_fromgssapi(name, gss_ctx, ring->mctx,
					  &dstkey, &intoken));
		/*
		 * Limit keys to 1 hour or the context's lifetime whichever
		 * is smaller.
		 */
		expire = now + 3600;
#ifdef GSSAPI
		gret = gss_context_time(&minor, gss_ctx, &lifetime);
		if (gret == GSS_S_COMPLETE && now + lifetime < expire)
			expire = now + lifetime;
#endif
		RETERR(dns_tsigkey_createfromkey(name, &tkeyin->algorithm,
						 dstkey, ISC_TRUE,
						 dns_fixedname_name(&principal),
						 now, expire, ring->mctx, ring,
						 NULL));
		dst_key_free(&dstkey);
		tkeyout->inception = now;
		tkeyout->expire = expire;
	} else {
		tkeyout->inception = tsigkey->inception;
		tkeyout->expire = tsigkey->expire;
		dns_tsigkey_detach(&tsigkey);
	}

	if (outtoken) {
		tkeyout->key = isc_mem_get(tkeyout->mctx,
					   isc_buffer_usedlength(outtoken));
		if (tkeyout->key == NULL) {
			result = ISC_R_NOMEMORY;
			goto failure;
		}
		tkeyout->keylen = isc_buffer_usedlength(outtoken);
		memmove(tkeyout->key, isc_buffer_base(outtoken),
		       isc_buffer_usedlength(outtoken));
		isc_buffer_free(&outtoken);
	} else {
		tkeyout->key = isc_mem_get(tkeyout->mctx, tkeyin->keylen);
		if (tkeyout->key == NULL) {
			result = ISC_R_NOMEMORY;
			goto failure;
		}
		tkeyout->keylen = tkeyin->keylen;
		memmove(tkeyout->key, tkeyin->key, tkeyin->keylen);
	}

	tkeyout->error = dns_rcode_noerror;

	tkey_log("process_gsstkey(): dns_tsigerror_noerror");   /* XXXSRA */

	return (ISC_R_SUCCESS);

failure:
	if (tsigkey != NULL)
		dns_tsigkey_detach(&tsigkey);

	if (dstkey != NULL)
		dst_key_free(&dstkey);

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

	tkey_log("process_gsstkey(): %s",
		isc_result_totext(result));	/* XXXSRA */

	return (result);
}
static void
sendquery(isc_task_t *task, isc_event_t *event) {
	struct in_addr inaddr;
	isc_sockaddr_t address;
	isc_region_t r;
	isc_result_t result;
	dns_fixedname_t keyname;
	dns_fixedname_t ownername;
	isc_buffer_t namestr, keybuf;
	unsigned char keydata[9];
	dns_message_t *query;
	dns_request_t *request;
	static char keystr[] = "0123456789ab";

	isc_event_free(&event);

	result = ISC_R_FAILURE;
	if (inet_pton(AF_INET, "10.53.0.1", &inaddr) != 1)
		CHECK("inet_pton", result);
	isc_sockaddr_fromin(&address, &inaddr, PORT);

	dns_fixedname_init(&keyname);
	isc_buffer_constinit(&namestr, "tkeytest.", 9);
	isc_buffer_add(&namestr, 9);
	result = dns_name_fromtext(dns_fixedname_name(&keyname), &namestr,
				   NULL, 0, NULL);
	CHECK("dns_name_fromtext", result);

	dns_fixedname_init(&ownername);
	isc_buffer_constinit(&namestr, ownername_str, strlen(ownername_str));
	isc_buffer_add(&namestr, strlen(ownername_str));
	result = dns_name_fromtext(dns_fixedname_name(&ownername), &namestr,
				   NULL, 0, NULL);
	CHECK("dns_name_fromtext", result);

	isc_buffer_init(&keybuf, keydata, 9);
	result = isc_base64_decodestring(keystr, &keybuf);
	CHECK("isc_base64_decodestring", result);

	isc_buffer_usedregion(&keybuf, &r);

	initialkey = NULL;
	result = dns_tsigkey_create(dns_fixedname_name(&keyname),
				    DNS_TSIG_HMACMD5_NAME,
				    isc_buffer_base(&keybuf),
				    isc_buffer_usedlength(&keybuf),
				    ISC_FALSE, NULL, 0, 0, mctx, ring,
				    &initialkey);
	CHECK("dns_tsigkey_create", result);

	query = NULL;
	result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &query);
	CHECK("dns_message_create", result);

	result = dns_tkey_builddhquery(query, ourkey,
				       dns_fixedname_name(&ownername),
				       DNS_TSIG_HMACMD5_NAME, &nonce, 3600);
	CHECK("dns_tkey_builddhquery", result);

	request = NULL;
	result = dns_request_create(requestmgr, query, &address,
				    DNS_REQUESTOPT_TCP, initialkey,
				    TIMEOUT, task, recvquery, query,
				    &request);
	CHECK("dns_request_create", result);
}
Exemple #4
0
static void
register_keys(const cfg_obj_t *control, const cfg_obj_t *keylist,
	      controlkeylist_t *keyids, isc_mem_t *mctx, const char *socktext)
{
	controlkey_t *keyid, *next;
	const cfg_obj_t *keydef;
	char secret[1024];
	isc_buffer_t b;
	isc_result_t result;

	/*
	 * Find the keys corresponding to the keyids used by this listener.
	 */
	for (keyid = ISC_LIST_HEAD(*keyids); keyid != NULL; keyid = next) {
		next = ISC_LIST_NEXT(keyid, link);

		result = cfgkeylist_find(keylist, keyid->keyname, &keydef);
		if (result != ISC_R_SUCCESS) {
			cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
				    "couldn't find key '%s' for use with "
				    "command channel %s",
				    keyid->keyname, socktext);
			ISC_LIST_UNLINK(*keyids, keyid, link);
			free_controlkey(keyid, mctx);
		} else {
			const cfg_obj_t *algobj = NULL;
			const cfg_obj_t *secretobj = NULL;
			const char *algstr = NULL;
			const char *secretstr = NULL;
			unsigned int algtype;

			(void)cfg_map_get(keydef, "algorithm", &algobj);
			(void)cfg_map_get(keydef, "secret", &secretobj);
			INSIST(algobj != NULL && secretobj != NULL);

			algstr = cfg_obj_asstring(algobj);
			secretstr = cfg_obj_asstring(secretobj);

			if (ns_config_getkeyalgorithm2(algstr, NULL,
					&algtype, NULL) != ISC_R_SUCCESS)
			{
				cfg_obj_log(control, ns_g_lctx,
					    ISC_LOG_WARNING,
					    "unsupported algorithm '%s' in "
					    "key '%s' for use with command "
					    "channel %s",
					    algstr, keyid->keyname, socktext);
				ISC_LIST_UNLINK(*keyids, keyid, link);
				free_controlkey(keyid, mctx);
				continue;
			}

			keyid->algorithm = algtype;
			isc_buffer_init(&b, secret, sizeof(secret));
			result = isc_base64_decodestring(secretstr, &b);

			if (result != ISC_R_SUCCESS) {
				cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING,
					    "secret for key '%s' on "
					    "command channel %s: %s",
					    keyid->keyname, socktext,
					    isc_result_totext(result));
				ISC_LIST_UNLINK(*keyids, keyid, link);
				free_controlkey(keyid, mctx);
				continue;
			}

			keyid->secret.length = isc_buffer_usedlength(&b);
			keyid->secret.base = isc_mem_get(mctx,
							 keyid->secret.length);
			if (keyid->secret.base == NULL) {
				cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING,
					   "couldn't register key '%s': "
					   "out of memory", keyid->keyname);
				ISC_LIST_UNLINK(*keyids, keyid, link);
				free_controlkey(keyid, mctx);
				break;
			}
			memmove(keyid->secret.base, isc_buffer_base(&b),
				keyid->secret.length);
		}
	}
}
Exemple #5
0
static void
lookup_done(isc_task_t *task, isc_event_t *event) {
	ns_lwdclient_t *client;
	ns_lwdclientmgr_t *cm;
	dns_lookupevent_t *levent;
	lwres_buffer_t lwb;
	dns_name_t *name;
	dns_rdataset_t *rdataset;
	dns_rdataset_t *sigrdataset;
	isc_result_t result;
	lwres_result_t lwresult;
	isc_region_t r;
	isc_buffer_t b;
	lwres_grbnresponse_t *grbn;
	int i;

	REQUIRE(event != NULL);

	UNUSED(task);

	lwb.base = NULL;
	client = event->ev_arg;
	cm = client->clientmgr;
	INSIST(client->lookup == (dns_lookup_t *)event->ev_sender);

	levent = (dns_lookupevent_t *)event;
	grbn = &client->grbn;

	ns_lwdclient_log(50, "lookup event result = %s",
			 isc_result_totext(levent->result));

	result = levent->result;
	if (result != ISC_R_SUCCESS) {
		dns_lookup_destroy(&client->lookup);
		isc_event_free(&event);
		levent = NULL;

		switch (result) {
		case DNS_R_NXDOMAIN:
		case DNS_R_NCACHENXDOMAIN:
			result = ns_lwsearchctx_next(&client->searchctx);
			if (result != ISC_R_SUCCESS)
				lwresult = LWRES_R_NOTFOUND;
			else {
				start_lookup(client);
				return;
			}
			break;
		case DNS_R_NXRRSET:
		case DNS_R_NCACHENXRRSET:
			lwresult = LWRES_R_TYPENOTFOUND;
			break;
		default:
			lwresult = LWRES_R_FAILURE;
		}
		ns_lwdclient_errorpktsend(client, lwresult);
		return;
	}

	name = levent->name;
	b = client->recv_buffer;

	grbn->flags = 0;

	grbn->nrdatas = 0;
	grbn->rdatas = NULL;
	grbn->rdatalen = NULL;

	grbn->nsigs = 0;
	grbn->sigs = NULL;
	grbn->siglen = NULL;

	result = dns_name_totext(name, ISC_TRUE, &client->recv_buffer);
	if (result != ISC_R_SUCCESS)
		goto out;
	grbn->realname = (char *)isc_buffer_used(&b);
	grbn->realnamelen = isc_buffer_usedlength(&client->recv_buffer) -
			    isc_buffer_usedlength(&b);
	ns_lwdclient_log(50, "found name '%.*s'", grbn->realnamelen,
			 grbn->realname);

	grbn->rdclass = cm->view->rdclass;
	grbn->rdtype = client->rdtype;

	rdataset = levent->rdataset;
	if (rdataset != NULL) {
		/* The normal case */
		grbn->nrdatas = dns_rdataset_count(rdataset);
		grbn->rdatas = isc_mem_get(cm->mctx, grbn->nrdatas *
					   sizeof(unsigned char *));
		if (grbn->rdatas == NULL)
			goto out;
		grbn->rdatalen = isc_mem_get(cm->mctx, grbn->nrdatas *
					     sizeof(lwres_uint16_t));
		if (grbn->rdatalen == NULL)
			goto out;

		i = 0;
		result = fill_array(&i, rdataset, grbn->nrdatas, grbn->rdatas,
				    grbn->rdatalen);
		if (result != ISC_R_SUCCESS)
			goto out;
		INSIST(i == grbn->nrdatas);
		grbn->ttl = rdataset->ttl;
		if (rdataset->trust == dns_trust_secure)
			grbn->flags |= LWRDATA_VALIDATED;
	} else {
		/* The SIG query case */
		result = iterate_node(grbn, levent->db, levent->node,
				      cm->mctx);
		if (result != ISC_R_SUCCESS)
			goto out;
	}
	ns_lwdclient_log(50, "filled in %d rdata%s", grbn->nrdatas,
			 (grbn->nrdatas == 1) ? "" : "s");

	sigrdataset = levent->sigrdataset;
	if (sigrdataset != NULL) {
		grbn->nsigs = dns_rdataset_count(sigrdataset);
		grbn->sigs = isc_mem_get(cm->mctx, grbn->nsigs *
					 sizeof(unsigned char *));
		if (grbn->sigs == NULL)
			goto out;
		grbn->siglen = isc_mem_get(cm->mctx, grbn->nsigs *
					   sizeof(lwres_uint16_t));
		if (grbn->siglen == NULL)
			goto out;

		i = 0;
		result = fill_array(&i, sigrdataset, grbn->nsigs, grbn->sigs,
				    grbn->siglen);
		if (result != ISC_R_SUCCESS)
			goto out;
		INSIST(i == grbn->nsigs);
		ns_lwdclient_log(50, "filled in %d signature%s", grbn->nsigs,
				 (grbn->nsigs == 1) ? "" : "s");
	}

	/*
	 * Render the packet.
	 */
	client->pkt.recvlength = LWRES_RECVLENGTH;
	client->pkt.authtype = 0; /* XXXMLG */
	client->pkt.authlength = 0;
	client->pkt.result = LWRES_R_SUCCESS;

	lwresult = lwres_grbnresponse_render(cm->lwctx,
					     grbn, &client->pkt, &lwb);
	if (lwresult != LWRES_R_SUCCESS)
		goto out;

	isc_mem_put(cm->mctx, grbn->rdatas,
		    grbn->nrdatas * sizeof(unsigned char *));
	isc_mem_put(cm->mctx, grbn->rdatalen,
		    grbn->nrdatas * sizeof(lwres_uint16_t));

	if (grbn->sigs != NULL)
		isc_mem_put(cm->mctx, grbn->sigs,
			    grbn->nsigs * sizeof(unsigned char *));
	if (grbn->siglen != NULL)
		isc_mem_put(cm->mctx, grbn->siglen,
			    grbn->nsigs * sizeof(lwres_uint16_t));

	r.base = lwb.base;
	r.length = lwb.used;
	client->sendbuf = r.base;
	client->sendlength = r.length;
	result = ns_lwdclient_sendreply(client, &r);
	if (result != ISC_R_SUCCESS)
		goto out2;

	NS_LWDCLIENT_SETSEND(client);

	dns_lookup_destroy(&client->lookup);
	isc_event_free(&event);

	return;

 out:
	if (grbn->rdatas != NULL)
		isc_mem_put(cm->mctx, grbn->rdatas,
			    grbn->nrdatas * sizeof(unsigned char *));
	if (grbn->rdatalen != NULL)
		isc_mem_put(cm->mctx, grbn->rdatalen,
			    grbn->nrdatas * sizeof(lwres_uint16_t));

	if (grbn->sigs != NULL)
		isc_mem_put(cm->mctx, grbn->sigs,
			    grbn->nsigs * sizeof(unsigned char *));
	if (grbn->siglen != NULL)
		isc_mem_put(cm->mctx, grbn->siglen,
			    grbn->nsigs * sizeof(lwres_uint16_t));
 out2:
	if (client->lookup != NULL)
		dns_lookup_destroy(&client->lookup);
	if (lwb.base != NULL)
		lwres_context_freemem(cm->lwctx, lwb.base, lwb.length);

		isc_event_free(&event);

	ns_lwdclient_log(50, "error constructing getrrsetbyname response");
	ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
}
Exemple #6
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_create2(key->key, mctx,
					  DNS_LOGCATEGORY_DNSSEC, &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);
	dns_rdataset_init(dataset);
	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);
}
Exemple #7
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);
}
Exemple #8
0
int
main(int argc, char **argv)  {
	isc_buffer_t buf;
	unsigned char key[1024];
	char secret[1024];
	char base64[(1024*4)/3];
	isc_region_t r;
	isc_result_t result;

	if (argc != 3) {
		fprintf(stderr, "Usage:\t%s algorithm secret\n", argv[0]);
		fprintf(stderr, "\talgorithm: (MD5 | SHA1 | SHA224 | "
				"SHA256 | SHA384 | SHA512)\n");
		return (1);
	}

	isc_buffer_init(&buf, secret, sizeof(secret));
	result = isc_base64_decodestring(argv[2], &buf);
	if (result != ISC_R_SUCCESS) {
		fprintf(stderr, "error: %s\n", isc_result_totext(result));
		return (1);
	}
	isc__buffer_usedregion(&buf, &r);

	if (!strcasecmp(argv[1], "md5") ||
	    !strcasecmp(argv[1], "hmac-md5")) {
		if (r.length > HMAC_LEN) {
			isc_md5_t md5ctx;
			isc_md5_init(&md5ctx);
			isc_md5_update(&md5ctx, r.base, r.length);
			isc_md5_final(&md5ctx, key);

			r.base = key;
			r.length = ISC_MD5_DIGESTLENGTH;
		}
	} else if (!strcasecmp(argv[1], "sha1") ||
		   !strcasecmp(argv[1], "hmac-sha1")) {
		if (r.length > ISC_SHA1_DIGESTLENGTH) {
			isc_sha1_t sha1ctx;
			isc_sha1_init(&sha1ctx);
			isc_sha1_update(&sha1ctx, r.base, r.length);
			isc_sha1_final(&sha1ctx, key);

			r.base = key;
			r.length = ISC_SHA1_DIGESTLENGTH;
		}
	} else if (!strcasecmp(argv[1], "sha224") ||
		   !strcasecmp(argv[1], "hmac-sha224")) {
		if (r.length > ISC_SHA224_DIGESTLENGTH) {
			isc_sha224_t sha224ctx;
			isc_sha224_init(&sha224ctx);
			isc_sha224_update(&sha224ctx, r.base, r.length);
			isc_sha224_final(key, &sha224ctx);

			r.base = key;
			r.length = ISC_SHA224_DIGESTLENGTH;
		}
	} else if (!strcasecmp(argv[1], "sha256") ||
		   !strcasecmp(argv[1], "hmac-sha256")) {
		if (r.length > ISC_SHA256_DIGESTLENGTH) {
			isc_sha256_t sha256ctx;
			isc_sha256_init(&sha256ctx);
			isc_sha256_update(&sha256ctx, r.base, r.length);
			isc_sha256_final(key, &sha256ctx);

			r.base = key;
			r.length = ISC_SHA256_DIGESTLENGTH;
		}
	} else if (!strcasecmp(argv[1], "sha384") ||
		   !strcasecmp(argv[1], "hmac-sha384")) {
		if (r.length > ISC_SHA384_DIGESTLENGTH) {
			isc_sha384_t sha384ctx;
			isc_sha384_init(&sha384ctx);
			isc_sha384_update(&sha384ctx, r.base, r.length);
			isc_sha384_final(key, &sha384ctx);

			r.base = key;
			r.length = ISC_SHA384_DIGESTLENGTH;
		}
	} else if (!strcasecmp(argv[1], "sha512") ||
		   !strcasecmp(argv[1], "hmac-sha512")) {
		if (r.length > ISC_SHA512_DIGESTLENGTH) {
			isc_sha512_t sha512ctx;
			isc_sha512_init(&sha512ctx);
			isc_sha512_update(&sha512ctx, r.base, r.length);
			isc_sha512_final(key, &sha512ctx);

			r.base = key;
			r.length = ISC_SHA512_DIGESTLENGTH;
		}
	} else {
		fprintf(stderr, "unknown hmac/digest algorithm: %s\n", argv[1]);
		return (1);
	}

	isc_buffer_init(&buf, base64, sizeof(base64));
	result = isc_base64_totext(&r, 0, "", &buf);
	if (result != ISC_R_SUCCESS) {
		fprintf(stderr, "error: %s\n", isc_result_totext(result));
		return (1);
	}
	fprintf(stdout, "%.*s\n", (int)isc_buffer_usedlength(&buf), base64);
	return (0);
}
ATF_TC_BODY(isdn, tc) {
	struct {
		unsigned char data[64];
		size_t len;
		isc_boolean_t ok;
	} test_data[] = {
		{
			/* "" */
			{ 0x00 }, 1, ISC_TRUE
		},
		{
			/* "\001" */
			{ 0x1, 0x01 }, 2, ISC_TRUE
		},
		{
			/* "\001" "" */
			{ 0x1, 0x01, 0x00 }, 3, ISC_TRUE
		},
		{
			/* "\000" "\001" */
			{ 0x1, 0x01, 0x01, 0x01 }, 4, ISC_TRUE
		},
		{
			/* sentinal */
			{ 0x00 }, 0, ISC_FALSE
		}
	};
	unsigned char buf1[1024];
	unsigned char buf2[1024];
	isc_buffer_t source, target1, target2;
	dns_rdata_t rdata;
	dns_decompress_t dctx;
	isc_result_t result;
	size_t i;
	dns_rdata_isdn_t isdn;

	UNUSED(tc);

	for (i = 0; test_data[i].len != 0; i++) {
		isc_buffer_init(&source, test_data[i].data, test_data[i].len);
		isc_buffer_add(&source, test_data[i].len);
		isc_buffer_setactive(&source, test_data[i].len);
		isc_buffer_init(&target1, buf1, sizeof(buf1));
		dns_rdata_init(&rdata);
		dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
		result = dns_rdata_fromwire(&rdata, dns_rdataclass_in,
					    dns_rdatatype_isdn, &source,
					    &dctx, 0, &target1);
		dns_decompress_invalidate(&dctx);
		if (test_data[i].ok)
			ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
		else
			ATF_REQUIRE(result != ISC_R_SUCCESS);
		if (result != ISC_R_SUCCESS)
			continue;
		result = dns_rdata_tostruct(&rdata, &isdn, NULL);
		ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
		isc_buffer_init(&target2, buf2, sizeof(buf2));
		dns_rdata_reset(&rdata);
		result = dns_rdata_fromstruct(&rdata, dns_rdataclass_in,
					      dns_rdatatype_isdn, &isdn,
					      &target2);
		ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
		ATF_REQUIRE_EQ(isc_buffer_usedlength(&target2),
						     test_data[i].len);
		ATF_REQUIRE_EQ(memcmp(buf2, test_data[i].data,
				      test_data[i].len), 0);
	}
}
static isc_result_t
process_gsstkey(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;
	dst_key_t *dstkey = NULL;
	void *gssctx = NULL;
	isc_stdtime_t now;
	isc_region_t intoken;
	unsigned char array[1024];
	isc_buffer_t outtoken;

	UNUSED(namelist);

	if (tctx->gsscred == NULL)
		return (ISC_R_NOPERM);

	if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPI_NAME) &&
	    !dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPIMS_NAME)) {
		tkeyout->error = dns_tsigerror_badalg;
		return (ISC_R_SUCCESS);
	}

	intoken.base = tkeyin->key;
	intoken.length = tkeyin->keylen;

	isc_buffer_init(&outtoken, array, sizeof(array));
	RETERR(dst_gssapi_acceptctx(name, tctx->gsscred, &intoken,
				    &outtoken, &gssctx));

	dstkey = NULL;
	RETERR(dst_key_fromgssapi(name, gssctx, msg->mctx, &dstkey));

	result = dns_tsigkey_createfromkey(name, &tkeyin->algorithm,
					   dstkey, ISC_TRUE, signer,
					   tkeyin->inception, tkeyin->expire,
					   msg->mctx, ring, NULL);
#if 1
	if (result != ISC_R_SUCCESS)
		goto failure;
#else
	if (result == ISC_R_NOTFOUND) {
		tkeyout->error = dns_tsigerror_badalg;
		return (ISC_R_SUCCESS);
	}
	if (result != ISC_R_SUCCESS)
		goto failure;
#endif

	/* This key is good for a long time */
	isc_stdtime_get(&now);
	tkeyout->inception = tkeyin->inception;
	tkeyout->expire = tkeyin->expire;

	tkeyout->key = isc_mem_get(msg->mctx,
				   isc_buffer_usedlength(&outtoken));
	if (tkeyout->key == NULL) {
		result = ISC_R_NOMEMORY;
		goto failure;
	}
	tkeyout->keylen = isc_buffer_usedlength(&outtoken);
	memcpy(tkeyout->key, isc_buffer_base(&outtoken), tkeyout->keylen);

	return (ISC_R_SUCCESS);

 failure:
	if (dstkey != NULL)
		dst_key_free(&dstkey);

	return (result);
}
Exemple #11
0
/*
 * Convert a resolv.conf file into a config structure.
 */
isc_result_t
ns_lwresd_parseeresolvconf(isc_mem_t *mctx, cfg_parser_t *pctx,
			   cfg_obj_t **configp)
{
	char text[4096];
	char str[16];
	isc_buffer_t b;
	lwres_context_t *lwctx = NULL;
	lwres_conf_t *lwc = NULL;
	isc_sockaddr_t sa;
	isc_netaddr_t na;
	int i;
	isc_result_t result;
	lwres_result_t lwresult;

	lwctx = NULL;
	lwresult = lwres_context_create(&lwctx, mctx, ns__lwresd_memalloc,
					ns__lwresd_memfree,
					LWRES_CONTEXT_SERVERMODE);
	if (lwresult != LWRES_R_SUCCESS) {
		result = ISC_R_NOMEMORY;
		goto cleanup;
	}

	lwresult = lwres_conf_parse(lwctx, lwresd_g_resolvconffile);
	if (lwresult != LWRES_R_SUCCESS) {
		result = DNS_R_SYNTAX;
		goto cleanup;
	}

	lwc = lwres_conf_get(lwctx);
	INSIST(lwc != NULL);

	isc_buffer_init(&b, text, sizeof(text));

	CHECK(buffer_putstr(&b, "options {\n"));

	/*
	 * Build the list of forwarders.
	 */
	if (lwc->nsnext > 0) {
		CHECK(buffer_putstr(&b, "\tforwarders {\n"));

		for (i = 0; i < lwc->nsnext; i++) {
			CHECK(lwaddr_sockaddr_fromlwresaddr(
							&sa,
							&lwc->nameservers[i],
							ns_g_port));
			isc_netaddr_fromsockaddr(&na, &sa);
			CHECK(buffer_putstr(&b, "\t\t"));
			CHECK(isc_netaddr_totext(&na, &b));
			CHECK(buffer_putstr(&b, ";\n"));
		}
		CHECK(buffer_putstr(&b, "\t};\n"));
	}

	/*
	 * Build the sortlist
	 */
	if (lwc->sortlistnxt > 0) {
		CHECK(buffer_putstr(&b, "\tsortlist {\n"));
		CHECK(buffer_putstr(&b, "\t\t{\n"));
		CHECK(buffer_putstr(&b, "\t\t\tany;\n"));
		CHECK(buffer_putstr(&b, "\t\t\t{\n"));
		for (i = 0; i < lwc->sortlistnxt; i++) {
			lwres_addr_t *lwaddr = &lwc->sortlist[i].addr;
			lwres_addr_t *lwmask = &lwc->sortlist[i].mask;
			unsigned int mask;

			CHECK(lwaddr_sockaddr_fromlwresaddr(&sa, lwmask, 0));
			isc_netaddr_fromsockaddr(&na, &sa);
			result = isc_netaddr_masktoprefixlen(&na, &mask);
			if (result != ISC_R_SUCCESS) {
				char addrtext[ISC_NETADDR_FORMATSIZE];
				isc_netaddr_format(&na, addrtext,
						   sizeof(addrtext));
				isc_log_write(ns_g_lctx,
					      NS_LOGCATEGORY_GENERAL,
					      NS_LOGMODULE_LWRESD,
					      ISC_LOG_ERROR,
					      "processing sortlist: '%s' is "
					      "not a valid netmask",
					      addrtext);
				goto cleanup;
			}

			CHECK(lwaddr_sockaddr_fromlwresaddr(&sa, lwaddr, 0));
			isc_netaddr_fromsockaddr(&na, &sa);

			CHECK(buffer_putstr(&b, "\t\t\t\t"));
			CHECK(isc_netaddr_totext(&na, &b));
			snprintf(str, sizeof(str), "%u", mask);
			CHECK(buffer_putstr(&b, "/"));
			CHECK(buffer_putstr(&b, str));
			CHECK(buffer_putstr(&b, ";\n"));
		}
		CHECK(buffer_putstr(&b, "\t\t\t};\n"));
		CHECK(buffer_putstr(&b, "\t\t};\n"));
		CHECK(buffer_putstr(&b, "\t};\n"));
	}

	CHECK(buffer_putstr(&b, "};\n\n"));

	CHECK(buffer_putstr(&b, "lwres {\n"));

	/*
	 * Build the search path
	 */
	if (lwc->searchnxt > 0) {
		if (lwc->searchnxt > 0) {
			CHECK(buffer_putstr(&b, "\tsearch {\n"));
			for (i = 0; i < lwc->searchnxt; i++) {
				CHECK(buffer_putstr(&b, "\t\t\""));
				CHECK(buffer_putstr(&b, lwc->search[i]));
				CHECK(buffer_putstr(&b, "\";\n"));
			}
			CHECK(buffer_putstr(&b, "\t};\n"));
		}
	}

	/*
	 * Build the ndots line
	 */
	if (lwc->ndots != 1) {
		CHECK(buffer_putstr(&b, "\tndots "));
		snprintf(str, sizeof(str), "%u", lwc->ndots);
		CHECK(buffer_putstr(&b, str));
		CHECK(buffer_putstr(&b, ";\n"));
	}

	/*
	 * Build the listen-on line
	 */
	if (lwc->lwnext > 0) {
		CHECK(buffer_putstr(&b, "\tlisten-on {\n"));

		for (i = 0; i < lwc->lwnext; i++) {
			CHECK(lwaddr_sockaddr_fromlwresaddr(&sa,
							    &lwc->lwservers[i],
							    0));
			isc_netaddr_fromsockaddr(&na, &sa);
			CHECK(buffer_putstr(&b, "\t\t"));
			CHECK(isc_netaddr_totext(&na, &b));
			CHECK(buffer_putstr(&b, ";\n"));
		}
		CHECK(buffer_putstr(&b, "\t};\n"));
	}

	CHECK(buffer_putstr(&b, "};\n"));

#if 0
	printf("%.*s\n",
	       (int)isc_buffer_usedlength(&b),
	       (char *)isc_buffer_base(&b));
#endif

	lwres_conf_clear(lwctx);
	lwres_context_destroy(&lwctx);

	return (cfg_parse_buffer(pctx, &b, &cfg_type_namedconf, configp));

 cleanup:

	if (lwctx != NULL) {
		lwres_conf_clear(lwctx);
		lwres_context_destroy(&lwctx);
	}

	return (result);
}
Exemple #12
0
int main (int argc, char **argv)
{
    dns_fixedname_t fixed;

    dns_name_t *name;

    isc_buffer_t buffer;

    isc_region_t region;

    isc_result_t result;

    unsigned char hash[NSEC3_MAX_HASH_LENGTH];

    unsigned char salt[DNS_NSEC3_SALTSIZE];

    unsigned char text[1024];

    unsigned int hash_alg;

    unsigned int length;

    unsigned int iterations;

    unsigned int salt_length;

    if (argc != 5)
        usage ();

    if (strcmp (argv[1], "-") == 0)
    {
        salt_length = 0;
        salt[0] = 0;
    }
    else
    {
        isc_buffer_init (&buffer, salt, sizeof (salt));
        result = isc_hex_decodestring (argv[1], &buffer);
        check_result (result, "isc_hex_decodestring(salt)");
        salt_length = isc_buffer_usedlength (&buffer);
        if (salt_length > DNS_NSEC3_SALTSIZE)
            fatal ("salt too long");
    }
    hash_alg = atoi (argv[2]);
    if (hash_alg > 255U)
        fatal ("hash algorithm too large");
    iterations = atoi (argv[3]);
    if (iterations > 0xffffU)
        fatal ("iterations to large");

    dns_fixedname_init (&fixed);
    name = dns_fixedname_name (&fixed);
    isc_buffer_init (&buffer, argv[4], strlen (argv[4]));
    isc_buffer_add (&buffer, strlen (argv[4]));
    result = dns_name_fromtext (name, &buffer, dns_rootname, 0, NULL);
    check_result (result, "dns_name_fromtext() failed");

    dns_name_downcase (name, name, NULL);
    length = isc_iterated_hash (hash, hash_alg, iterations, salt, salt_length, name->ndata, name->length);
    if (length == 0)
        fatal ("isc_iterated_hash failed");
    region.base = hash;
    region.length = length;
    isc_buffer_init (&buffer, text, sizeof (text));
    isc_base32hex_totext (&region, 1, "", &buffer);
    fprintf (stdout, "%.*s (salt=%s, hash=%u, iterations=%u)\n",
             (int) isc_buffer_usedlength (&buffer), text, argv[1], hash_alg, iterations);
    return (0);
}
Exemple #13
0
static inline isc_result_t
fromtext_keydata(ARGS_FROMTEXT) {
	isc_result_t result;
	isc_token_t token;
	dns_secalg_t alg;
	dns_secproto_t proto;
	dns_keyflags_t flags;
	isc_uint32_t refresh, addhd, removehd;

	REQUIRE(type == 65533);

	UNUSED(type);
	UNUSED(rdclass);
	UNUSED(origin);
	UNUSED(options);
	UNUSED(callbacks);

	/* refresh timer */
	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
				      ISC_FALSE));
	RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &refresh));
	RETERR(uint32_tobuffer(refresh, target));

	/* add hold-down */
	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
				      ISC_FALSE));
	RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &addhd));
	RETERR(uint32_tobuffer(addhd, target));

	/* remove hold-down */
	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
				      ISC_FALSE));
	RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &removehd));
	RETERR(uint32_tobuffer(removehd, target));

	/* flags */
	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
				      ISC_FALSE));
	RETTOK(dns_keyflags_fromtext(&flags, &token.value.as_textregion));
	RETERR(uint16_tobuffer(flags, target));

	/* protocol */
	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
				      ISC_FALSE));
	RETTOK(dns_secproto_fromtext(&proto, &token.value.as_textregion));
	RETERR(mem_tobuffer(target, &proto, 1));

	/* algorithm */
	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
				      ISC_FALSE));
	RETTOK(dns_secalg_fromtext(&alg, &token.value.as_textregion));
	RETERR(mem_tobuffer(target, &alg, 1));

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

	result = isc_base64_tobuffer(lexer, target, -1);
	if (result != ISC_R_SUCCESS)
		return (result);

	/* Ensure there's at least enough data to compute a key ID for MD5 */
	if (alg == DST_ALG_RSAMD5 && isc_buffer_usedlength(target) < 19)
		return (ISC_R_UNEXPECTEDEND);

	return (ISC_R_SUCCESS);
}
int
main(int argc, char **argv) {
	isc_boolean_t show_final_mem = ISC_FALSE;
	isc_buffer_t key_rawbuffer;
	isc_buffer_t key_txtbuffer;
	isc_region_t key_rawregion;
	isc_mem_t *mctx = NULL;
	isc_entropy_t *ectx = NULL;
	isc_entropysource_t *entropy_source = NULL;
	isc_result_t result = ISC_R_SUCCESS;
	dst_key_t *key = NULL;
	const char *keyname = NULL;
	const char *randomfile = NULL;
	const char *serveraddr = NULL;
	char key_rawsecret[64];
	char key_txtsecret[256];
	char *p;
	int ch;
	int port;
	int keysize;
	int entropy_flags = 0;
	int open_keyboard = ISC_ENTROPY_KEYBOARDMAYBE;
	struct in_addr addr4_dummy;
	struct in6_addr addr6_dummy;
	char *chrootdir = NULL;
	char *user = NULL;
	isc_boolean_t keyonly = ISC_FALSE;
	int len;

 	keydef = keyfile = RNDC_KEYFILE;

	result = isc_file_progname(*argv, program, sizeof(program));
	if (result != ISC_R_SUCCESS)
		memcpy(program, "rndc-confgen", 13);
	progname = program;

	keyname = DEFAULT_KEYNAME;
	keysize = DEFAULT_KEYLENGTH;
	serveraddr = DEFAULT_SERVER;
	port = DEFAULT_PORT;

	while ((ch = isc_commandline_parse(argc, argv,
					   "ab:c:hk:Mmp:r:s:t:u:Vy")) != -1) {
		switch (ch) {
		case 'a':
			keyonly = ISC_TRUE;
			break;
		case 'b':
			keysize = strtol(isc_commandline_argument, &p, 10);
			if (*p != '\0' || keysize < 0)
				fatal("-b requires a non-negative number");
			if (keysize < 1 || keysize > 512)
				fatal("-b must be in the range 1 through 512");
			break;
		case 'c':
			keyfile = isc_commandline_argument;
			break;
		case 'h':
			usage(0);
		case 'k':
		case 'y':	/* Compatible with rndc -y. */
			keyname = isc_commandline_argument;
			break;
		case 'M':
			isc_mem_debugging = ISC_MEM_DEBUGTRACE;
			break;

		case 'm':
			show_final_mem = ISC_TRUE;
			break;
		case 'p':
			port = strtol(isc_commandline_argument, &p, 10);
			if (*p != '\0' || port < 0 || port > 65535)
				fatal("port '%s' out of range",
				      isc_commandline_argument);
			break;
		case 'r':
			randomfile = isc_commandline_argument;
			break;
		case 's':
			serveraddr = isc_commandline_argument;
			if (inet_pton(AF_INET, serveraddr, &addr4_dummy) != 1 &&
			    inet_pton(AF_INET6, serveraddr, &addr6_dummy) != 1)
				fatal("-s should be an IPv4 or IPv6 address");
			break;
		case 't':
			chrootdir = isc_commandline_argument;
			break;
		case 'u':
			user = isc_commandline_argument;
			break;
		case 'V':
			verbose = ISC_TRUE;
			break;
		case '?':
			usage(1);
			break;
		default:
			fatal("unexpected error parsing command arguments: "
			      "got %c\n", ch);
			break;
		}
	}

	argc -= isc_commandline_index;
	argv += isc_commandline_index;

	if (argc > 0)
		usage(1);

	DO("create memory context", isc_mem_create(0, 0, &mctx));

	DO("create entropy context", isc_entropy_create(mctx, &ectx));

	if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) {
		randomfile = NULL;
		open_keyboard = ISC_ENTROPY_KEYBOARDYES;
	}
	DO("start entropy source", isc_entropy_usebestsource(ectx,
							     &entropy_source,
							     randomfile,
							     open_keyboard));

	entropy_flags = ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY;

	DO("initialize dst library", dst_lib_init(mctx, ectx, entropy_flags));

	DO("generate key", dst_key_generate(dns_rootname, DST_ALG_HMACMD5,
					    keysize, 0, 0,
					    DNS_KEYPROTO_ANY,
					    dns_rdataclass_in, mctx, &key));

	isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));

	DO("dump key to buffer", dst_key_tobuffer(key, &key_rawbuffer));

	isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
	isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);

	DO("bsse64 encode secret", isc_base64_totext(&key_rawregion, -1, "",
						     &key_txtbuffer));

	/*
	 * Shut down the entropy source now so the "stop typing" message
	 * does not muck with the output.
	 */
	if (entropy_source != NULL)
		isc_entropy_destroysource(&entropy_source);

	if (key != NULL)
		dst_key_free(&key);

	isc_entropy_detach(&ectx);
	dst_lib_destroy();

	if (keyonly) {
		write_key_file(keyfile, chrootdir == NULL ? user : NULL,
			       keyname, &key_txtbuffer);

		if (chrootdir != NULL) {
			char *buf;
			len = strlen(chrootdir) + strlen(keyfile) + 2;
			buf = isc_mem_get(mctx, len);
			if (buf == NULL)
				fatal("isc_mem_get(%d) failed\n", len);
			snprintf(buf, len, "%s%s%s", chrootdir,
				 (*keyfile != '/') ? "/" : "", keyfile);
			
			write_key_file(buf, user, keyname, &key_txtbuffer);
			isc_mem_put(mctx, buf, len);
		}
	} else {
		printf("\
# Start of rndc.conf\n\
key \"%s\" {\n\
	algorithm hmac-md5;\n\
	secret \"%.*s\";\n\
};\n\
\n\
options {\n\
	default-key \"%s\";\n\
	default-server %s;\n\
	default-port %d;\n\
};\n\
# End of rndc.conf\n\
\n\
# Use with the following in named.conf, adjusting the allow list as needed:\n\
# key \"%s\" {\n\
# 	algorithm hmac-md5;\n\
# 	secret \"%.*s\";\n\
# };\n\
# \n\
# controls {\n\
# 	inet %s port %d\n\
# 		allow { %s; } keys { \"%s\"; };\n\
# };\n\
# End of named.conf\n",
		       keyname,
		       (int)isc_buffer_usedlength(&key_txtbuffer),
		       (char *)isc_buffer_base(&key_txtbuffer),
		       keyname, serveraddr, port,
		       keyname,
		       (int)isc_buffer_usedlength(&key_txtbuffer),
		       (char *)isc_buffer_base(&key_txtbuffer),
		       serveraddr, port, serveraddr, keyname);
	}

	if (show_final_mem)
		isc_mem_stats(mctx, stderr);

	isc_mem_destroy(&mctx);

	return (0);
}
Exemple #15
0
static void
isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev)
{
    isc_region_t r;
    isc_result_t result;
    isc_httpd_t *httpd = ev->ev_arg;
    isc_socketevent_t *sev = (isc_socketevent_t *)ev;
    isc_httpdurl_t *url;
    isc_time_t now;
    char datebuf[32];  /* Only need 30, but safety first */

    ENTER("recv");

    INSIST(ISC_HTTPD_ISRECV(httpd));

    if (sev->result != ISC_R_SUCCESS) {
        NOTICE("recv destroying client");
        destroy_client(&httpd);
        goto out;
    }

    result = process_request(httpd, sev->n);
    if (result == ISC_R_NOTFOUND) {
        if (httpd->recvlen >= HTTP_RECVLEN - 1) {
            destroy_client(&httpd);
            goto out;
        }
        r.base = (unsigned char *)httpd->recvbuf + httpd->recvlen;
        r.length = HTTP_RECVLEN - httpd->recvlen - 1;
        result = isc_socket_recv(httpd->sock, &r, 1, task,
                                 isc_httpd_recvdone, httpd);
        goto out;
    } else if (result != ISC_R_SUCCESS) {
        destroy_client(&httpd);
        goto out;
    }

    ISC_HTTPD_SETSEND(httpd);

    /*
     * XXXMLG Call function here.  Provide an add-header function
     * which will append the common headers to a response we generate.
     */
    isc_buffer_initnull(&httpd->bodybuffer);
    isc_time_now(&now);
    isc_time_formathttptimestamp(&now, datebuf, sizeof(datebuf));
    url = ISC_LIST_HEAD(httpd->mgr->urls);
    while (url != NULL) {
        if (strcmp(httpd->url, url->url) == 0)
            break;
        url = ISC_LIST_NEXT(url, link);
    }
    if (url == NULL)
        result = httpd->mgr->render_404(httpd->url, httpd->querystring,
                                        NULL,
                                        &httpd->retcode,
                                        &httpd->retmsg,
                                        &httpd->mimetype,
                                        &httpd->bodybuffer,
                                        &httpd->freecb,
                                        &httpd->freecb_arg);
    else
        result = url->action(httpd->url, httpd->querystring,
                             url->action_arg,
                             &httpd->retcode, &httpd->retmsg,
                             &httpd->mimetype, &httpd->bodybuffer,
                             &httpd->freecb, &httpd->freecb_arg);
    if (result != ISC_R_SUCCESS) {
        destroy_client(&httpd);
        goto out;
    }

    isc_httpd_response(httpd);
    isc_httpd_addheader(httpd, "Content-Type", httpd->mimetype);
    isc_httpd_addheader(httpd, "Date", datebuf);
    isc_httpd_addheader(httpd, "Expires", datebuf);
    isc_httpd_addheader(httpd, "Last-Modified", datebuf);
    isc_httpd_addheader(httpd, "Pragma: no-cache", NULL);
    isc_httpd_addheader(httpd, "Cache-Control: no-cache", NULL);
    isc_httpd_addheader(httpd, "Server: libisc", NULL);
    isc_httpd_addheaderuint(httpd, "Content-Length",
                            isc_buffer_usedlength(&httpd->bodybuffer));
    isc_httpd_endheaders(httpd);  /* done */

    ISC_LIST_APPEND(httpd->bufflist, &httpd->headerbuffer, link);
    /*
     * Link the data buffer into our send queue, should we have any data
     * rendered into it.  If no data is present, we won't do anything
     * with the buffer.
     */
    if (isc_buffer_length(&httpd->bodybuffer) > 0)
        ISC_LIST_APPEND(httpd->bufflist, &httpd->bodybuffer, link);

    result = isc_socket_sendv(httpd->sock, &httpd->bufflist, task,
                              isc_httpd_senddone, httpd);

out:
    isc_event_free(&ev);
    EXIT("recv");
}
Exemple #16
0
/*
 * Arrange to send as much as we can of "stream" without blocking.
 *
 * Requires:
 *	The stream iterator is initialized and points at an RR,
 *      or possibly at the end of the stream (that is, the
 *      _first method of the iterator has been called).
 */
static void
sendstream(xfrout_ctx_t *xfr) {
	dns_message_t *tcpmsg = NULL;
	dns_message_t *msg = NULL; /* Client message if UDP, tcpmsg if TCP */
	isc_result_t result;
	isc_region_t used;
	isc_region_t region;
	dns_rdataset_t *qrdataset;
	dns_name_t *msgname = NULL;
	dns_rdata_t *msgrdata = NULL;
	dns_rdatalist_t *msgrdl = NULL;
	dns_rdataset_t *msgrds = NULL;
	dns_compress_t cctx;
	isc_boolean_t cleanup_cctx = ISC_FALSE;
	isc_boolean_t is_tcp;

	int n_rrs;

	isc_buffer_clear(&xfr->buf);
	isc_buffer_clear(&xfr->txlenbuf);
	isc_buffer_clear(&xfr->txbuf);

	is_tcp = ISC_TF((xfr->client->attributes & NS_CLIENTATTR_TCP) != 0);
	if (!is_tcp) {
		/*
		 * In the UDP case, we put the response data directly into
		 * the client message.
		 */
		msg = xfr->client->message;
		CHECK(dns_message_reply(msg, ISC_TRUE));
	} else {
		/*
		 * TCP. Build a response dns_message_t, temporarily storing
		 * the raw, uncompressed owner names and RR data contiguously
		 * in xfr->buf.  We know that if the uncompressed data fits
		 * in xfr->buf, the compressed data will surely fit in a TCP
		 * message.
		 */

		CHECK(dns_message_create(xfr->mctx,
					 DNS_MESSAGE_INTENTRENDER, &tcpmsg));
		msg = tcpmsg;

		msg->id = xfr->id;
		msg->rcode = dns_rcode_noerror;
		msg->flags = DNS_MESSAGEFLAG_QR | DNS_MESSAGEFLAG_AA;
		if ((xfr->client->attributes & NS_CLIENTATTR_RA) != 0)
			msg->flags |= DNS_MESSAGEFLAG_RA;
		CHECK(dns_message_settsigkey(msg, xfr->tsigkey));
		CHECK(dns_message_setquerytsig(msg, xfr->lasttsig));
		if (xfr->lasttsig != NULL)
			isc_buffer_free(&xfr->lasttsig);

		/*
		 * Add a EDNS option to the message?
		 */
		if ((xfr->client->attributes & NS_CLIENTATTR_WANTOPT) != 0) {
			dns_rdataset_t *opt = NULL;

			CHECK(ns_client_addopt(xfr->client, msg, &opt));
			CHECK(dns_message_setopt(msg, opt));
			/*
			 * Add to first message only.
			 */
			xfr->client->attributes &= ~NS_CLIENTATTR_WANTNSID;
			xfr->client->attributes &= ~NS_CLIENTATTR_HAVEEXPIRE;
		}

		/*
		 * Account for reserved space.
		 */
		if (xfr->tsigkey != NULL)
			INSIST(msg->reserved != 0U);
		isc_buffer_add(&xfr->buf, msg->reserved);

		/*
		 * Include a question section in the first message only.
		 * BIND 8.2.1 will not recognize an IXFR if it does not
		 * have a question section.
		 */
		if (xfr->nmsg == 0) {
			dns_name_t *qname = NULL;
			isc_region_t r;

			/*
			 * Reserve space for the 12-byte message header
			 * and 4 bytes of question.
			 */
			isc_buffer_add(&xfr->buf, 12 + 4);

			qrdataset = NULL;
			result = dns_message_gettemprdataset(msg, &qrdataset);
			if (result != ISC_R_SUCCESS)
				goto failure;
			dns_rdataset_makequestion(qrdataset,
					xfr->client->message->rdclass,
					xfr->qtype);

			result = dns_message_gettempname(msg, &qname);
			if (result != ISC_R_SUCCESS)
				goto failure;
			dns_name_init(qname, NULL);
			isc_buffer_availableregion(&xfr->buf, &r);
			INSIST(r.length >= xfr->qname->length);
			r.length = xfr->qname->length;
			isc_buffer_putmem(&xfr->buf, xfr->qname->ndata,
					  xfr->qname->length);
			dns_name_fromregion(qname, &r);
			ISC_LIST_INIT(qname->list);
			ISC_LIST_APPEND(qname->list, qrdataset, link);

			dns_message_addname(msg, qname, DNS_SECTION_QUESTION);
		} else {
			/*
			 * Reserve space for the 12-byte message header
			 */
			isc_buffer_add(&xfr->buf, 12);
			msg->tcp_continuation = 1;
		}
	}

	/*
	 * Try to fit in as many RRs as possible, unless "one-answer"
	 * format has been requested.
	 */
	for (n_rrs = 0; ; n_rrs++) {
		dns_name_t *name = NULL;
		isc_uint32_t ttl;
		dns_rdata_t *rdata = NULL;

		unsigned int size;
		isc_region_t r;

		msgname = NULL;
		msgrdata = NULL;
		msgrdl = NULL;
		msgrds = NULL;

		xfr->stream->methods->current(xfr->stream,
					      &name, &ttl, &rdata);
		size = name->length + 10 + rdata->length;
		isc_buffer_availableregion(&xfr->buf, &r);
		if (size >= r.length) {
			/*
			 * RR would not fit.  If there are other RRs in the
			 * buffer, send them now and leave this RR to the
			 * next message.  If this RR overflows the buffer
			 * all by itself, fail.
			 *
			 * In theory some RRs might fit in a TCP message
			 * when compressed even if they do not fit when
			 * uncompressed, but surely we don't want
			 * to send such monstrosities to an unsuspecting
			 * slave.
			 */
			if (n_rrs == 0) {
				xfrout_log(xfr, ISC_LOG_WARNING,
					   "RR too large for zone transfer "
					   "(%d bytes)", size);
				/* XXX DNS_R_RRTOOLARGE? */
				result = ISC_R_NOSPACE;
				goto failure;
			}
			break;
		}

		if (isc_log_wouldlog(ns_g_lctx, XFROUT_RR_LOGLEVEL))
			log_rr(name, rdata, ttl); /* XXX */

		result = dns_message_gettempname(msg, &msgname);
		if (result != ISC_R_SUCCESS)
			goto failure;
		dns_name_init(msgname, NULL);
		isc_buffer_availableregion(&xfr->buf, &r);
		INSIST(r.length >= name->length);
		r.length = name->length;
		isc_buffer_putmem(&xfr->buf, name->ndata, name->length);
		dns_name_fromregion(msgname, &r);

		/* Reserve space for RR header. */
		isc_buffer_add(&xfr->buf, 10);

		result = dns_message_gettemprdata(msg, &msgrdata);
		if (result != ISC_R_SUCCESS)
			goto failure;
		isc_buffer_availableregion(&xfr->buf, &r);
		r.length = rdata->length;
		isc_buffer_putmem(&xfr->buf, rdata->data, rdata->length);
		dns_rdata_init(msgrdata);
		dns_rdata_fromregion(msgrdata,
				     rdata->rdclass, rdata->type, &r);

		result = dns_message_gettemprdatalist(msg, &msgrdl);
		if (result != ISC_R_SUCCESS)
			goto failure;
		msgrdl->type = rdata->type;
		msgrdl->rdclass = rdata->rdclass;
		msgrdl->ttl = ttl;
		if (rdata->type == dns_rdatatype_sig ||
		    rdata->type == dns_rdatatype_rrsig)
			msgrdl->covers = dns_rdata_covers(rdata);
		else
			msgrdl->covers = dns_rdatatype_none;
		ISC_LIST_APPEND(msgrdl->rdata, msgrdata, link);

		result = dns_message_gettemprdataset(msg, &msgrds);
		if (result != ISC_R_SUCCESS)
			goto failure;
		result = dns_rdatalist_tordataset(msgrdl, msgrds);
		INSIST(result == ISC_R_SUCCESS);

		ISC_LIST_APPEND(msgname->list, msgrds, link);

		dns_message_addname(msg, msgname, DNS_SECTION_ANSWER);
		msgname = NULL;

		result = xfr->stream->methods->next(xfr->stream);
		if (result == ISC_R_NOMORE) {
			xfr->end_of_stream = ISC_TRUE;
			break;
		}
		CHECK(result);

		if (! xfr->many_answers)
			break;
		/*
		 * At this stage, at least 1 RR has been rendered into
		 * the message. Check if we want to clamp this message
		 * here (TCP only).
		 */
		if ((isc_buffer_usedlength(&xfr->buf) >=
		     ns_g_server->transfer_tcp_message_size) && is_tcp)
			break;
	}

	if (is_tcp) {
		CHECK(dns_compress_init(&cctx, -1, xfr->mctx));
		dns_compress_setsensitive(&cctx, ISC_TRUE);
		cleanup_cctx = ISC_TRUE;
		CHECK(dns_message_renderbegin(msg, &cctx, &xfr->txbuf));
		CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0));
		CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0));
		CHECK(dns_message_renderend(msg));
		dns_compress_invalidate(&cctx);
		cleanup_cctx = ISC_FALSE;

		isc_buffer_usedregion(&xfr->txbuf, &used);
		isc_buffer_putuint16(&xfr->txlenbuf,
				     (isc_uint16_t)used.length);
		region.base = xfr->txlenbuf.base;
		region.length = 2 + used.length;
		xfrout_log(xfr, ISC_LOG_DEBUG(8),
			   "sending TCP message of %d bytes",
			   used.length);
		CHECK(isc_socket_send(xfr->client->tcpsocket, /* XXX */
				      &region, xfr->client->task,
				      xfrout_senddone,
				      xfr));
		xfr->sends++;
	} else {
		xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending IXFR UDP response");
		ns_client_send(xfr->client);
		xfr->stream->methods->pause(xfr->stream);
		xfrout_ctx_destroy(&xfr);
		return;
	}

	/* Advance lasttsig to be the last TSIG generated */
	CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig));

	xfr->nmsg++;

 failure:
	if (msgname != NULL) {
		if (msgrds != NULL) {
			if (dns_rdataset_isassociated(msgrds))
				dns_rdataset_disassociate(msgrds);
			dns_message_puttemprdataset(msg, &msgrds);
		}
		if (msgrdl != NULL) {
			ISC_LIST_UNLINK(msgrdl->rdata, msgrdata, link);
			dns_message_puttemprdatalist(msg, &msgrdl);
		}
		if (msgrdata != NULL)
			dns_message_puttemprdata(msg, &msgrdata);
		dns_message_puttempname(msg, &msgname);
	}

	if (tcpmsg != NULL)
		dns_message_destroy(&tcpmsg);

	if (cleanup_cctx)
		dns_compress_invalidate(&cctx);
	/*
	 * Make sure to release any locks held by database
	 * iterators before returning from the event handler.
	 */
	xfr->stream->methods->pause(xfr->stream);

	if (result == ISC_R_SUCCESS)
		return;

	xfrout_fail(xfr, result, "sending zone data");
}
Exemple #17
0
static isc_result_t
add_initial_keys(const cfg_obj_t *list, dns_tsig_keyring_t *ring,
		 isc_mem_t *mctx)
{
	dns_tsigkey_t *tsigkey = NULL;
	const cfg_listelt_t *element;
	const cfg_obj_t *key = NULL;
	const char *keyid = NULL;
	unsigned char *secret = NULL;
	int secretalloc = 0;
	int secretlen = 0;
	isc_result_t ret;
	isc_stdtime_t now;
	isc_uint16_t bits;

	for (element = cfg_list_first(list);
	     element != NULL;
	     element = cfg_list_next(element))
	{
		const cfg_obj_t *algobj = NULL;
		const cfg_obj_t *secretobj = NULL;
		dns_name_t keyname;
		dns_name_t *alg;
		const char *algstr;
		char keynamedata[1024];
		isc_buffer_t keynamesrc, keynamebuf;
		const char *secretstr;
		isc_buffer_t secretbuf;

		key = cfg_listelt_value(element);
		keyid = cfg_obj_asstring(cfg_map_getname(key));

		algobj = NULL;
		secretobj = NULL;
		(void)cfg_map_get(key, "algorithm", &algobj);
		(void)cfg_map_get(key, "secret", &secretobj);
		INSIST(algobj != NULL && secretobj != NULL);

		/*
		 * Create the key name.
		 */
		dns_name_init(&keyname, NULL);
		isc_buffer_init(&keynamesrc, keyid, strlen(keyid));
		isc_buffer_add(&keynamesrc, strlen(keyid));
		isc_buffer_init(&keynamebuf, keynamedata, sizeof(keynamedata));
		ret = dns_name_fromtext(&keyname, &keynamesrc, dns_rootname,
					ISC_TRUE, &keynamebuf);
		if (ret != ISC_R_SUCCESS)
			goto failure;

		/*
		 * Create the algorithm.
		 */
		algstr = cfg_obj_asstring(algobj);
		if (ns_config_getkeyalgorithm(algstr, &alg, &bits)
		    != ISC_R_SUCCESS) {
			cfg_obj_log(algobj, ns_g_lctx, ISC_LOG_ERROR,
				    "key '%s': has a unsupported algorithm '%s'",
				    keyid, algstr);
			ret = DNS_R_BADALG;
			goto failure;
		}

		secretstr = cfg_obj_asstring(secretobj);
		secretalloc = secretlen = strlen(secretstr) * 3 / 4;
		secret = isc_mem_get(mctx, secretlen);
		if (secret == NULL) {
			ret = ISC_R_NOMEMORY;
			goto failure;
		}
		isc_buffer_init(&secretbuf, secret, secretlen);
		ret = isc_base64_decodestring(secretstr, &secretbuf);
		if (ret != ISC_R_SUCCESS)
			goto failure;
		secretlen = isc_buffer_usedlength(&secretbuf);

		isc_stdtime_get(&now);
		ret = dns_tsigkey_create(&keyname, alg, secret, secretlen,
					 ISC_FALSE, NULL, now, now,
					 mctx, ring, &tsigkey);
		isc_mem_put(mctx, secret, secretalloc);
		secret = NULL;
		if (ret != ISC_R_SUCCESS)
			goto failure;
		/*
		 * Set digest bits.
		 */
		dst_key_setbits(tsigkey->key, bits);
		dns_tsigkey_detach(&tsigkey);
	}

	return (ISC_R_SUCCESS);

 failure:
	cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
		    "configuring key '%s': %s", keyid,
		    isc_result_totext(ret));

	if (secret != NULL)
		isc_mem_put(mctx, secret, secretalloc);
	return (ret);
}
Exemple #18
0
static void
nsec3hash(nsec3printer *nsec3print, const char *algostr, const char *flagstr,
	  const char *iterstr, const char *saltstr, const char *domain)
{
	dns_fixedname_t fixed;
	dns_name_t *name;
	isc_buffer_t buffer;
	isc_region_t region;
	isc_result_t result;
	unsigned char hash[NSEC3_MAX_HASH_LENGTH];
	unsigned char salt[DNS_NSEC3_SALTSIZE];
	unsigned char text[1024];
	unsigned int hash_alg;
	unsigned int flags;
	unsigned int length;
	unsigned int iterations;
	unsigned int salt_length;
	const char dash[] = "-";

	if (strcmp(saltstr, "-") == 0) {
		salt_length = 0;
		salt[0] = 0;
	} else {
		isc_buffer_init(&buffer, salt, sizeof(salt));
		result = isc_hex_decodestring(saltstr, &buffer);
		check_result(result, "isc_hex_decodestring(salt)");
		salt_length = isc_buffer_usedlength(&buffer);
		if (salt_length > DNS_NSEC3_SALTSIZE)
			fatal("salt too long");
		if (salt_length == 0)
			saltstr = dash;
	}
	hash_alg = atoi(algostr);
	if (hash_alg > 255U)
		fatal("hash algorithm too large");
	flags = flagstr == NULL ? 0 : atoi(flagstr);
	if (flags > 255U)
		fatal("flags too large");
	iterations = atoi(iterstr);
	if (iterations > 0xffffU)
		fatal("iterations to large");

	dns_fixedname_init(&fixed);
	name = dns_fixedname_name(&fixed);
	isc_buffer_constinit(&buffer, domain, strlen(domain));
	isc_buffer_add(&buffer, strlen(domain));
	result = dns_name_fromtext(name, &buffer, dns_rootname, 0, NULL);
	check_result(result, "dns_name_fromtext() failed");

	dns_name_downcase(name, name, NULL);
	length = isc_iterated_hash(hash, hash_alg, iterations,  salt,
				   salt_length, name->ndata, name->length);
	if (length == 0)
		fatal("isc_iterated_hash failed");
	region.base = hash;
	region.length = length;
	isc_buffer_init(&buffer, text, sizeof(text));
	isc_base32hexnp_totext(&region, 1, "", &buffer);
	isc_buffer_putuint8(&buffer, '\0');

	nsec3print(hash_alg, flags, iterations, saltstr, domain, (char *)text);
}
Exemple #19
0
static void
sendquery(isc_task_t *task, isc_event_t *event)
{
	dns_request_t *request = NULL;
	dns_message_t *message = NULL;
	dns_name_t *qname = NULL;
	dns_rdataset_t *qrdataset = NULL;
	isc_result_t result;
	dns_fixedname_t queryname;
	isc_buffer_t buf;
	isc_buffer_t outbuf;
	char output[10 * 1024];
	static char host[256];
	int c;

	isc_event_free(&event);

	printf("Query => ");
	c = scanf("%255s", host);
	if (c == EOF)
		return;

	dns_fixedname_init(&queryname);
	isc_buffer_init(&buf, host, strlen(host));
	isc_buffer_add(&buf, strlen(host));
	result = dns_name_fromtext(dns_fixedname_name(&queryname), &buf,
				   dns_rootname, 0, NULL);
	CHECK("dns_name_fromtext", result);

	result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &message);
	if (result != ISC_R_SUCCESS)
		goto end;

	message->opcode = dns_opcode_query;
	message->rdclass = dns_rdataclass_in;
	message->id = (unsigned short)(random() & 0xFFFF);

	result = dns_message_gettempname(message, &qname);
	if (result != ISC_R_SUCCESS)
		goto end;

	result = dns_message_gettemprdataset(message, &qrdataset);
	if (result != ISC_R_SUCCESS)
		goto end;

	dns_name_init(qname, NULL);
	dns_name_clone(dns_fixedname_name(&queryname), qname);
	dns_rdataset_init(qrdataset);
	dns_rdataset_makequestion(qrdataset, dns_rdataclass_in,
				  dns_rdatatype_a);
	ISC_LIST_APPEND(qname->list, qrdataset, link);
	dns_message_addname(message, qname, DNS_SECTION_QUESTION);

	result = dns_request_create(requestmgr, message, &address, 0, tsigkey,
				    TIMEOUT, task, recvresponse,
		message, &request);
	CHECK("dns_request_create", result);

	printf("Submitting query:\n");
	isc_buffer_init(&outbuf, output, sizeof(output));
	result = dns_message_totext(message, &dns_master_style_debug, 0,
				    &outbuf);
	CHECK("dns_message_totext", result);
	printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf),
	       (char *)isc_buffer_base(&outbuf));

	return;

 end:
	if (qname != NULL)
		dns_message_puttempname(message, &qname);
	if (qrdataset != NULL)
		dns_message_puttemprdataset(message, &qrdataset);
	if (message != NULL)
		dns_message_destroy(&message);
}
Exemple #20
0
isc_result_t
fwd_print_list_buff(isc_mem_t *mctx, dns_forwarders_t *fwdrs,
			 isc_buffer_t **out_buf) {
	isc_result_t result;
	size_t list_len;
	isc_buffer_t *dummy_fwdr_buf = NULL; /* fully dynamic allocation */
	isc_buffer_t tmp_buf; /* hack: only the base buffer is allocated */

	cfg_parser_t *parser = NULL;
	cfg_obj_t *forwarders_cfg = NULL;
	const cfg_obj_t *faddresses;
	const cfg_listelt_t *fwdr_cfg; /* config representation */
	/* internal representation */
#if LIBDNS_VERSION_MAJOR < 140
	isc_sockaddr_t *fwdr_int;
#else /* LIBDNS_VERSION_MAJOR >= 140 */
	dns_forwarder_t *fwdr_int;
#endif

	isc_buffer_initnull(&tmp_buf);
	tmp_buf.mctx = mctx;
	CHECK(cfg_parser_create(mctx, dns_lctx, &parser));

	/* Create dummy string with list of IP addresses of the same length
	 * as the original list of forwarders. Parse this string to obtain
	 * nested cfg structures which will be filled with data for actual
	 * forwarders.
	 *
	 * This is nasty hack but it is easiest way to create list of cfg_objs
	 * I found.
	 */
	list_len = fwd_list_len(fwdrs);
	CHECK(fwd_list_gen_dummy_config_string(mctx,
					       list_len, &dummy_fwdr_buf));
	CHECK(cfg_parse_buffer(parser, dummy_fwdr_buf,
			       cfg_type_forwarders, &forwarders_cfg));

	/* Walk through internal representation and cfg representation and copy
	 * data from the internal one to cfg data structures.*/
	faddresses = cfg_tuple_get(forwarders_cfg, "addresses");
	for (fwdr_int = ISC_LIST_HEAD(
#if LIBDNS_VERSION_MAJOR < 140
			fwdrs->addrs
#else /* LIBDNS_VERSION_MAJOR >= 140 */
			fwdrs->fwdrs
#endif
			), fwdr_cfg = cfg_list_first(faddresses);
	     INSIST((fwdr_int == NULL) == (fwdr_cfg == NULL)), fwdr_int != NULL;
	     fwdr_int = ISC_LIST_NEXT(fwdr_int, link), fwdr_cfg = cfg_list_next(fwdr_cfg)) {
#if LIBDNS_VERSION_MAJOR < 140
		fwdr_cfg->obj->value.sockaddr = *fwdr_int;
#else /* LIBDNS_VERSION_MAJOR >= 140 */
		fwdr_cfg->obj->value.sockaddrdscp.sockaddr = fwdr_int->addr;
		fwdr_cfg->obj->value.sockaddrdscp.dscp = fwdr_int->dscp;
#endif
	}
	cfg_print(faddresses, buffer_append_str, &tmp_buf);

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

cleanup:
	if (forwarders_cfg != NULL)
		cfg_obj_destroy(parser, &forwarders_cfg);
	if (parser != NULL)
		cfg_parser_destroy(&parser);
	if (dummy_fwdr_buf != NULL) {
		if (tmp_buf.base != NULL)
			isc_mem_put(mctx, tmp_buf.base, tmp_buf.length);
		isc_buffer_free(&dummy_fwdr_buf);
	}

	return result;
}
Exemple #21
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;
	isccc_region_t ccregion;
	isc_uint32_t algorithm;
	isccc_region_t secret;
	isc_stdtime_t now;
	isc_buffer_t b;
	isc_region_t r;
	isc_uint32_t len;
	isc_buffer_t text;
	char textarray[2*1024];
	isc_result_t result;
	isc_result_t eresult;
	isccc_sexpr_t *_ctrl;
	isccc_time_t sent;
	isccc_time_t exp;
	isc_uint32_t nonce;

	REQUIRE(event->ev_type == ISCCC_EVENT_CCMSG);

	conn = event->ev_arg;
	listener = conn->listener;
	algorithm = DST_ALG_UNKNOWN;
	secret.rstart = 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))
	{
		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 (!isccc_alist_alistp(_ctrl)) {
		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;
	}

	isc_buffer_init(&text, textarray, sizeof(textarray));

	/*
	 * 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;
	if (eresult != ISC_R_SUCCESS) {
		isccc_sexpr_t *data;

		data = isccc_alist_lookup(response, "_data");
		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) {
		isccc_sexpr_t *data;

		data = isccc_alist_lookup(response, "_data");
		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;

	ccregion.rstart = conn->buffer + 4;
	ccregion.rend = conn->buffer + sizeof(conn->buffer);
	result = isccc_cc_towire(response, &ccregion, algorithm, &secret);
	if (result != ISC_R_SUCCESS)
		goto cleanup_response;
	isc_buffer_init(&b, conn->buffer, 4);
	len = sizeof(conn->buffer) - REGION_SIZE(ccregion);
	isc_buffer_putuint32(&b, len - 4);
	r.base = conn->buffer;
	r.length = len;

	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);
	return;

 cleanup_response:
	isccc_sexpr_free(&response);

 cleanup_request:
	isccc_sexpr_free(&request);
	isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));

 cleanup:
	isc_socket_detach(&conn->sock);
	isccc_ccmsg_invalidate(&conn->ccmsg);
	conn->ccmsg_valid = ISC_FALSE;
	maybe_free_connection(conn);
	maybe_free_listener(listener);
}
Exemple #22
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;
}
Exemple #23
0
static isc_result_t
get_rndckey(isc_mem_t *mctx, controlkeylist_t *keyids) {
	isc_result_t result;
	cfg_parser_t *pctx = NULL;
	cfg_obj_t *config = NULL;
	const cfg_obj_t *key = NULL;
	const cfg_obj_t *algobj = NULL;
	const cfg_obj_t *secretobj = NULL;
	const char *algstr = NULL;
	const char *secretstr = NULL;
	controlkey_t *keyid = NULL;
	char secret[1024];
	unsigned int algtype;
	isc_buffer_t b;

	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
		      NS_LOGMODULE_CONTROL, ISC_LOG_INFO,
		      "configuring command channel from '%s'",
		      ns_g_keyfile);
	if (! isc_file_exists(ns_g_keyfile))
		return (ISC_R_FILENOTFOUND);

	CHECK(cfg_parser_create(mctx, ns_g_lctx, &pctx));
	CHECK(cfg_parse_file(pctx, ns_g_keyfile, &cfg_type_rndckey, &config));
	CHECK(cfg_map_get(config, "key", &key));

	keyid = isc_mem_get(mctx, sizeof(*keyid));
	if (keyid == NULL)
		CHECK(ISC_R_NOMEMORY);
	keyid->keyname = isc_mem_strdup(mctx,
					cfg_obj_asstring(cfg_map_getname(key)));
	keyid->secret.base = NULL;
	keyid->secret.length = 0;
	keyid->algorithm = DST_ALG_UNKNOWN;
	ISC_LINK_INIT(keyid, link);
	if (keyid->keyname == NULL)
		CHECK(ISC_R_NOMEMORY);

	CHECK(bind9_check_key(key, ns_g_lctx));

	(void)cfg_map_get(key, "algorithm", &algobj);
	(void)cfg_map_get(key, "secret", &secretobj);
	INSIST(algobj != NULL && secretobj != NULL);

	algstr = cfg_obj_asstring(algobj);
	secretstr = cfg_obj_asstring(secretobj);

	if (ns_config_getkeyalgorithm2(algstr, NULL,
				       &algtype, NULL) != ISC_R_SUCCESS) {
		cfg_obj_log(key, ns_g_lctx,
			    ISC_LOG_WARNING,
			    "unsupported algorithm '%s' in "
			    "key '%s' for use with command "
			    "channel",
			    algstr, keyid->keyname);
		goto cleanup;
	}

	keyid->algorithm = algtype;
	isc_buffer_init(&b, secret, sizeof(secret));
	result = isc_base64_decodestring(secretstr, &b);

	if (result != ISC_R_SUCCESS) {
		cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
			    "secret for key '%s' on command channel: %s",
			    keyid->keyname, isc_result_totext(result));
		goto cleanup;
	}

	keyid->secret.length = isc_buffer_usedlength(&b);
	keyid->secret.base = isc_mem_get(mctx,
					 keyid->secret.length);
	if (keyid->secret.base == NULL) {
		cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
			   "couldn't register key '%s': "
			   "out of memory", keyid->keyname);
		CHECK(ISC_R_NOMEMORY);
	}
	memmove(keyid->secret.base, isc_buffer_base(&b),
		keyid->secret.length);
	ISC_LIST_APPEND(*keyids, keyid, link);
	keyid = NULL;
	result = ISC_R_SUCCESS;

  cleanup:
	if (keyid != NULL)
		free_controlkey(keyid, mctx);
	if (config != NULL)
		cfg_obj_destroy(pctx, &config);
	if (pctx != NULL)
		cfg_parser_destroy(&pctx);
	return (result);
}
Exemple #24
0
static void process_step_first(dnskey_glob *gs,
			       dnskey_lookup *dl,
			       struct rrsetinfo *ans,
			       int success,
			       int attempt)  /* attempt = 0 first time, 1 after cname */
{
	char simplebuf[132], typebuf[16];
	char txtbuf[1024];
	unsigned int i;

	switch(success) {
	case ERRSET_NODATA:
		if(attempt == 0) {
			lwresd_has_spoken = 1;
			setup_follow_possible_cname(gs, dl);
			dl->step = dkl_cname;
			return;
		} 
		/* FALLTHROUGH */
	case ERRSET_NONAME:
		lwresd_has_spoken = 1;
		snprintf(simplebuf, sizeof(simplebuf),
			 "RR of type %s for %s was not found",
			 dl->wantedtype_name,
			 dl->fqdn);
		output_transaction_line(gs, dl->tracking_id, 0, "RETRY", 
					simplebuf);
		dl->step = dkl_done;
		goto done;
		
	case ERRSET_NOMEMORY:
		snprintf(simplebuf, sizeof(simplebuf),
			 "ran out of memory while looking up RR of type %s for %s",
			 dl->wantedtype_name, dl->fqdn);
		output_transaction_line(gs, dl->tracking_id, 0, "FATAL", simplebuf);
		dl->step = dkl_done;
		goto done;

	case ERRSET_FAIL:
		snprintf(simplebuf, sizeof(simplebuf),
			 "unspecified failure while looking up RR of type %s for %s%s",
			 dl->wantedtype_name, dl->fqdn,
			 lwresd_has_spoken ? "" : " (is lwresd running?)");
		output_transaction_line(gs, dl->tracking_id, 0, "FATAL", simplebuf);
		dl->step = dkl_done;
		goto done;
		
	case ERRSET_INVAL:
		snprintf(simplebuf, sizeof(simplebuf),
			 "invalid input while looking up RR of type %s for %s",
			 dl->wantedtype_name, dl->fqdn);
		output_transaction_line(gs, dl->tracking_id, 0, "RETRY", simplebuf);
		dl->step = dkl_done;
		goto done;

	default:
		snprintf(simplebuf, sizeof(simplebuf), " unknown error %d", success);
		output_transaction_line(gs, dl->tracking_id, 0, "RETRY", simplebuf);
		dl->step = dkl_done;
	done:
		return;
		
	case 0:
		/* everything okay */
		lwresd_has_spoken = 1;
		dl->step = dkl_done;
		break;
	}

	/* output the rest of the data */

	if(ans->rri_flags & RRSET_VALIDATED) {
		output_transaction_line(gs, dl->tracking_id, 0, "DNSSEC", "OKAY");
		snprintf(typebuf, sizeof(typebuf), "AD-%s", dl->wantedtype_name);
		if(dl->wantedtype_name) free(dl->wantedtype_name);
		dl->wantedtype_name=xstrdup(typebuf);
	} else {
		output_transaction_line(gs, dl->tracking_id, 0, "DNSSEC", "not present");
	}

	output_transaction_line(gs, dl->tracking_id, 0, "NAME", ans->rri_name);

	for(i=0; i<ans->rri_nrdatas; i++) {
		struct rdatainfo *ri = &ans->rri_rdatas[i];
		isc_region_t  region;
		dns_rdata_t    rd;

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

		if(dl->wantedtype == dns_rdatatype_txt) {
			/* special treatment for TXT records */
			unsigned int len, rdatalen, totlen;
			unsigned char *txtp, *rdata;

			txtp     = txtbuf;
			totlen   = 0;
			rdatalen = ri->rdi_length;
			rdata    = ri->rdi_data;

			while(rdatalen > 0) {
				len= (unsigned)rdata[0];
				memcpy(txtp, rdata+1, len);
				totlen   += len;
				txtp     += len;
				rdata    += len+1;
				rdatalen -= len+1;
			}
			*txtp = '\0';

			output_transaction_line_limited(gs, dl->tracking_id, 0,
							dl->wantedtype_name,
							totlen, txtbuf);

		} else {
			dns_rdata_fromregion(&rd, dns_rdataclass_in,
					     dl->wantedtype, &region);
			
			if(dns_rdata_totext(&rd, NULL, gs->iscbuf) != ISC_R_SUCCESS) {

			}
			
			output_transaction_line_limited(gs, dl->tracking_id, 0,
							dl->wantedtype_name,
					(int)isc_buffer_usedlength(gs->iscbuf),
					(char *)isc_buffer_base(gs->iscbuf));
		}
	}
		
	for(i=0; i<ans->rri_nsigs; i++) {
		struct rdatainfo *ri = &ans->rri_sigs[i];
		isc_region_t  region;
		dns_rdata_t    rd;

		isc_buffer_clear(gs->iscbuf);
		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_sig, &region);
		if(dns_rdata_totext(&rd, NULL, gs->iscbuf) != ISC_R_SUCCESS) {
			output_transaction_line(gs, dl->tracking_id, 0, "FATAL", "isc totext error");
			return;
		}
		
		output_transaction_line_limited(gs, dl->tracking_id, 0, "SIG",
					(int)isc_buffer_usedlength(gs->iscbuf),
					(char *)isc_buffer_base(gs->iscbuf));
	}
}	
Exemple #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);
}
Exemple #26
0
int
main(int argc, char **argv) {
	isc_boolean_t show_final_mem = ISC_FALSE;
	isc_buffer_t key_txtbuffer;
	char key_txtsecret[256];
	isc_mem_t *mctx = NULL;
	isc_result_t result = ISC_R_SUCCESS;
	const char *keyname = NULL;
	const char *randomfile = NULL;
	const char *serveraddr = NULL;
	dns_secalg_t alg = DST_ALG_HMACMD5;
	const char *algname = alg_totext(alg);
	char *p;
	int ch;
	int port;
	int keysize;
	struct in_addr addr4_dummy;
	struct in6_addr addr6_dummy;
	char *chrootdir = NULL;
	char *user = NULL;
	isc_boolean_t keyonly = ISC_FALSE;
	int len;

	keydef = keyfile = RNDC_KEYFILE;

	result = isc_file_progname(*argv, program, sizeof(program));
	if (result != ISC_R_SUCCESS)
		memcpy(program, "rndc-confgen", 13);
	progname = program;

	keyname = DEFAULT_KEYNAME;
	keysize = DEFAULT_KEYLENGTH;
	serveraddr = DEFAULT_SERVER;
	port = DEFAULT_PORT;

	isc_commandline_errprint = ISC_FALSE;

	while ((ch = isc_commandline_parse(argc, argv,
					   "ab:c:hk:Mmp:r:s:t:u:Vy")) != -1) {
		switch (ch) {
		case 'a':
			keyonly = ISC_TRUE;
			break;
		case 'b':
			keysize = strtol(isc_commandline_argument, &p, 10);
			if (*p != '\0' || keysize < 0)
				fatal("-b requires a non-negative number");
			if (keysize < 1 || keysize > 512)
				fatal("-b must be in the range 1 through 512");
			break;
		case 'c':
			keyfile = isc_commandline_argument;
			break;
		case 'h':
			usage(0);
		case 'k':
		case 'y':	/* Compatible with rndc -y. */
			keyname = isc_commandline_argument;
			break;
		case 'M':
			isc_mem_debugging = ISC_MEM_DEBUGTRACE;
			break;

		case 'm':
			show_final_mem = ISC_TRUE;
			break;
		case 'p':
			port = strtol(isc_commandline_argument, &p, 10);
			if (*p != '\0' || port < 0 || port > 65535)
				fatal("port '%s' out of range",
				      isc_commandline_argument);
			break;
		case 'r':
			randomfile = isc_commandline_argument;
			break;
		case 's':
			serveraddr = isc_commandline_argument;
			if (inet_pton(AF_INET, serveraddr, &addr4_dummy) != 1 &&
			    inet_pton(AF_INET6, serveraddr, &addr6_dummy) != 1)
				fatal("-s should be an IPv4 or IPv6 address");
			break;
		case 't':
			chrootdir = isc_commandline_argument;
			break;
		case 'u':
			user = isc_commandline_argument;
			break;
		case 'V':
			verbose = ISC_TRUE;
			break;
		case '?':
			if (isc_commandline_option != '?') {
				fprintf(stderr, "%s: invalid argument -%c\n",
					program, isc_commandline_option);
				usage(1);
			} else
				usage(0);
			break;
		default:
			fprintf(stderr, "%s: unhandled option -%c\n",
				program, isc_commandline_option);
			exit(1);
		}
	}

	argc -= isc_commandline_index;
	argv += isc_commandline_index;
	POST(argv);

	if (argc > 0)
		usage(1);

	DO("create memory context", isc_mem_create(0, 0, &mctx));
	isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));

	generate_key(mctx, randomfile, alg, keysize, &key_txtbuffer);

	if (keyonly) {
		write_key_file(keyfile, chrootdir == NULL ? user : NULL,
			       keyname, &key_txtbuffer, alg);

		if (chrootdir != NULL) {
			char *buf;
			len = strlen(chrootdir) + strlen(keyfile) + 2;
			buf = isc_mem_get(mctx, len);
			if (buf == NULL)
				fatal("isc_mem_get(%d) failed\n", len);
			snprintf(buf, len, "%s%s%s", chrootdir,
				 (*keyfile != '/') ? "/" : "", keyfile);

			write_key_file(buf, user, keyname, &key_txtbuffer, alg);
			isc_mem_put(mctx, buf, len);
		}
	} else {
		printf("\
# Start of rndc.conf\n\
key \"%s\" {\n\
	algorithm %s;\n\
	secret \"%.*s\";\n\
};\n\
\n\
options {\n\
	default-key \"%s\";\n\
	default-server %s;\n\
	default-port %d;\n\
};\n\
# End of rndc.conf\n\
\n\
# Use with the following in named.conf, adjusting the allow list as needed:\n\
# key \"%s\" {\n\
# 	algorithm %s;\n\
# 	secret \"%.*s\";\n\
# };\n\
# \n\
# controls {\n\
# 	inet %s port %d\n\
# 		allow { %s; } keys { \"%s\"; };\n\
# };\n\
# End of named.conf\n",
		       keyname, algname,
		       (int)isc_buffer_usedlength(&key_txtbuffer),
		       (char *)isc_buffer_base(&key_txtbuffer),
		       keyname, serveraddr, port,
		       keyname, algname,
		       (int)isc_buffer_usedlength(&key_txtbuffer),
		       (char *)isc_buffer_base(&key_txtbuffer),
		       serveraddr, port, serveraddr, keyname);
	}

	if (show_final_mem)
		isc_mem_stats(mctx, stderr);

	isc_mem_destroy(&mctx);

	return (0);
}
Exemple #27
0
/*
 * 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 (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_COMMENT;
	}
	if (multiline || (nottl && noclass))
		result = dns_master_stylecreate(&style, styleflags,
						24, 24, 24, 32, 80, 8, mctx);
	else if (nottl || noclass)
		result = dns_master_stylecreate(&style, styleflags,
						24, 24, 32, 40, 80, 8, mctx);
	else
		result = dns_master_stylecreate(&style, styleflags,
						24, 32, 40, 48, 80, 8, 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 (!query->lookup->comments)
		flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS;

	result = ISC_R_SUCCESS;

	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 && 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);
}
ATF_TC_BODY(csync, tc) {
	struct {
		const char *data;
		isc_boolean_t ok;
	} text_data[] = {
		{ "", ISC_FALSE },
		{ "0", ISC_FALSE },
		{ "0 0", ISC_TRUE },
		{ "0 0 A", ISC_TRUE },
		{ "0 0 NS", ISC_TRUE },
		{ "0 0 AAAA", ISC_TRUE },
		{ "0 0 A AAAA", ISC_TRUE },
		{ "0 0 A NS AAAA", ISC_TRUE },
		{ "0 0 A NS AAAA BOGUS", ISC_FALSE },
		{ NULL, ISC_FALSE },
	};
	struct {
		unsigned char data[64];
		size_t len;
		isc_boolean_t ok;
	} wire_data[] = {
		/* short */
		{ { 0x00 }, 0,  ISC_FALSE },
		/* short */
		{ { 0x00 }, 1, ISC_FALSE },
		/* short */
		{ { 0x00, 0x00 }, 2, ISC_FALSE },
		/* short */
		{ { 0x00, 0x00, 0x00 }, 3, ISC_FALSE },
		/* short */
		{ { 0x00, 0x00, 0x00, 0x00 }, 4, ISC_FALSE },
		/* short */
		{ { 0x00, 0x00, 0x00, 0x00, 0x00 }, 5, ISC_FALSE },
		/* serial + flags only  */
		{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 6, ISC_TRUE },
		/* bad type map */
		{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 7, ISC_FALSE },
		/* bad type map */
		{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
		    8, ISC_FALSE },
		/* good type map */
		{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02 },
		    9, ISC_TRUE }
	};
	unsigned char buf1[1024];
	unsigned char buf2[1024];
	isc_buffer_t source, target1, target2;
	isc_result_t result;
	size_t i;
	dns_rdataclass_t rdclass = dns_rdataclass_in;
	dns_rdatatype_t type = dns_rdatatype_csync;
	isc_lex_t *lex = NULL;
	dns_rdatacallbacks_t callbacks;
	dns_rdata_csync_t csync;
	dns_decompress_t dctx;

	UNUSED(tc);

	result = dns_test_begin(NULL, ISC_FALSE);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	result = isc_lex_create(mctx, 64, &lex);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	dns_rdatacallbacks_init(&callbacks);
	callbacks.error = error_callback;
	callbacks.warn = warn_callback;

	for (i = 0; text_data[i].data != NULL; i++) {
		size_t length = strlen(text_data[i].data);
		isc_buffer_constinit(&source, text_data[i].data, length);
		isc_buffer_add(&source, length);
		result = isc_lex_openbuffer(lex, &source);
		ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

		isc_buffer_init(&target1, buf1, sizeof(buf1));

		result = dns_rdata_fromtext(NULL, rdclass, type, lex,
					    dns_rootname, 0, NULL, &target1,
					    &callbacks);
		if (text_data[i].ok)
			ATF_CHECK_EQ(result, ISC_R_SUCCESS);
		else
			ATF_CHECK(result != ISC_R_SUCCESS);
	}
	isc_lex_destroy(&lex);

	for (i = 0; i < sizeof(wire_data)/sizeof(wire_data[0]); i++) {
		dns_rdata_t rdata = DNS_RDATA_INIT;

		isc_buffer_init(&source, wire_data[i].data, wire_data[i].len);
		isc_buffer_add(&source, wire_data[i].len);
		isc_buffer_setactive(&source, wire_data[i].len);
		isc_buffer_init(&target1, buf1, sizeof(buf1));
		dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
		result = dns_rdata_fromwire(&rdata, rdclass, type, &source,
					    &dctx, 0, &target1);
		dns_decompress_invalidate(&dctx);
		if (wire_data[i].ok)
			ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
		else
			ATF_REQUIRE(result != ISC_R_SUCCESS);
		if (result != ISC_R_SUCCESS)
			continue;
		result = dns_rdata_tostruct(&rdata, &csync, NULL);
		ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
		isc_buffer_init(&target2, buf2, sizeof(buf2));
		dns_rdata_reset(&rdata);
		result = dns_rdata_fromstruct(&rdata, rdclass, type,
					      &csync, &target2);
		ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
		ATF_REQUIRE_EQ(isc_buffer_usedlength(&target2),
						     wire_data[i].len);
		ATF_REQUIRE_EQ(memcmp(buf2, wire_data[i].data,
				      wire_data[i].len), 0);
	}
}