X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fresolver.c;h=3ce74c32a99bd9f05b004969b39beda3c694a3b9;hb=46d7e52dcabccff5e010a6aa7232fbbfea1abecb;hp=59defd49bd7830ffb6b98db043184b837c894e17;hpb=fbc9569af18f4c6fd46413f32c57b05c4602393e;p=framework%2Fconnectivity%2Fconnman.git diff --git a/src/resolver.c b/src/resolver.c index 59defd4..3ce74c3 100644 --- a/src/resolver.c +++ b/src/resolver.c @@ -2,7 +2,7 @@ * * Connection Manager * - * Copyright (C) 2007-2010 Intel Corporation. All rights reserved. + * Copyright (C) 2007-2012 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -23,6 +23,7 @@ #include #endif +#define _GNU_SOURCE #include #include #include @@ -35,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; }; @@ -121,7 +129,7 @@ static int resolvfile_export(void) old_umask = umask(022); - fd = open("/etc/resolv.conf", O_RDWR | O_CREAT, + fd = open("/etc/resolv.conf", O_RDWR | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd < 0) { err = -errno; @@ -231,21 +239,68 @@ static gboolean resolver_expire_cb(gpointer user_data) { struct entry_data *entry = user_data; GSList *list; + int index; DBG("interface %s domain %s server %s", entry->interface, entry->domain, entry->server); list = g_slist_append(NULL, entry); + + index = connman_inet_ifindex(entry->interface); + if (index >= 0) { + struct connman_service *service; + service = __connman_service_lookup_from_index(index); + if (service != NULL) + __connman_service_nameserver_remove(service, + entry->server, TRUE); + } + remove_entries(list); 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); @@ -261,10 +316,31 @@ static int append_resolver(const char *interface, const char *domain, entry->domain = g_strdup(domain); entry->server = g_strdup(server); entry->flags = flags; - if (lifetime) - entry->timeout = g_timeout_add_seconds(lifetime, - resolver_expire_cb, entry); - + entry->lifetime = lifetime; + if (lifetime) { + int index; + 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 + * that are automagically added via netlink (lifetime > 0) + */ + index = connman_inet_ifindex(interface); + if (server != NULL && index >= 0) { + struct connman_service *service; + service = __connman_service_lookup_from_index(index); + if (service != NULL) + __connman_service_nameserver_append(service, + server, TRUE); + } + } entry_list = g_slist_append(entry_list, entry); if (dnsproxy_enabled == TRUE) @@ -286,8 +362,25 @@ static int append_resolver(const char *interface, const char *domain, int connman_resolver_append(const char *interface, const char *domain, const char *server) { + GSList *list; + DBG("interface %s domain %s server %s", interface, domain, server); + if (server == NULL && domain == NULL) + return -EINVAL; + + for (list = entry_list; list; list = list->next) { + struct entry_data *entry = list->data; + + if (entry->timeout > 0) + continue; + + if (g_strcmp0(entry->interface, interface) == 0 && + g_strcmp0(entry->domain, domain) == 0 && + g_strcmp0(entry->server, server) == 0) + return -EEXIST; + } + return append_resolver(interface, domain, server, 0, 0); } @@ -304,25 +397,38 @@ 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); - if (server == NULL) + if (server == NULL && domain == NULL) return -EINVAL; for (list = entry_list; list; list = list->next) { struct entry_data *entry = list->data; - if (!entry->timeout || - g_strcmp0(entry->interface, interface) || - g_strcmp0(entry->domain, domain) || - g_strcmp0(entry->server, server)) + if (entry->timeout == 0 || + g_strcmp0(entry->interface, interface) != 0 || + g_strcmp0(entry->domain, domain) != 0 || + g_strcmp0(entry->server, server) != 0) continue; g_source_remove(entry->timeout); - entry->timeout = g_timeout_add_seconds(lifetime, - resolver_expire_cb, entry); + + if (lifetime == 0) { + resolver_expire_cb(entry); + return 0; + } + + 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; } @@ -404,46 +510,81 @@ int connman_resolver_remove_all(const char *interface) } /** - * connman_resolver_append_public_server: - * @server: server address + * connman_resolver_flush: * - * Append public resolver server address to current list + * Flush pending resolver requests */ -int connman_resolver_append_public_server(const char *server) +void connman_resolver_flush(void) { - DBG("server %s", server); + if (dnsproxy_enabled == TRUE) + __connman_dnsproxy_flush(); - return append_resolver(NULL, NULL, server, 0, RESOLVER_FLAG_PUBLIC); + return; } -/** - * connman_resolver_remove_public_server: - * @server: server address - * - * Remove public resolver server address to current list - */ -int connman_resolver_remove_public_server(const char *server) +int __connman_resolver_redo_servers(const char *interface) { - DBG("server %s", server); + GSList *list; + + if (dnsproxy_enabled == FALSE) + return 0; + + DBG("interface %s", interface); + + if (interface == NULL) + return -EINVAL; + + for (list = entry_list; list; list = list->next) { + struct entry_data *entry = list->data; + + if (entry->timeout == 0 || + g_strcmp0(entry->interface, interface) != 0) + continue; - return connman_resolver_remove(NULL, NULL, server); + /* + * We remove the server, and then re-create so that it will + * use proper source addresses when sending DNS queries. + */ + __connman_dnsproxy_remove(entry->interface, entry->domain, + entry->server); + /* + * Remove also the resolver timer for the old server entry. + * A new timer will be set for the new server entry + * when the next Router Advertisement message arrives + * with RDNSS/DNSSL settings. + */ + g_source_remove(entry->timeout); + + __connman_dnsproxy_append(entry->interface, entry->domain, + entry->server); + } + + return 0; } -/** - * connman_resolver_flush: - * - * Flush pending resolver requests - */ -void connman_resolver_flush(void) +static void free_entry(gpointer data) { - if (dnsproxy_enabled == TRUE) - __connman_dnsproxy_flush(); + struct entry_data *entry = data; + g_free(entry->interface); + g_free(entry->domain); + g_free(entry->server); + g_free(entry); +} - return; +static void free_resolvfile(gpointer data) +{ + struct resolvfile_entry *entry = data; + g_free(entry->interface); + g_free(entry->domain); + g_free(entry->server); + g_free(entry); } int __connman_resolver_init(connman_bool_t dnsproxy) { + int i; + char **ns; + DBG("dnsproxy %d", dnsproxy); if (dnsproxy == FALSE) @@ -456,6 +597,12 @@ int __connman_resolver_init(connman_bool_t dnsproxy) dnsproxy_enabled = TRUE; + ns = connman_setting_get_string_list("FallbackNameservers"); + for (i = 0; ns != NULL && ns[i] != NULL; i += 1) { + DBG("server %s", ns[i]); + append_resolver(NULL, NULL, ns[i], 0, RESOLVER_FLAG_PUBLIC); + } + return 0; } @@ -465,4 +612,18 @@ void __connman_resolver_cleanup(void) if (dnsproxy_enabled == TRUE) __connman_dnsproxy_cleanup(); + else { + GList *list; + GSList *slist; + + for (list = resolvfile_list; list; list = g_list_next(list)) + free_resolvfile(list->data); + g_list_free(resolvfile_list); + resolvfile_list = NULL; + + for (slist = entry_list; slist; slist = g_slist_next(slist)) + free_entry(slist->data); + g_slist_free(entry_list); + entry_list = NULL; + } }