static void parse_rdata(isc_mem_t *mctx, char **cmdlinep, dns_rdataclass_t rdataclass, dns_rdatatype_t rdatatype, dns_rdata_t *rdata) { char *cmdline = *cmdlinep; isc_buffer_t source, *buf = NULL, *newbuf = NULL; isc_region_t r; isc_lex_t *lex = NULL; dns_rdatacallbacks_t callbacks; isc_result_t result; while (cmdline != NULL && *cmdline != 0 && isspace((unsigned char)*cmdline)) cmdline++; if (cmdline != NULL && *cmdline != 0) { dns_rdatacallbacks_init(&callbacks); result = isc_lex_create(mctx, strlen(cmdline), &lex); check_result(result, "isc_lex_create"); isc_buffer_init(&source, cmdline, strlen(cmdline)); isc_buffer_add(&source, strlen(cmdline)); result = isc_lex_openbuffer(lex, &source); check_result(result, "isc_lex_openbuffer"); result = isc_buffer_allocate(mctx, &buf, MAXWIRE); check_result(result, "isc_buffer_allocate"); result = dns_rdata_fromtext(rdata, rdataclass, rdatatype, lex, dns_rootname, 0, mctx, buf, &callbacks); isc_lex_destroy(&lex); if (result == ISC_R_SUCCESS) { isc_buffer_usedregion(buf, &r); result = isc_buffer_allocate(mctx, &newbuf, r.length); check_result(result, "isc_buffer_allocate"); isc_buffer_putmem(newbuf, r.base, r.length); isc_buffer_usedregion(newbuf, &r); dns_rdata_reset(rdata); dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r); isc_buffer_free(&buf); ISC_LIST_APPEND(usedbuffers, newbuf, link); } else { fprintf(stderr, "invalid rdata format: %s\n", isc_result_totext(result)); isc_buffer_free(&buf); exit(1); } } else { rdata->flags = DNS_RDATA_UPDATE; } *cmdlinep = cmdline; }
static void print_hex(dns_dtdata_t *dt) { isc_buffer_t *b = NULL; isc_result_t result; size_t textlen; if (dt->msg == NULL) { return; } textlen = (dt->msgdata.length * 2) + 1; isc_buffer_allocate(mctx, &b, textlen); if (b == NULL) { fatal("out of memory"); } result = isc_hex_totext(&dt->msgdata, 0, "", b); CHECKM(result, "isc_hex_totext"); printf("%.*s\n", (int) isc_buffer_usedlength(b), (char *) isc_buffer_base(b)); cleanup: if (b != NULL) isc_buffer_free(&b); }
static isc_result_t gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) { gssapi_ctx_t *ctx = dctx->opaque; isc_buffer_t *newbuffer = NULL; isc_region_t r; unsigned int length; isc_result_t result; result = isc_buffer_copyregion(ctx->buffer, data); if (result == ISC_R_SUCCESS) return (ISC_R_SUCCESS); length = isc_buffer_length(ctx->buffer) + data->length + BUFFER_EXTRA; result = isc_buffer_allocate(dctx->mctx, &newbuffer, length); if (result != ISC_R_SUCCESS) return (result); isc_buffer_usedregion(ctx->buffer, &r); (void) isc_buffer_copyregion(newbuffer, &r); (void) isc_buffer_copyregion(newbuffer, data); isc_buffer_free(&ctx->buffer); ctx->buffer = newbuffer; return (ISC_R_SUCCESS); }
isc_result_t dns_keytable_dump(dns_keytable_t *keytable, FILE *fp) { isc_result_t result; isc_buffer_t *text = NULL; REQUIRE(VALID_KEYTABLE(keytable)); REQUIRE(fp != NULL); result = isc_buffer_allocate(keytable->mctx, &text, 4096); if (result != ISC_R_SUCCESS) return (result); result = dns_keytable_totext(keytable, &text); if (isc_buffer_usedlength(text) != 0) { (void) putstr(&text, "\n"); } else if (result == ISC_R_SUCCESS) (void) putstr(&text, "none"); else { (void) putstr(&text, "could not dump key table: "); (void) putstr(&text, isc_result_totext(result)); } fprintf(fp, "%.*s", (int) isc_buffer_usedlength(text), (char *) isc_buffer_base(text)); isc_buffer_free(&text); return (result); }
/** * Generate dummy string which looks like list of forwarders * with list_len elements. This string might be fed into cfg parser. * * Caller has to deallocate resulting dummy_string. */ static isc_result_t fwd_list_gen_dummy_config_string(isc_mem_t *mctx, size_t list_len, isc_buffer_t **dummy_string) { isc_result_t result; const char prefix[] = "{ "; const char suffix[] = "} // dummy string, please ignore"; const char fill[] = "127.0.0.1; "; size_t target_size = sizeof(prefix) \ + list_len*sizeof(fill) + sizeof(suffix) + 1; /* \0 */ isc_buffer_t *output = NULL; REQUIRE(dummy_string != NULL && *dummy_string == NULL); CHECK(isc_buffer_allocate(mctx, &output, target_size)); isc_buffer_putstr(output, prefix); for (size_t i = 0; i < list_len; i++) isc_buffer_putstr(output, fill); isc_buffer_putstr(output, suffix); isc_buffer_putuint8(output, '\0'); *dummy_string = output; cleanup: if (result != ISC_R_SUCCESS && output != NULL) isc_buffer_free(&output); return result; }
static void printrdata(dns_rdata_t *rdata) { isc_result_t result; isc_buffer_t *b = NULL; unsigned int size = 1024; isc_boolean_t done = ISC_FALSE; if (rdata->type < N_KNOWN_RRTYPES) printf("%s", rtypetext[rdata->type]); else printf("rdata_%d = ", rdata->type); while (!done) { result = isc_buffer_allocate(mctx, &b, size); if (result != ISC_R_SUCCESS) check_result(result, "isc_buffer_allocate"); result = dns_rdata_totext(rdata, NULL, b); if (result == ISC_R_SUCCESS) { printf("%.*s\n", (int)isc_buffer_usedlength(b), (char *)isc_buffer_base(b)); done = ISC_TRUE; } else if (result != ISC_R_NOSPACE) check_result(result, "dns_rdata_totext"); isc_buffer_free(&b); size *= 2; } }
static void xfrout_ctx_destroy(xfrout_ctx_t **xfrp) { xfrout_ctx_t *xfr = *xfrp; INSIST(xfr->sends == 0); xfr->client->shutdown = NULL; xfr->client->shutdown_arg = NULL; if (xfr->stream != NULL) xfr->stream->methods->destroy(&xfr->stream); if (xfr->buf.base != NULL) isc_mem_put(xfr->mctx, xfr->buf.base, xfr->buf.length); if (xfr->txmem != NULL) isc_mem_put(xfr->mctx, xfr->txmem, xfr->txmemlen); if (xfr->lasttsig != NULL) isc_buffer_free(&xfr->lasttsig); if (xfr->quota != NULL) isc_quota_detach(&xfr->quota); if (xfr->ver != NULL) dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE); if (xfr->zone != NULL) dns_zone_detach(&xfr->zone); if (xfr->db != NULL) dns_db_detach(&xfr->db); ns_client_detach(&xfr->client); isc_mem_put(xfr->mctx, xfr, sizeof(*xfr)); *xfrp = NULL; }
void dst_key_free(dst_key_t **keyp) { isc_mem_t *mctx; dst_key_t *key; unsigned int refs; REQUIRE(dst_initialized == ISC_TRUE); REQUIRE(keyp != NULL && VALID_KEY(*keyp)); key = *keyp; mctx = key->mctx; isc_refcount_decrement(&key->refs, &refs); if (refs != 0) return; isc_refcount_destroy(&key->refs); if (key->keydata.generic != NULL) { INSIST(key->func->destroy != NULL); key->func->destroy(key); } if (key->engine != NULL) isc_mem_free(mctx, key->engine); if (key->label != NULL) isc_mem_free(mctx, key->label); dns_name_free(key->key_name, mctx); isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); if (key->key_tkeytoken) { isc_buffer_free(&key->key_tkeytoken); } memset(key, 0, sizeof(dst_key_t)); isc_mem_putanddetach(&mctx, key, sizeof(dst_key_t)); *keyp = NULL; }
/*% * Destroy the temporary sign/verify context. */ static void gssapi_destroy_signverify_ctx(dst_context_t *dctx) { dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx; if (ctx != NULL) { if (ctx->buffer != NULL) isc_buffer_free(&ctx->buffer); isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t)); dctx->ctxdata.gssctx = NULL; } }
static void gssapi_destroyctx(dst_context_t *dctx) { gssapi_ctx_t *ctx = dctx->opaque; if (ctx != NULL) { if (ctx->buffer != NULL) isc_buffer_free(&ctx->buffer); isc_mem_put(dctx->mctx, ctx, sizeof(gssapi_ctx_t)); dctx->opaque = NULL; } }
static void print_packet(dns_dtdata_t *dt, const dns_master_style_t *style) { isc_buffer_t *b = NULL; isc_result_t result; if (dt->msg != NULL) { size_t textlen = 2048; isc_buffer_allocate(mctx, &b, textlen); if (b == NULL) fatal("out of memory"); for (;;) { isc_buffer_reserve(&b, textlen); if (b == NULL) fatal("out of memory"); result = dns_message_totext(dt->msg, style, 0, b); if (result == ISC_R_NOSPACE) { textlen *= 2; continue; } else if (result == ISC_R_SUCCESS) { printf("%.*s", (int) isc_buffer_usedlength(b), (char *) isc_buffer_base(b)); isc_buffer_free(&b); } else { isc_buffer_free(&b); CHECKM(result, "dns_message_totext"); } break; } } cleanup: if (b != NULL) isc_buffer_free(&b); }
static isc_result_t gssapi_restore(dst_key_t *key, const char *keystr) { OM_uint32 major, minor; unsigned int len; isc_buffer_t *b = NULL; isc_region_t r; gss_buffer_desc gssbuffer; isc_result_t result; len = strlen(keystr); if ((len % 4) != 0U) return (ISC_R_BADBASE64); len = (len / 4) * 3; result = isc_buffer_allocate(key->mctx, &b, len); if (result != ISC_R_SUCCESS) return (result); result = isc_base64_decodestring(keystr, b); if (result != ISC_R_SUCCESS) { isc_buffer_free(&b); return (result); } isc_buffer_remainingregion(b, &r); REGION_TO_GBUFFER(r, gssbuffer); major = gss_import_sec_context(&minor, &gssbuffer, &key->keydata.gssctx); if (major != GSS_S_COMPLETE) { isc_buffer_free(&b); return (ISC_R_FAILURE); } isc_buffer_free(&b); return (ISC_R_SUCCESS); }
static void print_dtdata(dns_dtdata_t *dt) { isc_result_t result; isc_buffer_t *b = NULL; isc_buffer_allocate(mctx, &b, 2048); if (b == NULL) fatal("out of memory"); CHECKM(dns_dt_datatotext(dt, &b), "dns_dt_datatotext"); printf("%.*s\n", (int) isc_buffer_usedlength(b), (char *) isc_buffer_base(b)); cleanup: if (b != NULL) isc_buffer_free(&b); }
static isc_result_t newconnection(controllistener_t *listener, isc_socket_t *sock) { controlconnection_t *conn; isc_interval_t interval; isc_result_t result; conn = isc_mem_get(listener->mctx, sizeof(*conn)); if (conn == NULL) return (ISC_R_NOMEMORY); conn->sock = sock; isccc_ccmsg_init(listener->mctx, sock, &conn->ccmsg); conn->ccmsg_valid = ISC_TRUE; conn->sending = ISC_FALSE; conn->buffer = NULL; conn->timer = NULL; isc_interval_set(&interval, 60, 0); result = isc_timer_create(ns_g_timermgr, isc_timertype_once, NULL, &interval, listener->task, control_timeout, conn, &conn->timer); if (result != ISC_R_SUCCESS) goto cleanup; conn->listener = listener; conn->nonce = 0; ISC_LINK_INIT(conn, link); result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task, control_recvmessage, conn); if (result != ISC_R_SUCCESS) goto cleanup; ISC_LIST_APPEND(listener->connections, conn, link); return (ISC_R_SUCCESS); cleanup: if (conn->buffer != NULL) isc_buffer_free(&conn->buffer); isccc_ccmsg_invalidate(&conn->ccmsg); if (conn->timer != NULL) isc_timer_detach(&conn->timer); isc_mem_put(listener->mctx, conn, sizeof(*conn)); return (result); }
static void build_name_from_str(const char *namestr, dns_fixedname_t *fname) { size_t length; isc_buffer_t *b = NULL; isc_result_t result; dns_name_t *name; length = strlen(namestr); result = isc_buffer_allocate(mctx, &b, length); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); isc_buffer_putmem(b, (const unsigned char *) namestr, length); dns_fixedname_init(fname); name = dns_fixedname_name(fname); ATF_REQUIRE(name != NULL); result = dns_name_fromtext(name, b, dns_rootname, 0, NULL); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); isc_buffer_free(&b); }
void irs_dnsconf_destroy(irs_dnsconf_t **confp) { irs_dnsconf_t *conf; irs_dnsconf_dnskey_t *keyent; REQUIRE(confp != NULL); conf = *confp; REQUIRE(IRS_DNSCONF_VALID(conf)); while ((keyent = ISC_LIST_HEAD(conf->trusted_keylist)) != NULL) { ISC_LIST_UNLINK(conf->trusted_keylist, keyent, link); isc_buffer_free(&keyent->keydatabuf); dns_name_free(keyent->keyname, conf->mctx); isc_mem_put(conf->mctx, keyent->keyname, sizeof(dns_name_t)); isc_mem_put(conf->mctx, keyent, sizeof(*keyent)); } isc_mem_put(conf->mctx, conf, sizeof(*conf)); *confp = NULL; }
static void xfrout_ctx_destroy(xfrout_ctx_t **xfrp) { xfrout_ctx_t *xfr = *xfrp; ns_client_t *client = NULL; INSIST(xfr->sends == 0); xfr->client->shutdown = NULL; xfr->client->shutdown_arg = NULL; if (xfr->stream != NULL) xfr->stream->methods->destroy(&xfr->stream); if (xfr->buf.base != NULL) isc_mem_put(xfr->mctx, xfr->buf.base, xfr->buf.length); if (xfr->txmem != NULL) isc_mem_put(xfr->mctx, xfr->txmem, xfr->txmemlen); if (xfr->lasttsig != NULL) isc_buffer_free(&xfr->lasttsig); if (xfr->quota != NULL) isc_quota_detach(&xfr->quota); if (xfr->ver != NULL) dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE); if (xfr->zone != NULL) dns_zone_detach(&xfr->zone); if (xfr->db != NULL) dns_db_detach(&xfr->db); /* * We want to detch the client after we have released the memory * context as ns_client_detach checks the memory reference count. */ ns_client_attach(xfr->client, &client); ns_client_detach(&xfr->client); isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr)); ns_client_detach(&client); *xfrp = NULL; }
static void maybe_free_connection(controlconnection_t *conn) { controllistener_t *listener = conn->listener; if (conn->buffer != NULL) isc_buffer_free(&conn->buffer); if (conn->timer != NULL) isc_timer_detach(&conn->timer); if (conn->ccmsg_valid) { isccc_ccmsg_cancelread(&conn->ccmsg); return; } if (conn->sending) { isc_socket_cancel(conn->sock, listener->task, ISC_SOCKCANCEL_SEND); return; } ISC_LIST_UNLINK(listener->connections, conn, link); isc_mem_put(listener->mctx, conn, sizeof(*conn)); }
/* * 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). 20480 was set as an upper limit to * improve message compression. */ if ((isc_buffer_usedlength(&xfr->buf) >= 20480) && 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 */ ®ion, 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"); }
static void control_recvmessage(isc_task_t *task, isc_event_t *event) { controlconnection_t *conn; controllistener_t *listener; controlkey_t *key; isccc_sexpr_t *request = NULL; isccc_sexpr_t *response = NULL; isc_uint32_t algorithm; isccc_region_t secret; isc_stdtime_t now; isc_buffer_t b; isc_region_t r; isc_buffer_t *text; isc_result_t result; isc_result_t eresult; isccc_sexpr_t *_ctrl; isccc_time_t sent; isccc_time_t exp; isc_uint32_t nonce; isccc_sexpr_t *data; REQUIRE(event->ev_type == ISCCC_EVENT_CCMSG); conn = event->ev_arg; listener = conn->listener; algorithm = DST_ALG_UNKNOWN; secret.rstart = NULL; text = NULL; /* Is the server shutting down? */ if (listener->controls->shuttingdown) goto cleanup; if (conn->ccmsg.result != ISC_R_SUCCESS) { if (conn->ccmsg.result != ISC_R_CANCELED && conn->ccmsg.result != ISC_R_EOF) log_invalid(&conn->ccmsg, conn->ccmsg.result); goto cleanup; } request = NULL; for (key = ISC_LIST_HEAD(listener->keys); key != NULL; key = ISC_LIST_NEXT(key, link)) { isccc_region_t ccregion; ccregion.rstart = isc_buffer_base(&conn->ccmsg.buffer); ccregion.rend = isc_buffer_used(&conn->ccmsg.buffer); secret.rstart = isc_mem_get(listener->mctx, key->secret.length); if (secret.rstart == NULL) goto cleanup; memmove(secret.rstart, key->secret.base, key->secret.length); secret.rend = secret.rstart + key->secret.length; algorithm = key->algorithm; result = isccc_cc_fromwire(&ccregion, &request, algorithm, &secret); if (result == ISC_R_SUCCESS) break; isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); if (result != ISCCC_R_BADAUTH) { log_invalid(&conn->ccmsg, result); goto cleanup; } } if (key == NULL) { log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH); goto cleanup; } /* We shouldn't be getting a reply. */ if (isccc_cc_isreply(request)) { log_invalid(&conn->ccmsg, ISC_R_FAILURE); goto cleanup_request; } isc_stdtime_get(&now); /* * Limit exposure to replay attacks. */ _ctrl = isccc_alist_lookup(request, "_ctrl"); if (_ctrl == NULL) { log_invalid(&conn->ccmsg, ISC_R_FAILURE); goto cleanup_request; } if (isccc_cc_lookupuint32(_ctrl, "_tim", &sent) == ISC_R_SUCCESS) { if ((sent + CLOCKSKEW) < now || (sent - CLOCKSKEW) > now) { log_invalid(&conn->ccmsg, ISCCC_R_CLOCKSKEW); goto cleanup_request; } } else { log_invalid(&conn->ccmsg, ISC_R_FAILURE); goto cleanup_request; } /* * Expire messages that are too old. */ if (isccc_cc_lookupuint32(_ctrl, "_exp", &exp) == ISC_R_SUCCESS && now > exp) { log_invalid(&conn->ccmsg, ISCCC_R_EXPIRED); goto cleanup_request; } /* * Duplicate suppression (required for UDP). */ isccc_cc_cleansymtab(listener->controls->symtab, now); result = isccc_cc_checkdup(listener->controls->symtab, request, now); if (result != ISC_R_SUCCESS) { if (result == ISC_R_EXISTS) result = ISCCC_R_DUPLICATE; log_invalid(&conn->ccmsg, result); goto cleanup_request; } if (conn->nonce != 0 && (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS || conn->nonce != nonce)) { log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH); goto cleanup_request; } result = isc_buffer_allocate(listener->mctx, &text, 2 * 2048); if (result != ISC_R_SUCCESS) goto cleanup_request; /* * Establish nonce. */ if (conn->nonce == 0) { while (conn->nonce == 0) isc_random_get(&conn->nonce); eresult = ISC_R_SUCCESS; } else eresult = ns_control_docommand(request, &text); result = isccc_cc_createresponse(request, now, now + 60, &response); if (result != ISC_R_SUCCESS) goto cleanup_request; data = isccc_alist_lookup(response, "_data"); if (data != NULL) { if (isccc_cc_defineuint32(data, "result", eresult) == NULL) goto cleanup_response; } if (eresult != ISC_R_SUCCESS) { if (data != NULL) { const char *estr = isc_result_totext(eresult); if (isccc_cc_definestring(data, "err", estr) == NULL) goto cleanup_response; } } if (isc_buffer_usedlength(text) > 0) { if (data != NULL) { char *str = (char *)isc_buffer_base(text); if (isccc_cc_definestring(data, "text", str) == NULL) goto cleanup_response; } } _ctrl = isccc_alist_lookup(response, "_ctrl"); if (_ctrl == NULL || isccc_cc_defineuint32(_ctrl, "_nonce", conn->nonce) == NULL) goto cleanup_response; if (conn->buffer == NULL) { result = isc_buffer_allocate(listener->mctx, &conn->buffer, 2 * 2048); if (result != ISC_R_SUCCESS) goto cleanup_response; } isc_buffer_clear(conn->buffer); /* Skip the length field (4 bytes) */ isc_buffer_add(conn->buffer, 4); result = isccc_cc_towire(response, &conn->buffer, algorithm, &secret); if (result != ISC_R_SUCCESS) goto cleanup_response; isc_buffer_init(&b, conn->buffer->base, 4); isc_buffer_putuint32(&b, conn->buffer->used - 4); r.base = conn->buffer->base; r.length = conn->buffer->used; result = isc_socket_send(conn->sock, &r, task, control_senddone, conn); if (result != ISC_R_SUCCESS) goto cleanup_response; conn->sending = ISC_TRUE; isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); isccc_sexpr_free(&request); isccc_sexpr_free(&response); isc_buffer_free(&text); return; cleanup_response: isccc_sexpr_free(&response); cleanup_request: isccc_sexpr_free(&request); isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); if (text != NULL) isc_buffer_free(&text); cleanup: isc_socket_detach(&conn->sock); isccc_ccmsg_invalidate(&conn->ccmsg); conn->ccmsg_valid = ISC_FALSE; maybe_free_connection(conn); maybe_free_listener(listener); }
int main(int argc, char *argv[]) { int ch, i, gai_error; struct addrinfo hints, *res; isc_textregion_t tr; dns_client_t *client = NULL; isc_result_t result; isc_sockaddr_t sa; dns_message_t *qmessage, *rmessage; dns_rdatatype_t type = dns_rdatatype_a; isc_buffer_t *outputbuf; while ((ch = getopt(argc, argv, "t:")) != -1) { switch (ch) { case 't': tr.base = optarg; tr.length = strlen(optarg); result = dns_rdatatype_fromtext(&type, &tr); if (result != ISC_R_SUCCESS) { fprintf(stderr, "invalid RRtype: %s\n", optarg); exit(1); } break; default: usage(); } } argc -= optind; argv += optind; if (argc < 2) usage(); isc_lib_register(); result = dns_lib_init(); if (result != ISC_R_SUCCESS) { fprintf(stderr, "dns_lib_init failed: %d\n", result); exit(1); } result = dns_client_create(&client, 0); if (result != ISC_R_SUCCESS) { fprintf(stderr, "dns_client_create failed: %d\n", result); exit(1); } /* Prepare message structures */ mctx = NULL; qmessage = NULL; rmessage = NULL; result = isc_mem_create(0, 0, &mctx); if (result != ISC_R_SUCCESS) { fprintf(stderr, "failed to create a memory context\n"); exit(1); } result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &qmessage); if (result == ISC_R_SUCCESS) { result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rmessage); } if (result != ISC_R_SUCCESS) { fprintf(stderr, "failed to create messages\n"); exit(1); } /* Initialize the nameserver address */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; hints.ai_flags = AI_NUMERICHOST; gai_error = getaddrinfo(argv[0], "53", &hints, &res); if (gai_error != 0) { fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(gai_error)); exit(1); } INSIST(res->ai_addrlen <= sizeof(sa.type)); memcpy(&sa.type, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); sa.length = res->ai_addrlen; ISC_LINK_INIT(&sa, link); /* Construct qname */ result = make_querymessage(qmessage, argv[1], type); if (result != ISC_R_SUCCESS) { fprintf(stderr, "failed to create a query\n"); exit(1); } /* Send request and wait for a response */ result = dns_client_request(client, qmessage, rmessage, &sa, 0, 0, NULL, 60, 0, 3); if (result != ISC_R_SUCCESS) { fprintf(stderr, "failed to get a response: %s\n", dns_result_totext(result)); } /* Dump the response */ outputbuf = NULL; result = isc_buffer_allocate(mctx, &outputbuf, 65535); if (result != ISC_R_SUCCESS) { fprintf(stderr, "failed to allocate a result buffer\n"); exit(1); } for (i = 0; i < DNS_SECTION_MAX; i++) { print_section(rmessage, i, outputbuf); isc_buffer_clear(outputbuf); } isc_buffer_free(&outputbuf); /* Cleanup */ dns_message_destroy(&qmessage); dns_message_destroy(&rmessage); isc_mem_destroy(&mctx); dns_client_destroy(&client); dns_lib_shutdown(); exit(0); }
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); }
/* * Callback from dighost.c to print the reply from a server */ isc_result_t printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { isc_result_t result; dns_messagetextflag_t flags; isc_buffer_t *buf = NULL; unsigned int len = OUTPUTBUF; dns_master_style_t *style = NULL; unsigned int styleflags = 0; styleflags |= DNS_STYLEFLAG_REL_OWNER; if (query->lookup->comments) styleflags |= DNS_STYLEFLAG_COMMENT; if (rrcomments) styleflags |= DNS_STYLEFLAG_RRCOMMENT; if (nottl) styleflags |= DNS_STYLEFLAG_NO_TTL; if (noclass) styleflags |= DNS_STYLEFLAG_NO_CLASS; if (multiline) { styleflags |= DNS_STYLEFLAG_OMIT_OWNER; styleflags |= DNS_STYLEFLAG_OMIT_CLASS; styleflags |= DNS_STYLEFLAG_REL_DATA; styleflags |= DNS_STYLEFLAG_OMIT_TTL; styleflags |= DNS_STYLEFLAG_TTL; styleflags |= DNS_STYLEFLAG_MULTILINE; styleflags |= DNS_STYLEFLAG_RRCOMMENT; } if (multiline || (nottl && noclass)) result = dns_master_stylecreate2(&style, styleflags, 24, 24, 24, 32, 80, 8, splitwidth, mctx); else if (nottl || noclass) result = dns_master_stylecreate2(&style, styleflags, 24, 24, 32, 40, 80, 8, splitwidth, mctx); else result = dns_master_stylecreate2(&style, styleflags, 24, 32, 40, 48, 80, 8, splitwidth, mctx); check_result(result, "dns_master_stylecreate"); if (query->lookup->cmdline[0] != 0) { if (!short_form) fputs(query->lookup->cmdline, stdout); query->lookup->cmdline[0]=0; } debug("printmessage(%s %s %s)", headers ? "headers" : "noheaders", query->lookup->comments ? "comments" : "nocomments", short_form ? "short_form" : "long_form"); flags = 0; if (!headers) { flags |= DNS_MESSAGETEXTFLAG_NOHEADERS; flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS; } if (onesoa && query->lookup->rdtype == dns_rdatatype_axfr) flags |= (query->msg_count == 0) ? DNS_MESSAGETEXTFLAG_ONESOA : DNS_MESSAGETEXTFLAG_OMITSOA; if (!query->lookup->comments) flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS; result = isc_buffer_allocate(mctx, &buf, len); check_result(result, "isc_buffer_allocate"); if (query->lookup->comments && !short_form) { if (query->lookup->cmdline[0] != 0) printf("; %s\n", query->lookup->cmdline); if (msg == query->lookup->sendmsg) printf(";; Sending:\n"); else printf(";; Got answer:\n"); if (headers) { printf(";; ->>HEADER<<- opcode: %s, status: %s, " "id: %u\n", opcodetext[msg->opcode], rcode_totext(msg->rcode), msg->id); printf(";; flags:"); if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) printf(" qr"); if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) printf(" aa"); if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) printf(" tc"); if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) printf(" rd"); if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) printf(" ra"); if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) printf(" ad"); if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) printf(" cd"); if ((msg->flags & 0x0040U) != 0) printf("; MBZ: 0x4"); printf("; QUERY: %u, ANSWER: %u, " "AUTHORITY: %u, ADDITIONAL: %u\n", msg->counts[DNS_SECTION_QUESTION], msg->counts[DNS_SECTION_ANSWER], msg->counts[DNS_SECTION_AUTHORITY], msg->counts[DNS_SECTION_ADDITIONAL]); if (msg != query->lookup->sendmsg && (msg->flags & DNS_MESSAGEFLAG_RD) != 0 && (msg->flags & DNS_MESSAGEFLAG_RA) == 0) printf(";; WARNING: recursion requested " "but not available\n"); } if (msg != query->lookup->sendmsg && query->lookup->edns != -1 && msg->opt == NULL && (msg->rcode == dns_rcode_formerr || msg->rcode == dns_rcode_notimp)) printf("\n;; WARNING: EDNS query returned status " "%s - retry with '+noedns'\n", rcode_totext(msg->rcode)); if (msg != query->lookup->sendmsg && extrabytes != 0U) printf(";; WARNING: Messages has %u extra byte%s at " "end\n", extrabytes, extrabytes != 0 ? "s" : ""); } repopulate_buffer: if (query->lookup->comments && headers && !short_form) { result = dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_OPT, style, flags, buf); if (result == ISC_R_NOSPACE) { buftoosmall: len += OUTPUTBUF; isc_buffer_free(&buf); result = isc_buffer_allocate(mctx, &buf, len); if (result == ISC_R_SUCCESS) goto repopulate_buffer; else goto cleanup; } check_result(result, "dns_message_pseudosectiontotext"); } if (query->lookup->section_question && headers) { if (!short_form) { result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION, style, flags, buf); if (result == ISC_R_NOSPACE) goto buftoosmall; check_result(result, "dns_message_sectiontotext"); } } if (query->lookup->section_answer) { if (!short_form) { result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER, style, flags, buf); if (result == ISC_R_NOSPACE) goto buftoosmall; check_result(result, "dns_message_sectiontotext"); } else { result = short_answer(msg, flags, buf, query); if (result == ISC_R_NOSPACE) goto buftoosmall; check_result(result, "short_answer"); } } if (query->lookup->section_authority) { if (!short_form) { result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY, style, flags, buf); if (result == ISC_R_NOSPACE) goto buftoosmall; check_result(result, "dns_message_sectiontotext"); } } if (query->lookup->section_additional) { if (!short_form) { result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL, style, flags, buf); if (result == ISC_R_NOSPACE) goto buftoosmall; check_result(result, "dns_message_sectiontotext"); /* * Only print the signature on the first record. */ if (headers) { result = dns_message_pseudosectiontotext( msg, DNS_PSEUDOSECTION_TSIG, style, flags, buf); if (result == ISC_R_NOSPACE) goto buftoosmall; check_result(result, "dns_message_pseudosectiontotext"); result = dns_message_pseudosectiontotext( msg, DNS_PSEUDOSECTION_SIG0, style, flags, buf); if (result == ISC_R_NOSPACE) goto buftoosmall; check_result(result, "dns_message_pseudosectiontotext"); } } } if (headers && query->lookup->comments && !short_form) printf("\n"); printf("%.*s", (int)isc_buffer_usedlength(buf), (char *)isc_buffer_base(buf)); isc_buffer_free(&buf); cleanup: if (style != NULL) dns_master_styledestroy(&style, mctx); return (result); }
isc_result_t dns_tsig_sign(dns_message_t *msg) { dns_tsigkey_t *key; dns_rdata_any_tsig_t tsig, querytsig; unsigned char data[128]; isc_buffer_t databuf, sigbuf; isc_buffer_t *dynbuf; dns_name_t *owner; dns_rdata_t *rdata; dns_rdatalist_t *datalist; dns_rdataset_t *dataset; isc_region_t r; isc_stdtime_t now; isc_mem_t *mctx; dst_context_t *ctx = NULL; isc_result_t ret; unsigned char badtimedata[BADTIMELEN]; unsigned int sigsize = 0; REQUIRE(msg != NULL); REQUIRE(VALID_TSIG_KEY(dns_message_gettsigkey(msg))); /* * If this is a response, there should be a query tsig. */ if (is_response(msg) && msg->querytsig == NULL) return (DNS_R_EXPECTEDTSIG); dynbuf = NULL; mctx = msg->mctx; key = dns_message_gettsigkey(msg); tsig.mctx = mctx; tsig.common.rdclass = dns_rdataclass_any; tsig.common.rdtype = dns_rdatatype_tsig; ISC_LINK_INIT(&tsig.common, link); dns_name_init(&tsig.algorithm, NULL); dns_name_clone(key->algorithm, &tsig.algorithm); isc_stdtime_get(&now); tsig.timesigned = now + msg->timeadjust; tsig.fudge = DNS_TSIG_FUDGE; tsig.originalid = msg->id; isc_buffer_init(&databuf, data, sizeof(data)); if (is_response(msg)) tsig.error = msg->querytsigstatus; else tsig.error = dns_rcode_noerror; if (tsig.error != dns_tsigerror_badtime) { tsig.otherlen = 0; tsig.other = NULL; } else { isc_buffer_t otherbuf; tsig.otherlen = BADTIMELEN; tsig.other = badtimedata; isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen); buffer_putuint48(&otherbuf, tsig.timesigned); } if (key->key != NULL && tsig.error != dns_tsigerror_badsig) { unsigned char header[DNS_MESSAGE_HEADERLEN]; isc_buffer_t headerbuf; ret = dst_context_create(key->key, mctx, &ctx); if (ret != ISC_R_SUCCESS) return (ret); /* * If this is a response, digest the query signature. */ if (is_response(msg)) { dns_rdata_t querytsigrdata = DNS_RDATA_INIT; ret = dns_rdataset_first(msg->querytsig); if (ret != ISC_R_SUCCESS) goto cleanup_context; dns_rdataset_current(msg->querytsig, &querytsigrdata); ret = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL); if (ret != ISC_R_SUCCESS) goto cleanup_context; isc_buffer_putuint16(&databuf, querytsig.siglen); if (isc_buffer_availablelength(&databuf) < querytsig.siglen) { ret = ISC_R_NOSPACE; goto cleanup_context; } isc_buffer_putmem(&databuf, querytsig.signature, querytsig.siglen); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; } /* * Digest the header. */ isc_buffer_init(&headerbuf, header, sizeof(header)); dns_message_renderheader(msg, &headerbuf); isc_buffer_usedregion(&headerbuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; /* * Digest the remainder of the message. */ isc_buffer_usedregion(msg->buffer, &r); isc_region_consume(&r, DNS_MESSAGE_HEADERLEN); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; if (msg->tcp_continuation == 0) { /* * Digest the name, class, ttl, alg. */ dns_name_toregion(&key->name, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; isc_buffer_clear(&databuf); isc_buffer_putuint16(&databuf, dns_rdataclass_any); isc_buffer_putuint32(&databuf, 0); /* ttl */ isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; dns_name_toregion(&tsig.algorithm, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; } /* Digest the timesigned and fudge */ isc_buffer_clear(&databuf); if (tsig.error == dns_tsigerror_badtime) tsig.timesigned = querytsig.timesigned; buffer_putuint48(&databuf, tsig.timesigned); isc_buffer_putuint16(&databuf, tsig.fudge); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; if (msg->tcp_continuation == 0) { /* * Digest the error and other data length. */ isc_buffer_clear(&databuf); isc_buffer_putuint16(&databuf, tsig.error); isc_buffer_putuint16(&databuf, tsig.otherlen); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; /* * Digest the error and other data. */ if (tsig.otherlen > 0) { r.length = tsig.otherlen; r.base = tsig.other; ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; } } ret = dst_key_sigsize(key->key, &sigsize); if (ret != ISC_R_SUCCESS) goto cleanup_context; tsig.signature = (unsigned char *) isc_mem_get(mctx, sigsize); if (tsig.signature == NULL) { ret = ISC_R_NOMEMORY; goto cleanup_context; } isc_buffer_init(&sigbuf, tsig.signature, sigsize); ret = dst_context_sign(ctx, &sigbuf); if (ret != ISC_R_SUCCESS) goto cleanup_signature; dst_context_destroy(&ctx); tsig.siglen = isc_buffer_usedlength(&sigbuf); } else { tsig.siglen = 0; tsig.signature = NULL; } rdata = NULL; ret = dns_message_gettemprdata(msg, &rdata); if (ret != ISC_R_SUCCESS) goto cleanup_signature; ret = isc_buffer_allocate(msg->mctx, &dynbuf, 512); if (ret != ISC_R_SUCCESS) goto cleanup_signature; ret = dns_rdata_fromstruct(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &tsig, dynbuf); if (ret != ISC_R_SUCCESS) goto cleanup_dynbuf; dns_message_takebuffer(msg, &dynbuf); if (tsig.signature != NULL) { isc_mem_put(mctx, tsig.signature, sigsize); tsig.signature = NULL; } owner = NULL; ret = dns_message_gettempname(msg, &owner); if (ret != ISC_R_SUCCESS) goto cleanup_dynbuf; dns_name_init(owner, NULL); ret = dns_name_dup(&key->name, msg->mctx, owner); if (ret != ISC_R_SUCCESS) goto cleanup_owner; datalist = NULL; ret = dns_message_gettemprdatalist(msg, &datalist); if (ret != ISC_R_SUCCESS) goto cleanup_owner; datalist->rdclass = dns_rdataclass_any; datalist->type = dns_rdatatype_tsig; datalist->covers = 0; datalist->ttl = 0; ISC_LIST_INIT(datalist->rdata); ISC_LIST_APPEND(datalist->rdata, rdata, link); dataset = NULL; ret = dns_message_gettemprdataset(msg, &dataset); if (ret != ISC_R_SUCCESS) goto cleanup_owner; dns_rdataset_init(dataset); RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS); msg->tsig = dataset; msg->tsigname = owner; return (ISC_R_SUCCESS); cleanup_owner: if (owner != NULL) dns_message_puttempname(msg, &owner); cleanup_dynbuf: if (dynbuf != NULL) isc_buffer_free(&dynbuf); cleanup_signature: if (tsig.signature != NULL) isc_mem_put(mctx, tsig.signature, sigsize); cleanup_context: if (ctx != NULL) dst_context_destroy(&ctx); return (ret); }
int main(int argc, char *argv[]) { int ch; struct addrinfo hints, *res; int gai_error; dns_client_t *client = NULL; char *zonenamestr = NULL; char *keyfilename = NULL; char *prereqstr = NULL; isc_sockaddrlist_t auth_servers; char *auth_server = NULL; char *recursive_server = NULL; isc_sockaddr_t sa_auth, sa_recursive; isc_sockaddrlist_t rec_servers; isc_result_t result; isc_boolean_t isdelete; isc_buffer_t b, *buf; dns_fixedname_t zname0, pname0, uname0; size_t namelen; dns_name_t *zname = NULL, *uname, *pname; dns_rdataset_t *rdataset; dns_rdatalist_t *rdatalist; dns_rdata_t *rdata; dns_namelist_t updatelist, prereqlist, *prereqlistp = NULL; isc_mem_t *umctx = NULL; while ((ch = getopt(argc, argv, "a:k:p:r:z:")) != -1) { switch (ch) { case 'k': keyfilename = optarg; break; case 'a': auth_server = optarg; break; case 'p': prereqstr = optarg; break; case 'r': recursive_server = optarg; break; case 'z': zonenamestr = optarg; break; default: usage(); } } argc -= optind; argv += optind; if (argc < 2) usage(); /* command line argument validation */ if (strcmp(argv[0], "delete") == 0) isdelete = ISC_TRUE; else if (strcmp(argv[0], "add") == 0) isdelete = ISC_FALSE; else { fprintf(stderr, "invalid update command: %s\n", argv[0]); exit(1); } if (auth_server == NULL && recursive_server == NULL) { fprintf(stderr, "authoritative or recursive server " "must be specified\n"); usage(); } /* Initialization */ ISC_LIST_INIT(usedbuffers); ISC_LIST_INIT(usedrdatalists); ISC_LIST_INIT(prereqlist); ISC_LIST_INIT(auth_servers); isc_lib_register(); result = dns_lib_init(); if (result != ISC_R_SUCCESS) { fprintf(stderr, "dns_lib_init failed: %d\n", result); exit(1); } result = isc_mem_create(0, 0, &umctx); if (result != ISC_R_SUCCESS) { fprintf(stderr, "failed to crate mctx\n"); exit(1); } result = dns_client_create(&client, 0); if (result != ISC_R_SUCCESS) { fprintf(stderr, "dns_client_create failed: %d\n", result); exit(1); } /* Set the authoritative server */ if (auth_server != NULL) { memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; hints.ai_flags = AI_NUMERICHOST; gai_error = getaddrinfo(auth_server, "53", &hints, &res); if (gai_error != 0) { fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(gai_error)); exit(1); } INSIST(res->ai_addrlen <= sizeof(sa_auth.type)); memmove(&sa_auth.type, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); sa_auth.length = res->ai_addrlen; ISC_LINK_INIT(&sa_auth, link); ISC_LIST_APPEND(auth_servers, &sa_auth, link); } /* Set the recursive server */ if (recursive_server != NULL) { memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; hints.ai_flags = AI_NUMERICHOST; gai_error = getaddrinfo(recursive_server, "53", &hints, &res); if (gai_error != 0) { fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(gai_error)); exit(1); } INSIST(res->ai_addrlen <= sizeof(sa_recursive.type)); memmove(&sa_recursive.type, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); sa_recursive.length = res->ai_addrlen; ISC_LINK_INIT(&sa_recursive, link); ISC_LIST_INIT(rec_servers); ISC_LIST_APPEND(rec_servers, &sa_recursive, link); result = dns_client_setservers(client, dns_rdataclass_in, NULL, &rec_servers); if (result != ISC_R_SUCCESS) { fprintf(stderr, "set server failed: %d\n", result); exit(1); } } /* Construct zone name */ zname = NULL; if (zonenamestr != NULL) { namelen = strlen(zonenamestr); isc_buffer_init(&b, zonenamestr, namelen); isc_buffer_add(&b, namelen); dns_fixedname_init(&zname0); zname = dns_fixedname_name(&zname0); result = dns_name_fromtext(zname, &b, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) fprintf(stderr, "failed to convert zone name: %d\n", result); } /* Construct prerequisite name (if given) */ if (prereqstr != NULL) { dns_fixedname_init(&pname0); pname = dns_fixedname_name(&pname0); evaluate_prereq(umctx, prereqstr, pname); ISC_LIST_APPEND(prereqlist, pname, link); prereqlistp = &prereqlist; } /* Construct update name */ ISC_LIST_INIT(updatelist); dns_fixedname_init(&uname0); uname = dns_fixedname_name(&uname0); update_addordelete(umctx, argv[1], isdelete, uname); ISC_LIST_APPEND(updatelist, uname, link); /* Set up TSIG/SIG(0) key (if given) */ if (keyfilename != NULL) setup_tsec(keyfilename, umctx); /* Perform update */ result = dns_client_update(client, default_rdataclass, /* XXX: fixed */ zname, prereqlistp, &updatelist, (auth_server == NULL) ? NULL : &auth_servers, tsec, 0); if (result != ISC_R_SUCCESS) { fprintf(stderr, "update failed: %s\n", dns_result_totext(result)); } else fprintf(stderr, "update succeeded\n"); /* Cleanup */ while ((pname = ISC_LIST_HEAD(prereqlist)) != NULL) { while ((rdataset = ISC_LIST_HEAD(pname->list)) != NULL) { ISC_LIST_UNLINK(pname->list, rdataset, link); dns_rdataset_disassociate(rdataset); isc_mem_put(umctx, rdataset, sizeof(*rdataset)); } ISC_LIST_UNLINK(prereqlist, pname, link); } while ((uname = ISC_LIST_HEAD(updatelist)) != NULL) { while ((rdataset = ISC_LIST_HEAD(uname->list)) != NULL) { ISC_LIST_UNLINK(uname->list, rdataset, link); dns_rdataset_disassociate(rdataset); isc_mem_put(umctx, rdataset, sizeof(*rdataset)); } ISC_LIST_UNLINK(updatelist, uname, link); } while ((rdatalist = ISC_LIST_HEAD(usedrdatalists)) != NULL) { while ((rdata = ISC_LIST_HEAD(rdatalist->rdata)) != NULL) { ISC_LIST_UNLINK(rdatalist->rdata, rdata, link); isc_mem_put(umctx, rdata, sizeof(*rdata)); } ISC_LIST_UNLINK(usedrdatalists, rdatalist, link); isc_mem_put(umctx, rdatalist, sizeof(*rdatalist)); } while ((buf = ISC_LIST_HEAD(usedbuffers)) != NULL) { ISC_LIST_UNLINK(usedbuffers, buf, link); isc_buffer_free(&buf); } if (tsec != NULL) dns_tsec_destroy(&tsec); isc_mem_destroy(&umctx); dns_client_destroy(&client); dns_lib_shutdown(); return (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); }
isc_result_t dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, isc_stdtime_t *inception, isc_stdtime_t *expire, isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata) { dns_rdata_rrsig_t sig; dns_rdata_t tmpsigrdata; dns_rdata_t *rdatas; int nrdatas, i; isc_buffer_t sigbuf, envbuf; isc_region_t r; dst_context_t *ctx = NULL; isc_result_t ret; isc_buffer_t *databuf = NULL; char data[256 + 8]; isc_uint32_t flags; unsigned int sigsize; dns_fixedname_t fnewname; REQUIRE(name != NULL); REQUIRE(dns_name_countlabels(name) <= 255); REQUIRE(set != NULL); REQUIRE(key != NULL); REQUIRE(inception != NULL); REQUIRE(expire != NULL); REQUIRE(mctx != NULL); REQUIRE(sigrdata != NULL); if (*inception >= *expire) return (DNS_R_INVALIDTIME); /* * Is the key allowed to sign data? */ flags = dst_key_flags(key); if (flags & DNS_KEYTYPE_NOAUTH) return (DNS_R_KEYUNAUTHORIZED); if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE) return (DNS_R_KEYUNAUTHORIZED); sig.mctx = mctx; sig.common.rdclass = set->rdclass; sig.common.rdtype = dns_rdatatype_rrsig; ISC_LINK_INIT(&sig.common, link); dns_name_init(&sig.signer, NULL); dns_name_clone(dst_key_name(key), &sig.signer); sig.covered = set->type; sig.algorithm = dst_key_alg(key); sig.labels = dns_name_countlabels(name) - 1; if (dns_name_iswildcard(name)) sig.labels--; sig.originalttl = set->ttl; sig.timesigned = *inception; sig.timeexpire = *expire; sig.keyid = dst_key_id(key); ret = dst_key_sigsize(key, &sigsize); if (ret != ISC_R_SUCCESS) return (ret); sig.siglen = sigsize; /* * The actual contents of sig.signature are not important yet, since * they're not used in digest_sig(). */ sig.signature = isc_mem_get(mctx, sig.siglen); if (sig.signature == NULL) return (ISC_R_NOMEMORY); ret = isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18); if (ret != ISC_R_SUCCESS) goto cleanup_signature; dns_rdata_init(&tmpsigrdata); ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass, sig.common.rdtype, &sig, databuf); if (ret != ISC_R_SUCCESS) goto cleanup_databuf; ret = dst_context_create(key, mctx, &ctx); if (ret != ISC_R_SUCCESS) goto cleanup_databuf; /* * Digest the SIG rdata. */ ret = digest_sig(ctx, &tmpsigrdata, &sig); if (ret != ISC_R_SUCCESS) goto cleanup_context; dns_fixedname_init(&fnewname); RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname), NULL) == ISC_R_SUCCESS); dns_name_toregion(dns_fixedname_name(&fnewname), &r); /* * Create an envelope for each rdata: <name|type|class|ttl>. */ isc_buffer_init(&envbuf, data, sizeof(data)); memcpy(data, r.base, r.length); isc_buffer_add(&envbuf, r.length); isc_buffer_putuint16(&envbuf, set->type); isc_buffer_putuint16(&envbuf, set->rdclass); isc_buffer_putuint32(&envbuf, set->ttl); ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas); if (ret != ISC_R_SUCCESS) goto cleanup_context; isc_buffer_usedregion(&envbuf, &r); for (i = 0; i < nrdatas; i++) { isc_uint16_t len; isc_buffer_t lenbuf; isc_region_t lenr; /* * Skip duplicates. */ if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0) continue; /* * Digest the envelope. */ ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_array; /* * Digest the length of the rdata. */ isc_buffer_init(&lenbuf, &len, sizeof(len)); INSIST(rdatas[i].length < 65536); isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length); isc_buffer_usedregion(&lenbuf, &lenr); ret = dst_context_adddata(ctx, &lenr); if (ret != ISC_R_SUCCESS) goto cleanup_array; /* * Digest the rdata. */ ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx); if (ret != ISC_R_SUCCESS) goto cleanup_array; } isc_buffer_init(&sigbuf, sig.signature, sig.siglen); ret = dst_context_sign(ctx, &sigbuf); if (ret != ISC_R_SUCCESS) goto cleanup_array; isc_buffer_usedregion(&sigbuf, &r); if (r.length != sig.siglen) { ret = ISC_R_NOSPACE; goto cleanup_array; } memcpy(sig.signature, r.base, sig.siglen); ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass, sig.common.rdtype, &sig, buffer); cleanup_array: isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t)); cleanup_context: dst_context_destroy(&ctx); cleanup_databuf: isc_buffer_free(&databuf); cleanup_signature: isc_mem_put(mctx, sig.signature, sig.siglen); return (ret); }
isc_result_t dns_tsig_sign(dns_message_t *msg) { dns_tsigkey_t *key; dns_rdata_any_tsig_t tsig, querytsig; unsigned char data[128]; isc_buffer_t databuf, sigbuf; isc_buffer_t *dynbuf; dns_name_t *owner; dns_rdata_t *rdata = NULL; dns_rdatalist_t *datalist; dns_rdataset_t *dataset; isc_region_t r; isc_stdtime_t now; isc_mem_t *mctx; dst_context_t *ctx = NULL; isc_result_t ret; unsigned char badtimedata[BADTIMELEN]; unsigned int sigsize = 0; isc_boolean_t response = is_response(msg); REQUIRE(msg != NULL); REQUIRE(VALID_TSIG_KEY(dns_message_gettsigkey(msg))); /* * If this is a response, there should be a query tsig. */ if (response && msg->querytsig == NULL) return (DNS_R_EXPECTEDTSIG); dynbuf = NULL; mctx = msg->mctx; key = dns_message_gettsigkey(msg); tsig.mctx = mctx; tsig.common.rdclass = dns_rdataclass_any; tsig.common.rdtype = dns_rdatatype_tsig; ISC_LINK_INIT(&tsig.common, link); dns_name_init(&tsig.algorithm, NULL); dns_name_clone(key->algorithm, &tsig.algorithm); isc_stdtime_get(&now); tsig.timesigned = now + msg->timeadjust; tsig.fudge = DNS_TSIG_FUDGE; tsig.originalid = msg->id; isc_buffer_init(&databuf, data, sizeof(data)); if (response) tsig.error = msg->querytsigstatus; else tsig.error = dns_rcode_noerror; if (tsig.error != dns_tsigerror_badtime) { tsig.otherlen = 0; tsig.other = NULL; } else { isc_buffer_t otherbuf; tsig.otherlen = BADTIMELEN; tsig.other = badtimedata; isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen); isc_buffer_putuint48(&otherbuf, tsig.timesigned); } if (key->key != NULL && tsig.error != dns_tsigerror_badsig) { unsigned char header[DNS_MESSAGE_HEADERLEN]; isc_buffer_t headerbuf; isc_uint16_t digestbits; ret = dst_context_create3(key->key, mctx, DNS_LOGCATEGORY_DNSSEC, ISC_TRUE, &ctx); if (ret != ISC_R_SUCCESS) return (ret); /* * If this is a response, digest the query signature. */ if (response) { dns_rdata_t querytsigrdata = DNS_RDATA_INIT; ret = dns_rdataset_first(msg->querytsig); if (ret != ISC_R_SUCCESS) goto cleanup_context; dns_rdataset_current(msg->querytsig, &querytsigrdata); ret = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL); if (ret != ISC_R_SUCCESS) goto cleanup_context; isc_buffer_putuint16(&databuf, querytsig.siglen); if (isc_buffer_availablelength(&databuf) < querytsig.siglen) { ret = ISC_R_NOSPACE; goto cleanup_context; } isc_buffer_putmem(&databuf, querytsig.signature, querytsig.siglen); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; } #if defined(__clang__) && \ ( __clang_major__ < 3 || \ (__clang_major__ == 3 && __clang_minor__ < 2) || \ (__clang_major__ == 4 && __clang_minor__ < 2)) /* false positive: http://llvm.org/bugs/show_bug.cgi?id=14461 */ else memset(&querytsig, 0, sizeof(querytsig)); #endif /* * Digest the header. */ isc_buffer_init(&headerbuf, header, sizeof(header)); dns_message_renderheader(msg, &headerbuf); isc_buffer_usedregion(&headerbuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; /* * Digest the remainder of the message. */ isc_buffer_usedregion(msg->buffer, &r); isc_region_consume(&r, DNS_MESSAGE_HEADERLEN); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; if (msg->tcp_continuation == 0) { /* * Digest the name, class, ttl, alg. */ dns_name_toregion(&key->name, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; isc_buffer_clear(&databuf); isc_buffer_putuint16(&databuf, dns_rdataclass_any); isc_buffer_putuint32(&databuf, 0); /* ttl */ isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; dns_name_toregion(&tsig.algorithm, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; } /* Digest the timesigned and fudge */ isc_buffer_clear(&databuf); if (tsig.error == dns_tsigerror_badtime) { INSIST(response); tsig.timesigned = querytsig.timesigned; } isc_buffer_putuint48(&databuf, tsig.timesigned); isc_buffer_putuint16(&databuf, tsig.fudge); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; if (msg->tcp_continuation == 0) { /* * Digest the error and other data length. */ isc_buffer_clear(&databuf); isc_buffer_putuint16(&databuf, tsig.error); isc_buffer_putuint16(&databuf, tsig.otherlen); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; /* * Digest other data. */ if (tsig.otherlen > 0) { r.length = tsig.otherlen; r.base = tsig.other; ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; } } ret = dst_key_sigsize(key->key, &sigsize); if (ret != ISC_R_SUCCESS) goto cleanup_context; tsig.signature = (unsigned char *) isc_mem_get(mctx, sigsize); if (tsig.signature == NULL) { ret = ISC_R_NOMEMORY; goto cleanup_context; } isc_buffer_init(&sigbuf, tsig.signature, sigsize); ret = dst_context_sign(ctx, &sigbuf); if (ret != ISC_R_SUCCESS) goto cleanup_signature; dst_context_destroy(&ctx); digestbits = dst_key_getbits(key->key); if (digestbits != 0) { unsigned int bytes = (digestbits + 1) / 8; if (response && bytes < querytsig.siglen) bytes = querytsig.siglen; if (bytes > isc_buffer_usedlength(&sigbuf)) bytes = isc_buffer_usedlength(&sigbuf); tsig.siglen = bytes; } else tsig.siglen = isc_buffer_usedlength(&sigbuf); } else { tsig.siglen = 0; tsig.signature = NULL; } ret = dns_message_gettemprdata(msg, &rdata); if (ret != ISC_R_SUCCESS) goto cleanup_signature; ret = isc_buffer_allocate(msg->mctx, &dynbuf, 512); if (ret != ISC_R_SUCCESS) goto cleanup_rdata; ret = dns_rdata_fromstruct(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &tsig, dynbuf); if (ret != ISC_R_SUCCESS) goto cleanup_dynbuf; dns_message_takebuffer(msg, &dynbuf); if (tsig.signature != NULL) { isc_mem_put(mctx, tsig.signature, sigsize); tsig.signature = NULL; } owner = NULL; ret = dns_message_gettempname(msg, &owner); if (ret != ISC_R_SUCCESS) goto cleanup_rdata; dns_name_init(owner, NULL); ret = dns_name_dup(&key->name, msg->mctx, owner); if (ret != ISC_R_SUCCESS) goto cleanup_owner; datalist = NULL; ret = dns_message_gettemprdatalist(msg, &datalist); if (ret != ISC_R_SUCCESS) goto cleanup_owner; dataset = NULL; ret = dns_message_gettemprdataset(msg, &dataset); if (ret != ISC_R_SUCCESS) goto cleanup_rdatalist; datalist->rdclass = dns_rdataclass_any; datalist->type = dns_rdatatype_tsig; datalist->covers = 0; datalist->ttl = 0; ISC_LIST_INIT(datalist->rdata); ISC_LIST_APPEND(datalist->rdata, rdata, link); RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS); msg->tsig = dataset; msg->tsigname = owner; /* Windows does not like the tsig name being compressed. */ msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS; return (ISC_R_SUCCESS); cleanup_rdatalist: dns_message_puttemprdatalist(msg, &datalist); cleanup_owner: dns_message_puttempname(msg, &owner); goto cleanup_rdata; cleanup_dynbuf: isc_buffer_free(&dynbuf); cleanup_rdata: dns_message_puttemprdata(msg, &rdata); cleanup_signature: if (tsig.signature != NULL) isc_mem_put(mctx, tsig.signature, sigsize); cleanup_context: if (ctx != NULL) dst_context_destroy(&ctx); return (ret); }
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); }
isc_result_t dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) { dns_rdata_sig_t sig; /* SIG(0) */ unsigned char data[512]; unsigned char header[DNS_MESSAGE_HEADERLEN]; isc_buffer_t headerbuf, databuf, sigbuf; unsigned int sigsize; isc_buffer_t *dynbuf = NULL; dns_rdata_t *rdata; dns_rdatalist_t *datalist; dns_rdataset_t *dataset; isc_region_t r; isc_stdtime_t now; dst_context_t *ctx = NULL; isc_mem_t *mctx; isc_result_t result; isc_boolean_t signeedsfree = ISC_TRUE; REQUIRE(msg != NULL); REQUIRE(key != NULL); if (is_response(msg)) REQUIRE(msg->query.base != NULL); mctx = msg->mctx; memset(&sig, 0, sizeof(sig)); sig.mctx = mctx; sig.common.rdclass = dns_rdataclass_any; sig.common.rdtype = dns_rdatatype_sig; /* SIG(0) */ ISC_LINK_INIT(&sig.common, link); sig.covered = 0; sig.algorithm = dst_key_alg(key); sig.labels = 0; /* the root name */ sig.originalttl = 0; isc_stdtime_get(&now); sig.timesigned = now - DNS_TSIG_FUDGE; sig.timeexpire = now + DNS_TSIG_FUDGE; sig.keyid = dst_key_id(key); dns_name_init(&sig.signer, NULL); dns_name_clone(dst_key_name(key), &sig.signer); sig.siglen = 0; sig.signature = NULL; isc_buffer_init(&databuf, data, sizeof(data)); RETERR(dst_context_create(key, mctx, &ctx)); /* * Digest the fields of the SIG - we can cheat and use * dns_rdata_fromstruct. Since siglen is 0, the digested data * is identical to dns format. */ RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any, dns_rdatatype_sig /* SIG(0) */, &sig, &databuf)); isc_buffer_usedregion(&databuf, &r); RETERR(dst_context_adddata(ctx, &r)); /* * If this is a response, digest the query. */ if (is_response(msg)) RETERR(dst_context_adddata(ctx, &msg->query)); /* * Digest the header. */ isc_buffer_init(&headerbuf, header, sizeof(header)); dns_message_renderheader(msg, &headerbuf); isc_buffer_usedregion(&headerbuf, &r); RETERR(dst_context_adddata(ctx, &r)); /* * Digest the remainder of the message. */ isc_buffer_usedregion(msg->buffer, &r); isc_region_consume(&r, DNS_MESSAGE_HEADERLEN); RETERR(dst_context_adddata(ctx, &r)); RETERR(dst_key_sigsize(key, &sigsize)); sig.siglen = sigsize; sig.signature = (unsigned char *) isc_mem_get(mctx, sig.siglen); if (sig.signature == NULL) { result = ISC_R_NOMEMORY; goto failure; } isc_buffer_init(&sigbuf, sig.signature, sig.siglen); RETERR(dst_context_sign(ctx, &sigbuf)); dst_context_destroy(&ctx); rdata = NULL; RETERR(dns_message_gettemprdata(msg, &rdata)); RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024)); RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any, dns_rdatatype_sig /* SIG(0) */, &sig, dynbuf)); isc_mem_put(mctx, sig.signature, sig.siglen); signeedsfree = ISC_FALSE; dns_message_takebuffer(msg, &dynbuf); datalist = NULL; RETERR(dns_message_gettemprdatalist(msg, &datalist)); datalist->rdclass = dns_rdataclass_any; datalist->type = dns_rdatatype_sig; /* SIG(0) */ datalist->covers = 0; datalist->ttl = 0; ISC_LIST_INIT(datalist->rdata); ISC_LIST_APPEND(datalist->rdata, rdata, link); dataset = NULL; RETERR(dns_message_gettemprdataset(msg, &dataset)); dns_rdataset_init(dataset); RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS); msg->sig0 = dataset; return (ISC_R_SUCCESS); failure: if (dynbuf != NULL) isc_buffer_free(&dynbuf); if (signeedsfree) isc_mem_put(mctx, sig.signature, sig.siglen); if (ctx != NULL) dst_context_destroy(&ctx); return (result); }