From 6d87a86510687c3a52ad1b3cc37b8687c644be62 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 17 May 2023 10:17:14 +0200 Subject: [PATCH] android: Use new sockets to determine source IP Particularly on Samsung devices, the connect() call to dissolve the previous connection on an existing socket via AF_UNSPEC does fail in some situations with ECONNREFUSED: [KNL] failed to disconnect socket: Connection refused While creating a new socket is potentially a bit more overhead, this should avoid the issue. Closes strongswan/strongswan#1691 --- .../jni/libandroidbridge/kernel/android_net.c | 85 +++++-------------- 1 file changed, 20 insertions(+), 65 deletions(-) diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_net.c b/src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_net.c index d60bee6f7..2a6d5326e 100644 --- a/src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_net.c +++ b/src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_net.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2016 Tobias Brunner + * Copyright (C) 2012-2023 Tobias Brunner * * Copyright (C) secunet Security Networks AG * @@ -58,16 +58,6 @@ struct private_android_net_t { */ linked_list_t *vips; - /** - * Socket used to determine source address (IPv4) - */ - int socket_v4; - - /** - * Socket used to determine source address (IPv6) - */ - int socket_v6; - /** * Whether the device is currently connected */ @@ -112,44 +102,34 @@ static void connectivity_cb(private_android_net_t *this, } METHOD(kernel_net_t, get_source_addr, host_t*, - private_android_net_t *this, host_t *dest, host_t *src) + private_android_net_t *this, host_t *dst, host_t *src) { union { struct sockaddr sockaddr; struct sockaddr_in sin; struct sockaddr_in6 sin6; - } addr; - socklen_t addrlen; + } addr = {}; + socklen_t addrlen = *dst->get_sockaddr_len(dst); timeval_t now; job_t *job; - int socket; + host_t *host = NULL; + int skt; - if (dest->get_family(dest) == AF_INET) + skt = socket(dst->get_family(dst), SOCK_DGRAM, IPPROTO_UDP); + if (skt < 0) { - socket = this->socket_v4; - } - else - { - socket = this->socket_v6; - } - if (socket < 0) - { - DBG1(DBG_KNL, "unable to determine src address for address family"); - return NULL; - } - addrlen = *dest->get_sockaddr_len(dest); - addr.sockaddr.sa_family = AF_UNSPEC; - if (connect(socket, &addr.sockaddr, addrlen) < 0) - { - DBG1(DBG_KNL, "failed to disconnect socket: %s", strerror(errno)); + DBG1(DBG_KNL, "failed to create socket to lookup src addresses: %s", + strerror(errno)); return NULL; } + charonservice->bypass_socket(charonservice, skt, dst->get_family(dst)); + 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(socket, dest->get_sockaddr(dest), addrlen) < 0) + if (connect(skt, dst->get_sockaddr(dst), addrlen) < 0) { /* don't report an error if we are not connected (ENETUNREACH) */ if (errno != ENETUNREACH) @@ -177,14 +157,17 @@ METHOD(kernel_net_t, get_source_addr, host_t*, this->mutex->unlock(this->mutex); } } - return NULL; } - if (getsockname(socket, &addr.sockaddr, &addrlen) < 0) + else if (getsockname(skt, &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); + else + { + host = host_create_from_sockaddr((sockaddr_t*)&addr); + } + close(skt); + return host; } CALLBACK(vip_equals, bool, @@ -295,8 +278,6 @@ METHOD(kernel_net_t, destroy, void, (void*)connectivity_cb); this->mutex->destroy(this->mutex); this->vips->destroy(this->vips); - close(this->socket_v4); - close(this->socket_v6); free(this); } @@ -327,32 +308,6 @@ kernel_net_t *kernel_android_net_create() this->public.get_source_addr = _get_source_addr_old; } - 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); - - switch (charon->socket->supported_families(charon->socket)) - { - case SOCKET_FAMILY_IPV6: - case SOCKET_FAMILY_BOTH: - this->socket_v6 = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); - if (this->socket_v6 < 0) - { - DBG1(DBG_KNL, "failed to create socket to lookup IPv6 src " - "addresses: %s", strerror(errno)); - } - charonservice->bypass_socket(charonservice, this->socket_v6, - AF_INET6); - break; - default: - this->socket_v6 = -1; - break; - } - this->mutex->lock(this->mutex); this->network_manager->add_connectivity_cb( this->network_manager, (void*)connectivity_cb, this);