Skip to content

Commit

Permalink
check dns response buffer as it is filled, and set truncate flag acco…
Browse files Browse the repository at this point in the history
…rdingly (#831)

check dns response buffer as it is filled, and set truncate flag accordingly
  • Loading branch information
scareything committed Apr 12, 2024
1 parent 964e6ab commit 9110284
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 12 deletions.
47 changes: 42 additions & 5 deletions lib/ziti-tunnel-cbs/dns_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,50 @@ static int fmt_txt(const ns_msg *msg, const ns_rr* rr, dns_answer *ans, size_t m

#else

void do_query(const dns_question *q, dns_message *resp, resolver_t *resolver) {
uint8_t resp_msg[PACKETSZ];
int rc = res_nquery(resolver, q->name, ns_c_in, q->type, resp_msg, PACKETSZ);
static uint8_t *send_and_parse_query(const dns_question *q, int class, ns_msg *ans, resolver_t *resolver) {
int buf_sz = PACKETSZ;
uint8_t *resp_msg = NULL;
int rc;

for (int attempt = 0; attempt < 2; attempt++) { // retry the query with a larger buffer if first attempt was truncated
resp_msg = calloc(buf_sz, sizeof(uint8_t));
memset(ans, 0, sizeof(dns_question));
rc = res_nquery(resolver, q->name, class, q->type, resp_msg, buf_sz);
if (rc < 0) {
ZITI_LOG(DEBUG, "res_query for %s failed", q->name);
break;
}
ns_initparse(resp_msg, rc, ans);
bool trunc = ns_msg_getflag(*ans, ns_f_tc);
if (!trunc) {
break;
} else {
if (attempt == 0) {
ZITI_LOG(DEBUG, "dns response truncated, repeating query with %d byte buffer", rc);
free(resp_msg);
resp_msg = NULL;
buf_sz = rc; // try again with large enough buffer
} else {
rc = -1;
}
}
}

if (rc < 0) {
free(resp_msg);
resp_msg = NULL;
}

return resp_msg;
}

void do_query(const dns_question *q, dns_message *resp, resolver_t *resolver) {
ns_msg ans = {0};
uint8_t *resp_msg = send_and_parse_query(q, ns_c_in, &ans, resolver);
if (resp_msg == NULL) {
resp->status = ns_r_servfail;
return;
} else {
ns_msg ans = {0};
ns_initparse(resp_msg, rc, &ans);
resp->status = ns_msg_getflag(ans, ns_f_rcode);
int rr_count = ns_msg_count(ans, ns_s_an);
if (rr_count > 0) {
Expand All @@ -172,6 +208,7 @@ void do_query(const dns_question *q, dns_message *resp, resolver_t *resolver) {
}
}
}
free(resp_msg);
}
}

Expand Down
46 changes: 39 additions & 7 deletions lib/ziti-tunnel-cbs/ziti_dns.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ typedef struct ziti_dns_client_s {
struct dns_req {
uint16_t id;
size_t req_len;
uint8_t req[512];
uint8_t req[4096];
size_t resp_len;
uint8_t resp[512];
uint8_t resp[4096];

dns_message msg;

Expand Down Expand Up @@ -426,7 +426,7 @@ const ip_addr_t *ziti_dns_register_hostname(const ziti_address *addr, void *inte
}
}

static const char DNS_OPT[] = { 0x0, 0x0, 0x29, 0x02, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
static const char DNS_OPT[] = { 0x0, 0x0, 0x29, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };

#define DNS_HEADER_LEN 12
#define DNS_ID(p) ((uint8_t)(p)[0] << 8 | (uint8_t)(p)[1])
Expand All @@ -436,6 +436,7 @@ static const char DNS_OPT[] = { 0x0, 0x0, 0x29, 0x02, 0x0, 0x0, 0x0, 0x0, 0x0, 0
#define DNS_RD(p) ((p)[2] & 0x1)

#define DNS_SET_RA(p) ((p)[3] = (p)[3] | 0x80)
#define DNS_SET_TC(p) ((p)[2] = (p)[2] | 0x2)
#define DNS_SET_CODE(p,c) ((p)[3] = (p)[3] | ((c) & 0xf))
#define DNS_SET_ANS(p) ((p)[2] = (p)[2] | 0x80)
#define DNS_SET_ARS(p,n) do{ (p)[6] = (n) >> 8; (p)[7] = (n) & 0xff; } while(0)
Expand Down Expand Up @@ -487,12 +488,20 @@ static void format_resp(struct dns_req *req) {
memcpy(req->resp + DNS_HEADER_LEN, req->req + DNS_HEADER_LEN, query_section_len);

uint8_t *rp = req->resp + DNS_HEADER_LEN + query_section_len;
uint8_t *resp_end = req->resp + sizeof(req->resp);
bool truncated = false;

if (req->msg.status == DNS_NO_ERROR && req->msg.answer != NULL) {
int ans_count = 0;
for (int i = 0; req->msg.answer[i] != NULL; i++) {
ans_count++;
dns_answer *a = req->msg.answer[i];

if (resp_end - rp < 10) { // 2 bytes for name ref, 2 for type, 2 for class, and 4 for ttl
truncated = true;
goto done;
}

// name ref
*rp++ = 0xc0;
*rp++ = 0x0c;
Expand All @@ -505,6 +514,10 @@ static void format_resp(struct dns_req *req) {

switch (a->type) {
case NS_T_A: {
if (resp_end - rp < (2 + sizeof(req->addr.s_addr))) {
truncated = true;
goto done;
}
SET_U16(rp, sizeof(req->addr.s_addr));
memcpy(rp, &req->addr.s_addr, sizeof(req->addr.s_addr));
rp += sizeof(req->addr.s_addr);
Expand All @@ -514,6 +527,10 @@ static void format_resp(struct dns_req *req) {
case NS_T_TXT: {
uint16_t txtlen = strlen(a->data);
uint16_t datalen = 1 + txtlen;
if (resp_end - rp < (3 + txtlen)) {
truncated = true;
goto done;
}
SET_U16(rp, datalen);
SET_U8(rp, txtlen);
memcpy(rp, a->data, txtlen);
Expand All @@ -523,8 +540,11 @@ static void format_resp(struct dns_req *req) {
case NS_T_MX: {
uint8_t *hold = rp;
rp += 2;
// uint16_t datalen = strlen(a->data) + 1 + 2;
// SET_U16(rp, datalen);
uint16_t datalen_est = strlen(a->data) + 1;
if (resp_end - hold < (4 + datalen_est)) {
truncated = true;
goto done;
}
SET_U16(rp, a->priority);
rp = format_name(rp, a->data);
uint16_t datalen = rp - hold - 2;
Expand All @@ -534,6 +554,11 @@ static void format_resp(struct dns_req *req) {
case NS_T_SRV: {
uint8_t *hold = rp;
rp += 2;
uint16_t datalen_est = strlen(a->data) + 1;
if (resp_end - hold < (8 + datalen_est)) {
truncated = true;
goto done;
}
SET_U16(rp, a->priority);
SET_U16(rp, a->weight);
SET_U16(rp, a->port);
Expand All @@ -546,12 +571,19 @@ static void format_resp(struct dns_req *req) {
ZITI_LOG(WARN, "unhandled response type[%d]", a->type);
}
}
done:
if (truncated) {
ZITI_LOG(DEBUG, "dns response truncated");
DNS_SET_TC(req->resp);
}
DNS_SET_ARS(req->resp, ans_count);
}

DNS_SET_AARS(req->resp, 1);
memcpy(rp, DNS_OPT, sizeof(DNS_OPT));
rp += sizeof(DNS_OPT);
if (resp_end - rp > 11) {
memcpy(rp, DNS_OPT, sizeof(DNS_OPT));
rp += sizeof(DNS_OPT);
}
req->resp_len = rp - req->resp;
}

Expand Down

0 comments on commit 9110284

Please sign in to comment.