Commit 2ce2a64d authored by Daniel Salzman's avatar Daniel Salzman

zone: add request EDNS option support

parent c4d6f771
...@@ -482,6 +482,7 @@ zone: ...@@ -482,6 +482,7 @@ zone:
max\-journal\-size: SIZE max\-journal\-size: SIZE
dnssec\-signing: BOOL dnssec\-signing: BOOL
kasp\-db: STR kasp\-db: STR
request\-edns\-option: INT:[HEXSTR]
serial\-policy: increment | unixtime serial\-policy: increment | unixtime
module: STR/STR ... module: STR/STR ...
.ft P .ft P
...@@ -647,6 +648,12 @@ A KASP database path. Non absolute path is relative to ...@@ -647,6 +648,12 @@ A KASP database path. Non absolute path is relative to
\fI\%storage\fP\&. \fI\%storage\fP\&.
.sp .sp
Default: \fI\%storage\fP/keys Default: \fI\%storage\fP/keys
.SS request\-edns\-option
.sp
An arbitrary EDNS0 option which is included into a server request (AXFR, IXFR,
SOA, or NOTIFY). The value is in the option_code:option_data format.
.sp
Default: empty
.SS serial\-policy .SS serial\-policy
.sp .sp
Specifies how the zone serial is updated after a dynamic update or Specifies how the zone serial is updated after a dynamic update or
......
...@@ -562,6 +562,7 @@ Definition of zones served by the server. ...@@ -562,6 +562,7 @@ Definition of zones served by the server.
max-journal-size: SIZE max-journal-size: SIZE
dnssec-signing: BOOL dnssec-signing: BOOL
kasp-db: STR kasp-db: STR
request-edns-option: INT:[HEXSTR]
serial-policy: increment | unixtime serial-policy: increment | unixtime
module: STR/STR ... module: STR/STR ...
...@@ -759,6 +760,16 @@ A KASP database path. Non absolute path is relative to ...@@ -759,6 +760,16 @@ A KASP database path. Non absolute path is relative to
Default: :ref:`storage<zone_storage>`/keys Default: :ref:`storage<zone_storage>`/keys
.. _zone_request_edns_option:
request-edns-option
-------------------
An arbitrary EDNS0 option which is included into a server request (AXFR, IXFR,
SOA, or NOTIFY). The value is in the option_code:option_data format.
Default: empty
.. _zone_serial-policy: .. _zone_serial-policy:
serial-policy serial-policy
......
...@@ -133,23 +133,24 @@ static const yp_item_t desc_remote[] = { ...@@ -133,23 +133,24 @@ static const yp_item_t desc_remote[] = {
}; };
#define ZONE_ITEMS \ #define ZONE_ITEMS \
{ C_FILE, YP_TSTR, YP_VNONE }, \ { C_FILE, YP_TSTR, YP_VNONE }, \
{ C_STORAGE, YP_TSTR, YP_VSTR = { STORAGE_DIR } }, \ { C_STORAGE, YP_TSTR, YP_VSTR = { STORAGE_DIR } }, \
{ C_MASTER, YP_TREF, YP_VREF = { C_RMT }, YP_FMULTI, { check_ref } }, \ { C_MASTER, YP_TREF, YP_VREF = { C_RMT }, YP_FMULTI, { check_ref } }, \
{ C_DDNS_MASTER, YP_TREF, YP_VREF = { C_RMT }, YP_FNONE, { check_ref } }, \ { C_DDNS_MASTER, YP_TREF, YP_VREF = { C_RMT }, YP_FNONE, { check_ref } }, \
{ C_NOTIFY, YP_TREF, YP_VREF = { C_RMT }, YP_FMULTI, { check_ref } }, \ { C_NOTIFY, YP_TREF, YP_VREF = { C_RMT }, YP_FMULTI, { check_ref } }, \
{ C_ACL, YP_TREF, YP_VREF = { C_ACL }, YP_FMULTI, { check_ref } }, \ { C_ACL, YP_TREF, YP_VREF = { C_ACL }, YP_FMULTI, { check_ref } }, \
{ C_SEM_CHECKS, YP_TBOOL, YP_VNONE }, \ { C_SEM_CHECKS, YP_TBOOL, YP_VNONE }, \
{ C_DISABLE_ANY, YP_TBOOL, YP_VNONE }, \ { C_DISABLE_ANY, YP_TBOOL, YP_VNONE }, \
{ C_ZONEFILE_SYNC, YP_TINT, YP_VINT = { -1, INT32_MAX, 0, YP_STIME } }, \ { C_ZONEFILE_SYNC, YP_TINT, YP_VINT = { -1, INT32_MAX, 0, YP_STIME } }, \
{ C_IXFR_DIFF, YP_TBOOL, YP_VNONE }, \ { C_IXFR_DIFF, YP_TBOOL, YP_VNONE }, \
{ C_MAX_JOURNAL_SIZE, YP_TINT, YP_VINT = { 0, INT64_MAX, INT64_MAX, YP_SSIZE } }, \ { C_MAX_JOURNAL_SIZE, YP_TINT, YP_VINT = { 0, INT64_MAX, INT64_MAX, YP_SSIZE } }, \
{ C_DNSSEC_SIGNING, YP_TBOOL, YP_VNONE }, \ { C_DNSSEC_SIGNING, YP_TBOOL, YP_VNONE }, \
{ C_KASP_DB, YP_TSTR, YP_VSTR = { "keys" } }, \ { C_KASP_DB, YP_TSTR, YP_VSTR = { "keys" } }, \
{ C_SERIAL_POLICY, YP_TOPT, YP_VOPT = { serial_policies, SERIAL_POLICY_INCREMENT } }, \ { C_SERIAL_POLICY, YP_TOPT, YP_VOPT = { serial_policies, SERIAL_POLICY_INCREMENT } }, \
{ C_MODULE, YP_TDATA, YP_VDATA = { 0, NULL, mod_id_to_bin, mod_id_to_txt }, \ { C_REQUEST_EDNS_OPTION, YP_TDATA, YP_VDATA = { 0, NULL, edns_opt_to_bin, edns_opt_to_txt } }, \
YP_FMULTI, { check_modref } }, \ { C_MODULE, YP_TDATA, YP_VDATA = { 0, NULL, mod_id_to_bin, mod_id_to_txt }, \
{ C_COMMENT, YP_TSTR, YP_VNONE }, YP_FMULTI, { check_modref } }, \
{ C_COMMENT, YP_TSTR, YP_VNONE },
static const yp_item_t desc_template[] = { static const yp_item_t desc_template[] = {
{ C_ID, YP_TSTR, YP_VNONE }, { C_ID, YP_TSTR, YP_VNONE },
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
#define C_RATE_LIMIT "\x0A""rate-limit" #define C_RATE_LIMIT "\x0A""rate-limit"
#define C_RATE_LIMIT_SLIP "\x0F""rate-limit-slip" #define C_RATE_LIMIT_SLIP "\x0F""rate-limit-slip"
#define C_RATE_LIMIT_TBL_SIZE "\x15""rate-limit-table-size" #define C_RATE_LIMIT_TBL_SIZE "\x15""rate-limit-table-size"
#define C_REQUEST_EDNS_OPTION "\x13""request-edns-option"
#define C_RMT "\x06""remote" #define C_RMT "\x06""remote"
#define C_RUNDIR "\x06""rundir" #define C_RUNDIR "\x06""rundir"
#define C_SECRET "\x06""secret" #define C_SECRET "\x06""secret"
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "knot/conf/confdb.h" #include "knot/conf/confdb.h"
#include "knot/conf/scheme.h" #include "knot/conf/scheme.h"
#include "libknot/errcode.h" #include "libknot/errcode.h"
#include "libknot/internal/utils.h"
#include "libknot/yparser/yptrafo.h" #include "libknot/yparser/yptrafo.h"
static int hex_to_num(char hex) { static int hex_to_num(char hex) {
...@@ -179,6 +180,74 @@ int mod_id_to_txt( ...@@ -179,6 +180,74 @@ int mod_id_to_txt(
return KNOT_EOK; return KNOT_EOK;
} }
int edns_opt_to_bin(
char const *txt,
size_t txt_len,
uint8_t *bin,
size_t *bin_len)
{
char *suffix = NULL;
unsigned long number = strtoul(txt, &suffix, 10);
// Check for "code:[value]" format.
if (suffix <= txt || *suffix != ':' || number > UINT16_MAX) {
return KNOT_EINVAL;
}
// Store the option code.
uint16_t code = number;
if (*bin_len < sizeof(code)) {
return KNOT_ESPACE;
}
wire_write_u16(bin, code);
bin += sizeof(code);
// Prepare suffix input (behind colon character).
size_t txt_suffix_len = txt_len - (suffix - txt) - 1;
size_t bin_suffix_len = *bin_len - sizeof(code);
suffix++;
// Convert suffix data.
int ret = hex_text_to_bin(suffix, txt_suffix_len, bin, &bin_suffix_len);
if (ret != KNOT_EOK) {
return ret;
}
// Set output data length.
*bin_len = sizeof(code) + bin_suffix_len;
return KNOT_EOK;
}
int edns_opt_to_txt(
uint8_t const *bin,
size_t bin_len,
char *txt,
size_t *txt_len)
{
uint16_t code = wire_read_u16(bin);
// Write option code part.
int code_len = snprintf(txt, *txt_len, "%u:", code);
if (code_len <= 0 || code_len >= *txt_len) {
return KNOT_ESPACE;
}
size_t data_len = *txt_len - code_len;
// Write possible option data part.
int ret = hex_text_to_txt(bin + sizeof(code), bin_len - sizeof(code),
txt + code_len, &data_len);
if (ret != KNOT_EOK) {
return ret;
}
// Set output text length.
*txt_len = code_len + data_len;
return KNOT_EOK;
}
int check_ref( int check_ref(
conf_check_t *args) conf_check_t *args)
{ {
......
...@@ -79,6 +79,20 @@ int mod_id_to_txt( ...@@ -79,6 +79,20 @@ int mod_id_to_txt(
size_t *txt_len size_t *txt_len
); );
int edns_opt_to_bin(
char const *txt,
size_t txt_len,
uint8_t *bin,
size_t *bin_len
);
int edns_opt_to_txt(
uint8_t const *bin,
size_t bin_len,
char *txt,
size_t *txt_len
);
int check_ref( int check_ref(
conf_check_t *args conf_check_t *args
); );
......
...@@ -89,6 +89,44 @@ static knot_pkt_t *zone_query(const zone_t *zone, uint16_t pkt_type, mm_ctx_t *m ...@@ -89,6 +89,44 @@ static knot_pkt_t *zone_query(const zone_t *zone, uint16_t pkt_type, mm_ctx_t *m
return pkt; return pkt;
} }
/*! \brief Set EDNS section. */
static int prepare_edns(zone_t *zone, knot_pkt_t *pkt)
{
conf_val_t opt = conf_zone_get(conf(), C_REQUEST_EDNS_OPTION, zone->name);
/* Check if an extra EDNS option is configured. */
conf_data(&opt);
if (opt.data == NULL) {
return KNOT_EOK;
}
knot_rrset_t opt_rr;
conf_val_t udp_max = conf_get(conf(), C_SRV, C_MAX_UDP_PAYLOAD);
int ret = knot_edns_init(&opt_rr, conf_int(&udp_max), 0,
KNOT_EDNS_VERSION, &pkt->mm);
if (ret != KNOT_EOK) {
return ret;
}
ret = knot_edns_add_option(&opt_rr, wire_read_u16(opt.data),
opt.len - sizeof(uint16_t),
opt.data + sizeof(uint16_t), &pkt->mm);
if (ret != KNOT_EOK) {
knot_rrset_clear(&opt_rr, &pkt->mm);
return ret;
}
knot_pkt_begin(pkt, KNOT_ADDITIONAL);
ret = knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, &opt_rr, KNOT_PF_FREE);
if (ret != KNOT_EOK) {
knot_rrset_clear(&opt_rr, &pkt->mm);
return ret;
}
return KNOT_EOK;
}
/*! /*!
* \brief Create a zone event query, send it, wait for the response and process it. * \brief Create a zone event query, send it, wait for the response and process it.
* *
...@@ -119,6 +157,12 @@ static int zone_query_execute(zone_t *zone, uint16_t pkt_type, const conf_remote ...@@ -119,6 +157,12 @@ static int zone_query_execute(zone_t *zone, uint16_t pkt_type, const conf_remote
knot_requestor_init(&re, &mm); knot_requestor_init(&re, &mm);
knot_requestor_overlay(&re, KNOT_STATE_ANSWER, &param); knot_requestor_overlay(&re, KNOT_STATE_ANSWER, &param);
/* Set EDNS section. */
ret = prepare_edns(zone, query);
if (ret != KNOT_EOK) {
goto fail;
}
const knot_tsig_key_t *key = remote->key.name != NULL ? const knot_tsig_key_t *key = remote->key.name != NULL ?
&remote->key : NULL; &remote->key : NULL;
tsig_init(&param.tsig_ctx, key); tsig_init(&param.tsig_ctx, key);
......
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