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
37 #define RESOLVER_FLAG_PUBLIC (1 << 0)
47 static GSList *entry_list = NULL;
48 static connman_bool_t dnsproxy_enabled = FALSE;
50 struct resolvfile_entry {
56 static GList *resolvfile_list = NULL;
58 static void resolvfile_remove_entries(GList *entries)
62 for (list = entries; list; list = list->next) {
63 struct resolvfile_entry *entry = list->data;
65 resolvfile_list = g_list_remove(resolvfile_list, entry);
67 g_free(entry->server);
68 g_free(entry->domain);
69 g_free(entry->interface);
76 static int resolvfile_export(void)
84 content = g_string_new("# Generated by Connection Manager\n");
87 * Domains and nameservers are added in reverse so that the most
88 * recently appended entry is the primary one. No more than
89 * MAXDNSRCH/MAXNS entries are used.
92 for (count = 0, list = g_list_last(resolvfile_list);
93 list && (count < MAXDNSRCH);
94 list = g_list_previous(list)) {
95 struct resolvfile_entry *entry = list->data;
101 g_string_append_printf(content, "search ");
103 g_string_append_printf(content, "%s ", entry->domain);
108 g_string_append_printf(content, "\n");
110 for (count = 0, list = g_list_last(resolvfile_list);
111 list && (count < MAXNS);
112 list = g_list_previous(list)) {
113 struct resolvfile_entry *entry = list->data;
118 g_string_append_printf(content, "nameserver %s\n",
123 old_umask = umask(022);
125 fd = open("/etc/resolv.conf", O_RDWR | O_CREAT | O_CLOEXEC,
126 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
132 if (ftruncate(fd, 0) < 0) {
139 if (write(fd, content->str, content->len) < 0)
146 g_string_free(content, TRUE);
152 int __connman_resolvfile_append(const char *interface, const char *domain,
155 struct resolvfile_entry *entry;
157 DBG("interface %s server %s", interface, server);
159 if (interface == NULL)
162 entry = g_try_new0(struct resolvfile_entry, 1);
166 entry->interface = g_strdup(interface);
167 entry->domain = g_strdup(domain);
168 entry->server = g_strdup(server);
170 resolvfile_list = g_list_append(resolvfile_list, entry);
172 return resolvfile_export();
175 int __connman_resolvfile_remove(const char *interface, const char *domain,
178 GList *list, *matches = NULL;
180 DBG("interface %s server %s", interface, server);
182 for (list = resolvfile_list; list; list = g_list_next(list)) {
183 struct resolvfile_entry *entry = list->data;
185 if (interface != NULL &&
186 g_strcmp0(entry->interface, interface) != 0)
189 if (domain != NULL && g_strcmp0(entry->domain, domain) != 0)
192 if (g_strcmp0(entry->server, server) != 0)
195 matches = g_list_append(matches, entry);
198 resolvfile_remove_entries(matches);
200 return resolvfile_export();
203 static void remove_entries(GSList *entries)
207 for (list = entries; list; list = list->next) {
208 struct entry_data *entry = list->data;
210 entry_list = g_slist_remove(entry_list, entry);
212 if (dnsproxy_enabled == TRUE) {
213 __connman_dnsproxy_remove(entry->interface, entry->domain,
216 __connman_resolvfile_remove(entry->interface, entry->domain,
221 g_source_remove(entry->timeout);
222 g_free(entry->server);
223 g_free(entry->domain);
224 g_free(entry->interface);
228 g_slist_free(entries);
231 static gboolean resolver_expire_cb(gpointer user_data)
233 struct entry_data *entry = user_data;
236 DBG("interface %s domain %s server %s",
237 entry->interface, entry->domain, entry->server);
239 list = g_slist_append(NULL, entry);
240 remove_entries(list);
245 static int append_resolver(const char *interface, const char *domain,
246 const char *server, unsigned int lifetime,
249 struct entry_data *entry;
251 DBG("interface %s domain %s server %s lifetime %d flags %d",
252 interface, domain, server, lifetime, flags);
254 if (server == NULL && domain == NULL)
257 entry = g_try_new0(struct entry_data, 1);
261 entry->interface = g_strdup(interface);
262 entry->domain = g_strdup(domain);
263 entry->server = g_strdup(server);
264 entry->flags = flags;
266 entry->timeout = g_timeout_add_seconds(lifetime,
267 resolver_expire_cb, entry);
269 entry_list = g_slist_append(entry_list, entry);
271 if (dnsproxy_enabled == TRUE)
272 __connman_dnsproxy_append(interface, domain, server);
274 __connman_resolvfile_append(interface, domain, server);
280 * connman_resolver_append:
281 * @interface: network interface
282 * @domain: domain limitation
283 * @server: server address
285 * Append resolver server address to current list
287 int connman_resolver_append(const char *interface, const char *domain,
290 DBG("interface %s domain %s server %s", interface, domain, server);
292 return append_resolver(interface, domain, server, 0, 0);
296 * connman_resolver_append_lifetime:
297 * @interface: network interface
298 * @domain: domain limitation
299 * @server: server address
300 * @timeout: server lifetime in seconds
302 * Append resolver server address to current list
304 int connman_resolver_append_lifetime(const char *interface, const char *domain,
305 const char *server, unsigned int lifetime)
309 DBG("interface %s domain %s server %s lifetime %d",
310 interface, domain, server, lifetime);
315 for (list = entry_list; list; list = list->next) {
316 struct entry_data *entry = list->data;
318 if (!entry->timeout ||
319 g_strcmp0(entry->interface, interface) ||
320 g_strcmp0(entry->domain, domain) ||
321 g_strcmp0(entry->server, server))
324 g_source_remove(entry->timeout);
325 entry->timeout = g_timeout_add_seconds(lifetime,
326 resolver_expire_cb, entry);
330 return append_resolver(interface, domain, server, lifetime, 0);
334 * connman_resolver_remove:
335 * @interface: network interface
336 * @domain: domain limitation
337 * @server: server address
339 * Remover resolver server address from current list
341 int connman_resolver_remove(const char *interface, const char *domain,
344 GSList *list, *matches = NULL;
346 DBG("interface %s domain %s server %s", interface, domain, server);
351 for (list = entry_list; list; list = list->next) {
352 struct entry_data *entry = list->data;
354 if (interface != NULL &&
355 g_strcmp0(entry->interface, interface) != 0)
358 if (domain != NULL && g_strcmp0(entry->domain, domain) != 0)
361 if (g_strcmp0(entry->server, server) != 0)
364 matches = g_slist_append(matches, entry);
370 remove_entries(matches);
376 * connman_resolver_remove_all:
377 * @interface: network interface
379 * Remove all resolver server address for the specified interface
381 int connman_resolver_remove_all(const char *interface)
383 GSList *list, *matches = NULL;
385 DBG("interface %s", interface);
387 if (interface == NULL)
390 for (list = entry_list; list; list = list->next) {
391 struct entry_data *entry = list->data;
393 if (g_strcmp0(entry->interface, interface) != 0)
396 matches = g_slist_append(matches, entry);
402 remove_entries(matches);
408 * connman_resolver_append_public_server:
409 * @server: server address
411 * Append public resolver server address to current list
413 int connman_resolver_append_public_server(const char *server)
415 DBG("server %s", server);
417 return append_resolver(NULL, NULL, server, 0, RESOLVER_FLAG_PUBLIC);
421 * connman_resolver_remove_public_server:
422 * @server: server address
424 * Remove public resolver server address to current list
426 int connman_resolver_remove_public_server(const char *server)
428 DBG("server %s", server);
430 return connman_resolver_remove(NULL, NULL, server);
434 * connman_resolver_flush:
436 * Flush pending resolver requests
438 void connman_resolver_flush(void)
440 if (dnsproxy_enabled == TRUE)
441 __connman_dnsproxy_flush();
446 int __connman_resolver_init(connman_bool_t dnsproxy)
448 DBG("dnsproxy %d", dnsproxy);
450 if (dnsproxy == FALSE)
453 if (__connman_dnsproxy_init() < 0) {
454 /* Fall back to resolv.conf */
458 dnsproxy_enabled = TRUE;
463 void __connman_resolver_cleanup(void)
467 if (dnsproxy_enabled == TRUE)
468 __connman_dnsproxy_cleanup();