/* * Zone management. * * Copyright (C) 2009-2015 Red Hat ; see COPYRIGHT for license */ #include #include #include #include #include #include #include #include "util.h" #include "instance.h" #include "lock.h" #include "log.h" #include "zone.h" extern const char *impname; /* * Create a new zone with origin 'name'. The zone stay invisible to clients * until it is explicitly added to a view. */ isc_result_t create_zone(sample_instance_t * const inst, dns_name_t * const name, dns_zone_t ** const rawp) { isc_result_t result; dns_zone_t *raw = NULL; const char *zone_argv[1]; char zone_name[DNS_NAME_FORMATSIZE]; dns_acl_t *acl_any = NULL; REQUIRE(inst != NULL); REQUIRE(name != NULL); REQUIRE(rawp != NULL && *rawp == NULL); zone_argv[0] = inst->db_name; result = dns_zone_create(&raw, inst->mctx); if (result != ISC_R_SUCCESS) { log_write(ISC_LOG_ERROR, "create_zone: dns_zone_create -> %s\n", isc_result_totext(result)); goto cleanup; } result = dns_zone_setorigin(raw, name); if (result != ISC_R_SUCCESS) { log_write(ISC_LOG_ERROR, "create_zone: dns_zone_setorigin -> %s\n", isc_result_totext(result)); goto cleanup; } dns_zone_setclass(raw, dns_rdataclass_in); dns_zone_settype(raw, dns_zone_master); result = dns_zone_setdbtype(raw, 1, zone_argv); if (result != ISC_R_SUCCESS) { log_write(ISC_LOG_ERROR, "create_zone: dns_zone_setdbtype -> %s\n", isc_result_totext(result)); goto cleanup; } result = dns_zonemgr_managezone(inst->zmgr, raw); if (result != ISC_R_SUCCESS) { log_write(ISC_LOG_ERROR, "create_zone: dns_zonemgr_managezone -> %s\n", isc_result_totext(result)); goto cleanup; } /* This is completely insecure - use some sensible values instead! */ result = dns_acl_any(inst->mctx, &acl_any); if (result != ISC_R_SUCCESS) { log_write(ISC_LOG_ERROR, "create_zone: dns_acl_any -> %s\n", isc_result_totext(result)); goto cleanup; } dns_zone_setupdateacl(raw, acl_any); dns_zone_setqueryacl(raw, acl_any); dns_zone_setxfracl(raw, acl_any); dns_acl_detach(&acl_any); *rawp = raw; return (ISC_R_SUCCESS); cleanup: dns_name_format(name, zone_name, DNS_NAME_FORMATSIZE); log_error_r("failed to create new zone '%s'", zone_name); if (raw != NULL) { if (dns_zone_getmgr(raw) != NULL) dns_zonemgr_releasezone(inst->zmgr, raw); dns_zone_detach(&raw); } if (acl_any != NULL) dns_acl_detach(&acl_any); return (result); } /* * Add zone to the view defined in inst->view. This will make the zone visible * to clients. */ static isc_result_t publish_zone(sample_instance_t *inst, dns_zone_t *zone) { isc_result_t result; bool freeze = false; dns_zone_t *zone_in_view = NULL; dns_view_t *view_in_zone = NULL; isc_result_t lock_state = ISC_R_IGNORE; REQUIRE(inst != NULL); REQUIRE(zone != NULL); /* Return success if the zone is already in the view as expected. */ result = dns_view_findzone(inst->view, dns_zone_getorigin(zone), &zone_in_view); if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) goto cleanup; view_in_zone = dns_zone_getview(zone); if (view_in_zone != NULL) { /* Zone has a view set -> view should contain the same zone. */ if (zone_in_view == zone) { /* Zone is already published in the right view. */ CLEANUP_WITH(ISC_R_SUCCESS); } else if (view_in_zone != inst->view) { /* * Un-published inactive zone will have * inst->view in zone but will not be present * in the view itself. */ dns_zone_log(zone, ISC_LOG_ERROR, "zone->view doesn't " "match data in the view"); CLEANUP_WITH(ISC_R_UNEXPECTED); } } if (zone_in_view != NULL) { dns_zone_log(zone, ISC_LOG_ERROR, "cannot publish zone: view already " "contains another zone with this name"); CLEANUP_WITH(ISC_R_UNEXPECTED); } run_exclusive_enter(inst, &lock_state); if (inst->view->frozen) { freeze = true; dns_view_thaw(inst->view); } dns_zone_setview(zone, inst->view); result = dns_view_addzone(inst->view, zone); if (result != ISC_R_SUCCESS) { log_write(ISC_LOG_ERROR, "publish_zone: dns_view_addzone -> %s\n", isc_result_totext(result)); goto cleanup; } cleanup: if (zone_in_view != NULL) dns_zone_detach(&zone_in_view); if (freeze) dns_view_freeze(inst->view); run_exclusive_exit(inst, lock_state); return (result); } /* * @warning Never call this on raw part of in-line secure zone, call it only * on the secure zone! */ static isc_result_t load_zone(dns_zone_t *zone) { isc_result_t result; bool zone_dynamic; uint32_t serial; result = dns_zone_load(zone); if (result != ISC_R_SUCCESS && result != DNS_R_UPTODATE && result != DNS_R_DYNAMIC && result != DNS_R_CONTINUE) goto cleanup; zone_dynamic = (result == DNS_R_DYNAMIC); result = dns_zone_getserial2(zone, &serial); if (result != ISC_R_SUCCESS) { log_write(ISC_LOG_ERROR, "load_zone: dns_zone_getserial2 -> %s\n", isc_result_totext(result)); goto cleanup; } dns_zone_log(zone, ISC_LOG_INFO, "loaded serial %u", serial); if (zone_dynamic) dns_zone_notify(zone); cleanup: return (result); } /* * Add zone to view and call dns_zone_load(). */ isc_result_t activate_zone(sample_instance_t *inst, dns_zone_t *raw) { isc_result_t result; /* * Zone has to be published *before* zone load * otherwise it will race with zone->view != NULL check * in zone_maintenance() in zone.c. */ result = publish_zone(inst, raw); if (result != ISC_R_SUCCESS) { dns_zone_log(raw, ISC_LOG_ERROR, "cannot add zone to view: %s", dns_result_totext(result)); goto cleanup; } result = load_zone(raw); if (result != ISC_R_SUCCESS) { log_write(ISC_LOG_ERROR, "activate_zone: load_zone -> %s\n", isc_result_totext(result)); goto cleanup; } cleanup: return (result); }