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

requestor: support for TSIG signing (no verification yet)

ref #209
parent 6977e02b
......@@ -127,6 +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/update.c
src/knot/nameserver/update.h
src/knot/other/debug.h
......
......@@ -240,6 +240,8 @@ 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 \
......
......@@ -103,8 +103,6 @@ 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);
#warning TODO: check TSIG here?
/* Call appropriate processing handler. */
int next_state = NS_PROC_NOOP;
switch(knot_pkt_type(pkt)) {
......
......@@ -221,7 +221,7 @@ int process_query_err(knot_pkt_t *pkt, knot_process_t *ctx)
bool process_query_acl_check(acl_t *acl, struct query_data *qdata)
{
knot_pkt_t *query = qdata->query;
struct sockaddr_storage *query_source = qdata->param->remote;
const struct sockaddr_storage *query_source = qdata->param->remote;
const knot_dname_t *key_name = NULL;
knot_tsig_algorithm_t key_alg = KNOT_TSIG_ALG_NULL;
......
......@@ -65,7 +65,7 @@ struct process_query_param {
uint16_t proc_flags;
server_t *server;
int socket;
struct sockaddr_storage *remote;
const struct sockaddr_storage *remote;
};
/*! \brief Query processing intermediate data. */
......
......@@ -14,6 +14,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "knot/nameserver/requestor.h"
#include "knot/nameserver/process_answer.h"
#include "knot/server/net.h"
......@@ -139,11 +141,10 @@ bool requestor_finished(struct requestor *requestor)
}
struct request *requestor_make(struct requestor *requestor,
const struct sockaddr_storage *from,
const struct sockaddr_storage *to,
const conf_iface_t *remote,
knot_pkt_t *query)
{
if (requestor == NULL || query == NULL || to == NULL) {
if (requestor == NULL || query == NULL || remote == NULL) {
return NULL;
}
......@@ -154,10 +155,10 @@ struct request *requestor_make(struct requestor *requestor,
}
request->state = NS_PROC_DONE;
memcpy(&request->data.origin, from, sizeof(struct sockaddr_storage));
memcpy(&request->data.remote, to, sizeof(struct sockaddr_storage));
request->data.remote = remote;
request->data.fd = -1;
request->data.query = query;
requestor_tsig_init(&request->data.tsig_ctx, remote->key);
return request;
}
......@@ -168,8 +169,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,
&request->data.origin, O_NONBLOCK);
int fd = net_connected_socket(SOCK_STREAM, &request->data.remote->addr,
&request->data.remote->via, O_NONBLOCK);
if (fd < 0) {
return KNOT_ECONN;
}
......@@ -197,12 +198,39 @@ 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;
......@@ -217,6 +245,11 @@ 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,6 +18,7 @@
#include "knot/nameserver/process_query.h"
#include "knot/nameserver/process_answer.h"
#include "knot/nameserver/requestor_tsig.h"
#include "common/lists.h"
struct request;
......@@ -40,8 +41,9 @@ struct requestor {
struct request_data {
node_t node;
int fd;
struct sockaddr_storage remote, origin;
const conf_iface_t *remote;
knot_pkt_t *query;
requestor_tsig_ctx_t tsig_ctx;
};
/*!
......@@ -60,8 +62,7 @@ bool requestor_finished(struct requestor *requestor);
/*! \brief Make request out of endpoints and query. */
struct request *requestor_make(struct requestor *requestor,
const struct sockaddr_storage *from,
const struct sockaddr_storage *to,
const conf_iface_t *remote,
knot_pkt_t *query);
/*!
......
/* 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 <string.h>
#include <stdint.h>
#include <stdlib.h>
#include "common/errcode.h"
#include "libknot/rdata/tsig.h"
#include "libknot/tsig-op.h"
#include "knot/nameserver/requestor_tsig.h"
void requestor_tsig_init(requestor_tsig_ctx_t *ctx, const knot_tsig_key_t *key)
{
if (!ctx) {
return;
}
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)
{
if (!ctx || !packet) {
return KNOT_EINVAL;
}
if (ctx->key == NULL) {
return KNOT_EOK;
}
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,
ctx->key, 0, 0);
} else {
uint8_t previous_digest[ctx->digest_size];
memcpy(previous_digest, ctx->digest, ctx->digest_size);
ret = knot_tsig_sign_next(packet->wire, &packet->size, packet->max_size,
previous_digest, ctx->digest_size,
ctx->digest, &ctx->digest_size,
ctx->key, packet->wire, packet->size);
}
return ret;
}
int requestor_tsig_verify_packet(requestor_tsig_ctx_t *ctx, knot_pkt_t *packet)
{
if (!ctx || !packet) {
return KNOT_EINVAL;
}
if (ctx->key == NULL) {
return KNOT_EOK;
}
#warning "TODO: TSIG verify invocation."
//return KNOT_ENOTSUP;
return KNOT_EOK;
}
/* 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/>.
*/
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include "libknot/packet/pkt.h"
#include "libknot/rdata/tsig.h"
typedef struct requestor_tsig_ctx {
const knot_tsig_key_t *key;
uint8_t *digest;
size_t digest_size;
} requestor_tsig_ctx_t;
void requestor_tsig_init(requestor_tsig_ctx_t *ctx, const knot_tsig_key_t *key);
void requestor_tsig_cleanup(requestor_tsig_ctx_t *ctx);
int requestor_tsig_sign_packet(requestor_tsig_ctx_t *ctx, knot_pkt_t *packet);
int requestor_tsig_verify_packet(requestor_tsig_ctx_t *ctx, knot_pkt_t *packet);
......@@ -113,7 +113,7 @@ static int zone_query_execute(zone_t *zone, uint16_t pkt_type, const conf_iface_
requestor_init(&re, NS_PROC_ANSWER, &mm);
/* Create a request. */
struct request *req = requestor_make(&re, &remote->via, &remote->addr, query);
struct request *req = requestor_make(&re, remote, query);
if (req == NULL) {
return KNOT_ENOMEM;
}
......@@ -330,7 +330,7 @@ static int event_update(zone_t *zone)
/* Create minimal query data context. */
struct process_query_param param = {0};
param.remote = &update->remote;
param.remote = &update->remote->addr;
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