net: dns: Fix DNS caching bug
The current DNS caching logic is not aware of the IP address version. If there is a cached address for a query, the caller of dns_get_addr_info() will receive that address, even if it is not the same version as the caller requested. For example: - dns_get_addr_info() is called to resolve an IPv4 address - the DNS client caches the IPv4 address that was received - dns_get_addr_info() is called to resolve an IPv6 address - the DNS client sees that there is a cached IPv4 address for the given query - the DNS client does not check that the cached address is of the requested version (IPv6) - the cached IPv4 address is returned from dns_get_addr_info() This changes the DNS client to check IP address version when searching cached addresses. Signed-off-by: Noah Olson <noah@wavelynx.com>
This commit is contained in:
committed by
Benjamin Cabé
parent
3bbe56060f
commit
37a924be6a
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <zephyr/net/dns_resolve.h>
|
||||
#include <zephyr/net/net_ip.h>
|
||||
#include "dns_cache.h"
|
||||
|
||||
LOG_MODULE_REGISTER(net_dns_cache, CONFIG_DNS_RESOLVER_LOG_LEVEL);
|
||||
@@ -97,15 +98,23 @@ int dns_cache_remove(struct dns_cache *cache, char const *query)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_cache_find(struct dns_cache const *cache, const char *query, struct dns_addrinfo *addrinfo,
|
||||
size_t addrinfo_array_len)
|
||||
int dns_cache_find(struct dns_cache const *cache, const char *query, enum dns_query_type type,
|
||||
struct dns_addrinfo *addrinfo, size_t addrinfo_array_len)
|
||||
{
|
||||
size_t found = 0;
|
||||
sa_family_t family;
|
||||
|
||||
NET_DBG("Find \"%s\"", query);
|
||||
if (cache == NULL || query == NULL || addrinfo == NULL || addrinfo_array_len <= 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (type == DNS_QUERY_TYPE_A) {
|
||||
family = AF_INET;
|
||||
} else if (type == DNS_QUERY_TYPE_AAAA) {
|
||||
family = AF_INET6;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (strlen(query) >= CONFIG_DNS_RESOLVER_MAX_QUERY_LEN) {
|
||||
NET_WARN("Query string to big to be processed %u >= "
|
||||
"CONFIG_DNS_RESOLVER_MAX_QUERY_LEN",
|
||||
@@ -124,6 +133,9 @@ int dns_cache_find(struct dns_cache const *cache, const char *query, struct dns_
|
||||
if (strcmp(cache->entries[i].query, query) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (cache->entries[i].data.ai_family != family) {
|
||||
continue;
|
||||
}
|
||||
if (found >= addrinfo_array_len) {
|
||||
NET_WARN("Found \"%s\" but not enough space in provided buffer.", query);
|
||||
found++;
|
||||
|
||||
@@ -86,6 +86,7 @@ int dns_cache_remove(struct dns_cache *cache, char const *query);
|
||||
*
|
||||
* @param cache Cache where the entry should be searched.
|
||||
* @param query Query which should be searched for.
|
||||
* @param type Query type which will control the types of addresses that will be found.
|
||||
* @param addrinfo dns_addrinfo array which will be written if the query was found.
|
||||
* @param addrinfo_array_len Array size of the dns_addrinfo array
|
||||
* @retval on success the amount of dns_addrinfo written into the addrinfo array will be returned.
|
||||
@@ -94,7 +95,7 @@ int dns_cache_remove(struct dns_cache *cache, char const *query);
|
||||
* -ENOSR means there was not enough space in the addrinfo array to accommodate all cache hits the
|
||||
* array will however be filled with valid data.
|
||||
*/
|
||||
int dns_cache_find(struct dns_cache const *cache, const char *query, struct dns_addrinfo *addrinfo,
|
||||
size_t addrinfo_array_len);
|
||||
int dns_cache_find(struct dns_cache const *cache, const char *query, enum dns_query_type type,
|
||||
struct dns_addrinfo *addrinfo, size_t addrinfo_array_len);
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_NET_DNS_CACHE_H_ */
|
||||
|
||||
@@ -1414,7 +1414,7 @@ int dns_resolve_name(struct dns_resolve_context *ctx,
|
||||
|
||||
try_resolve:
|
||||
#ifdef CONFIG_DNS_RESOLVER_CACHE
|
||||
ret = dns_cache_find(&dns_cache, query, cached_info, ARRAY_SIZE(cached_info));
|
||||
ret = dns_cache_find(&dns_cache, query, type, cached_info, ARRAY_SIZE(cached_info));
|
||||
if (ret > 0) {
|
||||
/* The query was cached, no
|
||||
* need to continue further.
|
||||
|
||||
@@ -24,10 +24,11 @@ ZTEST(net_dns_cache_test, test_simple_cache_entry)
|
||||
struct dns_addrinfo info_write = {.ai_family = AF_INET};
|
||||
struct dns_addrinfo info_read = {0};
|
||||
const char *query = "example.com";
|
||||
enum dns_query_type query_type = DNS_QUERY_TYPE_A;
|
||||
|
||||
zassert_ok(dns_cache_add(&test_dns_cache, query, &info_write, TEST_DNS_CACHE_DEFAULT_TTL),
|
||||
"Cache entry adding should work.");
|
||||
zassert_equal(1, dns_cache_find(&test_dns_cache, query, &info_read, 1));
|
||||
zassert_equal(1, dns_cache_find(&test_dns_cache, query, query_type, &info_read, 1));
|
||||
zassert_equal(AF_INET, info_read.ai_family);
|
||||
}
|
||||
|
||||
@@ -35,8 +36,9 @@ ZTEST(net_dns_cache_test, test_not_cached)
|
||||
{
|
||||
struct dns_addrinfo info_read = {0};
|
||||
const char *query = "example.com";
|
||||
enum dns_query_type query_type = DNS_QUERY_TYPE_A;
|
||||
|
||||
zassert_equal(0, dns_cache_find(&test_dns_cache, query, &info_read, 1));
|
||||
zassert_equal(0, dns_cache_find(&test_dns_cache, query, query_type, &info_read, 1));
|
||||
zassert_equal(0, info_read.ai_family);
|
||||
}
|
||||
|
||||
@@ -45,14 +47,15 @@ ZTEST(net_dns_cache_test, test_fill_cache)
|
||||
struct dns_addrinfo info_write = {.ai_family = AF_INET};
|
||||
struct dns_addrinfo info_read[TEST_DNS_CACHE_SIZE] = {0};
|
||||
const char *query = "example.com";
|
||||
enum dns_query_type query_type = DNS_QUERY_TYPE_A;
|
||||
|
||||
for (size_t i = 0; i < TEST_DNS_CACHE_SIZE; i++) {
|
||||
zassert_ok(dns_cache_add(&test_dns_cache, query, &info_write,
|
||||
TEST_DNS_CACHE_DEFAULT_TTL),
|
||||
"Cache entry adding should work.");
|
||||
}
|
||||
zassert_equal(TEST_DNS_CACHE_SIZE,
|
||||
dns_cache_find(&test_dns_cache, query, info_read, TEST_DNS_CACHE_SIZE));
|
||||
zassert_equal(TEST_DNS_CACHE_SIZE, dns_cache_find(&test_dns_cache, query, query_type,
|
||||
info_read, TEST_DNS_CACHE_SIZE));
|
||||
zassert_equal(AF_INET, info_read[TEST_DNS_CACHE_SIZE - 1].ai_family);
|
||||
}
|
||||
|
||||
@@ -61,6 +64,7 @@ ZTEST(net_dns_cache_test, test_flush)
|
||||
struct dns_addrinfo info_write = {.ai_family = AF_INET};
|
||||
struct dns_addrinfo info_read[TEST_DNS_CACHE_SIZE] = {0};
|
||||
const char *query = "example.com";
|
||||
enum dns_query_type query_type = DNS_QUERY_TYPE_A;
|
||||
|
||||
for (size_t i = 0; i < TEST_DNS_CACHE_SIZE; i++) {
|
||||
zassert_ok(dns_cache_add(&test_dns_cache, query, &info_write,
|
||||
@@ -68,7 +72,8 @@ ZTEST(net_dns_cache_test, test_flush)
|
||||
"Cache entry adding should work.");
|
||||
}
|
||||
zassert_ok(dns_cache_flush(&test_dns_cache));
|
||||
zassert_equal(0, dns_cache_find(&test_dns_cache, query, info_read, TEST_DNS_CACHE_SIZE));
|
||||
zassert_equal(0, dns_cache_find(&test_dns_cache, query, query_type, info_read,
|
||||
TEST_DNS_CACHE_SIZE));
|
||||
zassert_equal(0, info_read[TEST_DNS_CACHE_SIZE - 1].ai_family);
|
||||
}
|
||||
|
||||
@@ -77,14 +82,15 @@ ZTEST(net_dns_cache_test, test_fill_cache_to_small)
|
||||
struct dns_addrinfo info_write = {.ai_family = AF_INET};
|
||||
struct dns_addrinfo info_read[TEST_DNS_CACHE_SIZE - 1] = {0};
|
||||
const char *query = "example.com";
|
||||
enum dns_query_type query_type = DNS_QUERY_TYPE_A;
|
||||
|
||||
for (size_t i = 0; i < TEST_DNS_CACHE_SIZE; i++) {
|
||||
zassert_ok(dns_cache_add(&test_dns_cache, query, &info_write,
|
||||
TEST_DNS_CACHE_DEFAULT_TTL),
|
||||
"Cache entry adding should work.");
|
||||
}
|
||||
zassert_equal(-ENOSR,
|
||||
dns_cache_find(&test_dns_cache, query, info_read, TEST_DNS_CACHE_SIZE - 1));
|
||||
zassert_equal(-ENOSR, dns_cache_find(&test_dns_cache, query, query_type, info_read,
|
||||
TEST_DNS_CACHE_SIZE - 1));
|
||||
zassert_equal(AF_INET, info_read[TEST_DNS_CACHE_SIZE - 2].ai_family);
|
||||
}
|
||||
|
||||
@@ -93,6 +99,7 @@ ZTEST(net_dns_cache_test, test_closest_expiry_removed)
|
||||
struct dns_addrinfo info_write = {.ai_family = AF_INET};
|
||||
struct dns_addrinfo info_read = {0};
|
||||
const char *closest_expiry = "example.com";
|
||||
enum dns_query_type query_type = DNS_QUERY_TYPE_A;
|
||||
|
||||
zassert_ok(dns_cache_add(&test_dns_cache, closest_expiry, &info_write,
|
||||
TEST_DNS_CACHE_DEFAULT_TTL),
|
||||
@@ -103,7 +110,8 @@ ZTEST(net_dns_cache_test, test_closest_expiry_removed)
|
||||
TEST_DNS_CACHE_DEFAULT_TTL),
|
||||
"Cache entry adding should work.");
|
||||
}
|
||||
zassert_equal(0, dns_cache_find(&test_dns_cache, closest_expiry, &info_read, 1));
|
||||
zassert_equal(0,
|
||||
dns_cache_find(&test_dns_cache, closest_expiry, query_type, &info_read, 1));
|
||||
zassert_equal(0, info_read.ai_family);
|
||||
}
|
||||
|
||||
@@ -112,6 +120,7 @@ ZTEST(net_dns_cache_test, test_expired_entries_removed)
|
||||
struct dns_addrinfo info_write = {.ai_family = AF_INET};
|
||||
struct dns_addrinfo info_read[3] = {0};
|
||||
const char *query = "example.com";
|
||||
enum dns_query_type query_type = DNS_QUERY_TYPE_A;
|
||||
|
||||
zassert_ok(dns_cache_add(&test_dns_cache, query, &info_write, TEST_DNS_CACHE_DEFAULT_TTL),
|
||||
"Cache entry adding should work.");
|
||||
@@ -121,15 +130,47 @@ ZTEST(net_dns_cache_test, test_expired_entries_removed)
|
||||
zassert_ok(
|
||||
dns_cache_add(&test_dns_cache, query, &info_write, TEST_DNS_CACHE_DEFAULT_TTL * 3),
|
||||
"Cache entry adding should work.");
|
||||
zassert_equal(3, dns_cache_find(&test_dns_cache, query, info_read, 3));
|
||||
zassert_equal(3, dns_cache_find(&test_dns_cache, query, query_type, info_read, 3));
|
||||
zassert_equal(AF_INET, info_read[0].ai_family);
|
||||
k_sleep(K_MSEC(TEST_DNS_CACHE_DEFAULT_TTL * 1000 + 1));
|
||||
zassert_equal(2, dns_cache_find(&test_dns_cache, query, info_read, 3));
|
||||
zassert_equal(2, dns_cache_find(&test_dns_cache, query, query_type, info_read, 3));
|
||||
zassert_equal(AF_INET, info_read[0].ai_family);
|
||||
k_sleep(K_MSEC(TEST_DNS_CACHE_DEFAULT_TTL * 1000 + 1));
|
||||
zassert_equal(1, dns_cache_find(&test_dns_cache, query, info_read, 3));
|
||||
zassert_equal(1, dns_cache_find(&test_dns_cache, query, query_type, info_read, 3));
|
||||
zassert_equal(AF_INET, info_read[0].ai_family);
|
||||
k_sleep(K_MSEC(1));
|
||||
zassert_equal(1, dns_cache_find(&test_dns_cache, query, info_read, 3));
|
||||
zassert_equal(1, dns_cache_find(&test_dns_cache, query, query_type, info_read, 3));
|
||||
zassert_equal(AF_INET, info_read[0].ai_family);
|
||||
}
|
||||
|
||||
ZTEST(net_dns_cache_test, test_different_type_not_returned)
|
||||
{
|
||||
struct dns_addrinfo info_write = {.ai_family = AF_INET};
|
||||
struct dns_addrinfo info_read = {0};
|
||||
const char *query = "example.com";
|
||||
enum dns_query_type query_type = DNS_QUERY_TYPE_AAAA;
|
||||
|
||||
zassert_ok(dns_cache_add(&test_dns_cache, query, &info_write, TEST_DNS_CACHE_DEFAULT_TTL),
|
||||
"Cache entry adding should work.");
|
||||
zassert_equal(0, dns_cache_find(&test_dns_cache, query, query_type, &info_read, 1));
|
||||
zassert_equal(0, info_read.ai_family);
|
||||
}
|
||||
|
||||
ZTEST(net_dns_cache_test, test_only_expected_type_returned)
|
||||
{
|
||||
struct dns_addrinfo info_write_a = {.ai_family = AF_INET};
|
||||
struct dns_addrinfo info_write_b = {.ai_family = AF_INET6};
|
||||
struct dns_addrinfo info_read = {0};
|
||||
const char *query = "example.com";
|
||||
enum dns_query_type query_type_a = DNS_QUERY_TYPE_A;
|
||||
enum dns_query_type query_type_b = DNS_QUERY_TYPE_AAAA;
|
||||
|
||||
zassert_ok(dns_cache_add(&test_dns_cache, query, &info_write_a, TEST_DNS_CACHE_DEFAULT_TTL),
|
||||
"Cache entry adding should work.");
|
||||
zassert_ok(dns_cache_add(&test_dns_cache, query, &info_write_b, TEST_DNS_CACHE_DEFAULT_TTL),
|
||||
"Cache entry adding should work.");
|
||||
zassert_equal(1, dns_cache_find(&test_dns_cache, query, query_type_a, &info_read, 1));
|
||||
zassert_equal(AF_INET, info_read.ai_family);
|
||||
zassert_equal(1, dns_cache_find(&test_dns_cache, query, query_type_b, &info_read, 1));
|
||||
zassert_equal(AF_INET6, info_read.ai_family);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user