Extended RCODE in OPT RR PsuedoRecord should not be exposed directly, it should be presented as part of the normal rcode

pull/617/head
Brad House 1 year ago
parent 4acd5759e9
commit b2ea0cd6b2
  1. 2
      include/ares_dns_record.h
  2. 5
      src/lib/ares_create_query.c
  3. 8
      src/lib/ares_dns_mapping.c
  4. 22
      src/lib/ares_dns_parse.c
  5. 6
      src/lib/ares_dns_private.h
  6. 25
      src/lib/ares_dns_record.c
  7. 18
      src/lib/ares_dns_write.c
  8. 18
      src/lib/ares_process.c
  9. 2
      test/ares-test-internal.cc

@ -232,8 +232,6 @@ typedef enum {
ARES_RR_NAPTR_REPLACEMENT = (ARES_REC_TYPE_NAPTR * 100) + 6,
/*! OPT Record. UDP Size. Datatype: U16 */
ARES_RR_OPT_UDP_SIZE = (ARES_REC_TYPE_OPT * 100) + 1,
/*! OPT Record. Extended RCode. Datatype: U8 */
ARES_RR_OPT_EXT_RCODE = (ARES_REC_TYPE_OPT * 100) + 2,
/*! OPT Record. Version. Datatype: U8 */
ARES_RR_OPT_VERSION = (ARES_REC_TYPE_OPT * 100) + 3,
/*! OPT Record. Flags. Datatype: U16 */

@ -83,11 +83,6 @@ int ares_create_query(const char *name, int dnsclass, int type,
goto done;
}
status = ares_dns_rr_set_u8(rr, ARES_RR_OPT_EXT_RCODE, 0);
if (status != ARES_SUCCESS) {
goto done;
}
status = ares_dns_rr_set_u8(rr, ARES_RR_OPT_VERSION, 0);
if (status != ARES_SUCCESS) {
goto done;

@ -338,9 +338,6 @@ const char *ares_dns_rr_key_tostr(ares_dns_rr_key_t key)
case ARES_RR_OPT_UDP_SIZE:
return "UDP_SIZE";
case ARES_RR_OPT_EXT_RCODE:
return "EXT_RCODE";
case ARES_RR_OPT_VERSION:
return "VERSION";
@ -460,7 +457,6 @@ ares_dns_datatype_t ares_dns_rr_key_datatype(ares_dns_rr_key_t key)
case ARES_RR_RAW_RR_TYPE:
return ARES_DATATYPE_U16;
case ARES_RR_OPT_EXT_RCODE:
case ARES_RR_OPT_VERSION:
case ARES_RR_TLSA_CERT_USAGE:
case ARES_RR_TLSA_SELECTOR:
@ -508,8 +504,8 @@ static const ares_dns_rr_key_t rr_naptr_keys[] = {
ARES_RR_NAPTR_SERVICES, ARES_RR_NAPTR_REGEXP, ARES_RR_NAPTR_REPLACEMENT
};
static const ares_dns_rr_key_t rr_opt_keys[] = {
ARES_RR_OPT_UDP_SIZE, ARES_RR_OPT_EXT_RCODE, ARES_RR_OPT_VERSION,
ARES_RR_OPT_FLAGS, ARES_RR_OPT_OPTIONS
ARES_RR_OPT_UDP_SIZE, ARES_RR_OPT_VERSION, ARES_RR_OPT_FLAGS,
ARES_RR_OPT_OPTIONS
};
static const ares_dns_rr_key_t rr_tlsa_keys[] = { ARES_RR_TLSA_CERT_USAGE,
ARES_RR_TLSA_SELECTOR,

@ -405,11 +405,9 @@ static ares_status_t ares_dns_parse_rr_opt(ares__buf_t *buf, ares_dns_rr_t *rr,
return status;
}
status = ares_dns_rr_set_u8(rr, ARES_RR_OPT_EXT_RCODE,
(unsigned char)(raw_ttl >> 24) & 0xFF);
if (status != ARES_SUCCESS) {
return status;
}
/* First 8 bits of TTL are an extended RCODE, and they go in the higher order
* after the original 4-bit rcode */
rr->parent->raw_rcode |= (unsigned short)((raw_ttl >> 20) & 0xFF0);
status = ares_dns_rr_set_u8(rr, ARES_RR_OPT_VERSION,
(unsigned char)(raw_ttl >> 16) & 0xFF);
@ -733,7 +731,7 @@ static ares_status_t ares_dns_parse_header(ares__buf_t *buf, unsigned int flags,
unsigned short id;
unsigned short dns_flags = 0;
ares_dns_opcode_t opcode;
ares_dns_rcode_t rcode;
unsigned short rcode;
(void)flags; /* currently unsed */
@ -843,11 +841,14 @@ static ares_status_t ares_dns_parse_header(ares__buf_t *buf, unsigned int flags,
goto fail;
}
status = ares_dns_record_create(dnsrec, id, dns_flags, opcode, rcode);
status = ares_dns_record_create(dnsrec, id, dns_flags, opcode,
ARES_RCODE_NOERROR /* Temporary */);
if (status != ARES_SUCCESS) {
goto fail;
}
(*dnsrec)->raw_rcode = rcode;
if (*ancount > 0) {
status =
ares_dns_record_rr_prealloc(*dnsrec, ARES_SECTION_ANSWER, *ancount);
@ -1197,6 +1198,13 @@ static ares_status_t ares_dns_parse_buf(ares__buf_t *buf, unsigned int flags,
}
}
/* Finalize rcode now that if we have OPT it is processed */
if (!ares_dns_rcode_isvalid((*dnsrec)->raw_rcode)) {
(*dnsrec)->rcode = ARES_RCODE_SERVFAIL;
} else {
(*dnsrec)->rcode = (ares_dns_rcode_t)(*dnsrec)->raw_rcode;
}
return ARES_SUCCESS;
fail:

@ -45,6 +45,7 @@ ares_status_t ares_dns_rr_set_opt_own(ares_dns_rr_t *dns_rr,
unsigned char *val, size_t val_len);
ares_status_t ares_dns_record_rr_prealloc(ares_dns_record_t *dnsrec,
ares_dns_section_t sect, size_t cnt);
ares_bool_t ares_dns_has_opt_rr(const ares_dns_record_t *rec);
struct ares_dns_qd {
char *name;
@ -128,7 +129,6 @@ typedef struct {
typedef struct {
unsigned short udp_size; /*!< taken from class */
unsigned char ext_rcode; /*!< Taken from first 8 bits of ttl */
unsigned char version; /*!< taken from bits 8-16 of ttl */
unsigned short flags; /*!< Flags, remaining 16 bits, though only
* 1 currently defined */
@ -172,6 +172,7 @@ typedef struct {
/*! DNS RR data structure */
struct ares_dns_rr {
ares_dns_record_t *parent;
char *name;
ares_dns_rec_type_t type;
ares_dns_class_t rclass;
@ -205,6 +206,9 @@ struct ares_dns_record {
unsigned short flags; /*!< One or more ares_dns_flags_t */
ares_dns_opcode_t opcode; /*!< DNS Opcode */
ares_dns_rcode_t rcode; /*!< DNS RCODE */
unsigned short raw_rcode; /*!< Raw rcode, used to ultimately form real
* rcode after reading OPT record if it
* exists */
ares_dns_qd_t *qd;
size_t qdcount;

@ -414,6 +414,7 @@ ares_status_t ares_dns_record_rr_add(ares_dns_rr_t **rr_out,
return ARES_ENOMEM;
}
rr->parent = dnsrec;
rr->type = type;
rr->rclass = rclass;
rr->ttl = ttl;
@ -498,6 +499,12 @@ ares_dns_rr_t *ares_dns_record_rr_get(ares_dns_record_t *dnsrec,
return &rr_ptr[idx];
}
static const ares_dns_rr_t *ares_dns_record_rr_get_const(const ares_dns_record_t *dnsrec,
ares_dns_section_t sect, size_t idx)
{
return ares_dns_record_rr_get((void *)((size_t)dnsrec), sect, idx);
}
const char *ares_dns_rr_get_name(const ares_dns_rr_t *rr)
{
if (rr == NULL) {
@ -626,9 +633,6 @@ static void *ares_dns_rr_data_ptr(ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key,
case ARES_RR_OPT_UDP_SIZE:
return &dns_rr->r.opt.udp_size;
case ARES_RR_OPT_EXT_RCODE:
return &dns_rr->r.opt.ext_rcode;
case ARES_RR_OPT_VERSION:
return &dns_rr->r.opt.version;
@ -1287,3 +1291,18 @@ fail:
ares__buf_destroy(buf);
return NULL;
}
/* search for an OPT RR in the response */
ares_bool_t ares_dns_has_opt_rr(const ares_dns_record_t *rec)
{
size_t i;
for (i = 0; i < ares_dns_record_rr_cnt(rec, ARES_SECTION_ADDITIONAL); i++) {
const ares_dns_rr_t *rr =
ares_dns_record_rr_get_const(rec, ARES_SECTION_ADDITIONAL, i);
if (ares_dns_rr_get_type(rr) == ARES_REC_TYPE_OPT) {
return ARES_TRUE;
}
}
return ARES_FALSE;
}

@ -93,7 +93,12 @@ static ares_status_t ares_dns_write_header(const ares_dns_record_t *dnsrec,
}
/* RCODE */
rcode = (unsigned short)(dnsrec->rcode & 0xF);
if (dnsrec->rcode > 15 && !ares_dns_has_opt_rr(dnsrec)) {
/* Must have OPT RR in order to write extended error codes */
rcode = ARES_RCODE_SERVFAIL;
} else {
rcode = (unsigned short)(dnsrec->rcode & 0xF);
}
u16 |= rcode;
status = ares__buf_append_be16(buf, u16);
@ -508,10 +513,11 @@ static ares_status_t ares_dns_write_rr_opt(ares__buf_t *buf,
const ares_dns_rr_t *rr,
ares__llist_t **namelist)
{
size_t len = ares__buf_len(buf);
ares_status_t status;
unsigned int ttl = 0;
size_t i;
size_t len = ares__buf_len(buf);
ares_status_t status;
unsigned int ttl = 0;
size_t i;
unsigned short rcode = (unsigned short)((rr->parent->rcode >> 4) & 0xFF);
(void)namelist;
@ -531,7 +537,7 @@ static ares_status_t ares_dns_write_rr_opt(ares__buf_t *buf,
}
/* TTL -> rcode (u8) << 24 | version (u8) << 16 | flags (u16) */
ttl |= (unsigned int)ares_dns_rr_get_u8(rr, ARES_RR_OPT_EXT_RCODE) << 24;
ttl |= (unsigned int)rcode << 24;
ttl |= (unsigned int)ares_dns_rr_get_u8(rr, ARES_RR_OPT_VERSION) << 16;
ttl |= (unsigned int)ares_dns_rr_get_u16(rr, ARES_RR_OPT_FLAGS);

@ -67,7 +67,6 @@ static ares_bool_t same_questions(const ares_dns_record_t *qrec,
const ares_dns_record_t *arec);
static ares_bool_t same_address(const struct sockaddr *sa,
const struct ares_addr *aa);
static ares_bool_t has_opt_rr(ares_dns_record_t *arec);
static void end_query(const ares_channel_t *channel, struct query *query,
ares_status_t status, const unsigned char *abuf,
size_t alen);
@ -660,7 +659,7 @@ static ares_status_t process_answer(ares_channel_t *channel,
* protocol extension is not understood by the responder. We must retry the
* query without EDNS enabled. */
if (ares_dns_record_get_rcode(rdnsrec) == ARES_RCODE_FORMERR &&
has_opt_rr(qdnsrec) && !has_opt_rr(rdnsrec)) {
ares_dns_has_opt_rr(qdnsrec) && !ares_dns_has_opt_rr(rdnsrec)) {
status = rewrite_without_edns(qdnsrec, query);
if (status != ARES_SUCCESS) {
end_query(channel, query, status, NULL, 0);
@ -1074,21 +1073,6 @@ static ares_bool_t same_address(const struct sockaddr *sa,
return ARES_FALSE; /* different */
}
/* search for an OPT RR in the response */
static ares_bool_t has_opt_rr(ares_dns_record_t *arec)
{
size_t i;
for (i = 0; i < ares_dns_record_rr_cnt(arec, ARES_SECTION_ADDITIONAL); i++) {
const ares_dns_rr_t *rr =
ares_dns_record_rr_get(arec, ARES_SECTION_ADDITIONAL, i);
if (ares_dns_rr_get_type(rr) == ARES_REC_TYPE_OPT) {
return ARES_TRUE;
}
}
return ARES_FALSE;
}
static void ares_detach_query(struct query *query)
{
/* Remove the query from all the lists in which it is linked */

@ -562,8 +562,6 @@ TEST_F(LibraryTest, DNSRecord) {
ARES_REC_TYPE_OPT, ARES_CLASS_IN, 0));
EXPECT_EQ(ARES_SUCCESS,
ares_dns_rr_set_u16(rr, ARES_RR_OPT_UDP_SIZE, 1280));
EXPECT_EQ(ARES_SUCCESS,
ares_dns_rr_set_u8(rr, ARES_RR_OPT_EXT_RCODE, 0));
EXPECT_EQ(ARES_SUCCESS,
ares_dns_rr_set_u8(rr, ARES_RR_OPT_VERSION, 0));
EXPECT_EQ(ARES_SUCCESS,

Loading…
Cancel
Save