net: icmpv6: Implement IPv6 RA Recursive DNS Server option
Handle RA RDNSS and use the first DNS server fetched. This is needed when building IPv6 only without static DNS server IP addresses. This implementation does not handle the lifetime, because the current resolve logic does not have support for a DNS server lifetime. Signed-off-by: Stig Bjørlykke <stig.bjorlykke@nordicsemi.no>
This commit is contained in:
parent
c69731a281
commit
cb50d49f33
|
@ -132,6 +132,7 @@ config NET_IPV6_DAD
|
|||
config NET_IPV6_RA_RDNSS
|
||||
bool "Support RA RDNSS option"
|
||||
depends on NET_IPV6_ND
|
||||
select DNS_RESOLVER
|
||||
default y
|
||||
help
|
||||
Support Router Advertisement Recursive DNS Server option.
|
||||
|
|
|
@ -89,6 +89,14 @@ struct net_icmpv6_nd_opt_route_info {
|
|||
*/
|
||||
} __packed;
|
||||
|
||||
struct net_icmpv6_nd_opt_rdnss {
|
||||
uint16_t reserved;
|
||||
uint32_t lifetime;
|
||||
/* Variable-length DNS server address follows,
|
||||
* depending on the option length.
|
||||
*/
|
||||
} __packed;
|
||||
|
||||
struct net_icmpv6_echo_req {
|
||||
uint16_t identifier;
|
||||
uint16_t sequence;
|
||||
|
|
|
@ -23,6 +23,7 @@ LOG_MODULE_DECLARE(net_ipv6, CONFIG_NET_IPV6_LOG_LEVEL);
|
|||
#include <zephyr/net/net_stats.h>
|
||||
#include <zephyr/net/net_context.h>
|
||||
#include <zephyr/net/net_mgmt.h>
|
||||
#include <zephyr/net/dns_resolve.h>
|
||||
#include "net_private.h"
|
||||
#include "connection.h"
|
||||
#include "icmpv6.h"
|
||||
|
@ -2327,6 +2328,62 @@ static inline bool handle_ra_route_info(struct net_pkt *pkt, uint8_t len)
|
|||
return true;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_IPV6_RA_RDNSS)
|
||||
static inline bool handle_ra_rdnss(struct net_pkt *pkt, uint8_t len)
|
||||
{
|
||||
NET_PKT_DATA_ACCESS_DEFINE(rdnss_access, struct net_icmpv6_nd_opt_rdnss);
|
||||
struct net_icmpv6_nd_opt_rdnss *rdnss;
|
||||
struct dns_resolve_context *ctx;
|
||||
struct sockaddr_in6 dns;
|
||||
const struct sockaddr *dns_servers[] = {
|
||||
(struct sockaddr *)&dns, NULL
|
||||
};
|
||||
size_t rdnss_size;
|
||||
int ret;
|
||||
|
||||
rdnss = (struct net_icmpv6_nd_opt_rdnss *) net_pkt_get_data(pkt, &rdnss_access);
|
||||
if (!rdnss) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = net_pkt_acknowledge_data(pkt, &rdnss_access);
|
||||
if (ret < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rdnss_size = len * 8U - 2 - sizeof(struct net_icmpv6_nd_opt_rdnss);
|
||||
if ((rdnss_size % NET_IPV6_ADDR_SIZE) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Recursive DNS servers option may present 1 or more addresses,
|
||||
* each 16 bytes in length. DNS servers should be listed in order
|
||||
* of preference, choose the first and skip the rest.
|
||||
*/
|
||||
ret = net_pkt_read(pkt, dns.sin6_addr.s6_addr, NET_IPV6_ADDR_SIZE);
|
||||
if (ret < 0) {
|
||||
NET_ERR("Failed to read RDNSS address, %d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Skip the rest of the DNS servers. */
|
||||
if (net_pkt_skip(pkt, rdnss_size - NET_IPV6_ADDR_SIZE)) {
|
||||
NET_ERR("Failed to skip RDNSS address, %d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO: Handle lifetime. */
|
||||
ctx = dns_resolve_get_default();
|
||||
dns.sin6_family = AF_INET6;
|
||||
ret = dns_resolve_reconfigure(ctx, NULL, dns_servers);
|
||||
if (ret < 0) {
|
||||
NET_DBG("Failed to set RDNSS resolve address: %d", ret);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static enum net_verdict handle_ra_input(struct net_pkt *pkt,
|
||||
struct net_ipv6_hdr *ip_hdr,
|
||||
struct net_icmp_hdr *icmp_hdr)
|
||||
|
@ -2477,8 +2534,10 @@ static enum net_verdict handle_ra_input(struct net_pkt *pkt,
|
|||
break;
|
||||
#if defined(CONFIG_NET_IPV6_RA_RDNSS)
|
||||
case NET_ICMPV6_ND_OPT_RDNSS:
|
||||
NET_DBG("RDNSS option skipped");
|
||||
goto skip;
|
||||
if (!handle_ra_rdnss(pkt, nd_opt_hdr->len)) {
|
||||
goto drop;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case NET_ICMPV6_ND_OPT_DNSSL:
|
||||
|
|
|
@ -25,6 +25,7 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_IPV6_LOG_LEVEL);
|
|||
#include <zephyr/net/ethernet.h>
|
||||
#include <zephyr/net/dummy.h>
|
||||
#include <zephyr/net/udp.h>
|
||||
#include <zephyr/net/dns_resolve.h>
|
||||
|
||||
#include "icmpv6.h"
|
||||
#include "ipv6.h"
|
||||
|
@ -85,19 +86,19 @@ static const unsigned char icmpv6_ns_no_sllao[] = {
|
|||
/* */
|
||||
static const unsigned char icmpv6_ra[] = {
|
||||
/* IPv6 header starts here */
|
||||
0x60, 0x00, 0x00, 0x00, 0x00, 0x58, 0x3a, 0xff,
|
||||
0x60, 0x00, 0x00, 0x00, 0x00, 0x70, 0x3a, 0xff,
|
||||
0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x60, 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea,
|
||||
0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
/* ICMPv6 RA header starts here */
|
||||
0x86, 0x00, 0x05, 0xd7, 0x40, 0x00, 0x07, 0x08,
|
||||
0x86, 0x00, 0xbf, 0x01, 0x40, 0x00, 0x07, 0x08,
|
||||
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
/* SLLAO */
|
||||
0x01, 0x01, 0x00, 0x60, 0x97, 0x07, 0x69, 0xea,
|
||||
/* MTU */
|
||||
0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0xdc,
|
||||
/* Prefix info*/
|
||||
/* Prefix info */
|
||||
0x03, 0x04, 0x40, 0xc0, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01,
|
||||
|
@ -106,6 +107,10 @@ static const unsigned char icmpv6_ra[] = {
|
|||
0x18, 0x03, 0x30, 0x08, 0xff, 0xff, 0xff, 0xff,
|
||||
0x20, 0x01, 0x0d, 0xb0, 0x0f, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
/* Recursive DNS Server */
|
||||
0x19, 0x03, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
||||
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
};
|
||||
|
||||
/* IPv6 hop-by-hop option in the message */
|
||||
|
@ -697,7 +702,14 @@ static void ra_message(void)
|
|||
struct in6_addr prefix = { { { 0x3f, 0xfe, 0x05, 0x07, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0 } } };
|
||||
struct in6_addr route_prefix = { { { 0x20, 0x01, 0x0d, 0xb0, 0x0f, 0xff } } };
|
||||
struct sockaddr_in6 dns_addr = {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
|
||||
};
|
||||
struct net_route_entry *route;
|
||||
struct dns_resolve_context *ctx;
|
||||
struct sockaddr_in6 *dns_server;
|
||||
|
||||
/* We received RA message earlier, make sure that the information
|
||||
* in that message is placed to proper prefix and lookup info.
|
||||
|
@ -722,6 +734,14 @@ static void ra_message(void)
|
|||
zassert_true(route->is_infinite, "Wrong lifetime set");
|
||||
zassert_equal(route->preference, NET_ROUTE_PREFERENCE_HIGH,
|
||||
"Wrong preference set");
|
||||
|
||||
/* Check if RDNSS was added correctly. */
|
||||
ctx = dns_resolve_get_default();
|
||||
zassert_equal(ctx->state, DNS_RESOLVE_CONTEXT_ACTIVE);
|
||||
dns_server = (struct sockaddr_in6 *)&ctx->servers[0].dns_server;
|
||||
zassert_equal(dns_server->sin6_family, dns_addr.sin6_family);
|
||||
zassert_mem_equal(&dns_server->sin6_addr, &dns_addr.sin6_addr,
|
||||
sizeof(dns_addr.sin6_addr), "Wrong DNS address set");
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_rs_ra_message)
|
||||
|
|
Loading…
Reference in a new issue