Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions subsys/net/lib/dns/dns_pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include <string.h>
#include <zephyr/net/buf.h>
#include <zephyr/sys/bitarray.h>
#include <zephyr/net/dns_resolve.h>

#include "dns_pack.h"

Expand Down Expand Up @@ -361,10 +363,11 @@ int dns_unpack_response_query(struct dns_msg_t *dns_msg)
int dns_copy_qname(uint8_t *buf, uint16_t *len, uint16_t size,
struct dns_msg_t *dns_msg, uint16_t pos)
{
SYS_BITARRAY_DEFINE(visited, DNS_RESOLVER_MAX_BUF_SIZE);
uint16_t msg_size = dns_msg->msg_size;
uint8_t *msg = dns_msg->msg;
uint16_t lb_size;
int rc = -EINVAL;
int rc = -EINVAL, ret, prev;

*len = 0U;

Expand All @@ -377,7 +380,7 @@ int dns_copy_qname(uint8_t *buf, uint16_t *len, uint16_t size,
lb_size = msg[pos];

/* pointer */
if (lb_size > DNS_LABEL_MAX_SIZE) {
if ((lb_size & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
uint8_t mask = DNS_LABEL_MAX_SIZE;

if (pos + 1 >= msg_size) {
Expand All @@ -388,7 +391,21 @@ int dns_copy_qname(uint8_t *buf, uint16_t *len, uint16_t size,
/* See: RFC 1035, 4.1.4. Message compression */
pos = ((msg[pos] & mask) << 8) + msg[pos + 1];

ret = sys_bitarray_test_and_set_bit(&visited, pos, &prev);
if (ret < 0) {
rc = -EINVAL;
break;
}

if (prev) {
rc = -ELOOP;
break;
}

continue;
} else if (lb_size & NS_CMPRSFLGS) {
rc = -EINVAL;
break;
}

/* validate that the label (i.e. size + elements),
Expand Down Expand Up @@ -477,7 +494,7 @@ static int dns_unpack_name(const uint8_t *msg, int maxlen, const uint8_t *src,
}

while ((val = *curr_src++)) {
if (val & NS_CMPRSFLGS) {
if ((val & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
/* Follow pointer */
int pos;

Expand Down
17 changes: 12 additions & 5 deletions subsys/net/lib/dns/resolve.c
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,8 @@ int dns_validate_msg(struct dns_resolve_context *ctx,

ret = dns_unpack_response_header(dns_msg, *dns_id);
if (ret < 0) {
ret = DNS_EAI_FAIL;
errno = -ret;
ret = DNS_EAI_SYSTEM;
goto quit;
}

Expand All @@ -711,7 +712,8 @@ int dns_validate_msg(struct dns_resolve_context *ctx,
ret = dns_unpack_response_query(dns_msg);
if (ret < 0) {
if (ret == -ENOMEM) {
ret = DNS_EAI_FAIL;
errno = -ret;
ret = DNS_EAI_SYSTEM;
goto quit;
}

Expand Down Expand Up @@ -742,7 +744,8 @@ int dns_validate_msg(struct dns_resolve_context *ctx,
ret = dns_unpack_answer(dns_msg, answer_ptr, &ttl,
&answer_type);
if (ret < 0) {
ret = DNS_EAI_FAIL;
errno = -ret;
ret = DNS_EAI_SYSTEM;
goto quit;
}

Expand Down Expand Up @@ -809,14 +812,16 @@ int dns_validate_msg(struct dns_resolve_context *ctx,

if (dns_msg->response_length < address_size) {
/* it seems this is a malformed message */
ret = DNS_EAI_FAIL;
errno = EMSGSIZE;
ret = DNS_EAI_SYSTEM;
goto quit;
}

if ((dns_msg->response_position + address_size) >
dns_msg->msg_size) {
/* Too short message */
ret = DNS_EAI_FAIL;
errno = EMSGSIZE;
ret = DNS_EAI_SYSTEM;
goto quit;
}

Expand Down Expand Up @@ -862,6 +867,7 @@ int dns_validate_msg(struct dns_resolve_context *ctx,

*query_idx = get_slot_by_id(ctx, *dns_id, *query_hash);
if (*query_idx < 0) {
errno = ENOENT;
ret = DNS_EAI_SYSTEM;
goto quit;
}
Expand All @@ -884,6 +890,7 @@ int dns_validate_msg(struct dns_resolve_context *ctx,
net_buf_max_len(dns_cname),
dns_msg, pos);
if (ret < 0) {
errno = -ret;
ret = DNS_EAI_SYSTEM;
goto quit;
}
Expand Down
247 changes: 247 additions & 0 deletions tests/net/lib/dns_packet/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1287,6 +1287,253 @@ ZTEST(dns_packet, test_dns_invalid_answer)
zassert_equal(ret, -EINVAL, "DNS message answer check succeed (%d)", ret);
}

static uint8_t recursive_query_resp_ipv4[] = {
/* DNS msg header (12 bytes) */
0x74, 0xe1, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00,

/* Query string (westus2-prod-2.notifications.teams.microsoft.com)
* (length 50)
*/
0x0e, 0x77, 0x65, 0x73, 0x74, 0x75, 0x73, 0x32,
0x2d, 0x70, 0x72, 0x6f, 0x64, 0x2d, 0x32, 0x0d,
0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x05, 0x74, 0x65,
0x61, 0x6d, 0x73, 0x09, 0x6d, 0x69, 0x63, 0x72,
0x6f, 0x73, 0x6f, 0x66, 0x74, 0x03, 0x63, 0x6f,
0x6d, 0x00,

/* Type (2 bytes) */
0x00, 0x01,

/* Class (2 bytes) */
0x00, 0x01,

/* Answer 1 */
0xc0, 0x0c,

/* Answer type (cname) */
0x00, 0x05,

/* Class */
0x00, 0x01,

/* TTL */
0x00, 0x00, 0x00, 0x04,

/* RR data length */
0x00, 0x02,

/* Data */
0xc0, 0x4e, /* <--- recursive pointer */
};

NET_BUF_POOL_DEFINE(dns_qname_pool_for_test, 2, 128, 0, NULL);

ZTEST(dns_packet, test_dns_recursive_query)
{
static const uint8_t query[] = {
/* Query string */
0x0e, 0x77, 0x65, 0x73, 0x74, 0x75, 0x73, 0x32,
0x2d, 0x70, 0x72, 0x6f, 0x64, 0x2d, 0x32, 0x0d,
0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x05, 0x74, 0x65,
0x61, 0x6d, 0x73, 0x09, 0x6d, 0x69, 0x63, 0x72,
0x6f, 0x73, 0x6f, 0x66, 0x74, 0x03, 0x63, 0x6f,
0x6d, 0x00,

/* Type */
0x00, 0x01,
};
struct dns_msg_t dns_msg = { 0 };
uint16_t dns_id = 0;
int query_idx = -1;
uint16_t query_hash = 0;
struct net_buf *dns_cname;
int ret;

dns_cname = net_buf_alloc(&dns_qname_pool_for_test, dns_ctx.buf_timeout);
zassert_not_null(dns_cname, "Out of mem");

dns_msg.msg = recursive_query_resp_ipv4;
dns_msg.msg_size = sizeof(recursive_query_resp_ipv4);

dns_id = dns_unpack_header_id(dns_msg.msg);

setup_dns_context(&dns_ctx, 0, dns_id, query, sizeof(query),
DNS_QUERY_TYPE_A);

ret = dns_validate_msg(&dns_ctx, &dns_msg, &dns_id, &query_idx,
dns_cname, &query_hash);
zassert_true(ret == DNS_EAI_SYSTEM && errno == ELOOP,
"[%s] DNS message was valid (%d / %d)",
"recursive rsp", ret, errno);

net_buf_unref(dns_cname);
}

static uint8_t invalid_compression_response_ipv4[] = {
/* DNS msg header (12 bytes) */
0x74, 0xe1, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00,

/* Query string */
0x0e, 0x77, 0x65, 0x73, 0x74, 0x75, 0x73, 0x32,
0x2d, 0x70, 0x72, 0x6f, 0x64, 0x2d, 0x32, 0x0d,
0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x05, 0x74, 0x65,
0x61, 0x6d, 0x73, 0x09, 0x6d, 0x69, 0x63, 0x72,
0x6f, 0x73, 0x6f, 0x66, 0x74, 0x03, 0x63, 0x6f,
0x6d, 0x00,

/* Type */
0x00, 0x01,

/* Class */
0x00, 0x01,

/* Answer 1 */
0xb0, 0x0c, /* <--- invalid compression pointer */

/* Answer type (cname) */
0x00, 0x05,

/* Class */
0x00, 0x01,

/* TTL */
0x00, 0x00, 0x00, 0x04,

/* RR data length */
0x00, 0x02,

/* Data */
0xc0, 0x0c,
};

ZTEST(dns_packet, test_dns_invalid_compress_bits)
{
static const uint8_t query[] = {
/* Query string */
0x0e, 0x77, 0x65, 0x73, 0x74, 0x75, 0x73, 0x32,
0x2d, 0x70, 0x72, 0x6f, 0x64, 0x2d, 0x32, 0x0d,
0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x05, 0x74, 0x65,
0x61, 0x6d, 0x73, 0x09, 0x6d, 0x69, 0x63, 0x72,
0x6f, 0x73, 0x6f, 0x66, 0x74, 0x03, 0x63, 0x6f,
0x6d, 0x00,

/* Type */
0x00, 0x01,
};
struct dns_msg_t dns_msg = { 0 };
uint16_t dns_id = 0;
int query_idx = -1;
uint16_t query_hash = 0;
struct net_buf *dns_cname;
int ret;

dns_cname = net_buf_alloc(&dns_qname_pool_for_test, dns_ctx.buf_timeout);
zassert_not_null(dns_cname, "Out of mem");

dns_msg.msg = invalid_compression_response_ipv4;
dns_msg.msg_size = sizeof(invalid_compression_response_ipv4);

dns_id = dns_unpack_header_id(dns_msg.msg);

setup_dns_context(&dns_ctx, 0, dns_id, query, sizeof(query),
DNS_QUERY_TYPE_A);

ret = dns_validate_msg(&dns_ctx, &dns_msg, &dns_id, &query_idx,
dns_cname, &query_hash);
zassert_true(ret == DNS_EAI_SYSTEM && errno == EINVAL,
"[%s] DNS message was valid (%d / %d)",
"invalid compression rsp", ret, errno);

net_buf_unref(dns_cname);
}

static uint8_t invalid_compression_response_cname_ipv4[] = {
/* DNS msg header (12 bytes) */
0x74, 0xe1, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00,

/* Query string */
0x0e, 0x77, 0x65, 0x73, 0x74, 0x75, 0x73, 0x32,
0x2d, 0x70, 0x72, 0x6f, 0x64, 0x2d, 0x32, 0x0d,
0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x05, 0x74, 0x65,
0x61, 0x6d, 0x73, 0x09, 0x6d, 0x69, 0x63, 0x72,
0x6f, 0x73, 0x6f, 0x66, 0x74, 0x03, 0x63, 0x6f,
0x6d, 0x00,

/* Type */
0x00, 0x01,

/* Class */
0x00, 0x01,

/* Answer 1 */
0xc0, 0x0c,

/* Answer type (cname) */
0x00, 0x05,

/* Class */
0x00, 0x01,

/* TTL */
0x00, 0x00, 0x00, 0x04,

/* RR data length */
0x00, 0x02,

/* Data */
0xb0, 0x0c, /* <--- invalid compression pointer */
};

ZTEST(dns_packet, test_dns_invalid_compress_bits_cname)
{
static const uint8_t query[] = {
/* Query string */
0x0e, 0x77, 0x65, 0x73, 0x74, 0x75, 0x73, 0x32,
0x2d, 0x70, 0x72, 0x6f, 0x64, 0x2d, 0x32, 0x0d,
0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x05, 0x74, 0x65,
0x61, 0x6d, 0x73, 0x09, 0x6d, 0x69, 0x63, 0x72,
0x6f, 0x73, 0x6f, 0x66, 0x74, 0x03, 0x63, 0x6f,
0x6d, 0x00,

/* Type */
0x00, 0x01,
};
struct dns_msg_t dns_msg = { 0 };
uint16_t dns_id = 0;
int query_idx = -1;
uint16_t query_hash = 0;
struct net_buf *dns_cname;
int ret;

dns_cname = net_buf_alloc(&dns_qname_pool_for_test, dns_ctx.buf_timeout);
zassert_not_null(dns_cname, "Out of mem");

dns_msg.msg = invalid_compression_response_cname_ipv4;
dns_msg.msg_size = sizeof(invalid_compression_response_cname_ipv4);

dns_id = dns_unpack_header_id(dns_msg.msg);

setup_dns_context(&dns_ctx, 0, dns_id, query, sizeof(query),
DNS_QUERY_TYPE_A);

ret = dns_validate_msg(&dns_ctx, &dns_msg, &dns_id, &query_idx,
dns_cname, &query_hash);
zassert_true(ret == DNS_EAI_SYSTEM && errno == EINVAL,
"[%s] DNS message was valid (%d / %d)",
"invalid compression rsp", ret, errno);

net_buf_unref(dns_cname);
}

ZTEST_SUITE(dns_packet, NULL, NULL, NULL, NULL, NULL);
/* TODO:
* 1) add malformed DNS data (mostly done)
Expand Down
Loading