5 * Copyright (C) 2007-2010 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
36 #define RESOLVER_FLAG_PUBLIC (1 << 0)
39 struct connman_resolver *resolver;
47 static GSList *entry_list = NULL;
48 static GSList *resolver_list = NULL;
50 static void remove_entries(GSList *entries)
54 for (list = entries; list; list = list->next) {
55 struct entry_data *entry = list->data;
56 struct connman_resolver *resolver = entry->resolver;
58 entry_list = g_slist_remove(entry_list, entry);
60 if (resolver && resolver->remove)
61 resolver->remove(entry->interface, entry->domain,
65 g_source_remove(entry->timeout);
66 g_free(entry->server);
67 g_free(entry->domain);
68 g_free(entry->interface);
72 g_slist_free(entries);
75 static gint compare_priority(gconstpointer a, gconstpointer b)
77 const struct connman_resolver *resolver1 = a;
78 const struct connman_resolver *resolver2 = b;
80 return resolver2->priority - resolver1->priority;
84 * connman_resolver_register:
85 * @resolver: resolver module
87 * Register a new resolver module
89 * Returns: %0 on success
91 int connman_resolver_register(struct connman_resolver *resolver)
95 DBG("resolver %p name %s", resolver, resolver->name);
97 resolver_list = g_slist_insert_sorted(resolver_list, resolver,
100 if (resolver->append == NULL)
103 for (list = entry_list; list; list = list->next) {
104 struct entry_data *entry = list->data;
109 if (resolver->append(entry->interface, entry->domain,
111 entry->resolver = resolver;
118 * connman_resolver_unregister:
119 * @resolver: resolver module
121 * Remove a previously registered resolver module
123 void connman_resolver_unregister(struct connman_resolver *resolver)
125 GSList *list, *matches = NULL;
127 DBG("resolver %p name %s", resolver, resolver->name);
129 resolver_list = g_slist_remove(resolver_list, resolver);
131 for (list = entry_list; list; list = list->next) {
132 struct entry_data *entry = list->data;
134 if (entry->resolver != resolver)
137 matches = g_slist_append(matches, entry);
140 remove_entries(matches);
143 static gboolean resolver_expire_cb(gpointer user_data)
145 struct entry_data *entry = user_data;
148 DBG("interface %s domain %s server %s",
149 entry->interface, entry->domain, entry->server);
151 list = g_slist_append(NULL, entry);
152 remove_entries(list);
157 static int append_resolver(const char *interface, const char *domain,
158 const char *server, unsigned int lifetime,
161 struct entry_data *entry;
164 DBG("interface %s domain %s server %s lifetime %d flags %d",
165 interface, domain, server, lifetime, flags);
167 if (server == NULL && domain == NULL)
170 entry = g_try_new0(struct entry_data, 1);
174 entry->interface = g_strdup(interface);
175 entry->domain = g_strdup(domain);
176 entry->server = g_strdup(server);
177 entry->flags = flags;
179 entry->timeout = g_timeout_add_seconds(lifetime,
183 entry_list = g_slist_append(entry_list, entry);
185 for (list = resolver_list; list; list = list->next) {
186 struct connman_resolver *resolver = list->data;
188 if (resolver->append == NULL)
191 if (resolver->append(interface, domain, server) == 0) {
192 entry->resolver = resolver;
201 * connman_resolver_append:
202 * @interface: network interface
203 * @domain: domain limitation
204 * @server: server address
206 * Append resolver server address to current list
208 int connman_resolver_append(const char *interface, const char *domain,
211 DBG("interface %s domain %s server %s", interface, domain, server);
213 return append_resolver(interface, domain, server, 0, 0);
217 * connman_resolver_append_lifetime:
218 * @interface: network interface
219 * @domain: domain limitation
220 * @server: server address
221 * @timeout: server lifetime in seconds
223 * Append resolver server address to current list
225 int connman_resolver_append_lifetime(const char *interface, const char *domain,
226 const char *server, unsigned int lifetime)
230 DBG("interface %s domain %s server %s lifetime %d",
231 interface, domain, server, lifetime);
236 for (list = entry_list; list; list = list->next) {
237 struct entry_data *entry = list->data;
239 if (!entry->timeout ||
240 g_strcmp0(entry->interface, interface) ||
241 g_strcmp0(entry->domain, domain) ||
242 g_strcmp0(entry->server, server))
245 g_source_remove(entry->timeout);
246 entry->timeout = g_timeout_add_seconds(lifetime,
251 return append_resolver(interface, domain, server, lifetime, 0);
255 * connman_resolver_remove:
256 * @interface: network interface
257 * @domain: domain limitation
258 * @server: server address
260 * Remover resolver server address from current list
262 int connman_resolver_remove(const char *interface, const char *domain,
265 GSList *list, *matches = NULL;
267 DBG("interface %s domain %s server %s", interface, domain, server);
272 for (list = entry_list; list; list = list->next) {
273 struct entry_data *entry = list->data;
275 if (interface != NULL &&
276 g_strcmp0(entry->interface, interface) != 0)
279 if (domain != NULL && g_strcmp0(entry->domain, domain) != 0)
282 if (g_strcmp0(entry->server, server) != 0)
285 matches = g_slist_append(matches, entry);
291 remove_entries(matches);
297 * connman_resolver_remove_all:
298 * @interface: network interface
300 * Remove all resolver server address for the specified interface
302 int connman_resolver_remove_all(const char *interface)
304 GSList *list, *matches = NULL;
306 DBG("interface %s", interface);
308 if (interface == NULL)
311 for (list = entry_list; list; list = list->next) {
312 struct entry_data *entry = list->data;
314 if (g_strcmp0(entry->interface, interface) != 0)
317 matches = g_slist_append(matches, entry);
323 remove_entries(matches);
329 * connman_resolver_append_public_server:
330 * @server: server address
332 * Append public resolver server address to current list
334 int connman_resolver_append_public_server(const char *server)
336 DBG("server %s", server);
338 return append_resolver(NULL, NULL, server, 0, RESOLVER_FLAG_PUBLIC);
342 * connman_resolver_remove_public_server:
343 * @server: server address
345 * Remove public resolver server address to current list
347 int connman_resolver_remove_public_server(const char *server)
349 DBG("server %s", server);
351 return connman_resolver_remove(NULL, NULL, server);
355 * connman_resolver_flush:
357 * Flush pending resolver requests
359 void connman_resolver_flush(void)
363 for (list = resolver_list; list; list = list->next) {
364 struct connman_resolver *resolver = list->data;
366 if (resolver->flush == NULL)
375 struct resolvfile_entry {
381 static GList *resolvfile_list = NULL;
383 static void resolvfile_remove_entries(GList *entries)
387 for (list = entries; list; list = list->next) {
388 struct resolvfile_entry *entry = list->data;
390 resolvfile_list = g_list_remove(resolvfile_list, entry);
392 g_free(entry->server);
393 g_free(entry->domain);
394 g_free(entry->interface);
398 g_list_free(entries);
401 static int resolvfile_export(void)
409 content = g_string_new("# Generated by Connection Manager\n");
412 * Domains and nameservers are added in reverse so that the most
413 * recently appended entry is the primary one. No more than
414 * MAXDNSRCH/MAXNS entries are used.
417 for (count = 0, list = g_list_last(resolvfile_list);
418 list && (count < MAXDNSRCH);
419 list = g_list_previous(list)) {
420 struct resolvfile_entry *entry = list->data;
426 g_string_append_printf(content, "search ");
428 g_string_append_printf(content, "%s ", entry->domain);
433 g_string_append_printf(content, "\n");
435 for (count = 0, list = g_list_last(resolvfile_list);
436 list && (count < MAXNS);
437 list = g_list_previous(list)) {
438 struct resolvfile_entry *entry = list->data;
443 g_string_append_printf(content, "nameserver %s\n",
448 old_umask = umask(022);
450 fd = open("/etc/resolv.conf", O_RDWR | O_CREAT,
451 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
457 if (ftruncate(fd, 0) < 0) {
464 if (write(fd, content->str, content->len) < 0)
471 g_string_free(content, TRUE);
477 static int resolvfile_append(const char *interface, const char *domain,
480 struct resolvfile_entry *entry;
482 DBG("interface %s server %s", interface, server);
484 if (interface == NULL)
487 entry = g_try_new0(struct resolvfile_entry, 1);
491 entry->interface = g_strdup(interface);
492 entry->domain = g_strdup(domain);
493 entry->server = g_strdup(server);
495 resolvfile_list = g_list_append(resolvfile_list, entry);
497 return resolvfile_export();
500 static int resolvfile_remove(const char *interface, const char *domain,
503 GList *list, *matches = NULL;
505 DBG("interface %s server %s", interface, server);
507 for (list = resolvfile_list; list; list = g_list_next(list)) {
508 struct resolvfile_entry *entry = list->data;
510 if (interface != NULL &&
511 g_strcmp0(entry->interface, interface) != 0)
514 if (domain != NULL && g_strcmp0(entry->domain, domain) != 0)
517 if (g_strcmp0(entry->server, server) != 0)
520 matches = g_list_append(matches, entry);
523 resolvfile_remove_entries(matches);
525 return resolvfile_export();
528 static struct connman_resolver resolvfile_resolver = {
529 .name = "resolvfile",
530 .priority = CONNMAN_RESOLVER_PRIORITY_LOW,
531 .append = resolvfile_append,
532 .remove = resolvfile_remove,
535 int __connman_resolver_init(void)
539 return connman_resolver_register(&resolvfile_resolver);
542 void __connman_resolver_cleanup(void)
546 connman_resolver_unregister(&resolvfile_resolver);