Skip to content
Snippets Groups Projects
Unverified Commit dd165628 authored by Sebastian Meiling's avatar Sebastian Meiling Committed by GitHub
Browse files

Merge pull request #8646 from miri64/gnrc/enh/dns-config

gnrc_ipv6_nib: Add capability to handle and send RDNSS option
parents 5d4ba9f5 95c1992d
No related branches found
No related tags found
No related merge requests found
......@@ -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)))
......
......@@ -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
......
......@@ -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)
/** @} */
/**
......
......@@ -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
*
......
......@@ -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.
......
......@@ -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
}
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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;
......
......@@ -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,
......
......@@ -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
......
......@@ -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);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment