Commit bfe90123 authored by Jussi Laakkonen's avatar Jussi Laakkonen

Merge branch 'jb45606' into 'master'

Change to use split routing for VPNs instead of default route

See merge request !278
parents 21151e66 7a82e6ff
......@@ -130,7 +130,14 @@ Properties string State [readonly]
configured externally via a configuration file.
The only valid operation are Connect(), Disconnect()
and GetProperties()
and GetProperties()
boolean SplitRouting
This value reflects the split routing setting on
connmand side. By default, this value is omitted and
defaults to false. The value needs to be explicitly
set to true for VPN to be split routed.
int Index [readonly]
......
......@@ -114,6 +114,8 @@ int connman_provider_set_nameservers(struct connman_provider *provider,
bool connman_provider_get_autoconnect(struct connman_provider *provider);
void connman_provider_set_autoconnect(struct connman_provider *provider,
bool flag);
void connman_provider_set_split_routing(struct connman_provider *provider,
bool split_routing);
const char *connman_provider_get_driver_name(struct connman_provider *provider);
const char *connman_provider_get_save_group(struct connman_provider *provider);
......
......@@ -677,6 +677,7 @@ static void add_connection(const char *path, DBusMessageIter *properties,
DBusMessageIter entry, value;
const char *key;
char *str;
dbus_bool_t value_bool;
dbus_message_iter_recurse(properties, &entry);
dbus_message_iter_get_basic(&entry, &key);
......@@ -699,10 +700,12 @@ static void add_connection(const char *path, DBusMessageIter *properties,
dbus_message_iter_get_basic(&value, &str);
data->type = g_strdup(str);
} else if (g_str_equal(key, "Immutable")) {
dbus_bool_t immutable;
dbus_message_iter_get_basic(&value, &immutable);
data->immutable = immutable;
dbus_message_iter_get_basic(&value, &value_bool);
data->immutable = value_bool;
} else if (g_str_equal(key, "SplitRouting")) {
dbus_message_iter_get_basic(&value, &value_bool);
connman_provider_set_split_routing(data->provider,
value_bool);
} else if (g_str_equal(key, "Host")) {
dbus_message_iter_get_basic(&value, &str);
data->host = g_strdup(str);
......@@ -1890,10 +1893,15 @@ static gboolean property_changed(DBusConnection *conn,
g_free(data->domain);
data->domain = g_strdup(str);
connman_provider_set_domain(data->provider, data->domain);
} else if (g_str_equal(key, "SplitRouting")) {
dbus_bool_t split_routing;
dbus_message_iter_get_basic(&value, &split_routing);
connman_provider_set_split_routing(data->provider,
split_routing);
} else if (g_str_equal(key, "DefaultRoute")) {
dbus_message_iter_get_basic(&value, &str);
g_hash_table_replace(data->setting_strings,
g_strdup(key), g_strdup(str));
connman_provider_set_split_routing(data->provider,
!g_strcmp0(str, "false"));
}
if (ip_set && err == 0) {
......
......@@ -143,19 +143,9 @@ static void get_gateway_cb(const char *gateway, int index, void *user_data)
struct gateway_data *data;
struct get_gateway_params *params = user_data;
int family;
struct connman_service *service;
if (index < 0)
goto out;
service = __connman_service_lookup_from_index(params->vpn_index);
if (!__connman_service_is_default_route(service)) {
DBG("Not setting gateway config of non default service %s",
service ? connman_service_get_identifier(service) : "");
goto out;
}
DBG("phy index %d phy gw %s vpn index %d vpn gw %s", index, gateway,
params->vpn_index, params->vpn_gateway);
......@@ -871,13 +861,6 @@ int __connman_connection_gateway_add(struct connman_service *service,
set_vpn_routes(new_gateway, service, gateway, type, peer,
active_gateway);
if (!__connman_service_is_default_route(service)) {
DBG("Not adding gateways for non default VPN %s",
service ? connman_service_get_identifier(service) :
"");
goto done;
}
} else {
if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
new_gateway->ipv4_gateway)
......
......@@ -747,7 +747,6 @@ void __connman_ipv6pd_cleanup(void);
#include <connman/provider.h>
bool __connman_provider_is_default_route(struct connman_provider *provider);
bool __connman_provider_check_routes(struct connman_provider *provider);
int __connman_provider_append_user_route(struct connman_provider *provider,
int family, const char *network, const char *netmask);
......@@ -889,6 +888,8 @@ void __connman_service_set_pac(struct connman_service *service,
bool __connman_service_is_hidden(struct connman_service *service);
bool __connman_service_is_split_routing(struct connman_service *service);
bool __connman_service_index_is_split_routing(int index);
void __connman_service_set_split_routing(struct connman_service *service,
bool split_routing);
int __connman_service_get_index(struct connman_service *service);
GSList *__connman_service_get_depending_vpn_index(
struct connman_service *service);
......@@ -901,7 +902,6 @@ void __connman_service_set_domainname(struct connman_service *service,
const char *__connman_service_get_nameserver(struct connman_service *service);
void __connman_service_set_proxy_autoconfig(struct connman_service *service,
const char *url);
bool __connman_service_is_default_route(struct connman_service *service);
void __connman_service_set_identity(struct connman_service *service,
const char *identity);
......
......@@ -52,7 +52,8 @@ struct connman_provider {
void __connman_provider_append_properties(struct connman_provider *provider,
DBusMessageIter *iter)
{
const char *host, *domain, *type, *defaultroute;
const char *host, *domain, *type;
bool split_routing = false;
if (!provider->driver || !provider->driver->get_property)
return;
......@@ -60,7 +61,10 @@ void __connman_provider_append_properties(struct connman_provider *provider,
host = provider->driver->get_property(provider, "Host");
domain = provider->driver->get_property(provider, "Domain");
type = provider->driver->get_property(provider, "Type");
defaultroute = provider->driver->get_property(provider, "DefaultRoute");
if (provider->vpn_service)
split_routing = __connman_service_is_split_routing(
provider->vpn_service);
if (host)
connman_dbus_dict_append_basic(iter, "Host",
......@@ -74,10 +78,8 @@ void __connman_provider_append_properties(struct connman_provider *provider,
connman_dbus_dict_append_basic(iter, "Type", DBUS_TYPE_STRING,
&type);
if (defaultroute)
connman_dbus_dict_append_basic(iter, "DefaultRoute",
DBUS_TYPE_STRING,
&defaultroute);
connman_dbus_dict_append_basic(iter, "SplitRouting",
DBUS_TYPE_BOOLEAN, &split_routing);
}
struct connman_provider *
......@@ -463,26 +465,6 @@ const char *connman_provider_get_string(struct connman_provider *provider,
return NULL;
}
bool __connman_provider_is_default_route(struct connman_provider *provider)
{
const char* default_route = NULL;
if (!provider)
return true;
default_route = connman_provider_get_string(provider, "DefaultRoute");
DBG("DefaultRoute:%s", default_route);
if (!default_route)
return true;
if (g_ascii_strcasecmp(default_route, "true") != 0)
return false;
return true;
}
bool
__connman_provider_check_routes(struct connman_provider *provider)
{
......@@ -637,6 +619,16 @@ void connman_provider_set_autoconnect(struct connman_provider *provider,
__connman_service_save(provider->vpn_service);
}
void connman_provider_set_split_routing(struct connman_provider *provider,
bool split_routing)
{
if (!provider || !provider->vpn_service)
return;
__connman_service_set_split_routing(provider->vpn_service,
split_routing);
}
static void unregister_provider(gpointer data)
{
struct connman_provider *provider = data;
......
......@@ -784,7 +784,8 @@ static void unset_vpn_dependency(struct connman_service *vpn_service)
vpn_service->depends_on = NULL;
}
static void set_split_routing(struct connman_service *service, bool value)
void __connman_service_set_split_routing(struct connman_service *service,
bool value)
{
if (service->type != CONNMAN_SERVICE_TYPE_VPN)
return;
......@@ -842,9 +843,10 @@ int __connman_service_load_modifiable(struct connman_service *service)
case CONNMAN_SERVICE_TYPE_P2P:
break;
case CONNMAN_SERVICE_TYPE_VPN:
set_split_routing(service, g_key_file_get_boolean(keyfile,
service->identifier,
"SplitRouting", NULL));
__connman_service_set_split_routing(service,
g_key_file_get_boolean(keyfile,
service->identifier,
"SplitRouting", NULL));
/* fall through */
case CONNMAN_SERVICE_TYPE_WIFI:
......@@ -887,9 +889,10 @@ static void service_apply(struct connman_service *service, GKeyFile *keyfile)
case CONNMAN_SERVICE_TYPE_P2P:
break;
case CONNMAN_SERVICE_TYPE_VPN:
set_split_routing(service, g_key_file_get_boolean(keyfile,
service->identifier,
"SplitRouting", NULL));
__connman_service_set_split_routing(service,
g_key_file_get_boolean(keyfile,
service->identifier,
"SplitRouting", NULL));
autoconnect = g_key_file_get_boolean(keyfile,
service->identifier, "AutoConnect", &error);
......@@ -1927,7 +1930,7 @@ bool __connman_service_index_is_default(int index)
return __connman_service_get_index(service) == index;
}
struct connman_service *get_connected_default_route_service()
static struct connman_service *get_connected_default_service()
{
GList *iter;
......@@ -1936,8 +1939,8 @@ struct connman_service *get_connected_default_route_service()
for (iter = service_list; iter; iter = iter->next) {
service = iter->data;
if (__connman_service_is_default_route(service) &&
is_connected(service))
if (!__connman_service_is_split_routing(service) &&
is_connected(service))
return service;
}
......@@ -1980,11 +1983,11 @@ static void default_changed(void)
/* If new service is NULL try to get a connected service. */
if (!service) {
service = get_connected_default_route_service();
DBG("got new connected default route %p", service);
service = get_connected_default_service();
DBG("got new connected default %p", service);
if (service == current_default) {
DBG("new connected default route == current_default");
DBG("new connected default == current_default");
return;
}
}
......@@ -3490,7 +3493,7 @@ int __connman_service_get_index(struct connman_service *service)
}
GSList *__connman_service_get_depending_vpn_index(
struct connman_service *service)
struct connman_service *service)
{
int index = -1;
GSList *index_list = NULL;
......@@ -3506,22 +3509,26 @@ GSList *__connman_service_get_depending_vpn_index(
/*
* Add the index of the VPN to the list of indexes if the VPN
* uses service as transport service and is not being used as
* default route. This way dnsproxy can forward messages to the
* DNS servers reported by a VPN not acting as default route
* for all traffic.
* uses service as transport service and is not being split
* routed. This way dnsproxy can forward messages to the DNS
* servers reported by a split routed VPN for all traffic.
*/
if (vpn->type == CONNMAN_SERVICE_TYPE_VPN &&
vpn->depends_on == service &&
(is_connecting(service) || is_connected(service)) &&
!__connman_service_is_default_route(vpn)) {
index = connman_provider_get_index(vpn->provider);
if (index > 0)
index_list = g_slist_append(index_list,
if (vpn->type != CONNMAN_SERVICE_TYPE_VPN ||
vpn->depends_on != service)
continue;
if (!(is_connecting(service) || is_connected(service)))
continue;
if (!__connman_service_is_split_routing(vpn))
continue;
index = connman_provider_get_index(vpn->provider);
if (index <= 0)
continue;
index_list = g_slist_append(index_list,
GINT_TO_POINTER(index));
}
}
out:
......@@ -3706,14 +3713,6 @@ void __connman_service_set_proxy_autoconfig(struct connman_service *service,
__connman_notifier_proxy_changed(service);
}
bool __connman_service_is_default_route(struct connman_service *service)
{
if (!service)
return true;
return __connman_provider_is_default_route(service->provider);
}
const char *connman_service_get_proxy_autoconfig(struct connman_service *service)
{
if (!service)
......@@ -6029,11 +6028,11 @@ static DBusMessage *move_service(DBusConnection *conn,
return __connman_error_invalid_service(msg);
}
set_split_routing(target, true);
__connman_service_set_split_routing(target, true);
} else
set_split_routing(target, false);
__connman_service_set_split_routing(target, false);
set_split_routing(service, false);
__connman_service_set_split_routing(service, false);
target4 = __connman_ipconfig_get_method(target->ipconfig_ipv4);
target6 = __connman_ipconfig_get_method(target->ipconfig_ipv6);
......@@ -6691,30 +6690,30 @@ static gint service_compare(gconstpointer a, gconstpointer b)
if (a_connected && b_connected) {
int preference;
if (__connman_service_is_default_route(service_a) &&
!__connman_service_is_default_route(service_b))
if (!__connman_service_is_split_routing(service_a) &&
__connman_service_is_split_routing(service_b))
return -1;
if (!__connman_service_is_default_route(service_a) &&
__connman_service_is_default_route(service_b))
if (__connman_service_is_split_routing(service_a) &&
!__connman_service_is_split_routing(service_b))
return 1;
if (service_a->type == CONNMAN_SERVICE_TYPE_VPN &&
service_b->type != CONNMAN_SERVICE_TYPE_VPN &&
service_a->depends_on &&
service_a->depends_on != service_b &&
is_connected(service_a->depends_on)) {
service_b->type != CONNMAN_SERVICE_TYPE_VPN &&
service_a->depends_on &&
service_a->depends_on != service_b &&
is_connected(service_a->depends_on)) {
return service_compare(service_a->depends_on,
service_b);
service_b);
}
if (service_b->type == CONNMAN_SERVICE_TYPE_VPN &&
service_a->type != CONNMAN_SERVICE_TYPE_VPN &&
service_b->depends_on &&
service_b->depends_on != service_a &&
is_connected(service_b->depends_on)) {
service_a->type != CONNMAN_SERVICE_TYPE_VPN &&
service_b->depends_on &&
service_b->depends_on != service_a &&
is_connected(service_b->depends_on)) {
return service_compare(service_a,
service_b->depends_on);
service_b->depends_on);
}
/* Set as -1, 0 or 1, return value if preferred list is used */
......
......@@ -170,9 +170,14 @@ const char *connman_provider_get_string(struct connman_provider *provider,
return NULL;
}
bool __connman_provider_is_default_route(struct connman_provider *provider)
void connman_provider_set_split_routing(struct connman_provider *provider,
bool split_routing)
{
return connman_provider_get_string(provider, NULL) ? false : true;
if (!provider || !provider->vpn_service)
return;
__connman_service_set_split_routing(provider->vpn_service,
split_routing);
}
/* EOD - end of dummies */
......@@ -268,15 +273,17 @@ static void setup_network_or_provider(struct connman_service *service)
if (type != CONNMAN_NETWORK_TYPE_UNKNOWN)
service->network = connman_network_create(ident, type);
if (service->type == CONNMAN_SERVICE_TYPE_VPN)
if (service->type == CONNMAN_SERVICE_TYPE_VPN) {
service->provider = connman_provider_get(ident);
service->provider->vpn_service = service;
}
g_free(ident);
}
static void add_service_type(enum connman_service_type type,
enum connman_service_state state, bool default_route,
uint8_t signal_str)
enum connman_service_state state, bool split_routing,
uint8_t signal_str)
{
char *ident = NULL;
struct connman_service *service = NULL;
......@@ -290,21 +297,19 @@ static void add_service_type(enum connman_service_type type,
setup_network_or_provider(service);
if (type == CONNMAN_SERVICE_TYPE_VPN) {
if (state == CONNMAN_SERVICE_STATE_READY) {
service->depends_on =
get_connected_default_route_service();
}
if (state == CONNMAN_SERVICE_STATE_READY)
service->depends_on = get_connected_default_service();
service->order = 10;
if (!default_route && service->provider) {
connman_provider_set_string(service->provider,
"DefaultRoute", "false");
}
if (service->provider)
connman_provider_set_split_routing(service->provider,
split_routing);
}
service_list = g_list_insert_sorted(service_list, service,
service_compare);
service_compare);
g_free(ident);
}
......@@ -315,27 +320,28 @@ static void add_services()
uint8_t strength = 0;
for (type = 1; type <= CONNMAN_SERVICE_TYPE_P2P; type++) {
for (state = 1; state <= CONNMAN_SERVICE_STATE_FAILURE; state++) {
for (state = 1; state <= CONNMAN_SERVICE_STATE_FAILURE;
state++) {
/*
* Apparently P2P, GPS, SYSTEM nor VPN do not have
* online check. TODO check this.
*/
if ((type == CONNMAN_SERVICE_TYPE_VPN ||
type == CONNMAN_SERVICE_TYPE_P2P ||
type == CONNMAN_SERVICE_TYPE_GPS ||
type == CONNMAN_SERVICE_TYPE_SYSTEM) &&
state == CONNMAN_SERVICE_STATE_ONLINE)
type == CONNMAN_SERVICE_TYPE_P2P ||
type == CONNMAN_SERVICE_TYPE_GPS ||
type == CONNMAN_SERVICE_TYPE_SYSTEM) &&
state == CONNMAN_SERVICE_STATE_ONLINE)
continue;
if (type == CONNMAN_SERVICE_TYPE_WIFI &&
(state == CONNMAN_SERVICE_STATE_READY ||
state == CONNMAN_SERVICE_STATE_ONLINE))
(state == CONNMAN_SERVICE_STATE_READY ||
state == CONNMAN_SERVICE_STATE_ONLINE))
strength = (int)state + 70;
else
strength = 0;
add_service_type(type, state, true, strength);
add_service_type(type, state, false, strength);
}
}
}
......@@ -346,15 +352,13 @@ static void print_test_service(struct connman_service *service, void *user_data)
return;
printf("%p %-56s %-3d %-6s %-10s %-16s %-12s %u\n",
service,
service->identifier,
service->order,
is_connected(service) ? "true" : "false",
is_available(service) ? "available" : "non-avail",
state2string(service->state),
__connman_service_is_default_route(service) ?
"default" : "non-default",
service->strength);
service, service->identifier, service->order,
is_connected(service) ? "true" : "false",
is_available(service) ? "available" : "non-avail",
state2string(service->state),
__connman_service_is_split_routing(service) ?
"split routed" : "default",
service->strength);
}
static void print_services()
......@@ -418,11 +422,11 @@ static void test_service_sort_full_positive()
add_services();
add_service_type(CONNMAN_SERVICE_TYPE_VPN, CONNMAN_SERVICE_STATE_READY,
false, 0);
true, 0);
add_service_type(CONNMAN_SERVICE_TYPE_WIFI,
CONNMAN_SERVICE_STATE_ONLINE, true, 60);
CONNMAN_SERVICE_STATE_ONLINE, false, 60);
add_service_type(CONNMAN_SERVICE_TYPE_WIFI,
CONNMAN_SERVICE_STATE_ONLINE, true, 85);
CONNMAN_SERVICE_STATE_ONLINE, false, 85);
service_list = g_list_sort(service_list, service_compare);
......@@ -445,7 +449,7 @@ static void test_service_sort_full_positive()
a->state == CONNMAN_SERVICE_STATE_READY) {
/* VPN as default should be on top */
if (__connman_service_is_default_route(a))
if (!__connman_service_is_split_routing(a))
g_assert(a == service_list->data);
else
g_assert(a != service_list->data);
......@@ -509,14 +513,14 @@ void test_service_sort_with_preferred_list()
preferred_list = list;
add_service_type(CONNMAN_SERVICE_TYPE_WIFI,
CONNMAN_SERVICE_STATE_ONLINE, true, 85);
CONNMAN_SERVICE_STATE_ONLINE, false, 85);
add_service_type(CONNMAN_SERVICE_TYPE_VPN, CONNMAN_SERVICE_STATE_READY,
false, 0);
true, 0);
add_service_type(CONNMAN_SERVICE_TYPE_WIFI,
CONNMAN_SERVICE_STATE_READY, true, 60);
CONNMAN_SERVICE_STATE_READY, false, 60);
add_service_type(CONNMAN_SERVICE_TYPE_WIFI,
CONNMAN_SERVICE_STATE_IDLE, true, 0);
CONNMAN_SERVICE_STATE_IDLE, false, 0);
service_list = g_list_sort(service_list, service_compare);
......@@ -587,20 +591,70 @@ int rmdir_r(const gchar* path)
} else {
return -1;
}
}
static void cleanup_test_directory(gchar *test_path)
{
gint access_mode = R_OK|W_OK|X_OK;
if (g_file_test(test_path, G_FILE_TEST_IS_DIR)) {
g_assert(!access(test_path, access_mode));
rmdir_r(test_path);
}
}
static gchar *option_debug = NULL;
static bool parse_debug(const char *key, const char *value,
gpointer user_data, GError **error)
{
if (value)
option_debug = g_strdup(value);
else
option_debug = g_strdup("*");
return true;
}
static GOptionEntry options[] = {
{ "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
G_OPTION_ARG_CALLBACK, parse_debug,
"Specify debug options to enable", "DEBUG" },
{ NULL },
};
int main(int argc, char **argv)
{
GOptionContext *context;
GError *error = NULL;
int ret;
char* test_dir = g_dir_make_tmp("test_service_XXXXXX", NULL);
context = g_option_context_new(NULL);
g_option_context_add_main_entries(context, options, NULL);
if (!g_option_context_parse(context, &argc, &argv, &error)) {
if (error) {
g_printerr("%s\n", error->message);
g_error_free(error);
} else {
g_printerr("An unknown error occurred\n");
}
return 1;
}
g_option_context_free(context);
g_test_init(&argc, &argv, NULL);
__connman_log_init("test-service", g_test_verbose() ? "*" : NULL,
FALSE, FALSE, "test-service", CONNMAN_VERSION);
__connman_storage_init(test_dir, 0755, 0644);
mkdir(STORAGEDIR, 0755);
g_assert_cmpint(__connman_storage_create_dir(STORAGEDIR,
__connman_storage_dir_mode()), ==, 0);
g_assert_cmpint(__connman_storage_create_dir(VPN_STORAGEDIR,
__connman_storage_dir_mode()), ==, 0);
g_test_add_func("/service/service_sort_full_positive",
test_service_sort_full_positive);
......@@ -616,7 +670,7 @@ int main(int argc, char **argv)
ret = g_test_run();
__connman_log_cleanup(FALSE);
__connman_storage_cleanup();
rmdir_r(test_dir);
cleanup_test_directory(test_dir);
g_free(test_dir);
return ret;
......
......@@ -574,3 +574,15 @@ char **__vpn_config_get_string_list(GKeyFile *key_file,
return strlist;
}
bool __vpn_config_get_boolean(GKeyFile *key_file, const char *group_name,
const char *key, GError **error, bool default_value)
{
bool val;
val = g_key_file_get_boolean(key_file, group_name, key, error);
if (error)
return default_value;
return val;
}
This diff is collapsed.
......@@ -88,6 +88,8 @@ const char *vpn_provider_get_string(struct vpn_provider *provider,
const char *key);
bool vpn_provider_get_string_immutable(struct vpn_provider *provider,
const char *key);
int vpn_provider_set_boolean(struct vpn_provider *provider, const char *key,
bool value);
bool vpn_provider_get_boolean(struct vpn_provider *provider, const char *key,
bool default_value);
......
......@@ -114,10 +114,12 @@ int __vpn_rtnl_send(const void *buf, size_t len);
int __vpn_config_init(void);
void __vpn_config_cleanup(void);
char *__vpn_config_get_string(GKeyFile *key_file,
const char *group_name, const char *key, GError **error);
char **__vpn_config_get_string_list(GKeyFile *key_file,
const char *group_name, const char *key, gsize *length, GError **error);
char *__vpn_config_get_string(GKeyFile *key_file, const char *group_name,
const char *key, GError **error);
char **__vpn_config_get_string_list(GKeyFile *key_file, const char *group_name,
const char *key, gsize *length, GError **error);
bool __vpn_config_get_boolean(GKeyFile *key_file, const char *group_name,
const char *key, GError **error, bool default_value);
#ifndef VPN_STATEDIR
#define VPN_STATEDIR vpn_settings_get_state_dir()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment