static void auto_detach(void *data, void *arg) { dns_zone_t *zone = data; UNUSED(arg); dns_zone_detach(&zone); }
static void xfrout_ctx_destroy(xfrout_ctx_t **xfrp) { xfrout_ctx_t *xfr = *xfrp; INSIST(xfr->sends == 0); xfr->client->shutdown = NULL; xfr->client->shutdown_arg = NULL; if (xfr->stream != NULL) xfr->stream->methods->destroy(&xfr->stream); if (xfr->buf.base != NULL) isc_mem_put(xfr->mctx, xfr->buf.base, xfr->buf.length); if (xfr->txmem != NULL) isc_mem_put(xfr->mctx, xfr->txmem, xfr->txmemlen); if (xfr->lasttsig != NULL) isc_buffer_free(&xfr->lasttsig); if (xfr->quota != NULL) isc_quota_detach(&xfr->quota); if (xfr->ver != NULL) dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE); if (xfr->zone != NULL) dns_zone_detach(&xfr->zone); if (xfr->db != NULL) dns_db_detach(&xfr->db); ns_client_detach(&xfr->client); isc_mem_put(xfr->mctx, xfr, sizeof(*xfr)); *xfrp = NULL; }
static isc_result_t make_zone(const char *name, dns_zone_t **zonep) { isc_result_t result; dns_view_t *view = NULL; dns_zone_t *zone = NULL; isc_buffer_t buffer; dns_fixedname_t fixorigin; dns_name_t *origin; CHECK(dns_view_create(mctx, dns_rdataclass_in, "view", &view)); CHECK(dns_zone_create(&zone, mctx)); isc_buffer_init(&buffer, name, strlen(name)); isc_buffer_add(&buffer, strlen(name)); dns_fixedname_init(&fixorigin); origin = dns_fixedname_name(&fixorigin); CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL)); CHECK(dns_zone_setorigin(zone, origin)); dns_zone_setview(zone, view); dns_zone_settype(zone, dns_zone_master); dns_zone_setclass(zone, view->rdclass); dns_view_detach(&view); *zonep = zone; return (ISC_R_SUCCESS); cleanup: if (zone != NULL) dns_zone_detach(&zone); if (view != NULL) dns_view_detach(&view); return (result); }
ATF_TC_BODY(zonemgr_unreachable, tc) { dns_zonemgr_t *zonemgr = NULL; dns_zone_t *zone = NULL; isc_sockaddr_t addr1, addr2; struct in_addr in; isc_result_t result; isc_time_t now; UNUSED(tc); TIME_NOW(&now); result = dns_test_begin(NULL, ISC_TRUE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); result = dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr, &zonemgr); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); result = dns_test_makezone("foo", &zone, NULL, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); result = dns_zonemgr_setsize(zonemgr, 1); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); result = dns_zonemgr_managezone(zonemgr, zone); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); in.s_addr = inet_addr("10.53.0.1"); isc_sockaddr_fromin(&addr1, &in, 2112); in.s_addr = inet_addr("10.53.0.2"); isc_sockaddr_fromin(&addr2, &in, 5150); ATF_CHECK(! dns_zonemgr_unreachable(zonemgr, &addr1, &addr2, &now)); dns_zonemgr_unreachableadd(zonemgr, &addr1, &addr2, &now); ATF_CHECK(dns_zonemgr_unreachable(zonemgr, &addr1, &addr2, &now)); in.s_addr = inet_addr("10.53.0.3"); isc_sockaddr_fromin(&addr2, &in, 5150); ATF_CHECK(! dns_zonemgr_unreachable(zonemgr, &addr1, &addr2, &now)); dns_zonemgr_unreachableadd(zonemgr, &addr1, &addr2, &now); ATF_CHECK(dns_zonemgr_unreachable(zonemgr, &addr1, &addr2, &now)); dns_zonemgr_unreachabledel(zonemgr, &addr1, &addr2); ATF_CHECK(! dns_zonemgr_unreachable(zonemgr, &addr1, &addr2, &now)); in.s_addr = inet_addr("10.53.0.2"); isc_sockaddr_fromin(&addr2, &in, 5150); ATF_CHECK(dns_zonemgr_unreachable(zonemgr, &addr1, &addr2, &now)); dns_zonemgr_unreachabledel(zonemgr, &addr1, &addr2); ATF_CHECK(! dns_zonemgr_unreachable(zonemgr, &addr1, &addr2, &now)); dns_zonemgr_releasezone(zonemgr, zone); dns_zone_detach(&zone); dns_zonemgr_shutdown(zonemgr); dns_zonemgr_detach(&zonemgr); ATF_REQUIRE_EQ(zonemgr, NULL); dns_test_end(); }
ATF_TC_BODY(zonemgr_createzone, tc) { dns_zonemgr_t *myzonemgr = NULL; dns_zone_t *zone = NULL; isc_result_t result; UNUSED(tc); result = dns_test_begin(NULL, ISC_TRUE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); result = dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr, &myzonemgr); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); /* This should not succeed until the dns_zonemgr_setsize() is run */ result = dns_zonemgr_createzone(myzonemgr, &zone); ATF_REQUIRE_EQ(result, ISC_R_FAILURE); result = dns_zonemgr_setsize(myzonemgr, 1); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); /* Now it should succeed */ result = dns_zonemgr_createzone(myzonemgr, &zone); ATF_CHECK_EQ(result, ISC_R_SUCCESS); ATF_CHECK(zone != NULL); if (zone != NULL) dns_zone_detach(&zone); dns_zonemgr_shutdown(myzonemgr); dns_zonemgr_detach(&myzonemgr); ATF_REQUIRE_EQ(myzonemgr, NULL); dns_test_end(); }
/*% load the zone */ isc_result_t load_zone(isc_mem_t *mctx, const char *zonename, const char *filename, dns_masterformat_t fileformat, const char *classname, dns_zone_t **zonep) { isc_result_t result; dns_rdataclass_t rdclass; isc_textregion_t region; isc_buffer_t buffer; dns_fixedname_t fixorigin; dns_name_t *origin; dns_zone_t *zone = NULL; REQUIRE(zonep == NULL || *zonep == NULL); if (debug) fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n", zonename, filename, classname); CHECK(dns_zone_create(&zone, mctx)); dns_zone_settype(zone, dns_zone_master); isc_buffer_init(&buffer, zonename, strlen(zonename)); isc_buffer_add(&buffer, strlen(zonename)); dns_fixedname_init(&fixorigin); origin = dns_fixedname_name(&fixorigin); CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL)); CHECK(dns_zone_setorigin(zone, origin)); CHECK(dns_zone_setdbtype(zone, 1, (const char * const *) dbtype)); CHECK(dns_zone_setfile2(zone, filename, fileformat)); DE_CONST(classname, region.base); region.length = strlen(classname); CHECK(dns_rdataclass_fromtext(&rdclass, ®ion)); dns_zone_setclass(zone, rdclass); dns_zone_setoption(zone, zone_options, ISC_TRUE); dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge); if (docheckmx) dns_zone_setcheckmx(zone, checkmx); if (docheckns) dns_zone_setcheckns(zone, checkns); if (dochecksrv) dns_zone_setchecksrv(zone, checksrv); CHECK(dns_zone_load(zone)); if (zonep != NULL) { *zonep = zone; zone = NULL; } cleanup: if (zone != NULL) dns_zone_detach(&zone); return (result); }
ATF_TC_BODY (zonemgr_managezone, tc) { dns_zonemgr_t *zonemgr = NULL; dns_zone_t *zone = NULL; isc_result_t result; UNUSED (tc); result = dns_test_begin (NULL, ISC_TRUE); ATF_REQUIRE_EQ (result, ISC_R_SUCCESS); result = dns_zonemgr_create (mctx, taskmgr, timermgr, socketmgr, &zonemgr); ATF_REQUIRE_EQ (result, ISC_R_SUCCESS); result = make_zone ("foo", &zone); ATF_REQUIRE_EQ (result, ISC_R_SUCCESS); /* This should not succeed until the dns_zonemgr_setsize() is run */ result = dns_zonemgr_managezone (zonemgr, zone); ATF_REQUIRE_EQ (result, ISC_R_FAILURE); ATF_REQUIRE_EQ (dns_zonemgr_getcount (zonemgr, DNS_ZONESTATE_ANY), 0); result = dns_zonemgr_setsize (zonemgr, 1); ATF_REQUIRE_EQ (result, ISC_R_SUCCESS); /* Now it should succeed */ result = dns_zonemgr_managezone (zonemgr, zone); ATF_REQUIRE_EQ (result, ISC_R_SUCCESS); ATF_REQUIRE_EQ (dns_zonemgr_getcount (zonemgr, DNS_ZONESTATE_ANY), 1); dns_zonemgr_releasezone (zonemgr, zone); dns_zone_detach (&zone); ATF_REQUIRE_EQ (dns_zonemgr_getcount (zonemgr, DNS_ZONESTATE_ANY), 0); dns_zonemgr_shutdown (zonemgr); dns_zonemgr_detach (&zonemgr); ATF_REQUIRE_EQ (zonemgr, NULL); dns_test_end (); }
/* * Create a zone with origin 'name', return a pointer to the zone object in * 'zonep'. If 'view' is set, add the zone to that view; otherwise, create * a new view for the purpose. * * If the created view is going to be needed by the caller subsequently, * then 'keepview' should be set to true; this will prevent the view * from being detached. In this case, the caller is responsible for * detaching the view. */ isc_result_t dns_test_makezone(const char *name, dns_zone_t **zonep, dns_view_t *view, isc_boolean_t keepview) { isc_result_t result; dns_zone_t *zone = NULL; isc_buffer_t buffer; dns_fixedname_t fixorigin; dns_name_t *origin; if (view == NULL) CHECK(dns_view_create(mctx, dns_rdataclass_in, "view", &view)); else if (!keepview) keepview = ISC_TRUE; zone = *zonep; if (zone == NULL) CHECK(dns_zone_create(&zone, mctx)); isc_buffer_constinit(&buffer, name, strlen(name)); isc_buffer_add(&buffer, strlen(name)); dns_fixedname_init(&fixorigin); origin = dns_fixedname_name(&fixorigin); CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL)); CHECK(dns_zone_setorigin(zone, origin)); dns_zone_setview(zone, view); dns_zone_settype(zone, dns_zone_master); dns_zone_setclass(zone, view->rdclass); dns_view_addzone(view, zone); if (!keepview) dns_view_detach(&view); *zonep = zone; return (ISC_R_SUCCESS); cleanup: if (zone != NULL) dns_zone_detach(&zone); if (view != NULL) dns_view_detach(&view); return (result); }
static void xfrout_ctx_destroy(xfrout_ctx_t **xfrp) { xfrout_ctx_t *xfr = *xfrp; ns_client_t *client = NULL; INSIST(xfr->sends == 0); xfr->client->shutdown = NULL; xfr->client->shutdown_arg = NULL; if (xfr->stream != NULL) xfr->stream->methods->destroy(&xfr->stream); if (xfr->buf.base != NULL) isc_mem_put(xfr->mctx, xfr->buf.base, xfr->buf.length); if (xfr->txmem != NULL) isc_mem_put(xfr->mctx, xfr->txmem, xfr->txmemlen); if (xfr->lasttsig != NULL) isc_buffer_free(&xfr->lasttsig); if (xfr->quota != NULL) isc_quota_detach(&xfr->quota); if (xfr->ver != NULL) dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE); if (xfr->zone != NULL) dns_zone_detach(&xfr->zone); if (xfr->db != NULL) dns_db_detach(&xfr->db); /* * We want to detch the client after we have released the memory * context as ns_client_detach checks the memory reference count. */ ns_client_attach(xfr->client, &client); ns_client_detach(&xfr->client); isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr)); ns_client_detach(&client); *xfrp = NULL; }
static void destroy(void) { if (zone != NULL) dns_zone_detach(&zone); dns_name_destroy(); }
static isc_result_t freezezones(dns_zone_t *zone, void *uap) { isc_boolean_t freeze = *(isc_boolean_t *)uap; isc_boolean_t frozen; isc_result_t result = ISC_R_SUCCESS; char classstr[DNS_RDATACLASS_FORMATSIZE]; char zonename[DNS_NAME_FORMATSIZE]; dns_zone_t *raw = NULL; dns_view_t *view; const char *vname; const char *sep; int level; dns_zone_getraw(zone, &raw); if (raw != NULL) zone = raw; if (dns_zone_gettype(zone) != dns_zone_master) { if (raw != NULL) dns_zone_detach(&raw); return (ISC_R_SUCCESS); } if (!dns_zone_isdynamic(zone, ISC_TRUE)) { if (raw != NULL) dns_zone_detach(&raw); return (ISC_R_SUCCESS); } frozen = dns_zone_getupdatedisabled(zone); if (freeze) { if (frozen) result = DNS_R_FROZEN; if (result == ISC_R_SUCCESS) result = dns_zone_flush(zone); if (result == ISC_R_SUCCESS) dns_zone_setupdatedisabled(zone, freeze); } else { if (frozen) { result = dns_zone_loadandthaw(zone); if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE) result = ISC_R_SUCCESS; } } view = dns_zone_getview(zone); if (strcmp(view->name, "_bind") == 0 || strcmp(view->name, "_default") == 0) { vname = ""; sep = ""; } else { vname = view->name; sep = " "; } dns_rdataclass_format(dns_zone_getclass(zone), classstr, sizeof(classstr)); dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename)); level = (result != ISC_R_SUCCESS) ? ISC_LOG_ERROR : ISC_LOG_DEBUG(1); isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE, level, "%s zone '%s/%s'%s%s: %s", freeze ? "freezing" : "thawing", zonename, classstr, sep, vname, isc_result_totext(result)); if (raw != NULL) dns_zone_detach(&raw); return (result); }
int main(int argc, char **argv) { int c; char *filename = NULL; const char *classname = "IN"; while ((c = isc_commandline_parse(argc, argv, "cdf:m:qsMS")) != EOF) { switch (c) { case 'c': classname = isc_commandline_argument; break; case 'd': debug++; break; case 'f': if (filename != NULL) usage(); filename = isc_commandline_argument; break; case 'm': memset(&addr, 0, sizeof(addr)); addr.type.sin.sin_family = AF_INET; inet_pton(AF_INET, isc_commandline_argument, &addr.type.sin.sin_addr); addr.type.sin.sin_port = htons(53); break; case 'q': quiet++; break; case 's': stats++; break; case 'S': zonetype = dns_zone_slave; break; case 'M': zonetype = dns_zone_master; break; default: usage(); } } if (argv[isc_commandline_index] == NULL) usage(); RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS); RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); RUNTIME_CHECK(isc_taskmgr_create(mctx, 2, 0, &taskmgr) == ISC_R_SUCCESS); RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS); RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS); RUNTIME_CHECK(dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr, &zonemgr) == ISC_R_SUCCESS); if (filename == NULL) filename = argv[isc_commandline_index]; setup(argv[isc_commandline_index], filename, classname); query(); if (zone != NULL) dns_zone_detach(&zone); dns_zonemgr_shutdown(zonemgr); dns_zonemgr_detach(&zonemgr); isc_socketmgr_destroy(&socketmgr); isc_taskmgr_destroy(&taskmgr); isc_timermgr_destroy(&timermgr); if (!quiet && stats) isc_mem_stats(mctx, stdout); isc_mem_destroy(&mctx); return (0); }
/*% load the zone */ isc_result_t load_zone(isc_mem_t *mctx, const char *zonename, const char *filename, dns_masterformat_t fileformat, const char *classname, dns_ttl_t maxttl, dns_zone_t **zonep) { isc_result_t result; dns_rdataclass_t rdclass; isc_textregion_t region; isc_buffer_t buffer; dns_fixedname_t fixorigin; dns_name_t *origin; dns_zone_t *zone = NULL; REQUIRE(zonep == NULL || *zonep == NULL); if (debug) fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n", zonename, filename, classname); CHECK(dns_zone_create(&zone, mctx)); dns_zone_settype(zone, dns_zone_master); isc_buffer_constinit(&buffer, zonename, strlen(zonename)); isc_buffer_add(&buffer, strlen(zonename)); dns_fixedname_init(&fixorigin); origin = dns_fixedname_name(&fixorigin); CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL)); CHECK(dns_zone_setorigin(zone, origin)); CHECK(dns_zone_setdbtype(zone, 1, (const char * const *) dbtype)); CHECK(dns_zone_setfile2(zone, filename, fileformat)); if (journal != NULL) CHECK(dns_zone_setjournal(zone, journal)); DE_CONST(classname, region.base); region.length = strlen(classname); CHECK(dns_rdataclass_fromtext(&rdclass, ®ion)); dns_zone_setclass(zone, rdclass); dns_zone_setoption(zone, zone_options, ISC_TRUE); dns_zone_setoption2(zone, zone_options2, ISC_TRUE); dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge); dns_zone_setmaxttl(zone, maxttl); if (docheckmx) dns_zone_setcheckmx(zone, checkmx); if (docheckns) dns_zone_setcheckns(zone, checkns); if (dochecksrv) dns_zone_setchecksrv(zone, checksrv); CHECK(dns_zone_load(zone)); /* * When loading map files we can't catch oversize TTLs during * load, so we check for them here. */ if (fileformat == dns_masterformat_map && maxttl != 0) { CHECK(check_ttls(zone, maxttl)); } if (zonep != NULL) { *zonep = zone; zone = NULL; } cleanup: if (zone != NULL) dns_zone_detach(&zone); return (result); }
/* * Create a writeable DLZ zone. This can be called by DLZ drivers * during configure() to create a zone that can be updated. The zone * type is set to dns_zone_dlz, which is equivalent to a master zone * * This function uses a callback setup in dns_dlzconfigure() to call * into the server zone code to setup the remaining pieces of server * specific functionality on the zone */ isc_result_t dns_dlz_writeablezone(dns_view_t *view, const char *zone_name) { dns_zone_t *zone = NULL; dns_zone_t *dupzone = NULL; isc_result_t result; isc_buffer_t buffer; dns_fixedname_t fixorigin; dns_name_t *origin; dns_dlzdb_t *dlzdatabase; REQUIRE(DNS_DLZ_VALID(view->dlzdatabase)); dlzdatabase = view->dlzdatabase; REQUIRE(dlzdatabase->configure_callback != NULL); isc_buffer_init(&buffer, zone_name, strlen(zone_name)); isc_buffer_add(&buffer, strlen(zone_name)); dns_fixedname_init(&fixorigin); result = dns_name_fromtext(dns_fixedname_name(&fixorigin), &buffer, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) goto cleanup; origin = dns_fixedname_name(&fixorigin); /* See if the zone already exists */ result = dns_view_findzone(view, origin, &dupzone); if (result == ISC_R_SUCCESS) { dns_zone_detach(&dupzone); result = ISC_R_EXISTS; goto cleanup; } INSIST(dupzone == NULL); /* Create it */ result = dns_zone_create(&zone, view->mctx); if (result != ISC_R_SUCCESS) goto cleanup; result = dns_zone_setorigin(zone, origin); if (result != ISC_R_SUCCESS) goto cleanup; dns_zone_setview(zone, view); dns_zone_setadded(zone, ISC_TRUE); if (dlzdatabase->ssutable == NULL) { result = dns_ssutable_createdlz(dlzdatabase->mctx, &dlzdatabase->ssutable, view->dlzdatabase); if (result != ISC_R_SUCCESS) goto cleanup; } dns_zone_setssutable(zone, dlzdatabase->ssutable); result = dlzdatabase->configure_callback(view, zone); if (result != ISC_R_SUCCESS) goto cleanup; /* * Add the zone to its view in the new view list. */ result = dns_view_addzone(view, zone); cleanup: if (zone != NULL) dns_zone_detach(&zone); return (result); }
/* * Create a writeable DLZ zone. This can be called by DLZ drivers * during configure() to create a zone that can be updated. The zone * type is set to dns_zone_dlz, which is equivalent to a master zone * * This function uses a callback setup in dns_dlzconfigure() to call * into the server zone code to setup the remaining pieces of server * specific functionality on the zone */ isc_result_t dns_dlz_writeablezone(dns_view_t *view, dns_dlzdb_t *dlzdb, const char *zone_name) { dns_zone_t *zone = NULL; dns_zone_t *dupzone = NULL; isc_result_t result; isc_buffer_t buffer; dns_fixedname_t fixorigin; dns_name_t *origin; REQUIRE(DNS_DLZ_VALID(dlzdb)); REQUIRE(dlzdb->configure_callback != NULL); isc_buffer_constinit(&buffer, zone_name, strlen(zone_name)); isc_buffer_add(&buffer, strlen(zone_name)); dns_fixedname_init(&fixorigin); result = dns_name_fromtext(dns_fixedname_name(&fixorigin), &buffer, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) goto cleanup; origin = dns_fixedname_name(&fixorigin); if (!dlzdb->search) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_WARNING, "DLZ %s has 'search no;', but attempted to " "register writeable zone %s.", dlzdb->dlzname, zone_name); result = ISC_R_SUCCESS; goto cleanup; } /* See if the zone already exists */ result = dns_view_findzone(view, origin, &dupzone); if (result == ISC_R_SUCCESS) { dns_zone_detach(&dupzone); result = ISC_R_EXISTS; goto cleanup; } INSIST(dupzone == NULL); /* Create it */ result = dns_zone_create(&zone, view->mctx); if (result != ISC_R_SUCCESS) goto cleanup; result = dns_zone_setorigin(zone, origin); if (result != ISC_R_SUCCESS) goto cleanup; dns_zone_setview(zone, view); dns_zone_setadded(zone, ISC_TRUE); if (dlzdb->ssutable == NULL) { result = dns_ssutable_createdlz(dlzdb->mctx, &dlzdb->ssutable, dlzdb); if (result != ISC_R_SUCCESS) goto cleanup; } dns_zone_setssutable(zone, dlzdb->ssutable); result = dlzdb->configure_callback(view, dlzdb, zone); if (result != ISC_R_SUCCESS) goto cleanup; result = dns_view_addzone(view, zone); cleanup: if (zone != NULL) dns_zone_detach(&zone); return (result); }
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, *raw = NULL, *mayberaw; 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; isc_boolean_t is_ixfr = ISC_FALSE; isc_uint32_t begin_serial = 0, current_serial; 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 */ // Temporary: only searching the first DLZ database if (! ISC_LIST_EMPTY(client->view->dlz_searched)) { result = dns_dlzallowzonexfr(client->view, question_name, &client->peeraddr, &db); pfilter_notify(result, client, "zonexfr"); 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; } 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)) { /* Master and slave zones are OK for transfer. */ case dns_zone_master: case dns_zone_slave: case dns_zone_dlz: break; 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)); current_serial = dns_soa_getserial(¤t_soa_tuple->rdata); if (reqtype == dns_rdatatype_ixfr) { 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); /* * 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 = is_dlz ? NULL : 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); is_ixfr = ISC_TRUE; } 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 if (is_ixfr) xfrout_log1(client, question_name, question_class, ISC_LOG_INFO, "%s started%s%s (serial %u -> %u)", mnemonic, (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname, begin_serial, current_serial); else xfrout_log1(client, question_name, question_class, ISC_LOG_INFO, "%s started%s%s (serial %u)", mnemonic, (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname, current_serial); if (zone != NULL) { dns_zone_getraw(zone, &raw); mayberaw = (raw != NULL) ? raw : zone; if ((client->attributes & NS_CLIENTATTR_WANTEXPIRE) != 0 && dns_zone_gettype(mayberaw) == dns_zone_slave) { isc_time_t expiretime; isc_uint32_t secs; dns_zone_getexpiretime(zone, &expiretime); secs = isc_time_seconds(&expiretime); if (secs >= client->now && result == ISC_R_SUCCESS) { client->attributes |= NS_CLIENTATTR_HAVEEXPIRE; client->expire = secs - client->now; } } if (raw != NULL) dns_zone_detach(&raw); } /* * 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); } }
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); }