+static bool dnsproxy_enabled = false;
+
+struct resolvfile_entry {
+ int index;
+ char *domain;
+ char *server;
+};
+
+static GList *resolvfile_list = NULL;
+
+static void resolvfile_remove_entries(GList *entries)
+{
+ GList *list;
+
+ for (list = entries; list; list = list->next) {
+ struct resolvfile_entry *entry = list->data;
+
+ resolvfile_list = g_list_remove(resolvfile_list, entry);
+
+ g_free(entry->server);
+ g_free(entry->domain);
+ g_free(entry);
+ }
+
+ g_list_free(entries);
+}
+
+static int resolvfile_export(void)
+{
+ GList *list;
+ GString *content;
+ int fd, err;
+ unsigned int count;
+ mode_t old_umask;
+
+ content = g_string_new("# Generated by Connection Manager\n");
+
+ /*
+ * Domains and nameservers are added in reverse so that the most
+ * recently appended entry is the primary one. No more than
+ * MAXDNSRCH/MAXNS entries are used.
+ */
+
+ for (count = 0, list = g_list_first(resolvfile_list);
+ list && (count < MAXDNSRCH);
+ list = g_list_next(list)) {
+ struct resolvfile_entry *entry = list->data;
+
+ if (!entry->domain)
+ continue;
+
+ if (count == 0)
+ g_string_append_printf(content, "search ");
+
+ g_string_append_printf(content, "%s ", entry->domain);
+ count++;
+ }
+
+ if (count)
+ g_string_append_printf(content, "\n");
+
+ for (count = 0, list = g_list_first(resolvfile_list);
+ list && (count < MAXNS);
+ list = g_list_next(list)) {
+ struct resolvfile_entry *entry = list->data;
+
+ if (!entry->server)
+ continue;
+
+ g_string_append_printf(content, "nameserver %s\n",
+ entry->server);
+ count++;
+ }
+
+ old_umask = umask(022);
+
+ fd = open(RESOLV_CONF_STATEDIR, O_RDWR | O_CREAT | O_CLOEXEC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd < 0) {
+ connman_warn_once("Cannot create "RESOLV_CONF_STATEDIR" "
+ "falling back to "RESOLV_CONF_ETC);
+
+ fd = open(RESOLV_CONF_ETC, O_RDWR | O_CREAT | O_CLOEXEC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ if (fd < 0) {
+ err = -errno;
+ goto done;
+ }
+ }
+
+ if (ftruncate(fd, 0) < 0) {
+ err = -errno;
+ goto failed;
+ }
+
+ err = 0;
+
+ if (write(fd, content->str, content->len) < 0)
+ err = -errno;
+
+failed:
+ close(fd);
+
+done:
+ g_string_free(content, TRUE);
+ umask(old_umask);
+
+ return err;
+}
+
+int __connman_resolvfile_append(int index, const char *domain,
+ const char *server)
+{
+ struct resolvfile_entry *entry;
+
+ DBG("index %d server %s", index, server);
+
+ if (index < 0)
+ return -ENOENT;
+
+ entry = g_try_new0(struct resolvfile_entry, 1);
+ if (!entry)
+ return -ENOMEM;
+
+ entry->index = index;
+ entry->domain = g_strdup(domain);
+ entry->server = g_strdup(server);
+
+ resolvfile_list = g_list_append(resolvfile_list, entry);
+
+ return resolvfile_export();
+}
+
+int __connman_resolvfile_remove(int index, const char *domain,
+ const char *server)
+{
+ GList *list, *matches = NULL;
+
+ DBG("index %d server %s", index, server);
+
+ for (list = resolvfile_list; list; list = g_list_next(list)) {
+ struct resolvfile_entry *entry = list->data;
+
+ if (index >= 0 && entry->index != index)
+ continue;
+
+ if (domain && g_strcmp0(entry->domain, domain) != 0)
+ continue;
+
+ if (g_strcmp0(entry->server, server) != 0)
+ continue;
+
+ matches = g_list_append(matches, entry);
+ }
+
+ resolvfile_remove_entries(matches);
+
+ return resolvfile_export();
+}
+
+void __connman_resolver_append_fallback_nameservers(void)
+{
+ GSList *list;
+
+ for (list = entry_list; list; list = list->next) {
+ struct entry_data *entry = list->data;
+
+ if (entry->index >= 0 && entry->server)
+ return;
+ }
+
+ for (list = entry_list; list; list = list->next) {
+ struct entry_data *entry = list->data;
+
+ if (entry->index != -1 || !entry->server)
+ continue;
+
+ DBG("index %d server %s", entry->index, entry->server);
+
+ if (dnsproxy_enabled) {
+ __connman_dnsproxy_append(entry->index, entry->domain,
+ entry->server);
+ } else {
+ __connman_resolvfile_append(entry->index,
+ entry->domain, entry->server);
+ }
+ }
+}
+
+static void remove_fallback_nameservers(void)
+{
+ GSList *list;
+
+ for (list = entry_list; list; list = list->next) {
+ struct entry_data *entry = list->data;
+
+ if (entry->index >= 0 || !entry->server)
+ continue;
+
+ DBG("index %d server %s", entry->index, entry->server);
+
+ if (dnsproxy_enabled) {
+ __connman_dnsproxy_remove(entry->index, entry->domain,
+ entry->server);
+ } else {
+ __connman_resolvfile_remove(entry->index,
+ entry->domain, entry->server);
+ }
+ }
+}