Commit 117198ff authored by Marek Vavruša's avatar Marek Vavruša

update: UPDATE forwarding

parent de2e61ce
......@@ -29,7 +29,7 @@
#include "knot/nameserver/process_query.h"
#include "knot/nameserver/tsig_ctx.h"
/* Query processing module implementation. */
/* Processing module implementation. */
const knot_process_module_t *process_answer_get_module(void);
#define NS_PROC_ANSWER process_answer_get_module()
#define NS_PROC_ANSWER_ID 2
......@@ -42,7 +42,7 @@ const knot_process_module_t *process_answer_get_module(void);
} while(0)
/*!
* \brief Answer processing parameters.
* \brief Processing module parameters.
*/
struct process_answer_param {
zone_t *zone; /*!< Answer bailiwick. */
......@@ -52,7 +52,7 @@ struct process_answer_param {
};
/*!
* \brief Answer processing context.
* \brief Processing module context.
*/
struct answer_data {
/* Extensions. */
......
......@@ -396,7 +396,7 @@ static int query_internet(knot_pkt_t *pkt, knot_process_t *ctx)
next_state = ixfr_query(pkt, data);
break;
case KNOT_QUERY_UPDATE:
next_state = update_answer(pkt, data);
next_state = update_query_process(pkt, data);
break;
default:
/* Nothing else is supported. */
......
......@@ -10,19 +10,17 @@
#include "libknot/tsig-op.h"
#include "knot/zone/zone.h"
#include "knot/zone/events.h"
#include "knot/server/tcp-handler.h"
#include "knot/server/udp-handler.h"
#include "knot/nameserver/requestor.h"
#include "knot/nameserver/capture.h"
#include "libknot/dnssec/random.h"
/* UPDATE-specific logging (internal, expects 'qdata' variable set). */
#define UPDATE_LOG(severity, msg...) \
QUERY_LOG(severity, qdata, "UPDATE", msg)
static int update_forward(knot_pkt_t *pkt, struct query_data *qdata)
{
/*! \todo ref #244 This will be reimplemented later. */
qdata->rcode = KNOT_RCODE_NOTIMPL;
return NS_PROC_FAIL;
}
int update_answer(knot_pkt_t *pkt, struct query_data *qdata)
int update_query_process(knot_pkt_t *pkt, struct query_data *qdata)
{
/* RFC1996 require SOA question. */
NS_NEED_QTYPE(qdata, KNOT_RRTYPE_SOA, KNOT_RCODE_FORMERR);
......@@ -30,14 +28,8 @@ int update_answer(knot_pkt_t *pkt, struct query_data *qdata)
/* Check valid zone. */
NS_NEED_ZONE(qdata, KNOT_RCODE_NOTAUTH);
/* Allow pass-through of an unknown TSIG in DDNS forwarding
(must have zone). */
zone_t *zone = (zone_t *)qdata->zone;
if (zone_master(zone) != NULL) {
return update_forward(pkt, qdata);
}
/* Need valid transaction security. */
zone_t *zone = (zone_t *)qdata->zone;
NS_NEED_AUTH(&zone->conf->acl.update_in, qdata);
/* Check expiration. */
NS_NEED_ZONE_CONTENTS(qdata, KNOT_RCODE_SERVFAIL);
......@@ -226,7 +218,7 @@ static int process_authenticated(uint16_t *rcode, struct query_data *qdata)
}
int update_process_query(knot_pkt_t *pkt, struct query_data *qdata)
static int execute_query(knot_pkt_t *pkt, struct query_data *qdata)
{
if (pkt == NULL || qdata == NULL) {
return KNOT_EINVAL;
......@@ -268,4 +260,94 @@ int update_process_query(knot_pkt_t *pkt, struct query_data *qdata)
return KNOT_EOK;
}
static int forward_query(knot_pkt_t *pkt, struct query_data *qdata)
{
/* Create requestor instance. */
struct requestor re;
requestor_init(&re, NS_PROC_CAPTURE, qdata->mm);
/* Fetch primary master. */
const conf_iface_t *master = zone_master(qdata->zone);
/* Copy request and assign new ID. */
knot_pkt_t *query = knot_pkt_new(NULL, pkt->max_size, qdata->mm);
if (knot_pkt_copy(query, qdata->query) != KNOT_EOK) {
return KNOT_ENOMEM;
}
knot_wire_set_id(query->wire, knot_random_uint16_t());
knot_tsig_append(query->wire, &query->size, query->max_size, query->tsig_rr);
/* Create a request. */
struct request *req = requestor_make(&re, master, query);
if (req == NULL) {
knot_pkt_free(&query);
return KNOT_ENOMEM;
}
/* Enqueue and execute request. */
struct process_capture_param param;
param.sink = pkt;
int ret = requestor_enqueue(&re, req, &param);
if (ret == KNOT_EOK) {
struct timeval tv = { conf()->max_conn_reply, 0 };
ret = requestor_exec(&re, &tv);
}
requestor_clear(&re);
/* Restore message ID and TSIG. */
knot_wire_set_id(pkt->wire, knot_wire_get_id(qdata->query->wire));
knot_tsig_append(pkt->wire, &pkt->size, pkt->max_size, pkt->tsig_rr);
/* Set RCODE if forwarding failed. */
if (ret != KNOT_EOK) {
knot_wire_set_rcode(pkt->wire, KNOT_RCODE_SERVFAIL);
UPDATE_LOG(LOG_INFO, "Failed to forward UPDATE to master.");
} else {
UPDATE_LOG(LOG_INFO, "Forwarded UPDATE to master.");
}
return ret;
}
#undef UPDATE_LOG
int update_execute(zone_t *zone, struct request_data *update)
{
knot_pkt_t *resp = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, NULL);
if (resp == NULL) {
return KNOT_ENOMEM;
}
/* Initialize query response. */
assert(update->query);
knot_pkt_init_response(resp, update->query);
/* Create minimal query data context. */
struct process_query_param param = { 0 };
param.remote = &update->remote;
struct query_data qdata = { 0 };
qdata.param = &param;
qdata.query = update->query;
qdata.zone = zone;
/* Process the update query. */
int ret = KNOT_EOK;
if (zone_master(zone) != NULL) {
ret = forward_query(resp, &qdata);
} else {
ret = execute_query(resp, &qdata);
}
/* Send response. */
if (net_is_connected(update->fd)) {
tcp_send_msg(update->fd, resp->wire, resp->size);
} else {
udp_send_msg(update->fd, resp->wire, resp->size,
(struct sockaddr *)param.remote);
}
knot_pkt_free(&resp);
return ret;
}
......@@ -34,21 +34,19 @@ struct query_data;
/*!
* \brief UPDATE query processing module.
*
* \retval FAIL if it encountered an error.
* \retval DONE if finished.
* \return NS_PROC_* processing states
*/
int update_answer(knot_pkt_t *pkt, struct query_data *qdata);
int update_query_process(knot_pkt_t *pkt, struct query_data *qdata);
/*!
* \brief Processes serialized packet with DDNS. Function expects that the
* query is already authenticated and TSIG signature is verified.
*
* \param pkt Prepared response packet.
* \param qdata Minimal query data context.
* \param zone Updated zone.
* \param update UPDATE request.
*
* \return KNOT_E*
*/
int update_process_query(knot_pkt_t *pkt, struct query_data *qdata);
int update_execute(zone_t *zone, struct request_data *update);
/*! @} */
......@@ -388,43 +388,17 @@ static int event_update(zone_t *zone)
{
assert(zone);
knot_pkt_t *resp = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, NULL);
if (resp == NULL) {
return KNOT_ENOMEM;
}
struct request_data *update = zone_update_dequeue(zone);
if (update == NULL) {
return KNOT_EOK;
}
/* Initialize query response. */
assert(update->query);
knot_pkt_init_response(resp, update->query);
/* Create minimal query data context. */
struct process_query_param param = { 0 };
param.remote = &update->remote;
struct query_data qdata = { 0 };
qdata.param = &param;
qdata.query = update->query;
qdata.zone = zone;
/* Process the update query. */
int ret = update_process_query(resp, &qdata);
UNUSED(ret); /* Don't care about the Knot code, RCODE is set. */
/* Send response. */
if (net_is_connected(update->fd)) {
tcp_send_msg(update->fd, resp->wire, resp->size);
} else {
udp_send_msg(update->fd, resp->wire, resp->size,
(struct sockaddr *)param.remote);
}
/* Forward if zone has master, or execute. */
int ret = update_execute(zone, update);
UNUSED(ret);
/* Cleanup. */
close(update->fd);
knot_pkt_free(&resp);
knot_pkt_free(&update->query);
free(update);
......
#!/usr/bin/env python3
'''Test for DDNS forwarding'''
from dnstest.test import Test
t = Test()
master = t.server("bind")
slave = t.server("knot")
zone = t.zone("example.com.")
t.link(zone, master, slave, ddns=True)
t.start()
master.zones_wait(zone)
slave.zones_wait(zone)
# OK
update = slave.update(zone)
update.add("forwarded.example.com.", 1, "TXT", "forwarded")
update.send("NOERROR")
resp = master.dig("forwarded.example.com.", "TXT")
resp.check("forwarded")
t.sleep(2)
t.xfr_diff(master, slave, zone)
# NAME out of zone
update = slave.update(zone)
update.add("forwarded.", 1, "TXT", "forwarded")
update.send("NOTZONE")
resp = master.dig("forwarded.", "TXT")
resp.check(rcode="REFUSED")
t.sleep(2)
t.xfr_diff(master, slave, zone)
t.end()
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