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;
46 static GSList *entry_list = NULL;
47 static GSList *resolver_list = NULL;
49 static void remove_entries(GSList *entries)
53 for (list = entries; list; list = list->next) {
54 struct entry_data *entry = list->data;
55 struct connman_resolver *resolver = entry->resolver;
57 entry_list = g_slist_remove(entry_list, entry);
59 if (resolver && resolver->remove)
60 resolver->remove(entry->interface, entry->domain,
63 g_free(entry->server);
64 g_free(entry->domain);
65 g_free(entry->interface);
69 g_slist_free(entries);
72 static gint compare_priority(gconstpointer a, gconstpointer b)
74 const struct connman_resolver *resolver1 = a;
75 const struct connman_resolver *resolver2 = b;
77 return resolver2->priority - resolver1->priority;
81 * connman_resolver_register:
82 * @resolver: resolver module
84 * Register a new resolver module
86 * Returns: %0 on success
88 int connman_resolver_register(struct connman_resolver *resolver)
92 DBG("resolver %p name %s", resolver, resolver->name);
94 resolver_list = g_slist_insert_sorted(resolver_list, resolver,
97 if (resolver->append == NULL)
100 for (list = entry_list; list; list = list->next) {
101 struct entry_data *entry = list->data;
106 if (resolver->append(entry->interface, entry->domain,
108 entry->resolver = resolver;
115 * connman_resolver_unregister:
116 * @resolver: resolver module
118 * Remove a previously registered resolver module
120 void connman_resolver_unregister(struct connman_resolver *resolver)
122 GSList *list, *matches = NULL;
124 DBG("resolver %p name %s", resolver, resolver->name);
126 resolver_list = g_slist_remove(resolver_list, resolver);
128 for (list = entry_list; list; list = list->next) {
129 struct entry_data *entry = list->data;
131 if (entry->resolver != resolver)
134 matches = g_slist_append(matches, entry);
137 remove_entries(matches);
140 static int append_resolver(const char *interface, const char *domain,
141 const char *server, unsigned int flags)
143 struct entry_data *entry;
146 DBG("interface %s domain %s server %s flags %d",
147 interface, domain, server, flags);
152 entry = g_try_new0(struct entry_data, 1);
156 entry->interface = g_strdup(interface);
157 entry->domain = g_strdup(domain);
158 entry->server = g_strdup(server);
159 entry->flags = flags;
161 entry_list = g_slist_append(entry_list, entry);
163 for (list = resolver_list; list; list = list->next) {
164 struct connman_resolver *resolver = list->data;
166 if (resolver->append == NULL)
169 if (resolver->append(interface, domain, server) == 0) {
170 entry->resolver = resolver;
179 * connman_resolver_append:
180 * @interface: network interface
181 * @domain: domain limitation
182 * @server: server address
184 * Append resolver server address to current list
186 int connman_resolver_append(const char *interface, const char *domain,
189 DBG("interface %s domain %s server %s", interface, domain, server);
191 return append_resolver(interface, domain, server, 0);
195 * connman_resolver_remove:
196 * @interface: network interface
197 * @domain: domain limitation
198 * @server: server address
200 * Remover resolver server address from current list
202 int connman_resolver_remove(const char *interface, const char *domain,
205 GSList *list, *matches = NULL;
207 DBG("interface %s domain %s server %s", interface, domain, server);
212 for (list = entry_list; list; list = list->next) {
213 struct entry_data *entry = list->data;
215 if (interface != NULL &&
216 g_strcmp0(entry->interface, interface) != 0)
219 if (domain != NULL && g_strcmp0(entry->domain, domain) != 0)
222 if (g_strcmp0(entry->server, server) != 0)
225 matches = g_slist_append(matches, entry);
231 remove_entries(matches);
237 * connman_resolver_remove_all:
238 * @interface: network interface
240 * Remove all resolver server address for the specified interface
242 int connman_resolver_remove_all(const char *interface)
244 GSList *list, *matches = NULL;
246 DBG("interface %s", interface);
248 if (interface == NULL)
251 for (list = entry_list; list; list = list->next) {
252 struct entry_data *entry = list->data;
254 if (g_strcmp0(entry->interface, interface) != 0)
257 matches = g_slist_append(matches, entry);
263 remove_entries(matches);
269 * connman_resolver_append_public_server:
270 * @server: server address
272 * Append public resolver server address to current list
274 int connman_resolver_append_public_server(const char *server)
276 DBG("server %s", server);
278 return append_resolver(NULL, NULL, server, RESOLVER_FLAG_PUBLIC);
282 * connman_resolver_remove_public_server:
283 * @server: server address
285 * Remove public resolver server address to current list
287 int connman_resolver_remove_public_server(const char *server)
289 DBG("server %s", server);
291 return connman_resolver_remove(NULL, NULL, server);
295 * connman_resolver_flush:
297 * Flush pending resolver requests
299 void connman_resolver_flush(void)
303 for (list = resolver_list; list; list = list->next) {
304 struct connman_resolver *resolver = list->data;
306 if (resolver->flush == NULL)
315 static int selftest_append(const char *interface, const char *domain,
318 DBG("server %s", server);
323 static int selftest_remove(const char *interface, const char *domain,
326 DBG("server %s", server);
331 static struct connman_resolver selftest_resolver = {
333 .priority = CONNMAN_RESOLVER_PRIORITY_HIGH + 42,
334 .append = selftest_append,
335 .remove = selftest_remove,
338 int __connman_resolver_selftest(void)
340 connman_resolver_append("wlan0", "lwn.net", "192.168.0.1");
342 connman_resolver_register(&selftest_resolver);
344 connman_resolver_append("eth0", "moblin.org", "192.168.42.1");
345 connman_resolver_append("wlan0", "lwn.net", "192.168.0.2");
347 connman_resolver_append_public_server("8.8.8.8");
349 connman_resolver_remove_public_server("8.8.8.8");
351 connman_resolver_remove_all("wlan0");
353 connman_resolver_unregister(&selftest_resolver);
358 struct resolvfile_entry {
364 static GList *resolvfile_list = NULL;
366 static void resolvfile_remove_entries(GList *entries)
370 for (list = entries; list; list = list->next) {
371 struct resolvfile_entry *entry = list->data;
373 resolvfile_list = g_list_remove(resolvfile_list, entry);
375 g_free(entry->server);
376 g_free(entry->domain);
377 g_free(entry->interface);
381 g_list_free(entries);
384 static int resolvfile_export(void)
392 content = g_string_new("# Generated by Connection Manager\n");
395 * Nameservers are added in reverse so that the most recently
396 * appended entry is the primary nameserver. No more than MAXNS
397 * nameservers are used.
399 for (count = 0, list = g_list_last(resolvfile_list);
400 list && (count < MAXNS);
401 list = g_list_previous(list)) {
402 struct resolvfile_entry *entry = list->data;
403 g_string_append_printf(content, "nameserver %s\n",
408 old_umask = umask(022);
410 fd = open("/etc/resolv.conf", O_RDWR | O_CREAT,
411 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
417 if (ftruncate(fd, 0) < 0) {
424 if (write(fd, content->str, content->len) < 0)
431 g_string_free(content, TRUE);
437 static int resolvfile_append(const char *interface, const char *domain,
440 struct resolvfile_entry *entry;
442 DBG("interface %s server %s", interface, server);
444 if (interface == NULL)
447 entry = g_try_new0(struct resolvfile_entry, 1);
451 entry->interface = g_strdup(interface);
452 entry->domain = g_strdup(domain);
453 entry->server = g_strdup(server);
455 resolvfile_list = g_list_append(resolvfile_list, entry);
457 return resolvfile_export();
460 static int resolvfile_remove(const char *interface, const char *domain,
463 GList *list, *matches = NULL;
465 DBG("interface %s server %s", interface, server);
467 for (list = resolvfile_list; list; list = g_list_next(list)) {
468 struct resolvfile_entry *entry = list->data;
470 if (interface != NULL &&
471 g_strcmp0(entry->interface, interface) != 0)
474 if (domain != NULL && g_strcmp0(entry->domain, domain) != 0)
477 if (g_strcmp0(entry->server, server) != 0)
480 matches = g_list_append(matches, entry);
483 resolvfile_remove_entries(matches);
485 return resolvfile_export();
488 static struct connman_resolver resolvfile_resolver = {
489 .name = "resolvfile",
490 .priority = CONNMAN_RESOLVER_PRIORITY_LOW,
491 .append = resolvfile_append,
492 .remove = resolvfile_remove,
495 int __connman_resolver_init(void)
499 return connman_resolver_register(&resolvfile_resolver);
502 void __connman_resolver_cleanup(void)
506 connman_resolver_unregister(&resolvfile_resolver);