Skip to content

Keep tracker statistics truthful when DNS goes unseen - #982

Open
kasnder wants to merge 1 commit into
masterfrom
claude/ecstatic-tesla-tos3pq
Open

kasnder wants to merge 1 commit into
masterfrom
claude/ecstatic-tesla-tos3pq

Conversation

@kasnder

@kasnder kasnder commented Oct 7, 2026

Copy link
Copy Markdown
Member

Addresses #968: the statistics say nothing was blocked and show trackers as "Allowed", whatever the blocking mode.

I couldn't open the screenshots or the settings XML attached to the issue, so the root cause below is inferred from the code and from the reporter saying they turned on research mode.

Cause

The onboarding research preset set block_dot=false. When Android's Private DNS is on "Automatic" (the default), Android then switches to DoT against the resolvers the VPN advertises. TrackerControl sees no plaintext DNS, so blockKnownTracker has nothing to match by IP and allows everything. SNI logging still names the trackers, so they are recorded as allowed. No warning appeared: the bypass warning only fired for a resolver set by hostname, or with the full traffic log turned on.

Changes

  • Research preset: every onboarding preset now keeps "Block Android's Private DNS" on.
  • Private DNS detection: new Util.isPrivateDnsActiveOnVpn checks LinkProperties.isPrivateDnsActive() on VPN networks (API 28+). It feeds a new PRIVATE_DNS_WARNING_ACTIVE state. That state shows a notification and banner which open TrackerControl's settings, and it doesn't need the traffic log. Android validates DoT asynchronously, so there's a one-shot re-check 30 s after the VPN is established and after block_dot changes. Nothing runs periodically, and nothing runs at all while DoT is blocked.
  • SNI attribution (research mode):
    • The contact is now stored under the tracker name that actually matched, which for a cloaked tracker is the CNAME target. Previously the timeline and the Protection screen looked the stored SNI name up again, found nothing and dropped the row.
    • uncertain keeps ACCESS_UNCERTAIN_MIXED_TRACKER_AND_NON_TRACKER instead of being reset to none. Blocking is still decided by IP, and that mark is what explains "Allowed · shared IP".

Not in this PR

  • The research preset's description still says "No tracker blocking", but the preset applies Minimal mode.
  • In research mode, a connection blocked by IP whose SNI isn't a tracker is still not recorded.

Testing

  • ./gradlew :app:compileGithubDebugJavaWithJavac: passes.

  • New ServiceSinkholeSniAttributionTest and a new case in PrivateDnsWarningTest: pass.

  • PrivateDnsBlockedTest and ServiceSinkholeCnameEvidenceTest: pass.

  • Full :app:testGithubDebugUnitTest: 498 tests, 2 failures:

    • TrackerListMinimalTest.detectionOnlyTrackerIsMonitoredRatherThanBlockedOrAllowed
    • TrackerListModeTest.minimalModeRepresentativeDomainsComeFromDuckDuckGoAsset

    Both also fail on master without this change.

  • :app:lintGithubDebug: 0 errors, and no warnings in the touched code.

  • Not tested on a device. Whether getAllNetworks() exposes TrackerControl's own VPN network on recent Android, given the app excludes itself from it, still needs checking on a real device.

https://claude.ai/code/session_01WgbtBAKqNxgmeXSPtUoXxp


Generated by Claude Code

The research preset turned off DoT blocking. With Android's Private DNS on
"Automatic", Android then upgrades to DoT against the resolvers the VPN
advertises, TrackerControl sees no plaintext DNS, and nothing is blocked in
any mode while SNI still records trackers as allowed (#968).

- Keep "Block Android's Private DNS" on in every onboarding preset.
- Warn when Private DNS is active on the VPN network
  (LinkProperties.isPrivateDnsActive), without needing the full traffic
  log. Re-check 30 s after the VPN comes up and after block_dot changes,
  since Android validates DoT asynchronously.
- In SNI attribution, store the tracker name that matched (the CNAME
  target for cloaked trackers) so the timeline and Protection screen find
  the row again, and keep the shared-IP mark that explains why standard
  mode allowed the contact.

Claude-Session: https://claude.ai/code/session_01WgbtBAKqNxgmeXSPtUoXxp
@kasnder
kasnder marked this pull request as ready for review October 8, 2026 14:32

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants