More conventional server DNSSEC behaviour

+ documentation of behaviour
This commit is contained in:
Willem Toorop 2016-07-11 15:13:40 +02:00
parent f1b2dbeaa7
commit 7e614bc534
5 changed files with 202 additions and 27 deletions

Binary file not shown.

Binary file not shown.

View File

@ -611,6 +611,15 @@ _getdns_wire2msg_dict_scan(struct mem_funcs *mf,
if (!wire || !*wire || !wire_len || !msg_dict)
return GETDNS_RETURN_INVALID_PARAMETER;
#if 0 && defined(SERVER_DEBUG) && SERVER_DEBUG
do {
char *str = gldns_wire2str_pkt((uint8_t *)*wire, *wire_len);
DEBUG_SERVER("_getdns_wire2msg_dict_scan for a packet size: %d: %s\n",
(int)*wire_len, str);
free(str);
} while(0);
#endif
if (!(result = _getdns_dict_create_with_mf(mf)) ||
!(header = _getdns_dict_create_with_mf(mf)) ||
!(sections[SECTION_ANSWER]
@ -768,11 +777,12 @@ _getdns_reply_dict2wire(
const getdns_dict *reply, gldns_buffer *buf, int reuse_header)
{
uint8_t header_spc[GLDNS_HEADER_SIZE], *header;
uint32_t n, qtype, qclass = GETDNS_RRCLASS_IN;
uint32_t n, qtype, qclass = GETDNS_RRCLASS_IN, rr_type;
size_t pkt_start, i;
getdns_list *section;
getdns_dict *rr_dict;
getdns_bindata *qname;
int remove_dnssec;
pkt_start = gldns_buffer_position(buf);
if (reuse_header) {
@ -814,11 +824,18 @@ _getdns_reply_dict2wire(
buf, pkt_start+GLDNS_ARCOUNT_OFF, 0);
}
}
remove_dnssec = !getdns_dict_get_int(reply, "/header/do", &n) && n == 0;
DEBUG_SERVER("remove_dnssec: %d\n", remove_dnssec);
if (!getdns_dict_get_list(reply, "answer", &section)) {
for ( n = 0, i = 0
; !getdns_list_get_dict(section, i, &rr_dict); i++) {
if (!_getdns_rr_dict2wire(rr_dict, buf))
if (remove_dnssec &&
!getdns_dict_get_int(rr_dict, "type", &rr_type) &&
rr_type == GETDNS_RRTYPE_RRSIG)
continue;
if (!_getdns_rr_dict2wire(rr_dict, buf))
n++;
}
gldns_buffer_write_u16_at(buf, pkt_start+GLDNS_ANCOUNT_OFF, n);
@ -827,7 +844,15 @@ _getdns_reply_dict2wire(
for ( n = 0, i = 0
; !getdns_list_get_dict(section, i, &rr_dict); i++) {
if (!_getdns_rr_dict2wire(rr_dict, buf))
if (remove_dnssec &&
!getdns_dict_get_int(rr_dict, "type", &rr_type) &&
( rr_type == GETDNS_RRTYPE_RRSIG
|| rr_type == GETDNS_RRTYPE_NSEC
|| rr_type == GETDNS_RRTYPE_NSEC3
|| rr_type == GETDNS_RRTYPE_DS
))
continue;
if (!_getdns_rr_dict2wire(rr_dict, buf))
n++;
}
gldns_buffer_write_u16_at(buf, pkt_start+GLDNS_NSCOUNT_OFF, n);
@ -836,6 +861,10 @@ _getdns_reply_dict2wire(
for ( n = 0, i = 0
; !getdns_list_get_dict(section, i, &rr_dict); i++) {
if (remove_dnssec &&
!getdns_dict_get_int(rr_dict, "type", &rr_type) &&
rr_type == GETDNS_RRTYPE_RRSIG)
continue;
if (!_getdns_rr_dict2wire(rr_dict, buf))
n++;
}

View File

@ -503,6 +503,72 @@ static void udp_read_cb(void *userarg)
close(l->fd);
l->fd = -1;
#if 0 && defined(SERVER_DEBUG) && SERVER_DEBUG
} else {
char addrbuf[100];
char hexbuf[4096], *hexptr;
size_t l, i, j;
if (conn->remote_in.ss_family == AF_INET) {
if (inet_ntop(AF_INET,
&((struct sockaddr_in*)&conn->remote_in)->sin_addr,
addrbuf, sizeof(addrbuf))) {
l = strlen(addrbuf);
(void) snprintf(addrbuf + l,
sizeof(addrbuf) - l, ":%d",
(int)((struct sockaddr_in*)
&conn->remote_in)->sin_port);
} else
(void) strncpy(
addrbuf, "error ipv4", sizeof(addrbuf));
} else if (conn->remote_in.ss_family == AF_INET6) {
addrbuf[0] = '[';
if (inet_ntop(AF_INET6,
&((struct sockaddr_in6*)
&conn->remote_in)->sin6_addr,
addrbuf, sizeof(addrbuf))) {
l = strlen(addrbuf);
(void) snprintf(addrbuf + l,
sizeof(addrbuf) - l, ":%d",
(int)((struct sockaddr_in6*)
&conn->remote_in)->sin6_port);
} else
(void) strncpy(
addrbuf, "error ipv6", sizeof(addrbuf));
} else {
(void) strncpy(
addrbuf, "unknown address", sizeof(addrbuf));
}
*(hexptr = hexbuf) = 0;
for (i = 0; i < len; i++) {
if (i % 12 == 0) {
hexptr += snprintf(hexptr,
sizeof(hexbuf) - (hexptr - hexbuf) - 1,
"\n%.4x", (int)i);
} else if (i % 4 == 0) {
hexptr += snprintf(hexptr,
sizeof(hexbuf) - (hexptr - hexbuf) - 1,
" ");
}
if (hexptr - hexbuf > sizeof(hexbuf))
break;
hexptr += snprintf(hexptr,
sizeof(hexbuf) - (hexptr - hexbuf) - 1,
" %.2x", (int)buf[i]);
if (hexptr - hexbuf > sizeof(hexbuf))
break;
}
DEBUG_SERVER("Received %d bytes from %s: %s\n",
(int)len, addrbuf, hexbuf);
}
if (len == -1) {
; /* pass */
#endif
} else if ((r = getdns_wire2msg_dict(buf, len, &request_dict)))
; /* FROMERR on input, ignore */

View File

@ -1200,8 +1200,10 @@ typedef struct dns_msg {
getdns_transaction_t request_id;
getdns_dict *request;
uint32_t rt;
uint32_t ad_bit;
uint32_t do_bit;
uint32_t cd_bit;
int has_edns0;
} dns_msg;
#if defined(SERVER_DEBUG) && SERVER_DEBUG
@ -1236,15 +1238,53 @@ void servfail(dns_msg *msg, getdns_dict **resp_p)
(void) getdns_dict_set_int(*resp_p, "/header/ad", 0);
}
void request_cb(getdns_context *context, getdns_callback_type_t callback_type,
static getdns_return_t _handle_edns0(
getdns_dict *response, int has_edns0, uint32_t do_bit)
{
getdns_return_t r;
getdns_list *additional;
size_t len, i;
getdns_dict *rr;
uint32_t rr_type;
char remove_str[100] = "/replies_tree/0/additional/";
if ((r = getdns_dict_set_int(
response, "/replies_tree/0/header/do", do_bit)))
return r;
if (has_edns0)
return GETDNS_RETURN_GOOD;
if ((r = getdns_dict_get_list(response, "/replies_tree/0/additional",
&additional)))
return r;
if ((r = getdns_list_get_length(additional, &len)))
return r;
for (i = 0; i < len; i++) {
if ((r = getdns_list_get_dict(additional, i, &rr)))
return r;
if ((r = getdns_dict_get_int(rr, "type", &rr_type)))
return r;
if (rr_type != GETDNS_RRTYPE_OPT)
continue;
(void) snprintf(remove_str + 27, 60, "%d", (int)i);
if ((r = getdns_dict_remove_name(response, remove_str)))
return r;
break;
}
return GETDNS_RETURN_GOOD;
}
static void request_cb(
getdns_context *context, getdns_callback_type_t callback_type,
getdns_dict *response, void *userarg, getdns_transaction_t transaction_id)
{
dns_msg *msg = (dns_msg *)userarg;
uint32_t qid;
getdns_return_t r = GETDNS_RETURN_GOOD;
uint32_t n;
uint32_t n, rcode, dnssec_status;
DEBUG_SERVER("reply for: %p %"PRIu64" %d\n", msg, transaction_id, (int)callback_type);
DEBUG_SERVER("reply for: %p %"PRIu64" %d (edns0: %d, do: %d, ad: %d,"
" cd: %d)\n", msg, transaction_id, (int)callback_type,
msg->has_edns0, msg->do_bit, msg->ad_bit, msg->cd_bit);
assert(msg);
#if 0
@ -1263,21 +1303,36 @@ void request_cb(getdns_context *context, getdns_callback_type_t callback_type,
SERVFAIL("Could not copy QID", r, msg, &response);
else if (getdns_dict_get_int(
response, "/replies_tree/0/header/rcode", &n))
response, "/replies_tree/0/header/rcode", &rcode))
SERVFAIL("No reply in replies tree", 0, msg, &response);
else if (msg->cd_bit != 1 && !getdns_dict_get_int(
response, "/replies_tree/0/dnssec_status", &n)
&& n == GETDNS_DNSSEC_BOGUS)
/* ansers when CD or not BOGUS */
else if (!msg->cd_bit && !getdns_dict_get_int(
response, "/replies_tree/0/dnssec_status", &dnssec_status)
&& dnssec_status == GETDNS_DNSSEC_BOGUS)
SERVFAIL("DNSSEC status was bogus", 0, msg, &response);
else if ((r = getdns_dict_get_int(
response, "/replies_tree/0/header/rcode", &n)))
SERVFAIL("Could not get rcode from reply", r, msg, &response);
else if (n == GETDNS_RCODE_SERVFAIL)
else if (rcode == GETDNS_RCODE_SERVFAIL)
servfail(msg, &response);
/* RRsigs when DO and (CD or not BOGUS)
* Implemented in conversion to wireformat function by checking for DO
* bit. In recursing resolution mode we have to copy the do bit from
* the request, because libunbound has it in the answer always.
*/
else if (msg->rt == GETDNS_RESOLUTION_RECURSING &&
(r = _handle_edns0(response, msg->has_edns0, msg->do_bit)))
SERVFAIL("Could not handle EDNS0", r, msg, &response);
/* AD when (DO or AD) and SECURE */
else if ((r = getdns_dict_set_int(response,"/replies_tree/0/header/ad",
((msg->do_bit || msg->ad_bit)
&& ( (!msg->cd_bit && dnssec_status == GETDNS_DNSSEC_SECURE)
|| ( msg->cd_bit && !getdns_dict_get_int(response,
"/replies_tree/0/dnssec_status", &dnssec_status)
&& dnssec_status == GETDNS_DNSSEC_SECURE ))) ? 1 : 0)))
SERVFAIL("Could not set AD bit", r, msg, &response);
else if (msg->rt == GETDNS_RESOLUTION_STUB)
; /* following checks are for RESOLUTION_RECURSING only */
@ -1324,6 +1379,10 @@ static void incoming_request_handler(getdns_context *context,
getdns_dict *qext = NULL;
dns_msg *msg = NULL;
getdns_dict *response = NULL;
size_t i, len;
getdns_list *additional;
getdns_dict *rr;
uint32_t rr_type;
if (!query_extensions_spc &&
!(query_extensions_spc = getdns_dict_create()))
@ -1345,10 +1404,26 @@ static void incoming_request_handler(getdns_context *context,
n = 0;
msg->request_id = request_id;
msg->request = request;
msg->do_bit = msg->cd_bit = 0;
msg->rt = GETDNS_RESOLUTION_STUB;
(void) getdns_dict_get_int(request, "/additional/0/do", &msg->do_bit);
msg->ad_bit = msg->do_bit = msg->cd_bit = 0;
msg->has_edns0 = 0;
msg->rt = GETDNS_RESOLUTION_RECURSING;
(void) getdns_dict_get_int(request, "/header/ad", &msg->ad_bit);
(void) getdns_dict_get_int(request, "/header/cd", &msg->cd_bit);
if (!getdns_dict_get_list(request, "additional", &additional)) {
if (getdns_list_get_length(additional, &len))
len = 0;
for (i = 0; i < len; i++) {
if (getdns_list_get_dict(additional, i, &rr))
break;
if (getdns_dict_get_int(rr, "type", &rr_type))
break;
if (rr_type != GETDNS_RRTYPE_OPT)
continue;
msg->has_edns0 = 1;
(void) getdns_dict_get_int(rr, "do", &msg->do_bit);
break;
}
}
if ((r = getdns_context_get_resolution_type(context, &msg->rt)))
fprintf(stderr, "Could get resolution type from context: %s\n",
getdns_get_errorstr_by_id(r));
@ -1359,15 +1434,10 @@ static void incoming_request_handler(getdns_context *context,
if (!getdns_dict_get_dict(request, "header", &header))
(void)getdns_dict_set_dict(qext, "header", header);
} else if (getdns_dict_get_int(extensions,"dnssec_return_status",&n) ||
n == GETDNS_EXTENSION_FALSE)
(void)getdns_dict_set_int(qext, "dnssec_return_status",
msg->do_bit ? GETDNS_EXTENSION_TRUE : GETDNS_EXTENSION_FALSE);
if (!getdns_dict_get_int(qext, "dnssec_return_status", &n) &&
n == GETDNS_EXTENSION_TRUE)
(void) getdns_dict_set_int(qext, "dnssec_return_all_statuses",
msg->cd_bit ? GETDNS_EXTENSION_TRUE : GETDNS_EXTENSION_FALSE);
}
if (msg->cd_bit)
getdns_dict_set_int(qext, "dnssec_return_all_statuses",
GETDNS_EXTENSION_TRUE);
if (!getdns_dict_get_int(request, "/additional/0/extended_rcode",&n))
(void)getdns_dict_set_int(
@ -1431,6 +1501,16 @@ error:
if (qname_str)
free(qname_str);
servfail(msg, &response);
#if defined(SERVER_DEBUG) && SERVER_DEBUG
do {
char *request_str = getdns_pretty_print_dict(request);
char *response_str = getdns_pretty_print_dict(response);
DEBUG_SERVER("request error, request: %s\n, response: %s\n"
, request_str, response_str);
free(response_str);
free(request_str);
} while(0);
#endif
if (!response)
/* No response, no reply */
_getdns_cancel_reply(context, request_id);