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
---
src/connman.h | 3 ++
src/network.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/resolver.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 131 insertions(+), 4 deletions(-)
diff --git a/src/connman.h b/src/connman.h
index 734213d..7f998eb 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 10f1bf3..7516053 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,59 @@ 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;
+ }
+
+ /* Just send one RS message, without retrying */
+ 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 58af2f7..e0a81d8 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;
}
--
1.7.5.4
_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman