Commit ecc8ccd8 authored by Marek Vavrusa's avatar Marek Vavrusa

Dynamic update forwarding, except unauthorized forwarding.

Implemented as a XFR handler task, in a same way as NOTIFY queries
for example. It also allows to change TSIG keys between hops,
or no keys at all - this clear AD flag.
Like: client <--key:A--> f1 <--key:B--> f2 <--NOKEY--> MASTER
Forwarded queries also keep socket mode.

To do:
According to RFC2845, it should also forward queries with no
known key intact to the next forwarded, this is not done yet.

refs #1130
parent cdd5da92
......@@ -256,7 +256,7 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen
// KNOT_RCODE_NOTIMPL,
// qbuf, &resp_len);
res = zones_process_update(ns, packet, &addr, qbuf, &resp_len,
NS_TRANSPORT_TCP);
fd, NS_TRANSPORT_TCP);
// res = KNOT_EOK;
break;
......
......@@ -167,7 +167,7 @@ int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len,
// KNOT_RCODE_NOTIMPL, qbuf,
// resp_len);
res = zones_process_update(ns, packet, addr, qbuf, resp_len,
NS_TRANSPORT_UDP);
fd, NS_TRANSPORT_UDP);
break;
/* Unhandled opcodes. */
......
......@@ -34,6 +34,7 @@
#include "knot/server/udp-handler.h"
#include "knot/server/tcp-handler.h"
#include "libknot/updates/xfr-in.h"
#include "libknot/util/wire.h"
#include "knot/server/zones.h"
#include "libknot/tsig-op.h"
#include "common/evsched.h"
......@@ -256,7 +257,7 @@ static int xfr_process_udp_resp(xfrworker_t *w, int fd, knot_ns_xfr_t *data)
if (n <= 0) {
return ret;
}
// parse packet
knot_packet_t *re = knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
if (re == NULL) {
......@@ -269,12 +270,18 @@ static int xfr_process_udp_resp(xfrworker_t *w, int fd, knot_ns_xfr_t *data)
knot_packet_free(&re);
return KNOT_EOK; /* Ignore */
}
/* Ignore other packets. */
if (rt != KNOT_RESPONSE_NORMAL && rt != KNOT_RESPONSE_NOTIFY) {
switch(rt) {
case KNOT_RESPONSE_NORMAL:
case KNOT_RESPONSE_NOTIFY:
case KNOT_RESPONSE_UPDATE:
break;
default:
knot_packet_free(&re);
return KNOT_EOK; /* Ignore */
}
ret = knot_packet_parse_rest(re);
if (ret != KNOT_EOK) {
knot_packet_free(&re);
......@@ -301,6 +308,7 @@ static int xfr_process_udp_resp(xfrworker_t *w, int fd, knot_ns_xfr_t *data)
}
// process response
size_t qlen = n;
switch(rt) {
case KNOT_RESPONSE_NORMAL:
ret = zones_process_response(w->ns, &data->addr, re,
......@@ -310,10 +318,18 @@ static int xfr_process_udp_resp(xfrworker_t *w, int fd, knot_ns_xfr_t *data)
ret = notify_process_response(w->ns, re, &data->addr,
data->wire, &resp_len);
break;
case KNOT_RESPONSE_UPDATE:
ret = zones_process_update_response(w->ns, data, re, data->wire,
&qlen, resp_len);
if (ret == KNOT_EOK) {
log_server_info("%s Forwarded response.\n",
data->msgpref);
}
break;
default:
break;
}
knot_packet_free(&re);
/* Check up-to-date zone. */
......@@ -348,6 +364,7 @@ static void xfr_sweep(fdset_t *set, int fd, void *data)
switch(t->type) {
case XFR_TYPE_SOA:
case XFR_TYPE_NOTIFY:
case XFR_TYPE_FORWARD:
xfr_udp_timeout(t);
break;
default:
......@@ -615,8 +632,13 @@ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf,
data->wire_size = buflen;
/* Handle SOA/NOTIFY responses. */
if (data->type == XFR_TYPE_NOTIFY || data->type == XFR_TYPE_SOA) {
switch(data->type) {
case XFR_TYPE_NOTIFY:
case XFR_TYPE_SOA:
case XFR_TYPE_FORWARD:
return xfr_process_udp_resp(w, fd, data);
default:
break;
}
/* Read DNS/TCP packet. */
......@@ -1056,6 +1078,9 @@ static int xfr_update_msgpref(knot_ns_xfr_t *req, const char *keytag)
case XFR_TYPE_SOA:
pformat = "SOA query of '%s' to %s:";
break;
case XFR_TYPE_FORWARD:
pformat = "UPDATE forwarded query of '%s' to %s:";
break;
default:
pformat = "UNKNOWN query '%s' from %s:";
break;
......@@ -1455,6 +1480,7 @@ static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen)
break;
case XFR_TYPE_SOA:
case XFR_TYPE_NOTIFY:
case XFR_TYPE_FORWARD:
/* Register task. */
task = xfr_register_task(w, &xfr);
if (!task) {
......@@ -1466,7 +1492,13 @@ static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen)
fdset_set_watchdog(w->fdset, task->session,
conf()->max_conn_reply);
rcu_read_unlock();
log_server_info("%s Query issued.\n", xfr.msgpref);
if (xfr.type == XFR_TYPE_FORWARD) {
log_server_info("%s Forwarded query.\n",
xfr.msgpref);
} else {
log_server_info("%s Query issued.\n",
xfr.msgpref);
}
ret = KNOT_EOK;
}
break;
......
This diff is collapsed.
......@@ -79,13 +79,11 @@ typedef struct zonedata_t
int next_id; /*!< ID of the next awaited SOA resp.*/
uint32_t bootstrap_retry;/*!< AXFR/IN bootstrap retry. */
unsigned scheduled;/*!< Scheduled operations. */
int has_master; /*!< True if it has master set. */
} xfr_in;
/*! \brief List of pending NOTIFY events. */
list notify_pending;
/*! \brief List of fds with pending SOA queries. */
int soa_pending;
/*! \brief Zone IXFR history. */
journal_t *ixfr_db;
......@@ -162,7 +160,7 @@ int zones_normal_query_answer(knot_nameserver_t *nameserver,
int zones_process_update(knot_nameserver_t *nameserver,
knot_packet_t *query, const sockaddr_t *addr,
uint8_t *resp_wire, size_t *rsize,
knot_ns_transport_t transport);
int fd, knot_ns_transport_t transport);
/*!
* \brief Processes normal response packet.
......@@ -333,6 +331,15 @@ int zones_timers_update(knot_zone_t *zone, conf_zone_t *cfzone, evsched_t *sch);
*/
int zones_cancel_notify(zonedata_t *zd, notify_ev_t *ev);
/*!
* \brief Processes forwarded UPDATE response packet.
* \todo #1291 move to appropriate section (DDNS).
*/
int zones_process_update_response(knot_nameserver_t *ns,
knot_ns_xfr_t *data,
knot_packet_t *packet, uint8_t *rwire,
size_t *rsize, size_t maxlen);
#endif // _KNOTD_ZONES_H_
/*! @} */
......@@ -57,7 +57,8 @@ typedef enum knot_packet_type {
KNOT_RESPONSE_NORMAL, /*!< Normal response. */
KNOT_RESPONSE_AXFR, /*!< AXFR transfer response. */
KNOT_RESPONSE_IXFR, /*!< IXFR transfer response. */
KNOT_RESPONSE_NOTIFY /*!< NOTIFY response. */
KNOT_RESPONSE_NOTIFY, /*!< NOTIFY response. */
KNOT_RESPONSE_UPDATE /*!< Dynamic update response. */
} knot_packet_type_t;
/*
......
......@@ -3200,7 +3200,7 @@ int knot_ns_parse_packet(const uint8_t *query_wire, size_t qsize,
if(knot_packet_is_query(packet)) {
*type = KNOT_QUERY_UPDATE;
} else {
return KNOT_RCODE_FORMERR;
*type = KNOT_RESPONSE_UPDATE;
}
break;
default:
......@@ -4283,9 +4283,18 @@ int knot_ns_process_update(const knot_packet_t *query,
/*----------------------------------------------------------------------------*/
int knot_ns_create_forward_query(const knot_packet_t *query,
uint8_t *query_wire, size_t *size)
uint8_t *query_wire, size_t *size,
knot_key_t *tsig_key,
uint8_t **digest, size_t *digest_len)
{
// just copy the wireformat of the query and set a new random ID to it
/* Forward UPDATE query:
* assign a new packet id
* if has tsig:
* clear tsig and keep digest
* resign if tsig is present on the next hop
*/
int ret = KNOT_EOK;
size_t maxlen = *size;
if (knot_packet_size(query) > *size) {
return KNOT_ESPACE;
}
......@@ -4293,10 +4302,33 @@ int knot_ns_create_forward_query(const knot_packet_t *query,
memcpy(query_wire, knot_packet_wireformat(query),
knot_packet_size(query));
*size = knot_packet_size(query);
knot_wire_set_id(query_wire, knot_random_id());
/* Remove previous signature if exists. */
const knot_rrset_t *tsig_rr = knot_packet_tsig(query);
uint16_t arc = knot_wire_get_arcount(query_wire);
if (arc > 0) {
knot_wire_set_arcount(query_wire, --arc);
}
if (tsig_rr) {
size_t tsig_len = tsig_wire_actsize(tsig_rr);
*size -= tsig_len;
}
/* Resign if TSIG for the next hop is set. */
if (tsig_key && tsig_key->name) {
/* Store digest of forwarded query for validation. */
*digest_len = tsig_alg_digest_length(tsig_key->algorithm);
*digest = (uint8_t *)malloc(*digest_len);
if (*digest == NULL) {
*size = 0;
return KNOT_ENOMEM;
}
ret = knot_tsig_sign(query_wire, size, maxlen, NULL, 0,
*digest, digest_len, tsig_key, 0, 0);
}
return KNOT_EOK;
return ret;
}
/*----------------------------------------------------------------------------*/
......
......@@ -121,6 +121,10 @@ typedef struct knot_ns_xfr {
uint8_t *digest; /*!< Buffer for counting digest. */
size_t digest_size; /*!< Size of the digest. */
size_t digest_max_size; /*!< Size of the buffer. */
/*! \note [DDNS] Update forwarding fields. */
int fwd_src_fd; /*!< Query originator fd. */
knot_key_t *fwd_src_tsig; /*!< Key used by originator. */
uint16_t tsig_rcode;
uint64_t tsig_prev_time_signed;
......@@ -158,13 +162,14 @@ typedef enum knot_ns_transport {
*/
typedef enum knot_ns_xfr_type_t {
/* DNS events. */
XFR_TYPE_AIN = 1 << 0, /*!< AXFR-IN request (start transfer). */
XFR_TYPE_AOUT= 1 << 1, /*!< AXFR-OUT request (incoming transfer). */
XFR_TYPE_IIN = 1 << 2, /*!< IXFR-IN request (start transfer). */
XFR_TYPE_IOUT = 1 << 3, /*!< IXFR-OUT request (incoming transfer). */
XFR_TYPE_SOA = 1 << 4, /*!< Pending SOA request. */
XFR_TYPE_AIN = 1 << 0, /*!< AXFR-IN request (start transfer). */
XFR_TYPE_AOUT= 1 << 1, /*!< AXFR-OUT request (incoming transfer). */
XFR_TYPE_IIN = 1 << 2, /*!< IXFR-IN request (start transfer). */
XFR_TYPE_IOUT = 1 << 3, /*!< IXFR-OUT request (incoming transfer). */
XFR_TYPE_SOA = 1 << 4, /*!< Pending SOA request. */
XFR_TYPE_NOTIFY = 1 << 5, /*!< Pending NOTIFY query. */
XFR_TYPE_UPDATE = 1 << 6 /*!< UPDATE request (incoming UPDATE). */
XFR_TYPE_UPDATE = 1 << 6, /*!< UPDATE request (incoming UPDATE). */
XFR_TYPE_FORWARD = 1 << 7 /*!< UPDATE forward request. */
} knot_ns_xfr_type_t;
/*----------------------------------------------------------------------------*/
......@@ -349,7 +354,9 @@ int knot_ns_process_update(const knot_packet_t *query,
knot_changeset_t *changeset, knot_rcode_t *rcode);
int knot_ns_create_forward_query(const knot_packet_t *query,
uint8_t *query_wire, size_t *size);
uint8_t *query_wire, size_t *size,
knot_key_t *tsig_key,
uint8_t **digest, size_t *digest_len);
int knot_ns_process_forward_response(const knot_packet_t *response,
uint16_t original_id,
......
......@@ -33,6 +33,7 @@
#include "rrset.h"
#include "dname.h"
#include "consts.h"
#include "common/lists.h"
typedef struct knot_ddns_prereq_t {
knot_rrset_t **exist;
......
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