[PATCH v5 15/42] vpn: Resolve vpn hostname if necessary

Jukka Rissanen jukka.rissanen at linux.intel.com
Mon Nov 12 04:07:31 PST 2012


---
 plugins/vpn.c      | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 vpn/vpn-provider.c |   8 +++-
 2 files changed, 112 insertions(+), 2 deletions(-)

diff --git a/plugins/vpn.c b/plugins/vpn.c
index 9aa8f1d..39c47e7 100644
--- a/plugins/vpn.c
+++ b/plugins/vpn.c
@@ -40,6 +40,7 @@
 #include <connman/ipaddress.h>
 #include <connman/vpn-dbus.h>
 #include <connman/inet.h>
+#include <gweb/gresolv.h>
 
 #define DBUS_TIMEOUT 10000
 
@@ -69,6 +70,7 @@ struct connection_data {
 	char *type;
 	char *name;
 	char *host;
+	char **host_ip;
 	char *domain;
 	char **nameservers;
 
@@ -77,6 +79,9 @@ struct connection_data {
 	GHashTable *setting_strings;
 
 	struct connman_ipaddress *ip;
+
+	GResolv *resolv;
+	guint resolv_id;
 };
 
 static int set_string(struct connman_provider *provider,
@@ -126,7 +131,13 @@ static const char *get_string(struct connman_provider *provider,
 		return data->name;
 	else if (g_str_equal(key, "Host") == TRUE)
 		return data->host;
-	else if (g_str_equal(key, "VPN.Domain") == TRUE)
+	else if (g_str_equal(key, "HostIP") == TRUE) {
+		if (data->host_ip == NULL ||
+				data->host_ip[0] == NULL)
+			return data->host;
+		else
+			return data->host_ip[0];
+	} else if (g_str_equal(key, "VPN.Domain") == TRUE)
 		return data->domain;
 
 	return g_hash_table_lookup(data->setting_strings, key);
@@ -146,6 +157,69 @@ static char *get_ident(const char *path)
 	return pos + 1;
 }
 
+static void cancel_host_resolv(struct connection_data *data)
+{
+	if (data->resolv_id != 0)
+		g_resolv_cancel_lookup(data->resolv, data->resolv_id);
+
+	data->resolv_id = 0;
+
+	g_resolv_unref(data->resolv);
+	data->resolv = NULL;
+}
+
+static gboolean remove_resolv(gpointer user_data)
+{
+	struct connection_data *data = user_data;
+
+	cancel_host_resolv(data);
+
+	return FALSE;
+}
+
+static void resolv_result(GResolvResultStatus status,
+					char **results, gpointer user_data)
+{
+	struct connection_data *data = user_data;
+
+	DBG("status %d", status);
+
+	if (status == G_RESOLV_RESULT_STATUS_SUCCESS && results != NULL &&
+						g_strv_length(results) > 0)
+		data->host_ip = g_strdupv(results);
+
+	/*
+	 * We cannot unref the resolver here as resolv struct is manipulated
+	 * by gresolv.c after we return from this callback.
+	 */
+	g_timeout_add_seconds(0, remove_resolv, data);
+
+	data->resolv_id = 0;
+}
+
+static void resolv_host_addr(struct connection_data *data)
+{
+	if (data->host == NULL)
+		return;
+
+	if (connman_inet_check_ipaddress(data->host) > 0)
+		return;
+
+	if (data->host_ip != NULL)
+		return;
+
+	data->resolv = g_resolv_new(0);
+	if (data->resolv == NULL) {
+		DBG("Cannot resolv %s", data->host);
+		return;
+	}
+
+	DBG("Trying to resolv %s", data->host);
+
+	data->resolv_id = g_resolv_lookup_hostname(data->resolv, data->host,
+						resolv_result, data);
+}
+
 static void set_provider_state(struct connection_data *data)
 {
 	if (g_str_equal(data->state, "ready") == TRUE)
@@ -483,6 +557,8 @@ static void add_connection(const char *path, DBusMessageIter *properties,
 	if (err < 0)
 		goto out;
 
+	resolv_host_addr(data);
+
 	return;
 
 out:
@@ -1102,8 +1178,34 @@ done:
 	return err;
 }
 
+static connman_bool_t check_host(char **hosts, char *host)
+{
+	int i;
+
+	if (hosts == NULL)
+		return FALSE;
+
+	for (i = 0; hosts[i] != NULL; i++) {
+		if (g_strcmp0(hosts[i], host) == 0)
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
 static void set_route(struct connection_data *data, struct vpn_route *route)
 {
+	/*
+	 * If the VPN administrator/user has given a route to
+	 * VPN server, then we must discard that because the
+	 * server cannot be contacted via VPN tunnel.
+	 */
+	if (check_host(data->host_ip, route->network) == TRUE) {
+		DBG("Discarding VPN route to %s via %s at index %d",
+			route->network, route->gateway, data->index);
+		return;
+	}
+
 	if (route->family == AF_INET6) {
 		unsigned char prefix_len = atoi(route->netmask);
 
@@ -1222,6 +1324,8 @@ static void connection_destroy(gpointer hash_data)
 	g_hash_table_destroy(data->setting_strings);
 	connman_ipaddress_free(data->ip);
 
+	cancel_host_resolv(data);
+
 	g_free(data);
 }
 
diff --git a/vpn/vpn-provider.c b/vpn/vpn-provider.c
index eb12f04..5dfd010 100644
--- a/vpn/vpn-provider.c
+++ b/vpn/vpn-provider.c
@@ -1749,7 +1749,13 @@ const char *vpn_provider_get_string(struct vpn_provider *provider,
 		return provider->name;
 	else if (g_str_equal(key, "Host") == TRUE)
 		return provider->host;
-	else if (g_str_equal(key, "VPN.Domain") == TRUE)
+	else if (g_str_equal(key, "HostIP") == TRUE) {
+		if (provider->host_ip == NULL ||
+				provider->host_ip[0] == NULL)
+			return provider->host;
+		else
+			return provider->host_ip[0];
+	} else if (g_str_equal(key, "VPN.Domain") == TRUE)
 		return provider->domain;
 
 	return g_hash_table_lookup(provider->setting_strings, key);
-- 
1.7.11.4




More information about the connman mailing list