process_answer.c 4.17 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*  Copyright (C) 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "knot/nameserver/process_answer.h"
18 19 20 21
#include "knot/nameserver/internet.h"
#include "knot/nameserver/notify.h"
#include "knot/nameserver/ixfr.h"
#include "knot/nameserver/axfr.h"
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

static int noop(knot_pkt_t *pkt, knot_process_t *ctx)
{
	return NS_PROC_NOOP;
}

/*! \brief Accessor to query-specific data. */
#define ANSWER_DATA(ctx) ((struct answer_data *)(ctx)->data)

static void answer_data_init(knot_process_t *ctx, void *module_param)
{
	/* Initialize persistent data. */
	struct answer_data *data = ANSWER_DATA(ctx);
	memset(data, 0, sizeof(struct answer_data));
	data->mm = &ctx->mm;
	data->param = module_param;
}

40 41 42 43 44 45 46 47 48
/*! \brief Answer is paired to query if MsgId and QUESTION matches. */
static bool is_answer_to_query(const knot_pkt_t *query, knot_pkt_t *answer)
{
	return knot_wire_get_id(query->wire) == knot_wire_get_id(answer->wire) &&
	       knot_pkt_qtype(query)  == knot_pkt_qtype(answer)  &&
	       knot_pkt_qclass(query) == knot_pkt_qclass(answer) &&
	       knot_dname_is_equal(knot_pkt_qname(query), knot_pkt_qname(answer));
}

49
static int process_answer_begin(knot_process_t *ctx, void *module_param)
50 51 52 53 54 55 56 57 58 59 60 61 62
{
	/* Initialize context. */
	assert(ctx);
	ctx->type = NS_PROC_ANSWER_ID;
	ctx->data = mm_alloc(&ctx->mm, sizeof(struct answer_data));

	/* Initialize persistent data. */
	answer_data_init(ctx, module_param);

	/* Await packet. */
	return NS_PROC_MORE;
}

63
static int process_answer_reset(knot_process_t *ctx)
64 65 66 67 68 69 70 71 72
{
	assert(ctx);

	/* Initialize persistent data. */
	answer_data_init(ctx, ANSWER_DATA(ctx)->param);

	/* Await packet. */
	return NS_PROC_MORE;
}
73

74
static int process_answer_finish(knot_process_t *ctx)
75 76 77 78 79 80 81
{
	process_answer_reset(ctx);
	mm_free(&ctx->mm, ctx->data);
	ctx->data = NULL;

	return NS_PROC_NOOP;
}
82

83 84 85 86 87
/* \note Private helper for process_answer repetitive checks. */
#define ANSWER_REQUIRES(condition, ret) \
	if (!(condition)) { \
		knot_pkt_free(&pkt); \
		return ret; \
88 89
	}

90
static int process_answer(knot_pkt_t *pkt, knot_process_t *ctx)
91 92 93 94 95
{
	assert(pkt && ctx);
	struct answer_data *data = ANSWER_DATA(ctx);

	/* Check parse state. */
96 97
	ANSWER_REQUIRES(pkt->parsed >= KNOT_WIRE_HEADER_SIZE, NS_PROC_FAIL);
	ANSWER_REQUIRES(pkt->parsed == pkt->size, NS_PROC_FAIL);
98
	/* Accept only responses. */
99
	ANSWER_REQUIRES(knot_wire_get_qr(pkt->wire), NS_PROC_NOOP);
100 101
	/* Check if we want answer paired to query. */
	const knot_pkt_t *query = data->param->query;
102 103 104
	ANSWER_REQUIRES(query == NULL || is_answer_to_query(query, pkt), NS_PROC_NOOP);
	/* Class specific answer processing. */
	ANSWER_REQUIRES(knot_pkt_qclass(pkt) == KNOT_CLASS_IN, NS_PROC_NOOP);
105

106 107 108 109 110
	/* Call appropriate processing handler. */
	int next_state = NS_PROC_NOOP;
	switch(knot_pkt_type(pkt)) {
	case KNOT_RESPONSE_NORMAL:
		next_state = internet_process_answer(pkt, data);
111
		break;
112 113 114 115
	case KNOT_RESPONSE_AXFR:
		next_state = axfr_process_answer(pkt, data);
		break;
	case KNOT_RESPONSE_IXFR:
116
		next_state = ixfr_process_answer(pkt, data);
117 118 119 120 121
		break;
	case KNOT_RESPONSE_NOTIFY:
		next_state = notify_process_answer(pkt, data);
		break;
	default:
122 123 124 125 126
		next_state = NS_PROC_NOOP;
		break;
	}

	knot_pkt_free(&pkt);
127
	return next_state;
128 129
}

130
#undef ANSWER_REQUIRES
131 132 133 134 135 136 137 138 139 140 141 142 143 144

/*! \brief Module implementation. */
static const knot_process_module_t PROCESS_ANSWER_MODULE = {
        &process_answer_begin,
        &process_answer_reset,
        &process_answer_finish,
        &process_answer,
        &noop, /* No output. */
        &noop  /* No error processing. */
};

const knot_process_module_t *process_answer_get_module(void)
{
	return &PROCESS_ANSWER_MODULE;
145
}