Commit fff23454 authored by Jan Včelák's avatar Jan Včelák 🚀

tsig verification in answer processing

parent 6332c2b8
......@@ -127,8 +127,8 @@ src/knot/nameserver/query_module.c
src/knot/nameserver/query_module.h
src/knot/nameserver/requestor.c
src/knot/nameserver/requestor.h
src/knot/nameserver/requestor_tsig.c
src/knot/nameserver/requestor_tsig.h
src/knot/nameserver/tsig_ctx.c
src/knot/nameserver/tsig_ctx.h
src/knot/nameserver/update.c
src/knot/nameserver/update.h
src/knot/other/debug.h
......
......@@ -240,14 +240,14 @@ libknotd_la_SOURCES = \
knot/nameserver/process_answer.h \
knot/nameserver/requestor.c \
knot/nameserver/requestor.h \
knot/nameserver/requestor_tsig.c \
knot/nameserver/requestor_tsig.h \
knot/nameserver/query_module.c \
knot/nameserver/query_module.h \
knot/nameserver/update.c \
knot/nameserver/update.h \
knot/nameserver/notify.c \
knot/nameserver/notify.h \
knot/nameserver/tsig_ctx.c \
knot/nameserver/tsig_ctx.h \
knot/modules/synth_record.c \
knot/modules/synth_record.h \
knot/other/debug.h \
......
......@@ -318,10 +318,14 @@ int axfr_process_answer(knot_pkt_t *pkt, struct answer_data *data)
/* Initialize processing with first packet. */
int ret = KNOT_EOK;
if (data->ext == NULL) {
NS_NEED_TSIG_SIGNED(&data->param->tsig_ctx, 0);
ret = axfr_answer_init(data);
if (ret != KNOT_EOK) {
return NS_PROC_FAIL;
}
} else {
NS_NEED_TSIG_SIGNED(&data->param->tsig_ctx, 100);
}
/* Process answer packet. */
......
......@@ -899,6 +899,8 @@ int internet_process_answer(knot_pkt_t *pkt, struct answer_data *data)
return NS_PROC_FAIL;
}
NS_NEED_TSIG_SIGNED(&data->param->tsig_ctx, 0);
/* As of now, server can only issue SOA queries. */
switch(knot_pkt_qtype(pkt)) {
case KNOT_RRTYPE_SOA:
......
......@@ -127,6 +127,11 @@ int ns_put_rr(knot_pkt_t *pkt, const knot_rrset_t *rr,
} \
}
#define NS_NEED_TSIG_SIGNED(tsig_ctx, max_unsigned) \
if (tsig_unsigned_count(tsig_ctx) > max_unsigned) { \
return NS_PROC_FAIL; \
}
#endif /* _KNOT_INTERNET_H_ */
/*! @} */
......@@ -33,6 +33,8 @@
#include "knot/nameserver/internet.h"
#include "common/debug.h"
#include "knot/nameserver/process_query.h"
#include "knot/nameserver/tsig_ctx.h"
#include "knot/nameserver/process_answer.h"
#include "libknot/dnssec/random.h"
#include "libknot/rdata/soa.h"
......@@ -84,5 +86,7 @@ int notify_query(knot_pkt_t *pkt, struct query_data *qdata)
int notify_process_answer(knot_pkt_t *pkt, struct answer_data *data)
{
NS_NEED_TSIG_SIGNED(&data->param->tsig_ctx, 0);
return NS_PROC_DONE; /* No processing. */
}
......@@ -103,6 +103,12 @@ static int process_answer(knot_pkt_t *pkt, knot_process_t *ctx)
/* Class specific answer processing. */
ANSWER_REQUIRES(knot_pkt_qclass(pkt) == KNOT_CLASS_IN, NS_PROC_NOOP);
/* Verify incoming packet. */
int ret = tsig_verify_packet(&data->param->tsig_ctx, pkt);
if (ret != KNOT_EOK) {
return NS_PROC_FAIL;
}
/* Call appropriate processing handler. */
int next_state = NS_PROC_NOOP;
switch(knot_pkt_type(pkt)) {
......
......@@ -17,6 +17,7 @@
#pragma once
#include "knot/nameserver/process_query.h"
#include "knot/nameserver/tsig_ctx.h"
/* Query processing module implementation. */
const knot_process_module_t *process_answer_get_module(void);
......@@ -35,6 +36,7 @@ struct process_answer_param {
zone_t *zone;
const knot_pkt_t *query;
const struct sockaddr_storage *remote;
tsig_ctx_t tsig_ctx;
};
struct answer_data
......
......@@ -55,7 +55,6 @@ static void request_close(mm_ctx_t *mm, struct request *request)
knot_process_finish(&request->process);
rem_node(&request->data.node);
requestor_tsig_cleanup(&request->data.tsig_ctx);
close(request->data.fd);
knot_pkt_free(&request->data.query);
mm_free(mm, request->pkt_buf);
......@@ -155,11 +154,12 @@ struct request *requestor_make(struct requestor *requestor,
return NULL;
}
memcpy(&request->data.origin, &remote->via, sizeof(remote->via));
memcpy(&request->data.remote, &remote->addr, sizeof(remote->addr));
request->state = NS_PROC_DONE;
request->data.remote = remote;
request->data.fd = -1;
request->data.query = query;
requestor_tsig_init(&request->data.tsig_ctx, remote->key);
return request;
}
......@@ -170,8 +170,8 @@ int requestor_enqueue(struct requestor *requestor, struct request * request, voi
}
/* Fetch a bound socket. */
int fd = net_connected_socket(SOCK_STREAM, &request->data.remote->addr,
&request->data.remote->via, O_NONBLOCK);
int fd = net_connected_socket(SOCK_STREAM, &request->data.remote,
&request->data.origin, O_NONBLOCK);
if (fd < 0) {
return KNOT_ECONN;
}
......@@ -199,39 +199,12 @@ int requestor_dequeue(struct requestor *requestor)
return KNOT_EOK;
}
/*!
* \brief Sign outbound packet using TSIG.
*/
static int request_sign(struct request *request)
{
assert(request);
return requestor_tsig_sign_packet(&request->data.tsig_ctx,
request->data.query);
}
/*!
* \brief Check inbound packet TSIG signature.
*/
static int request_verify(struct request *request)
{
assert(request);
return requestor_tsig_verify_packet(&request->data.tsig_ctx,
request->data.query);
}
static int exec_request(struct request *last, struct timeval *timeout)
{
int ret = KNOT_EOK;
/* Process any pending data. */
if (last->state == NS_PROC_FULL) {
ret = request_sign(last);
if (ret != KNOT_EOK) {
return ret;
}
ret = request_send(last, timeout);
if (ret != KNOT_EOK) {
return ret;
......@@ -246,11 +219,6 @@ static int exec_request(struct request *last, struct timeval *timeout)
return rcvd;
}
ret = request_verify(last);
if (ret != KNOT_EOK) {
return ret;
}
last->state = knot_process_in(last->pkt_buf, rcvd, &last->process);
if (last->state == NS_PROC_FAIL) {
return KNOT_EMALF;
......
......@@ -18,7 +18,6 @@
#include "knot/nameserver/process_query.h"
#include "knot/nameserver/process_answer.h"
#include "knot/nameserver/requestor_tsig.h"
#include "common/lists.h"
struct request;
......@@ -41,9 +40,8 @@ struct requestor {
struct request_data {
node_t node;
int fd;
const conf_iface_t *remote;
struct sockaddr_storage remote, origin;
knot_pkt_t *query;
requestor_tsig_ctx_t tsig_ctx;
};
/*!
......
......@@ -21,9 +21,9 @@
#include "common/errcode.h"
#include "libknot/rdata/tsig.h"
#include "libknot/tsig-op.h"
#include "knot/nameserver/requestor_tsig.h"
#include "knot/nameserver/tsig_ctx.h"
void requestor_tsig_init(requestor_tsig_ctx_t *ctx, const knot_tsig_key_t *key)
void tsig_init(tsig_ctx_t *ctx, const knot_tsig_key_t *key)
{
if (!ctx) {
return;
......@@ -31,19 +31,12 @@ void requestor_tsig_init(requestor_tsig_ctx_t *ctx, const knot_tsig_key_t *key)
memset(ctx, 0, sizeof(*ctx));
ctx->key = key;
}
void requestor_tsig_cleanup(requestor_tsig_ctx_t *ctx)
{
if (!ctx) {
return;
}
free(ctx->digest);
memset(ctx, 0, sizeof(*ctx));
}
int requestor_tsig_sign_packet(requestor_tsig_ctx_t *ctx, knot_pkt_t *packet)
int tsig_sign_packet(tsig_ctx_t *ctx, knot_pkt_t *packet)
{
if (!ctx || !packet) {
return KNOT_EINVAL;
......@@ -54,14 +47,8 @@ int requestor_tsig_sign_packet(requestor_tsig_ctx_t *ctx, knot_pkt_t *packet)
}
int ret = KNOT_ERROR;
if (ctx->digest_size == 0) {
ctx->digest_size = knot_tsig_digest_length(ctx->key->algorithm);
ctx->digest = malloc(ctx->digest_size);
if (!ctx->digest) {
return KNOT_ENOMEM;
}
ret = knot_tsig_sign(packet->wire, &packet->size, packet->max_size,
NULL, 0,
ctx->digest, &ctx->digest_size,
......@@ -79,7 +66,23 @@ int requestor_tsig_sign_packet(requestor_tsig_ctx_t *ctx, knot_pkt_t *packet)
return ret;
}
int requestor_tsig_verify_packet(requestor_tsig_ctx_t *ctx, knot_pkt_t *packet)
static int update_ctx_after_verify(tsig_ctx_t *ctx, knot_rrset_t *tsig_rr)
{
assert(ctx);
assert(tsig_rr);
if (ctx->digest_size != tsig_rdata_mac_length(tsig_rr)) {
return KNOT_EMALF;
}
memcpy(ctx->digest, tsig_rdata_mac(tsig_rr), ctx->digest_size);
ctx->last_signed = tsig_rdata_time_signed(tsig_rr);
ctx->unsigned_count = 0;
return KNOT_EOK;
}
int tsig_verify_packet(tsig_ctx_t *ctx, knot_pkt_t *packet)
{
if (!ctx || !packet) {
return KNOT_EINVAL;
......@@ -89,7 +92,40 @@ int requestor_tsig_verify_packet(requestor_tsig_ctx_t *ctx, knot_pkt_t *packet)
return KNOT_EOK;
}
#warning "TODO: TSIG verify invocation."
//return KNOT_ENOTSUP;
if (packet->tsig_rr == NULL) {
ctx->unsigned_count += 1;
return KNOT_EOK;
}
int ret = KNOT_ERROR;
if (ctx->last_signed == 0) {
ret = knot_tsig_client_check(packet->tsig_rr, packet->wire,
packet->size, ctx->digest,
ctx->digest_size, ctx->key, 0);
} else {
ret = knot_tsig_client_check_next(packet->tsig_rr, packet->wire,
packet->size, ctx->digest,
ctx->digest_size, ctx->key,
ctx->last_signed);
}
if (ret != KNOT_EOK) {
return ret;
}
ret = update_ctx_after_verify(ctx, packet->tsig_rr);
if (ret != KNOT_EOK) {
return ret;
}
return KNOT_EOK;
}
unsigned tsig_unsigned_count(tsig_ctx_t *ctx)
{
if (!ctx) {
return -1;
}
return ctx->unsigned_count;
}
......@@ -21,17 +21,26 @@
#include "libknot/packet/pkt.h"
#include "libknot/rdata/tsig.h"
#include "libknot/tsig-op.h"
typedef struct requestor_tsig_ctx {
#define TSIG_MAX_DIGEST_SIZE 64
typedef struct tsig_ctx {
const knot_tsig_key_t *key;
uint8_t *digest;
uint8_t digest[TSIG_MAX_DIGEST_SIZE];
size_t digest_size;
} requestor_tsig_ctx_t;
void requestor_tsig_init(requestor_tsig_ctx_t *ctx, const knot_tsig_key_t *key);
uint64_t last_signed;
unsigned unsigned_count;
} tsig_ctx_t;
void tsig_init(tsig_ctx_t *ctx, const knot_tsig_key_t *key);
void requestor_tsig_cleanup(requestor_tsig_ctx_t *ctx);
int tsig_sign_packet(tsig_ctx_t *ctx, knot_pkt_t *packet);
int requestor_tsig_sign_packet(requestor_tsig_ctx_t *ctx, knot_pkt_t *packet);
int tsig_verify_packet(tsig_ctx_t *ctx, knot_pkt_t *packet);
int requestor_tsig_verify_packet(requestor_tsig_ctx_t *ctx, knot_pkt_t *packet);
/*!
* \brief Get number of unsigned packets since the last signed one.
*/
unsigned tsig_unsigned_count(tsig_ctx_t *ctx);
......@@ -34,6 +34,7 @@
#include "knot/nameserver/update.h"
#include "knot/nameserver/notify.h"
#include "knot/nameserver/requestor.h"
#include "knot/nameserver/tsig_ctx.h"
#include "knot/nameserver/process_answer.h"
/* ------------------------- bootstrap timer logic -------------------------- */
......@@ -108,6 +109,19 @@ static int zone_query_execute(zone_t *zone, uint16_t pkt_type, const conf_iface_
knot_pkt_put(query, COMPR_HINT_QNAME, &soa_rr, 0);
}
/* Answer processing parameters. */
struct process_answer_param param = { 0 };
param.zone = zone;
param.query = query;
param.remote = &remote->addr;
tsig_init(&param.tsig_ctx, remote->key);
ret = tsig_sign_packet(&param.tsig_ctx, query);
if (ret != KNOT_EOK) {
mp_delete(mm.ctx);
return ret;
}
/* Create requestor instance. */
struct requestor re;
requestor_init(&re, NS_PROC_ANSWER, &mm);
......@@ -115,13 +129,10 @@ static int zone_query_execute(zone_t *zone, uint16_t pkt_type, const conf_iface_
/* Create a request. */
struct request *req = requestor_make(&re, remote, query);
if (req == NULL) {
mp_delete(mm.ctx);
return KNOT_ENOMEM;
}
struct process_answer_param param;
param.zone = zone;
param.query = query;
param.remote = &remote->addr;
requestor_enqueue(&re, req, &param);
/* Send the queries and process responses. */
......@@ -330,7 +341,7 @@ static int event_update(zone_t *zone)
/* Create minimal query data context. */
struct process_query_param param = {0};
param.remote = &update->remote->addr;
param.remote = &update->remote;
struct query_data qdata = {0};
qdata.param = &param;
qdata.query = update->query;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment