mirror of https://github.com/getdnsapi/getdns.git
Response to BADCOOKIE extended rcode
This commit is contained in:
parent
563b2b113a
commit
8b62970e0c
|
@ -255,7 +255,7 @@ static struct const_name_info consts_name_info[] = {
|
|||
{ "GETDNS_RCODE_BADTIME", 18 },
|
||||
{ "GETDNS_RCODE_BADTRUNC", 22 },
|
||||
{ "GETDNS_RCODE_BADVERS", 16 },
|
||||
{ "GETDNS_RCODE_COOKIE", 23 },
|
||||
{ "GETDNS_RCODE_BADCOOKIE", 23 },
|
||||
{ "GETDNS_RCODE_FORMERR", 1 },
|
||||
{ "GETDNS_RCODE_NOERROR", 0 },
|
||||
{ "GETDNS_RCODE_NOTAUTH", 9 },
|
||||
|
|
27
src/dict.c
27
src/dict.c
|
@ -1036,21 +1036,21 @@ static int
|
|||
_getdns_print_rcode(gldns_buffer *buf, uint32_t rcode)
|
||||
{
|
||||
static const char *rcodes[] = {
|
||||
" GETDNS_RCODE_NOERROR" , " GETDNS_RCODE_FORMERR" ,
|
||||
" GETDNS_RCODE_SERVFAIL", " GETDNS_RCODE_NXDOMAIN",
|
||||
" GETDNS_RCODE_NOTIMP" , " GETDNS_RCODE_REFUSED" ,
|
||||
" GETDNS_RCODE_YXDOMAIN", " GETDNS_RCODE_YXRRSET" ,
|
||||
" GETDNS_RCODE_NXRRSET" , " GETDNS_RCODE_NOTAUTH" ,
|
||||
" GETDNS_RCODE_NOERROR" , " GETDNS_RCODE_FORMERR" ,
|
||||
" GETDNS_RCODE_SERVFAIL", " GETDNS_RCODE_NXDOMAIN" ,
|
||||
" GETDNS_RCODE_NOTIMP" , " GETDNS_RCODE_REFUSED" ,
|
||||
" GETDNS_RCODE_YXDOMAIN", " GETDNS_RCODE_YXRRSET" ,
|
||||
" GETDNS_RCODE_NXRRSET" , " GETDNS_RCODE_NOTAUTH" ,
|
||||
" GETDNS_RCODE_NOTZONE" ,
|
||||
" GETDNS_RCODE_BADSIG" , " GETDNS_RCODE_BADKEY" ,
|
||||
" GETDNS_RCODE_BADTIME" , " GETDNS_RCODE_BADMODE" ,
|
||||
" GETDNS_RCODE_BADNAME" , " GETDNS_RCODE_BADALG" ,
|
||||
" GETDNS_RCODE_BADTRUNC"
|
||||
" GETDNS_RCODE_BADSIG" , " GETDNS_RCODE_BADKEY" ,
|
||||
" GETDNS_RCODE_BADTIME" , " GETDNS_RCODE_BADMODE" ,
|
||||
" GETDNS_RCODE_BADNAME" , " GETDNS_RCODE_BADALG" ,
|
||||
" GETDNS_RCODE_BADTRUNC", " GETDNS_RCODE_BADCOOKIE"
|
||||
};
|
||||
if (rcode <= 10)
|
||||
(void) gldns_buffer_printf(buf, "%s", rcodes[rcode]);
|
||||
else if (rcode >= 16 && rcode <= 22)
|
||||
(void) gldns_buffer_printf(buf, "%s", rcodes[rcode-6]);
|
||||
else if (rcode >= 16 && rcode <= 23)
|
||||
(void) gldns_buffer_printf(buf, "%s", rcodes[rcode-5]);
|
||||
else
|
||||
return 0;
|
||||
return 1;
|
||||
|
@ -1156,6 +1156,11 @@ getdns_pp_dict(gldns_buffer * buf, size_t indent,
|
|||
if (!json && strcmp(item->node.key, "rcode") == 0 &&
|
||||
_getdns_print_rcode(buf, item->i.data.n))
|
||||
break;
|
||||
if (!json &&
|
||||
strcmp(item->node.key, "extended_rcode") == 0 &&
|
||||
item->i.data.n >= 16 &&
|
||||
_getdns_print_rcode(buf, item->i.data.n))
|
||||
break;
|
||||
if (gldns_buffer_printf(
|
||||
buf,(json < 2 ? " %d" : "%d"), item->i.data.n) < 0)
|
||||
return -1;
|
||||
|
|
|
@ -473,26 +473,26 @@ typedef enum getdns_callback_type_t {
|
|||
* \defgroup rcodes Rcodes
|
||||
* @{
|
||||
*/
|
||||
#define GETDNS_RCODE_NOERROR 0
|
||||
#define GETDNS_RCODE_FORMERR 1
|
||||
#define GETDNS_RCODE_SERVFAIL 2
|
||||
#define GETDNS_RCODE_NXDOMAIN 3
|
||||
#define GETDNS_RCODE_NOTIMP 4
|
||||
#define GETDNS_RCODE_REFUSED 5
|
||||
#define GETDNS_RCODE_YXDOMAIN 6
|
||||
#define GETDNS_RCODE_YXRRSET 7
|
||||
#define GETDNS_RCODE_NXRRSET 8
|
||||
#define GETDNS_RCODE_NOTAUTH 9
|
||||
#define GETDNS_RCODE_NOTZONE 10
|
||||
#define GETDNS_RCODE_BADVERS 16
|
||||
#define GETDNS_RCODE_BADSIG 16
|
||||
#define GETDNS_RCODE_BADKEY 17
|
||||
#define GETDNS_RCODE_BADTIME 18
|
||||
#define GETDNS_RCODE_BADMODE 19
|
||||
#define GETDNS_RCODE_BADNAME 20
|
||||
#define GETDNS_RCODE_BADALG 21
|
||||
#define GETDNS_RCODE_BADTRUNC 22
|
||||
#define GETDNS_RCODE_COOKIE 23
|
||||
#define GETDNS_RCODE_NOERROR 0
|
||||
#define GETDNS_RCODE_FORMERR 1
|
||||
#define GETDNS_RCODE_SERVFAIL 2
|
||||
#define GETDNS_RCODE_NXDOMAIN 3
|
||||
#define GETDNS_RCODE_NOTIMP 4
|
||||
#define GETDNS_RCODE_REFUSED 5
|
||||
#define GETDNS_RCODE_YXDOMAIN 6
|
||||
#define GETDNS_RCODE_YXRRSET 7
|
||||
#define GETDNS_RCODE_NXRRSET 8
|
||||
#define GETDNS_RCODE_NOTAUTH 9
|
||||
#define GETDNS_RCODE_NOTZONE 10
|
||||
#define GETDNS_RCODE_BADVERS 16
|
||||
#define GETDNS_RCODE_BADSIG 16
|
||||
#define GETDNS_RCODE_BADKEY 17
|
||||
#define GETDNS_RCODE_BADTIME 18
|
||||
#define GETDNS_RCODE_BADMODE 19
|
||||
#define GETDNS_RCODE_BADNAME 20
|
||||
#define GETDNS_RCODE_BADALG 21
|
||||
#define GETDNS_RCODE_BADTRUNC 22
|
||||
#define GETDNS_RCODE_BADCOOKIE 23
|
||||
/** @}
|
||||
*/
|
||||
|
||||
|
|
|
@ -147,6 +147,7 @@ netreq_reset(getdns_network_req *net_req)
|
|||
net_req->dnssec_status = GETDNS_DNSSEC_INDETERMINATE;
|
||||
net_req->tsig_status = GETDNS_DNSSEC_INDETERMINATE;
|
||||
net_req->response_len = 0;
|
||||
net_req->response_opt = NULL;
|
||||
/* Some fields to record info for return_call_reporting */
|
||||
net_req->debug_start_time = 0;
|
||||
net_req->debug_end_time = 0;
|
||||
|
@ -308,6 +309,7 @@ _getdns_network_req_clear_upstream_options(getdns_network_req * req)
|
|||
req->response = req->opt + 11 + req->base_query_option_sz;
|
||||
pktlen = req->response - req->query;
|
||||
gldns_write_uint16(req->query - 2, (uint16_t) pktlen);
|
||||
req->response_opt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
149
src/stub.c
149
src/stub.c
|
@ -210,62 +210,73 @@ attach_edns_cookie(getdns_network_req *req)
|
|||
* and 1 on FORMERR
|
||||
*/
|
||||
static int
|
||||
match_edns_opt_rr(uint16_t code, uint8_t *response, size_t response_len,
|
||||
match_edns_opt_rr(uint16_t code, getdns_network_req *netreq,
|
||||
const uint8_t **position, uint16_t *option_len)
|
||||
{
|
||||
_getdns_rr_iter rr_iter_storage, *rr_iter;
|
||||
const uint8_t *pos;
|
||||
const uint8_t *pos, *rdata_end;
|
||||
uint16_t rdata_len, opt_code = 0, opt_len = 0;
|
||||
static uint8_t *NO_OPT_RR = (uint8_t *)"\x00\x00";
|
||||
|
||||
/* Search for the OPT RR (if any) */
|
||||
for ( rr_iter = _getdns_rr_iter_init(&rr_iter_storage
|
||||
, response, response_len)
|
||||
; rr_iter
|
||||
; rr_iter = _getdns_rr_iter_next(rr_iter)) {
|
||||
if (!netreq->response_opt) {
|
||||
_getdns_rr_iter rr_iter_storage, *rr_iter;
|
||||
for ( rr_iter = _getdns_rr_iter_init(&rr_iter_storage
|
||||
, netreq->response, netreq->response_len)
|
||||
; rr_iter
|
||||
; rr_iter = _getdns_rr_iter_next(rr_iter)) {
|
||||
|
||||
if (_getdns_rr_iter_section(rr_iter) != SECTION_ADDITIONAL)
|
||||
continue;
|
||||
if (_getdns_rr_iter_section(rr_iter) != SECTION_ADDITIONAL)
|
||||
continue;
|
||||
|
||||
if (gldns_read_uint16(rr_iter->rr_type) != GETDNS_RRTYPE_OPT)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
if (! rr_iter)
|
||||
return 0; /* No OPT, no cookie */
|
||||
|
||||
pos = rr_iter->rr_type + 8;
|
||||
if (gldns_read_uint16(rr_iter->rr_type) != GETDNS_RRTYPE_OPT)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (! rr_iter) {
|
||||
netreq->response_opt = NO_OPT_RR;
|
||||
return 0; /* No OPT, no options cookie */
|
||||
}
|
||||
pos = netreq->response_opt = rr_iter->rr_type + 8;
|
||||
|
||||
#if defined(STUB_DEBUG) && STUB_DEBUG
|
||||
char str_spc[8192], *str = str_spc;
|
||||
size_t str_len = sizeof(str_spc);
|
||||
uint8_t *data = (uint8_t *)rr_iter->pos;
|
||||
size_t data_len = rr_iter->nxt - rr_iter->pos;
|
||||
(void) gldns_wire2str_rr_scan(
|
||||
&data, &data_len, &str, &str_len, (uint8_t *)rr_iter->pkt, rr_iter->pkt_end - rr_iter->pkt, NULL);
|
||||
DEBUG_STUB("%s %-35s: OPT RR: %s",
|
||||
STUB_DEBUG_READ, __FUNC__, str_spc);
|
||||
char str_spc[8192], *str = str_spc;
|
||||
size_t str_len = sizeof(str_spc);
|
||||
uint8_t *data = (uint8_t *)rr_iter->pos;
|
||||
size_t data_len = rr_iter->nxt - rr_iter->pos;
|
||||
(void) gldns_wire2str_rr_scan(&data, &data_len, &str, &str_len,
|
||||
(uint8_t *)rr_iter->pkt, rr_iter->pkt_end - rr_iter->pkt,
|
||||
NULL);
|
||||
DEBUG_STUB("%s %-35s: OPT RR: %s",
|
||||
STUB_DEBUG_READ, __FUNC__, str_spc);
|
||||
#endif
|
||||
/* Check limits only the first time*/
|
||||
if (pos + 2 > rr_iter->nxt
|
||||
|| pos + 2 + gldns_read_uint16(pos) > rr_iter->nxt) {
|
||||
netreq->response_opt = NO_OPT_RR;
|
||||
return 1; /* FORMERR */
|
||||
}
|
||||
} else if (netreq->response_opt == NO_OPT_RR)
|
||||
return 0; /* No OPT, no options */
|
||||
else
|
||||
/* Reuse earlier found option */
|
||||
pos = netreq->response_opt;;
|
||||
|
||||
/* OPT found, now search for the specified option */
|
||||
if (pos + 2 > rr_iter->nxt)
|
||||
return 1; /* FORMERR */
|
||||
rdata_len = gldns_read_uint16(pos);
|
||||
pos += 2;
|
||||
rdata_end = pos + rdata_len;
|
||||
|
||||
rdata_len = gldns_read_uint16(pos); pos += 2;
|
||||
if (pos + rdata_len > rr_iter->nxt)
|
||||
return 1; /* FORMERR */
|
||||
|
||||
while (pos < rr_iter->nxt) {
|
||||
while (pos < rdata_end) {
|
||||
opt_code = gldns_read_uint16(pos); pos += 2;
|
||||
opt_len = gldns_read_uint16(pos); pos += 2;
|
||||
if (pos + opt_len > rr_iter->nxt)
|
||||
if (pos + opt_len > rdata_end)
|
||||
return 1; /* FORMERR */
|
||||
if (opt_code == code)
|
||||
break;
|
||||
pos += opt_len; /* Skip unknown options */
|
||||
}
|
||||
if (pos >= rr_iter->nxt || opt_code != code)
|
||||
return 0; /* Everything OK, just no cookie found. */
|
||||
if (pos >= rdata_end || opt_code != code)
|
||||
return 0; /* Everything OK,
|
||||
* the searched for option was just not found. */
|
||||
*position = pos;
|
||||
*option_len = opt_len;
|
||||
return 2;
|
||||
|
@ -274,12 +285,12 @@ match_edns_opt_rr(uint16_t code, uint8_t *response, size_t response_len,
|
|||
/* TODO: Test combinations of EDNS0 options*/
|
||||
static int
|
||||
match_and_process_server_cookie(
|
||||
getdns_upstream *upstream, uint8_t *response, size_t response_len)
|
||||
getdns_upstream *upstream, getdns_network_req *netreq)
|
||||
{
|
||||
const uint8_t *position = NULL;
|
||||
uint16_t option_len = 0;
|
||||
int found = match_edns_opt_rr(EDNS_COOKIE_OPCODE, response,
|
||||
response_len, &position, &option_len);
|
||||
int found = match_edns_opt_rr(EDNS_COOKIE_OPCODE, netreq,
|
||||
&position, &option_len);
|
||||
if (found != 2)
|
||||
return found;
|
||||
|
||||
|
@ -309,14 +320,12 @@ match_and_process_server_cookie(
|
|||
}
|
||||
|
||||
static void
|
||||
process_keepalive(
|
||||
getdns_upstream *upstream, getdns_network_req *netreq,
|
||||
uint8_t *response, size_t response_len)
|
||||
process_keepalive( getdns_upstream *upstream, getdns_network_req *netreq)
|
||||
{
|
||||
const uint8_t *position = NULL;
|
||||
uint16_t option_len = 0;
|
||||
int found = match_edns_opt_rr(GLDNS_EDNS_KEEPALIVE, response,
|
||||
response_len, &position, &option_len);
|
||||
int found = match_edns_opt_rr(GLDNS_EDNS_KEEPALIVE, netreq,
|
||||
&position, &option_len);
|
||||
if (found != 2 || option_len != 2) {
|
||||
if (netreq->keepalive_sent == 1) {
|
||||
/* For TCP if no keepalive sent back, then we must use 0 idle timeout
|
||||
|
@ -1342,12 +1351,14 @@ _getdns_get_time_as_uintt64() {
|
|||
/**************************/
|
||||
|
||||
|
||||
static void stub_udp_write_cb(void *userarg);
|
||||
static void
|
||||
stub_udp_read_cb(void *userarg)
|
||||
{
|
||||
getdns_network_req *netreq = (getdns_network_req *)userarg;
|
||||
getdns_dns_req *dnsreq = netreq->owner;
|
||||
getdns_upstream *upstream = netreq->upstream;
|
||||
int prev_server_cookie = 0;
|
||||
ssize_t read;
|
||||
DEBUG_STUB("%s %-35s: MSG: %p \n", STUB_DEBUG_READ,
|
||||
__FUNC__, (void*)netreq);
|
||||
|
@ -1387,14 +1398,16 @@ stub_udp_read_cb(void *userarg)
|
|||
if (GLDNS_ID_WIRE(netreq->response) != GLDNS_ID_WIRE(netreq->query))
|
||||
return; /* Cache poisoning attempt ;) */
|
||||
|
||||
if (netreq->owner->edns_cookies && match_and_process_server_cookie(
|
||||
upstream, netreq->response, read))
|
||||
return; /* Client cookie didn't match? */
|
||||
|
||||
if (netreq->owner->edns_cookies) {
|
||||
prev_server_cookie = upstream->has_server_cookie;
|
||||
netreq->response_len = read;
|
||||
if (match_and_process_server_cookie(upstream, netreq)) {
|
||||
netreq->response_len = 0; /* 0 means error */
|
||||
return; /* Client cookie didn't match? */
|
||||
}
|
||||
netreq->response_len = 0; /* 0 means error */
|
||||
}
|
||||
GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event);
|
||||
|
||||
_getdns_closesocket(netreq->fd);
|
||||
netreq->fd = -1;
|
||||
while (GLDNS_TC_WIRE(netreq->response)) {
|
||||
DEBUG_STUB("%s %-35s: MSG: %p TC bit set in response \n", STUB_DEBUG_READ,
|
||||
__FUNC__, (void*)netreq);
|
||||
|
@ -1405,6 +1418,9 @@ stub_udp_read_cb(void *userarg)
|
|||
if (next_transport != GETDNS_TRANSPORT_TCP &&
|
||||
next_transport != GETDNS_TRANSPORT_TLS)
|
||||
break;
|
||||
|
||||
_getdns_closesocket(netreq->fd);
|
||||
netreq->fd = -1;
|
||||
/* For now, special case where fallback should be on the same upstream*/
|
||||
if ((netreq->fd = upstream_connect(upstream, next_transport,
|
||||
dnsreq)) == -1)
|
||||
|
@ -1414,10 +1430,27 @@ stub_udp_read_cb(void *userarg)
|
|||
_getdns_ms_until_expiry(dnsreq->expires),
|
||||
getdns_eventloop_event_init(&netreq->event,
|
||||
netreq, NULL, NULL, stub_timeout_cb));
|
||||
|
||||
return;
|
||||
}
|
||||
netreq->response_len = read;
|
||||
if (netreq->owner->edns_cookies
|
||||
&& !prev_server_cookie
|
||||
&& upstream->has_server_cookie /* newly learned server cookie */
|
||||
&& netreq->response_opt /* actually: assert(netreq->response_opt) */
|
||||
&& (netreq->response_opt[-4] << 4 | GLDNS_RCODE_WIRE(netreq->response))
|
||||
== GETDNS_RCODE_BADCOOKIE
|
||||
&& netreq->fd >= 0) {
|
||||
|
||||
/* Retry over UDP with the newly learned Cookie */
|
||||
GETDNS_SCHEDULE_EVENT(dnsreq->loop, netreq->fd,
|
||||
_getdns_ms_until_expiry(dnsreq->expires),
|
||||
getdns_eventloop_event_init(&netreq->event, netreq,
|
||||
NULL, stub_udp_write_cb, stub_timeout_cb));
|
||||
return;
|
||||
}
|
||||
_getdns_closesocket(netreq->fd);
|
||||
netreq->fd = -1;
|
||||
|
||||
if (!dnsreq->context->round_robin_upstreams)
|
||||
dnsreq->upstreams->current_udp = 0;
|
||||
else {
|
||||
|
@ -1428,7 +1461,7 @@ stub_udp_read_cb(void *userarg)
|
|||
netreq->debug_end_time = _getdns_get_time_as_uintt64();
|
||||
_getdns_netreq_change_state(netreq, NET_REQ_FINISHED);
|
||||
upstream->udp_responses++;
|
||||
upstream->back_off = 1;
|
||||
upstream->back_off = 1;
|
||||
if (upstream->udp_responses == 1 ||
|
||||
upstream->udp_responses % 100 == 0)
|
||||
_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_INFO,
|
||||
|
@ -1584,16 +1617,12 @@ upstream_read_cb(void *userarg)
|
|||
upstream->tcp.read_buf = NULL;
|
||||
upstream->responses_received++;
|
||||
|
||||
/* !THIS CODE NEEDS TESTING! */
|
||||
if (netreq->owner->edns_cookies &&
|
||||
match_and_process_server_cookie(
|
||||
netreq->upstream, upstream->tcp.read_buf,
|
||||
upstream->tcp.read_pos - upstream->tcp.read_buf))
|
||||
match_and_process_server_cookie(netreq->upstream, netreq))
|
||||
return; /* Client cookie didn't match (or FORMERR) */
|
||||
|
||||
if (netreq->owner->context->idle_timeout != 0)
|
||||
process_keepalive(netreq->upstream, netreq, netreq->response,
|
||||
netreq->response_len);
|
||||
process_keepalive(netreq->upstream, netreq);
|
||||
|
||||
netreq->debug_end_time = _getdns_get_time_as_uintt64();
|
||||
/* This also reschedules events for the upstream*/
|
||||
|
|
|
@ -267,6 +267,7 @@ typedef struct getdns_network_req
|
|||
size_t base_query_option_sz;
|
||||
size_t response_len;
|
||||
uint8_t *response;
|
||||
const uint8_t *response_opt; /* offset of OPT RR in response */
|
||||
size_t wire_data_sz;
|
||||
uint8_t wire_data[];
|
||||
|
||||
|
|
|
@ -642,6 +642,12 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
|
|||
rr_type == GETDNS_RRTYPE_RRSIG && rrsigs_in_answer)
|
||||
*rrsigs_in_answer = 1;
|
||||
|
||||
if (section == SECTION_ADDITIONAL &&
|
||||
rr_type == GETDNS_RRTYPE_OPT &&
|
||||
getdns_dict_set_int( result, "/header/extended_rcode"
|
||||
, (uint32_t)rr_iter->rr_type[4] << 4
|
||||
| GLDNS_RCODE_WIRE(req->response)))
|
||||
goto error;
|
||||
if (section != SECTION_ANSWER) {
|
||||
if (_getdns_list_append_this_dict(
|
||||
sections[section], rr_dict))
|
||||
|
|
Loading…
Reference in New Issue