From c5c5f5d4614b87600c40458e7d76bc4ca66fd17d Mon Sep 17 00:00:00 2001 From: Denozordec Date: Mon, 9 Nov 2026 20:26:41 +0700 Subject: [PATCH] android: DoT closes the per-worker connection on any read error or id mismatch (a late reply would answer the next query and desync it forever); the connect probe no longer does an untimed host lookup for the log Co-Authored-By: Claude Opus 5.5 --- .../android/logic/protection/SecureDns.kt | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/protection/SecureDns.kt b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/protection/SecureDns.kt index c47f3a558..c5bfb3a65 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/protection/SecureDns.kt +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/protection/SecureDns.kt @@ -233,20 +233,12 @@ object SecureDns { return true } - val upstream = try - { - InetAddress.getAllByName(config.host).joinToString(",") { it.hostAddress ?: "" } - } - catch (e: Exception) - { - "unresolved" - } val result = probe(config) probedConfig = config probedAt = now probeOk = result.ok - DiagLog.i(TAG, if (result.ok) "probe ${config.label} ok in ${result.ms} ms (upstream $upstream)" - else "probe ${config.label} failed after ${result.ms} ms (upstream $upstream): ${result.error}; falling back to plain DNS") + DiagLog.i(TAG, if (result.ok) "probe ${config.label} ok in ${result.ms} ms" + else "probe ${config.label} failed after ${result.ms} ms: ${result.error}; falling back to plain DNS") return result.ok } @@ -430,9 +422,20 @@ object SecureDns dot.get()?.close() dot.set(it) } - conn.out.write(SecureDnsCodec.frame(query)) - conn.out.flush() - return SecureDnsCodec.readFrame(conn.input) + try + { + conn.out.write(SecureDnsCodec.frame(query)) + conn.out.flush() + val reply = SecureDnsCodec.readFrame(conn.input) + if (!SecureDnsCodec.sameId(query, reply)) throw IOException("reply id mismatch") + return reply + } + catch (e: IOException) + { /* a late reply would stay in the stream and answer the next query: never reuse it */ + conn.close() + dot.set(null) + throw e + } } private class DotConnection(val config: SecureDnsConfig, val socket: SSLSocket)