diff options
-rw-r--r-- | vpn/plugins/openvpn.c | 88 |
1 files changed, 71 insertions, 17 deletions
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 <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); |