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 }
/*% scan the zone for oversize TTLs */ static isc_result_t check_ttls(dns_zone_t *zone, dns_ttl_t maxttl) { isc_result_t result; dns_db_t *db = NULL; dns_dbversion_t *version = NULL; dns_dbnode_t *node = NULL; dns_dbiterator_t *dbiter = NULL; dns_rdatasetiter_t *rdsiter = NULL; dns_rdataset_t rdataset; dns_fixedname_t fname; dns_name_t *name; dns_fixedname_init(&fname); name = dns_fixedname_name(&fname); dns_rdataset_init(&rdataset); CHECK(dns_zone_getdb(zone, &db)); INSIST(db != NULL); CHECK(dns_db_newversion(db, &version)); CHECK(dns_db_createiterator(db, 0, &dbiter)); for (result = dns_dbiterator_first(dbiter); result == ISC_R_SUCCESS; result = dns_dbiterator_next(dbiter)) { result = dns_dbiterator_current(dbiter, &node, name); if (result == DNS_R_NEWORIGIN) result = ISC_R_SUCCESS; CHECK(result); CHECK(dns_db_allrdatasets(db, node, version, 0, &rdsiter)); for (result = dns_rdatasetiter_first(rdsiter); result == ISC_R_SUCCESS; result = dns_rdatasetiter_next(rdsiter)) { dns_rdatasetiter_current(rdsiter, &rdataset); if (rdataset.ttl > maxttl) { char nbuf[DNS_NAME_FORMATSIZE]; char tbuf[255]; isc_buffer_t b; isc_region_t r; dns_name_format(name, nbuf, sizeof(nbuf)); isc_buffer_init(&b, tbuf, sizeof(tbuf) - 1); CHECK(dns_rdatatype_totext(rdataset.type, &b)); isc_buffer_usedregion(&b, &r); r.base[r.length] = 0; dns_zone_log(zone, ISC_LOG_ERROR, "%s/%s TTL %d exceeds " "maximum TTL %d", nbuf, tbuf, rdataset.ttl, maxttl); dns_rdataset_disassociate(&rdataset); CHECK(ISC_R_RANGE); } dns_rdataset_disassociate(&rdataset); } if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS; CHECK(result); dns_rdatasetiter_destroy(&rdsiter); dns_db_detachnode(db, &node); } if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS; cleanup: if (node != NULL) dns_db_detachnode(db, &node); if (rdsiter != NULL) dns_rdatasetiter_destroy(&rdsiter); if (dbiter != NULL) dns_dbiterator_destroy(&dbiter); if (version != NULL) dns_db_closeversion(db, &version, ISC_FALSE); if (db != NULL) dns_db_detach(&db); return (result); }
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_result_t acl_configure_zone_ssutable(const char *policy_str, dns_zone_t *zone) { isc_result_t result = ISC_R_SUCCESS; cfg_parser_t *parser = NULL; const cfg_listelt_t *el; cfg_obj_t *policy = NULL; dns_ssutable_t *table = NULL; ld_string_t *new_policy_str = NULL; isc_mem_t *mctx; REQUIRE(zone != NULL); mctx = dns_zone_getmctx(zone); if (policy_str == NULL) goto cleanup; CHECK(bracket_str(mctx, policy_str, &new_policy_str)); CHECK(cfg_parser_create(mctx, dns_lctx, &parser)); result = cfg_parse_strbuf(parser, str_buf(new_policy_str), &cfg_type_update_policy, &policy); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, "failed to parse policy string"); goto cleanup; } CHECK(dns_ssutable_create(mctx, &table)); for (el = cfg_list_first(policy); el != NULL; el = cfg_list_next(el)) { const cfg_obj_t *stmt; isc_boolean_t grant; unsigned int match_type; dns_fixedname_t fname, fident; dns_rdatatype_t *types; unsigned int n; types = NULL; stmt = cfg_listelt_value(el); CHECK(get_mode(stmt, &grant)); CHECK(get_match_type(stmt, &match_type)); CHECK(get_fixed_name(stmt, "identity", &fident)); /* Use zone name for 'zonesub' match type */ result = get_fixed_name(stmt, "name", &fname); if (result == ISC_R_NOTFOUND && match_type == DNS_SSUMATCHTYPE_SUBDOMAIN) { dns_fixedname_init(&fname); CHECK(dns_name_copy(dns_zone_getorigin(zone), dns_fixedname_name(&fname), &fname.buffer)); } else if (result != ISC_R_SUCCESS) goto cleanup; CHECK(get_types(mctx, stmt, &types, &n)); if (match_type == DNS_SSUMATCHTYPE_WILDCARD && !dns_name_iswildcard(dns_fixedname_name(&fname))) { char name[DNS_NAME_FORMATSIZE]; dns_name_format(dns_fixedname_name(&fname), name, DNS_NAME_FORMATSIZE); dns_zone_log(zone, ISC_LOG_ERROR, "invalid update policy: " "name '%s' is expected to be a wildcard", name); CLEANUP_WITH(DNS_R_BADNAME); } result = dns_ssutable_addrule(table, grant, dns_fixedname_name(&fident), match_type, dns_fixedname_name(&fname), n, types); SAFE_MEM_PUT(mctx, types, n * sizeof(dns_rdatatype_t)); if (result != ISC_R_SUCCESS) goto cleanup; } cleanup: if (result == ISC_R_SUCCESS) dns_zone_setssutable(zone, table); str_destroy(&new_policy_str); if (policy != NULL) cfg_obj_destroy(parser, &policy); if (parser != NULL) cfg_parser_destroy(&parser); if (table != NULL) dns_ssutable_detach(&table); return result; }