5 * Copyright (C) 2007-2013 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
38 * Just to avoid build failure due to missing STATEDIR
44 #define STATEDIR "/etc"
47 #define RESOLV_CONF_STATEDIR STATEDIR"/resolv.conf"
48 #define RESOLV_CONF_ETC "/etc/resolv.conf"
50 #define RESOLVER_FLAG_PUBLIC (1 << 0)
53 * Threshold for RDNSS lifetime. Will be used to trigger RS
54 * before RDNSS entries actually expire
56 #define RESOLVER_LIFETIME_REFRESH_THRESHOLD 0.8
64 unsigned int lifetime;
68 static GSList *entry_list = NULL;
69 static bool dnsproxy_enabled = false;
71 struct resolvfile_entry {
77 static GList *resolvfile_list = NULL;
79 static void resolvfile_remove_entries(GList *entries)
83 for (list = entries; list; list = list->next) {
84 struct resolvfile_entry *entry = list->data;
86 resolvfile_list = g_list_remove(resolvfile_list, entry);
88 g_free(entry->server);
89 g_free(entry->domain);
96 static int resolvfile_export(void)
104 content = g_string_new("# Generated by Connection Manager\n");
107 * Domains and nameservers are added in reverse so that the most
108 * recently appended entry is the primary one. No more than
109 * MAXDNSRCH/MAXNS entries are used.
112 for (count = 0, list = g_list_first(resolvfile_list);
113 list && (count < MAXDNSRCH);
114 list = g_list_next(list)) {
115 struct resolvfile_entry *entry = list->data;
121 g_string_append_printf(content, "search ");
123 g_string_append_printf(content, "%s ", entry->domain);
128 g_string_append_printf(content, "\n");
130 for (count = 0, list = g_list_first(resolvfile_list);
131 list && (count < MAXNS);
132 list = g_list_next(list)) {
133 struct resolvfile_entry *entry = list->data;
138 g_string_append_printf(content, "nameserver %s\n",
143 old_umask = umask(022);
145 fd = open(RESOLV_CONF_STATEDIR, O_RDWR | O_CREAT | O_CLOEXEC,
146 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
148 connman_warn_once("Cannot create "RESOLV_CONF_STATEDIR" "
149 "falling back to "RESOLV_CONF_ETC);
151 fd = open(RESOLV_CONF_ETC, O_RDWR | O_CREAT | O_CLOEXEC,
152 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
160 if (ftruncate(fd, 0) < 0) {
167 if (write(fd, content->str, content->len) < 0)
174 g_string_free(content, TRUE);
180 int __connman_resolvfile_append(int index, const char *domain,
183 struct resolvfile_entry *entry;
185 DBG("index %d server %s", index, server);
190 entry = g_try_new0(struct resolvfile_entry, 1);
194 entry->index = index;
195 entry->domain = g_strdup(domain);
196 entry->server = g_strdup(server);
198 resolvfile_list = g_list_append(resolvfile_list, entry);
200 return resolvfile_export();
203 int __connman_resolvfile_remove(int index, const char *domain,
206 GList *list, *matches = NULL;
208 DBG("index %d server %s", index, server);
210 for (list = resolvfile_list; list; list = g_list_next(list)) {
211 struct resolvfile_entry *entry = list->data;
213 if (index >= 0 && entry->index != index)
216 if (domain && g_strcmp0(entry->domain, domain) != 0)
219 if (g_strcmp0(entry->server, server) != 0)
222 matches = g_list_append(matches, entry);
225 resolvfile_remove_entries(matches);
227 return resolvfile_export();
230 void __connman_resolver_append_fallback_nameservers(void)
234 for (list = entry_list; list; list = list->next) {
235 struct entry_data *entry = list->data;
237 if (entry->index >= 0 && entry->server)
241 for (list = entry_list; list; list = list->next) {
242 struct entry_data *entry = list->data;
244 if (entry->index != -1 || !entry->server)
247 DBG("index %d server %s", entry->index, entry->server);
249 if (dnsproxy_enabled) {
250 __connman_dnsproxy_append(entry->index, entry->domain,
253 __connman_resolvfile_append(entry->index,
254 entry->domain, entry->server);
259 static void remove_fallback_nameservers(void)
263 for (list = entry_list; list; list = list->next) {
264 struct entry_data *entry = list->data;
266 if (entry->index >= 0 || !entry->server)
269 DBG("index %d server %s", entry->index, entry->server);
271 if (dnsproxy_enabled) {
272 __connman_dnsproxy_remove(entry->index, entry->domain,
275 __connman_resolvfile_remove(entry->index,
276 entry->domain, entry->server);
281 static void remove_entries(GSList *entries)
285 for (list = entries; list; list = list->next) {
286 struct entry_data *entry = list->data;
288 entry_list = g_slist_remove(entry_list, entry);
290 if (dnsproxy_enabled) {
291 __connman_dnsproxy_remove(entry->index, entry->domain,
294 __connman_resolvfile_remove(entry->index, entry->domain,
299 g_source_remove(entry->timeout);
300 g_free(entry->server);
301 g_free(entry->domain);
305 g_slist_free(entries);
307 __connman_resolver_append_fallback_nameservers();
310 static gboolean resolver_expire_cb(gpointer user_data)
312 struct entry_data *entry = user_data;
315 DBG("index %d domain %s server %s",
316 entry->index, entry->domain, entry->server);
318 list = g_slist_prepend(NULL, entry);
320 if (entry->index >= 0) {
321 struct connman_service *service;
322 service = __connman_service_lookup_from_index(entry->index);
324 #if defined TIZEN_EXT
325 __connman_service_nameserver_remove(service,
327 CONNMAN_IPCONFIG_TYPE_ALL);
329 __connman_service_nameserver_remove(service,
330 entry->server, true);
334 remove_entries(list);
339 static gboolean resolver_refresh_cb(gpointer user_data)
341 struct entry_data *entry = user_data;
342 unsigned int interval;
343 struct connman_service *service = NULL;
345 /* Round up what we have left from lifetime */
346 interval = entry->lifetime *
347 (1 - RESOLVER_LIFETIME_REFRESH_THRESHOLD) + 1.0;
349 DBG("RDNSS start index %d domain %s "
350 "server %s remaining lifetime %d",
351 entry->index, entry->domain,
352 entry->server, interval);
354 entry->timeout = g_timeout_add_seconds(interval,
355 resolver_expire_cb, entry);
357 if (entry->index >= 0) {
358 service = __connman_service_lookup_from_index(entry->index);
361 * Send Router Solicitation to refresh RDNSS entries
362 * before their lifetime expires
364 __connman_network_refresh_rs_ipv6(
365 __connman_service_get_network(service),
372 static int append_resolver(int index, const char *domain,
373 const char *server, unsigned int lifetime,
376 struct entry_data *entry;
377 unsigned int interval;
379 DBG("index %d domain %s server %s lifetime %d flags %d",
380 index, domain, server, lifetime, flags);
382 if (!server && !domain)
386 if (g_strcmp0(server, "0.0.0.0") == 0)
390 entry = g_try_new0(struct entry_data, 1);
394 entry->index = index;
395 entry->domain = g_strdup(domain);
396 entry->server = g_strdup(server);
397 entry->flags = flags;
398 entry->lifetime = lifetime;
401 entry->family = connman_inet_check_ipaddress(server);
404 interval = lifetime * RESOLVER_LIFETIME_REFRESH_THRESHOLD;
406 DBG("RDNSS start index %d domain %s "
407 "server %s lifetime threshold %d",
408 index, domain, server, interval);
410 entry->timeout = g_timeout_add_seconds(interval,
411 resolver_refresh_cb, entry);
414 if (entry->index >= 0 && entry->server)
415 remove_fallback_nameservers();
417 entry_list = g_slist_append(entry_list, entry);
419 if (dnsproxy_enabled)
420 __connman_dnsproxy_append(entry->index, domain, server);
422 __connman_resolvfile_append(entry->index, domain, server);
425 * We update the service only for those nameservers
426 * that are automagically added via netlink (lifetime > 0)
428 if (server && entry->index >= 0 && lifetime) {
429 struct connman_service *service;
430 service = __connman_service_lookup_from_index(entry->index);
432 #if defined TIZEN_EXT
433 __connman_service_nameserver_append(service,
435 CONNMAN_IPCONFIG_TYPE_ALL);
437 __connman_service_nameserver_append(service,
446 * connman_resolver_append:
447 * @index: network interface index
448 * @domain: domain limitation
449 * @server: server address
451 * Append resolver server address to current list
453 int connman_resolver_append(int index, const char *domain,
458 DBG("index %d domain %s server %s", index, domain, server);
460 if (!server && !domain)
463 for (list = entry_list; list; list = list->next) {
464 struct entry_data *entry = list->data;
466 if (entry->timeout > 0)
469 if (entry->index == index &&
470 g_strcmp0(entry->domain, domain) == 0 &&
471 g_strcmp0(entry->server, server) == 0) {
472 if (dnsproxy_enabled)
473 __connman_dnsproxy_append(entry->index, domain,
480 return append_resolver(index, domain, server, 0, 0);
484 * connman_resolver_append_lifetime:
485 * @index: network interface index
486 * @domain: domain limitation
487 * @server: server address
488 * @timeout: server lifetime in seconds
490 * Append resolver server address to current list
492 int connman_resolver_append_lifetime(int index, const char *domain,
493 const char *server, unsigned int lifetime)
496 unsigned int interval;
498 DBG("index %d domain %s server %s lifetime %d",
499 index, domain, server, lifetime);
501 if (!server && !domain)
504 for (list = entry_list; list; list = list->next) {
505 struct entry_data *entry = list->data;
507 if (entry->timeout == 0 ||
508 entry->index != index ||
509 g_strcmp0(entry->domain, domain) != 0 ||
510 g_strcmp0(entry->server, server) != 0)
513 g_source_remove(entry->timeout);
516 resolver_expire_cb(entry);
520 interval = lifetime * RESOLVER_LIFETIME_REFRESH_THRESHOLD;
522 DBG("RDNSS start index %d domain %s "
523 "server %s lifetime threshold %d",
524 index, domain, server, interval);
526 entry->timeout = g_timeout_add_seconds(interval,
527 resolver_refresh_cb, entry);
531 return append_resolver(index, domain, server, lifetime, 0);
535 * connman_resolver_remove:
536 * @index: network interface index
537 * @domain: domain limitation
538 * @server: server address
540 * Remover resolver server address from current list
542 int connman_resolver_remove(int index, const char *domain, const char *server)
544 GSList *list, *matches = NULL;
546 DBG("index %d domain %s server %s", index, domain, server);
548 for (list = entry_list; list; list = list->next) {
549 struct entry_data *entry = list->data;
551 if (entry->index != index)
554 if (g_strcmp0(entry->domain, domain) != 0)
557 if (g_strcmp0(entry->server, server) != 0)
560 matches = g_slist_prepend(matches, entry);
567 remove_entries(matches);
573 * connman_resolver_remove_all:
574 * @index: network interface index
576 * Remove all resolver server address for the specified interface index
578 int connman_resolver_remove_all(int index)
580 GSList *list, *matches = NULL;
582 DBG("index %d", index);
587 for (list = entry_list; list; list = list->next) {
588 struct entry_data *entry = list->data;
590 if (entry->index != index)
593 matches = g_slist_prepend(matches, entry);
599 remove_entries(matches);
604 int __connman_resolver_redo_servers(int index)
608 if (!dnsproxy_enabled)
611 DBG("index %d", index);
616 for (list = entry_list; list; list = list->next) {
617 struct entry_data *entry = list->data;
619 if (entry->timeout == 0 || entry->index != index)
623 * This function must only check IPv6 server addresses so
624 * do not remove IPv4 name servers unnecessarily.
626 if (entry->family != AF_INET6)
630 * We remove the server, and then re-create so that it will
631 * use proper source addresses when sending DNS queries.
633 __connman_dnsproxy_remove(entry->index, entry->domain,
636 __connman_dnsproxy_append(entry->index, entry->domain,
641 * We want to re-add all search domains back to search
642 * domain lists as they just got removed for RDNSS IPv6-servers
644 * Removal of search domains is not necessary
645 * as there can be only one instance of each search domain
646 * in the each dns-servers search domain list.
649 for (list = entry_list; list; list = list->next) {
650 struct entry_data *entry = list->data;
652 if (entry->index != index)
658 __connman_dnsproxy_append(entry->index, entry->domain,
665 static void free_entry(gpointer data)
667 struct entry_data *entry = data;
668 g_free(entry->domain);
669 g_free(entry->server);
673 static void free_resolvfile(gpointer data)
675 struct resolvfile_entry *entry = data;
676 g_free(entry->domain);
677 g_free(entry->server);
681 int __connman_resolver_set_mdns(int index, bool enabled)
683 if (!dnsproxy_enabled)
686 return __connman_dnsproxy_set_mdns(index, enabled);
689 int __connman_resolver_init(gboolean dnsproxy)
694 DBG("dnsproxy %d", dnsproxy);
696 /* get autoip nameservers */
697 ns = __connman_inet_get_pnp_nameservers(NULL);
698 for (i = 0; ns && ns[i]; i += 1) {
699 DBG("pnp server %s", ns[i]);
700 append_resolver(i, NULL, ns[i], 86400, 0);
707 if (__connman_dnsproxy_init() < 0) {
708 /* Fall back to resolv.conf */
712 dnsproxy_enabled = true;
714 ns = connman_setting_get_string_list("FallbackNameservers");
715 for (i = 0; ns && ns[i]; i += 1) {
716 DBG("server %s", ns[i]);
717 append_resolver(-1, NULL, ns[i], 0, RESOLVER_FLAG_PUBLIC);
723 void __connman_resolver_cleanup(void)
727 if (dnsproxy_enabled)
728 __connman_dnsproxy_cleanup();
733 for (list = resolvfile_list; list; list = g_list_next(list))
734 free_resolvfile(list->data);
735 g_list_free(resolvfile_list);
736 resolvfile_list = NULL;
738 for (slist = entry_list; slist; slist = g_slist_next(slist))
739 free_entry(slist->data);
740 g_slist_free(entry_list);