diff --git a/Makefile.dep b/Makefile.dep index 0d1751434a5dad26691f472bd0f605abe2f456e9..923756103601cbfc76955bf186be2f50e95980ff 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 1b4ca0337e2da2da8a556793bbfa4535b008ef00..dca9b530d0cf1e1b12ea0f8aa40f129583cae34b 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.h b/sys/include/net/gnrc/ipv6/nib.h index facc9e6ccffefbb7df5fb97e373b6b0339d32fde..a3acfa906638c18b1de252168df23d542b666f42 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/include/net/gnrc/ipv6/nib/conf.h b/sys/include/net/gnrc/ipv6/nib/conf.h index a62c4b47d0c55d77e12cf3d3c049dd286ebbc900..d859428782461a03b56fcf97c40ac8fd96f81b14 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 660f47646f92e0a2ce5b4d25733b173fb4d83a48..94aff3898272265299e92624fd92d1f5ebbd7b3e 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/include/net/ndp.h b/sys/include/net/ndp.h index 01f64a70366da35c8c9108e35b361daa93e7b644..97fd869511a54838269d12515d478b29cd5f99e7 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 } diff --git a/sys/net/application_layer/dns/dns.c b/sys/net/application_layer/dns/dns.c index ec146636cd043dcd2e061ad2b4c407fce1e958cc..adef0df244ac69ce76d12b9aaa5310c966f7f5ae 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) { /* @@ -132,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; } 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 5873b099032b996a1096439bd2e57c688c7b8502..9b2bd14bc30a4b0fa2d37f951112571d10ba4806 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; diff --git a/sys/net/gnrc/network_layer/ipv6/nib/nib.c b/sys/net/gnrc/network_layer/ipv6/nib/nib.c index 4bc923948a5680ae9a5e20942bb9204b55596208..c726827ddcd5ab02dd3e1d0f35032f806328870f 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; diff --git a/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c b/sys/net/gnrc/network_layer/ndp/gnrc_ndp.c index afce23dac935626f401d143f7f98385b0839bb72..e467ea9506e1542022caeccd238d99b9d1aa22ab 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, diff --git a/tests/gnrc_sock_dns/Makefile b/tests/gnrc_sock_dns/Makefile index a0abd781fba501da52845852163c37eaf8116058..7bdcdc41d1ee74b745b11cfd3c85718efbeb5e54 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 1b6cc3d22390afbdd057cfa02224a4ac117b2b43..52700febbbbf7df4ea24d63a52455056cda59aef 100644 --- a/tests/gnrc_sock_dns/main.c +++ b/tests/gnrc_sock_dns/main.c @@ -31,13 +31,6 @@ #define TEST_NAME "example.org" #endif -#ifndef DNS_SERVER -#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); @@ -46,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);