From 3c73eb5a2774959f7d788bdb643afe54559cc6f4 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Sun, 4 Oct 2026 01:15:25 +0700 Subject: [PATCH] android: 2.13.14 - fix owner attribution protocol, log update events, ESP replay window context --- src/frontends/android/app/build.gradle | 4 +- .../android/logic/CharonVpnService.java | 5 ++- .../android/logic/updates/UpdateManager.kt | 38 ++++++++++++++++++- src/libipsec/esp_packet.c | 5 ++- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/frontends/android/app/build.gradle b/src/frontends/android/app/build.gradle index 8300dbd21..d460062b9 100644 --- a/src/frontends/android/app/build.gradle +++ b/src/frontends/android/app/build.gradle @@ -37,8 +37,8 @@ android { minSdkVersion 21 targetSdkVersion 36 - versionCode 150 - versionName "2.13.13" + versionCode 151 + versionName "2.13.14" /* Base URL of the update storage, trailing slash included */ buildConfigField "String", "UPDATE_BASE_URL", "\"${updateBaseUrl}\"" diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java index 75b0ec597..5dab55e3c 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java @@ -1432,8 +1432,9 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe InetAddress remoteInet = InetAddress.getByAddress(remoteAddr); InetSocketAddress local = new InetSocketAddress(localInet, localPort); InetSocketAddress remote = new InetSocketAddress(remoteInet, remotePort); - int protocol = localInet instanceof Inet6Address - ? android.system.OsConstants.AF_INET6 : android.system.OsConstants.AF_INET; + /* getConnectionOwnerUid expects an IP protocol (TCP or UDP only), + * not an address family - AF_INET here throws on every call */ + int protocol = android.system.OsConstants.IPPROTO_TCP; int uid = manager.getConnectionOwnerUid(protocol, local, remote); if (uid < 0) { /* the socket is already gone - nothing to attribute */ diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/updates/UpdateManager.kt b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/updates/UpdateManager.kt index d82518e57..f472ab031 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/updates/UpdateManager.kt +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/updates/UpdateManager.kt @@ -47,6 +47,7 @@ import kotlinx.coroutines.launch import org.json.JSONObject import org.strongswan.android.BuildConfig import org.strongswan.android.R +import org.strongswan.android.logic.DiagLog import org.strongswan.android.logic.StrongSwanApplication import org.strongswan.android.logic.VpnStateService import org.strongswan.android.ui.MainActivity @@ -235,11 +236,14 @@ class UpdateManager private constructor(private val context: Context) mPrefs.edit().putLong(Constants.PREF_LAST_UPDATE_CHECK, System.currentTimeMillis()).apply() if (info.versionCode > currentVersionCode()) { + DiagLog.i(TAG, "update: available ${info.versionName} (${info.versionCode}), " + + "installed ${currentVersionName()} (${currentVersionCode()})") mState.value = UpdateState.Available(info) maybeDownloadSilently(info) } else { + DiagLog.i(TAG, "update: up to date (${currentVersionName()} ${currentVersionCode()})") mState.value = UpdateState.UpToDate } } @@ -254,29 +258,43 @@ class UpdateManager private constructor(private val context: Context) */ private fun maybeDownloadSilently(info: UpdateInfo) { - if (!isSilentUpdatesEnabled() || isNetworkMetered() || mDownloadJob?.isActive == true) + if (!isSilentUpdatesEnabled()) + { + DiagLog.i(TAG, "update: silent download disabled, waiting for manual install") + return + } + if (isNetworkMetered()) + { + DiagLog.i(TAG, "update: silent download deferred (network metered)") + return + } + if (mDownloadJob?.isActive == true) { return } mDownloadJob = mScope.launch { try { + DiagLog.i(TAG, "update: downloading ${info.versionName} (${info.size} B)") val apk = downloadApk(info) verifySignature(apk) if (isVpnDown() && canInstallSilently()) { Log.i(TAG, "Applying the downloaded update silently") + DiagLog.i(TAG, "update: installing ${info.versionName} silently") UpdateInstaller.install(context, apk) mState.value = UpdateState.Idle } else { + DiagLog.i(TAG, "update: ${info.versionName} downloaded, waiting for the user") notifyUpdateReady(info) } } catch (e: Exception) { Log.e(TAG, "Silent update download failed", e) + DiagLog.i(TAG, "update: silent download failed: ${e.javaClass.simpleName}: ${e.message}") /* the manual download from the settings screen still works */ } } @@ -355,20 +373,24 @@ class UpdateManager private constructor(private val context: Context) mDownloadJob = mScope.launch { try { + DiagLog.i(TAG, "update: downloading ${info.versionName} (manual)") val apk = downloadApk(info) verifySignature(apk) + DiagLog.i(TAG, "update: installing ${info.versionName} (manual)") UpdateInstaller.install(context, apk) mState.value = UpdateState.Idle } catch (e: UpdateException) { Log.e(TAG, "Update failed: ${e.kind}", e) + DiagLog.i(TAG, "update: install failed (${e.kind}): ${e.message}") mState.value = UpdateState.Failed(e.kind, e.message) cleanup() } catch (e: Exception) { Log.e(TAG, "Update failed", e) + DiagLog.i(TAG, "update: install failed: ${e.javaClass.simpleName}: ${e.message}") mState.value = UpdateState.Failed(UpdateError.OTHER, e.message) cleanup() } @@ -396,6 +418,7 @@ class UpdateManager private constructor(private val context: Context) if (code != HttpURLConnection.HTTP_OK) { conn.disconnect() + DiagLog.i(TAG, "update: check failed: HTTP $code") mState.value = UpdateState.Failed(UpdateError.NETWORK, "HTTP $code") return null } @@ -414,6 +437,7 @@ class UpdateManager private constructor(private val context: Context) catch (e: Exception) { Log.e(TAG, "Failed to fetch the update manifest", e) + DiagLog.i(TAG, "update: check failed: ${e.javaClass.simpleName}: ${e.message}") mState.value = UpdateState.Failed(UpdateError.NETWORK, e.message) return null } @@ -531,6 +555,18 @@ class UpdateManager private constructor(private val context: Context) } } + private fun currentVersionName(): String + { + return try + { + getPackageInfo()?.versionName ?: "?" + } + catch (e: Exception) + { + "?" + } + } + private fun getPackageInfo(): PackageInfo? { val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) PackageManager.GET_SIGNING_CERTIFICATES diff --git a/src/libipsec/esp_packet.c b/src/libipsec/esp_packet.c index 46a8dfcf6..190946f9c 100644 --- a/src/libipsec/esp_packet.c +++ b/src/libipsec/esp_packet.c @@ -255,8 +255,9 @@ METHOD(esp_packet_t, decrypt, status_t, if (!esp_context->verify_seqno(esp_context, seq)) { DBG1(DBG_ESP, "ESP sequence number verification failed:\n " - "src %H, dst %H, SPI %.8x [seq %u]", - get_source(this), get_destination(this), spi, seq); + "src %H, dst %H, SPI %.8x [seq %u], window high %u", + get_source(this), get_destination(this), spi, seq, + esp_context->get_seqno(esp_context)); return VERIFY_ERROR; } DBG3(DBG_ESP, "ESP decryption:\n SPI %.8x [seq %u]\n IV %B\n "