From dd1f71247c9c49534409a7906d18b93dc641cb5e Mon Sep 17 00:00:00 2001 From: Jan Vcelak <jan.vcelak@nic.cz> Date: Tue, 21 Oct 2014 16:20:08 +0200 Subject: [PATCH] expire zone if SOA is accepted, but AXFR is not --- src/knot/nameserver/internet.c | 3 +- src/knot/zone/events/handlers.c | 95 +++++++++++++++++++-------------- 2 files changed, 56 insertions(+), 42 deletions(-) diff --git a/src/knot/nameserver/internet.c b/src/knot/nameserver/internet.c index 17c13d8e1f..3af64f429f 100644 --- a/src/knot/nameserver/internet.c +++ b/src/knot/nameserver/internet.c @@ -864,7 +864,7 @@ int internet_query_plan(struct query_plan *plan) /*! \brief Process answer to SOA query. */ static int process_soa_answer(knot_pkt_t *pkt, struct answer_data *data) { - zone_t *zone = data->param->zone; + zone_t *zone = data->param->zone; /* Expect SOA in answer section. */ const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER); @@ -884,6 +884,7 @@ static int process_soa_answer(knot_pkt_t *pkt, struct answer_data *data) uint32_t their_serial = knot_soa_serial(&answer->rr[0].rrs); if (knot_serial_compare(our_serial, their_serial) >= 0) { ANSWER_LOG(LOG_INFO, data, "refresh, outgoing", "zone is up-to-date"); + zone_events_cancel(zone, ZONE_EVENT_EXPIRE); return NS_PROC_DONE; /* Our zone is up to date. */ } diff --git a/src/knot/zone/events/handlers.c b/src/knot/zone/events/handlers.c index 81cadb7661..a0bce68cbb 100644 --- a/src/knot/zone/events/handlers.c +++ b/src/knot/zone/events/handlers.c @@ -196,7 +196,11 @@ static void schedule_dnssec(zone_t *zone, time_t refresh_at) zone_events_schedule_at(zone, ZONE_EVENT_DNSSEC, refresh_at); } -/* -- zone events handling callbacks --------------------------------------- */ +/*! \brief Get SOA from zone. */ +static const knot_rdataset_t *zone_soa(zone_t *zone) +{ + return node_rdataset(zone->contents->apex, KNOT_RRTYPE_SOA); +} /*! \brief Fetch SOA expire timer and add a timeout grace period. */ static uint32_t soa_graceful_expire(const knot_rdataset_t *soa) @@ -206,6 +210,18 @@ static uint32_t soa_graceful_expire(const knot_rdataset_t *soa) return knot_soa_expire(soa) + 2 * conf()->max_conn_idle; } +/*! \brief Schedule expire event, unless it is already scheduled. */ +static void start_expire_timer(zone_t *zone, const knot_rdataset_t *soa) +{ + if (zone_events_is_scheduled(zone, ZONE_EVENT_EXPIRE)) { + return; + } + + zone_events_schedule(zone, ZONE_EVENT_EXPIRE, soa_graceful_expire(soa)); +} + +/* -- zone events handling callbacks --------------------------------------- */ + int event_reload(zone_t *zone) { assert(zone); @@ -283,14 +299,11 @@ fail: return result; } -/* -- zone events implementation API ---------------------------------------- */ - int event_refresh(zone_t *zone) { assert(zone); - zone_contents_t *contents = zone->contents; - if (zone_contents_is_empty(contents)) { + if (zone_contents_is_empty(zone->contents)) { /* No contents, schedule retransfer now. */ zone_events_schedule(zone, ZONE_EVENT_XFER, ZONE_EVENT_NOW); return KNOT_EOK; @@ -300,8 +313,7 @@ int event_refresh(zone_t *zone) assert(master); int ret = zone_query_execute(zone, KNOT_QUERY_NORMAL, master); - - const knot_rdataset_t *soa = node_rdataset(contents->apex, KNOT_RRTYPE_SOA); + const knot_rdataset_t *soa = zone_soa(zone); if (ret != KNOT_EOK) { /* Log connection errors. */ ZONE_QUERY_LOG(LOG_WARNING, zone, master, "SOA query, outgoing", @@ -310,15 +322,10 @@ int event_refresh(zone_t *zone) zone_master_rotate(zone); /* Schedule next retry. */ zone_events_schedule(zone, ZONE_EVENT_REFRESH, knot_soa_retry(soa)); - if (zone_events_get_time(zone, ZONE_EVENT_EXPIRE) <= ZONE_EVENT_NOW) { - /* Schedule zone expiration if not previously planned. */ - zone_events_schedule(zone, ZONE_EVENT_EXPIRE, soa_graceful_expire(soa)); - } + start_expire_timer(zone, soa); } else { /* SOA query answered, reschedule refresh timer. */ zone_events_schedule(zone, ZONE_EVENT_REFRESH, knot_soa_refresh(soa)); - /* Cancel possible expire. */ - zone_events_cancel(zone, ZONE_EVENT_EXPIRE); } return zone_events_write_persistent(zone); @@ -329,41 +336,47 @@ int event_xfer(zone_t *zone) assert(zone); /* Determine transfer type. */ - bool is_bootstrap = false; + bool is_boostrap = zone_contents_is_empty(zone->contents); uint16_t pkt_type = KNOT_QUERY_IXFR; - if (zone_contents_is_empty(zone->contents) || zone->flags & ZONE_FORCE_AXFR) { + if (is_boostrap || zone->flags & ZONE_FORCE_AXFR) { pkt_type = KNOT_QUERY_AXFR; - is_bootstrap = true; } /* Execute zone transfer and reschedule timers. */ int ret = zone_query_transfer(zone, zone_master(zone), pkt_type); - if (ret == KNOT_EOK) { - assert(!zone_contents_is_empty(zone->contents)); - /* New zone transferred, reschedule zone expiration and refresh - * timers and send notifications to slaves. */ - const knot_rdataset_t *soa = - node_rdataset(zone->contents->apex, KNOT_RRTYPE_SOA); - zone_events_schedule(zone, ZONE_EVENT_REFRESH, knot_soa_refresh(soa)); - zone_events_schedule(zone, ZONE_EVENT_NOTIFY, ZONE_EVENT_NOW); - /* Sync zonefile immediately if configured. */ - if (zone->conf->dbsync_timeout == 0) { - zone_events_schedule(zone, ZONE_EVENT_FLUSH, ZONE_EVENT_NOW); - } else if (zone_events_get_time(zone, ZONE_EVENT_FLUSH) <= ZONE_EVENT_NOW) { - /* Plan sync if not previously planned. */ - zone_events_schedule(zone, ZONE_EVENT_FLUSH, zone->conf->dbsync_timeout); - } - zone->bootstrap_retry = ZONE_EVENT_NOW; - zone->flags &= ~ZONE_FORCE_AXFR; - /* Trim extra heap. */ - if (!is_bootstrap) { - mem_trim(); + + /* Handle failure during transfer. */ + if (ret != KNOT_EOK) { + if (is_boostrap) { + zone->bootstrap_retry = bootstrap_next(zone->bootstrap_retry); + zone_events_schedule(zone, ZONE_EVENT_XFER, zone->bootstrap_retry); + } else { + start_expire_timer(zone, zone_soa(zone)); } - } else { - /* Zone contents is still empty, increment bootstrap retry timer - * and try again. */ - zone->bootstrap_retry = bootstrap_next(zone->bootstrap_retry); - zone_events_schedule(zone, ZONE_EVENT_XFER, zone->bootstrap_retry); + + return KNOT_EOK; + } + + assert(!zone_contents_is_empty(zone->contents)); + const knot_rdataset_t *soa = zone_soa(zone); + + /* Rechedule events. */ + zone_events_schedule(zone, ZONE_EVENT_REFRESH, knot_soa_refresh(soa)); + zone_events_schedule(zone, ZONE_EVENT_NOTIFY, ZONE_EVENT_NOW); + zone_events_cancel(zone, ZONE_EVENT_EXPIRE); + if (zone->conf->dbsync_timeout == 0) { + zone_events_schedule(zone, ZONE_EVENT_FLUSH, ZONE_EVENT_NOW); + } else if (!zone_events_is_scheduled(zone, ZONE_EVENT_FLUSH)) { + zone_events_schedule(zone, ZONE_EVENT_FLUSH, zone->conf->dbsync_timeout); + } + + /* Transfer cleanup. */ + zone->bootstrap_retry = ZONE_EVENT_NOW; + zone->flags &= ~ZONE_FORCE_AXFR; + + /* Trim extra heap. */ + if (pkt_type == KNOT_QUERY_AXFR) { + mem_trim(); } return KNOT_EOK; -- GitLab