static isc_boolean_t checksrv(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) { #ifdef USE_GETADDRINFO struct addrinfo hints, *ai, *cur; char namebuf[DNS_NAME_FORMATSIZE + 1]; char ownerbuf[DNS_NAME_FORMATSIZE]; int result; int level = ISC_LOG_ERROR; isc_boolean_t answer = ISC_TRUE; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_CANONNAME; hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; dns_name_format(name, namebuf, sizeof(namebuf) - 1); /* * Turn off search. */ if (dns_name_countlabels(name) > 1U) strcat(namebuf, "."); dns_name_format(owner, ownerbuf, sizeof(ownerbuf)); result = getaddrinfo(namebuf, NULL, &hints, &ai); dns_name_format(name, namebuf, sizeof(namebuf) - 1); switch (result) { case 0: /* * Work around broken getaddrinfo() implementations that * fail to set ai_canonname on first entry. */ cur = ai; while (cur != NULL && cur->ai_canonname == NULL && cur->ai_next != NULL) cur = cur->ai_next; if (cur != NULL && cur->ai_canonname != NULL && strcasecmp(cur->ai_canonname, namebuf) != 0) { if ((zone_options & DNS_ZONEOPT_WARNSRVCNAME) != 0) level = ISC_LOG_WARNING; if ((zone_options & DNS_ZONEOPT_IGNORESRVCNAME) == 0) { if (!logged(namebuf, ERR_IS_SRVCNAME)) { dns_zone_log(zone, level, "%s/SRV '%s'" " (out of zone) is a " "CNAME '%s' (illegal)", ownerbuf, namebuf, cur->ai_canonname); add(namebuf, ERR_IS_SRVCNAME); } if (level == ISC_LOG_ERROR) answer = ISC_FALSE; } } freeaddrinfo(ai); return (answer); case EAI_NONAME: #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) case EAI_NODATA: #endif if (!logged(namebuf, ERR_NO_ADDRESSES)) { dns_zone_log(zone, ISC_LOG_ERROR, "%s/SRV '%s' (out of zone) " "has no addresses records (A or AAAA)", ownerbuf, namebuf); add(namebuf, ERR_NO_ADDRESSES); } /* XXX950 make fatal for 9.5.0. */ return (ISC_TRUE); default: if (!logged(namebuf, ERR_LOOKUP_FAILURE)) { dns_zone_log(zone, ISC_LOG_WARNING, "getaddrinfo(%s) failed: %s", namebuf, gai_strerror(result)); add(namebuf, ERR_LOOKUP_FAILURE); } return (ISC_TRUE); } #else return (ISC_TRUE); #endif }
isc_result_t dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm, dst_key_t *dstkey, isc_boolean_t generated, dns_name_t *creator, isc_stdtime_t inception, isc_stdtime_t expire, isc_mem_t *mctx, dns_tsig_keyring_t *ring, dns_tsigkey_t **key) { dns_tsigkey_t *tkey; isc_result_t ret; unsigned int refs = 0; REQUIRE(key == NULL || *key == NULL); REQUIRE(name != NULL); REQUIRE(algorithm != NULL); REQUIRE(mctx != NULL); REQUIRE(key != NULL || ring != NULL); tkey = (dns_tsigkey_t *) isc_mem_get(mctx, sizeof(dns_tsigkey_t)); if (tkey == NULL) return (ISC_R_NOMEMORY); dns_name_init(&tkey->name, NULL); ret = dns_name_dup(name, mctx, &tkey->name); if (ret != ISC_R_SUCCESS) goto cleanup_key; (void)dns_name_downcase(&tkey->name, &tkey->name, NULL); if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) { tkey->algorithm = DNS_TSIG_HMACMD5_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACMD5) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA1_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA1) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA224_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA224_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA224) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA256_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA256_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA256) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA384_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA384_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA384) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA512_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA512_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA512) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME)) { tkey->algorithm = DNS_TSIG_GSSAPI_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) { tkey->algorithm = DNS_TSIG_GSSAPIMS_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) { ret = DNS_R_BADALG; goto cleanup_name; } } else { if (dstkey != NULL) { ret = DNS_R_BADALG; goto cleanup_name; } tkey->algorithm = isc_mem_get(mctx, sizeof(dns_name_t)); if (tkey->algorithm == NULL) { ret = ISC_R_NOMEMORY; goto cleanup_name; } dns_name_init(tkey->algorithm, NULL); ret = dns_name_dup(algorithm, mctx, tkey->algorithm); if (ret != ISC_R_SUCCESS) goto cleanup_algorithm; (void)dns_name_downcase(tkey->algorithm, tkey->algorithm, NULL); } if (creator != NULL) { tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t)); if (tkey->creator == NULL) { ret = ISC_R_NOMEMORY; goto cleanup_algorithm; } dns_name_init(tkey->creator, NULL); ret = dns_name_dup(creator, mctx, tkey->creator); if (ret != ISC_R_SUCCESS) { isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t)); goto cleanup_algorithm; } } else tkey->creator = NULL; tkey->key = NULL; if (dstkey != NULL) dst_key_attach(dstkey, &tkey->key); tkey->ring = ring; if (key != NULL) refs = 1; if (ring != NULL) refs++; ret = isc_refcount_init(&tkey->refs, refs); if (ret != ISC_R_SUCCESS) goto cleanup_creator; tkey->generated = generated; tkey->inception = inception; tkey->expire = expire; tkey->mctx = NULL; isc_mem_attach(mctx, &tkey->mctx); ISC_LINK_INIT(tkey, link); tkey->magic = TSIG_MAGIC; if (ring != NULL) { ret = keyring_add(ring, name, tkey); if (ret != ISC_R_SUCCESS) goto cleanup_refs; } /* * Ignore this if it's a GSS key, since the key size is meaningless. */ if (dstkey != NULL && dst_key_size(dstkey) < 64 && !dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME) && !dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) { char namestr[DNS_NAME_FORMATSIZE]; dns_name_format(name, namestr, sizeof(namestr)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG, ISC_LOG_INFO, "the key '%s' is too short to be secure", namestr); } if (key != NULL) *key = tkey; return (ISC_R_SUCCESS); cleanup_refs: tkey->magic = 0; while (refs-- > 0) isc_refcount_decrement(&tkey->refs, NULL); isc_refcount_destroy(&tkey->refs); cleanup_creator: if (tkey->key != NULL) dst_key_free(&tkey->key); if (tkey->creator != NULL) { dns_name_free(tkey->creator, mctx); isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t)); } cleanup_algorithm: if (algname_is_allocated(tkey->algorithm)) { if (dns_name_dynamic(tkey->algorithm)) dns_name_free(tkey->algorithm, mctx); isc_mem_put(mctx, tkey->algorithm, sizeof(dns_name_t)); } cleanup_name: dns_name_free(&tkey->name, mctx); cleanup_key: isc_mem_put(mctx, tkey, sizeof(dns_tsigkey_t)); return (ret); }
static inline isc_result_t totext_dnskey(ARGS_TOTEXT) { isc_region_t sr; char buf[sizeof("64000")]; unsigned int flags; unsigned char algorithm; char algbuf[DNS_NAME_FORMATSIZE]; const char *keyinfo; REQUIRE(rdata->type == 48); REQUIRE(rdata->length != 0); dns_rdata_toregion(rdata, &sr); /* flags */ flags = uint16_fromregion(&sr); isc_region_consume(&sr, 2); sprintf(buf, "%u", flags); RETERR(str_totext(buf, target)); RETERR(str_totext(" ", target)); if ((flags & DNS_KEYFLAG_KSK) != 0) { if (flags & DNS_KEYFLAG_REVOKE) keyinfo = "revoked KSK"; else keyinfo = "KSK"; } else keyinfo = "ZSK"; /* protocol */ sprintf(buf, "%u", sr.base[0]); isc_region_consume(&sr, 1); RETERR(str_totext(buf, target)); RETERR(str_totext(" ", target)); /* algorithm */ algorithm = sr.base[0]; sprintf(buf, "%u", algorithm); isc_region_consume(&sr, 1); RETERR(str_totext(buf, target)); /* No Key? */ if ((flags & 0xc000) == 0xc000) return (ISC_R_SUCCESS); if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0 && algorithm == DNS_KEYALG_PRIVATEDNS) { dns_name_t name; dns_name_init(&name, NULL); dns_name_fromregion(&name, &sr); dns_name_format(&name, algbuf, sizeof(algbuf)); } else { dns_secalg_format((dns_secalg_t) algorithm, algbuf, sizeof(algbuf)); } /* key */ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) RETERR(str_totext(" (", target)); RETERR(str_totext(tctx->linebreak, target)); if (tctx->width == 0) /* No splitting */ RETERR(isc_base64_totext(&sr, 0, "", target)); else RETERR(isc_base64_totext(&sr, tctx->width - 2, tctx->linebreak, target)); if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0) RETERR(str_totext(tctx->linebreak, target)); else if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) RETERR(str_totext(" ", target)); if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) RETERR(str_totext(")", target)); if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0) { isc_region_t tmpr; RETERR(str_totext(" ; ", target)); RETERR(str_totext(keyinfo, target)); RETERR(str_totext("; alg = ", target)); RETERR(str_totext(algbuf, target)); RETERR(str_totext("; key id = ", target)); dns_rdata_toregion(rdata, &tmpr); sprintf(buf, "%u", dst_region_computeid(&tmpr, algorithm)); RETERR(str_totext(buf, target)); } return (ISC_R_SUCCESS); }
static isc_boolean_t checkns(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner, dns_rdataset_t *a, dns_rdataset_t *aaaa) { #ifdef USE_GETADDRINFO dns_rdataset_t *rdataset; dns_rdata_t rdata = DNS_RDATA_INIT; struct addrinfo hints, *ai, *cur; char namebuf[DNS_NAME_FORMATSIZE + 1]; char ownerbuf[DNS_NAME_FORMATSIZE]; char addrbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")]; isc_boolean_t answer = ISC_TRUE; isc_boolean_t match; const char *type; void *ptr = NULL; int result; REQUIRE(a == NULL || !dns_rdataset_isassociated(a) || a->type == dns_rdatatype_a); REQUIRE(aaaa == NULL || !dns_rdataset_isassociated(aaaa) || aaaa->type == dns_rdatatype_aaaa); memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_CANONNAME; hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; dns_name_format(name, namebuf, sizeof(namebuf) - 1); /* * Turn off search. */ if (dns_name_countlabels(name) > 1U) strcat(namebuf, "."); dns_name_format(owner, ownerbuf, sizeof(ownerbuf)); result = getaddrinfo(namebuf, NULL, &hints, &ai); dns_name_format(name, namebuf, sizeof(namebuf) - 1); switch (result) { case 0: /* * Work around broken getaddrinfo() implementations that * fail to set ai_canonname on first entry. */ cur = ai; while (cur != NULL && cur->ai_canonname == NULL && cur->ai_next != NULL) cur = cur->ai_next; if (cur != NULL && cur->ai_canonname != NULL && strcasecmp(cur->ai_canonname, namebuf) != 0 && !logged(namebuf, ERR_IS_CNAME)) { dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' (out of zone) " "is a CNAME '%s' (illegal)", ownerbuf, namebuf, cur->ai_canonname); /* XXX950 make fatal for 9.5.0 */ /* answer = ISC_FALSE; */ add(namebuf, ERR_IS_CNAME); } break; case EAI_NONAME: #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) case EAI_NODATA: #endif if (!logged(namebuf, ERR_NO_ADDRESSES)) { dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' (out of zone) " "has no addresses records (A or AAAA)", ownerbuf, namebuf); add(namebuf, ERR_NO_ADDRESSES); } /* XXX950 make fatal for 9.5.0 */ return (ISC_TRUE); default: if (!logged(namebuf, ERR_LOOKUP_FAILURE)) { dns_zone_log(zone, ISC_LOG_WARNING, "getaddrinfo(%s) failed: %s", namebuf, gai_strerror(result)); add(namebuf, ERR_LOOKUP_FAILURE); } return (ISC_TRUE); } if (a == NULL || aaaa == NULL) return (answer); /* * Check that all glue records really exist. */ if (!dns_rdataset_isassociated(a)) goto checkaaaa; result = dns_rdataset_first(a); while (result == ISC_R_SUCCESS) { dns_rdataset_current(a, &rdata); match = ISC_FALSE; for (cur = ai; cur != NULL; cur = cur->ai_next) { if (cur->ai_family != AF_INET) continue; ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr; if (memcmp(ptr, rdata.data, rdata.length) == 0) { match = ISC_TRUE; break; } } if (!match && !logged(namebuf, ERR_EXTRA_A)) { dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' " "extra GLUE A record (%s)", ownerbuf, namebuf, inet_ntop(AF_INET, rdata.data, addrbuf, sizeof(addrbuf))); add(namebuf, ERR_EXTRA_A); /* XXX950 make fatal for 9.5.0 */ /* answer = ISC_FALSE; */ } dns_rdata_reset(&rdata); result = dns_rdataset_next(a); } checkaaaa: if (!dns_rdataset_isassociated(aaaa)) goto checkmissing; result = dns_rdataset_first(aaaa); while (result == ISC_R_SUCCESS) { dns_rdataset_current(aaaa, &rdata); match = ISC_FALSE; for (cur = ai; cur != NULL; cur = cur->ai_next) { if (cur->ai_family != AF_INET6) continue; ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr; if (memcmp(ptr, rdata.data, rdata.length) == 0) { match = ISC_TRUE; break; } } if (!match && !logged(namebuf, ERR_EXTRA_AAAA)) { dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' " "extra GLUE AAAA record (%s)", ownerbuf, namebuf, inet_ntop(AF_INET6, rdata.data, addrbuf, sizeof(addrbuf))); add(namebuf, ERR_EXTRA_AAAA); /* XXX950 make fatal for 9.5.0. */ /* answer = ISC_FALSE; */ } dns_rdata_reset(&rdata); result = dns_rdataset_next(aaaa); } checkmissing: /* * Check that all addresses appear in the glue. */ if (!logged(namebuf, ERR_MISSING_GLUE)) { isc_boolean_t missing_glue = ISC_FALSE; for (cur = ai; cur != NULL; cur = cur->ai_next) { switch (cur->ai_family) { case AF_INET: rdataset = a; ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr; type = "A"; break; case AF_INET6: rdataset = aaaa; ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr; type = "AAAA"; break; default: continue; } match = ISC_FALSE; if (dns_rdataset_isassociated(rdataset)) result = dns_rdataset_first(rdataset); else result = ISC_R_FAILURE; while (result == ISC_R_SUCCESS && !match) { dns_rdataset_current(rdataset, &rdata); if (memcmp(ptr, rdata.data, rdata.length) == 0) match = ISC_TRUE; dns_rdata_reset(&rdata); result = dns_rdataset_next(rdataset); } if (!match) { dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' " "missing GLUE %s record (%s)", ownerbuf, namebuf, type, inet_ntop(cur->ai_family, ptr, addrbuf, sizeof(addrbuf))); /* XXX950 make fatal for 9.5.0. */ /* answer = ISC_FALSE; */ missing_glue = ISC_TRUE; } } if (missing_glue) add(namebuf, ERR_MISSING_GLUE); } freeaddrinfo(ai); return (answer); #else return (ISC_TRUE); #endif }
isc_boolean_t dst_gssapi_identitymatchesrealmkrb5(dns_name_t *signer, dns_name_t *name, dns_name_t *realm) { #ifdef GSSAPI char sbuf[DNS_NAME_FORMATSIZE]; char nbuf[DNS_NAME_FORMATSIZE]; char rbuf[DNS_NAME_FORMATSIZE]; char *sname; char *rname; isc_buffer_t buffer; isc_result_t result; /* * It is far, far easier to write the names we are looking at into * a string, and do string operations on them. */ isc_buffer_init(&buffer, sbuf, sizeof(sbuf)); result = dns_name_toprincipal(signer, &buffer); RUNTIME_CHECK(result == ISC_R_SUCCESS); isc_buffer_putuint8(&buffer, 0); if (name != NULL) dns_name_format(name, nbuf, sizeof(nbuf)); dns_name_format(realm, rbuf, sizeof(rbuf)); /* * Find the realm portion. This is the part after the @. If it * does not exist, we don't have something we like, so we fail our * compare. */ rname = strchr(sbuf, '@'); if (rname == NULL) return (isc_boolean_false); *rname = '\0'; rname++; /* * Find the host portion of the signer's name. We do this by * searching for the first / character. We then check to make * certain the instance name is "host" * * This will work for * host/[email protected] */ sname = strchr(sbuf, '/'); if (sname == NULL) return (isc_boolean_false); *sname = '\0'; sname++; if (strcmp(sbuf, "host") != 0) return (isc_boolean_false); /* * Now, we do a simple comparison between the name and the realm. */ if (name != NULL) { if ((strcasecmp(sname, nbuf) == 0) && (strcmp(rname, rbuf) == 0)) return (isc_boolean_true); } else { if (strcmp(rname, rbuf) == 0) return (isc_boolean_true); } return (isc_boolean_false); #else UNUSED(signer); UNUSED(name); UNUSED(realm); return (isc_boolean_false); #endif }
isc_boolean_t dst_gssapi_identitymatchesrealmms(dns_name_t *signer, dns_name_t *name, dns_name_t *realm) { #ifdef GSSAPI char sbuf[DNS_NAME_FORMATSIZE]; char nbuf[DNS_NAME_FORMATSIZE]; char rbuf[DNS_NAME_FORMATSIZE]; char *sname; char *nname; char *rname; isc_buffer_t buffer; isc_result_t result; /* * It is far, far easier to write the names we are looking at into * a string, and do string operations on them. */ isc_buffer_init(&buffer, sbuf, sizeof(sbuf)); result = dns_name_toprincipal(signer, &buffer); RUNTIME_CHECK(result == ISC_R_SUCCESS); isc_buffer_putuint8(&buffer, 0); if (name != NULL) dns_name_format(name, nbuf, sizeof(nbuf)); dns_name_format(realm, rbuf, sizeof(rbuf)); /* * Find the realm portion. This is the part after the @. If it * does not exist, we don't have something we like, so we fail our * compare. */ rname = strchr(sbuf, '@'); if (rname == NULL) return (isc_boolean_false); sname = strchr(sbuf, '$'); if (sname == NULL) return (isc_boolean_false); /* * Verify that the $ and @ follow one another. */ if (rname - sname != 1) return (isc_boolean_false); /* * Find the host portion of the signer's name. Zero out the $ so * it terminates the signer's name, and skip past the @ for * the realm. * * All service principals in Microsoft format seem to be in * [email protected] * format. */ rname++; *sname = '\0'; sname = sbuf; /* * Find the first . in the target name, and make it the end of * the string. The rest of the name has to match the realm. */ if (name != NULL) { nname = strchr(nbuf, '.'); if (nname == NULL) return (isc_boolean_false); *nname++ = '\0'; } /* * Now, we do a simple comparison between the name and the realm. */ if (name != NULL) { if ((strcasecmp(sname, nbuf) == 0) && (strcmp(rname, rbuf) == 0) && (strcasecmp(nname, rbuf) == 0)) return (isc_boolean_true); } else { if (strcmp(rname, rbuf) == 0) return (isc_boolean_true); } return (isc_boolean_false); #else UNUSED(signer); UNUSED(name); UNUSED(realm); return (isc_boolean_false); #endif }
void ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) { isc_result_t result; dns_name_t *question_name; dns_rdataset_t *question_rdataset; dns_zone_t *zone = NULL; dns_db_t *db = NULL; dns_dbversion_t *ver = NULL; dns_rdataclass_t question_class; rrstream_t *soa_stream = NULL; rrstream_t *data_stream = NULL; rrstream_t *stream = NULL; dns_difftuple_t *current_soa_tuple = NULL; dns_name_t *soa_name; dns_rdataset_t *soa_rdataset; dns_rdata_t soa_rdata = DNS_RDATA_INIT; isc_boolean_t have_soa = ISC_FALSE; const char *mnemonic = NULL; isc_mem_t *mctx = client->mctx; dns_message_t *request = client->message; xfrout_ctx_t *xfr = NULL; isc_quota_t *quota = NULL; dns_transfer_format_t format = client->view->transfer_format; isc_netaddr_t na; dns_peer_t *peer = NULL; isc_buffer_t *tsigbuf = NULL; char *journalfile; char msg[NS_CLIENT_ACLMSGSIZE("zone transfer")]; char keyname[DNS_NAME_FORMATSIZE]; isc_boolean_t is_poll = ISC_FALSE; isc_boolean_t is_dlz = ISC_FALSE; switch (reqtype) { case dns_rdatatype_axfr: mnemonic = "AXFR"; break; case dns_rdatatype_ixfr: mnemonic = "IXFR"; break; default: INSIST(0); break; } ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT, ISC_LOG_DEBUG(6), "%s request", mnemonic); /* * Apply quota. */ result = isc_quota_attach(&ns_g_server->xfroutquota, "a); if (result != ISC_R_SUCCESS) { isc_log_write(XFROUT_COMMON_LOGARGS, ISC_LOG_WARNING, "%s request denied: %s", mnemonic, isc_result_totext(result)); goto failure; } /* * Interpret the question section. */ result = dns_message_firstname(request, DNS_SECTION_QUESTION); INSIST(result == ISC_R_SUCCESS); /* * The question section must contain exactly one question, and * it must be for AXFR/IXFR as appropriate. */ question_name = NULL; dns_message_currentname(request, DNS_SECTION_QUESTION, &question_name); question_rdataset = ISC_LIST_HEAD(question_name->list); question_class = question_rdataset->rdclass; INSIST(question_rdataset->type == reqtype); if (ISC_LIST_NEXT(question_rdataset, link) != NULL) FAILC(DNS_R_FORMERR, "multiple questions"); result = dns_message_nextname(request, DNS_SECTION_QUESTION); if (result != ISC_R_NOMORE) FAILC(DNS_R_FORMERR, "multiple questions"); result = dns_zt_find(client->view->zonetable, question_name, 0, NULL, &zone); if (result != ISC_R_SUCCESS) { /* * Normal zone table does not have a match. * Try the DLZ database */ if (client->view->dlzdatabase != NULL) { result = dns_dlzallowzonexfr(client->view, question_name, &client->peeraddr, &db); if (result == ISC_R_NOPERM) { char _buf1[DNS_NAME_FORMATSIZE]; char _buf2[DNS_RDATACLASS_FORMATSIZE]; result = DNS_R_REFUSED; dns_name_format(question_name, _buf1, sizeof(_buf1)); dns_rdataclass_format(question_class, _buf2, sizeof(_buf2)); ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_XFER_OUT, ISC_LOG_ERROR, "zone transfer '%s/%s' denied", _buf1, _buf2); goto failure; } if (result != ISC_R_SUCCESS) FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", question_name, question_class); is_dlz = ISC_TRUE; /* * DLZ only support full zone transfer, not incremental */ if (reqtype != dns_rdatatype_axfr) { mnemonic = "AXFR-style IXFR"; reqtype = dns_rdatatype_axfr; } } else { /* * not DLZ and not in normal zone table, we are * not authoritative */ FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", question_name, question_class); } } else { /* zone table has a match */ switch(dns_zone_gettype(zone)) { case dns_zone_master: case dns_zone_slave: case dns_zone_dlz: break; /* Master and slave zones are OK for transfer. */ default: FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", question_name, question_class); } CHECK(dns_zone_getdb(zone, &db)); dns_db_currentversion(db, &ver); } xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6), "%s question section OK", mnemonic); /* * Check the authority section. Look for a SOA record with * the same name and class as the question. */ for (result = dns_message_firstname(request, DNS_SECTION_AUTHORITY); result == ISC_R_SUCCESS; result = dns_message_nextname(request, DNS_SECTION_AUTHORITY)) { soa_name = NULL; dns_message_currentname(request, DNS_SECTION_AUTHORITY, &soa_name); /* * Ignore data whose owner name is not the zone apex. */ if (! dns_name_equal(soa_name, question_name)) continue; for (soa_rdataset = ISC_LIST_HEAD(soa_name->list); soa_rdataset != NULL; soa_rdataset = ISC_LIST_NEXT(soa_rdataset, link)) { /* * Ignore non-SOA data. */ if (soa_rdataset->type != dns_rdatatype_soa) continue; if (soa_rdataset->rdclass != question_class) continue; CHECK(dns_rdataset_first(soa_rdataset)); dns_rdataset_current(soa_rdataset, &soa_rdata); result = dns_rdataset_next(soa_rdataset); if (result == ISC_R_SUCCESS) FAILC(DNS_R_FORMERR, "IXFR authority section " "has multiple SOAs"); have_soa = ISC_TRUE; goto got_soa; } } got_soa: if (result != ISC_R_NOMORE) CHECK(result); xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6), "%s authority section OK", mnemonic); /* * If not a DLZ zone, decide whether to allow this transfer. */ if (!is_dlz) { ns_client_aclmsg("zone transfer", question_name, reqtype, client->view->rdclass, msg, sizeof(msg)); CHECK(ns_client_checkacl(client, NULL, msg, dns_zone_getxfracl(zone), ISC_TRUE, ISC_LOG_ERROR)); } /* * AXFR over UDP is not possible. */ if (reqtype == dns_rdatatype_axfr && (client->attributes & NS_CLIENTATTR_TCP) == 0) FAILC(DNS_R_FORMERR, "attempted AXFR over UDP"); /* * Look up the requesting server in the peer table. */ isc_netaddr_fromsockaddr(&na, &client->peeraddr); (void)dns_peerlist_peerbyaddr(client->view->peers, &na, &peer); /* * Decide on the transfer format (one-answer or many-answers). */ if (peer != NULL) (void)dns_peer_gettransferformat(peer, &format); /* * Get a dynamically allocated copy of the current SOA. */ if (is_dlz) dns_db_currentversion(db, &ver); CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS, ¤t_soa_tuple)); if (reqtype == dns_rdatatype_ixfr) { isc_uint32_t begin_serial, current_serial; isc_boolean_t provide_ixfr; /* * Outgoing IXFR may have been disabled for this peer * or globally. */ provide_ixfr = client->view->provideixfr; if (peer != NULL) (void) dns_peer_getprovideixfr(peer, &provide_ixfr); if (provide_ixfr == ISC_FALSE) goto axfr_fallback; if (! have_soa) FAILC(DNS_R_FORMERR, "IXFR request missing SOA"); begin_serial = dns_soa_getserial(&soa_rdata); current_serial = dns_soa_getserial(¤t_soa_tuple->rdata); /* * RFC1995 says "If an IXFR query with the same or * newer version number than that of the server * is received, it is replied to with a single SOA * record of the server's current version, just as * in AXFR". The claim about AXFR is incorrect, * but other than that, we do as the RFC says. * * Sending a single SOA record is also how we refuse * IXFR over UDP (currently, we always do). */ if (DNS_SERIAL_GE(begin_serial, current_serial) || (client->attributes & NS_CLIENTATTR_TCP) == 0) { CHECK(soa_rrstream_create(mctx, db, ver, &stream)); is_poll = ISC_TRUE; goto have_stream; } journalfile = dns_zone_getjournal(zone); if (journalfile != NULL) result = ixfr_rrstream_create(mctx, journalfile, begin_serial, current_serial, &data_stream); else result = ISC_R_NOTFOUND; if (result == ISC_R_NOTFOUND || result == ISC_R_RANGE) { xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(4), "IXFR version not in journal, " "falling back to AXFR"); mnemonic = "AXFR-style IXFR"; goto axfr_fallback; } CHECK(result); } else { axfr_fallback: CHECK(axfr_rrstream_create(mctx, db, ver, &data_stream)); } /* * Bracket the data stream with SOAs. */ CHECK(soa_rrstream_create(mctx, db, ver, &soa_stream)); CHECK(compound_rrstream_create(mctx, &soa_stream, &data_stream, &stream)); soa_stream = NULL; data_stream = NULL; have_stream: CHECK(dns_message_getquerytsig(request, mctx, &tsigbuf)); /* * Create the xfrout context object. This transfers the ownership * of "stream", "db", "ver", and "quota" to the xfrout context object. */ if (is_dlz) CHECK(xfrout_ctx_create(mctx, client, request->id, question_name, reqtype, question_class, zone, db, ver, quota, stream, dns_message_gettsigkey(request), tsigbuf, 3600, 3600, (format == dns_many_answers) ? ISC_TRUE : ISC_FALSE, &xfr)); else CHECK(xfrout_ctx_create(mctx, client, request->id, question_name, reqtype, question_class, zone, db, ver, quota, stream, dns_message_gettsigkey(request), tsigbuf, dns_zone_getmaxxfrout(zone), dns_zone_getidleout(zone), (format == dns_many_answers) ? ISC_TRUE : ISC_FALSE, &xfr)); xfr->mnemonic = mnemonic; stream = NULL; quota = NULL; CHECK(xfr->stream->methods->first(xfr->stream)); if (xfr->tsigkey != NULL) dns_name_format(&xfr->tsigkey->name, keyname, sizeof(keyname)); else keyname[0] = '\0'; if (is_poll) xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(1), "IXFR poll up to date%s%s", (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname); else xfrout_log1(client, question_name, question_class, ISC_LOG_INFO, "%s started%s%s", mnemonic, (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname); /* * Hand the context over to sendstream(). Set xfr to NULL; * sendstream() is responsible for either passing the * context on to a later event handler or destroying it. */ sendstream(xfr); xfr = NULL; result = ISC_R_SUCCESS; failure: if (result == DNS_R_REFUSED) inc_stats(zone, dns_nsstatscounter_xfrrej); if (quota != NULL) isc_quota_detach("a); if (current_soa_tuple != NULL) dns_difftuple_free(¤t_soa_tuple); if (stream != NULL) stream->methods->destroy(&stream); if (soa_stream != NULL) soa_stream->methods->destroy(&soa_stream); if (data_stream != NULL) data_stream->methods->destroy(&data_stream); if (ver != NULL) dns_db_closeversion(db, &ver, ISC_FALSE); if (db != NULL) dns_db_detach(&db); if (zone != NULL) dns_zone_detach(&zone); /* XXX kludge */ if (xfr != NULL) { xfrout_fail(xfr, result, "setting up zone transfer"); } else if (result != ISC_R_SUCCESS) { ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT, ISC_LOG_DEBUG(3), "zone transfer setup failed"); ns_client_error(client, result); } }
/* * Perform an update-policy rule check against an external application * over a socket. * * This currently only supports local: for unix domain datagram sockets. * * Note that by using a datagram socket and creating a new socket each * time we avoid the need for locking and allow for parallel access to * the authorization server. */ isc_boolean_t dns_ssu_external_match (dns_name_t * identity, dns_name_t * signer, dns_name_t * name, isc_netaddr_t * tcpaddr, dns_rdatatype_t type, const dst_key_t * key, isc_mem_t * mctx) { char b_identity[DNS_NAME_FORMATSIZE]; char b_signer[DNS_NAME_FORMATSIZE]; char b_name[DNS_NAME_FORMATSIZE]; char b_addr[ISC_NETADDR_FORMATSIZE]; char b_type[DNS_RDATATYPE_FORMATSIZE]; char b_key[DST_KEY_FORMATSIZE]; isc_buffer_t *tkey_token = NULL; int fd; const char *sock_path; size_t req_len; isc_region_t token_region; unsigned char *data; isc_buffer_t buf; isc_uint32_t token_len = 0; isc_uint32_t reply; ssize_t ret; /* The identity contains local:/path/to/socket */ dns_name_format (identity, b_identity, sizeof (b_identity)); /* For now only local: is supported */ if (strncmp (b_identity, "local:", 6) != 0) { ssu_e_log (3, "ssu_external: invalid socket path '%s'", b_identity); return (ISC_FALSE); } sock_path = &b_identity[6]; fd = ux_socket_connect (sock_path); if (fd == -1) return (ISC_FALSE); if (key != NULL) { dst_key_format (key, b_key, sizeof (b_key)); tkey_token = dst_key_tkeytoken (key); } else b_key[0] = 0; if (tkey_token != NULL) { isc_buffer_region (tkey_token, &token_region); token_len = token_region.length; } /* Format the request elements */ if (signer != NULL) dns_name_format (signer, b_signer, sizeof (b_signer)); else b_signer[0] = 0; dns_name_format (name, b_name, sizeof (b_name)); if (tcpaddr != NULL) isc_netaddr_format (tcpaddr, b_addr, sizeof (b_addr)); else b_addr[0] = 0; dns_rdatatype_format (type, b_type, sizeof (b_type)); /* Work out how big the request will be */ req_len = sizeof (isc_uint32_t) + /* Format version */ sizeof (isc_uint32_t) + /* Length */ strlen (b_signer) + 1 + /* Signer */ strlen (b_name) + 1 + /* Name */ strlen (b_addr) + 1 + /* Address */ strlen (b_type) + 1 + /* Type */ strlen (b_key) + 1 + /* Key */ sizeof (isc_uint32_t) + /* tkey_token length */ token_len; /* tkey_token */ /* format the buffer */ data = isc_mem_allocate (mctx, req_len); if (data == NULL) { close (fd); return (ISC_FALSE); } isc_buffer_init (&buf, data, req_len); isc_buffer_putuint32 (&buf, SSU_EXTERNAL_VERSION); isc_buffer_putuint32 (&buf, req_len); /* Strings must be null-terminated */ isc_buffer_putstr (&buf, b_signer); isc_buffer_putuint8 (&buf, 0); isc_buffer_putstr (&buf, b_name); isc_buffer_putuint8 (&buf, 0); isc_buffer_putstr (&buf, b_addr); isc_buffer_putuint8 (&buf, 0); isc_buffer_putstr (&buf, b_type); isc_buffer_putuint8 (&buf, 0); isc_buffer_putstr (&buf, b_key); isc_buffer_putuint8 (&buf, 0); isc_buffer_putuint32 (&buf, token_len); if (tkey_token && token_len != 0) isc_buffer_putmem (&buf, token_region.base, token_len); ENSURE (isc_buffer_availablelength (&buf) == 0); /* Send the request */ ret = write (fd, data, req_len); isc_mem_free (mctx, data); if (ret != (ssize_t) req_len) { char strbuf[ISC_STRERRORSIZE]; isc__strerror (errno, strbuf, sizeof (strbuf)); ssu_e_log (3, "ssu_external: unable to send request - %s", strbuf); close (fd); return (ISC_FALSE); } /* Receive the reply */ ret = read (fd, &reply, sizeof (isc_uint32_t)); if (ret != (ssize_t) sizeof (isc_uint32_t)) { char strbuf[ISC_STRERRORSIZE]; isc__strerror (errno, strbuf, sizeof (strbuf)); ssu_e_log (3, "ssu_external: unable to receive reply - %s", strbuf); close (fd); return (ISC_FALSE); } close (fd); reply = ntohl (reply); if (reply == 0) { ssu_e_log (3, "ssu_external: denied external auth for '%s'", b_name); return (ISC_FALSE); } else if (reply == 1) { ssu_e_log (3, "ssu_external: allowed external auth for '%s'", b_name); return (ISC_TRUE); } ssu_e_log (3, "ssu_external: invalid reply 0x%08x", reply); return (ISC_FALSE); }
static isc_result_t detailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, dns_section_t section) { isc_result_t result, loopresult; dns_name_t *name; dns_rdataset_t *rdataset = NULL; dns_rdata_t rdata = DNS_RDATA_INIT; char namebuf[DNS_NAME_FORMATSIZE]; UNUSED(query); debug("detailsection()"); if (headers) { switch (section) { case DNS_SECTION_QUESTION: puts(" QUESTIONS:"); break; case DNS_SECTION_ANSWER: puts(" ANSWERS:"); break; case DNS_SECTION_AUTHORITY: puts(" AUTHORITY RECORDS:"); break; case DNS_SECTION_ADDITIONAL: puts(" ADDITIONAL RECORDS:"); break; } } result = dns_message_firstname(msg, section); if (result == ISC_R_NOMORE) return (ISC_R_SUCCESS); else if (result != ISC_R_SUCCESS) return (result); for (;;) { name = NULL; dns_message_currentname(msg, section, &name); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { if (section == DNS_SECTION_QUESTION) { dns_name_format(name, namebuf, sizeof(namebuf)); printf("\t%s, ", namebuf); dns_rdatatype_format(rdataset->type, namebuf, sizeof(namebuf)); printf("type = %s, ", namebuf); dns_rdataclass_format(rdataset->rdclass, namebuf, sizeof(namebuf)); printf("class = %s\n", namebuf); } loopresult = dns_rdataset_first(rdataset); while (loopresult == ISC_R_SUCCESS) { dns_rdataset_current(rdataset, &rdata); dns_name_format(name, namebuf, sizeof(namebuf)); printf(" -> %s\n", namebuf); switch (rdata.type) { case dns_rdatatype_soa: printsoa(&rdata); break; default: printf("\t"); printrdata(&rdata); } dns_rdata_reset(&rdata); printf("\tttl = %u\n", rdataset->ttl); loopresult = dns_rdataset_next(rdataset); } } result = dns_message_nextname(msg, section); if (result == ISC_R_NOMORE) break; else if (result != ISC_R_SUCCESS) { return (result); } } return (ISC_R_SUCCESS); }
static isc_result_t printdata(dns_rdataset_t *rdataset, dns_name_t *owner, dns_master_style_t *style) { isc_result_t result = ISC_R_SUCCESS; static dns_trust_t trust; static isc_boolean_t first = ISC_TRUE; isc_buffer_t target; isc_region_t r; char *t = NULL; int len = 2048; if (!dns_rdataset_isassociated(rdataset)) { char namebuf[DNS_NAME_FORMATSIZE]; dns_name_format(owner, namebuf, sizeof(namebuf)); delv_log(ISC_LOG_DEBUG(4), "WARN: empty rdataset %s", namebuf); return (ISC_R_SUCCESS); } if (!showdnssec && rdataset->type == dns_rdatatype_rrsig) return (ISC_R_SUCCESS); if (first || rdataset->trust != trust) { if (!first && showtrust && !short_form) putchar('\n'); print_status(rdataset); trust = rdataset->trust; first = ISC_FALSE; } do { t = isc_mem_get(mctx, len); if (t == NULL) return (ISC_R_NOMEMORY); isc_buffer_init(&target, t, len); if (short_form) { dns_rdata_t rdata = DNS_RDATA_INIT; for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(rdataset)) { if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) continue; dns_rdataset_current(rdataset, &rdata); result = dns_rdata_tofmttext(&rdata, dns_rootname, styleflags, 0, splitwidth, " ", &target); if (result != ISC_R_SUCCESS) break; if (isc_buffer_availablelength(&target) < 1) { result = ISC_R_NOSPACE; break; } isc_buffer_putstr(&target, "\n"); dns_rdata_reset(&rdata); } } else { if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) isc_buffer_putstr(&target, "; "); result = dns_master_rdatasettotext(owner, rdataset, style, &target); } if (result == ISC_R_NOSPACE) { isc_mem_put(mctx, t, len); len += 1024; } else if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS; else CHECK(result); } while (result == ISC_R_NOSPACE); isc_buffer_usedregion(&target, &r); printf("%.*s", (int)r.length, (char *)r.base); cleanup: if (t != NULL) isc_mem_put(mctx, t, len); return (ISC_R_SUCCESS); }
static isc_result_t printsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, dns_section_t section) { isc_result_t result, loopresult; dns_name_t *name; dns_rdataset_t *rdataset = NULL; dns_rdata_t rdata = DNS_RDATA_INIT; char namebuf[DNS_NAME_FORMATSIZE]; UNUSED(query); UNUSED(headers); debug("printsection()"); result = dns_message_firstname(msg, section); if (result == ISC_R_NOMORE) return (ISC_R_SUCCESS); else if (result != ISC_R_SUCCESS) return (result); for (;;) { name = NULL; dns_message_currentname(msg, section, &name); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { loopresult = dns_rdataset_first(rdataset); while (loopresult == ISC_R_SUCCESS) { dns_rdataset_current(rdataset, &rdata); switch (rdata.type) { case dns_rdatatype_a: if (section != DNS_SECTION_ANSWER) goto def_short_section; dns_name_format(name, namebuf, sizeof(namebuf)); printf("Name:\t%s\n", namebuf); printa(&rdata); break; case dns_rdatatype_soa: dns_name_format(name, namebuf, sizeof(namebuf)); printf("%s\n", namebuf); printsoa(&rdata); break; default: def_short_section: dns_name_format(name, namebuf, sizeof(namebuf)); printf("%s\t", namebuf); printrdata(&rdata); break; } dns_rdata_reset(&rdata); loopresult = dns_rdataset_next(rdataset); } } result = dns_message_nextname(msg, section); if (result == ISC_R_NOMORE) break; else if (result != ISC_R_SUCCESS) { return (result); } } return (ISC_R_SUCCESS); }
int main(int argc, char **argv) { char *algname = NULL, *nametype = NULL, *type = NULL; char *classname = NULL; char *endp; dst_key_t *key = NULL, *oldkey; dns_fixedname_t fname; dns_name_t *name; isc_uint16_t flags = 0, ksk = 0; dns_secalg_t alg; isc_boolean_t null_key = ISC_FALSE; isc_mem_t *mctx = NULL; int ch; int protocol = -1, signatory = 0; isc_result_t ret; isc_textregion_t r; char filename[255]; isc_buffer_t buf; isc_log_t *log = NULL; isc_entropy_t *ectx = NULL; dns_rdataclass_t rdclass; int options = DST_TYPE_PRIVATE | DST_TYPE_PUBLIC; char *label = NULL; if (argc == 1) usage(); RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); dns_result_register(); isc_commandline_errprint = ISC_FALSE; while ((ch = isc_commandline_parse(argc, argv, "a:c:f:kl:n:p:t:v:h")) != -1) { switch (ch) { case 'a': algname = isc_commandline_argument; break; case 'c': classname = isc_commandline_argument; break; case 'f': if (strcasecmp(isc_commandline_argument, "KSK") == 0) ksk = DNS_KEYFLAG_KSK; else fatal("unknown flag '%s'", isc_commandline_argument); break; case 'k': options |= DST_TYPE_KEY; break; case 'l': label = isc_commandline_argument; break; case 'n': nametype = isc_commandline_argument; break; case 'p': protocol = strtol(isc_commandline_argument, &endp, 10); if (*endp != '\0' || protocol < 0 || protocol > 255) fatal("-p must be followed by a number " "[0..255]"); break; case 't': type = isc_commandline_argument; break; case 'v': verbose = strtol(isc_commandline_argument, &endp, 0); if (*endp != '\0') fatal("-v must be followed by a number"); break; case '?': if (isc_commandline_option != '?') fprintf(stderr, "%s: invalid argument -%c\n", program, isc_commandline_option); case 'h': usage(); default: fprintf(stderr, "%s: unhandled option -%c\n", program, isc_commandline_option); exit(1); } } if (ectx == NULL) setup_entropy(mctx, NULL, &ectx); ret = dst_lib_init(mctx, ectx, ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY); if (ret != ISC_R_SUCCESS) fatal("could not initialize dst"); setup_logging(verbose, mctx, &log); if (label == NULL) fatal("the key label was not specified"); if (argc < isc_commandline_index + 1) fatal("the key name was not specified"); if (argc > isc_commandline_index + 1) fatal("extraneous arguments"); if (algname == NULL) fatal("no algorithm was specified"); if (strcasecmp(algname, "RSA") == 0) { fprintf(stderr, "The use of RSA (RSAMD5) is not recommended.\n" "If you still wish to use RSA (RSAMD5) please " "specify \"-a RSAMD5\"\n"); return (1); } else { r.base = algname; r.length = strlen(algname); ret = dns_secalg_fromtext(&alg, &r); if (ret != ISC_R_SUCCESS) fatal("unknown algorithm %s", algname); if (alg == DST_ALG_DH) options |= DST_TYPE_KEY; } if (type != NULL && (options & DST_TYPE_KEY) != 0) { if (strcasecmp(type, "NOAUTH") == 0) flags |= DNS_KEYTYPE_NOAUTH; else if (strcasecmp(type, "NOCONF") == 0) flags |= DNS_KEYTYPE_NOCONF; else if (strcasecmp(type, "NOAUTHCONF") == 0) { flags |= (DNS_KEYTYPE_NOAUTH | DNS_KEYTYPE_NOCONF); } else if (strcasecmp(type, "AUTHCONF") == 0) /* nothing */; else fatal("invalid type %s", type); } if (nametype == NULL) { if ((options & DST_TYPE_KEY) != 0) /* KEY */ fatal("no nametype specified"); flags |= DNS_KEYOWNER_ZONE; /* DNSKEY */ } else if (strcasecmp(nametype, "zone") == 0) flags |= DNS_KEYOWNER_ZONE; else if ((options & DST_TYPE_KEY) != 0) { /* KEY */ if (strcasecmp(nametype, "host") == 0 || strcasecmp(nametype, "entity") == 0) flags |= DNS_KEYOWNER_ENTITY; else if (strcasecmp(nametype, "user") == 0) flags |= DNS_KEYOWNER_USER; else fatal("invalid KEY nametype %s", nametype); } else if (strcasecmp(nametype, "other") != 0) /* DNSKEY */ fatal("invalid DNSKEY nametype %s", nametype); rdclass = strtoclass(classname); if ((options & DST_TYPE_KEY) != 0) /* KEY */ flags |= signatory; else if ((flags & DNS_KEYOWNER_ZONE) != 0) /* DNSKEY */ flags |= ksk; if (protocol == -1) protocol = DNS_KEYPROTO_DNSSEC; else if ((options & DST_TYPE_KEY) == 0 && protocol != DNS_KEYPROTO_DNSSEC) fatal("invalid DNSKEY protocol: %d", protocol); if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) { if ((flags & DNS_KEYFLAG_SIGNATORYMASK) != 0) fatal("specified null key with signing authority"); } if ((flags & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE && alg == DNS_KEYALG_DH) fatal("a key with algorithm '%s' cannot be a zone key", algname); dns_fixedname_init(&fname); name = dns_fixedname_name(&fname); isc_buffer_init(&buf, argv[isc_commandline_index], strlen(argv[isc_commandline_index])); isc_buffer_add(&buf, strlen(argv[isc_commandline_index])); ret = dns_name_fromtext(name, &buf, dns_rootname, ISC_FALSE, NULL); if (ret != ISC_R_SUCCESS) fatal("invalid key name %s: %s", argv[isc_commandline_index], isc_result_totext(ret)); if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) null_key = ISC_TRUE; isc_buffer_init(&buf, filename, sizeof(filename) - 1); /* associate the key */ ret = dst_key_fromlabel(name, alg, flags, protocol, rdclass, "", label, NULL, mctx, &key); isc_entropy_stopcallbacksources(ectx); if (ret != ISC_R_SUCCESS) { char namestr[DNS_NAME_FORMATSIZE]; char algstr[ALG_FORMATSIZE]; dns_name_format(name, namestr, sizeof(namestr)); alg_format(alg, algstr, sizeof(algstr)); fatal("failed to generate key %s/%s: %s\n", namestr, algstr, isc_result_totext(ret)); exit(-1); } /* * Try to read a key with the same name, alg and id from disk. * If there is one we must continue generating a new one * unless we were asked to generate a null key, in which * case we return failure. */ ret = dst_key_fromfile(name, dst_key_id(key), alg, DST_TYPE_PRIVATE, NULL, mctx, &oldkey); /* do not overwrite an existing key */ if (ret == ISC_R_SUCCESS) { isc_buffer_clear(&buf); ret = dst_key_buildfilename(key, 0, NULL, &buf); fprintf(stderr, "%s: %s already exists\n", program, filename); dst_key_free(&key); exit (1); } ret = dst_key_tofile(key, options, NULL); if (ret != ISC_R_SUCCESS) { char keystr[KEY_FORMATSIZE]; key_format(key, keystr, sizeof(keystr)); fatal("failed to write key %s: %s\n", keystr, isc_result_totext(ret)); } isc_buffer_clear(&buf); ret = dst_key_buildfilename(key, 0, NULL, &buf); printf("%s\n", filename); dst_key_free(&key); cleanup_logging(&log); cleanup_entropy(&ectx); dst_lib_destroy(); dns_name_destroy(); if (verbose > 10) isc_mem_stats(mctx, stdout); isc_mem_destroy(&mctx); return (0); }
void ns_notify_start(ns_client_t *client) { dns_message_t *request = client->message; isc_result_t result; dns_name_t *zonename; dns_rdataset_t *zone_rdataset; dns_zone_t *zone = NULL; char namebuf[DNS_NAME_FORMATSIZE]; char tsigbuf[DNS_NAME_FORMATSIZE + sizeof(": TSIG ''")]; dns_tsigkey_t *tsigkey; /* * Interpret the question section. */ result = dns_message_firstname(request, DNS_SECTION_QUESTION); if (result != ISC_R_SUCCESS) { notify_log(client, ISC_LOG_NOTICE, "notify question section empty"); goto formerr; } /* * The question section must contain exactly one question. */ zonename = NULL; dns_message_currentname(request, DNS_SECTION_QUESTION, &zonename); zone_rdataset = ISC_LIST_HEAD(zonename->list); if (ISC_LIST_NEXT(zone_rdataset, link) != NULL) { notify_log(client, ISC_LOG_NOTICE, "notify question section contains multiple RRs"); goto formerr; } /* The zone section must have exactly one name. */ result = dns_message_nextname(request, DNS_SECTION_ZONE); if (result != ISC_R_NOMORE) { notify_log(client, ISC_LOG_NOTICE, "notify question section contains multiple RRs"); goto formerr; } /* The one rdataset must be an SOA. */ if (zone_rdataset->type != dns_rdatatype_soa) { notify_log(client, ISC_LOG_NOTICE, "notify question section contains no SOA"); goto formerr; } tsigkey = dns_message_gettsigkey(request); if (tsigkey != NULL) { dns_name_format(&tsigkey->name, namebuf, sizeof(namebuf)); if (tsigkey->generated) { char cnamebuf[DNS_NAME_FORMATSIZE]; dns_name_format(tsigkey->creator, cnamebuf, sizeof(cnamebuf)); snprintf(tsigbuf, sizeof(tsigbuf), ": TSIG '%s' (%s)", namebuf, cnamebuf); } else { snprintf(tsigbuf, sizeof(tsigbuf), ": TSIG '%s'", namebuf); } } else tsigbuf[0] = '\0'; dns_name_format(zonename, namebuf, sizeof(namebuf)); result = dns_zt_find(client->view->zonetable, zonename, 0, NULL, &zone); if (result != ISC_R_SUCCESS) goto notauth; switch (dns_zone_gettype(zone)) { case dns_zone_master: case dns_zone_slave: case dns_zone_stub: /* Allow dialup passive to work. */ notify_log(client, ISC_LOG_INFO, "received notify for zone '%s'%s", namebuf, tsigbuf); respond(client, dns_zone_notifyreceive(zone, ns_client_getsockaddr(client), request)); break; default: goto notauth; } dns_zone_detach(&zone); return; notauth: notify_log(client, ISC_LOG_NOTICE, "received notify for zone '%s'%s: not authoritative", namebuf, tsigbuf); result = DNS_R_NOTAUTH; goto failure; formerr: result = DNS_R_FORMERR; failure: if (zone != NULL) dns_zone_detach(&zone); respond(client, result); }
isc_result_t ns_stats_dump(ns_server_t *server, FILE *fp) { isc_stdtime_t now; isc_result_t result; dns_view_t *view; dns_zone_t *zone, *next; stats_dumparg_t dumparg; RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS); /* Set common fields */ dumparg.type = statsformat_file; dumparg.arg = fp; isc_stdtime_get(&now); fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now); fprintf(fp, "++ Incoming Requests ++\n"); dns_opcodestats_dump(server->opcodestats, opcodestat_dump, &dumparg, 0); fprintf(fp, "++ Incoming Queries ++\n"); dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump, &dumparg, 0); fprintf(fp, "++ Outgoing Queries ++\n"); for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; view = ISC_LIST_NEXT(view, link)) { if (view->resquerystats == NULL) continue; if (strcmp(view->name, "_default") == 0) fprintf(fp, "[View: default]\n"); else fprintf(fp, "[View: %s]\n", view->name); dns_rdatatypestats_dump(view->resquerystats, rdtypestat_dump, &dumparg, 0); } fprintf(fp, "++ Name Server Statistics ++\n"); dumparg.desc = nsstats_desc; dumparg.ncounters = dns_nsstatscounter_max; dns_generalstats_dump(server->nsstats, generalstat_dump, &dumparg, 0); fprintf(fp, "++ Zone Maintenance Statistics ++\n"); dumparg.desc = zonestats_desc; dumparg.ncounters = dns_zonestatscounter_max; dns_generalstats_dump(server->zonestats, generalstat_dump, &dumparg, 0); fprintf(fp, "++ Resolver Statistics ++\n"); fprintf(fp, "[Common]\n"); dumparg.desc = resstats_desc; dumparg.ncounters = dns_resstatscounter_max; dns_generalstats_dump(server->resolverstats, generalstat_dump, &dumparg, 0); for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; view = ISC_LIST_NEXT(view, link)) { if (view->resstats == NULL) continue; if (strcmp(view->name, "_default") == 0) fprintf(fp, "[View: default]\n"); else fprintf(fp, "[View: %s]\n", view->name); dns_generalstats_dump(view->resstats, generalstat_dump, &dumparg, 0); } fprintf(fp, "++ Cache DB RRsets ++\n"); for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; view = ISC_LIST_NEXT(view, link)) { dns_stats_t *cachestats; cachestats = dns_db_getrrsetstats(view->cachedb); if (cachestats == NULL) continue; if (strcmp(view->name, "_default") == 0) fprintf(fp, "[View: default]\n"); else fprintf(fp, "[View: %s]\n", view->name); dns_rdatasetstats_dump(cachestats, rdatasetstats_dump, &dumparg, 0); } fprintf(fp, "++ Per Zone Query Statistics ++\n"); zone = NULL; for (result = dns_zone_first(server->zonemgr, &zone); result == ISC_R_SUCCESS; next = NULL, result = dns_zone_next(zone, &next), zone = next) { dns_stats_t *zonestats = dns_zone_getrequeststats(zone); if (zonestats != NULL) { char zonename[DNS_NAME_FORMATSIZE]; dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename)); view = dns_zone_getview(zone); fprintf(fp, "[%s", zonename); if (strcmp(view->name, "_default") != 0) fprintf(fp, " (view: %s)", view->name); fprintf(fp, "]\n"); dumparg.desc = nsstats_desc; dumparg.ncounters = dns_nsstatscounter_max; dns_generalstats_dump(zonestats, generalstat_dump, &dumparg, 0); } } fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now); return (ISC_R_SUCCESS); /* this function currently always succeeds */ }
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); }