static inline isc_boolean_t checknames_minfo(ARGS_CHECKNAMES) { isc_region_t region; dns_name_t name; REQUIRE(rdata->type == 14); UNUSED(owner); dns_rdata_toregion(rdata, ®ion); dns_name_init(&name, NULL); dns_name_fromregion(&name, ®ion); if (!dns_name_ismailbox(&name)) { if (bad != NULL) dns_name_clone(&name, bad); return (ISC_FALSE); } isc_region_consume(®ion, name_length(&name)); dns_name_fromregion(&name, ®ion); if (!dns_name_ismailbox(&name)) { if (bad != NULL) dns_name_clone(&name, bad); return (ISC_FALSE); } return (ISC_TRUE); }
/* * Common routine to make query data */ static isc_result_t make_querymessage(dns_message_t *message, dns_name_t *qname0, dns_rdatatype_t rdtype) { dns_name_t *qname = NULL; dns_rdataset_t *qrdataset = NULL; isc_result_t result; message->opcode = dns_opcode_query; message->rdclass = dns_rdataclass_in; result = dns_message_gettempname(message, &qname); if (result != ISC_R_SUCCESS) goto cleanup; result = dns_message_gettemprdataset(message, &qrdataset); if (result != ISC_R_SUCCESS) goto cleanup; dns_name_init(qname, NULL); dns_name_clone(qname0, qname); dns_rdataset_init(qrdataset); dns_rdataset_makequestion(qrdataset, message->rdclass, rdtype); ISC_LIST_APPEND(qname->list, qrdataset, link); dns_message_addname(message, qname, DNS_SECTION_QUESTION); return (ISC_R_SUCCESS); cleanup: if (qname != NULL) dns_message_puttempname(message, &qname); if (qrdataset != NULL) dns_message_puttemprdataset(message, &qrdataset); return (result); }
static inline isc_boolean_t checknames_ptr(ARGS_CHECKNAMES) { isc_region_t region; dns_name_t name; REQUIRE(rdata->type == dns_rdatatype_ptr); if (rdata->rdclass != dns_rdataclass_in) return (ISC_TRUE); if (dns_name_isdnssd(owner)) return (ISC_TRUE); if (dns_name_issubdomain(owner, &in_addr_arpa) || dns_name_issubdomain(owner, &ip6_arpa) || dns_name_issubdomain(owner, &ip6_int)) { dns_rdata_toregion(rdata, ®ion); dns_name_init(&name, NULL); dns_name_fromregion(&name, ®ion); if (!dns_name_ishostname(&name, ISC_FALSE)) { if (bad != NULL) dns_name_clone(&name, bad); return (ISC_FALSE); } } return (ISC_TRUE); }
static isc_result_t sendquery(isc_task_t *task) { dns_request_t *request; dns_message_t *message; dns_name_t *qname; dns_rdataset_t *qrdataset; isc_result_t result; dns_fixedname_t queryname; isc_buffer_t buf; static char host[256]; int c; c = scanf("%255s", host); if (c == EOF) return ISC_R_NOMORE; onfly++; 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); message = NULL; result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &message); CHECK("dns_message_create", result); message->opcode = dns_opcode_query; message->flags |= DNS_MESSAGEFLAG_RD; message->rdclass = dns_rdataclass_in; message->id = (unsigned short)(random() & 0xFFFF); qname = NULL; result = dns_message_gettempname(message, &qname); CHECK("dns_message_gettempname", result); qrdataset = NULL; result = dns_message_gettemprdataset(message, &qrdataset); CHECK("dns_message_gettemprdataset", result); 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); request = NULL; result = dns_request_createvia(requestmgr, message, have_src ? &srcaddr : NULL, &dstaddr, DNS_REQUESTOPT_TCP|DNS_REQUESTOPT_SHARE, NULL, TIMEOUT, task, recvresponse, message, &request); CHECK("dns_request_create", result); return ISC_R_SUCCESS; }
isc_result_t isc__rdatalist_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, dns_rdataset_t *nsec, dns_rdataset_t *nsecsig) { dns_rdataclass_t rdclass = rdataset->rdclass; dns_rdataset_t *tnsec = NULL; dns_rdataset_t *tnsecsig = NULL; dns_name_t *noqname = rdataset->private6; REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0); (void)dns_name_dynamic(noqname); /* Sanity Check. */ for (rdataset = ISC_LIST_HEAD(noqname->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { if (rdataset->rdclass != rdclass) continue; if (rdataset->type == dns_rdatatype_nsec) tnsec = rdataset; if (rdataset->type == dns_rdatatype_rrsig && rdataset->covers == dns_rdatatype_nsec) tnsecsig = rdataset; } if (tnsec == NULL || tnsecsig == NULL) return (ISC_R_NOTFOUND); dns_name_clone(noqname, name); dns_rdataset_clone(tnsec, nsec); dns_rdataset_clone(tnsecsig, nsecsig); return (ISC_R_SUCCESS); }
static isc_result_t make_querymessage(dns_message_t *message, const char *namestr, dns_rdatatype_t rdtype) { dns_name_t *qname = NULL, *qname0; dns_rdataset_t *qrdataset = NULL; isc_result_t result; isc_buffer_t b; unsigned int namelen; REQUIRE(message != NULL); REQUIRE(namestr != NULL); /* Construct qname */ namelen = strlen(namestr); isc_buffer_constinit(&b, namestr, namelen); isc_buffer_add(&b, namelen); dns_fixedname_init(&fixedqname); qname0 = dns_fixedname_name(&fixedqname); result = dns_name_fromtext(qname0, &b, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) { fprintf(stderr, "failed to convert qname: %d\n", result); return (result); } /* Construct query message */ message->opcode = dns_opcode_query; message->rdclass = dns_rdataclass_in; result = dns_message_gettempname(message, &qname); if (result != ISC_R_SUCCESS) goto cleanup; result = dns_message_gettemprdataset(message, &qrdataset); if (result != ISC_R_SUCCESS) goto cleanup; dns_name_init(qname, NULL); dns_name_clone(qname0, qname); dns_rdataset_init(qrdataset); dns_rdataset_makequestion(qrdataset, message->rdclass, rdtype); ISC_LIST_APPEND(qname->list, qrdataset, link); dns_message_addname(message, qname, DNS_SECTION_QUESTION); return (ISC_R_SUCCESS); cleanup: if (qname != NULL) dns_message_puttempname(message, &qname); if (qrdataset != NULL) dns_message_puttemprdataset(message, &qrdataset); dns_message_destroy(&message); return (result); }
isc_result_t dns_difftuple_create(isc_mem_t *mctx, dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata, dns_difftuple_t **tp) { dns_difftuple_t *t; unsigned int size; unsigned char *datap; REQUIRE(tp != NULL && *tp == NULL); /* * Create a new tuple. The variable-size wire-format name data and * rdata immediately follow the dns_difftuple_t structure * in memory. */ size = sizeof(*t) + name->length + rdata->length; t = isc_mem_allocate(mctx, size); if (t == NULL) return (ISC_R_NOMEMORY); t->mctx = NULL; isc_mem_attach(mctx, &t->mctx); t->op = op; datap = (unsigned char *)(t + 1); memmove(datap, name->ndata, name->length); dns_name_init(&t->name, NULL); dns_name_clone(name, &t->name); t->name.ndata = datap; datap += name->length; t->ttl = ttl; memmove(datap, rdata->data, rdata->length); dns_rdata_init(&t->rdata); dns_rdata_clone(rdata, &t->rdata); t->rdata.data = datap; datap += rdata->length; ISC_LINK_INIT(&t->rdata, link); ISC_LINK_INIT(t, link); t->magic = DNS_DIFFTUPLE_MAGIC; INSIST(datap == (unsigned char *)t + size); *tp = t; return (ISC_R_SUCCESS); }
static inline isc_boolean_t checknames_ns(ARGS_CHECKNAMES) { isc_region_t region; dns_name_t name; REQUIRE(rdata->type == 2); UNUSED(owner); dns_rdata_toregion(rdata, ®ion); dns_name_init(&name, NULL); dns_name_fromregion(&name, ®ion); if (!dns_name_ishostname(&name, ISC_FALSE)) { if (bad != NULL) dns_name_clone(&name, bad); return (ISC_FALSE); } return (ISC_TRUE); }
isc_result_t isc__rdatalist_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, dns_rdataset_t *neg, dns_rdataset_t *negsig) { dns_rdataclass_t rdclass = rdataset->rdclass; dns_rdataset_t *tneg = NULL; dns_rdataset_t *tnegsig = NULL; dns_name_t *closest = rdataset->private7; REQUIRE((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0); (void)dns_name_dynamic(closest); /* Sanity Check. */ for (rdataset = ISC_LIST_HEAD(closest->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { if (rdataset->rdclass != rdclass) continue; if (rdataset->type == dns_rdatatype_nsec || rdataset->type == dns_rdatatype_nsec3) tneg = rdataset; } if (tneg == NULL) return (ISC_R_NOTFOUND); for (rdataset = ISC_LIST_HEAD(closest->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { if (rdataset->type == dns_rdatatype_rrsig && rdataset->covers == tneg->type) tnegsig = rdataset; } if (tnegsig == NULL) return (ISC_R_NOTFOUND); dns_name_clone(closest, name); dns_rdataset_clone(tneg, neg); dns_rdataset_clone(tnegsig, negsig); return (ISC_R_SUCCESS); }
isc_result_t ATTR_NONNULLS dns_ns_buildrdata(dns_name_t *origin, dns_name_t *ns_name, dns_rdataclass_t rdclass, unsigned char *buffer, dns_rdata_t *rdata) { dns_rdata_ns_t ns; isc_buffer_t rdatabuf; REQUIRE(origin != NULL); REQUIRE(ns_name != NULL); memset(buffer, 0, DNS_SOA_BUFFERSIZE); isc_buffer_init(&rdatabuf, buffer, DNS_SOA_BUFFERSIZE); ns.common.rdtype = dns_rdatatype_ns; ns.common.rdclass = rdclass; ns.mctx = NULL; dns_name_init(&ns.name, NULL); dns_name_clone(ns_name, &ns.name); return (dns_rdata_fromstruct(rdata, rdclass, dns_rdatatype_ns, &ns, &rdatabuf)); }
static isc_result_t add_ns(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name, const dns_name_t *nsname) { dns_dbnode_t *node = NULL; dns_rdata_ns_t ns; dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdatalist_t rdatalist; dns_rdataset_t rdataset; isc_result_t result; isc_buffer_t b; unsigned char buf[DNS_NAME_MAXWIRE]; isc_buffer_init(&b, buf, sizeof(buf)); dns_rdataset_init(&rdataset); dns_rdatalist_init(&rdatalist); ns.common.rdtype = dns_rdatatype_ns; ns.common.rdclass = dns_db_class(db); ns.mctx = NULL; dns_name_init(&ns.name, NULL); dns_name_clone(nsname, &ns.name); CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns, &ns, &b)); rdatalist.type = rdata.type; rdatalist.covers = 0; rdatalist.rdclass = rdata.rdclass; rdatalist.ttl = 86400; ISC_LIST_APPEND(rdatalist.rdata, &rdata, link); CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset)); CHECK(dns_db_findnode(db, name, ISC_TRUE, &node)); CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL)); cleanup: if (node != NULL) dns_db_detachnode(db, &node); return (result); }
/*% * Configure static-stub zone. */ static isc_result_t configure_staticstub(const cfg_obj_t *zconfig, dns_zone_t *zone, const char *zname, const char *dbtype) { int i = 0; const cfg_obj_t *obj; isc_mem_t *mctx = dns_zone_getmctx(zone); dns_db_t *db = NULL; dns_dbversion_t *dbversion = NULL; dns_dbnode_t *apexnode = NULL; dns_name_t apexname; isc_result_t result; dns_rdataset_t rdataset; dns_rdatalist_t rdatalist_ns, rdatalist_a, rdatalist_aaaa; dns_rdatalist_t* rdatalists[] = { &rdatalist_ns, &rdatalist_a, &rdatalist_aaaa, NULL }; dns_rdata_t *rdata; isc_region_t region; /* Create the DB beforehand */ RETERR(dns_db_create(mctx, dbtype, dns_zone_getorigin(zone), dns_dbtype_stub, dns_zone_getclass(zone), 0, NULL, &db)); dns_zone_setdb(zone, db); dns_rdatalist_init(&rdatalist_ns); rdatalist_ns.rdclass = dns_zone_getclass(zone); rdatalist_ns.type = dns_rdatatype_ns; rdatalist_ns.ttl = STATICSTUB_SERVER_TTL; dns_rdatalist_init(&rdatalist_a); rdatalist_a.rdclass = dns_zone_getclass(zone); rdatalist_a.type = dns_rdatatype_a; rdatalist_a.ttl = STATICSTUB_SERVER_TTL; dns_rdatalist_init(&rdatalist_aaaa); rdatalist_aaaa.rdclass = dns_zone_getclass(zone); rdatalist_aaaa.type = dns_rdatatype_aaaa; rdatalist_aaaa.ttl = STATICSTUB_SERVER_TTL; /* Prepare zone RRs from the configuration */ obj = NULL; result = cfg_map_get(zconfig, "server-addresses", &obj); if (result == ISC_R_SUCCESS) { INSIST(obj != NULL); result = configure_staticstub_serveraddrs(obj, zone, &rdatalist_ns, &rdatalist_a, &rdatalist_aaaa); if (result != ISC_R_SUCCESS) goto cleanup; } obj = NULL; result = cfg_map_get(zconfig, "server-names", &obj); if (result == ISC_R_SUCCESS) { INSIST(obj != NULL); result = configure_staticstub_servernames(obj, zone, &rdatalist_ns, zname); if (result != ISC_R_SUCCESS) goto cleanup; } /* * Sanity check: there should be at least one NS RR at the zone apex * to trigger delegation. */ if (ISC_LIST_EMPTY(rdatalist_ns.rdata)) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR, "No NS record is configured for a " "static-stub zone '%s'", zname); result = ISC_R_FAILURE; goto cleanup; } /* * Now add NS and glue A/AAAA RRsets to the zone DB. * First open a new version for the add operation and get a pointer * to the apex node (all RRs are of the apex name). */ result = dns_db_newversion(db, &dbversion); if (result != ISC_R_SUCCESS) goto cleanup; dns_name_init(&apexname, NULL); dns_name_clone(dns_zone_getorigin(zone), &apexname); result = dns_db_findnode(db, &apexname, ISC_FALSE, &apexnode); if (result != ISC_R_SUCCESS) goto cleanup; /* Add NS RRset */ dns_rdataset_init(&rdataset); RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_ns, &rdataset) == ISC_R_SUCCESS); result = dns_db_addrdataset(db, apexnode, dbversion, 0, &rdataset, 0, NULL); dns_rdataset_disassociate(&rdataset); if (result != ISC_R_SUCCESS) goto cleanup; /* Add glue A RRset, if any */ if (!ISC_LIST_EMPTY(rdatalist_a.rdata)) { RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_a, &rdataset) == ISC_R_SUCCESS); result = dns_db_addrdataset(db, apexnode, dbversion, 0, &rdataset, 0, NULL); dns_rdataset_disassociate(&rdataset); if (result != ISC_R_SUCCESS) goto cleanup; } /* Add glue AAAA RRset, if any */ if (!ISC_LIST_EMPTY(rdatalist_aaaa.rdata)) { RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_aaaa, &rdataset) == ISC_R_SUCCESS); result = dns_db_addrdataset(db, apexnode, dbversion, 0, &rdataset, 0, NULL); dns_rdataset_disassociate(&rdataset); if (result != ISC_R_SUCCESS) goto cleanup; } result = ISC_R_SUCCESS; cleanup: if (apexnode != NULL) dns_db_detachnode(db, &apexnode); if (dbversion != NULL) dns_db_closeversion(db, &dbversion, ISC_TRUE); if (db != NULL) dns_db_detach(&db); for (i = 0; rdatalists[i] != NULL; i++) { while ((rdata = ISC_LIST_HEAD(rdatalists[i]->rdata)) != NULL) { ISC_LIST_UNLINK(rdatalists[i]->rdata, rdata, link); dns_rdata_toregion(rdata, ®ion); isc_mem_put(mctx, rdata, sizeof(*rdata) + region.length); } } return (result); }
isc_result_t dns_name_towire(dns_name_t *name, dns_compress_t *cctx, isc_buffer_t *target) { unsigned int methods; isc_uint16_t offset; dns_name_t gp; /* Global compression prefix */ isc_boolean_t gf; /* Global compression target found */ isc_uint16_t go; /* Global compression offset */ dns_offsets_t clo; dns_name_t clname; /* * Convert 'name' into wire format, compressing it as specified by the * compression context 'cctx', and storing the result in 'target'. */ REQUIRE(VALID_NAME(name)); REQUIRE(cctx != NULL); REQUIRE(ISC_BUFFER_VALID(target)); /* * If 'name' doesn't have an offsets table, make a clone which * has one. */ if (name->offsets == NULL) { DNS_NAME_INIT(&clname, clo); dns_name_clone(name, &clname); name = &clname; } DNS_NAME_INIT(&gp, NULL); offset = target->used; /*XXX*/ methods = dns_compress_getmethods(cctx); if ((methods & DNS_COMPRESS_GLOBAL14) != 0) gf = dns_compress_findglobal(cctx, name, &gp, &go); else gf = ISC_FALSE; /* * If the offset is too high for 14 bit global compression, we're * out of luck. */ if (gf && go >= 0x4000) gf = ISC_FALSE; /* * Will the compression pointer reduce the message size? */ if (gf && (gp.length + 2) >= name->length) gf = ISC_FALSE; if (gf) { if (target->length - target->used < gp.length) return (ISC_R_NOSPACE); (void)memcpy((unsigned char *)target->base + target->used, gp.ndata, (size_t)gp.length); isc_buffer_add(target, gp.length); go |= 0xc000; if (target->length - target->used < 2) return (ISC_R_NOSPACE); isc_buffer_putuint16(target, go); if (gp.length != 0) dns_compress_add(cctx, name, &gp, offset); } else { if (target->length - target->used < name->length) return (ISC_R_NOSPACE); (void)memcpy((unsigned char *)target->base + target->used, name->ndata, (size_t)name->length); isc_buffer_add(target, name->length); dns_compress_add(cctx, name, name, offset); } return (ISC_R_SUCCESS); }
isc_result_t dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx, dns_tsig_keyring_t *ring) { isc_result_t result = ISC_R_SUCCESS; dns_rdata_tkey_t tkeyin, tkeyout; isc_boolean_t freetkeyin = ISC_FALSE; dns_name_t *qname, *name, *keyname, *signer, tsigner; dns_fixedname_t fkeyname; dns_rdataset_t *tkeyset; dns_rdata_t rdata; dns_namelist_t namelist; char tkeyoutdata[512]; isc_buffer_t tkeyoutbuf; REQUIRE(msg != NULL); REQUIRE(tctx != NULL); REQUIRE(ring != NULL); ISC_LIST_INIT(namelist); /* * Interpret the question section. */ result = dns_message_firstname(msg, DNS_SECTION_QUESTION); if (result != ISC_R_SUCCESS) return (DNS_R_FORMERR); qname = NULL; dns_message_currentname(msg, DNS_SECTION_QUESTION, &qname); /* * Look for a TKEY record that matches the question. */ tkeyset = NULL; name = NULL; result = dns_message_findname(msg, DNS_SECTION_ADDITIONAL, qname, dns_rdatatype_tkey, 0, &name, &tkeyset); if (result != ISC_R_SUCCESS) { /* * Try the answer section, since that's where Win2000 * puts it. */ name = NULL; if (dns_message_findname(msg, DNS_SECTION_ANSWER, qname, dns_rdatatype_tkey, 0, &name, &tkeyset) != ISC_R_SUCCESS) { result = DNS_R_FORMERR; tkey_log("dns_tkey_processquery: couldn't find a TKEY " "matching the question"); goto failure; } } result = dns_rdataset_first(tkeyset); if (result != ISC_R_SUCCESS) { result = DNS_R_FORMERR; goto failure; } dns_rdata_init(&rdata); dns_rdataset_current(tkeyset, &rdata); RETERR(dns_rdata_tostruct(&rdata, &tkeyin, NULL)); freetkeyin = ISC_TRUE; if (tkeyin.error != dns_rcode_noerror) { result = DNS_R_FORMERR; goto failure; } /* * Before we go any farther, verify that the message was signed. * GSSAPI TKEY doesn't require a signature, the rest do. */ dns_name_init(&tsigner, NULL); result = dns_message_signer(msg, &tsigner); if (result != ISC_R_SUCCESS) { if (tkeyin.mode == DNS_TKEYMODE_GSSAPI && result == ISC_R_NOTFOUND) signer = NULL; else { tkey_log("dns_tkey_processquery: query was not " "properly signed - rejecting"); result = DNS_R_FORMERR; goto failure; } } else signer = &tsigner; tkeyout.common.rdclass = tkeyin.common.rdclass; tkeyout.common.rdtype = tkeyin.common.rdtype; ISC_LINK_INIT(&tkeyout.common, link); tkeyout.mctx = msg->mctx; dns_name_init(&tkeyout.algorithm, NULL); dns_name_clone(&tkeyin.algorithm, &tkeyout.algorithm); tkeyout.inception = tkeyout.expire = 0; tkeyout.mode = tkeyin.mode; tkeyout.error = 0; tkeyout.keylen = tkeyout.otherlen = 0; tkeyout.key = tkeyout.other = NULL; /* * A delete operation must have a fully specified key name. If this * is not a delete, we do the following: * if (qname != ".") * keyname = qname + defaultdomain * else * keyname = <random hex> + defaultdomain */ if (tkeyin.mode != DNS_TKEYMODE_DELETE) { dns_tsigkey_t *tsigkey = NULL; if (tctx->domain == NULL && tkeyin.mode != DNS_TKEYMODE_GSSAPI) { tkey_log("dns_tkey_processquery: tkey-domain not set"); result = DNS_R_REFUSED; goto failure; } dns_fixedname_init(&fkeyname); keyname = dns_fixedname_name(&fkeyname); if (!dns_name_equal(qname, dns_rootname)) { unsigned int n = dns_name_countlabels(qname); RUNTIME_CHECK(dns_name_copy(qname, keyname, NULL) == ISC_R_SUCCESS); dns_name_getlabelsequence(keyname, 0, n - 1, keyname); } else { static char hexdigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; unsigned char randomdata[16]; char randomtext[32]; isc_buffer_t b; unsigned int i, j; result = isc_entropy_getdata(tctx->ectx, randomdata, sizeof(randomdata), NULL, 0); if (result != ISC_R_SUCCESS) goto failure; for (i = 0, j = 0; i < sizeof(randomdata); i++) { unsigned char val = randomdata[i]; randomtext[j++] = hexdigits[val >> 4]; randomtext[j++] = hexdigits[val & 0xF]; } isc_buffer_init(&b, randomtext, sizeof(randomtext)); isc_buffer_add(&b, sizeof(randomtext)); result = dns_name_fromtext(keyname, &b, NULL, 0, NULL); if (result != ISC_R_SUCCESS) goto failure; } if (tkeyin.mode == DNS_TKEYMODE_GSSAPI) { /* Yup. This is a hack */ result = dns_name_concatenate(keyname, dns_rootname, keyname, NULL); if (result != ISC_R_SUCCESS) goto failure; } else { result = dns_name_concatenate(keyname, tctx->domain, keyname, NULL); if (result != ISC_R_SUCCESS) goto failure; } result = dns_tsigkey_find(&tsigkey, keyname, NULL, ring); if (result == ISC_R_SUCCESS) { tkeyout.error = dns_tsigerror_badname; dns_tsigkey_detach(&tsigkey); goto failure_with_tkey; } else if (result != ISC_R_NOTFOUND) goto failure; } else
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); }
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); }
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); }
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); }
static void resigned(isc_assertioncallback_t callback) { isc_result_t result; dns_rdataset_t rdataset, added; dns_dbnode_t *node = NULL; dns_rdatalist_t rdatalist; dns_rdata_rrsig_t rrsig; dns_rdata_t rdata = DNS_RDATA_INIT; isc_buffer_t b; unsigned char buf[1024]; result = dns_test_begin(NULL, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); setup_db(); /* * Create a dummy RRSIG record and set a resigning time. */ dns_rdataset_init(&added); dns_rdataset_init(&rdataset); dns_rdatalist_init(&rdatalist); isc_buffer_init(&b, buf, sizeof(buf)); DNS_RDATACOMMON_INIT(&rrsig, dns_rdatatype_rrsig, dns_rdataclass_in); rrsig.covered = dns_rdatatype_a; rrsig.algorithm = 100; rrsig.labels = 0; rrsig.originalttl = 0; rrsig.timeexpire = 3600; rrsig.timesigned = 0; rrsig.keyid = 0; dns_name_init(&rrsig.signer, NULL); dns_name_clone(dns_rootname, &rrsig.signer); rrsig.siglen = 0; rrsig.signature = NULL; result = dns_rdata_fromstruct(&rdata, dns_rdataclass_in, dns_rdatatype_rrsig, &rrsig, &b); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); rdatalist.rdclass = dns_rdataclass_in; rdatalist.type = dns_rdatatype_rrsig; ISC_LIST_APPEND(rdatalist.rdata, &rdata, link); result = dns_rdatalist_tordataset(&rdatalist, &rdataset); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); rdataset.attributes |= DNS_RDATASETATTR_RESIGN; rdataset.resign = 7200; result = dns_db_findnode(db1, dns_rootname, ISC_FALSE, &node); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); result = dns_db_addrdataset(db1, node, v1, 0, &rdataset, 0, &added); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); dns_db_detachnode(db1, &node); ATF_REQUIRE_EQ(node, NULL); isc_assertion_setcallback(callback); dns_db_resigned(db1, &added, VERSION(callback)); if (callback != NULL) atf_tc_fail("dns_db_resigned did not assert"); dns_rdataset_disassociate(&added); close_db(); dns_test_end(); }
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_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); }
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); }