From 8eab80c3ec05a29252846e4c1e6044182f031518 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Mon, 26 Feb 2018 17:28:59 +0100 Subject: [PATCH 1/7] ndp: define RDNSS option --- sys/include/net/ndp.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sys/include/net/ndp.h b/sys/include/net/ndp.h index 01f64a7036..97fd869511 100644 --- a/sys/include/net/ndp.h +++ b/sys/include/net/ndp.h @@ -88,6 +88,7 @@ extern "C" { #define NDP_OPT_PI (3) /**< prefix information option */ #define NDP_OPT_RH (4) /**< redirected option */ #define NDP_OPT_MTU (5) /**< MTU option */ +#define NDP_OPT_RDNSS (25) /**< recursive DNS server option */ #define NDP_OPT_AR (33) /**< address registration option */ #define NDP_OPT_6CTX (34) /**< 6LoWPAN context option */ #define NDP_OPT_ABR (35) /**< authoritative border router option */ @@ -120,6 +121,12 @@ extern "C" { #define NDP_OPT_MTU_LEN (1U) /** @} */ +/** + * @brief Minimum length of a recursive DNS server option (in units of 8 bytes) + * @see [RFC 8106, section 5.1](https://tools.ietf.org/html/rfc8106#section-5.1) + */ +#define NDP_OPT_RDNSS_MIN_LEN (3U) + /** * @{ * @name Router constants @@ -314,6 +321,19 @@ typedef struct __attribute__((packed)) { network_uint32_t mtu; /**< MTU */ } ndp_opt_mtu_t; +/** + * @brief Recursive DNS server option format + * @extends ndp_opt_t + * + * @see [RFC 8106, section 5.1](https://tools.ietf.org/html/rfc8106#section-5.1) + */ +typedef struct __attribute__((packed)) { + uint8_t type; /**< option type */ + uint8_t len; /**< length in units of 8 octets */ + network_uint16_t resv; /**< reserved field */ + network_uint32_t ltime; /**< lifetime in seconds */ + ipv6_addr_t addrs[]; /**< addresses of IPv6 recursive DNS servers */ +} ndp_opt_rdnss_t; #ifdef __cplusplus } From fbf216f864b1706f65ffc40de45cfbc01f2dcea8 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Mon, 26 Feb 2018 17:31:12 +0100 Subject: [PATCH 2/7] gnrc_sock_dns: Move DNS server end point to implementation --- sys/net/application_layer/dns/dns.c | 3 +++ tests/gnrc_sock_dns/main.c | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sys/net/application_layer/dns/dns.c b/sys/net/application_layer/dns/dns.c index ec146636cd..83536c9981 100644 --- a/sys/net/application_layer/dns/dns.c +++ b/sys/net/application_layer/dns/dns.c @@ -28,6 +28,9 @@ /* min domain name length is 1, so minimum record length is 7 */ #define DNS_MIN_REPLY_LEN (unsigned)(sizeof(sock_dns_hdr_t ) + 7) +/* global DNS server UDP endpoint */ +sock_udp_ep_t sock_dns_server; + static ssize_t _enc_domain_name(uint8_t *out, const char *domain_name) { /* diff --git a/tests/gnrc_sock_dns/main.c b/tests/gnrc_sock_dns/main.c index 1b6cc3d223..44fe24f1b0 100644 --- a/tests/gnrc_sock_dns/main.c +++ b/tests/gnrc_sock_dns/main.c @@ -35,9 +35,6 @@ #define DNS_SERVER "[2001:db8::1]:53" #endif -/* global DNS server UDP endpoint */ -sock_udp_ep_t sock_dns_server; - /* import "ifconfig" shell command, used for printing addresses */ extern int _gnrc_netif_config(int argc, char **argv); From 0ef62b9690ee09b559e09a5235c5c7bbf0ecea5c Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Mon, 26 Feb 2018 17:34:43 +0100 Subject: [PATCH 3/7] gnrc_ndp: add support for building RDNSS option --- Makefile.dep | 7 +++++++ makefiles/pseudomodules.inc.mk | 1 + sys/include/net/gnrc/ipv6/nib/conf.h | 13 +++++++++++++ sys/include/net/gnrc/ndp.h | 23 +++++++++++++++++++++++ sys/net/gnrc/network_layer/ndp/gnrc_ndp.c | 21 +++++++++++++++++++++ 5 files changed, 65 insertions(+) diff --git a/Makefile.dep b/Makefile.dep index 0d1751434a..9237561036 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -305,6 +305,10 @@ ifneq (,$(filter gnrc_ipv6_nib_6ln,$(USEMODULE))) USEMODULE += gnrc_sixlowpan_nd endif +ifneq (,$(filter gnrc_ipv6_nib_dns,$(USEMODULE))) + USEMODULE += gnrc_ipv6_nib +endif + ifneq (,$(filter gnrc_ipv6_nib_router,$(USEMODULE))) USEMODULE += gnrc_ipv6_nib endif @@ -315,6 +319,9 @@ ifneq (,$(filter gnrc_ipv6_nib,$(USEMODULE))) USEMODULE += gnrc_netif USEMODULE += ipv6_addr USEMODULE += random + ifneq (,$(filter sock_dns,$(USEMODULE))) + USEMODULE += gnrc_ipv6_nib_dns + endif endif ifneq (,$(filter gnrc_udp,$(USEMODULE))) diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 1b4ca0337e..dca9b530d0 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -17,6 +17,7 @@ PSEUDOMODULES += gnrc_ipv6_router_default PSEUDOMODULES += gnrc_ipv6_nib_6lbr PSEUDOMODULES += gnrc_ipv6_nib_6ln PSEUDOMODULES += gnrc_ipv6_nib_6lr +PSEUDOMODULES += gnrc_ipv6_nib_dns PSEUDOMODULES += gnrc_ipv6_nib_router PSEUDOMODULES += gnrc_netdev_default PSEUDOMODULES += gnrc_neterr diff --git a/sys/include/net/gnrc/ipv6/nib/conf.h b/sys/include/net/gnrc/ipv6/nib/conf.h index a62c4b47d0..d859428782 100644 --- a/sys/include/net/gnrc/ipv6/nib/conf.h +++ b/sys/include/net/gnrc/ipv6/nib/conf.h @@ -68,6 +68,10 @@ extern "C" { #define GNRC_IPV6_NIB_CONF_ROUTER (1) #endif +#ifdef MODULE_GNRC_IPV6_NIB_DNS +#define GNRC_IPV6_NIB_CONF_DNS (1) +#endif + /** * @name Compile flags * @brief Compile flags to (de-)activate certain features for NIB @@ -171,6 +175,15 @@ extern "C" { #endif #endif +/** + * @brief Support for DNS configuration options + * + * @see [RFC 8106](https://tools.ietf.org/html/rfc8106) + */ +#ifndef GNRC_IPV6_NIB_CONF_DNS +#define GNRC_IPV6_NIB_CONF_DNS (0) +#endif + /** * @brief Multihop prefix and 6LoWPAN context distribution * diff --git a/sys/include/net/gnrc/ndp.h b/sys/include/net/gnrc/ndp.h index 660f47646f..94aff38982 100644 --- a/sys/include/net/gnrc/ndp.h +++ b/sys/include/net/gnrc/ndp.h @@ -250,6 +250,29 @@ gnrc_pktsnip_t *gnrc_ndp_opt_pi_build(const ipv6_addr_t *prefix, */ gnrc_pktsnip_t *gnrc_ndp_opt_mtu_build(uint32_t mtu, gnrc_pktsnip_t *next); +/** + * @brief Builts the recursive DNS server option + * + * @see [RFC 8106, section 5.1](https://tools.ietf.org/html/rfc8106#section-5.1) + * @pre `addrs != NULL` + * @pre `addrs_num > 0` + * + * @note Should only be used with router advertisemnents. This is not checked + * however, since nodes should silently ignore it in other NDP messages. + * + * @param[in] lifetime The lifetime of the recursive DNS servers + * @param[in] addrs The addresses of the recursive DNS servers + * @param[in] addrs_num The number of addresses in @p addrs + * @param[in] next More options in the packet. NULL, if there are none. + * + * @return The packet snip list of options, on success + * @return @p next, if RDNSS is not supported + * @return NULL, if packet buffer is full + */ +gnrc_pktsnip_t *gnrc_ndp_opt_rdnss_build(uint32_t lifetime, ipv6_addr_t *addrs, + unsigned addrs_num, + gnrc_pktsnip_t *next); + /** * @brief Send pre-compiled neighbor solicitation depending on a given network * interface. diff --git a/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c b/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c index afce23dac9..e467ea9506 100644 --- a/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c +++ b/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c @@ -222,6 +222,27 @@ gnrc_pktsnip_t *gnrc_ndp_opt_mtu_build(uint32_t mtu, gnrc_pktsnip_t *next) return pkt; } +gnrc_pktsnip_t *gnrc_ndp_opt_rdnss_build(uint32_t ltime, ipv6_addr_t *addrs, + unsigned addrs_num, + gnrc_pktsnip_t *next) +{ + assert(addrs != NULL); + assert(addrs_num > 0); + size_t opt_size = sizeof(ndp_opt_t) + (sizeof(ipv6_addr_t) * addrs_num); + gnrc_pktsnip_t *pkt = gnrc_ndp_opt_build(NDP_OPT_RDNSS, opt_size, next); + + if (pkt != NULL) { + ndp_opt_rdnss_t *rdnss_opt = pkt->data; + rdnss_opt->resv.u16 = 0; + rdnss_opt->ltime = byteorder_htonl(ltime); + for (unsigned i = 0; i < addrs_num; i++) { + memcpy(&rdnss_opt->addrs[i], &addrs[i], + sizeof(rdnss_opt->addrs[i])); + } + } + return pkt; +} + static gnrc_pktsnip_t *_build_headers(gnrc_netif_t *netif, const ipv6_addr_t *src, const ipv6_addr_t *dst, From 6d1f012c9dca91523872e58c9e9660e788edd3e8 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Mon, 26 Feb 2018 17:35:39 +0100 Subject: [PATCH 4/7] gnrc_ipv6_nib: add support to handle RDNSSO --- sys/include/net/gnrc/ipv6/nib.h | 11 +++ sys/net/gnrc/network_layer/ipv6/nib/nib.c | 91 +++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/sys/include/net/gnrc/ipv6/nib.h b/sys/include/net/gnrc/ipv6/nib.h index facc9e6ccf..a3acfa9066 100644 --- a/sys/include/net/gnrc/ipv6/nib.h +++ b/sys/include/net/gnrc/ipv6/nib.h @@ -222,6 +222,17 @@ extern "C" { * @note Only handled with @ref GNRC_IPV6_NIB_CONF_SLAAC != 0 */ #define GNRC_IPV6_NIB_VALID_ADDR (0x4fd2U) + +/** + * @brief Recursive DNS server timeout + * + * This message type is for the event of a recursive DNS server timeout. + * The expected message context is the [UDP end point](@ref sock_udp_ep_t) + * representing the DNS server. + * + * @note Only handled with @ref GNRC_IPV6_NIB_CONF_DNS != 0 + */ +#define GNRC_IPV6_NIB_RDNSS_TIMEOUT (0x4fd3U) /** @} */ /** diff --git a/sys/net/gnrc/network_layer/ipv6/nib/nib.c b/sys/net/gnrc/network_layer/ipv6/nib/nib.c index 4bc923948a..c726827ddc 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/nib.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/nib.c @@ -26,6 +26,9 @@ #include "net/gnrc/sixlowpan/nd.h" #include "net/ndp.h" #include "net/sixlowpan/nd.h" +#if GNRC_IPV6_NIB_CONF_DNS +#include "net/sock/dns.h" +#endif #include "_nib-internal.h" #include "_nib-arsm.h" @@ -46,6 +49,10 @@ static char addr_str[IPV6_ADDR_MAX_STR_LEN]; static gnrc_pktqueue_t _queue_pool[GNRC_IPV6_NIB_NUMOF]; #endif /* GNRC_IPV6_NIB_CONF_QUEUE_PKT */ +#if GNRC_IPV6_NIB_CONF_DNS +static evtimer_msg_event_t _rdnss_timeout; +#endif + /** * @internal * @{ @@ -70,6 +77,9 @@ static void _handle_rtr_timeout(_nib_dr_entry_t *router); static void _handle_snd_na(gnrc_pktsnip_t *pkt); /* needs to be exported for 6LN's ARO handling */ void _handle_search_rtr(gnrc_netif_t *netif); +#if GNRC_IPV6_NIB_CONF_DNS +static void _handle_rdnss_timeout(sock_udp_ep_t *dns_server); +#endif /** @} */ void gnrc_ipv6_nib_init(void) @@ -355,6 +365,10 @@ void gnrc_ipv6_nib_handle_timer_event(void *ctx, uint16_t type) case GNRC_IPV6_NIB_VALID_ADDR: _handle_valid_addr(ctx); break; +#if GNRC_IPV6_NIB_CONF_DNS + case GNRC_IPV6_NIB_RDNSS_TIMEOUT: + _handle_rdnss_timeout(ctx); +#endif default: break; } @@ -388,6 +402,10 @@ void gnrc_ipv6_nib_change_rtr_adv_iface(gnrc_netif_t *netif, bool enable) */ static void _handle_mtuo(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6, const ndp_opt_mtu_t *mtuo); +#if GNRC_IPV6_NIB_CONF_DNS +static uint32_t _handle_rdnsso(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6, + const ndp_opt_rdnss_t *rdnsso); +#endif #if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C static uint32_t _handle_pio(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6, const ndp_opt_pi_t *pio, @@ -696,6 +714,14 @@ static void _handle_rtr_adv(gnrc_netif_t *netif, const ipv6_hdr_t *ipv6, #endif /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */ break; #endif /* GNRC_IPV6_NIB_CONF_6LN */ +#if GNRC_IPV6_NIB_CONF_DNS + case NDP_OPT_RDNSS: + next_timeout = _min(_handle_rdnsso(netif, + (icmpv6_hdr_t *)rtr_adv, + (ndp_opt_rdnss_t *)opt), + next_timeout); + break; +#endif default: break; } @@ -1225,6 +1251,13 @@ void _handle_search_rtr(gnrc_netif_t *netif) gnrc_netif_release(netif); } +#if GNRC_IPV6_NIB_CONF_DNS +static void _handle_rdnss_timeout(sock_udp_ep_t *dns_server) +{ + memset(dns_server, 0, sizeof(sock_udp_ep_t)); +} +#endif + static void _handle_mtuo(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6, const ndp_opt_mtu_t *mtuo) { @@ -1236,6 +1269,64 @@ static void _handle_mtuo(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6, } } +#if GNRC_IPV6_NIB_CONF_DNS +static uint32_t _handle_rdnsso(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6, + const ndp_opt_rdnss_t *rdnsso) +{ + uint32_t ltime = UINT32_MAX; + const ipv6_addr_t *addr; + + if ((rdnsso->len < NDP_OPT_RDNSS_MIN_LEN) || + (icmpv6->type != ICMPV6_RTR_ADV)) { + return ltime; + } + /* select first if unassigned, search possible address otherwise */ + addr = (sock_dns_server.port == 0) ? &rdnsso->addrs[0] : NULL; + if (addr == NULL) { + unsigned addrs_num = (rdnsso->len - 1) / 2; + for (unsigned i = 0; i < addrs_num; i++) { + if (memcmp(sock_dns_server.addr.ipv6, + &rdnsso->addrs[i], + sizeof(rdnsso->addrs[i])) == 0) { + addr = &rdnsso->addrs[i]; + break; + } + } + } +#if SOCK_HAS_IPV6 + ltime = byteorder_ntohl(rdnsso->ltime); + if (addr != NULL) { + if (ltime > 0) { + sock_dns_server.port = SOCK_DNS_PORT; + sock_dns_server.family = AF_INET6; + sock_dns_server.netif = netif->pid; + memcpy(sock_dns_server.addr.ipv6, rdnsso->addrs, + sizeof(sock_dns_server.addr.ipv6)); + + if (ltime < UINT32_MAX) { + /* the valid lifetime is given in seconds, but our timers work + * in milliseconds, so we have to scale down to the smallest + * possible value (UINT32_MAX - 1). This is however alright + * since we ask for a new router advertisement before this + * timeout expires */ + ltime = (ltime > (UINT32_MAX / MS_PER_SEC)) ? + (UINT32_MAX - 1) : ltime * MS_PER_SEC; + _evtimer_add(&sock_dns_server, GNRC_IPV6_NIB_RDNSS_TIMEOUT, + &_rdnss_timeout, ltime); + } + } + else { + evtimer_del(&_nib_evtimer, &_rdnss_timeout.event); + _handle_rdnss_timeout(&sock_dns_server); + } + } +#else + (void)addr; +#endif + return ltime; +} +#endif + static void _remove_prefix(const ipv6_addr_t *pfx, unsigned pfx_len) { _nib_offl_entry_t *offl = NULL; From 1916c45dc0eea23685f07b7a00569b0fc8917fb3 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Mon, 26 Feb 2018 17:36:09 +0100 Subject: [PATCH 5/7] gnrc_ipv6_nib_router: add support to send RDNSSO --- .../gnrc/network_layer/ipv6/nib/_nib-router.c | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.c b/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.c index 5873b09903..9b2bd14bc3 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-router.c @@ -17,6 +17,9 @@ #include "net/gnrc/ndp.h" #include "net/gnrc/netif/internal.h" #include "net/gnrc/sixlowpan/nd.h" +#if GNRC_IPV6_NIB_CONF_DNS +#include "net/sock/dns.h" +#endif #if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C #include "_nib-6ln.h" @@ -131,6 +134,26 @@ static gnrc_pktsnip_t *_build_ext_opts(gnrc_netif_t *netif, _nib_offl_entry_t *pfx = NULL; unsigned id = netif->pid; +#if GNRC_IPV6_NIB_CONF_DNS && SOCK_HAS_IPV6 + uint32_t rdnss_ltime = _evtimer_lookup(&sock_dns_server, + GNRC_IPV6_NIB_RDNSS_TIMEOUT); + + if ((rdnss_ltime < UINT32_MAX) && + (!ipv6_addr_is_link_local((ipv6_addr_t *)sock_dns_server.addr.ipv6))) { + gnrc_pktsnip_t *rdnsso = gnrc_ndp_opt_rdnss_build( + rdnss_ltime * MS_PER_SEC, + (ipv6_addr_t *)&sock_dns_server.addr, + 1U, ext_opts + ); + if (rdnsso == NULL) { + /* gnrc_ndp_opt_rdnss_build() only returns NULL when pktbuf is full + * in this configuration */ + DEBUG("nib: No space left in packet buffer. Not adding RDNSSO\n"); + return NULL; + } + ext_opts = rdnsso; + } +#endif /* GNRC_IPV6_NIB_CONF_DNS */ #if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C uint16_t ltime; gnrc_pktsnip_t *abro; From 5361c4cfff43f3b2d4b9f2fce3d5fa8b6a8e3d98 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Mon, 26 Feb 2018 17:36:36 +0100 Subject: [PATCH 6/7] sock_dns: return error if DNS server is not set --- sys/net/application_layer/dns/dns.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sys/net/application_layer/dns/dns.c b/sys/net/application_layer/dns/dns.c index 83536c9981..adef0df244 100644 --- a/sys/net/application_layer/dns/dns.c +++ b/sys/net/application_layer/dns/dns.c @@ -135,6 +135,10 @@ int sock_dns_query(const char *domain_name, void *addr_out, int family) uint8_t buf[SOCK_DNS_QUERYBUF_LEN]; uint8_t reply_buf[512]; + if (sock_dns_server.port == 0) { + return -ECONNREFUSED; + } + if (strlen(domain_name) > SOCK_DNS_MAX_NAME_LEN) { return -ENOSPC; } From 95c1992d9788c0f67b7ab827d9b0e8c056924861 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Mon, 26 Feb 2018 17:37:14 +0100 Subject: [PATCH 7/7] tests: adapt gnrc_sock_dns for auto-configured DNS --- tests/gnrc_sock_dns/Makefile | 1 + tests/gnrc_sock_dns/main.c | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/gnrc_sock_dns/Makefile b/tests/gnrc_sock_dns/Makefile index a0abd781fb..7bdcdc41d1 100644 --- a/tests/gnrc_sock_dns/Makefile +++ b/tests/gnrc_sock_dns/Makefile @@ -9,6 +9,7 @@ BOARD_INSUFFICIENT_MEMORY := chronos telosb nucleo-f042k6 nucleo-f031k6 \ USEMODULE += sock_dns USEMODULE += gnrc_sock_udp USEMODULE += gnrc_ipv6_default +USEMODULE += gnrc_ipv6_nib_dns USEMODULE += gnrc_netdev_default USEMODULE += auto_init_gnrc_netif diff --git a/tests/gnrc_sock_dns/main.c b/tests/gnrc_sock_dns/main.c index 44fe24f1b0..52700febbb 100644 --- a/tests/gnrc_sock_dns/main.c +++ b/tests/gnrc_sock_dns/main.c @@ -31,10 +31,6 @@ #define TEST_NAME "example.org" #endif -#ifndef DNS_SERVER -#define DNS_SERVER "[2001:db8::1]:53" -#endif - /* import "ifconfig" shell command, used for printing addresses */ extern int _gnrc_netif_config(int argc, char **argv); @@ -43,8 +39,6 @@ int main(void) { uint8_t addr[16] = {0}; - sock_udp_str2ep(&sock_dns_server, DNS_SERVER); - puts("waiting for router advertisement..."); xtimer_usleep(1U*1000000);