provider: Discard routes to VPN server via VPN tunnel
authorJukka Rissanen <jukka.rissanen@linux.intel.com>
Wed, 8 Aug 2012 10:22:48 +0000 (13:22 +0300)
committerPatrik Flykt <patrik.flykt@linux.intel.com>
Thu, 9 Aug 2012 09:16:56 +0000 (12:16 +0300)
These obsolete routes must be discarded as we cannot
contact VPN server via VPN tunnel. If the VPN server
address is not yet resolved, we do that while starting
the VPN client process.

Example of non working routes:
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         0.0.0.0         0.0.0.0         UG    0      0        0 vpn0
10.10.15.0      0.0.0.0         255.255.255.0   U     0      0        0 wlan0
10.10.15.1      0.0.0.0         255.255.255.255 UH    0      0        0 wlan0
10.252.112.0    0.0.0.0         255.255.240.0   U     0      0        0 vpn0
193.229.0.40    10.10.15.1      255.255.255.255 UGH   0      0        0 wlan0
193.229.0.42    10.10.15.1      255.255.255.255 UGH   0      0        0 wlan0
113.108.211.91  0.0.0.0         255.255.255.255 UH    0      0        0 vpn0
113.108.211.91  10.10.15.1      255.255.255.255 UGH   0      0        0 wlan0

The correct routes should be like this:
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         0.0.0.0         0.0.0.0         U     0      0        0 vpn0
10.10.15.0      0.0.0.0         255.255.255.0   U     0      0        0 wlan0
10.10.15.1      0.0.0.0         255.255.255.255 UH    0      0        0 wlan0
10.252.112.0    0.0.0.0         255.255.240.0   U     0      0        0 vpn0
193.229.0.40    10.10.15.1      255.255.255.255 UGH   0      0        0 wlan0
193.229.0.42    10.10.15.1      255.255.255.255 UGH   0      0        0 wlan0
113.108.211.91  10.10.15.1      255.255.255.255 UGH   0      0        0 wlan0

src/provider.c

index ebc7055..76e8478 100644 (file)
@@ -28,6 +28,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <gdbus.h>
+#include <gweb/gresolv.h>
 
 #include "connman.h"
 
@@ -61,8 +62,55 @@ struct connman_provider {
        GHashTable *user_routes;
        gchar **user_networks;
        gsize num_user_networks;
+       GResolv *resolv;
+       char **host_ip;
 };
 
+static void resolv_result(GResolvResultStatus status,
+                                       char **results, gpointer user_data)
+{
+       struct connman_provider *provider = user_data;
+
+       DBG("status %d", status);
+
+       if (status == G_RESOLV_RESULT_STATUS_SUCCESS && results != NULL &&
+                                               g_strv_length(results) > 0)
+               provider->host_ip = g_strdupv(results);
+
+       connman_provider_unref(provider);
+}
+
+static void provider_resolv_host_addr(struct connman_provider *provider)
+{
+       if (provider->host == NULL)
+               return;
+
+       if (connman_inet_check_ipaddress(provider->host) > 0)
+               return;
+
+       if (provider->host_ip != NULL)
+               return;
+
+       /*
+        * If the hostname is not numeric, try to resolv it. We do not wait
+        * the result as it might take some time. We will get the result
+        * before VPN will feed routes to us because VPN client will need
+        * the IP address also before VPN connection can be established.
+        */
+       provider->resolv = g_resolv_new(0);
+       if (provider->resolv == NULL) {
+               DBG("Cannot resolv %s", provider->host);
+               return;
+       }
+
+       DBG("Trying to resolv %s", provider->host);
+
+       connman_provider_ref(provider);
+
+       g_resolv_lookup_hostname(provider->resolv, provider->host,
+                               resolv_result, provider);
+}
+
 void __connman_provider_append_properties(struct connman_provider *provider,
                                                        DBusMessageIter *iter)
 {
@@ -350,6 +398,11 @@ static void provider_destruct(struct connman_provider *provider)
        g_hash_table_destroy(provider->routes);
        g_hash_table_destroy(provider->user_routes);
        g_hash_table_destroy(provider->setting_strings);
+       if (provider->resolv != NULL) {
+               g_resolv_unref(provider->resolv);
+               provider->resolv = NULL;
+       }
+       g_strfreev(provider->host_ip);
        g_free(provider);
 }
 
@@ -410,9 +463,10 @@ int __connman_provider_connect(struct connman_provider *provider)
 
        DBG("provider %p", provider);
 
-       if (provider->driver != NULL && provider->driver->connect != NULL)
+       if (provider->driver != NULL && provider->driver->connect != NULL) {
+               provider_resolv_host_addr(provider);
                err = provider->driver->connect(provider);
-       else
+       else
                return -EOPNOTSUPP;
 
        if (err < 0) {
@@ -459,6 +513,21 @@ int __connman_provider_remove(const char *path)
        return -ENXIO;
 }
 
+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 provider_append_routes(gpointer key, gpointer value,
                                        gpointer user_data)
 {
@@ -466,6 +535,17 @@ static void provider_append_routes(gpointer key, gpointer value,
        struct connman_provider *provider = user_data;
        int index = provider->index;
 
+       /*
+        * 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(provider->host_ip, route->host) == TRUE) {
+               DBG("Discarding VPN route to %s via %s at index %d",
+                       route->host, route->gateway, index);
+               return;
+       }
+
        if (route->family == AF_INET6) {
                unsigned char prefix_len = atoi(route->netmask);
 
@@ -881,6 +961,8 @@ int __connman_provider_create_and_connect(DBusMessage *msg)
 
                if (provider_register(provider) == 0)
                        connman_provider_load(provider);
+
+               provider_resolv_host_addr(provider);
        }
 
        if (networks != NULL) {