Skip to content

Add Android ECH support#9573

Merged
yschimke merged 6 commits into
lysine-dev:masterfrom
yschimke:AndroidDns
Jul 24, 2026
Merged

Add Android ECH support#9573
yschimke merged 6 commits into
lysine-dev:masterfrom
yschimke:AndroidDns

Conversation

@yschimke

Copy link
Copy Markdown
Collaborator

Initial version before dealing with NetworkSecurityPolicy,

instead just activated by developer using AndroidDns, and a server having HTTPS records with ECH.

@yschimke

Copy link
Copy Markdown
Collaborator Author

@swankjesse my biggest question is how to deal with NetworkSecurityPolicy for both
a) activation - is that AndroidDns? is that just whether to include for a specific host
b) error handling / fallback

I previously ended up with EchModes (disabled, strict and so on) read from the policy

https://github.com/lysine-dev/okhttp/pull/9383/changes#diff-62659f553c144abdf5c3d578b9d14e96bf069b4ef9e7f93549b04ff38e4fcbc9

@swankjesse swankjesse left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

THIS IS IT

private val network: Network? = null,
/**
* True to also query the `HTTPS` record for service metadata such as ECH. Set this to false to
* save a query when only IP addresses are needed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there’s a way to phrase this documentation to encourage people to keep it on.

‘Set this to false to omit the service metadata query. This will disable privacy features in the HTTPS call.’

@yschimke yschimke Jul 21, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think maybe we end up defaulting to the networkSecurityConfig, but let developers opt-out, or opt-in.

For now, likely opt-in while we confirm it works.

GREASE means it should never cause failures just by being enabled.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll ask tomorrow if that mode still exists.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I'll update the wording. But also think if we want this we should make AndroidDns the default on API 37+ and when network security policy isn't globally disabled?

I think effectively the modes are (potentially per host)

UNSPECIFIED
DISABLED
ENABLED

So maybe that default once we are confident is the right option?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread okhttp/src/androidMain/kotlin/okhttp3/android/AndroidDns.kt Outdated
Comment thread okhttp/src/androidMain/kotlin/okhttp3/android/AndroidDns.kt Outdated
Comment thread okhttp/src/androidMain/kotlin/okhttp3/android/AndroidDns.kt Outdated
Comment thread okhttp/src/androidMain/kotlin/okhttp3/android/AndroidDns.kt Outdated
Comment thread okhttp/src/androidMain/kotlin/okhttp3/android/AndroidDns.kt Outdated
Comment thread okhttp/src/androidMain/kotlin/okhttp3/android/AndroidDns.kt Outdated
@swankjesse

Copy link
Copy Markdown
Collaborator

I previously ended up with EchModes (disabled, strict and so on) read from the policy

My preference is we assume DNS is where this should be configured. If there’s a ECH parameter on the TYPE_HTTPS record we should use it, and if there isn’t then we should assume the site operators don‘t care.

Configuring it on the client is too difficult for large organizations, because the team that ships services and apps is far detached from the team that manages DNS and HTTPS.

@yschimke

Copy link
Copy Markdown
Collaborator Author

I previously ended up with EchModes (disabled, strict and so on) read from the policy

My preference is we assume DNS is where this should be configured. If there’s a ECH parameter on the TYPE_HTTPS record we should use it, and if there isn’t then we should assume the site operators don‘t care.

Configuring it on the client is too difficult for large organizations, because the team that ships services and apps is far detached from the team that manages DNS and HTTPS.

But there is a developer API that we should honour.

https://developer.android.com/privacy-and-security/security-config#EncryptedClientHelloSummary

@yschimke

Copy link
Copy Markdown
Collaborator Author

Still tests to go

@yschimke

Copy link
Copy Markdown
Collaborator Author

Need to put this catch back

emulator-5554 - 17 Tests 34/29 completed. (5 skipped) (1 failed)
Tests on emulator-5554 - 17 failed: There was 1 failure(s).
Finished 34 tests on emulator-5554 - 17
Execute okhttp.android.test.OkHttpTest.testUnderscoreRequest: FAILED
The input does not conform to the STD 3 ASCII rules. line: java.lang.IllegalArgumentException: Invalid input to toASCII: example_underscore_123.s3.amazonaws.com
at java.net.IDN.toASCII(IDN.java:115)
at javax.net.ssl.SNIHostName.<init>(SNIHostName.java:99)
at com.android.org.conscrypt.Platform.getSSLParameters(Platform.java:269)
at com.android.org.conscrypt.ConscryptEngine.getSSLParameters(ConscryptEngine.java:425)
at com.android.org.conscrypt.ConscryptEngineSocket.getSSLParameters(ConscryptEngineSocket.java:193)
at okhttp3.internal.platform.android.Android17SocketAdapter.configureTlsExtensions(Android17SocketAdapter.kt:63)
at okhttp3.internal.platform.Android10Platform.configureTlsExtensions(Android10Platform.kt:86)
at okhttp3.internal.connection.ConnectPlan.connectTls(ConnectPlan.kt:349)

@swankjesse

Copy link
Copy Markdown
Collaborator

Where does Android implement the policy in that XML file? Presumably we act as if it's always enabled, and the XML config overrides our preferences?

@yschimke

Copy link
Copy Markdown
Collaborator Author

Where does Android implement the policy in that XML file? Presumably we act as if it's always enabled, and the XML config overrides our preferences?

But then we do extra work fetching ECH records that won't be used.

But I think the test is that we do the correct, secure, optimal thing with DnsOverHttps enabled? So it can't be inside AndroidDns then?

Not sure where exactly - one of these

https://cs.android.com/android/platform/superproject/+/android-latest-release:external/conscrypt/repackaged/platform/src/main/java/com/android/org/conscrypt/ConscryptNetworkSecurityPolicy.java

https://cs.android.com/android/platform/superproject/+/android-latest-release:external/conscrypt/nsc/src/android/security/NetworkSecurityPolicy.java

cc @swankjesse not sure if you see non threaded comments.

Comment thread okhttp/src/androidMain/kotlin/okhttp3/android/AndroidDns.kt Outdated
Adds AndroidDns, backed by the system resolver and Android's DnsResolver
for HTTPS/ECH records, driving okhttp's StateMachineDnsCall as a transport.
Adds Android17SocketAdapter for platform ALPN/session-ticket/ECH setup on
API 37+. Pins Robolectric android-test to SDK 36.
@yschimke
yschimke marked this pull request as ready for review July 24, 2026 08:23
@yschimke
yschimke merged commit fb13116 into lysine-dev:master Jul 24, 2026
63 of 65 checks passed
* [Network.getAllByName] when a [network] is set. Internally this drives OkHttp's
* [StateMachineDnsCall] through a private transport: a single `A` query stands in for the blocking
* address lookup (which returns both address families), plus an optional `HTTPS` query for service
* metadata such as ECH.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great docs

*
* `WrongConstant` is suppressed because okhttp's [TYPE_HTTPS] is the DNS wire value (65), the
* same as the platform's `DnsResolver.TYPE_HTTPS`. We use ours so the query stays valid on
* API 29+; `DnsResolver.TYPE_HTTPS` was only added in API 37.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oooh neat

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants