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 #if defined TIZEN_EXT
127 * Description: /etc path is read-only in SLP
128 * /opt/etc/resolv.conf rather than /etc/resolv.conf
130 fd = open("/opt/etc/resolv.conf", O_RDWR | O_CREAT | O_CLOEXEC,
131 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
133 fd = open("/etc/resolv.conf", O_RDWR | O_CREAT | O_CLOEXEC,
134 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
141 if (ftruncate(fd, 0) < 0) {
148 if (write(fd, content->str, content->len) < 0)
155 g_string_free(content, TRUE);
161 int __connman_resolvfile_append(const char *interface, const char *domain,
164 struct resolvfile_entry *entry;
166 DBG("interface %s server %s", interface, server);
168 if (interface == NULL)
171 entry = g_try_new0(struct resolvfile_entry, 1);
175 entry->interface = g_strdup(interface);
176 entry->domain = g_strdup(domain);
177 entry->server = g_strdup(server);
179 resolvfile_list = g_list_append(resolvfile_list, entry);
181 return resolvfile_export();
184 int __connman_resolvfile_remove(const char *interface, const char *domain,
187 GList *list, *matches = NULL;
189 DBG("interface %s server %s", interface, server);
191 for (list = resolvfile_list; list; list = g_list_next(list)) {
192 struct resolvfile_entry *entry = list->data;
194 if (interface != NULL &&
195 g_strcmp0(entry->interface, interface) != 0)
198 if (domain != NULL && g_strcmp0(entry->domain, domain) != 0)
201 if (g_strcmp0(entry->server, server) != 0)
204 matches = g_list_append(matches, entry);
207 resolvfile_remove_entries(matches);
209 return resolvfile_export();
212 static void remove_entries(GSList *entries)
216 for (list = entries; list; list = list->next) {
217 struct entry_data *entry = list->data;
219 entry_list = g_slist_remove(entry_list, entry);
221 if (dnsproxy_enabled == TRUE) {
222 __connman_dnsproxy_remove(entry->interface, entry->domain,
225 __connman_resolvfile_remove(entry->interface, entry->domain,
230 g_source_remove(entry->timeout);
231 g_free(entry->server);
232 g_free(entry->domain);
233 g_free(entry->interface);
237 g_slist_free(entries);
240 static gboolean resolver_expire_cb(gpointer user_data)
242 struct entry_data *entry = user_data;
246 DBG("interface %s domain %s server %s",
247 entry->interface, entry->domain, entry->server);
249 list = g_slist_append(NULL, entry);
251 index = connman_inet_ifindex(entry->interface);
253 struct connman_service *service;
254 service = __connman_service_lookup_from_index(index);
256 __connman_service_nameserver_remove(service,
257 entry->server, TRUE);
260 remove_entries(list);
265 static int append_resolver(const char *interface, const char *domain,
266 const char *server, unsigned int lifetime,
269 struct entry_data *entry;
271 DBG("interface %s domain %s server %s lifetime %d flags %d",
272 interface, domain, server, lifetime, flags);
274 if (server == NULL && domain == NULL)
277 entry = g_try_new0(struct entry_data, 1);
281 entry->interface = g_strdup(interface);
282 entry->domain = g_strdup(domain);
283 entry->server = g_strdup(server);
284 entry->flags = flags;
287 entry->timeout = g_timeout_add_seconds(lifetime,
288 resolver_expire_cb, entry);
291 * We update the service only for those nameservers
292 * that are automagically added via netlink (lifetime > 0)
294 index = connman_inet_ifindex(interface);
296 struct connman_service *service;
297 service = __connman_service_lookup_from_index(index);
299 __connman_service_nameserver_append(service,
303 entry_list = g_slist_append(entry_list, entry);
305 if (dnsproxy_enabled == TRUE)
306 __connman_dnsproxy_append(interface, domain, server);
308 __connman_resolvfile_append(interface, domain, server);
314 * connman_resolver_append:
315 * @interface: network interface
316 * @domain: domain limitation
317 * @server: server address
319 * Append resolver server address to current list
321 int connman_resolver_append(const char *interface, const char *domain,
324 GSList *list, *matches = NULL;
326 DBG("interface %s domain %s server %s", interface, domain, server);
328 if (server == NULL && domain == NULL)
331 for (list = entry_list; list; list = list->next) {
332 struct entry_data *entry = list->data;
334 if (entry->timeout > 0 ||
335 g_strcmp0(entry->interface, interface) != 0 ||
336 g_strcmp0(entry->domain, domain) != 0 ||
337 g_strcmp0(entry->server, server) != 0)
340 matches = g_slist_append(matches, entry);
344 remove_entries(matches);
346 return append_resolver(interface, domain, server, 0, 0);
350 * connman_resolver_append_lifetime:
351 * @interface: network interface
352 * @domain: domain limitation
353 * @server: server address
354 * @timeout: server lifetime in seconds
356 * Append resolver server address to current list
358 int connman_resolver_append_lifetime(const char *interface, const char *domain,
359 const char *server, unsigned int lifetime)
363 DBG("interface %s domain %s server %s lifetime %d",
364 interface, domain, server, lifetime);
369 for (list = entry_list; list; list = list->next) {
370 struct entry_data *entry = list->data;
372 if (!entry->timeout ||
373 g_strcmp0(entry->interface, interface) ||
374 g_strcmp0(entry->domain, domain) ||
375 g_strcmp0(entry->server, server))
378 g_source_remove(entry->timeout);
381 resolver_expire_cb(entry);
385 entry->timeout = g_timeout_add_seconds(lifetime,
386 resolver_expire_cb, entry);
390 return append_resolver(interface, domain, server, lifetime, 0);
394 * connman_resolver_remove:
395 * @interface: network interface
396 * @domain: domain limitation
397 * @server: server address
399 * Remover resolver server address from current list
401 int connman_resolver_remove(const char *interface, const char *domain,
404 GSList *list, *matches = NULL;
406 DBG("interface %s domain %s server %s", interface, domain, server);
411 for (list = entry_list; list; list = list->next) {
412 struct entry_data *entry = list->data;
414 if (interface != NULL &&
415 g_strcmp0(entry->interface, interface) != 0)
418 if (domain != NULL && g_strcmp0(entry->domain, domain) != 0)
421 if (g_strcmp0(entry->server, server) != 0)
424 matches = g_slist_append(matches, entry);
430 remove_entries(matches);
436 * connman_resolver_remove_all:
437 * @interface: network interface
439 * Remove all resolver server address for the specified interface
441 int connman_resolver_remove_all(const char *interface)
443 GSList *list, *matches = NULL;
445 DBG("interface %s", interface);
447 if (interface == NULL)
450 for (list = entry_list; list; list = list->next) {
451 struct entry_data *entry = list->data;
453 if (g_strcmp0(entry->interface, interface) != 0)
456 matches = g_slist_append(matches, entry);
462 remove_entries(matches);
468 * connman_resolver_append_public_server:
469 * @server: server address
471 * Append public resolver server address to current list
473 int connman_resolver_append_public_server(const char *server)
475 DBG("server %s", server);
477 return append_resolver(NULL, NULL, server, 0, RESOLVER_FLAG_PUBLIC);
481 * connman_resolver_remove_public_server:
482 * @server: server address
484 * Remove public resolver server address to current list
486 int connman_resolver_remove_public_server(const char *server)
488 DBG("server %s", server);
490 return connman_resolver_remove(NULL, NULL, server);
494 * connman_resolver_flush:
496 * Flush pending resolver requests
498 void connman_resolver_flush(void)
500 if (dnsproxy_enabled == TRUE)
501 __connman_dnsproxy_flush();
506 int __connman_resolver_init(connman_bool_t dnsproxy)
508 DBG("dnsproxy %d", dnsproxy);
510 if (dnsproxy == FALSE)
513 if (__connman_dnsproxy_init() < 0) {
514 /* Fall back to resolv.conf */
518 dnsproxy_enabled = TRUE;
523 void __connman_resolver_cleanup(void)
527 if (dnsproxy_enabled == TRUE)
528 __connman_dnsproxy_cleanup();