예제 #1
0
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;
}
예제 #2
0
파일: handlers.c 프로젝트: idtek/knot
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, &notify);
		size_t addr_count = conf_val_count(&addr);

		for (int i = 0; i < addr_count; i++) {
			conf_remote_t slave = conf_remote(conf, &notify, 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(&notify);
	}

	return KNOT_EOK;
}
예제 #3
0
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;
	}
}
예제 #4
0
파일: handlers.c 프로젝트: idtek/knot
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;
}