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);