From a1ef3bc2f851d56d1899c0eb5676e491b2a98ff5 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 25 Mar 2013 16:58:57 +0200 Subject: openvpn: Set the nameservers in correct order The nameservers that we get from OpenVPN server can be received in any order. Make sure that we sort them in correct order before sending them to connmand. --- vpn/plugins/openvpn.c | 88 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 71 insertions(+), 17 deletions(-) (limited to 'vpn/plugins') diff --git a/vpn/plugins/openvpn.c b/vpn/plugins/openvpn.c index 87549ca0..d938eb14 100644 --- a/vpn/plugins/openvpn.c +++ b/vpn/plugins/openvpn.c @@ -23,6 +23,7 @@ #include #endif +#include #include #include #include @@ -72,13 +73,19 @@ struct { { "OpenVPN.ConfigFile", "--config", 1 }, }; -static void ov_append_dns_entries(const char *key, const char *value, - char **dns_entries) +struct nameserver_entry { + int id; + char *nameserver; +}; + +static struct nameserver_entry *ov_append_dns_entries(const char *key, + const char *value) { + struct nameserver_entry *entry = NULL; gchar **options; if (g_str_has_prefix(key, "foreign_option_") == FALSE) - return; + return NULL; options = g_strsplit(value, " ", 3); if (options[0] != NULL && @@ -87,28 +94,48 @@ static void ov_append_dns_entries(const char *key, const char *value, !strcmp(options[1], "DNS") && options[2] != NULL) { - if (*dns_entries != NULL) { - char *tmp; + entry = g_try_new(struct nameserver_entry, 1); + if (entry == NULL) + return NULL; - tmp = g_strjoin(" ", *dns_entries, - options[2], NULL); - g_free(*dns_entries); - *dns_entries = tmp; - } else { - *dns_entries = g_strdup(options[2]); - } + entry->nameserver = g_strdup(options[2]); + entry->id = atoi(key + 15); /* foreign_option_XXX */ } g_strfreev(options); + + return entry; +} + +static gint cmp_ns(gconstpointer a, gconstpointer b) +{ + struct nameserver_entry *entry_a = (struct nameserver_entry *)a; + struct nameserver_entry *entry_b = (struct nameserver_entry *)b; + + if (entry_a->id < entry_b->id) + return -1; + + if (entry_a->id > entry_b->id) + return 1; + + return 0; +} + +static void free_ns_entry(gpointer data) +{ + struct nameserver_entry *entry = data; + + g_free(entry->nameserver); + g_free(entry); } static int ov_notify(DBusMessage *msg, struct vpn_provider *provider) { DBusMessageIter iter, dict; const char *reason, *key, *value; - char *nameservers = NULL; char *address = NULL, *gateway = NULL, *peer = NULL; struct connman_ipaddress *ipaddress; + GSList *nameserver_list = NULL; dbus_message_iter_init(msg, &iter); @@ -126,6 +153,7 @@ static int ov_notify(DBusMessage *msg, struct vpn_provider *provider) dbus_message_iter_recurse(&iter, &dict); while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + struct nameserver_entry *ns_entry = NULL; DBusMessageIter entry; dbus_message_iter_recurse(&dict, &entry); @@ -153,14 +181,16 @@ static int ov_notify(DBusMessage *msg, struct vpn_provider *provider) if (g_str_has_prefix(key, "route_") == TRUE) vpn_provider_append_route(provider, key, value); - ov_append_dns_entries(key, value, &nameservers); + if ((ns_entry = ov_append_dns_entries(key, value)) != NULL) + nameserver_list = g_slist_prepend(nameserver_list, + ns_entry); dbus_message_iter_next(&dict); } ipaddress = connman_ipaddress_alloc(AF_INET); if (ipaddress == NULL) { - g_free(nameservers); + g_slist_free_full(nameserver_list, free_ns_entry); g_free(address); g_free(gateway); g_free(peer); @@ -172,9 +202,33 @@ static int ov_notify(DBusMessage *msg, struct vpn_provider *provider) connman_ipaddress_set_peer(ipaddress, peer); vpn_provider_set_ipaddress(provider, ipaddress); - vpn_provider_set_nameservers(provider, nameservers); + if (nameserver_list != NULL) { + char *nameservers = NULL; + GSList *tmp; + + nameserver_list = g_slist_sort(nameserver_list, cmp_ns); + for (tmp = nameserver_list; tmp != NULL; + tmp = g_slist_next(tmp)) { + struct nameserver_entry *ns = tmp->data; + + if (nameservers == NULL) { + nameservers = g_strdup(ns->nameserver); + } else { + char *str; + str = g_strjoin(" ", nameservers, + ns->nameserver, NULL); + g_free(nameservers); + nameservers = str; + } + } + + g_slist_free_full(nameserver_list, free_ns_entry); + + vpn_provider_set_nameservers(provider, nameservers); + + g_free(nameservers); + } - g_free(nameservers); g_free(address); g_free(gateway); g_free(peer); -- cgit v1.2.3