diff --git a/src/frontends/android/jni/Android.mk b/src/frontends/android/jni/Android.mk index 670e83de1..1fb233b48 100644 --- a/src/frontends/android/jni/Android.mk +++ b/src/frontends/android/jni/Android.mk @@ -6,7 +6,7 @@ include $(CLEAR_VARS) strongswan_USE_BYOD := true strongswan_CHARON_PLUGINS := android-log openssl fips-prf random nonce pubkey \ - pkcs1 pkcs8 pem xcbc hmac socket-default kernel-netlink \ + pkcs1 pkcs8 pem xcbc hmac socket-default \ eap-identity eap-mschapv2 eap-md5 eap-gtc eap-tls ifneq ($(strongswan_USE_BYOD),) diff --git a/src/frontends/android/jni/libandroidbridge/charonservice.c b/src/frontends/android/jni/libandroidbridge/charonservice.c index f94da0515..2655f7361 100644 --- a/src/frontends/android/jni/libandroidbridge/charonservice.c +++ b/src/frontends/android/jni/libandroidbridge/charonservice.c @@ -82,11 +82,6 @@ struct private_charonservice_t { */ network_manager_t *network_manager; - /** - * Handle network events - */ - android_net_t *net_handler; - /** * CharonVpnService reference */ @@ -431,14 +426,12 @@ static bool charonservice_register(plugin_t *plugin, plugin_feature_t *feature, private_charonservice_t *this = (private_charonservice_t*)charonservice; if (reg) { - this->net_handler = android_net_create(); lib->credmgr->add_set(lib->credmgr, &this->creds->set); charon->attributes->add_handler(charon->attributes, &this->attr->handler); } else { - this->net_handler->destroy(this->net_handler); lib->credmgr->remove_set(lib->credmgr, &this->creds->set); charon->attributes->remove_handler(charon->attributes, &this->attr->handler); @@ -491,19 +484,6 @@ static void set_options(char *logfile) * so lets disable IPv6 for now to avoid issues with dual-stack gateways */ lib->settings->set_bool(lib->settings, "charon.plugins.socket-default.use_ipv6", FALSE); - /* don't install virtual IPs via kernel-netlink */ - lib->settings->set_bool(lib->settings, - "charon.install_virtual_ip", FALSE); - /* kernel-netlink should not trigger roam events, we use Android's - * ConnectivityManager for that, much less noise */ - lib->settings->set_bool(lib->settings, - "charon.plugins.kernel-netlink.roam_events", FALSE); - /* ignore tun devices (it's mostly tun0 but it may already be taken, ignore - * some others too), also ignore lo as a default route points to it when - * no connectivity is available */ - lib->settings->set_str(lib->settings, - "charon.interfaces_ignore", "lo, tun0, tun1, tun2, tun3, " - "tun4"); #ifdef USE_BYOD lib->settings->set_str(lib->settings, @@ -527,6 +507,8 @@ static void charonservice_init(JNIEnv *env, jobject service, jobject builder, static plugin_feature_t features[] = { PLUGIN_CALLBACK(kernel_ipsec_register, kernel_android_ipsec_create), PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"), + PLUGIN_CALLBACK(kernel_net_register, kernel_android_net_create), + PLUGIN_PROVIDE(CUSTOM, "kernel-net"), PLUGIN_CALLBACK(charonservice_register, NULL), PLUGIN_PROVIDE(CUSTOM, "android-backend"), PLUGIN_DEPENDS(CUSTOM, "libcharon"), diff --git a/src/frontends/android/jni/libandroidbridge/kernel/android_net.c b/src/frontends/android/jni/libandroidbridge/kernel/android_net.c index 653e2738b..9cab74e13 100644 --- a/src/frontends/android/jni/libandroidbridge/kernel/android_net.c +++ b/src/frontends/android/jni/libandroidbridge/kernel/android_net.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2013 Tobias Brunner + * Copyright (C) 2012-2015 Tobias Brunner * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -11,6 +11,10 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ +#include +#include +#include +#include #include "android_net.h" @@ -29,7 +33,7 @@ struct private_android_net_t { /** * Public kernel interface */ - android_net_t public; + kernel_net_t public; /** * Reference to NetworkManager object @@ -37,14 +41,24 @@ struct private_android_net_t { network_manager_t *network_manager; /** - * earliest time of the next roam event + * Earliest time of the next roam event */ timeval_t next_roam; /** - * mutex to check and update roam event time + * Mutex to check and update roam event time, and other private members */ mutex_t *mutex; + + /** + * List of virtual IPs + */ + linked_list_t *vips; + + /** + * Socket used to determine source address + */ + int socket_v4; }; /** @@ -83,32 +97,151 @@ static void connectivity_cb(private_android_net_t *this, lib->scheduler->schedule_job_ms(lib->scheduler, job, ROAM_DELAY); } -METHOD(android_net_t, destroy, void, +METHOD(kernel_net_t, get_source_addr, host_t*, + private_android_net_t *this, host_t *dest, host_t *src) +{ + union { + struct sockaddr sockaddr; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } addr; + socklen_t addrlen; + + addrlen = *dest->get_sockaddr_len(dest); + addr.sockaddr.sa_family = AF_UNSPEC; + if (connect(this->socket_v4, &addr.sockaddr, addrlen) < 0) + { + DBG1(DBG_KNL, "failed to disconnect socket: %s", strerror(errno)); + return NULL; + } + if (connect(this->socket_v4, dest->get_sockaddr(dest), addrlen) < 0) + { + /* don't report an error if we are not connected (ENETUNREACH) */ + if (errno != ENETUNREACH) + { + DBG1(DBG_KNL, "failed to connect socket: %s", strerror(errno)); + } + return NULL; + } + if (getsockname(this->socket_v4, &addr.sockaddr, &addrlen) < 0) + { + DBG1(DBG_KNL, "failed to determine src address: %s", strerror(errno)); + return NULL; + } + return host_create_from_sockaddr((sockaddr_t*)&addr); +} + +METHOD(kernel_net_t, get_nexthop, host_t*, + private_android_net_t *this, host_t *dest, int prefix, host_t *src) +{ + return NULL; +} + +METHOD(kernel_net_t, get_interface, bool, + private_android_net_t *this, host_t *host, char **name) +{ + if (name) + { /* the actual name does not matter in our case */ + *name = strdup("strongswan"); + } + return TRUE; +} + +METHOD(kernel_net_t, create_address_enumerator, enumerator_t*, + private_android_net_t *this, kernel_address_type_t which) +{ + /* return virtual IPs if requested, nothing otherwise */ + if (which & ADDR_TYPE_VIRTUAL) + { + this->mutex->lock(this->mutex); + return enumerator_create_cleaner( + this->vips->create_enumerator(this->vips), + (void*)this->mutex->unlock, this->mutex); + } + return enumerator_create_empty(); +} + +METHOD(kernel_net_t, add_ip, status_t, + private_android_net_t *this, host_t *virtual_ip, int prefix, char *iface) +{ + this->mutex->lock(this->mutex); + this->vips->insert_last(this->vips, virtual_ip->clone(virtual_ip)); + this->mutex->unlock(this->mutex); + return SUCCESS; +} + +METHOD(kernel_net_t, del_ip, status_t, + private_android_net_t *this, host_t *virtual_ip, int prefix, bool wait) +{ + host_t *vip; + + this->mutex->lock(this->mutex); + if (this->vips->find_first(this->vips, (void*)virtual_ip->ip_equals, + (void**)&vip, virtual_ip) == SUCCESS) + { + this->vips->remove(this->vips, vip, NULL); + vip->destroy(vip); + } + this->mutex->unlock(this->mutex); + return SUCCESS; +} + +METHOD(kernel_net_t, add_route, status_t, + private_android_net_t *this, chunk_t dst_net, u_int8_t prefixlen, + host_t *gateway, host_t *src_ip, char *if_name) +{ + return NOT_SUPPORTED; +} + +METHOD(kernel_net_t, del_route, status_t, + private_android_net_t *this, chunk_t dst_net, u_int8_t prefixlen, + host_t *gateway, host_t *src_ip, char *if_name) +{ + return NOT_SUPPORTED; +} + +METHOD(kernel_net_t, destroy, void, private_android_net_t *this) { this->network_manager->remove_connectivity_cb(this->network_manager, (void*)connectivity_cb); this->mutex->destroy(this->mutex); + this->vips->destroy(this->vips); + close(this->socket_v4); free(this); } -/* - * Described in header. - */ -android_net_t *android_net_create() +kernel_net_t *kernel_android_net_create() { private_android_net_t *this; INIT(this, .public = { + .get_source_addr = _get_source_addr, + .get_nexthop = _get_nexthop, + .get_interface = _get_interface, + .create_address_enumerator = _create_address_enumerator, + .add_ip = _add_ip, + .del_ip = _del_ip, + .add_route = _add_route, + .del_route = _del_route, .destroy = _destroy, }, .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .vips = linked_list_create(), .network_manager = charonservice->get_network_manager(charonservice), ); timerclear(&this->next_roam); + this->socket_v4 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (this->socket_v4 < 0) + { + DBG1(DBG_KNL, "failed to create socket to lookup src addresses: %s", + strerror(errno)); + } + charonservice->bypass_socket(charonservice, this->socket_v4, AF_INET); + this->network_manager->add_connectivity_cb(this->network_manager, (void*)connectivity_cb, this); return &this->public; -}; +} diff --git a/src/frontends/android/jni/libandroidbridge/kernel/android_net.h b/src/frontends/android/jni/libandroidbridge/kernel/android_net.h index ade83f32a..761fa21bc 100644 --- a/src/frontends/android/jni/libandroidbridge/kernel/android_net.h +++ b/src/frontends/android/jni/libandroidbridge/kernel/android_net.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2013 Tobias Brunner + * Copyright (C) 2012-2015 Tobias Brunner * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -22,25 +22,14 @@ #define ANDROID_NET_H_ #include - -typedef struct android_net_t android_net_t; +#include /** - * Handle connectivity events from NetworkManager - */ -struct android_net_t { - - /** - * Destroy an android_net_t instance. - */ - void (*destroy)(android_net_t *this); -}; - -/** - * Create an android_net_t instance. + * Create an Android-specific kernel_net_t instance. * - * @return android_net_t instance + * @return kernel_net_t instance */ -android_net_t *android_net_create(); +kernel_net_t *kernel_android_net_create(); + #endif /** ANDROID_NET_H_ @}*/