diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 645cb5b7164d..05c8fe7ee7cd 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -24,6 +24,7 @@ PSEUDOMODULES += cpu_check_address PSEUDOMODULES += dbgpin PSEUDOMODULES += devfs_% PSEUDOMODULES += dhcpv6_% +PSEUDOMODULES += dhcpv6_client_dns PSEUDOMODULES += ecc_% PSEUDOMODULES += event_% PSEUDOMODULES += event_timeout_ztimer diff --git a/sys/Makefile.dep b/sys/Makefile.dep index f666c0c60e1e..d95370858353 100644 --- a/sys/Makefile.dep +++ b/sys/Makefile.dep @@ -102,6 +102,9 @@ ifneq (,$(filter dhcpv6_client,$(USEMODULE))) USEMODULE += event USEMODULE += random USEMODULE += xtimer + ifneq (,$(filter sock_dns,$(USEMODULE))) + USEMODULE += dhcpv6_client_dns + endif endif ifneq (,$(filter fuzzing,$(USEMODULE))) diff --git a/sys/include/net/dhcpv6.h b/sys/include/net/dhcpv6.h index 817d9d96e586..47497cf64234 100644 --- a/sys/include/net/dhcpv6.h +++ b/sys/include/net/dhcpv6.h @@ -65,6 +65,7 @@ extern "C" { #define DHCPV6_OPT_PREF (7U) /**< preference option */ #define DHCPV6_OPT_ELAPSED_TIME (8U) /**< elapsed time option */ #define DHCPV6_OPT_STATUS (13U) /**< status code option */ +#define DHCPV6_OPT_DNS_RNS (23U) /**< DNS recursive name server option */ #define DHCPV6_OPT_IA_PD (25U) /**< identity association for prefix * delegation (IA_PD) option */ #define DHCPV6_OPT_IAPFX (26U) /**< IA prefix option */ diff --git a/sys/net/application_layer/dhcpv6/_dhcpv6.h b/sys/net/application_layer/dhcpv6/_dhcpv6.h index 1aff58561f6c..8fc8bebe36b8 100644 --- a/sys/net/application_layer/dhcpv6/_dhcpv6.h +++ b/sys/net/application_layer/dhcpv6/_dhcpv6.h @@ -172,6 +172,19 @@ typedef struct __attribute__((packed)) { char msg[]; /**< UTF-8 encoded text string (not 0-terminated!) */ } dhcpv6_opt_status_t; +/** + * @brief DHCPv6 DNS recursive name server option + * @see [RFC 3646, section 3] + * (https://datatracker.ietf.org/doc/html/rfc3646#section-3) + * @note Only parsed with `dhcpv6_client_dns` module compiled in. + */ +typedef struct __attribute__((packed)) { + network_uint16_t type; /**< @ref DHCPV6_OPT_DNS_RNS */ + network_uint16_t len; /**< length of dhcpv6_opt_status_t::dns_rns in byte */ + ipv6_addr_t dns_rns[]; /**< addresses of DNS recursive name servers + * in order of preference */ +} dhcpv6_opt_dns_rns_t; + /** * @brief DHCPv6 identity association for prefix delegation option (IA_PD) * format @@ -224,6 +237,17 @@ typedef struct __attribute__((packed)) { char mud_string[]; /**< MUD URL using the "https" scheme */ } dhcpv6_opt_mud_url_t; +/** + * @brief Configures a DNS recursive name server provided by the server. + * + * @note Only available with module `dhcpv6_client_dns`. + * + * @param[in] opt A legal DNS recursive name option. + * @param[in] netif Network interface the message carrying @p opt came in. + */ +void dhcpv6_client_dns_rns_conf(const dhcpv6_opt_dns_rns_t *opt, + uint16_t netif); + #ifdef __cplusplus } #endif diff --git a/sys/net/application_layer/dhcpv6/client.c b/sys/net/application_layer/dhcpv6/client.c index 2fc8461febf2..bab8b14e7101 100644 --- a/sys/net/application_layer/dhcpv6/client.c +++ b/sys/net/application_layer/dhcpv6/client.c @@ -636,6 +636,12 @@ static bool _parse_reply(uint8_t *rep, size_t len) for (dhcpv6_opt_t *opt = (dhcpv6_opt_t *)(&rep[sizeof(dhcpv6_msg_t)]); len > 0; len -= _opt_len(opt), opt = _opt_next(opt)) { switch (byteorder_ntohs(opt->type)) { +#if IS_USED(MODULE_DHCPV6_CLIENT_DNS) + case DHCPV6_OPT_DNS_RNS: + dhcpv6_client_dns_rns_conf((dhcpv6_opt_dns_rns_t *)opt, + remote.netif); + break; +#endif /* IS_USED(MODULE_DHCPV6_CLIENT_DNS) */ case DHCPV6_OPT_IA_PD: for (unsigned i = 0; i < CONFIG_DHCPV6_CLIENT_PFX_LEASE_MAX; i++) { dhcpv6_opt_iapfx_t *iapfx = NULL; diff --git a/sys/net/application_layer/dhcpv6/client_dns.c b/sys/net/application_layer/dhcpv6/client_dns.c new file mode 100644 index 000000000000..7c37b1e9a8ad --- /dev/null +++ b/sys/net/application_layer/dhcpv6/client_dns.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * + * @file + * @author Martine Lenders + */ + +#include "net/dhcpv6/client.h" +#if IS_USED(MODULE_SOCK_DNS) +#include "net/sock/dns.h" +#endif + +#include "_dhcpv6.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +static char addr_str[IPV6_ADDR_MAX_STR_LEN]; + +void dhcpv6_client_dns_rns_conf(const dhcpv6_opt_dns_rns_t *opt, uint16_t netif) +{ + if (byteorder_ntohs(opt->len) < sizeof(ipv6_addr_t)) { + DEBUG("dhcpv6_client_dns: no DNS recursive name server provided.\n"); + return; + } +#if IS_USED(MODULE_SOCK_DNS) && IS_ACTIVE(SOCK_HAS_IPV6) + DEBUG("Overriding sock_dns_server with %s\n", + ipv6_addr_to_str(addr_str, opt->dns_rns, sizeof(addr_str))); + sock_dns_server.port = SOCK_DNS_PORT; + sock_dns_server.family = AF_INET6; + sock_dns_server.netif = netif; + memcpy(sock_dns_server.addr.ipv6, opt->dns_rns, + sizeof(sock_dns_server.addr.ipv6)); + return; +#endif +} + +/** @} */