From 0e469f4d52fd980dc316b060418105c70d2f1c29 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 27 Jan 2011 00:05:10 +0100 Subject: [PATCH] provider: Factorize VPN routing environment variables parsing --- include/provider.h | 4 +- plugins/openconnect.c | 6 ++ plugins/openvpn.c | 112 +------------------------------- src/provider.c | 172 +++++++++++++++++++++++++++++++++++++------------- 4 files changed, 138 insertions(+), 156 deletions(-) diff --git a/include/provider.h b/include/provider.h index 085bda3..b46033f 100644 --- a/include/provider.h +++ b/include/provider.h @@ -84,9 +84,7 @@ void connman_provider_set_domain(struct connman_provider *provider, const char *domain); int connman_provider_append_route(struct connman_provider *provider, - int family, const char *host, - const char *netmask, - const char *gateway); + const char *key, const char *value); const char *connman_provider_get_driver_name(struct connman_provider *provider); diff --git a/plugins/openconnect.c b/plugins/openconnect.c index 6181046..cc8b51b 100644 --- a/plugins/openconnect.c +++ b/plugins/openconnect.c @@ -27,6 +27,8 @@ #include #include +#include + #define CONNMAN_API_SUBJECT_TO_CHANGE #include #include @@ -87,6 +89,10 @@ static int oc_notify(DBusMessage *msg, struct connman_provider *provider) if (domain == NULL && !strcmp(key, "CISCO_DEF_DOMAIN")) domain = value; + if (g_str_has_prefix(key, "CISCO_SPLIT_INC") == TRUE || + g_str_has_prefix(key, "CISCO_IPV6_SPLIT_INC") == TRUE) + connman_provider_append_route(provider, key, value); + dbus_message_iter_next(&dict); } diff --git a/plugins/openvpn.c b/plugins/openvpn.c index 410cfbd..6083874 100644 --- a/plugins/openvpn.c +++ b/plugins/openvpn.c @@ -42,107 +42,6 @@ static DBusConnection *connection; -struct ov_route { - int family; - 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->family, route->host, - route->netmask, route->gateway); -} - -static struct ov_route *ov_route_lookup(const char *key, const char *prefix_key, - GHashTable *routes) -{ - unsigned long idx; - const char *start; - char *end; - struct ov_route *route; - - if (g_str_has_prefix(key, prefix_key) == FALSE) - return NULL; - - 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; - } - - route->family = AF_INET; - - g_hash_table_replace(routes, GINT_TO_POINTER(idx), - route); - } - - return route; -} - -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 void ov_append_dns_entries(const char *key, const char *value, char **dns_entries) { @@ -179,7 +78,6 @@ static int ov_notify(DBusMessage *msg, struct connman_provider *provider) const char *reason, *key, *value; const char *domain = NULL; char *dns_entries = NULL; - GHashTable *routes; dbus_message_iter_init(msg, &iter); @@ -198,9 +96,6 @@ 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; @@ -220,7 +115,8 @@ static int ov_notify(DBusMessage *msg, struct connman_provider *provider) if (!strcmp(key, "ifconfig_remote")) connman_provider_set_string(provider, "Peer", value); - ov_append_route(key, value, routes); + if (g_str_has_prefix(key, "network_") == TRUE) + connman_provider_append_route(provider, key, value); ov_append_dns_entries(key, value, &dns_entries); @@ -232,10 +128,6 @@ 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; } diff --git a/src/provider.c b/src/provider.c index b7cba23..279cec3 100644 --- a/src/provider.c +++ b/src/provider.c @@ -52,7 +52,7 @@ struct connman_provider { char *host; char *dns; char *domain; - GSList *route_list; + GHashTable *routes; struct connman_provider_driver *driver; void *driver_data; }; @@ -256,6 +256,26 @@ int __connman_provider_remove(const char *path) return -ENXIO; } +static void provider_append_routes(gpointer key, gpointer value, + gpointer user_data) +{ + struct connman_route *route = value; + struct connman_provider *provider = user_data; + int index = provider->element.index; + + if (route->family == AF_INET6) { + unsigned char prefix_len = atoi(route->netmask); + + connman_inet_add_ipv6_network_route(index, route->host, + route->gateway, + prefix_len); + } else { + connman_inet_add_network_route(index, route->host, + route->gateway, + route->netmask); + } +} + static void provider_set_nameservers(struct connman_provider *provider) { struct connman_service *service = provider->vpn_service; @@ -304,7 +324,6 @@ static int set_connected(struct connman_provider *provider, if (connected == TRUE) { enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN; struct connman_element *element; - GSList *list; int err; __connman_service_indicate_state(provider->vpn_service, @@ -336,24 +355,8 @@ static int set_connected(struct connman_provider *provider, provider_set_nameservers(provider); - for (list = provider->route_list; list; list = list->next) { - struct connman_route *route = list->data; - int index = provider->element.index; - - if (route->family == AF_INET6) { - unsigned char prefix_len = atoi(route->netmask); - - connman_inet_add_ipv6_network_route(index, - route->host, - route->gateway, - prefix_len); - } else { - connman_inet_add_network_route(index, - route->host, - route->gateway, - route->netmask); - } - } + g_hash_table_foreach(provider->routes, provider_append_routes, + provider); } else { connman_element_unregister_children(&provider->element); __connman_service_indicate_state(service, @@ -407,7 +410,6 @@ static void unregister_provider(gpointer data) static void provider_destruct(struct connman_element *element) { struct connman_provider *provider = element->private; - GSList *list; DBG("provider %p", provider); @@ -416,15 +418,17 @@ static void provider_destruct(struct connman_element *element) g_free(provider->domain); g_free(provider->identifier); g_free(provider->dns); + g_hash_table_destroy(provider->routes); +} - for (list = provider->route_list; list; list = list->next) { - struct connman_route *route = list->data; +static void destroy_route(gpointer user_data) +{ + struct connman_route *route = user_data; - g_free(route->host); - g_free(route->netmask); - g_free(route->gateway); - } - g_slist_free(provider->route_list); + g_free(route->host); + g_free(route->netmask); + g_free(route->gateway); + g_free(route); } static void provider_initialize(struct connman_provider *provider) @@ -447,7 +451,8 @@ static void provider_initialize(struct connman_provider *provider) provider->dns = NULL; provider->domain = NULL; provider->identifier = NULL; - provider->route_list = NULL; + provider->routes = g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, destroy_route); } static struct connman_provider *connman_provider_new(void) @@ -762,28 +767,109 @@ int connman_provider_get_index(struct connman_provider *provider) return provider->element.index; } +enum provider_route_type { + PROVIDER_ROUTE_TYPE_NONE = 0, + PROVIDER_ROUTE_TYPE_MASK = 1, + PROVIDER_ROUTE_TYPE_ADDR = 2, + PROVIDER_ROUTE_TYPE_GW = 3, +}; + +static int route_env_parse(struct connman_provider *provider, const char *key, + int *family, unsigned long *idx, + enum provider_route_type *type) +{ + char *end; + const char *start; + + DBG("name %s", provider->name); + + if (!strcmp(provider->name, "openvpn")) { + if (g_str_has_prefix(key, "route_network_") == TRUE) { + start = key + strlen("route_network_"); + *type = PROVIDER_ROUTE_TYPE_ADDR; + } else if (g_str_has_prefix(key, "route_netmask_") == TRUE) { + start = key + strlen("route_netmask_"); + *type = PROVIDER_ROUTE_TYPE_MASK; + } else if (g_str_has_prefix(key, "route_gateway_") == TRUE) { + start = key + strlen("route_gateway_"); + *type = PROVIDER_ROUTE_TYPE_GW; + } else + return -EINVAL; + + *family = AF_INET; + *idx = g_ascii_strtoull(start, &end, 10); + + } else if (!strcmp(provider->name, "openconnect")) { + if (g_str_has_prefix(key, "CISCO_SPLIT_INC_") == TRUE) { + *family = AF_INET; + start = key + strlen("CISCO_SPLIT_INC_"); + } else if (g_str_has_prefix(key, "CISCO_IPV6_SPLIT_INC_") == TRUE) { + *family = AF_INET6; + start = key + strlen("CISCO_IPV6_SPLIT_INC_"); + } else + return -EINVAL; + + *idx = g_ascii_strtoull(start, &end, 10); + + if (strncmp(end, "_ADDR", 5) == 0) + *type = PROVIDER_ROUTE_TYPE_ADDR; + else if (strncmp(end, "_MASK", 5) == 0) + *type = PROVIDER_ROUTE_TYPE_MASK; + else if (strncmp(end, "_MASKLEN", 8) == 0 && + *family == AF_INET6) { + *type = PROVIDER_ROUTE_TYPE_MASK; + } else + return -EINVAL; + } + + return 0; +} + int connman_provider_append_route(struct connman_provider *provider, - int family, const char *host, - const char *netmask, - const char *gateway) + const char *key, const char *value) { struct connman_route *route; + int ret, family = 0; + unsigned long idx = 0; + enum provider_route_type type = PROVIDER_ROUTE_TYPE_NONE; - if (family != AF_INET && family != AF_INET6) - return -EINVAL; + DBG("key %s value %s", key, value); - route = g_try_new0(struct connman_route, 1); - if (route == NULL) - return -ENOMEM; + ret = route_env_parse(provider, key, &family, &idx, &type); + if (ret < 0) + return ret; - route->family = family; - route->host = g_strdup(host); - route->netmask = g_strdup(netmask); - route->gateway = g_strdup(gateway); + DBG("idx %lu family %d type %d", idx, family, type); - provider->route_list = g_slist_append(provider->route_list, route); + route = g_hash_table_lookup(provider->routes, GINT_TO_POINTER(idx)); + if (route == NULL) { + route = g_try_new0(struct connman_route, 1); + if (route == NULL) { + connman_error("out of memory"); + return -ENOMEM; + } + + route->family = family; + + g_hash_table_replace(provider->routes, GINT_TO_POINTER(idx), + route); + } + + switch (type) { + case PROVIDER_ROUTE_TYPE_NONE: + break; + case PROVIDER_ROUTE_TYPE_MASK: + route->netmask = g_strdup(value); + break; + case PROVIDER_ROUTE_TYPE_ADDR: + route->host = g_strdup(value); + break; + case PROVIDER_ROUTE_TYPE_GW: + route->gateway = g_strdup(value); + break; + } - return TRUE; + return 0; } const char *connman_provider_get_driver_name(struct connman_provider *provider) -- 2.7.4