From 5bf6e62fa5cdf7d9a19af04948e53b7db07abbc8 Mon Sep 17 00:00:00 2001 From: Elena Tebesoi Date: Mon, 21 May 2012 14:49:42 +0200 Subject: resolver: Send RS before RDNSS lifetime expires 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 - set to 80% from lifetime - number of retries in case RA is not received - set to 0 - time between retries, in case RA is not received - set to 3 seconds --- src/connman.h | 3 +++ src/network.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/resolver.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 130 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/connman.h b/src/connman.h index 734213d8..7f998ebc 100644 --- a/src/connman.h +++ b/src/connman.h @@ -147,6 +147,9 @@ typedef void (*__connman_inet_rs_cb_t) (struct nd_router_advert *reply, int __connman_inet_ipv6_send_rs(int index, int timeout, __connman_inet_rs_cb_t callback, void *user_data); + +int __connman_refresh_rs_ipv6(struct connman_network *network, int index); + GSList *__connman_inet_ipv6_get_prefixes(struct nd_router_advert *hdr, unsigned int length); diff --git a/src/network.c b/src/network.c index 10f1bf32..6fe1d9c5 100644 --- a/src/network.c +++ b/src/network.c @@ -28,6 +28,19 @@ #include "connman.h" +/* + * How many times to send RS with the purpose of + * refreshing RDNSS entries before they actually expire. + * With a value of 1, one RS will be sent, with no retries. + */ +#define RS_REFRESH_COUNT 1 + +/* + * 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; @@ -46,6 +59,7 @@ struct connman_network { char *path; int index; int router_solicit_count; + int router_solicit_refresh_count; struct connman_network_driver *driver; void *driver_data; @@ -1113,6 +1127,58 @@ 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_refresh_count > 1) { + network->router_solicit_refresh_count--; + DBG("re-send router solicitation %d", + network->router_solicit_refresh_count); + __connman_inet_ipv6_send_rs(network->index, + RS_REFRESH_TIMEOUT, + receive_refresh_rs_reply, + network); + return; + } + } + + /* RS refresh not in progress anymore */ + network->router_solicit_refresh_count = 0; + + connman_network_unref(network); + return; +} + +int __connman_refresh_rs_ipv6(struct connman_network *network, int index) +{ + int ret = 0; + + DBG("network %p index %d", network, index); + + /* Send only one RS for all RDNSS entries which are about to expire */ + if (network->router_solicit_refresh_count > 0) { + DBG("RS refresh already started"); + return 0; + } + + network->router_solicit_refresh_count = RS_REFRESH_COUNT; + + connman_network_ref(network); + + 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 421b12f0..4780ac12 100644 --- a/src/resolver.c +++ b/src/resolver.c @@ -36,11 +36,18 @@ #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 +260,47 @@ 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; + + /* Round up what we have left from lifetime */ + interval = entry->lifetime * + (1 - RESOLVER_LIFETIME_REFRESH_THRESHOLD) + 1.0; + + DBG("RDNSS start 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 + */ + __connman_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 +316,17 @@ 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 = lifetime * RESOLVER_LIFETIME_REFRESH_THRESHOLD; + + DBG("RDNSS start 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 +400,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 +424,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 = lifetime * RESOLVER_LIFETIME_REFRESH_THRESHOLD; + + DBG("RDNSS start 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; } -- cgit v1.2.3