openvpn: Set the nameservers in correct order
authorJukka Rissanen <jukka.rissanen@linux.intel.com>
Mon, 25 Mar 2013 14:58:57 +0000 (16:58 +0200)
committerPatrik Flykt <patrik.flykt@linux.intel.com>
Wed, 27 Mar 2013 14:00:19 +0000 (16:00 +0200)
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

index 87549ca..d938eb1 100644 (file)
@@ -23,6 +23,7 @@
 #include <config.h>
 #endif
 
+#include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
@@ -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);