From: Tobias Brunner Date: Mon, 22 Jun 2015 15:15:33 +0000 (+0200) Subject: android: Fix kernel-net implementation on Android 4.3 and earlier X-Git-Tag: 5.3.3dr3~8^2~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5da31733de79baf9249b45be1132c1e2f7203f4e;p=thirdparty%2Fstrongswan.git android: Fix kernel-net implementation on Android 4.3 and earlier Before fwmarks were used protected sockets were bound to the outbound interface via SO_BINDTODEVICE. This does not always seem to work well together with our connect()/getsockname() trick if the server is covered by the traffic selectors. Calling protect() again after disconnecting the socket seems to help, but if there is no connectivity at all we still get the virtual IP back (maybe protect() does not bind the socket to any interface then). --- diff --git a/src/frontends/android/jni/libandroidbridge/android_jni.h b/src/frontends/android/jni/libandroidbridge/android_jni.h index 99c0bc2cd9..b08670f7eb 100644 --- a/src/frontends/android/jni/libandroidbridge/android_jni.h +++ b/src/frontends/android/jni/libandroidbridge/android_jni.h @@ -54,6 +54,8 @@ typedef enum { ANDROID_ICE_CREAM_SANDWICH = 14, ANDROID_ICE_CREAM_SANDWICH_MR1 = 15, ANDROID_JELLY_BEAN = 16, + ANDROID_JELLY_BEAN_MR1 = 17, + ANDROID_JELLY_BEAN_MR2 = 18, } android_sdk_version_t; /** diff --git a/src/frontends/android/jni/libandroidbridge/kernel/android_net.c b/src/frontends/android/jni/libandroidbridge/kernel/android_net.c index 9cab74e13d..73322ad76d 100644 --- a/src/frontends/android/jni/libandroidbridge/kernel/android_net.c +++ b/src/frontends/android/jni/libandroidbridge/kernel/android_net.c @@ -18,6 +18,7 @@ #include "android_net.h" +#include "../android_jni.h" #include "../charonservice.h" #include #include @@ -114,6 +115,11 @@ METHOD(kernel_net_t, get_source_addr, host_t*, DBG1(DBG_KNL, "failed to disconnect socket: %s", strerror(errno)); return NULL; } + if (android_sdk_version <= ANDROID_JELLY_BEAN_MR2) + { /* this seems to help avoiding the VIP, unless there is no connectivity + * at all */ + charonservice->bypass_socket(charonservice, -1, 0); + } if (connect(this->socket_v4, dest->get_sockaddr(dest), addrlen) < 0) { /* don't report an error if we are not connected (ENETUNREACH) */ @@ -131,6 +137,29 @@ METHOD(kernel_net_t, get_source_addr, host_t*, return host_create_from_sockaddr((sockaddr_t*)&addr); } +METHOD(kernel_net_t, get_source_addr_old, host_t*, + private_android_net_t *this, host_t *dest, host_t *src) +{ + host_t *host; + + /* on older Android versions we might get the virtual IP back because + * the protect() implementation there and connect() don't properly work + * together, on newer releases (using fwmarks) that's not a problem */ + host = get_source_addr(this, dest, src); + if (host) + { + this->mutex->lock(this->mutex); + if (this->vips->find_first(this->vips, (void*)host->ip_equals, + NULL, host) == SUCCESS) + { + host->destroy(host); + host = NULL; + } + this->mutex->unlock(this->mutex); + } + return host; +} + METHOD(kernel_net_t, get_nexthop, host_t*, private_android_net_t *this, host_t *dest, int prefix, host_t *src) { @@ -233,6 +262,11 @@ kernel_net_t *kernel_android_net_create() ); timerclear(&this->next_roam); + if (android_sdk_version <= ANDROID_JELLY_BEAN_MR2) + { + this->public.get_source_addr = _get_source_addr_old; + } + this->socket_v4 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (this->socket_v4 < 0) {