diff options
-rw-r--r-- | src/resolver.c | 111 |
1 files changed, 94 insertions, 17 deletions
diff --git a/src/resolver.c b/src/resolver.c index df0d3c15..4a9db266 100644 --- a/src/resolver.c +++ b/src/resolver.c @@ -29,6 +29,7 @@ #include <unistd.h> #include <string.h> #include <sys/stat.h> +#include <resolv.h> #include "connman.h" @@ -333,17 +334,56 @@ int __connman_resolver_selftest(void) return 0; } -static int resolvfile_append(const char *interface, const char *domain, - const char *server) +struct resolvfile_entry { + char *interface; + char *domain; + char *server; +}; + +static GList *resolvfile_list = NULL; + +static void resolvfile_remove_entries(GList *entries) { - char *cmd; - int fd, len, err; - mode_t old_umask; + GList *list; - DBG("interface %s server %s", interface, server); + for (list = entries; list; list = list->next) { + struct resolvfile_entry *entry = list->data; - if (interface == NULL) - return -ENOENT; + resolvfile_list = g_list_remove( + resolvfile_list, entry); + + g_free(entry->server); + g_free(entry->domain); + g_free(entry->interface); + 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" + "options edns0\n"); + + /* Nameservers are added in reverse so that the most recently appended + * entry is the primary nameserver. No more than MAXNS nameservers are + * used. + */ + for (count = 0, list = g_list_last(resolvfile_list); + list && (count < MAXNS); + list = g_list_previous(list)) { + struct resolvfile_entry *entry = list->data; + g_string_append_printf(content, "nameserver %s\n", + entry->server); + count++; + } old_umask = umask(022); @@ -361,31 +401,68 @@ static int resolvfile_append(const char *interface, const char *domain, err = 0; - cmd = g_strdup_printf("# Generated by Connection Manager\n" - "options edns0\n" - "nameserver %s\n", server); - - len = write(fd, cmd, strlen(cmd)); - if (len < 0) + if (write(fd, content->str, content->len) < 0) err = -errno; - g_free(cmd); - failed: close(fd); done: + g_string_free(content, TRUE); umask(old_umask); return err; } +static int resolvfile_append(const char *interface, const char *domain, + const char *server) +{ + struct resolvfile_entry *entry; + + DBG("interface %s server %s", interface, server); + + if (interface == NULL) + return -ENOENT; + + entry = g_try_new0(struct resolvfile_entry, 1); + if (entry == NULL) + return -ENOMEM; + + entry->interface = g_strdup(interface); + entry->domain = g_strdup(domain); + entry->server = g_strdup(server); + + resolvfile_list = g_list_append(resolvfile_list, entry); + + return resolvfile_export(); +} + static int resolvfile_remove(const char *interface, const char *domain, const char *server) { + GList *list, *matches = NULL; + DBG("interface %s server %s", interface, server); - return 0; + for (list = resolvfile_list; list; list = g_list_next(list)) { + struct resolvfile_entry *entry = list->data; + + if (interface != NULL && + g_strcmp0(entry->interface, interface) != 0) + continue; + + if (domain != NULL && 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(); } static struct connman_resolver resolvfile_resolver = { |