aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2015-06-22 17:15:33 +0200
committerTobias Brunner <tobias@strongswan.org>2015-07-28 13:27:33 +0200
commit5da31733de79baf9249b45be1132c1e2f7203f4e (patch)
tree55f5b02978b84f86856e60958ef7fc55196ca486
parent1082372448d8055b9ab2cd296a011b2f71eee3fe (diff)
downloadstrongswan-5da31733de79baf9249b45be1132c1e2f7203f4e.tar.bz2
strongswan-5da31733de79baf9249b45be1132c1e2f7203f4e.tar.xz
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).
-rw-r--r--src/frontends/android/jni/libandroidbridge/android_jni.h2
-rw-r--r--src/frontends/android/jni/libandroidbridge/kernel/android_net.c34
2 files changed, 36 insertions, 0 deletions
diff --git a/src/frontends/android/jni/libandroidbridge/android_jni.h b/src/frontends/android/jni/libandroidbridge/android_jni.h
index 99c0bc2cd..b08670f7e 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 9cab74e13..73322ad76 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 <hydra.h>
#include <processing/jobs/callback_job.h>
@@ -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)
{