Added flags to are_dns_parse to force RAW packet parsing (#693)

This pull request adds six flags to instruct the parser under various circumstances to skip parsing of the returned RR records so the raw data can be retrieved.

Fixes Bug: #686
Fix By: Erik Lax (@eriklax)
pull/698/head
Erik Lax 10 months ago committed by GitHub
parent d6850eb4ad
commit 26642c1014
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 22
      docs/ares_dns_record.3
  2. 12
      include/ares_dns_record.h
  3. 14
      src/lib/ares_dns_parse.c
  4. 116
      test/ares-test-internal.cc

@ -252,6 +252,28 @@ zone denoted by the Zone Section.
.br
.RE
.B ares_dns_parse_flags_t -
Flags for altering \fIares_dns_parse(3)\fP behaviour:
.RS 4
.B ARES_DNS_PARSE_AN_BASE_RAW
- Parse Answer Section from RFC 1035 that allow name compression as RAW RR type
.br
.B ARES_DNS_PARSE_NS_BASE_RAW
- Parse Authority Section from RFC 1035 that allow name compression as RAW RR type
.br
.B ARES_DNS_PARSE_AR_BASE_RAW
- Parse Additional Section from RFC 1035 that allow name compression as RAW RR type
.br
.B ARES_DNS_PARSE_AN_EXT_RAW
- Parse Answer Section from later RFCs (no name compression) as RAW RR type
.br
.B ARES_DNS_PARSE_NS_EXT_RAW
- Parse Authority Section from later RFCs (no name compression) as RAW RR type
.br
.B ARES_DNS_PARSE_AR_EXT_RAW
- Parse Additional Section from later RFCs (no name compression) as RAW RR type
.br
.RE
.SH DESCRIPTION

@ -384,6 +384,16 @@ typedef enum {
ARES_OPT_DATATYPE_NAME = 11
} ares_dns_opt_datatype_t;
/*! Data type for flags to ares_dns_parse() */
typedef enum {
ARES_DNS_PARSE_AN_BASE_RAW = 1 << 0, /*!< Parse Answers from RFC 1035 that allow name compression as RAW */
ARES_DNS_PARSE_NS_BASE_RAW = 1 << 1, /*!< Parse Authority from RFC 1035 that allow name compression as RAW */
ARES_DNS_PARSE_AR_BASE_RAW = 1 << 2, /*!< Parse Additional from RFC 1035 that allow name compression as RAW */
ARES_DNS_PARSE_AN_EXT_RAW = 1 << 3, /*!< Parse Answers from later RFCs (no name compression) RAW */
ARES_DNS_PARSE_NS_EXT_RAW = 1 << 4, /*!< Parse Authority from later RFCs (no name compression) as RAW */
ARES_DNS_PARSE_AR_EXT_RAW = 1 << 5, /*!< Parse Additional from later RFCs (no name compression) as RAW */
} ares_dns_parse_flags_t;
/*! String representation of DNS Record Type
*
* \param[in] type DNS Record Type
@ -926,7 +936,7 @@ CARES_EXTERN ares_bool_t ares_dns_rr_get_opt_byid(const ares_dns_rr_t *dns_rr
*
* \param[in] buf pointer to bytes to be parsed
* \param[in] buf_len Length of buf provided
* \param[in] flags Flags dictating how the message should be parsed. TBD.
* \param[in] flags Flags dictating how the message should be parsed.
* \param[out] dnsrec Pointer passed by reference for a new DNS record object
* that must be ares_dns_record_destroy()'d by caller.
* \return ARES_SUCCESS on success

@ -1003,8 +1003,7 @@ static ares_status_t ares_dns_parse_rr(ares__buf_t *buf, unsigned int flags,
ares_dns_rr_t *rr = NULL;
size_t remaining_len = 0;
size_t processed_len = 0;
(void)flags; /* currently unused */
ares_bool_t namecomp;
/* All RRs have the same top level format shown below:
* 1 1 1 1 1 1
@ -1067,6 +1066,17 @@ static ares_status_t ares_dns_parse_rr(ares__buf_t *buf, unsigned int flags,
type = ARES_REC_TYPE_RAW_RR;
}
namecomp = ares_dns_rec_type_allow_name_compression(type);
if (sect == ARES_SECTION_ANSWER && (flags & (namecomp ? ARES_DNS_PARSE_AN_BASE_RAW : ARES_DNS_PARSE_AN_EXT_RAW))) {
type = ARES_REC_TYPE_RAW_RR;
}
if (sect == ARES_SECTION_AUTHORITY && (flags & (namecomp ? ARES_DNS_PARSE_NS_BASE_RAW : ARES_DNS_PARSE_NS_EXT_RAW))) {
type = ARES_REC_TYPE_RAW_RR;
}
if (sect == ARES_SECTION_ADDITIONAL && (flags & (namecomp ? ARES_DNS_PARSE_AR_BASE_RAW : ARES_DNS_PARSE_AR_EXT_RAW))) {
type = ARES_REC_TYPE_RAW_RR;
}
/* Pull into another buffer for safety */
if (rdlength > ares__buf_len(buf)) {
status = ARES_EBADRESP;

@ -816,6 +816,122 @@ TEST_F(LibraryTest, DNSRecord) {
ares_free(msg);
}
TEST_F(LibraryTest, DNSParseFlags) {
ares_dns_record_t *dnsrec = NULL;
ares_dns_rr_t *rr = NULL;
struct in_addr addr;
unsigned char *msg = NULL;
size_t msglen = 0;
EXPECT_EQ(ARES_SUCCESS,
ares_dns_record_create(&dnsrec, 0x1234,
ARES_FLAG_QR|ARES_FLAG_AA|ARES_FLAG_RD|ARES_FLAG_RA,
ARES_OPCODE_QUERY, ARES_RCODE_NOERROR));
/* == Question == */
EXPECT_EQ(ARES_SUCCESS,
ares_dns_record_query_add(dnsrec, "example.com",
ARES_REC_TYPE_ANY,
ARES_CLASS_IN));
/* == Answer == */
/* A */
EXPECT_EQ(ARES_SUCCESS,
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ANSWER, "example.com",
ARES_REC_TYPE_A, ARES_CLASS_IN, 300));
EXPECT_LT(0, ares_inet_net_pton(AF_INET, "1.1.1.1", &addr, sizeof(addr)));
EXPECT_EQ(ARES_SUCCESS,
ares_dns_rr_set_addr(rr, ARES_RR_A_ADDR, &addr));
/* TLSA */
EXPECT_EQ(ARES_SUCCESS,
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ANSWER,
"_443._tcp.example.com", ARES_REC_TYPE_TLSA, ARES_CLASS_IN, 86400));
EXPECT_EQ(ARES_SUCCESS,
ares_dns_rr_set_u8(rr, ARES_RR_TLSA_CERT_USAGE, ARES_TLSA_USAGE_CA));
EXPECT_EQ(ARES_SUCCESS,
ares_dns_rr_set_u8(rr, ARES_RR_TLSA_SELECTOR, ARES_TLSA_SELECTOR_FULL));
EXPECT_EQ(ARES_SUCCESS,
ares_dns_rr_set_u8(rr, ARES_RR_TLSA_MATCH, ARES_TLSA_MATCH_SHA256));
const unsigned char tlsa[] = {
0xd2, 0xab, 0xde, 0x24, 0x0d, 0x7c, 0xd3, 0xee, 0x6b, 0x4b, 0x28, 0xc5,
0x4d, 0xf0, 0x34, 0xb9, 0x79, 0x83, 0xa1, 0xd1, 0x6e, 0x8a, 0x41, 0x0e,
0x45, 0x61, 0xcb, 0x10, 0x66, 0x18, 0xe9, 0x71 };
EXPECT_EQ(ARES_SUCCESS,
ares_dns_rr_set_bin(rr, ARES_RR_TLSA_DATA, tlsa, sizeof(tlsa)));
/* == Authority == */
/* NS */
EXPECT_EQ(ARES_SUCCESS,
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_AUTHORITY, "example.com",
ARES_REC_TYPE_NS, ARES_CLASS_IN, 38400));
EXPECT_EQ(ARES_SUCCESS,
ares_dns_rr_set_str(rr, ARES_RR_NS_NSDNAME, "ns1.example.com"));
/* == Additional */
/* PTR -- doesn't make sense, but ok */
EXPECT_EQ(ARES_SUCCESS,
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "example.com",
ARES_REC_TYPE_PTR, ARES_CLASS_IN, 300));
EXPECT_EQ(ARES_SUCCESS,
ares_dns_rr_set_str(rr, ARES_RR_PTR_DNAME, "b.example.com"));
/* Write */
EXPECT_EQ(ARES_SUCCESS, ares_dns_write(dnsrec, &msg, &msglen));
/* Cleanup - before reuse */
ares_dns_record_destroy(dnsrec);
/* Parse "base" type records (1035) */
EXPECT_EQ(ARES_SUCCESS, ares_dns_parse(msg, msglen, ARES_DNS_PARSE_AN_BASE_RAW |
ARES_DNS_PARSE_NS_BASE_RAW | ARES_DNS_PARSE_AR_BASE_RAW, &dnsrec));
EXPECT_EQ(1, ares_dns_record_query_cnt(dnsrec));
EXPECT_EQ(2, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER));
EXPECT_EQ(1, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_AUTHORITY));
EXPECT_EQ(1, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ADDITIONAL));
rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, 0);
EXPECT_EQ(ARES_REC_TYPE_RAW_RR, ares_dns_rr_get_type(rr));
rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, 1);
EXPECT_EQ(ARES_REC_TYPE_TLSA, ares_dns_rr_get_type(rr));
rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_AUTHORITY, 0);
EXPECT_EQ(ARES_REC_TYPE_RAW_RR, ares_dns_rr_get_type(rr));
rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_ADDITIONAL, 0);
EXPECT_EQ(ARES_REC_TYPE_RAW_RR, ares_dns_rr_get_type(rr));
/* Cleanup - before reuse */
ares_dns_record_destroy(dnsrec);
/* Parse later RFCs (no name compression) type records */
EXPECT_EQ(ARES_SUCCESS, ares_dns_parse(msg, msglen, ARES_DNS_PARSE_AN_EXT_RAW |
ARES_DNS_PARSE_NS_EXT_RAW | ARES_DNS_PARSE_AR_EXT_RAW, &dnsrec));
EXPECT_EQ(1, ares_dns_record_query_cnt(dnsrec));
EXPECT_EQ(2, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER));
EXPECT_EQ(1, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_AUTHORITY));
EXPECT_EQ(1, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ADDITIONAL));
rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, 0);
EXPECT_EQ(ARES_REC_TYPE_A, ares_dns_rr_get_type(rr));
rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, 1);
EXPECT_EQ(ARES_REC_TYPE_RAW_RR, ares_dns_rr_get_type(rr));
rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_AUTHORITY, 0);
EXPECT_EQ(ARES_REC_TYPE_NS, ares_dns_rr_get_type(rr));
rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_ADDITIONAL, 0);
EXPECT_EQ(ARES_REC_TYPE_PTR, ares_dns_rr_get_type(rr));
ares_dns_record_destroy(dnsrec);
ares_free(msg); msg = NULL;
}
TEST_F(LibraryTest, CatDomain) {
char *s;

Loading…
Cancel
Save