static isc_stdtime_t setresign(dns_rdataset_t *modified) { dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdata_rrsig_t sig; isc_stdtime_t when; isc_result_t result; result = dns_rdataset_first(modified); INSIST(result == ISC_R_SUCCESS); dns_rdataset_current(modified, &rdata); (void)dns_rdata_tostruct(&rdata, &sig, NULL); if ((rdata.flags & DNS_RDATA_OFFLINE) != 0) when = 0; else when = sig.timeexpire; dns_rdata_reset(&rdata); result = dns_rdataset_next(modified); while (result == ISC_R_SUCCESS) { dns_rdataset_current(modified, &rdata); (void)dns_rdata_tostruct(&rdata, &sig, NULL); if ((rdata.flags & DNS_RDATA_OFFLINE) != 0) { goto next_rr; } if (when == 0 || sig.timeexpire < when) when = sig.timeexpire; next_rr: dns_rdata_reset(&rdata); result = dns_rdataset_next(modified); } INSIST(result == ISC_R_NOMORE); return (when); }
isc_boolean_t dns_nsec_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type) { dns_rdata_nsec_t nsecstruct; isc_result_t result; isc_boolean_t present; unsigned int i, len, window; REQUIRE(nsec != NULL); REQUIRE(nsec->type == dns_rdatatype_nsec); /* This should never fail */ result = dns_rdata_tostruct(nsec, &nsecstruct, NULL); INSIST(result == ISC_R_SUCCESS); present = ISC_FALSE; for (i = 0; i < nsecstruct.len; i += len) { INSIST(i + 2 <= nsecstruct.len); window = nsecstruct.typebits[i]; len = nsecstruct.typebits[i + 1]; INSIST(len > 0 && len <= 32); i += 2; INSIST(i + len <= nsecstruct.len); if (window * 256 > type) break; if ((window + 1) * 256 <= type) continue; if (type < (window * 256) + len * 8) present = ISC_TF(bit_isset(&nsecstruct.typebits[i], type % 256)); break; } dns_rdata_freestruct(&nsec); return (present); }
isc_result_t dns_nsec_nseconly(dns_db_t *db, dns_dbversion_t *version, isc_boolean_t *answer) { dns_dbnode_t *node = NULL; dns_rdataset_t rdataset; dns_rdata_dnskey_t dnskey; isc_result_t result; REQUIRE(answer != NULL); dns_rdataset_init(&rdataset); result = dns_db_getoriginnode(db, &node); if (result != ISC_R_SUCCESS) return (result); result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey, 0, 0, &rdataset, NULL); dns_db_detachnode(db, &node); if (result == ISC_R_NOTFOUND) { *answer = ISC_FALSE; return (ISC_R_SUCCESS); } if (result != ISC_R_SUCCESS) return (result); for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(&rdataset)) { dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_current(&rdataset, &rdata); result = dns_rdata_tostruct(&rdata, &dnskey, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); if (dnskey.algorithm == DST_ALG_RSAMD5 || dnskey.algorithm == DST_ALG_RSASHA1 || dnskey.algorithm == DST_ALG_DSA || dnskey.algorithm == DST_ALG_ECC) break; } dns_rdataset_disassociate(&rdataset); if (result == ISC_R_SUCCESS) *answer = ISC_TRUE; if (result == ISC_R_NOMORE) { *answer = ISC_FALSE; result = ISC_R_SUCCESS; } return (result); }
static void printsoa(dns_rdata_t *rdata) { dns_rdata_soa_t soa; isc_result_t result; char namebuf[DNS_NAME_FORMATSIZE]; result = dns_rdata_tostruct(rdata, &soa, NULL); check_result(result, "dns_rdata_tostruct"); dns_name_format(&soa.origin, namebuf, sizeof(namebuf)); printf("\torigin = %s\n", namebuf); dns_name_format(&soa.contact, namebuf, sizeof(namebuf)); printf("\tmail addr = %s\n", namebuf); printf("\tserial = %u\n", soa.serial); printf("\trefresh = %u\n", soa.refresh); printf("\tretry = %u\n", soa.retry); printf("\texpire = %u\n", soa.expire); printf("\tminimum = %u\n", soa.minimum); dns_rdata_freestruct(&soa); }
isc_boolean_t dns_zonekey_iszonekey(dns_rdata_t *keyrdata) { isc_result_t result; dns_rdata_dnskey_t key; isc_boolean_t iszonekey = ISC_TRUE; REQUIRE(keyrdata != NULL); result = dns_rdata_tostruct(keyrdata, &key, NULL); if (result != ISC_R_SUCCESS) return (ISC_FALSE); if ((key.flags & DNS_KEYTYPE_NOAUTH) != 0) iszonekey = ISC_FALSE; if ((key.flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE) iszonekey = ISC_FALSE; if (key.protocol != DNS_KEYPROTO_DNSSEC && key.protocol != DNS_KEYPROTO_ANY) iszonekey = ISC_FALSE; return (iszonekey); }
static isc_result_t add_mac(dst_context_t *tsigctx, isc_buffer_t *buf) { dns_rdata_any_tsig_t tsig; dns_rdata_t rdata = DNS_RDATA_INIT; isc_buffer_t databuf; isc_region_t r; isc_result_t result; unsigned char tsigbuf[1024]; isc_buffer_usedregion(buf, &r); dns_rdata_fromregion(&rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r); isc_buffer_init(&databuf, tsigbuf, sizeof(tsigbuf)); CHECK(dns_rdata_tostruct(&rdata, &tsig, NULL)); isc_buffer_putuint16(&databuf, tsig.siglen); isc_buffer_putmem(&databuf, tsig.signature, tsig.siglen); isc_buffer_usedregion(&databuf, &r); result = dst_context_adddata(tsigctx, &r); dns_rdata_freestruct(&tsig); cleanup: return (result); }
static isc_result_t in_rootns(dns_rdataset_t *rootns, dns_name_t *name) { isc_result_t result; dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdata_ns_t ns; if (!dns_rdataset_isassociated(rootns)) return (ISC_R_NOTFOUND); result = dns_rdataset_first(rootns); while (result == ISC_R_SUCCESS) { dns_rdataset_current(rootns, &rdata); result = dns_rdata_tostruct(&rdata, &ns, NULL); if (result != ISC_R_SUCCESS) return (result); if (dns_name_compare(name, &ns.name) == 0) return (ISC_R_SUCCESS); result = dns_rdataset_next(rootns); } if (result == ISC_R_NOMORE) result = ISC_R_NOTFOUND; return (result); }
static void chase_cnamechain(dns_message_t *msg, dns_name_t *qname) { isc_result_t result; dns_rdataset_t *rdataset; dns_rdata_cname_t cname; dns_rdata_t rdata = DNS_RDATA_INIT; unsigned int i = msg->counts[DNS_SECTION_ANSWER]; while (i-- > 0) { rdataset = NULL; result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname, dns_rdatatype_cname, 0, NULL, &rdataset); if (result != ISC_R_SUCCESS) return; result = dns_rdataset_first(rdataset); check_result(result, "dns_rdataset_first"); dns_rdata_reset(&rdata); dns_rdataset_current(rdataset, &rdata); result = dns_rdata_tostruct(&rdata, &cname, NULL); check_result(result, "dns_rdata_tostruct"); dns_name_copy(&cname.cname, qname, NULL); dns_rdata_freestruct(&cname); } }
void dns_root_checkhints(dns_view_t *view, dns_db_t *hints, dns_db_t *db) { isc_result_t result; dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdata_ns_t ns; dns_rdataset_t hintns, rootns; const char *viewname = "", *sep = ""; isc_stdtime_t now; dns_name_t *name; dns_fixedname_t fixed; REQUIRE(hints != NULL); REQUIRE(db != NULL); REQUIRE(view != NULL); isc_stdtime_get(&now); if (strcmp(view->name, "_bind") != 0 && strcmp(view->name, "_default") != 0) { viewname = view->name; sep = ": view "; } dns_rdataset_init(&hintns); dns_rdataset_init(&rootns); dns_fixedname_init(&fixed); name = dns_fixedname_name(&fixed); result = dns_db_find(hints, dns_rootname, NULL, dns_rdatatype_ns, 0, now, NULL, name, &hintns, NULL); if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_HINTS, ISC_LOG_WARNING, "checkhints%s%s: unable to get root NS rrset " "from hints: %s", sep, viewname, dns_result_totext(result)); goto cleanup; } result = dns_db_find(db, dns_rootname, NULL, dns_rdatatype_ns, 0, now, NULL, name, &rootns, NULL); if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_HINTS, ISC_LOG_WARNING, "checkhints%s%s: unable to get root NS rrset " "from cache: %s", sep, viewname, dns_result_totext(result)); goto cleanup; } /* * Look for missing root NS names. */ result = dns_rdataset_first(&rootns); while (result == ISC_R_SUCCESS) { dns_rdataset_current(&rootns, &rdata); result = dns_rdata_tostruct(&rdata, &ns, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); result = in_rootns(&hintns, &ns.name); if (result != ISC_R_SUCCESS) { char namebuf[DNS_NAME_FORMATSIZE]; /* missing from hints */ dns_name_format(&ns.name, namebuf, sizeof(namebuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_HINTS, ISC_LOG_WARNING, "checkhints%s%s: unable to find root " "NS '%s' in hints", sep, viewname, namebuf); } else check_address_records(view, hints, db, &ns.name, now); dns_rdata_reset(&rdata); result = dns_rdataset_next(&rootns); } if (result != ISC_R_NOMORE) { goto cleanup; } /* * Look for extra root NS names. */ result = dns_rdataset_first(&hintns); while (result == ISC_R_SUCCESS) { dns_rdataset_current(&hintns, &rdata); result = dns_rdata_tostruct(&rdata, &ns, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); result = in_rootns(&rootns, &ns.name); if (result != ISC_R_SUCCESS) { char namebuf[DNS_NAME_FORMATSIZE]; /* extra entry in hints */ dns_name_format(&ns.name, namebuf, sizeof(namebuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_HINTS, ISC_LOG_WARNING, "checkhints%s%s: extra NS '%s' in hints", sep, viewname, namebuf); } dns_rdata_reset(&rdata); result = dns_rdataset_next(&hintns); } if (result != ISC_R_NOMORE) { goto cleanup; } cleanup: if (dns_rdataset_isassociated(&rootns)) dns_rdataset_disassociate(&rootns); if (dns_rdataset_isassociated(&hintns)) dns_rdataset_disassociate(&hintns); }
static void viastruct(dns_rdata_t *rdata, isc_mem_t *mctx, dns_rdata_t *rdata2, isc_buffer_t *b) { isc_result_t result; void *sp = NULL; isc_boolean_t need_free = ISC_FALSE; dns_rdatatype_t rdt; dns_rdataclass_t rdc; UNUSED(rdata2); /* XXXMPA remove when fromstruct is ready. */ UNUSED(b); switch (rdata->type) { case dns_rdatatype_a6: { static dns_rdata_in_a6_t in_a6; result = dns_rdata_tostruct(rdata, sp = &in_a6, NULL); break; } case dns_rdatatype_a: { switch (rdata->rdclass) { case dns_rdataclass_hs: { static dns_rdata_hs_a_t hs_a; result = dns_rdata_tostruct(rdata, sp = &hs_a, NULL); break; } case dns_rdataclass_in: { static dns_rdata_in_a_t in_a; result = dns_rdata_tostruct(rdata, sp = &in_a, NULL); break; } default: result = ISC_R_NOTIMPLEMENTED; break; } break; } case dns_rdatatype_aaaa: { static dns_rdata_in_aaaa_t in_aaaa; result = dns_rdata_tostruct(rdata, sp = &in_aaaa, NULL); break; } case dns_rdatatype_afsdb: { static dns_rdata_afsdb_t afsdb; result = dns_rdata_tostruct(rdata, sp = &afsdb, NULL); break; } case dns_rdatatype_any: { result = ISC_R_NOTIMPLEMENTED; break; } case dns_rdatatype_apl: { switch (rdata->rdclass) { case dns_rdataclass_in: { static dns_rdata_in_apl_t in_apl; result = dns_rdata_tostruct(rdata, sp = &in_apl, NULL); break; } default: result = ISC_R_NOTIMPLEMENTED; break; } break; } case dns_rdatatype_cert: { static dns_rdata_cert_t cert; result = dns_rdata_tostruct(rdata, sp = &cert, NULL); break; } case dns_rdatatype_cname: { static dns_rdata_cname_t cname; result = dns_rdata_tostruct(rdata, sp = &cname, NULL); break; } case dns_rdatatype_dname: { static dns_rdata_dname_t dname; result = dns_rdata_tostruct(rdata, sp = &dname, NULL); break; } case dns_rdatatype_gpos: { static dns_rdata_gpos_t gpos; result = dns_rdata_tostruct(rdata, sp = &gpos, NULL); break; } case dns_rdatatype_hinfo: { static dns_rdata_hinfo_t hinfo; result = dns_rdata_tostruct(rdata, sp = &hinfo, NULL); break; } case dns_rdatatype_isdn: { static dns_rdata_isdn_t isdn; result = dns_rdata_tostruct(rdata, sp = &isdn, NULL); break; } case dns_rdatatype_key: { static dns_rdata_key_t key; result = dns_rdata_tostruct(rdata, sp = &key, NULL); break; } case dns_rdatatype_kx: { static dns_rdata_in_kx_t in_kx; result = dns_rdata_tostruct(rdata, sp = &in_kx, NULL); break; } case dns_rdatatype_loc: { static dns_rdata_loc_t loc; result = dns_rdata_tostruct(rdata, sp = &loc, NULL); break; } case dns_rdatatype_mb: { static dns_rdata_mb_t mb; result = dns_rdata_tostruct(rdata, sp = &mb, NULL); break; } case dns_rdatatype_md: { static dns_rdata_md_t md; result = dns_rdata_tostruct(rdata, sp = &md, NULL); break; } case dns_rdatatype_mf: { static dns_rdata_mf_t mf; result = dns_rdata_tostruct(rdata, sp = &mf, NULL); break; } case dns_rdatatype_mg: { static dns_rdata_mg_t mg; result = dns_rdata_tostruct(rdata, sp = &mg, NULL); break; } case dns_rdatatype_minfo: { static dns_rdata_minfo_t minfo; result = dns_rdata_tostruct(rdata, sp = &minfo, NULL); break; } case dns_rdatatype_mr: { static dns_rdata_mr_t mr; result = dns_rdata_tostruct(rdata, sp = &mr, NULL); break; } case dns_rdatatype_mx: { static dns_rdata_mx_t mx; result = dns_rdata_tostruct(rdata, sp = &mx, NULL); break; } case dns_rdatatype_naptr: { static dns_rdata_naptr_t naptr; result = dns_rdata_tostruct(rdata, sp = &naptr, NULL); break; } case dns_rdatatype_ns: { static dns_rdata_ns_t ns; result = dns_rdata_tostruct(rdata, sp = &ns, NULL); break; } case dns_rdatatype_nsap: { static dns_rdata_in_nsap_t in_nsap; result = dns_rdata_tostruct(rdata, sp = &in_nsap, NULL); break; } case dns_rdatatype_nsap_ptr: { static dns_rdata_in_nsap_ptr_t in_nsap_ptr; result = dns_rdata_tostruct(rdata, sp = &in_nsap_ptr, NULL); break; } case dns_rdatatype_null: { static dns_rdata_null_t null; result = dns_rdata_tostruct(rdata, sp = &null, NULL); break; } case dns_rdatatype_nxt: { static dns_rdata_nxt_t nxt; result = dns_rdata_tostruct(rdata, sp = &nxt, NULL); break; } case dns_rdatatype_opt: { static dns_rdata_opt_t opt; result = dns_rdata_tostruct(rdata, sp = &opt, NULL); break; } case dns_rdatatype_ptr: { static dns_rdata_ptr_t ptr; result = dns_rdata_tostruct(rdata, sp = &ptr, NULL); break; } case dns_rdatatype_px: { static dns_rdata_in_px_t in_px; result = dns_rdata_tostruct(rdata, sp = &in_px, NULL); break; } case dns_rdatatype_rp: { static dns_rdata_rp_t rp; result = dns_rdata_tostruct(rdata, sp = &rp, NULL); break; } case dns_rdatatype_rt: { static dns_rdata_rt_t rt; result = dns_rdata_tostruct(rdata, sp = &rt, NULL); break; } case dns_rdatatype_sig: { static dns_rdata_sig_t sig; result = dns_rdata_tostruct(rdata, sp = &sig, NULL); break; } case dns_rdatatype_soa: { static dns_rdata_soa_t soa; result = dns_rdata_tostruct(rdata, sp = &soa, NULL); break; } case dns_rdatatype_srv: { static dns_rdata_in_srv_t in_srv; result = dns_rdata_tostruct(rdata, sp = &in_srv, NULL); break; } case dns_rdatatype_tkey: { static dns_rdata_tkey_t tkey; result = dns_rdata_tostruct(rdata, sp = &tkey, NULL); break; } case dns_rdatatype_tsig: { static dns_rdata_any_tsig_t tsig; result = dns_rdata_tostruct(rdata, sp = &tsig, NULL); break; } case dns_rdatatype_txt: { static dns_rdata_txt_t txt; result = dns_rdata_tostruct(rdata, sp = &txt, NULL); break; } case dns_rdatatype_spf: { static dns_rdata_spf_t spf; result = dns_rdata_tostruct(rdata, sp = &spf, NULL); break; } case dns_rdatatype_unspec: { static dns_rdata_unspec_t unspec; result = dns_rdata_tostruct(rdata, sp = &unspec, NULL); break; } case dns_rdatatype_uri: { static dns_rdata_uri_t uri; result = dns_rdata_tostruct(rdata, sp = &uri, NULL); break; } case dns_rdatatype_wks: { static dns_rdata_in_wks_t in_wks; result = dns_rdata_tostruct(rdata, sp = &in_wks, NULL); break; } case dns_rdatatype_x25: { static dns_rdata_x25_t x25; result = dns_rdata_tostruct(rdata, sp = &x25, NULL); break; } case dns_rdatatype_nsec: { static dns_rdata_nsec_t nsec; result = dns_rdata_tostruct(rdata, sp = &nsec, NULL); break; } case dns_rdatatype_rrsig: { static dns_rdata_rrsig_t rrsig; result = dns_rdata_tostruct(rdata, sp = &rrsig, NULL); break; } case dns_rdatatype_dnskey: { static dns_rdata_dnskey_t dnskey; result = dns_rdata_tostruct(rdata, sp = &dnskey, NULL); break; } default: result = ISC_R_NOTIMPLEMENTED; break; } if (result != ISC_R_SUCCESS) fprintf(stdout, "viastruct: tostruct %d %d return %s\n", rdata->type, rdata->rdclass, dns_result_totext(result)); else dns_rdata_freestruct(sp); switch (rdata->type) { case dns_rdatatype_a6: { static dns_rdata_in_a6_t in_a6; result = dns_rdata_tostruct(rdata, sp = &in_a6, mctx); break; } case dns_rdatatype_a: { switch (rdata->rdclass) { case dns_rdataclass_hs: { static dns_rdata_hs_a_t hs_a; result = dns_rdata_tostruct(rdata, sp = &hs_a, mctx); break; } case dns_rdataclass_in: { static dns_rdata_in_a_t in_a; result = dns_rdata_tostruct(rdata, sp = &in_a, mctx); break; } default: result = ISC_R_NOTIMPLEMENTED; break; } break; } case dns_rdatatype_aaaa: { static dns_rdata_in_aaaa_t in_aaaa; result = dns_rdata_tostruct(rdata, sp = &in_aaaa, mctx); break; } case dns_rdatatype_afsdb: { static dns_rdata_afsdb_t afsdb; result = dns_rdata_tostruct(rdata, sp = &afsdb, mctx); break; } case dns_rdatatype_any: { result = ISC_R_NOTIMPLEMENTED; break; } case dns_rdatatype_apl: { switch (rdata->rdclass) { case dns_rdataclass_in: { static dns_rdata_in_apl_t in_apl; result = dns_rdata_tostruct(rdata, sp = &in_apl, mctx); break; } default: result = ISC_R_NOTIMPLEMENTED; break; } break; } case dns_rdatatype_cert: { static dns_rdata_cert_t cert; result = dns_rdata_tostruct(rdata, sp = &cert, mctx); break; } case dns_rdatatype_cname: { static dns_rdata_cname_t cname; result = dns_rdata_tostruct(rdata, sp = &cname, mctx); break; } case dns_rdatatype_dname: { static dns_rdata_dname_t dname; result = dns_rdata_tostruct(rdata, sp = &dname, mctx); break; } case dns_rdatatype_gpos: { static dns_rdata_gpos_t gpos; result = dns_rdata_tostruct(rdata, sp = &gpos, mctx); break; } case dns_rdatatype_hinfo: { static dns_rdata_hinfo_t hinfo; result = dns_rdata_tostruct(rdata, sp = &hinfo, mctx); break; } case dns_rdatatype_isdn: { static dns_rdata_isdn_t isdn; result = dns_rdata_tostruct(rdata, sp = &isdn, mctx); break; } case dns_rdatatype_key: { static dns_rdata_key_t key; result = dns_rdata_tostruct(rdata, sp = &key, mctx); break; } case dns_rdatatype_kx: { static dns_rdata_in_kx_t in_kx; result = dns_rdata_tostruct(rdata, sp = &in_kx, mctx); break; } case dns_rdatatype_loc: { static dns_rdata_loc_t loc; result = dns_rdata_tostruct(rdata, sp = &loc, mctx); break; } case dns_rdatatype_mb: { static dns_rdata_mb_t mb; result = dns_rdata_tostruct(rdata, sp = &mb, mctx); break; } case dns_rdatatype_md: { static dns_rdata_md_t md; result = dns_rdata_tostruct(rdata, sp = &md, mctx); break; } case dns_rdatatype_mf: { static dns_rdata_mf_t mf; result = dns_rdata_tostruct(rdata, sp = &mf, mctx); break; } case dns_rdatatype_mg: { static dns_rdata_mg_t mg; result = dns_rdata_tostruct(rdata, sp = &mg, mctx); break; } case dns_rdatatype_minfo: { static dns_rdata_minfo_t minfo; result = dns_rdata_tostruct(rdata, sp = &minfo, mctx); break; } case dns_rdatatype_mr: { static dns_rdata_mr_t mr; result = dns_rdata_tostruct(rdata, sp = &mr, mctx); break; } case dns_rdatatype_mx: { static dns_rdata_mx_t mx; result = dns_rdata_tostruct(rdata, sp = &mx, mctx); break; } case dns_rdatatype_naptr: { static dns_rdata_naptr_t naptr; result = dns_rdata_tostruct(rdata, sp = &naptr, mctx); break; } case dns_rdatatype_ns: { static dns_rdata_ns_t ns; result = dns_rdata_tostruct(rdata, sp = &ns, mctx); break; } case dns_rdatatype_nsap: { static dns_rdata_in_nsap_t in_nsap; result = dns_rdata_tostruct(rdata, sp = &in_nsap, mctx); break; } case dns_rdatatype_nsap_ptr: { static dns_rdata_in_nsap_ptr_t in_nsap_ptr; result = dns_rdata_tostruct(rdata, sp = &in_nsap_ptr, mctx); break; } case dns_rdatatype_null: { static dns_rdata_null_t null; result = dns_rdata_tostruct(rdata, sp = &null, mctx); break; } case dns_rdatatype_nxt: { static dns_rdata_nxt_t nxt; result = dns_rdata_tostruct(rdata, sp = &nxt, mctx); break; } case dns_rdatatype_opt: { static dns_rdata_opt_t opt; result = dns_rdata_tostruct(rdata, sp = &opt, mctx); break; } case dns_rdatatype_ptr: { static dns_rdata_ptr_t ptr; result = dns_rdata_tostruct(rdata, sp = &ptr, mctx); break; } case dns_rdatatype_px: { static dns_rdata_in_px_t in_px; result = dns_rdata_tostruct(rdata, sp = &in_px, mctx); break; } case dns_rdatatype_rp: { static dns_rdata_rp_t rp; result = dns_rdata_tostruct(rdata, sp = &rp, mctx); break; } case dns_rdatatype_rt: { static dns_rdata_rt_t rt; result = dns_rdata_tostruct(rdata, sp = &rt, mctx); break; } case dns_rdatatype_sig: { static dns_rdata_sig_t sig; result = dns_rdata_tostruct(rdata, sp = &sig, mctx); break; } case dns_rdatatype_soa: { static dns_rdata_soa_t soa; result = dns_rdata_tostruct(rdata, sp = &soa, mctx); break; } case dns_rdatatype_srv: { static dns_rdata_in_srv_t in_srv; result = dns_rdata_tostruct(rdata, sp = &in_srv, mctx); break; } case dns_rdatatype_tkey: { static dns_rdata_tkey_t tkey; result = dns_rdata_tostruct(rdata, sp = &tkey, mctx); break; } case dns_rdatatype_tsig: { static dns_rdata_any_tsig_t tsig; result = dns_rdata_tostruct(rdata, sp = &tsig, mctx); break; } case dns_rdatatype_txt: { static dns_rdata_txt_t txt; result = dns_rdata_tostruct(rdata, sp = &txt, mctx); break; } case dns_rdatatype_spf: { static dns_rdata_spf_t spf; result = dns_rdata_tostruct(rdata, sp = &spf, mctx); break; } case dns_rdatatype_unspec: { static dns_rdata_unspec_t unspec; result = dns_rdata_tostruct(rdata, sp = &unspec, mctx); break; } case dns_rdatatype_uri: { static dns_rdata_uri_t uri; result = dns_rdata_tostruct(rdata, sp = &uri, mctx); break; } case dns_rdatatype_wks: { static dns_rdata_in_wks_t in_wks; result = dns_rdata_tostruct(rdata, sp = &in_wks, mctx); break; } case dns_rdatatype_x25: { static dns_rdata_x25_t x25; result = dns_rdata_tostruct(rdata, sp = &x25, mctx); break; } case dns_rdatatype_nsec: { static dns_rdata_nsec_t nsec; result = dns_rdata_tostruct(rdata, sp = &nsec, mctx); break; } case dns_rdatatype_rrsig: { static dns_rdata_rrsig_t rrsig; result = dns_rdata_tostruct(rdata, sp = &rrsig, mctx); break; } case dns_rdatatype_dnskey: { static dns_rdata_dnskey_t dnskey; result = dns_rdata_tostruct(rdata, sp = &dnskey, mctx); break; } default: result = ISC_R_NOTIMPLEMENTED; break; } if (result != ISC_R_SUCCESS) fprintf(stdout, "viastruct: tostruct %d %d return %s\n", rdata->type, rdata->rdclass, dns_result_totext(result)); else { need_free = ISC_TRUE; rdc = rdata->rdclass; rdt = rdata->type; result = dns_rdata_fromstruct(rdata2, rdc, rdt, sp, b); if (result != ISC_R_SUCCESS) fprintf(stdout, "viastruct: fromstruct %d %d return %s\n", rdata->type, rdata->rdclass, dns_result_totext(result)); else if (rdata->length != rdata2->length || memcmp(rdata->data, rdata2->data, rdata->length) != 0) { isc_uint32_t i; isc_uint32_t l; fprintf(stdout, "viastruct: memcmp failed\n"); fprintf(stdout, "%d %d\n", rdata->length, rdata2->length); l = rdata->length; if (rdata2->length < l) l = rdata2->length; for (i = 0; i < l; i++) fprintf(stdout, "%02x %02x\n", rdata->data[i], rdata2->data[i]); } } #if 0 switch (rdata->type) { case dns_rdatatype_a6: { dns_rdata_in_a6_t in_a6; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &in_a6, b); break; } case dns_rdatatype_a: { switch (rdata->rdclass) { case dns_rdataclass_hs: { dns_rdata_hs_a_t hs_a; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &hs_a, b); break; } case dns_rdataclass_in: { dns_rdata_in_a_t in_a; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &in_a, b); break; } default: result = ISC_R_NOTIMPLEMENTED; break; } break; } case dns_rdatatype_aaaa: { dns_rdata_in_aaaa_t in_aaaa; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &in_aaaa, b); break; } case dns_rdatatype_afsdb: { dns_rdata_afsdb_t afsdb; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &afsdb, b); break; } case dns_rdatatype_any: { result = ISC_R_NOTIMPLEMENTED; break; } case dns_rdatatype_apl: { switch (rdata->rdclass) { case dns_rdataclass_in: { dns_rdata_in_apl_t in_apl; result = dns_rdata_fromstruct(rdata, rdc, rdt, &in_apl, b); break; } default: result = ISC_R_NOTIMPLEMENTED; break; } break; } case dns_rdatatype_cert: { dns_rdata_cert_t cert; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &cert, b); break; } case dns_rdatatype_cname: { dns_rdata_cname_t cname; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &cname, b); break; } case dns_rdatatype_dname: { dns_rdata_dname_t dname; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &dname, b); break; } case dns_rdatatype_gpos: { dns_rdata_gpos_t gpos; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &gpos, b); break; } case dns_rdatatype_hinfo: { dns_rdata_hinfo_t hinfo; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &hinfo, b); break; } case dns_rdatatype_isdn: { dns_rdata_isdn_t isdn; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &isdn, b); break; } case dns_rdatatype_key: { dns_rdata_key_t key; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &key, b); break; } case dns_rdatatype_kx: { dns_rdata_in_kx_t in_kx; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &in_kx, b); break; } case dns_rdatatype_loc: { dns_rdata_loc_t loc; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &loc, b); break; } case dns_rdatatype_mb: { dns_rdata_mb_t mb; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &mb, b); break; } case dns_rdatatype_md: { dns_rdata_md_t md; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &md, b); break; } case dns_rdatatype_mf: { dns_rdata_mf_t mf; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &mf, b); break; } case dns_rdatatype_mg: { dns_rdata_mg_t mg; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &mg, b); break; } case dns_rdatatype_minfo: { dns_rdata_minfo_t minfo; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &minfo, b); break; } case dns_rdatatype_mr: { dns_rdata_mr_t mr; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &mr, b); break; } case dns_rdatatype_mx: { dns_rdata_mx_t mx; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &mx, b); break; } case dns_rdatatype_naptr: { dns_rdata_naptr_t naptr; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &naptr, b); break; } case dns_rdatatype_ns: { dns_rdata_ns_t ns; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &ns, b); break; } case dns_rdatatype_nsap: { dns_rdata_in_nsap_t in_nsap; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &in_nsap, b); break; } case dns_rdatatype_nsap_ptr: { dns_rdata_in_nsap_ptr_t in_nsap_ptr; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &in_nsap_ptr, b); break; } case dns_rdatatype_null: { dns_rdata_null_t null; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &null, b); break; } case dns_rdatatype_nxt: { dns_rdata_nxt_t nxt; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &nxt, b); break; } case dns_rdatatype_opt: { dns_rdata_opt_t opt; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &opt, b); break; } case dns_rdatatype_ptr: { dns_rdata_ptr_t ptr; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &ptr, b); break; } case dns_rdatatype_px: { dns_rdata_in_px_t in_px; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &in_px, b); break; } case dns_rdatatype_rp: { dns_rdata_rp_t rp; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &rp, b); break; } case dns_rdatatype_rt: { dns_rdata_rt_t rt; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &rt, b); break; } case dns_rdatatype_sig: { dns_rdata_sig_t sig; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &sig, b); break; } case dns_rdatatype_soa: { dns_rdata_soa_t soa; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &soa, b); break; } case dns_rdatatype_srv: { dns_rdata_in_srv_t in_srv; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &in_srv, b); break; } case dns_rdatatype_tkey: { dns_rdata_tkey_t tkey; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &tkey, b); break; } case dns_rdatatype_tsig: { dns_rdata_any_tsig_t tsig; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &tsig, b); break; } case dns_rdatatype_txt: { dns_rdata_txt_t txt; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &txt, b); break; } case dns_rdatatype_spf: { dns_rdata_spf_t spf; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &spf, b); break; } case dns_rdatatype_unspec: { dns_rdata_unspec_t unspec; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &unspec, b); break; } case dns_rdatatype_uri: { dns_rdata_uri_t uri; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &uri, b); break; } case dns_rdatatype_wks: { dns_rdata_in_wks_t in_wks; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &in_wks, b); break; } case dns_rdatatype_x25: { dns_rdata_x25_t x25; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &x25, b); break; } case dns_rdatatype_nsec: { dns_rdata_nsec_t nsec; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &nsec, b); break; } case dns_rdatatype_rrsig: { dns_rdata_rrsig_t rrsig; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &rrsig, b); break; } case dns_rdatatype_dnskey: { dns_rdata_dnskey_t dnskey; result = dns_rdata_fromstruct(rdata2, rdc, rdt, &dnskey, b); break; } default: result = ISC_R_NOTIMPLEMENTED; break; } #endif if (need_free) dns_rdata_freestruct(sp); }
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 tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { dns_rdata_any_tsig_t tsig, querytsig; isc_region_t r, source_r, header_r, sig_r; isc_buffer_t databuf; unsigned char data[32]; dns_name_t *keyname; dns_rdata_t rdata = DNS_RDATA_INIT; isc_stdtime_t now; isc_result_t ret; dns_tsigkey_t *tsigkey; dst_key_t *key = NULL; unsigned char header[DNS_MESSAGE_HEADERLEN]; isc_uint16_t addcount, id; isc_boolean_t has_tsig = ISC_FALSE; isc_mem_t *mctx; REQUIRE(source != NULL); REQUIRE(msg != NULL); REQUIRE(dns_message_gettsigkey(msg) != NULL); REQUIRE(msg->tcp_continuation == 1); REQUIRE(msg->querytsig != NULL); if (!is_response(msg)) return (DNS_R_EXPECTEDRESPONSE); mctx = msg->mctx; tsigkey = dns_message_gettsigkey(msg); /* * Extract and parse the previous TSIG */ ret = dns_rdataset_first(msg->querytsig); if (ret != ISC_R_SUCCESS) return (ret); dns_rdataset_current(msg->querytsig, &rdata); ret = dns_rdata_tostruct(&rdata, &querytsig, NULL); if (ret != ISC_R_SUCCESS) return (ret); dns_rdata_reset(&rdata); /* * If there is a TSIG in this message, do some checks. */ if (msg->tsig != NULL) { has_tsig = ISC_TRUE; keyname = msg->tsigname; ret = dns_rdataset_first(msg->tsig); if (ret != ISC_R_SUCCESS) goto cleanup_querystruct; dns_rdataset_current(msg->tsig, &rdata); ret = dns_rdata_tostruct(&rdata, &tsig, NULL); if (ret != ISC_R_SUCCESS) goto cleanup_querystruct; /* * Do the key name and algorithm match that of the query? */ if (!dns_name_equal(keyname, &tsigkey->name) || !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)) { msg->tsigstatus = dns_tsigerror_badkey; ret = DNS_R_TSIGVERIFYFAILURE; tsig_log(msg->tsigkey, 2, "key name and algorithm do not match"); goto cleanup_querystruct; } /* * Is the time ok? */ isc_stdtime_get(&now); if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) { msg->tsigstatus = dns_tsigerror_badtime; tsig_log(msg->tsigkey, 2, "signature has expired"); ret = DNS_R_CLOCKSKEW; goto cleanup_querystruct; } else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge) { msg->tsigstatus = dns_tsigerror_badtime; tsig_log(msg->tsigkey, 2, "signature is in the future"); ret = DNS_R_CLOCKSKEW; goto cleanup_querystruct; } } key = tsigkey->key; if (msg->tsigctx == NULL) { ret = dst_context_create3(key, mctx, DNS_LOGCATEGORY_DNSSEC, ISC_FALSE, &msg->tsigctx); if (ret != ISC_R_SUCCESS) goto cleanup_querystruct; /* * Digest the length of the query signature */ isc_buffer_init(&databuf, data, sizeof(data)); isc_buffer_putuint16(&databuf, querytsig.siglen); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(msg->tsigctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; /* * Digest the data of the query signature */ if (querytsig.siglen > 0) { r.length = querytsig.siglen; r.base = querytsig.signature; ret = dst_context_adddata(msg->tsigctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; } } /* * Extract the header. */ isc_buffer_usedregion(source, &r); memmove(header, r.base, DNS_MESSAGE_HEADERLEN); isc_region_consume(&r, DNS_MESSAGE_HEADERLEN); /* * Decrement the additional field counter if necessary. */ if (has_tsig) { memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2); addcount = htons((isc_uint16_t)(ntohs(addcount) - 1)); memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2); } /* * Put in the original id. */ /* XXX Can TCP transfers be forwarded? How would that work? */ if (has_tsig) { id = htons(tsig.originalid); memmove(&header[0], &id, 2); } /* * Digest the modified header. */ header_r.base = (unsigned char *) header; header_r.length = DNS_MESSAGE_HEADERLEN; ret = dst_context_adddata(msg->tsigctx, &header_r); if (ret != ISC_R_SUCCESS) goto cleanup_context; /* * Digest all non-TSIG records. */ isc_buffer_usedregion(source, &source_r); r.base = source_r.base + DNS_MESSAGE_HEADERLEN; if (has_tsig) r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN; else r.length = source_r.length - DNS_MESSAGE_HEADERLEN; ret = dst_context_adddata(msg->tsigctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; /* * Digest the time signed and fudge. */ if (has_tsig) { isc_buffer_init(&databuf, data, sizeof(data)); isc_buffer_putuint48(&databuf, tsig.timesigned); isc_buffer_putuint16(&databuf, tsig.fudge); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(msg->tsigctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; sig_r.base = tsig.signature; sig_r.length = tsig.siglen; if (tsig.siglen == 0) { if (tsig.error != dns_rcode_noerror) { if (tsig.error == dns_tsigerror_badtime) ret = DNS_R_CLOCKSKEW; else ret = DNS_R_TSIGERRORSET; } else { tsig_log(msg->tsigkey, 2, "signature is empty"); ret = DNS_R_TSIGVERIFYFAILURE; } goto cleanup_context; } ret = dst_context_verify(msg->tsigctx, &sig_r); if (ret == DST_R_VERIFYFAILURE) { msg->tsigstatus = dns_tsigerror_badsig; tsig_log(msg->tsigkey, 2, "signature failed to verify(2)"); ret = DNS_R_TSIGVERIFYFAILURE; goto cleanup_context; } else if (ret != ISC_R_SUCCESS) goto cleanup_context; dst_context_destroy(&msg->tsigctx); } msg->tsigstatus = dns_rcode_noerror; return (ISC_R_SUCCESS); cleanup_context: dst_context_destroy(&msg->tsigctx); cleanup_querystruct: dns_rdata_freestruct(&querytsig); return (ret); }
isc_result_t dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, dns_tsig_keyring_t *ring1, dns_tsig_keyring_t *ring2) { dns_rdata_any_tsig_t tsig, querytsig; isc_region_t r, source_r, header_r, sig_r; isc_buffer_t databuf; unsigned char data[32]; dns_name_t *keyname; dns_rdata_t rdata = DNS_RDATA_INIT; isc_stdtime_t now; isc_result_t ret; dns_tsigkey_t *tsigkey; dst_key_t *key = NULL; unsigned char header[DNS_MESSAGE_HEADERLEN]; dst_context_t *ctx = NULL; isc_mem_t *mctx; isc_uint16_t addcount, id; unsigned int siglen; unsigned int alg; isc_boolean_t response; REQUIRE(source != NULL); REQUIRE(DNS_MESSAGE_VALID(msg)); tsigkey = dns_message_gettsigkey(msg); response = is_response(msg); REQUIRE(tsigkey == NULL || VALID_TSIG_KEY(tsigkey)); msg->verify_attempted = 1; if (msg->tcp_continuation) { if (tsigkey == NULL || msg->querytsig == NULL) return (DNS_R_UNEXPECTEDTSIG); return (tsig_verify_tcp(source, msg)); } /* * There should be a TSIG record... */ if (msg->tsig == NULL) return (DNS_R_EXPECTEDTSIG); /* * If this is a response and there's no key or query TSIG, there * shouldn't be one on the response. */ if (response && (tsigkey == NULL || msg->querytsig == NULL)) return (DNS_R_UNEXPECTEDTSIG); mctx = msg->mctx; /* * If we're here, we know the message is well formed and contains a * TSIG record. */ keyname = msg->tsigname; ret = dns_rdataset_first(msg->tsig); if (ret != ISC_R_SUCCESS) return (ret); dns_rdataset_current(msg->tsig, &rdata); ret = dns_rdata_tostruct(&rdata, &tsig, NULL); if (ret != ISC_R_SUCCESS) return (ret); dns_rdata_reset(&rdata); if (response) { ret = dns_rdataset_first(msg->querytsig); if (ret != ISC_R_SUCCESS) return (ret); dns_rdataset_current(msg->querytsig, &rdata); ret = dns_rdata_tostruct(&rdata, &querytsig, NULL); if (ret != ISC_R_SUCCESS) return (ret); } #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 /* * Do the key name and algorithm match that of the query? */ if (response && (!dns_name_equal(keyname, &tsigkey->name) || !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))) { msg->tsigstatus = dns_tsigerror_badkey; tsig_log(msg->tsigkey, 2, "key name and algorithm do not match"); return (DNS_R_TSIGVERIFYFAILURE); } /* * Get the current time. */ isc_stdtime_get(&now); /* * Find dns_tsigkey_t based on keyname. */ if (tsigkey == NULL) { ret = ISC_R_NOTFOUND; if (ring1 != NULL) ret = dns_tsigkey_find(&tsigkey, keyname, &tsig.algorithm, ring1); if (ret == ISC_R_NOTFOUND && ring2 != NULL) ret = dns_tsigkey_find(&tsigkey, keyname, &tsig.algorithm, ring2); if (ret != ISC_R_SUCCESS) { msg->tsigstatus = dns_tsigerror_badkey; ret = dns_tsigkey_create(keyname, &tsig.algorithm, NULL, 0, ISC_FALSE, NULL, now, now, mctx, NULL, &msg->tsigkey); if (ret != ISC_R_SUCCESS) return (ret); tsig_log(msg->tsigkey, 2, "unknown key"); return (DNS_R_TSIGVERIFYFAILURE); } msg->tsigkey = tsigkey; } key = tsigkey->key; /* * Is the time ok? */ if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) { msg->tsigstatus = dns_tsigerror_badtime; tsig_log(msg->tsigkey, 2, "signature has expired"); return (DNS_R_CLOCKSKEW); } else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge) { msg->tsigstatus = dns_tsigerror_badtime; tsig_log(msg->tsigkey, 2, "signature is in the future"); return (DNS_R_CLOCKSKEW); } /* * Check digest length. */ alg = dst_key_alg(key); ret = dst_key_sigsize(key, &siglen); if (ret != ISC_R_SUCCESS) return (ret); if (alg == DST_ALG_HMACMD5 || alg == DST_ALG_HMACSHA1 || alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 || alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512) { isc_uint16_t digestbits = dst_key_getbits(key); if (tsig.siglen > siglen) { tsig_log(msg->tsigkey, 2, "signature length too big"); return (DNS_R_FORMERR); } if (tsig.siglen > 0 && (tsig.siglen < 10 || tsig.siglen < ((siglen + 1) / 2))) { tsig_log(msg->tsigkey, 2, "signature length below minimum"); return (DNS_R_FORMERR); } if (tsig.siglen > 0 && digestbits != 0 && tsig.siglen < ((digestbits + 1) / 8)) { msg->tsigstatus = dns_tsigerror_badtrunc; tsig_log(msg->tsigkey, 2, "truncated signature length too small"); return (DNS_R_TSIGVERIFYFAILURE); } if (tsig.siglen > 0 && digestbits == 0 && tsig.siglen < siglen) { msg->tsigstatus = dns_tsigerror_badtrunc; tsig_log(msg->tsigkey, 2, "signature length too small"); return (DNS_R_TSIGVERIFYFAILURE); } } if (tsig.siglen > 0) { sig_r.base = tsig.signature; sig_r.length = tsig.siglen; ret = dst_context_create3(key, mctx, DNS_LOGCATEGORY_DNSSEC, ISC_FALSE, &ctx); if (ret != ISC_R_SUCCESS) return (ret); if (response) { isc_buffer_init(&databuf, data, sizeof(data)); isc_buffer_putuint16(&databuf, querytsig.siglen); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; if (querytsig.siglen > 0) { r.length = querytsig.siglen; r.base = querytsig.signature; ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; } } /* * Extract the header. */ isc_buffer_usedregion(source, &r); memmove(header, r.base, DNS_MESSAGE_HEADERLEN); isc_region_consume(&r, DNS_MESSAGE_HEADERLEN); /* * Decrement the additional field counter. */ memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2); addcount = htons((isc_uint16_t)(ntohs(addcount) - 1)); memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2); /* * Put in the original id. */ id = htons(tsig.originalid); memmove(&header[0], &id, 2); /* * Digest the modified header. */ header_r.base = (unsigned char *) header; header_r.length = DNS_MESSAGE_HEADERLEN; ret = dst_context_adddata(ctx, &header_r); if (ret != ISC_R_SUCCESS) goto cleanup_context; /* * Digest all non-TSIG records. */ isc_buffer_usedregion(source, &source_r); r.base = source_r.base + DNS_MESSAGE_HEADERLEN; r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN; ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; /* * Digest the key name. */ dns_name_toregion(&tsigkey->name, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; isc_buffer_init(&databuf, data, sizeof(data)); isc_buffer_putuint16(&databuf, tsig.common.rdclass); isc_buffer_putuint32(&databuf, msg->tsig->ttl); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; /* * Digest the key algorithm. */ dns_name_toregion(tsigkey->algorithm, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; isc_buffer_clear(&databuf); isc_buffer_putuint48(&databuf, tsig.timesigned); isc_buffer_putuint16(&databuf, tsig.fudge); 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; if (tsig.otherlen > 0) { r.base = tsig.other; r.length = tsig.otherlen; ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; } ret = dst_context_verify(ctx, &sig_r); if (ret == DST_R_VERIFYFAILURE) { msg->tsigstatus = dns_tsigerror_badsig; ret = DNS_R_TSIGVERIFYFAILURE; tsig_log(msg->tsigkey, 2, "signature failed to verify(1)"); goto cleanup_context; } else if (ret != ISC_R_SUCCESS) goto cleanup_context; dst_context_destroy(&ctx); } else if (tsig.error != dns_tsigerror_badsig && tsig.error != dns_tsigerror_badkey) { msg->tsigstatus = dns_tsigerror_badsig; tsig_log(msg->tsigkey, 2, "signature was empty"); return (DNS_R_TSIGVERIFYFAILURE); } msg->tsigstatus = dns_rcode_noerror; if (tsig.error != dns_rcode_noerror) { if (tsig.error == dns_tsigerror_badtime) return (DNS_R_CLOCKSKEW); else return (DNS_R_TSIGERRORSET); } msg->verified_sig = 1; return (ISC_R_SUCCESS); cleanup_context: if (ctx != NULL) dst_context_destroy(&ctx); return (ret); }
static void resolve_nsaddress(isc_task_t *task, isc_event_t *event) { struct probe_trans *trans = event->ev_arg; dns_clientresevent_t *rev = (dns_clientresevent_t *)event; dns_name_t *name; dns_rdataset_t *rdataset; dns_rdata_t rdata = DNS_RDATA_INIT; struct probe_ns *pns = trans->current_ns; isc_result_t result; REQUIRE(task == probe_task); REQUIRE(trans->inuse == ISC_TRUE); REQUIRE(pns != NULL); INSIST(outstanding_probes > 0); for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; name = ISC_LIST_NEXT(name, link)) { for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { (void)print_rdataset(rdataset, name); if (rdataset->type != dns_rdatatype_a) continue; for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(rdataset)) { dns_rdata_in_a_t rdata_a; struct server *server; dns_rdataset_current(rdataset, &rdata); result = dns_rdata_tostruct(&rdata, &rdata_a, NULL); if (result != ISC_R_SUCCESS) continue; server = isc_mem_get(mctx, sizeof(*server)); if (server == NULL) { fprintf(stderr, "resolve_nsaddress: " "mem_get failed"); result = ISC_R_NOMEMORY; POST(result); goto cleanup; } isc_sockaddr_fromin(&server->address, &rdata_a.in_addr, 53); ISC_LINK_INIT(server, link); server->result_a = none; server->result_aaaa = none; ISC_LIST_APPEND(pns->servers, server, link); } } } cleanup: dns_client_freeresanswer(client, &rev->answerlist); dns_client_destroyrestrans(&trans->resid); isc_event_free(&event); next_ns: trans->current_ns = ISC_LIST_NEXT(pns, link); if (trans->current_ns == NULL) { trans->current_ns = ISC_LIST_HEAD(trans->nslist); dns_fixedname_invalidate(&trans->fixedname); trans->qname = NULL; result = set_nextqname(trans); if (result == ISC_R_SUCCESS) result = probe_name(trans, dns_rdatatype_a); } else { result = fetch_nsaddress(trans); if (result != ISC_R_SUCCESS) goto next_ns; /* XXX: this is unlikely to succeed */ } if (result != ISC_R_SUCCESS) reset_probe(trans); }
ATF_TC_BODY(isdn, tc) { struct { unsigned char data[64]; size_t len; isc_boolean_t ok; } test_data[] = { { /* "" */ { 0x00 }, 1, ISC_TRUE }, { /* "\001" */ { 0x1, 0x01 }, 2, ISC_TRUE }, { /* "\001" "" */ { 0x1, 0x01, 0x00 }, 3, ISC_TRUE }, { /* "\000" "\001" */ { 0x1, 0x01, 0x01, 0x01 }, 4, ISC_TRUE }, { /* sentinal */ { 0x00 }, 0, ISC_FALSE } }; unsigned char buf1[1024]; unsigned char buf2[1024]; isc_buffer_t source, target1, target2; dns_rdata_t rdata; dns_decompress_t dctx; isc_result_t result; size_t i; dns_rdata_isdn_t isdn; UNUSED(tc); for (i = 0; test_data[i].len != 0; i++) { isc_buffer_init(&source, test_data[i].data, test_data[i].len); isc_buffer_add(&source, test_data[i].len); isc_buffer_setactive(&source, test_data[i].len); isc_buffer_init(&target1, buf1, sizeof(buf1)); dns_rdata_init(&rdata); dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY); result = dns_rdata_fromwire(&rdata, dns_rdataclass_in, dns_rdatatype_isdn, &source, &dctx, 0, &target1); dns_decompress_invalidate(&dctx); if (test_data[i].ok) ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); else ATF_REQUIRE(result != ISC_R_SUCCESS); if (result != ISC_R_SUCCESS) continue; result = dns_rdata_tostruct(&rdata, &isdn, NULL); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); isc_buffer_init(&target2, buf2, sizeof(buf2)); dns_rdata_reset(&rdata); result = dns_rdata_fromstruct(&rdata, dns_rdataclass_in, dns_rdatatype_isdn, &isdn, &target2); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); ATF_REQUIRE_EQ(isc_buffer_usedlength(&target2), test_data[i].len); ATF_REQUIRE_EQ(memcmp(buf2, test_data[i].data, test_data[i].len), 0); } }
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
isc_result_t dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg, dst_key_t *key) { dns_rdata_sig_t sig; /* SIG(0) */ unsigned char header[DNS_MESSAGE_HEADERLEN]; dns_rdata_t rdata = DNS_RDATA_INIT; isc_region_t r, source_r, sig_r, header_r; isc_stdtime_t now; dst_context_t *ctx = NULL; isc_mem_t *mctx; isc_result_t result; isc_uint16_t addcount; isc_boolean_t signeedsfree = ISC_FALSE; REQUIRE(source != NULL); REQUIRE(msg != NULL); REQUIRE(key != NULL); mctx = msg->mctx; msg->verify_attempted = 1; if (is_response(msg)) { if (msg->query.base == NULL) return (DNS_R_UNEXPECTEDTSIG); } isc_buffer_usedregion(source, &source_r); RETERR(dns_rdataset_first(msg->sig0)); dns_rdataset_current(msg->sig0, &rdata); RETERR(dns_rdata_tostruct(&rdata, &sig, NULL)); signeedsfree = ISC_TRUE; if (sig.labels != 0) { result = DNS_R_SIGINVALID; goto failure; } if (isc_serial_lt(sig.timeexpire, sig.timesigned)) { result = DNS_R_SIGINVALID; msg->sig0status = dns_tsigerror_badtime; goto failure; } isc_stdtime_get(&now); if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) { result = DNS_R_SIGFUTURE; msg->sig0status = dns_tsigerror_badtime; goto failure; } else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) { result = DNS_R_SIGEXPIRED; msg->sig0status = dns_tsigerror_badtime; goto failure; } if (!dns_name_equal(dst_key_name(key), &sig.signer)) { result = DNS_R_SIGINVALID; msg->sig0status = dns_tsigerror_badkey; goto failure; } RETERR(dst_context_create(key, mctx, &ctx)); /* * Digest the SIG(0) record, except for the signature. */ dns_rdata_toregion(&rdata, &r); r.length -= sig.siglen; 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)); /* * Extract the header. */ memcpy(header, source_r.base, DNS_MESSAGE_HEADERLEN); /* * Decrement the additional field counter. */ memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2); addcount = htons((isc_uint16_t)(ntohs(addcount) - 1)); memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2); /* * Digest the modified header. */ header_r.base = (unsigned char *) header; header_r.length = DNS_MESSAGE_HEADERLEN; RETERR(dst_context_adddata(ctx, &header_r)); /* * Digest all non-SIG(0) records. */ r.base = source_r.base + DNS_MESSAGE_HEADERLEN; r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN; RETERR(dst_context_adddata(ctx, &r)); sig_r.base = sig.signature; sig_r.length = sig.siglen; result = dst_context_verify(ctx, &sig_r); if (result != ISC_R_SUCCESS) { msg->sig0status = dns_tsigerror_badsig; goto failure; } msg->verified_sig = 1; dst_context_destroy(&ctx); dns_rdata_freestruct(&sig); return (ISC_R_SUCCESS); failure: if (signeedsfree) dns_rdata_freestruct(&sig); if (ctx != NULL) dst_context_destroy(&ctx); return (result); }
isc_result_t dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, isc_boolean_t ignoretime, isc_mem_t *mctx, dns_rdata_t *sigrdata, dns_name_t *wild) { dns_rdata_rrsig_t sig; dns_fixedname_t fnewname; isc_region_t r; isc_buffer_t envbuf; dns_rdata_t *rdatas; int nrdatas, i; isc_stdtime_t now; isc_result_t ret; unsigned char data[300]; dst_context_t *ctx = NULL; int labels = 0; isc_uint32_t flags; REQUIRE(name != NULL); REQUIRE(set != NULL); REQUIRE(key != NULL); REQUIRE(mctx != NULL); REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig); ret = dns_rdata_tostruct(sigrdata, &sig, NULL); if (ret != ISC_R_SUCCESS) return (ret); if (isc_serial_lt(sig.timeexpire, sig.timesigned)) return (DNS_R_SIGINVALID); if (!ignoretime) { isc_stdtime_get(&now); /* * Is SIG temporally valid? */ if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) return (DNS_R_SIGFUTURE); else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) return (DNS_R_SIGEXPIRED); } /* * 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); ret = dst_context_create(key, mctx, &ctx); if (ret != ISC_R_SUCCESS) goto cleanup_struct; /* * Digest the SIG rdata (not including the signature). */ ret = digest_sig(ctx, sigrdata, &sig); if (ret != ISC_R_SUCCESS) goto cleanup_context; /* * If the name is an expanded wildcard, use the wildcard name. */ dns_fixedname_init(&fnewname); labels = dns_name_countlabels(name) - 1; RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname), NULL) == ISC_R_SUCCESS); if (labels - sig.labels > 0) dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1, NULL, dns_fixedname_name(&fnewname)); 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)); if (labels - sig.labels > 0) { isc_buffer_putuint8(&envbuf, 1); isc_buffer_putuint8(&envbuf, '*'); memcpy(data + 2, r.base, r.length); } else 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, sig.originalttl); 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 rdata length. */ 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); /* * Digest the rdata. */ ret = dst_context_adddata(ctx, &lenr); if (ret != ISC_R_SUCCESS) goto cleanup_array; ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx); if (ret != ISC_R_SUCCESS) goto cleanup_array; } r.base = sig.signature; r.length = sig.siglen; ret = dst_context_verify(ctx, &r); if (ret == DST_R_VERIFYFAILURE) ret = DNS_R_SIGINVALID; cleanup_array: isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t)); cleanup_context: dst_context_destroy(&ctx); cleanup_struct: dns_rdata_freestruct(&sig); if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) { if (wild != NULL) RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname, dns_fixedname_name(&fnewname), wild, NULL) == ISC_R_SUCCESS); ret = DNS_R_FROMWILDCARD; } return (ret); }
/* * we asked for, and got a CNAME of some kind. */ static void process_step_cname(dnskey_glob *gs, dnskey_lookup *dl, struct rrsetinfo *ans, int success) { struct rdatainfo *ri; isc_region_t region; dns_rdata_t rd; dns_rdata_cname_t cn; char simplebuf[80]; isc_buffer_t *cname_text; char cname_buf[DNS_NAME_MAXTEXT]; /* char cname_buf2[DNS_NAME_MAXTEXT]; */ switch(success) { case ERRSET_NONAME: case ERRSET_NODATA: /* no, no CNAME found, thing isn't there */ snprintf(simplebuf, sizeof(simplebuf), "RR of type %s for %s was not found (tried CNAMEs)", dl->wantedtype_name, dl->fqdn); output_transaction_line(gs, dl->tracking_id, 0, "RETRY", simplebuf); dl->step = dkl_done; return; case 0: /* aha! found a CNAME */ break; default: fatal: /* some other error */ snprintf(simplebuf, sizeof(simplebuf), "err=%d", success); output_transaction_line(gs, dl->tracking_id, 0, "FATAL", simplebuf); dl->step = dkl_done; return; } /* * now process out the CNAMEs, and look them up, one by one... * there should be only one... We just use the first one that works. */ if(ans->rri_flags & RRSET_VALIDATED) { output_transaction_line(gs, dl->tracking_id, 0, "DNSSEC", "OKAY"); } else { output_transaction_line(gs, dl->tracking_id, 0, "DNSSEC", "not present"); } if(ans->rri_nrdatas != 1) { /* we got a number of CNAMEs different from 1! */ success=0; snprintf(simplebuf, sizeof(simplebuf), "illegal number of CNAMES: %d", ans->rri_nrdatas); output_transaction_line(gs, dl->tracking_id, 0, "FATAL", simplebuf); dl->step = dkl_done; return; } /* process first CNAME record */ ri= &ans->rri_rdatas[0]; memset(®ion, 0, sizeof(region)); memset(&rd, 0, sizeof(rd)); region.base = ri->rdi_data; region.length = ri->rdi_length; dns_rdata_fromregion(&rd, dns_rdataclass_in, dns_rdatatype_cname, ®ion); /* we set mctx to NULL, which means that the tenure for * the stuff pointed to by cn will persist only as long * as rd persists. */ if(dns_rdata_tostruct(&rd, &cn, NULL) != ISC_R_SUCCESS) { /* failed, try next return error */ success=0; goto fatal; } cname_text=NULL; if(isc_buffer_allocate(gs->iscmem, &cname_text, DNS_NAME_MAXTEXT)) { success=0; goto fatal; } if(dns_name_totext(&cn.cname, ISC_TRUE, cname_text) != ISC_R_SUCCESS) { success=0; goto fatal; } cname_buf[0]='\0'; strncat(cname_buf, isc_buffer_base(cname_text), isc_buffer_usedlength(cname_text)); /* free up buffer */ isc_buffer_free(&cname_text); { /* add a trailing . */ char *end; end = &cname_buf[strlen(cname_buf)]; if(*end != '.') { strncat(cname_buf, ".", sizeof(cname_buf)); } } /* format out a text version */ output_transaction_line(gs, dl->tracking_id, 0, "CNAME", cname_buf); output_transaction_line(gs, dl->tracking_id, 0, "CNAMEFROM", dl->fqdn); /* check for loops in the CNAMEs! */ if(dns_name_equal(&dl->last_cname, &cn.cname) == ISC_TRUE) { /* damn, we found a loop! */ dl->step = dkl_done; return; } /* send new request. */ /* okay, so look this new thing up */ success = lwres_getrrsetbyname_init(cname_buf, dns_rdataclass_in, dl->wantedtype, 0 /*flags*/, gs->lwctx, &dl->las); if(success != ERRSET_SUCCESS) { return; } lwres_getrrsetbyname_xmit(gs->lwctx, &dl->las); dl->step = dkl_second; }
isc_result_t dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, dns_rdatatype_t covers, dns_rdataset_t *rdataset) { dns_name_t tname; dns_rdata_rrsig_t rrsig; dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_t clone; dns_rdatatype_t type; dns_trust_t trust = dns_trust_none; isc_buffer_t source; isc_region_t remaining, sigregion; isc_result_t result; unsigned char *raw; unsigned int count; REQUIRE(ncacherdataset != NULL); REQUIRE(ncacherdataset->type == 0); REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0); REQUIRE(name != NULL); REQUIRE(!dns_rdataset_isassociated(rdataset)); dns_rdataset_init(&clone); dns_rdataset_clone(ncacherdataset, &clone); result = dns_rdataset_first(&clone); while (result == ISC_R_SUCCESS) { dns_rdataset_current(&clone, &rdata); isc_buffer_init(&source, rdata.data, rdata.length); isc_buffer_add(&source, rdata.length); dns_name_init(&tname, NULL); isc_buffer_remainingregion(&source, &remaining); dns_name_fromregion(&tname, &remaining); INSIST(remaining.length >= tname.length); isc_buffer_forward(&source, tname.length); isc_region_consume(&remaining, tname.length); INSIST(remaining.length >= 2); type = isc_buffer_getuint16(&source); isc_region_consume(&remaining, 2); if (type != dns_rdatatype_rrsig || !dns_name_equal(&tname, name)) { result = dns_rdataset_next(&clone); dns_rdata_reset(&rdata); continue; } INSIST(remaining.length >= 1); trust = isc_buffer_getuint8(&source); INSIST(trust <= dns_trust_ultimate); isc_region_consume(&remaining, 1); raw = remaining.base; count = raw[0] * 256 + raw[1]; INSIST(count > 0); raw += 2; sigregion.length = raw[0] * 256 + raw[1]; raw += 2; sigregion.base = raw; dns_rdata_reset(&rdata); dns_rdata_fromregion(&rdata, rdataset->rdclass, dns_rdatatype_rrsig, &sigregion); (void)dns_rdata_tostruct(&rdata, &rrsig, NULL); if (rrsig.covered == covers) { isc_buffer_remainingregion(&source, &remaining); break; } result = dns_rdataset_next(&clone); dns_rdata_reset(&rdata); } dns_rdataset_disassociate(&clone); if (result == ISC_R_NOMORE) return (ISC_R_NOTFOUND); if (result != ISC_R_SUCCESS) return (result); INSIST(remaining.length != 0); rdataset->methods = &rdataset_methods; rdataset->rdclass = ncacherdataset->rdclass; rdataset->type = dns_rdatatype_rrsig; rdataset->covers = covers; rdataset->ttl = ncacherdataset->ttl; rdataset->trust = trust; rdataset->private1 = NULL; rdataset->private2 = NULL; rdataset->private3 = remaining.base; /* * Reset iterator state. */ rdataset->privateuint4 = 0; rdataset->private5 = NULL; rdataset->private6 = NULL; return (ISC_R_SUCCESS); }
static void emit(unsigned int dtype, isc_boolean_t showall, char *lookaside, dns_rdata_t *rdata) { isc_result_t result; unsigned char buf[DNS_DS_BUFFERSIZE]; char text_buf[DST_KEY_MAXTEXTSIZE]; char name_buf[DNS_NAME_MAXWIRE]; char class_buf[10]; isc_buffer_t textb, nameb, classb; isc_region_t r; dns_rdata_t ds; dns_rdata_dnskey_t dnskey; isc_buffer_init(&textb, text_buf, sizeof(text_buf)); isc_buffer_init(&nameb, name_buf, sizeof(name_buf)); isc_buffer_init(&classb, class_buf, sizeof(class_buf)); dns_rdata_init(&ds); result = dns_rdata_tostruct(rdata, &dnskey, NULL); if (result != ISC_R_SUCCESS) fatal("can't convert DNSKEY"); if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0 && !showall) return; result = dns_ds_buildrdata(name, rdata, dtype, buf, &ds); if (result != ISC_R_SUCCESS) fatal("can't build record"); result = dns_name_totext(name, ISC_FALSE, &nameb); if (result != ISC_R_SUCCESS) fatal("can't print name"); /* Add lookaside origin, if set */ if (lookaside != NULL) { if (isc_buffer_availablelength(&nameb) < strlen(lookaside)) fatal("DLV origin '%s' is too long", lookaside); isc_buffer_putstr(&nameb, lookaside); if (lookaside[strlen(lookaside) - 1] != '.') { if (isc_buffer_availablelength(&nameb) < 1) fatal("DLV origin '%s' is too long", lookaside); isc_buffer_putstr(&nameb, "."); } } result = dns_rdata_totext(&ds, (dns_name_t *) NULL, &textb); if (result != ISC_R_SUCCESS) fatal("can't print rdata"); result = dns_rdataclass_totext(rdclass, &classb); if (result != ISC_R_SUCCESS) fatal("can't print class"); isc_buffer_usedregion(&nameb, &r); printf("%.*s ", (int)r.length, r.base); isc_buffer_usedregion(&classb, &r); printf("%.*s", (int)r.length, r.base); if (lookaside == NULL) printf(" DS "); else printf(" DLV "); isc_buffer_usedregion(&textb, &r); printf("%.*s\n", (int)r.length, r.base); }
void dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found, dns_rdataset_t *rdataset) { dns_rdata_t rdata = DNS_RDATA_INIT; dns_trust_t trust; isc_region_t remaining, sigregion; isc_buffer_t source; dns_name_t tname; dns_rdatatype_t type; unsigned int count; dns_rdata_rrsig_t rrsig; unsigned char *raw; REQUIRE(ncacherdataset != NULL); REQUIRE(ncacherdataset->type == 0); REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0); REQUIRE(found != NULL); REQUIRE(!dns_rdataset_isassociated(rdataset)); dns_rdataset_current(ncacherdataset, &rdata); isc_buffer_init(&source, rdata.data, rdata.length); isc_buffer_add(&source, rdata.length); dns_name_init(&tname, NULL); isc_buffer_remainingregion(&source, &remaining); dns_name_fromregion(found, &remaining); INSIST(remaining.length >= found->length); isc_buffer_forward(&source, found->length); remaining.length -= found->length; INSIST(remaining.length >= 5); type = isc_buffer_getuint16(&source); trust = isc_buffer_getuint8(&source); INSIST(trust <= dns_trust_ultimate); isc_buffer_remainingregion(&source, &remaining); rdataset->methods = &rdataset_methods; rdataset->rdclass = ncacherdataset->rdclass; rdataset->type = type; if (type == dns_rdatatype_rrsig) { /* * Extract covers from RRSIG. */ raw = remaining.base; count = raw[0] * 256 + raw[1]; INSIST(count > 0); raw += 2; sigregion.length = raw[0] * 256 + raw[1]; raw += 2; sigregion.base = raw; dns_rdata_reset(&rdata); dns_rdata_fromregion(&rdata, rdataset->rdclass, rdataset->type, &sigregion); (void)dns_rdata_tostruct(&rdata, &rrsig, NULL); rdataset->covers = rrsig.covered; } else rdataset->covers = 0; rdataset->ttl = ncacherdataset->ttl; rdataset->trust = trust; rdataset->private1 = NULL; rdataset->private2 = NULL; rdataset->private3 = remaining.base; /* * Reset iterator state. */ rdataset->privateuint4 = 0; rdataset->private5 = NULL; rdataset->private6 = NULL; }
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 resolve_ns(isc_task_t *task, isc_event_t *event) { struct probe_trans *trans = event->ev_arg; dns_clientresevent_t *rev = (dns_clientresevent_t *)event; dns_name_t *name; dns_rdataset_t *rdataset; isc_result_t result = ISC_R_SUCCESS; dns_rdata_t rdata = DNS_RDATA_INIT; struct probe_ns *pns; REQUIRE(task == probe_task); REQUIRE(trans->inuse == ISC_TRUE); INSIST(outstanding_probes > 0); for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; name = ISC_LIST_NEXT(name, link)) { for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { (void)print_rdataset(rdataset, name); if (rdataset->type != dns_rdatatype_ns) continue; for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(rdataset)) { dns_rdata_ns_t ns; dns_rdataset_current(rdataset, &rdata); /* * Extract the name from the NS record. */ result = dns_rdata_tostruct(&rdata, &ns, NULL); if (result != ISC_R_SUCCESS) continue; pns = isc_mem_get(mctx, sizeof(*pns)); if (pns == NULL) { fprintf(stderr, "resolve_ns: mem_get failed"); result = ISC_R_NOMEMORY; POST(result); /* * XXX: should we continue with the * available servers anyway? */ goto cleanup; } dns_fixedname_init(&pns->fixedname); pns->name = dns_fixedname_name(&pns->fixedname); ISC_LINK_INIT(pns, link); ISC_LIST_APPEND(trans->nslist, pns, link); ISC_LIST_INIT(pns->servers); dns_name_copy(&ns.name, pns->name, NULL); dns_rdata_reset(&rdata); dns_rdata_freestruct(&ns); } } } cleanup: dns_client_freeresanswer(client, &rev->answerlist); dns_client_destroyrestrans(&trans->resid); isc_event_free(&event); if (!ISC_LIST_EMPTY(trans->nslist)) { /* Go get addresses of NSes */ trans->current_ns = ISC_LIST_HEAD(trans->nslist); result = fetch_nsaddress(trans); } else result = ISC_R_FAILURE; if (result == ISC_R_SUCCESS) return; reset_probe(trans); }
static void lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event) { isc_result_t result; isc_boolean_t want_restart; isc_boolean_t send_event; dns_name_t *name, *fname, *prefix; dns_fixedname_t foundname, fixed; dns_rdata_t rdata = DNS_RDATA_INIT; unsigned int nlabels; int order; dns_namereln_t namereln; dns_rdata_cname_t cname; dns_rdata_dname_t dname; REQUIRE(VALID_LOOKUP(lookup)); LOCK(&lookup->lock); result = ISC_R_SUCCESS; name = dns_fixedname_name(&lookup->name); do { lookup->restarts++; want_restart = ISC_FALSE; send_event = ISC_TRUE; if (event == NULL && !lookup->canceled) { dns_fixedname_init(&foundname); fname = dns_fixedname_name(&foundname); INSIST(!dns_rdataset_isassociated(&lookup->rdataset)); INSIST(!dns_rdataset_isassociated (&lookup->sigrdataset)); /* * If we have restarted then clear the old node. */ if (lookup->event->node != NULL) { INSIST(lookup->event->db != NULL); dns_db_detachnode(lookup->event->db, &lookup->event->node); } if (lookup->event->db != NULL) dns_db_detach(&lookup->event->db); result = view_find(lookup, fname); if (result == ISC_R_NOTFOUND) { /* * We don't know anything about the name. * Launch a fetch. */ if (lookup->event->node != NULL) { INSIST(lookup->event->db != NULL); dns_db_detachnode(lookup->event->db, &lookup->event->node); } if (lookup->event->db != NULL) dns_db_detach(&lookup->event->db); result = start_fetch(lookup); if (result == ISC_R_SUCCESS) send_event = ISC_FALSE; goto done; } } else if (event != NULL) { result = event->result; fname = dns_fixedname_name(&event->foundname); dns_resolver_destroyfetch(&lookup->fetch); INSIST(event->rdataset == &lookup->rdataset); INSIST(event->sigrdataset == &lookup->sigrdataset); } else fname = NULL; /* Silence compiler warning. */ /* * If we've been canceled, forget about the result. */ if (lookup->canceled) result = ISC_R_CANCELED; switch (result) { case ISC_R_SUCCESS: result = build_event(lookup); if (event == NULL) break; if (event->db != NULL) dns_db_attach(event->db, &lookup->event->db); if (event->node != NULL) dns_db_attachnode(lookup->event->db, event->node, &lookup->event->node); break; case DNS_R_CNAME: /* * Copy the CNAME's target into the lookup's * query name and start over. */ result = dns_rdataset_first(&lookup->rdataset); if (result != ISC_R_SUCCESS) break; dns_rdataset_current(&lookup->rdataset, &rdata); result = dns_rdata_tostruct(&rdata, &cname, NULL); dns_rdata_reset(&rdata); if (result != ISC_R_SUCCESS) break; result = dns_name_copy(&cname.cname, name, NULL); dns_rdata_freestruct(&cname); if (result == ISC_R_SUCCESS) { want_restart = ISC_TRUE; send_event = ISC_FALSE; } break; case DNS_R_DNAME: namereln = dns_name_fullcompare(name, fname, &order, &nlabels); INSIST(namereln == dns_namereln_subdomain); /* * Get the target name of the DNAME. */ result = dns_rdataset_first(&lookup->rdataset); if (result != ISC_R_SUCCESS) break; dns_rdataset_current(&lookup->rdataset, &rdata); result = dns_rdata_tostruct(&rdata, &dname, NULL); dns_rdata_reset(&rdata); if (result != ISC_R_SUCCESS) break; /* * Construct the new query name and start over. */ dns_fixedname_init(&fixed); prefix = dns_fixedname_name(&fixed); dns_name_split(name, nlabels, prefix, NULL); result = dns_name_concatenate(prefix, &dname.dname, name, NULL); dns_rdata_freestruct(&dname); if (result == ISC_R_SUCCESS) { want_restart = ISC_TRUE; send_event = ISC_FALSE; } break; default: send_event = ISC_TRUE; } if (dns_rdataset_isassociated(&lookup->rdataset)) dns_rdataset_disassociate(&lookup->rdataset); if (dns_rdataset_isassociated(&lookup->sigrdataset)) dns_rdataset_disassociate(&lookup->sigrdataset); done: if (event != NULL) { if (event->node != NULL) dns_db_detachnode(event->db, &event->node); if (event->db != NULL) dns_db_detach(&event->db); isc_event_free(ISC_EVENT_PTR(&event)); } /* * Limit the number of restarts. */ if (want_restart && lookup->restarts == MAX_RESTARTS) { want_restart = ISC_FALSE; result = ISC_R_QUOTA; send_event = ISC_TRUE; } } while (want_restart); if (send_event) { lookup->event->result = result; lookup->event->ev_sender = lookup; isc_task_sendanddetach(&lookup->task, (isc_event_t **)(void *)&lookup->event); dns_view_detach(&lookup->view); } UNLOCK(&lookup->lock); }
ATF_TC_BODY(csync, tc) { struct { const char *data; isc_boolean_t ok; } text_data[] = { { "", ISC_FALSE }, { "0", ISC_FALSE }, { "0 0", ISC_TRUE }, { "0 0 A", ISC_TRUE }, { "0 0 NS", ISC_TRUE }, { "0 0 AAAA", ISC_TRUE }, { "0 0 A AAAA", ISC_TRUE }, { "0 0 A NS AAAA", ISC_TRUE }, { "0 0 A NS AAAA BOGUS", ISC_FALSE }, { NULL, ISC_FALSE }, }; struct { unsigned char data[64]; size_t len; isc_boolean_t ok; } wire_data[] = { /* short */ { { 0x00 }, 0, ISC_FALSE }, /* short */ { { 0x00 }, 1, ISC_FALSE }, /* short */ { { 0x00, 0x00 }, 2, ISC_FALSE }, /* short */ { { 0x00, 0x00, 0x00 }, 3, ISC_FALSE }, /* short */ { { 0x00, 0x00, 0x00, 0x00 }, 4, ISC_FALSE }, /* short */ { { 0x00, 0x00, 0x00, 0x00, 0x00 }, 5, ISC_FALSE }, /* serial + flags only */ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 6, ISC_TRUE }, /* bad type map */ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 7, ISC_FALSE }, /* bad type map */ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 8, ISC_FALSE }, /* good type map */ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02 }, 9, ISC_TRUE } }; unsigned char buf1[1024]; unsigned char buf2[1024]; isc_buffer_t source, target1, target2; isc_result_t result; size_t i; dns_rdataclass_t rdclass = dns_rdataclass_in; dns_rdatatype_t type = dns_rdatatype_csync; isc_lex_t *lex = NULL; dns_rdatacallbacks_t callbacks; dns_rdata_csync_t csync; dns_decompress_t dctx; UNUSED(tc); result = dns_test_begin(NULL, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); result = isc_lex_create(mctx, 64, &lex); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); dns_rdatacallbacks_init(&callbacks); callbacks.error = error_callback; callbacks.warn = warn_callback; for (i = 0; text_data[i].data != NULL; i++) { size_t length = strlen(text_data[i].data); isc_buffer_constinit(&source, text_data[i].data, length); isc_buffer_add(&source, length); result = isc_lex_openbuffer(lex, &source); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); isc_buffer_init(&target1, buf1, sizeof(buf1)); result = dns_rdata_fromtext(NULL, rdclass, type, lex, dns_rootname, 0, NULL, &target1, &callbacks); if (text_data[i].ok) ATF_CHECK_EQ(result, ISC_R_SUCCESS); else ATF_CHECK(result != ISC_R_SUCCESS); } isc_lex_destroy(&lex); for (i = 0; i < sizeof(wire_data)/sizeof(wire_data[0]); i++) { dns_rdata_t rdata = DNS_RDATA_INIT; isc_buffer_init(&source, wire_data[i].data, wire_data[i].len); isc_buffer_add(&source, wire_data[i].len); isc_buffer_setactive(&source, wire_data[i].len); isc_buffer_init(&target1, buf1, sizeof(buf1)); dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY); result = dns_rdata_fromwire(&rdata, rdclass, type, &source, &dctx, 0, &target1); dns_decompress_invalidate(&dctx); if (wire_data[i].ok) ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); else ATF_REQUIRE(result != ISC_R_SUCCESS); if (result != ISC_R_SUCCESS) continue; result = dns_rdata_tostruct(&rdata, &csync, NULL); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); isc_buffer_init(&target2, buf2, sizeof(buf2)); dns_rdata_reset(&rdata); result = dns_rdata_fromstruct(&rdata, rdclass, type, &csync, &target2); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); ATF_REQUIRE_EQ(isc_buffer_usedlength(&target2), wire_data[i].len); ATF_REQUIRE_EQ(memcmp(buf2, wire_data[i].data, wire_data[i].len), 0); } }
/*% * Return ISC_R_SUCCESS if we can determine that the name doesn't exist * or we can determine whether there is data or not at the name. * If the name does not exist return the wildcard name. * * Return ISC_R_IGNORE when the NSEC is not the appropriate one. */ isc_result_t dns_nsec_noexistnodata(dns_rdatatype_t type, dns_name_t *name, dns_name_t *nsecname, dns_rdataset_t *nsecset, isc_boolean_t *exists, isc_boolean_t *data, dns_name_t *wild, dns_nseclog_t logit, void *arg) { int order; dns_rdata_t rdata = DNS_RDATA_INIT; isc_result_t result; dns_namereln_t relation; unsigned int olabels, nlabels, labels; dns_rdata_nsec_t nsec; isc_boolean_t atparent; isc_boolean_t ns; isc_boolean_t soa; REQUIRE(exists != NULL); REQUIRE(data != NULL); REQUIRE(nsecset != NULL && nsecset->type == dns_rdatatype_nsec); result = dns_rdataset_first(nsecset); if (result != ISC_R_SUCCESS) { (*logit)(arg, ISC_LOG_DEBUG(3), "failure processing NSEC set"); return (result); } dns_rdataset_current(nsecset, &rdata); (*logit)(arg, ISC_LOG_DEBUG(3), "looking for relevant NSEC"); relation = dns_name_fullcompare(name, nsecname, &order, &olabels); if (order < 0) { /* * The name is not within the NSEC range. */ (*logit)(arg, ISC_LOG_DEBUG(3), "NSEC does not cover name, before NSEC"); return (ISC_R_IGNORE); } if (order == 0) { /* * The names are the same. If we are validating "." * then atparent should not be set as there is no parent. */ atparent = (olabels != 1) && dns_rdatatype_atparent(type); ns = dns_nsec_typepresent(&rdata, dns_rdatatype_ns); soa = dns_nsec_typepresent(&rdata, dns_rdatatype_soa); if (ns && !soa) { if (!atparent) { /* * This NSEC record is from somewhere higher in * the DNS, and at the parent of a delegation. * It can not be legitimately used here. */ (*logit)(arg, ISC_LOG_DEBUG(3), "ignoring parent nsec"); return (ISC_R_IGNORE); } } else if (atparent && ns && soa) { /* * This NSEC record is from the child. * It can not be legitimately used here. */ (*logit)(arg, ISC_LOG_DEBUG(3), "ignoring child nsec"); return (ISC_R_IGNORE); } if (type == dns_rdatatype_cname || type == dns_rdatatype_nxt || type == dns_rdatatype_nsec || type == dns_rdatatype_key || !dns_nsec_typepresent(&rdata, dns_rdatatype_cname)) { *exists = ISC_TRUE; *data = dns_nsec_typepresent(&rdata, type); (*logit)(arg, ISC_LOG_DEBUG(3), "nsec proves name exists (owner) data=%d", *data); return (ISC_R_SUCCESS); } (*logit)(arg, ISC_LOG_DEBUG(3), "NSEC proves CNAME exists"); return (ISC_R_IGNORE); } if (relation == dns_namereln_subdomain && dns_nsec_typepresent(&rdata, dns_rdatatype_ns) && !dns_nsec_typepresent(&rdata, dns_rdatatype_soa)) { /* * This NSEC record is from somewhere higher in * the DNS, and at the parent of a delegation. * It can not be legitimately used here. */ (*logit)(arg, ISC_LOG_DEBUG(3), "ignoring parent nsec"); return (ISC_R_IGNORE); } result = dns_rdata_tostruct(&rdata, &nsec, NULL); if (result != ISC_R_SUCCESS) return (result); relation = dns_name_fullcompare(&nsec.next, name, &order, &nlabels); if (order == 0) { dns_rdata_freestruct(&nsec); (*logit)(arg, ISC_LOG_DEBUG(3), "ignoring nsec matches next name"); return (ISC_R_IGNORE); } if (order < 0 && !dns_name_issubdomain(nsecname, &nsec.next)) { /* * The name is not within the NSEC range. */ dns_rdata_freestruct(&nsec); (*logit)(arg, ISC_LOG_DEBUG(3), "ignoring nsec because name is past end of range"); return (ISC_R_IGNORE); } if (order > 0 && relation == dns_namereln_subdomain) { (*logit)(arg, ISC_LOG_DEBUG(3), "nsec proves name exist (empty)"); dns_rdata_freestruct(&nsec); *exists = ISC_TRUE; *data = ISC_FALSE; return (ISC_R_SUCCESS); } if (wild != NULL) { dns_name_t common; dns_name_init(&common, NULL); if (olabels > nlabels) { labels = dns_name_countlabels(nsecname); dns_name_getlabelsequence(nsecname, labels - olabels, olabels, &common); } else { labels = dns_name_countlabels(&nsec.next); dns_name_getlabelsequence(&nsec.next, labels - nlabels, nlabels, &common); } result = dns_name_concatenate(dns_wildcardname, &common, wild, NULL); if (result != ISC_R_SUCCESS) { dns_rdata_freestruct(&nsec); (*logit)(arg, ISC_LOG_DEBUG(3), "failure generating wildcard name"); return (result); } } dns_rdata_freestruct(&nsec); (*logit)(arg, ISC_LOG_DEBUG(3), "nsec range ok"); *exists = ISC_FALSE; return (ISC_R_SUCCESS); }