diff options
author | Forest Bond <forest@alittletooquiet.net> | 2010-05-06 13:35:33 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2010-05-08 12:53:35 +0200 |
commit | ef5dc3742d7ed33bcd70becb2952918380a3972d (patch) | |
tree | b3864d3124e5ae2f3d46b12e0cf0afdde9823a9d /src/resolver.c | |
parent | d51a6ad75f88cb85647003736bb499ec5aebdcb1 (diff) | |
download | connman-ef5dc3742d7ed33bcd70becb2952918380a3972d.tar.gz connman-ef5dc3742d7ed33bcd70becb2952918380a3972d.tar.bz2 connman-ef5dc3742d7ed33bcd70becb2952918380a3972d.zip |
Add support multiple nameservers in /etc/resolv.conf
Nameservers are appended to a local entry list. The MAXNS most recently
appended nameservers are written to /etc/resolv.conf in reverse order
(the most recently appended entry becomes the primary nameserver).
Diffstat (limited to 'src/resolver.c')
-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 = { |