Commit 6ac2bad0 authored by Daniel Salzman's avatar Daniel Salzman

Merge branch 'ecs_support' into 'master'

knot: add support for ECS EDNS option

See merge request !904
parents 1900d841 81004fcb
......@@ -190,6 +190,7 @@ server:
max\-udp\-payload: SIZE
max\-ipv4\-udp\-payload: SIZE
max\-ipv6\-udp\-payload: SIZE
edns\-client\-subnet: BOOL
listen: ADDR[@INT] ...
.ft P
.fi
......@@ -295,6 +296,12 @@ Maximum EDNS0 UDP payload size for IPv4.
Maximum EDNS0 UDP payload size for IPv6.
.sp
\fIDefault:\fP 4096
.SS edns\-client\-subnet
.sp
Enable or disable EDNS Client Subnet support. If enabled, responses to queries containing the EDNS Client Subnet option
always contain a valid EDNS Client Subnet option according to \fI\%RFC 7871\fP\&.
.sp
\fIDefault:\fP off
.SS listen
.sp
One or more IP addresses where the server listens for incoming queries.
......
......@@ -141,6 +141,7 @@ General options related to the server.
max-udp-payload: SIZE
max-ipv4-udp-payload: SIZE
max-ipv6-udp-payload: SIZE
edns-client-subnet: BOOL
listen: ADDR[@INT] ...
.. _server_identity:
......@@ -311,6 +312,16 @@ Maximum EDNS0 UDP payload size for IPv6.
*Default:* 4096
.. _server_edns-client-subnet:
edns-client-subnet
------------------
Enable or disable EDNS Client Subnet support. If enabled, responses to queries containing the EDNS Client Subnet option
always contain a valid EDNS Client Subnet option according to :rfc:`7871`.
*Default:* off
.. _server_listen:
listen
......
......@@ -138,6 +138,9 @@ static void init_cache(
conf->cache.ctl_timeout = conf_int(&val) * 1000;
conf->cache.srv_nsid = conf_get(conf, C_SRV, C_NSID);
val = conf_get(conf, C_SRV, C_ECS);
conf->cache.use_ecs = conf_bool(&val);
}
int conf_new(
......
......@@ -116,6 +116,7 @@ typedef struct {
int32_t srv_max_tcp_clients;
int32_t ctl_timeout;
conf_val_t srv_nsid;
bool use_ecs;
} cache;
/*! List of dynamically loaded modules. */
......
......@@ -156,6 +156,7 @@ static const yp_item_t desc_server[] = {
KNOT_EDNS_MAX_UDP_PAYLOAD, YP_SSIZE } },
{ C_LISTEN, YP_TADDR, YP_VADDR = { 53 }, YP_FMULTI },
{ C_COMMENT, YP_TSTR, YP_VNONE },
{ C_ECS, YP_TBOOL, YP_VNONE },
{ NULL }
};
......
......@@ -40,6 +40,7 @@
#define C_DNSSEC_POLICY "\x0D""dnssec-policy"
#define C_DNSSEC_SIGNING "\x0E""dnssec-signing"
#define C_DOMAIN "\x06""domain"
#define C_ECS "\x12""edns-client-subnet"
#define C_FILE "\x04""file"
#define C_GLOBAL_MODULE "\x0D""global-module"
#define C_ID "\x02""id"
......
......@@ -380,14 +380,15 @@ typedef struct {
/*! Query processing data context. */
typedef struct {
knot_pkt_t *query; /*!< Query to be solved. */
knotd_query_type_t type; /*!< Query packet type. */
const knot_dname_t *name; /*!< Currently processed name. */
uint16_t rcode; /*!< Resulting RCODE (Whole extended RCODE). */
uint16_t rcode_tsig; /*!< Resulting TSIG RCODE. */
knot_rrset_t opt_rr; /*!< OPT record. */
knot_sign_context_t sign; /*!< Signing context. */
bool err_truncated; /*!< Set TC bit if error reply. */
knot_pkt_t *query; /*!< Query to be solved. */
knotd_query_type_t type; /*!< Query packet type. */
const knot_dname_t *name; /*!< Currently processed name. */
uint16_t rcode; /*!< Resulting RCODE (Whole extended RCODE). */
uint16_t rcode_tsig; /*!< Resulting TSIG RCODE. */
knot_rrset_t opt_rr; /*!< OPT record. */
knot_sign_context_t sign; /*!< Signing context. */
knot_edns_client_subnet_t *ecs; /*!< EDNS Client Subnet option. */
bool err_truncated; /*!< Set TC bit if error reply. */
/*! Persistent items on processing reset. */
knot_mm_t *mm; /*!< Memory context. */
......
......@@ -291,6 +291,34 @@ static int answer_edns_init(const knot_pkt_t *query, knot_pkt_t *resp,
}
}
/* Initialize EDNS Client Subnet if configured and present in query. */
if (conf()->cache.use_ecs) {
uint8_t *ecs_opt = knot_pkt_edns_option(query, KNOT_EDNS_OPTION_CLIENT_SUBNET);
if (ecs_opt != NULL) {
qdata->ecs = mm_alloc(qdata->mm, sizeof(knot_edns_client_subnet_t));
if (qdata->ecs == NULL) {
return KNOT_ENOMEM;
}
const uint8_t *ecs_data = knot_edns_opt_get_data(ecs_opt);
uint16_t ecs_len = knot_edns_opt_get_length(ecs_opt);
ret = knot_edns_client_subnet_parse(qdata->ecs, ecs_data, ecs_len);
if (ret != KNOT_EOK) {
qdata->rcode = KNOT_RCODE_FORMERR;
return ret;
}
qdata->ecs->scope_len = 0;
/* Reserve space for the option in the answer. */
ret = knot_edns_reserve_option(&qdata->opt_rr, KNOT_EDNS_OPTION_CLIENT_SUBNET,
ecs_len, NULL, qdata->mm);
if (ret != KNOT_EOK) {
return ret;
}
}
} else {
qdata->ecs = NULL;
}
return answer_edns_reserve(resp, qdata);
}
......@@ -300,8 +328,22 @@ static int answer_edns_put(knot_pkt_t *resp, knotd_qdata_t *qdata)
return KNOT_EOK;
}
/* Add ECS if present. */
int ret = KNOT_EOK;
if (qdata->ecs != NULL) {
uint8_t *ecs_opt = knot_edns_get_option(&qdata->opt_rr, KNOT_EDNS_OPTION_CLIENT_SUBNET);
if (ecs_opt != NULL) {
uint8_t *ecs_data = knot_edns_opt_get_data(ecs_opt);
uint16_t ecs_len = knot_edns_opt_get_length(ecs_opt);
ret = knot_edns_client_subnet_write(ecs_data, ecs_len, qdata->ecs);
if (ret != KNOT_EOK) {
return ret;
}
}
}
/* Reclaim reserved size. */
int ret = knot_pkt_reclaim(resp, knot_edns_wire_size(&qdata->opt_rr));
ret = knot_pkt_reclaim(resp, knot_edns_wire_size(&qdata->opt_rr));
if (ret != KNOT_EOK) {
return ret;
}
......
......@@ -908,7 +908,8 @@ static void test_conf_io_list(void)
"server.max-tcp-clients\n"
"server.max-udp-payload\n"
"server.max-ipv4-udp-payload\n"
"server.max-ipv6-udp-payload";
"server.max-ipv6-udp-payload\n"
"server.edns-client-subnet";
ok(strcmp(ref, out) == 0, "compare result");
}
......@@ -924,6 +925,7 @@ static const yp_item_t desc_server[] = {
{ C_MAX_UDP_PAYLOAD, YP_TINT, YP_VNONE },
{ C_MAX_IPV4_UDP_PAYLOAD, YP_TINT, YP_VNONE },
{ C_MAX_IPV6_UDP_PAYLOAD, YP_TINT, YP_VNONE },
{ C_ECS, YP_TBOOL, YP_VNONE },
{ NULL }
};
......
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