]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
xfr: finalize timers and master serial only after commit set_master_post_commit
authorLibor Peltan <libor.peltan@nic.cz>
Wed, 3 Dec 2025 10:17:57 +0000 (11:17 +0100)
committerLibor Peltan <libor.peltan@nic.cz>
Wed, 3 Dec 2025 10:17:57 +0000 (11:17 +0100)
src/knot/dnssec/zone-events.h
src/knot/events/handlers/dnssec.c
src/knot/events/handlers/refresh.c
src/knot/updates/zone-update.c
src/knot/updates/zone-update.h

index 6bad0b7169802d734d425a95e23720a12b7d71dc..b604925d0559416e2759b58f3fdd155f3d797397 100644 (file)
@@ -37,6 +37,7 @@ typedef struct {
        bool keys_changed;
        bool plan_ds_check;
        bool plan_dnskey_sync;
+       bool zone_changed;
 } zone_sign_reschedule_t;
 
 typedef struct {
index d669d1e2372327b4db02d7412218ecf2720077b2..ba52ddb4aa33cb8111be4b76f044dac41eb67e00 100644 (file)
@@ -28,7 +28,7 @@ static void log_dnssec_next(const knot_dname_t *zone, knot_time_t refresh_at)
 }
 
 void event_dnssec_reschedule(conf_t *conf, zone_t *zone,
-                            const zone_sign_reschedule_t *refresh, bool zone_changed)
+                            const zone_sign_reschedule_t *refresh)
 {
        time_t now = time(NULL);
        time_t ignore = -1;
@@ -49,7 +49,7 @@ void event_dnssec_reschedule(conf_t *conf, zone_t *zone,
                ZONE_EVENT_DS_CHECK, refresh->plan_ds_check ? now : ignore,
                ZONE_EVENT_DNSKEY_SYNC, refresh->plan_dnskey_sync ? now + jitter : ignore
        );
-       if (zone_changed) {
+       if (refresh->zone_changed) {
                zone_schedule_notify(zone, 0);
        }
 }
@@ -61,7 +61,6 @@ int event_dnssec(conf_t *conf, zone_t *zone)
        zone_sign_reschedule_t resch = { 0 };
        zone_sign_roll_flags_t r_flags = KEY_ROLL_ALLOW_ALL;
        int sign_flags = 0;
-       bool zone_changed = false;
 
        if (zone_get_flag(zone, ZONE_FORCE_RESIGN, true)) {
                log_zone_info(zone->name, "DNSSEC, dropping previous "
@@ -90,7 +89,9 @@ int event_dnssec(conf_t *conf, zone_t *zone)
                goto done;
        }
 
-       zone_changed = !zone_update_no_change(&up);
+       resch.zone_changed = !zone_update_no_change(&up);
+
+       zone_update_set_post_commit(&up, (zone_update_commit_cb_t)event_dnssec_reschedule, &resch);
 
        ret = zone_update_commit(conf, &up);
        if (ret != KNOT_EOK) {
@@ -98,9 +99,6 @@ int event_dnssec(conf_t *conf, zone_t *zone)
        }
 
 done:
-       // Schedule dependent events
-       event_dnssec_reschedule(conf, zone, &resch, zone_changed);
-
        if (ret != KNOT_EOK) {
                zone_update_clear(&up);
        }
index 745200e816596d03190077ecd4274449d5c7884c..bf7b8bf401fbde1c735489a6ae03dfa4cc9100af 100644 (file)
@@ -114,10 +114,13 @@ struct refresh_data {
        enum state state;                 //!< Event processing state.
        enum xfr_type xfr_type;           //!< Transfer type (mostly IXFR versus AXFR).
        bool axfr_style_ixfr;             //!< Master responded with AXFR-style-IXFR.
+       bool axfr_bootstrap;
        knot_rrset_t *initial_soa_copy;   //!< Copy of the received initial SOA.
        struct xfr_stats stats;           //!< Transfer statistics.
        struct timespec started;          //!< When refresh started.
        size_t change_size;               //!< Size of added and removed RRs.
+       uint32_t old_serial;
+       uint32_t master_serial;
 
        struct {
                zone_contents_t *zone;    //!< AXFR result, new zone.
@@ -330,19 +333,44 @@ static void axfr_slave_sign_serial(zone_contents_t *new_contents, zone_t *zone,
        zone_contents_set_soa_serial(new_contents, new_serial);
 }
 
+static void post_commit(conf_t *conf, zone_t *zone, void *ctx)
+{
+       struct refresh_data *data = ctx;
+       conf_val_t val = conf_zone_get(data->conf, C_DNSSEC_SIGNING, data->zone->name);
+       bool dnssec_enable = conf_bool(&val);
+
+       if (dnssec_enable && (data->xfr_type == XFR_TYPE_AXFR || !EMPTY_LIST(data->ixfr.changesets))) {
+               int ret = zone_set_master_serial(data->zone, data->master_serial);
+               if (ret != KNOT_EOK) {
+                       log_zone_warning(data->zone->name,
+                                        "unable to save master serial, future transfers might be broken");
+               }
+       }
+
+       finalize_timers(data);
+       xfr_log_publish(data, data->old_serial, zone_contents_serial(data->zone->contents),
+                       data->master_serial, dnssec_enable, data->axfr_bootstrap);
+
+
+       if (data->xfr_type == XFR_TYPE_AXFR || data->old_serial != zone_contents_serial(data->zone->contents)) {
+               data->fallback->remote = false;
+               zone_set_last_master(data->zone, (const struct sockaddr_storage *)data->remote);
+       }
+}
+
 static int axfr_finalize(struct refresh_data *data)
 {
        zone_contents_t *new_zone = data->axfr.zone;
 
        conf_val_t val = conf_zone_get(data->conf, C_DNSSEC_SIGNING, data->zone->name);
        bool dnssec_enable = conf_bool(&val);
-       uint32_t old_serial = zone_contents_serial(data->zone->contents), master_serial = 0;
-       bool bootstrap = (data->zone->contents == NULL);
+       data->old_serial = zone_contents_serial(data->zone->contents);
+       data->axfr_bootstrap = (data->zone->contents == NULL);
        zone_skip_t skip = { 0 };
        int ret = KNOT_EOK;
 
        if (dnssec_enable) {
-               axfr_slave_sign_serial(new_zone, data->zone, data->conf, &master_serial);
+               axfr_slave_sign_serial(new_zone, data->zone, data->conf, &data->master_serial);
                ret = zone_skip_add_dnssec_diff(&skip);
                assert(ret == KNOT_EOK); // static size of zone_skip is enough to cover dnssec types
        }
@@ -388,6 +416,8 @@ static int axfr_finalize(struct refresh_data *data)
                return ret;
        }
 
+       zone_update_set_post_commit(&up, post_commit, data);
+
        ret = zone_update_commit(data->conf, &up);
        if (ret != KNOT_EOK) {
                zone_update_clear(&up);
@@ -397,21 +427,6 @@ static int axfr_finalize(struct refresh_data *data)
                return ret;
        }
 
-       if (dnssec_enable) {
-               ret = zone_set_master_serial(data->zone, master_serial);
-               if (ret != KNOT_EOK) {
-                       log_zone_warning(data->zone->name,
-                       "unable to save master serial, future transfers might be broken");
-               }
-       }
-
-       finalize_timers(data);
-       xfr_log_publish(data, old_serial, zone_contents_serial(data->zone->contents),
-                       master_serial, dnssec_enable, bootstrap);
-
-       data->fallback->remote = false;
-       zone_set_last_master(data->zone, (const struct sockaddr_storage *)data->remote);
-
        return KNOT_EOK;
 }
 
@@ -595,10 +610,10 @@ static int ixfr_finalize(struct refresh_data *data)
 {
        conf_val_t val = conf_zone_get(data->conf, C_DNSSEC_SIGNING, data->zone->name);
        bool dnssec_enable = conf_bool(&val);
-       uint32_t master_serial = 0, old_serial = zone_contents_serial(data->zone->contents);
+       data->old_serial = zone_contents_serial(data->zone->contents);
 
        if (dnssec_enable) {
-               int ret = ixfr_slave_sign_serial(&data->ixfr.changesets, data->zone, data->conf, &master_serial);
+               int ret = ixfr_slave_sign_serial(&data->ixfr.changesets, data->zone, data->conf, &data->master_serial);
                if (ret != KNOT_EOK) {
                        IXFRIN_LOG(LOG_WARNING, data,
                                   "failed to adjust SOA serials from unsigned remote (%s)",
@@ -664,6 +679,8 @@ static int ixfr_finalize(struct refresh_data *data)
                return ret;
        }
 
+       zone_update_set_post_commit(&up, post_commit, data);
+
        ret = zone_update_commit(data->conf, &up);
        if (ret != KNOT_EOK) {
                zone_update_clear(&up);
@@ -672,23 +689,6 @@ static int ixfr_finalize(struct refresh_data *data)
                return ret;
        }
 
-       if (dnssec_enable && !EMPTY_LIST(data->ixfr.changesets)) {
-               ret = zone_set_master_serial(data->zone, master_serial);
-               if (ret != KNOT_EOK) {
-                       log_zone_warning(data->zone->name,
-                       "unable to save master serial, future transfers might be broken");
-               }
-       }
-
-       finalize_timers(data);
-       xfr_log_publish(data, old_serial, zone_contents_serial(data->zone->contents),
-                       master_serial, dnssec_enable, false);
-
-       if (old_serial != zone_contents_serial(data->zone->contents)) {
-               data->fallback->remote = false;
-               zone_set_last_master(data->zone, (const struct sockaddr_storage *)data->remote);
-       }
-
        return KNOT_EOK;
 }
 
index b936643ee8a3381fd37b38de53715e81c3bf00c9..13be9baaff9b4d63f6211c26cef88eeaf224f31b 100644 (file)
@@ -1038,11 +1038,21 @@ int zone_update_commit(conf_t *conf, zone_update_t *update)
                                       zone_contents_serial(update->zone->contents));
        }
 
+       if (update->post_commit_cb != NULL) {
+               update->post_commit_cb(conf, update->zone, update->post_commit_cb_ctx);
+       }
+
        memset(update, 0, sizeof(*update));
 
        return KNOT_EOK;
 }
 
+void zone_update_set_post_commit(zone_update_t *update, zone_update_commit_cb_t cb, void *cb_ctx)
+{
+       update->post_commit_cb = cb;
+       update->post_commit_cb_ctx = cb_ctx;
+}
+
 bool zone_update_no_change(zone_update_t *update)
 {
        if (update == NULL) {
index f4f6ca94efae560f8d9eaaaa435e2ad276d2c57a..c7b7938fc68aa3cdf77335e82957baf41c6fb410 100644 (file)
@@ -20,6 +20,8 @@ typedef struct {
        int warning;
 } dnssec_validation_hint_t;
 
+typedef void (*zone_update_commit_cb_t)(conf_t *, zone_t *, void *);
+
 /*! \brief Structure for zone contents updating / querying. */
 typedef struct zone_update {
        zone_t *zone;                /*!< Zone being updated. */
@@ -29,6 +31,8 @@ typedef struct zone_update {
        changeset_t extra_ch;        /*!< Extra changeset to store just diff btwn zonefile and result. */
        apply_ctx_t *a_ctx;          /*!< Context for applying changesets. */
        uint32_t flags;              /*!< Zone update flags. */
+       void *post_commit_cb_ctx;
+       zone_update_commit_cb_t  post_commit_cb;
        dnssec_validation_hint_t validation_hint;
 } zone_update_t;
 
@@ -278,6 +282,15 @@ int zone_update_verify_digest(conf_t *conf, zone_update_t *update);
  */
 int zone_update_commit(conf_t *conf, zone_update_t *update);
 
+/*!
+ * \brief Set a callback to be called after successful zone_update_commit.
+ *
+ * \param update       Zone update.
+ * \param cb           Callback.
+ * \param cb_ctx       Arbitrary context.
+ */
+void zone_update_set_post_commit(zone_update_t *update, zone_update_commit_cb_t cb, void *cb_ctx);
+
 /*!
  * \brief Returns bool whether there are any changes at all.
  *