Implemented feature from RFC 6106 section '5.1. Recursive DNS Server Option': "Lifetime 32-bit unsigned integer. ... Hosts MAY send a Router Solicitation to ensure the RDNSS information is fresh before the interval expires."
Host will send RS when a certain threshold of RDNSS lifetime is reached. Values which can be adjusted: - lifetime threshold - currently configured with a value of 80% from lifetime - number of retries in case RA is not received - currently set to 0 - time between retries, in case RA is not received - currently set to 3 seconds --- include/network.h | 2 + src/network.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/resolver.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 108 insertions(+), 4 deletions(-) diff --git a/include/network.h b/include/network.h index 12b0621..d602683 100644 --- a/include/network.h +++ b/include/network.h @@ -147,6 +147,8 @@ void connman_network_set_data(struct connman_network *network, void *data); void connman_network_update(struct connman_network *network); +int refresh_rs_ipv6(struct connman_network *network, int index); + struct connman_network_driver { const char *name; enum connman_network_type type; diff --git a/src/network.c b/src/network.c index 10f1bf3..311b3b8 100644 --- a/src/network.c +++ b/src/network.c @@ -28,8 +28,17 @@ #include "connman.h" +/* How many times to retry sending RS with the purpose of + * refreshing RDNSS entries before they actually expire. + * With a value of 0, one RS will be sent, with no retries. */ +#define RS_REFRESH_RETRIES 0 +/* Value in seconds to wait for RA after RS was sent. + * After this time elapsed, we can send another RS. */ +#define RS_REFRESH_TIMEOUT 3 + static GSList *network_list = NULL; static GSList *driver_list = NULL; +static connman_bool_t refresh_rs_in_progress = FALSE; struct connman_network { int refcount; @@ -1113,6 +1122,51 @@ static void check_dhcpv6(struct nd_router_advert *reply, connman_network_unref(network); } +static void receive_refresh_rs_reply(struct nd_router_advert *reply, + unsigned int length, void *user_data) +{ + struct connman_network *network = user_data; + + DBG("reply %p", reply); + + if (reply == NULL) { + /* + * Router solicitation message seem to get lost easily so + * try to send it again. + */ + if (network->router_solicit_count > 0) { + DBG("re-send router solicitation %d", + network->router_solicit_count); + network->router_solicit_count--; + __connman_inet_ipv6_send_rs(network->index, 1, + receive_refresh_rs_reply, network); + return; + } + } + + network->router_solicit_count = 0; + refresh_rs_in_progress = FALSE; +} + +int refresh_rs_ipv6(struct connman_network *network, int index) +{ + int ret = 0; + + DBG("Send RS before RDNSS entries expire"); + + /* Send only one RS for all RDNSS entries which are about to expire */ + if (refresh_rs_in_progress == TRUE) + return 0; + + refresh_rs_in_progress = TRUE; + + /* Just send one RS message, without retrying */ + network->router_solicit_count = RS_REFRESH_RETRIES; + ret = __connman_inet_ipv6_send_rs(index, RS_REFRESH_TIMEOUT, + receive_refresh_rs_reply, network); + return ret; +} + static void autoconf_ipv6_set(struct connman_network *network) { struct connman_service *service; diff --git a/src/resolver.c b/src/resolver.c index 9656838..3a0ea3d 100644 --- a/src/resolver.c +++ b/src/resolver.c @@ -31,16 +31,21 @@ #include <string.h> #include <sys/stat.h> #include <resolv.h> +#include <math.h> #include "connman.h" #define RESOLVER_FLAG_PUBLIC (1 << 0) +/* Threshold for RDNSS lifetime. Will be used to trigger RS + * before RDNSS entries actually expire */ +#define RESOLVER_LIFETIME_REFRESH_THRESHOLD (0.8) struct entry_data { char *interface; char *domain; char *server; unsigned int flags; + unsigned int lifetime; guint timeout; }; @@ -253,11 +258,41 @@ static gboolean resolver_expire_cb(gpointer user_data) return FALSE; } +static gboolean resolver_refresh_cb(gpointer user_data) +{ + struct entry_data *entry = user_data; + int index; + unsigned int interval; + struct connman_service *service = NULL; + + interval = ceil(entry->lifetime * + (1 - RESOLVER_LIFETIME_REFRESH_THRESHOLD)); + DBG("RDNSS start lifetime timer remainder from threshold." + " interface %s domain %s server %s remaining lifetime %d", + entry->interface, entry->domain, entry->server, interval); + + entry->timeout = g_timeout_add_seconds(interval, + resolver_expire_cb, entry); + + index = connman_inet_ifindex(entry->interface); + if (index >= 0) { + service = __connman_service_lookup_from_index(index); + if (service != NULL) { + /* Send Router Solicitation to refresh RDNSS entries + * before their lifetime expires */ + refresh_rs_ipv6(__connman_service_get_network(service), + index); + } + } + return FALSE; +} + static int append_resolver(const char *interface, const char *domain, const char *server, unsigned int lifetime, unsigned int flags) { struct entry_data *entry; + unsigned int interval; DBG("interface %s domain %s server %s lifetime %d flags %d", interface, domain, server, lifetime, flags); @@ -273,10 +308,16 @@ static int append_resolver(const char *interface, const char *domain, entry->domain = g_strdup(domain); entry->server = g_strdup(server); entry->flags = flags; + entry->lifetime = lifetime; if (lifetime) { int index; - entry->timeout = g_timeout_add_seconds(lifetime, - resolver_expire_cb, entry); + interval = floor(lifetime * + RESOLVER_LIFETIME_REFRESH_THRESHOLD); + DBG("RDNSS start lifetime threshold timer." + " interface %s domain %s server %s lifetime threshold %d", + interface, domain, server, interval); + entry->timeout = g_timeout_add_seconds(interval, + resolver_refresh_cb, entry); /* * We update the service only for those nameservers @@ -350,6 +391,7 @@ int connman_resolver_append_lifetime(const char *interface, const char *domain, const char *server, unsigned int lifetime) { GSList *list; + unsigned int interval; DBG("interface %s domain %s server %s lifetime %d", interface, domain, server, lifetime); @@ -373,8 +415,14 @@ int connman_resolver_append_lifetime(const char *interface, const char *domain, return 0; } - entry->timeout = g_timeout_add_seconds(lifetime, - resolver_expire_cb, entry); + interval = floor(lifetime * + RESOLVER_LIFETIME_REFRESH_THRESHOLD); + DBG("RDNSS start lifetime threshold timer." + " interface %s domain %s server %s lifetime threshold %d", + interface, domain, server, interval); + + entry->timeout = g_timeout_add_seconds(interval, + resolver_refresh_cb, entry); return 0; } -- 1.7.5.4 _______________________________________________ connman mailing list connman@connman.net http://lists.connman.net/listinfo/connman