openvpn: Append routes
authorDaniel Wagner <daniel.wagner@bmw-carit.de>
Fri, 17 Dec 2010 14:52:03 +0000 (15:52 +0100)
committerSamuel Ortiz <sameo@linux.intel.com>
Tue, 21 Dec 2010 00:34:50 +0000 (01:34 +0100)
plugins/openvpn.c

index 15169bd..7cea4e6 100644 (file)
 
 static DBusConnection *connection;
 
+struct ov_route {
+       char *host;
+       char *netmask;
+       char *gateway;
+};
+
+static void destroy_route(gpointer user_data)
+{
+       struct ov_route *route = user_data;
+
+       g_free(route->host);
+       g_free(route->netmask);
+       g_free(route->gateway);
+       g_free(route);
+}
+
+static void ov_provider_append_routes(gpointer key, gpointer value,
+                                       gpointer user_data)
+{
+       struct ov_route *route = value;
+       struct connman_provider *provider = user_data;
+
+       connman_provider_append_route(provider, route->host, route->netmask,
+                                       route->gateway);
+}
+
+static struct ov_route *ov_route_lookup(const char *key, const char *prefix_key,
+                                       GHashTable *routes)
+{
+       if (g_str_has_prefix(key, prefix_key)) {
+               unsigned long idx;
+               const char *start;
+               char *end;
+               struct ov_route *route;
+
+               start = key + strlen(prefix_key);
+               idx = g_ascii_strtoull(start, &end, 10);
+
+               if (idx == 0 && start == end) {
+                       connman_error("string conversion failed %s", start);
+                       return NULL;
+               }
+
+               route = g_hash_table_lookup(routes, GINT_TO_POINTER(idx));
+               if (route == NULL) {
+                       route = g_try_new0(struct ov_route, 1);
+                       if (route == NULL) {
+                               connman_error("out of memory");
+                               return NULL;
+                       }
+
+                       g_hash_table_replace(routes, GINT_TO_POINTER(idx),
+                                               route);
+               }
+
+               return  route;
+       }
+
+       return NULL;
+}
+
+static void ov_append_route(const char *key, const char *value, GHashTable *routes)
+{
+       struct ov_route *route;
+
+       /*
+        * OpenVPN pushes routing tupples (host, nw, gw) as several
+        * environment values, e.g.
+        *
+        * route_gateway_2 = 10.242.2.13
+        * route_netmask_2 = 255.255.0.0
+        * route_network_2 = 192.168.0.0
+        * route_gateway_1 = 10.242.2.13
+        * route_netmask_1 = 255.255.255.255
+        * route_network_1 = 10.242.2.1
+        *
+        * The hash table is used to group the separate environment
+        * variables together. It also makes sure all tupples are
+        * complete even when OpenVPN pushes the information in a
+        * wrong order (unlikely).
+        */
+
+       route = ov_route_lookup(key, "route_network_", routes);
+       if (route != NULL) {
+               route->host = g_strdup(value);
+               return;
+       }
+
+       route = ov_route_lookup(key, "route_netmask_", routes);
+       if (route != NULL) {
+               route->netmask = g_strdup(value);
+               return;
+       }
+
+       route = ov_route_lookup(key, "route_gateway_", routes);
+       if (route != NULL)
+               route->gateway = g_strdup(value);
+}
+
 static int ov_notify(DBusMessage *msg, struct connman_provider *provider)
 {
        DBusMessageIter iter, dict;
        const char *reason, *key, *value;
        const char *domain = NULL;
        char *dns_entries = NULL;
+       GHashTable *routes;
 
        dbus_message_iter_init(msg, &iter);
 
@@ -71,6 +171,9 @@ static int ov_notify(DBusMessage *msg, struct connman_provider *provider)
 
        dbus_message_iter_recurse(&iter, &dict);
 
+       routes = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                                       NULL, destroy_route);
+
        while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
                DBusMessageIter entry;
 
@@ -115,6 +218,8 @@ static int ov_notify(DBusMessage *msg, struct connman_provider *provider)
                        g_strfreev(options);
                }
 
+               ov_append_route(key, value, routes);
+
                dbus_message_iter_next(&dict);
        }
 
@@ -123,6 +228,10 @@ static int ov_notify(DBusMessage *msg, struct connman_provider *provider)
                g_free(dns_entries);
        }
 
+       g_hash_table_foreach(routes, ov_provider_append_routes, provider);
+
+       g_hash_table_destroy(routes);
+
        return VPN_STATE_CONNECT;
 }