summaryrefslogtreecommitdiff
path: root/plugins/vpn.c
diff options
context:
space:
mode:
authorJukka Rissanen <jukka.rissanen@linux.intel.com>2012-11-12 14:07:31 +0200
committerPatrik Flykt <patrik.flykt@linux.intel.com>2012-11-23 12:58:51 +0200
commitf9603194e91e48ce1badc1378a7b973a7e925013 (patch)
tree538b2e6b452a5258fa0b73d637030438c9c2bf24 /plugins/vpn.c
parent4034f337edbb89f87465a05066cace379f6cc14f (diff)
downloadconnman-f9603194e91e48ce1badc1378a7b973a7e925013.tar.gz
connman-f9603194e91e48ce1badc1378a7b973a7e925013.tar.bz2
connman-f9603194e91e48ce1badc1378a7b973a7e925013.zip
vpn: Resolve vpn hostname if necessary
Diffstat (limited to 'plugins/vpn.c')
-rw-r--r--plugins/vpn.c106
1 files changed, 105 insertions, 1 deletions
diff --git a/plugins/vpn.c b/plugins/vpn.c
index 9aa8f1d7..39c47e74 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);
}