Skip to content

Commit

Permalink
Basic support for SIG RR record (RFC 2931 / RFC 2535) (c-ares#773)
Browse files Browse the repository at this point in the history
With the current c-ares parser, as per PR c-ares#765 parsing was broken due to
validation that didn't understand the `SIG` record class. This PR adds
basic, non validating, and incomplete support for the `SIG` record type.
The additional `KEY` and `NXT` which would be required for additional
verification of the records is not implemented. It also does not store
the raw unprocessed RR data that would be required for the validation.

The primary purpose of this PR is to be able to recognize the record and
handle some periphery aspects such as validation of the class associated
with the RR and to not honor the TTL in the RR in the c-ares query cache
since it will always be 0.

Fixes c-ares#765
Fix By: Brad House (@bradh352)
  • Loading branch information
bradh352 authored Jun 3, 2024
1 parent 25ad4ca commit 6129d9b
Show file tree
Hide file tree
Showing 10 changed files with 347 additions and 9 deletions.
5 changes: 4 additions & 1 deletion docs/ares_dns_record.3
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ on requests, and some may only be valid on responses:
.B ARES_REC_TYPE_TXT
- Text strings
.br
.B ARES_REC_TYPE_SIG
- RFC 2535. RFC 2931. SIG Record
.br
.B ARES_REC_TYPE_AAAA
- RFC 3596. Ip6 Address
.br
Expand Down Expand Up @@ -161,7 +164,7 @@ DNS Header Opcodes:
- Zone change notification (RFC 1996)
.br
.B ARES_OPCODE_UPDATE
- Zone update message (RFC2136)
- Zone update message (RFC 2136)
.br
.RE

Expand Down
27 changes: 27 additions & 0 deletions docs/ares_dns_rr.3
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,33 @@ Keys used for handling RR record parameters:
.B ARES_RR_TXT_DATA
- TXT Record. Data. Datatype: \fIARES_DATATYPE_BINP\fP
.br
.B ARES_RR_SIG_TYPE_COVERED
- SIG Record. Type Covered. Datatype: \fIARES_DATATYPE_U16\fP
.br
.B ARES_RR_SIG_ALGORITHM
- SIG Record. Algorithm. Datatype: \fIARES_DATATYPE_U8\fP
.br
.B ARES_RR_SIG_LABELS
- SIG Record. Labels. Datatype: \fIARES_DATATYPE_U8\fP
.br
.B ARES_RR_SIG_ORIGINAL_TTL
- SIG Record. Original TTL. Datatype: \fIARES_DATATYPE_U32\fP
.br
.B ARES_RR_SIG_EXPIRATION
- SIG Record. Signature Expiration. Datatype: \fIARES_DATATYPE_U32\fP
.br
.B ARES_RR_SIG_INCEPTION
- SIG Record. Signature Inception. Datatype: \fIARES_DATATYPE_U32\fP
.br
.B ARES_RR_SIG_KEY_TAG
- SIG Record. Key Tag. Datatype: \fIARES_DATATYPE_U16\fP
.br
.B ARES_RR_SIG_SIGNERS_NAME
- SIG Record. Signer's Name. Datatype: \fIARES_DATATYPE_NAME\fP
.br
.B ARES_RR_SIG_SIGNATURE
- SIG Record. Signature. Datatype: \fIARES_DATATYPE_BIN\fP
.br
.B ARES_RR_AAAA_ADDR
- AAAA Record. Address. Datatype: \fIARES_DATATYPE_INADDR6\fP
.br
Expand Down
19 changes: 19 additions & 0 deletions include/ares_dns_record.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ typedef enum {
ARES_REC_TYPE_HINFO = 13, /*!< Host information. */
ARES_REC_TYPE_MX = 15, /*!< Mail routing information. */
ARES_REC_TYPE_TXT = 16, /*!< Text strings. */
ARES_REC_TYPE_SIG = 24, /*!< RFC 2535 / RFC 2931. SIG Record */
ARES_REC_TYPE_AAAA = 28, /*!< RFC 3596. Ip6 Address. */
ARES_REC_TYPE_SRV = 33, /*!< RFC 2782. Server Selection. */
ARES_REC_TYPE_NAPTR = 35, /*!< RFC 3403. Naming Authority Pointer */
Expand Down Expand Up @@ -208,6 +209,24 @@ typedef enum {
ARES_RR_MX_EXCHANGE = (ARES_REC_TYPE_MX * 100) + 2,
/*! TXT Record. Data. Datatype: BINP */
ARES_RR_TXT_DATA = (ARES_REC_TYPE_TXT * 100) + 1,
/*! SIG Record. Type Covered. Datatype: U16 */
ARES_RR_SIG_TYPE_COVERED = (ARES_REC_TYPE_SIG * 100) + 1,
/*! SIG Record. Algorithm. Datatype: U8 */
ARES_RR_SIG_ALGORITHM = (ARES_REC_TYPE_SIG * 100) + 2,
/*! SIG Record. Labels. Datatype: U8 */
ARES_RR_SIG_LABELS = (ARES_REC_TYPE_SIG * 100) + 3,
/*! SIG Record. Original TTL. Datatype: U32 */
ARES_RR_SIG_ORIGINAL_TTL = (ARES_REC_TYPE_SIG * 100) + 4,
/*! SIG Record. Signature Expiration. Datatype: U32 */
ARES_RR_SIG_EXPIRATION = (ARES_REC_TYPE_SIG * 100) + 5,
/*! SIG Record. Signature Inception. Datatype: U32 */
ARES_RR_SIG_INCEPTION = (ARES_REC_TYPE_SIG * 100) + 6,
/*! SIG Record. Key Tag. Datatype: U16 */
ARES_RR_SIG_KEY_TAG = (ARES_REC_TYPE_SIG * 100) + 7,
/*! SIG Record. Signers Name. Datatype: NAME */
ARES_RR_SIG_SIGNERS_NAME = (ARES_REC_TYPE_SIG * 100) + 8,
/*! SIG Record. Signature. Datatype: BIN */
ARES_RR_SIG_SIGNATURE = (ARES_REC_TYPE_SIG * 100) + 9,
/*! AAAA Record. Address. Datatype: INADDR6 */
ARES_RR_AAAA_ADDR = (ARES_REC_TYPE_AAAA * 100) + 1,
/*! SRV Record. Priority. Datatype: U16 */
Expand Down
73 changes: 70 additions & 3 deletions src/lib/ares_dns_mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ ares_bool_t ares_dns_rec_type_isvalid(ares_dns_rec_type_t type,
case ARES_REC_TYPE_HINFO:
case ARES_REC_TYPE_MX:
case ARES_REC_TYPE_TXT:
case ARES_REC_TYPE_SIG:
case ARES_REC_TYPE_AAAA:
case ARES_REC_TYPE_SRV:
case ARES_REC_TYPE_NAPTR:
Expand Down Expand Up @@ -133,17 +134,32 @@ ares_bool_t ares_dns_rec_type_allow_name_compression(ares_dns_rec_type_t type)
return ARES_FALSE;
}

ares_bool_t ares_dns_class_isvalid(ares_dns_class_t qclass,
ares_bool_t is_query)
ares_bool_t ares_dns_class_isvalid(ares_dns_class_t qclass,
ares_dns_rec_type_t type,
ares_bool_t is_query)
{
/* If we don't understand the record type, we shouldn't validate the class
* as there are some instances like on RFC 2391 (SIG RR) the class is
* meaningless, but since we didn't support that record type, we didn't
* know it shouldn't be validated */
if (type == ARES_REC_TYPE_RAW_RR) {
return ARES_TRUE;
}

switch (qclass) {
case ARES_CLASS_IN:
case ARES_CLASS_CHAOS:
case ARES_CLASS_HESOID:
case ARES_CLASS_NONE:
return ARES_TRUE;
case ARES_CLASS_ANY:
return is_query ? ARES_TRUE : ARES_FALSE;
if (type == ARES_REC_TYPE_SIG) {
return ARES_TRUE;
}
if (is_query) {
return ARES_TRUE;
}
return ARES_FALSE;
}
return ARES_FALSE;
}
Expand Down Expand Up @@ -191,6 +207,8 @@ const char *ares_dns_rec_type_tostr(ares_dns_rec_type_t type)
return "MX";
case ARES_REC_TYPE_TXT:
return "TXT";
case ARES_REC_TYPE_SIG:
return "SIG";
case ARES_REC_TYPE_AAAA:
return "AAAA";
case ARES_REC_TYPE_SRV:
Expand Down Expand Up @@ -305,6 +323,33 @@ const char *ares_dns_rr_key_tostr(ares_dns_rr_key_t key)
case ARES_RR_TXT_DATA:
return "DATA";

case ARES_RR_SIG_TYPE_COVERED:
return "TYPE_COVERED";

case ARES_RR_SIG_ALGORITHM:
return "ALGORITHM";

case ARES_RR_SIG_LABELS:
return "LABELS";

case ARES_RR_SIG_ORIGINAL_TTL:
return "ORIGINAL_TTL";

case ARES_RR_SIG_EXPIRATION:
return "EXPIRATION";

case ARES_RR_SIG_INCEPTION:
return "INCEPTION";

case ARES_RR_SIG_KEY_TAG:
return "KEY_TAG";

case ARES_RR_SIG_SIGNERS_NAME:
return "SIGNERS_NAME";

case ARES_RR_SIG_SIGNATURE:
return "SIGNATURE";

case ARES_RR_SRV_PRIORITY:
return "PRIORITY";

Expand Down Expand Up @@ -420,6 +465,7 @@ ares_dns_datatype_t ares_dns_rr_key_datatype(ares_dns_rr_key_t key)
case ARES_RR_SOA_RNAME:
case ARES_RR_PTR_DNAME:
case ARES_RR_MX_EXCHANGE:
case ARES_RR_SIG_SIGNERS_NAME:
case ARES_RR_SRV_TARGET:
case ARES_RR_SVCB_TARGET:
case ARES_RR_HTTPS_TARGET:
Expand All @@ -440,9 +486,14 @@ ares_dns_datatype_t ares_dns_rr_key_datatype(ares_dns_rr_key_t key)
case ARES_RR_SOA_RETRY:
case ARES_RR_SOA_EXPIRE:
case ARES_RR_SOA_MINIMUM:
case ARES_RR_SIG_ORIGINAL_TTL:
case ARES_RR_SIG_EXPIRATION:
case ARES_RR_SIG_INCEPTION:
return ARES_DATATYPE_U32;

case ARES_RR_MX_PREFERENCE:
case ARES_RR_SIG_TYPE_COVERED:
case ARES_RR_SIG_KEY_TAG:
case ARES_RR_SRV_PRIORITY:
case ARES_RR_SRV_WEIGHT:
case ARES_RR_SRV_PORT:
Expand All @@ -457,6 +508,8 @@ 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_SIG_ALGORITHM:
case ARES_RR_SIG_LABELS:
case ARES_RR_OPT_VERSION:
case ARES_RR_TLSA_CERT_USAGE:
case ARES_RR_TLSA_SELECTOR:
Expand All @@ -468,6 +521,7 @@ ares_dns_datatype_t ares_dns_rr_key_datatype(ares_dns_rr_key_t key)
case ARES_RR_TXT_DATA:
return ARES_DATATYPE_BINP;

case ARES_RR_SIG_SIGNATURE:
case ARES_RR_TLSA_DATA:
case ARES_RR_RAW_RR_DATA:
return ARES_DATATYPE_BIN;
Expand All @@ -494,6 +548,15 @@ static const ares_dns_rr_key_t rr_hinfo_keys[] = { ARES_RR_HINFO_CPU,
ARES_RR_HINFO_OS };
static const ares_dns_rr_key_t rr_mx_keys[] = { ARES_RR_MX_PREFERENCE,
ARES_RR_MX_EXCHANGE };
static const ares_dns_rr_key_t rr_sig_keys[] = { ARES_RR_SIG_TYPE_COVERED,
ARES_RR_SIG_ALGORITHM,
ARES_RR_SIG_LABELS,
ARES_RR_SIG_ORIGINAL_TTL,
ARES_RR_SIG_EXPIRATION,
ARES_RR_SIG_INCEPTION,
ARES_RR_SIG_KEY_TAG,
ARES_RR_SIG_SIGNERS_NAME,
ARES_RR_SIG_SIGNATURE };
static const ares_dns_rr_key_t rr_txt_keys[] = { ARES_RR_TXT_DATA };
static const ares_dns_rr_key_t rr_aaaa_keys[] = { ARES_RR_AAAA_ADDR };
static const ares_dns_rr_key_t rr_srv_keys[] = {
Expand Down Expand Up @@ -560,6 +623,9 @@ const ares_dns_rr_key_t *ares_dns_rr_get_keys(ares_dns_rec_type_t type,
case ARES_REC_TYPE_TXT:
*cnt = sizeof(rr_txt_keys) / sizeof(*rr_txt_keys);
return rr_txt_keys;
case ARES_REC_TYPE_SIG:
*cnt = sizeof(rr_sig_keys) / sizeof(*rr_sig_keys);
return rr_sig_keys;
case ARES_REC_TYPE_AAAA:
*cnt = sizeof(rr_aaaa_keys) / sizeof(*rr_aaaa_keys);
return rr_aaaa_keys;
Expand Down Expand Up @@ -644,6 +710,7 @@ ares_bool_t ares_dns_rec_type_fromstr(ares_dns_rec_type_t *qtype,
{ "HINFO", ARES_REC_TYPE_HINFO },
{ "MX", ARES_REC_TYPE_MX },
{ "TXT", ARES_REC_TYPE_TXT },
{ "SIG", ARES_REC_TYPE_SIG },
{ "AAAA", ARES_REC_TYPE_AAAA },
{ "SRV", ARES_REC_TYPE_SRV },
{ "NAPTR", ARES_REC_TYPE_NAPTR },
Expand Down
70 changes: 70 additions & 0 deletions src/lib/ares_dns_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,74 @@ static ares_status_t ares_dns_parse_rr_txt(ares__buf_t *buf, ares_dns_rr_t *rr,
ARES_RR_TXT_DATA);
}

static ares_status_t ares_dns_parse_rr_sig(ares__buf_t *buf, ares_dns_rr_t *rr,
size_t rdlength)
{
ares_status_t status;
size_t orig_len = ares__buf_len(buf);
size_t len;
unsigned char *data;

status = ares_dns_parse_and_set_be16(buf, rr, ARES_RR_SIG_TYPE_COVERED);
if (status != ARES_SUCCESS) {
return status;
}

status = ares_dns_parse_and_set_u8(buf, rr, ARES_RR_SIG_ALGORITHM);
if (status != ARES_SUCCESS) {
return status;
}

status = ares_dns_parse_and_set_u8(buf, rr, ARES_RR_SIG_LABELS);
if (status != ARES_SUCCESS) {
return status;
}

status = ares_dns_parse_and_set_be32(buf, rr, ARES_RR_SIG_ORIGINAL_TTL);
if (status != ARES_SUCCESS) {
return status;
}

status = ares_dns_parse_and_set_be32(buf, rr, ARES_RR_SIG_EXPIRATION);
if (status != ARES_SUCCESS) {
return status;
}

status = ares_dns_parse_and_set_be32(buf, rr, ARES_RR_SIG_INCEPTION);
if (status != ARES_SUCCESS) {
return status;
}

status = ares_dns_parse_and_set_be16(buf, rr, ARES_RR_SIG_KEY_TAG);
if (status != ARES_SUCCESS) {
return status;
}

status = ares_dns_parse_and_set_dns_name(buf, ARES_FALSE, rr,
ARES_RR_SIG_SIGNERS_NAME);
if (status != ARES_SUCCESS) {
return status;
}

len = ares_dns_rr_remaining_len(buf, orig_len, rdlength);
if (len == 0) {
return ARES_EBADRESP;
}

status = ares__buf_fetch_bytes_dup(buf, len, ARES_FALSE, &data);
if (status != ARES_SUCCESS) {
return status;
}

status = ares_dns_rr_set_bin_own(rr, ARES_RR_SIG_SIGNATURE, data, len);
if (status != ARES_SUCCESS) {
ares_free(data);
return status;
}

return ARES_SUCCESS;
}

static ares_status_t ares_dns_parse_rr_aaaa(ares__buf_t *buf, ares_dns_rr_t *rr,
size_t rdlength)
{
Expand Down Expand Up @@ -912,6 +980,8 @@ static ares_status_t
return ares_dns_parse_rr_mx(buf, rr, rdlength);
case ARES_REC_TYPE_TXT:
return ares_dns_parse_rr_txt(buf, rr, rdlength);
case ARES_REC_TYPE_SIG:
return ares_dns_parse_rr_sig(buf, rr, rdlength);
case ARES_REC_TYPE_AAAA:
return ares_dns_parse_rr_aaaa(buf, rr, rdlength);
case ARES_REC_TYPE_SRV:
Expand Down
19 changes: 17 additions & 2 deletions src/lib/ares_dns_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ ares_bool_t ares_dns_rcode_isvalid(ares_dns_rcode_t rcode);
ares_bool_t ares_dns_flags_arevalid(unsigned short flags);
ares_bool_t ares_dns_rec_type_isvalid(ares_dns_rec_type_t type,
ares_bool_t is_query);
ares_bool_t ares_dns_class_isvalid(ares_dns_class_t qclass,
ares_bool_t is_query);
ares_bool_t ares_dns_class_isvalid(ares_dns_class_t qclass,
ares_dns_rec_type_t type,
ares_bool_t is_query);
ares_bool_t ares_dns_section_isvalid(ares_dns_section_t sect);
ares_status_t ares_dns_rr_set_str_own(ares_dns_rr_t *dns_rr,
ares_dns_rr_key_t key, char *val);
Expand Down Expand Up @@ -123,6 +124,19 @@ typedef struct {
size_t data_len;
} ares__dns_txt_t;

typedef struct {
unsigned short type_covered;
unsigned char algorithm;
unsigned char labels;
unsigned int original_ttl;
unsigned int expiration;
unsigned int inception;
unsigned short key_tag;
char *signers_name;
unsigned char *signature;
size_t signature_len;
} ares__dns_sig_t;

typedef struct {
struct ares_in6_addr addr;
} ares__dns_aaaa_t;
Expand Down Expand Up @@ -216,6 +230,7 @@ struct ares_dns_rr {
ares__dns_hinfo_t hinfo;
ares__dns_mx_t mx;
ares__dns_txt_t txt;
ares__dns_sig_t sig;
ares__dns_aaaa_t aaaa;
ares__dns_srv_t srv;
ares__dns_naptr_t naptr;
Expand Down
Loading

0 comments on commit 6129d9b

Please sign in to comment.