Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mobike fails due to socket dissolve call in android_net::get_source_addr #1691

Closed
andphillips opened this issue May 10, 2023 · 9 comments
Closed
Labels
Milestone

Comments

@andphillips
Copy link

andphillips commented May 10, 2023

System (please complete the following information):

  • OS: Samsung Galaxy S22 Android 12 / S23 Android 13
  • Kernel version (if applicable): S23: 5.15.41-android13-8-25800099-abS911BXXS1AWD1
  • strongSwan version(s): 5.9.10
  • Tested/confirmed with the latest version: yes

Describe the bug
In ./src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_net.c, there is a socket "dissolve" call (sorry it all got jumbled on one line):

addr.sockaddr.sa_family = AF_UNSPEC; if (connect(socket, &addr.sockaddr, addrlen) < 0) { DBG1(DBG_KNL, "failed to disconnect socket: %s", strerror(errno)); return NULL; }

On the Samsung Galaxy devices (I don't know whether it's specific to Samsung or not, but it was 100% reproducible on them), socket dissolve does not consistently work. As tested, it behaves better if you instead do a clean socket close and open to get a new socket FD. The example pictured below is for the IPv4 socket in android_net.c.

if (dest->get_family(dest) == AF_INET) { socket = this->socket_v4; // Instead of using socket "dissolve" just close and reopen the socket. // see https://man7.org/linux/man-pages/man2/connect.2.html // https://idea.popcount.org/2019-11-06-creating-sockets close(this->socket_v4); this->socket_v4 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); charonservice->bypass_socket(charonservice, this->socket_v4, AF_INET); socketFd = this->socket_v4; }

As the link below says "This AF_UNSPEC socket dissolve trick is totally ugly, but it can save us a syscall. Instead of calling close() and then socket(), we can do a single connect(AF_UNSPEC) only. The big issue is it's not obvious which internal socket fields are reset and which are preserved."
https://idea.popcount.org/2019-11-06-creating-sockets/
https://man7.org/linux/man-pages/man2/connect.2.html

To Reproduce
Steps to reproduce the behavior:

  1. Connect to a WiFi router
  2. Disconnect Mobile data
  3. Make sure that there are NO fallback networks that the device can connect to
  4. Make sure the device is not plugged into anything (especially USB)
  5. Lock the screen
  6. Unplug the power cable from the router
  7. Wait at least 10-20 minutes so that the Android device goes into doze mode
  8. Plug the router power cable back in
  9. Wait for it to connect

Expected behavior
The connection is restored.

Actual behavior
Mobike fails because android_net::get_source_addr bails out early since it gets the following error. The errno returned is ECONNREFUSED.
"failed to disconnect socket: Connection refused"

Logs/Backtraces
05-09 06:03:25.846 26854 8804 I charon : 16[NET] error writing to socket: Network is unreachable
...
05-09 06:03:30.851 26854 8804 I charon : 16[NET] error writing to socket: Network is unreachable
...
05-09 09:18:20.391 26854 8788 I charon : 17[DMN] charonservice get_network_manager
05-09 09:18:20.393 26854 8788 I charon : 17[KNL] networkChanged 1
05-09 09:18:20.394 26854 8788 I charon : 17[KNL] connectivity_cb: connected 1
05-09 09:18:20.395 26854 8788 I charon : 17[KNL] connectivity_cb: too soon
05-09 09:18:20.552 26854 8790 I charon : 02[ESP] could not find an outbound IPsec SA for reqid {46}, dropping packet
05-09 09:18:21.026 26854 8790 I charon : 02[ESP] could not find an outbound IPsec SA for reqid {46}, dropping packet
05-09 09:18:21.043 26854 8802 I charon : 14[KNL] failed to disconnect socket: Connection refused
05-09 09:18:21.045 26854 8802 I charon : 14[IKE] old path is not available anymore, try to find another
05-09 09:18:21.046 26854 8802 I charon : 14[IKE] looking for a route to 62.67.59.130 ...
05-09 09:18:21.048 26854 8802 I charon : 14[KNL] failed to disconnect socket: Connection refused
05-09 09:18:21.050 26854 8802 I charon : 14[IKE] is_any_path_valid source address:(null) path valid:0
05-09 09:18:21.052 26854 8802 I charon : 14[IKE] no route found to reach 62.67.59.130, MOBIKE update deferred
05-09 09:18:22.908 26854 8788 I charon : 17[DMN] charonservice get_network_manager
05-09 09:18:22.910 26854 8788 I charon : 17[KNL] networkChanged 1
05-09 09:18:22.911 26854 8788 I charon : 17[KNL] connectivity_cb: connected 1
05-09 09:18:22.912 26854 8788 I charon : 17[KNL] connectivity_cb: checking connectivity
05-09 09:18:23.041 26854 8790 I charon : 02[ESP] could not find an outbound IPsec SA for reqid {46}, dropping packet
05-09 09:18:23.922 26854 8803 I charon : 15[KNL] failed to disconnect socket: Connection refused
05-09 09:18:23.923 26854 8803 I charon : 15[IKE] old path is not available anymore, try to find another
05-09 09:18:23.924 26854 8803 I charon : 15[IKE] looking for a route to 62.67.59.130 ...
05-09 09:18:23.926 26854 8803 I charon : 15[KNL] failed to disconnect socket: Connection refused
05-09 09:18:23.926 26854 8803 I charon : 15[IKE] is_any_path_valid source address:(null) path valid:0
05-09 09:18:23.927 26854 8803 I charon : 15[IKE] no route found to reach 62.67.59.130, MOBIKE update deferred
05-09 09:18:24.032 26854 8792 I charon : 04[IKE] sending keep alive to 62.67.59.130[4500]. uptime:68762(s)

@tobiasbrunner
Copy link
Member

Hm, while creating a new socket might be a workaround, I really wonder what goes wrong here. Because according to the man page for connect(), ECONNREFUSED is only returned if "connect() on a stream socket found no one listening on the remote address", which clearly doesn't apply for a dissolve attempt on a SOCK_DGRAM socket with AF_UNSPEC. However, I did notice that addr isn't initialized to 0 (the assumption is that AF_UNSPEC is enough to trigger the disolve and any other fields are ignored). Could you try if this change makes a difference:

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 d60bee6f780e..210adbf3ba08 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
@@ -118,7 +118,7 @@ METHOD(kernel_net_t, get_source_addr, host_t*,
 		struct sockaddr sockaddr;
 		struct sockaddr_in sin;
 		struct sockaddr_in6 sin6;
-	} addr;
+	} addr = {};
 	socklen_t addrlen;
 	timeval_t now;
 	job_t *job;

@tobiasbrunner tobiasbrunner removed the new label May 11, 2023
@andphillips
Copy link
Author

andphillips commented May 11, 2023 via email

@andphillips
Copy link
Author

Initializing addr didn't do anything. So far, the only thing i've found that works is a close of the socket fd and opening a new one.

@tobiasbrunner
Copy link
Member

OK, thanks for testing. I've pushed a possible fix to the 1691-android-src-ip branch. Please let me know if that work for you.

@andphillips
Copy link
Author

andphillips commented May 17, 2023 via email

@tobiasbrunner
Copy link
Member

Ok. I see, you just made it a local rather than a class variable.

Yeah, if we replace the socket with each call anyway, there is no need to keep it around.

I’ll get back to you.

Have you been able to test the patch in your environment in the meantime?

@andphillips
Copy link
Author

andphillips commented May 31, 2023 via email

@tobiasbrunner
Copy link
Member

Any updates on this?

@andphillips
Copy link
Author

andphillips commented Jul 24, 2023 via email

@tobiasbrunner tobiasbrunner added this to the 5.9.12 milestone Oct 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants