static int axfr_answer_finalize(struct answer_data *adata) { struct timeval now; gettimeofday(&now, NULL); /* * Adjust zone so that node count is set properly and nodes are * marked authoritative / delegation point. */ struct xfr_proc *proc = adata->ext; int rc = zone_contents_adjust_full(proc->contents, NULL, NULL); if (rc != KNOT_EOK) { return rc; } /* Switch contents. */ zone_t *zone = adata->param->zone; zone_contents_t *old_contents = zone_switch_contents(zone, proc->contents); synchronize_rcu(); AXFRIN_LOG(LOG_INFO, "finished, " "serial %u -> %u, %.02f seconds, %u messages, %u bytes", zone_contents_serial(old_contents), zone_contents_serial(proc->contents), time_diff(&proc->tstamp, &now) / 1000.0, proc->npkts, proc->nbytes); /* Do not free new contents with cleanup. */ zone_contents_deep_free(&old_contents); proc->contents = NULL; return KNOT_EOK; }
int event_notify(conf_t *conf, zone_t *zone) { assert(zone); /* Check zone contents. */ if (zone_contents_is_empty(zone->contents)) { return KNOT_EOK; } /* Walk through configured remotes and send messages. */ conf_val_t notify = conf_zone_get(conf, C_NOTIFY, zone->name); while (notify.code == KNOT_EOK) { conf_val_t addr = conf_id_get(conf, C_RMT, C_ADDR, ¬ify); size_t addr_count = conf_val_count(&addr); for (int i = 0; i < addr_count; i++) { conf_remote_t slave = conf_remote(conf, ¬ify, i); int ret = zone_query_execute(conf, zone, KNOT_QUERY_NOTIFY, &slave); if (ret == KNOT_EOK) { ZONE_QUERY_LOG(LOG_INFO, zone, &slave, "NOTIFY, outgoing", "serial %u", zone_contents_serial(zone->contents)); break; } else { ZONE_QUERY_LOG(LOG_WARNING, zone, &slave, "NOTIFY, outgoing", "failed (%s)", knot_strerror(ret)); } } conf_val_next(¬ify); } return KNOT_EOK; }
int axfr_query_process(knot_pkt_t *pkt, struct query_data *qdata) { if (pkt == NULL || qdata == NULL) { return KNOT_NS_PROC_FAIL; } int ret = KNOT_EOK; struct timeval now = {0}; /* If AXFR is disabled, respond with NOTIMPL. */ if (qdata->param->proc_flags & NS_QUERY_NO_AXFR) { qdata->rcode = KNOT_RCODE_NOTIMPL; return KNOT_NS_PROC_FAIL; } /* Initialize on first call. */ if (qdata->ext == NULL) { ret = axfr_query_init(qdata); if (ret != KNOT_EOK) { AXFROUT_LOG(LOG_ERR, "failed to start (%s)", knot_strerror(ret)); return KNOT_NS_PROC_FAIL; } else { AXFROUT_LOG(LOG_INFO, "started, serial %u", zone_contents_serial(qdata->zone->contents)); } } /* Reserve space for TSIG. */ knot_pkt_reserve(pkt, knot_tsig_wire_maxsize(qdata->sign.tsig_key)); /* Answer current packet (or continue). */ struct axfr_proc *axfr = (struct axfr_proc *)qdata->ext; ret = xfr_process_list(pkt, &axfr_process_node_tree, qdata); switch(ret) { case KNOT_ESPACE: /* Couldn't write more, send packet and continue. */ return KNOT_NS_PROC_FULL; /* Check for more. */ case KNOT_EOK: /* Last response. */ gettimeofday(&now, NULL); AXFROUT_LOG(LOG_INFO, "finished, %.02f seconds, %u messages, %u bytes", time_diff(&axfr->proc.tstamp, &now) / 1000.0, axfr->proc.npkts, axfr->proc.nbytes); return KNOT_NS_PROC_DONE; break; default: /* Generic error. */ AXFROUT_LOG(LOG_ERR, "failed (%s)", knot_strerror(ret)); return KNOT_NS_PROC_FAIL; } }
int event_load(conf_t *conf, zone_t *zone) { assert(zone); /* Take zone file mtime and load it. */ char *filename = conf_zonefile(conf, zone->name); time_t mtime = zonefile_mtime(filename); free(filename); uint32_t dnssec_refresh = time(NULL); zone_contents_t *contents = NULL; int ret = zone_load_contents(conf, zone->name, &contents); if (ret != KNOT_EOK) { goto fail; } /* Store zonefile serial and apply changes from the journal. */ zone->zonefile_serial = zone_contents_serial(contents); ret = zone_load_journal(conf, zone, contents); if (ret != KNOT_EOK) { goto fail; } /* Post load actions - calculate delta, sign with DNSSEC... */ /*! \todo issue #242 dnssec signing should occur in the special event */ ret = zone_load_post(conf, zone, contents, &dnssec_refresh); if (ret != KNOT_EOK) { if (ret == KNOT_ESPACE) { log_zone_error(zone->name, "journal size is too small " "to fit the changes"); } else { log_zone_error(zone->name, "failed to store changes into " "journal (%s)", knot_strerror(ret)); } goto fail; } /* Check zone contents consistency. */ ret = zone_load_check(conf, contents); if (ret != KNOT_EOK) { goto fail; } /* Everything went alright, switch the contents. */ zone->zonefile_mtime = mtime; zone_contents_t *old = zone_switch_contents(zone, contents); zone->flags &= ~ZONE_EXPIRED; uint32_t old_serial = zone_contents_serial(old); if (old != NULL) { synchronize_rcu(); zone_contents_deep_free(&old); } /* Schedule notify and refresh after load. */ if (zone_is_slave(conf, zone)) { zone_events_schedule(zone, ZONE_EVENT_REFRESH, ZONE_EVENT_NOW); } if (!zone_contents_is_empty(contents)) { zone_events_schedule(zone, ZONE_EVENT_NOTIFY, ZONE_EVENT_NOW); zone->bootstrap_retry = ZONE_EVENT_NOW; } /* Schedule zone resign. */ conf_val_t val = conf_zone_get(conf, C_DNSSEC_SIGNING, zone->name); if (conf_bool(&val)) { schedule_dnssec(zone, dnssec_refresh); } /* Periodic execution. */ val = conf_zone_get(conf, C_ZONEFILE_SYNC, zone->name); int64_t sync_timeout = conf_int(&val); if (sync_timeout >= 0) { zone_events_schedule(zone, ZONE_EVENT_FLUSH, sync_timeout); } uint32_t current_serial = zone_contents_serial(zone->contents); log_zone_info(zone->name, "loaded, serial %u -> %u", old_serial, current_serial); return KNOT_EOK; fail: zone_contents_deep_free(&contents); /* Try to bootstrap the zone if local error. */ if (zone_is_slave(conf, zone) && !zone_events_is_scheduled(zone, ZONE_EVENT_XFER)) { zone_events_schedule(zone, ZONE_EVENT_XFER, ZONE_EVENT_NOW); } return ret; }