From 45567146f4c38f3a8285ed05514a7c85ad586ef7 Mon Sep 17 00:00:00 2001 From: Andrew Dunham Date: Wed, 11 Sep 2024 12:21:06 -0400 Subject: [PATCH] android, libtailscale: pass BuildConfig to Go code; use for DNS config This commit wires up a method to allow the Tailscale Go backend to obtain the build configuration, and then adds a new build configuration to the build to control whether we fall back to the Google public DNS servers if we can't determine the platform's DNS configuration. This replaces the previous "IsPlayVersion" / "MaybeGoogle" check for whether to use the DNS servers as fallbacks, to allow users to decide this independently of what version of the Android app this is. Updates tailscale/tailscale#13431 Signed-off-by: Andrew Dunham --- android/build.gradle | 21 +++++++++++++------ .../src/main/java/com/tailscale/ipn/App.kt | 8 +++++++ libtailscale/backend.go | 13 ++++++++---- libtailscale/interfaces.go | 14 +++++++++++++ libtailscale/net.go | 2 +- libtailscale/tailscale.go | 5 +++++ 6 files changed, 52 insertions(+), 11 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 0befe7d..264223f 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -39,6 +39,14 @@ android { targetSdkVersion 34 versionCode 241 versionName "1.73.114-t0970615b1-gab7ab737364" + + // This setting, which defaults to 'true', will cause Tailscale to fall + // back to the Google DNS servers if it cannot determine what the + // operating system's DNS configuration is. + // + // Set it to false either here or in your local.properties file to + // disable this behaviour. + buildConfigField "boolean", "USE_GOOGLE_DNS_FALLBACK", getLocalProperty("tailscale.useGoogleDnsFallback", "true") } compileOptions { @@ -54,6 +62,7 @@ android { jvmTarget = "17" } buildFeatures { + buildConfig true compose true } composeOptions { @@ -66,9 +75,9 @@ android { applicationTest { initWith debug manifestPlaceholders.leanbackRequired = false - buildConfigField "String", "GITHUB_USERNAME", "\"" + getLocalProperty("githubUsername")+"\"" - buildConfigField "String", "GITHUB_PASSWORD", "\"" + getLocalProperty("githubPassword")+"\"" - buildConfigField "String", "GITHUB_2FA_SECRET", "\"" + getLocalProperty("github2FASecret")+"\"" + buildConfigField "String", "GITHUB_USERNAME", "\"" + getLocalProperty("githubUsername", "")+"\"" + buildConfigField "String", "GITHUB_PASSWORD", "\"" + getLocalProperty("githubPassword", "")+"\"" + buildConfigField "String", "GITHUB_2FA_SECRET", "\"" + getLocalProperty("github2FASecret", "")+"\"" } debug { manifestPlaceholders.leanbackRequired = false @@ -156,12 +165,12 @@ dependencies { implementation("androidx.compose.ui:ui-tooling-preview") } -def getLocalProperty(key) { +def getLocalProperty(key, defaultValue) { try { Properties properties = new Properties() properties.load(project.file('local.properties').newDataInputStream()) - return properties.getProperty(key) + return properties.getProperty(key) ?: defaultValue } catch(Throwable ignored) { - return "" + return defaultValue } } diff --git a/android/src/main/java/com/tailscale/ipn/App.kt b/android/src/main/java/com/tailscale/ipn/App.kt index 5df2cab..a9430dd 100644 --- a/android/src/main/java/com/tailscale/ipn/App.kt +++ b/android/src/main/java/com/tailscale/ipn/App.kt @@ -38,6 +38,7 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.launch import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import libtailscale.BuildConfig as GoBuildConfig import libtailscale.Libtailscale import java.io.File import java.io.IOException @@ -311,6 +312,13 @@ class App : UninitializedApp(), libtailscale.AppContext, ViewModelStoreOwner { } } + // getBuildConfig implements the libtailscale.AppContext interface. + override fun getBuildConfig(): GoBuildConfig { + var buildConfig = GoBuildConfig() + buildConfig.useGoogleDNSFallback = BuildConfig.USE_GOOGLE_DNS_FALLBACK + return buildConfig + } + fun notifyPolicyChanged() { app.notifyPolicyChanged() } diff --git a/libtailscale/backend.go b/libtailscale/backend.go index 908b7e2..414eeeb 100644 --- a/libtailscale/backend.go +++ b/libtailscale/backend.go @@ -44,6 +44,9 @@ type App struct { // appCtx is a global reference to the com.tailscale.ipn.App instance. appCtx AppContext + // buildConfig is the build configuration for the app. + buildConfig *BuildConfig + store *stateStore policyStore *syspolicyHandler logIDPublicAtomic atomic.Pointer[logid.PublicID] @@ -97,7 +100,8 @@ type backend struct { // when no nameservers are provided by Tailscale. avoidEmptyDNS bool - appCtx AppContext + appCtx AppContext + buildConfig *BuildConfig } type settingsFunc func(*router.Config, *dns.OSConfig) error @@ -262,9 +266,10 @@ func (a *App) newBackend(dataDir, directFileRoot string, appCtx AppContext, stor logf := logger.RusagePrefixLog(log.Printf) b := &backend{ - devices: newTUNDevices(), - settings: settings, - appCtx: appCtx, + devices: newTUNDevices(), + settings: settings, + appCtx: appCtx, + buildConfig: a.buildConfig, } var logID logid.PrivateID logID.UnmarshalText([]byte("dead0000dead0000dead0000dead0000dead0000dead0000dead0000dead0000")) diff --git a/libtailscale/interfaces.go b/libtailscale/interfaces.go index f344baa..11e40e2 100644 --- a/libtailscale/interfaces.go +++ b/libtailscale/interfaces.go @@ -57,6 +57,12 @@ type AppContext interface { // GetSyspolicyStringArrayValue returns the current string array value for the given system policy, // expressed as a JSON string. GetSyspolicyStringArrayJSONValue(key string) (string, error) + + // GetBuildConfig gets the build configuration of the Android app. + // + // The returned BuildConfig should not change during the lifetime of + // the app. + GetBuildConfig() *BuildConfig } // IPNService corresponds to our IPNService in Java. @@ -166,3 +172,11 @@ func RequestVPN(service IPNService) { func ServiceDisconnect(service IPNService) { onDisconnect <- service } + +// BuildConfig is a struct that represents the build configuration of the +// Android application, as set in BuildConfig.java. +type BuildConfig struct { + // UseGoogleDNSFallback is whether to fall back to the Google public + // DNS servers if the platform's DNS servers cannot be determined. + UseGoogleDNSFallback bool +} diff --git a/libtailscale/net.go b/libtailscale/net.go index efa7e8f..c49efd6 100644 --- a/libtailscale/net.go +++ b/libtailscale/net.go @@ -287,7 +287,7 @@ func (b *backend) getDNSBaseConfig() (ret dns.OSConfig, _ error) { // DNS config are lacking, and almost all Android phones use Google // services anyway, so it's a reasonable default: it's an ecosystem the // user has selected by having an Android device. - if len(ret.Nameservers) == 0 && b.appCtx.IsPlayVersion() { + if len(ret.Nameservers) == 0 && b.buildConfig.UseGoogleDNSFallback { log.Printf("getDNSBaseConfig: none found; falling back to Google public DNS") ret.Nameservers = append(ret.Nameservers, googleDNSServers...) } diff --git a/libtailscale/tailscale.go b/libtailscale/tailscale.go index 7370726..5d08cd7 100644 --- a/libtailscale/tailscale.go +++ b/libtailscale/tailscale.go @@ -38,6 +38,11 @@ func newApp(dataDir, directFileRoot string, appCtx AppContext) Application { } a.ready.Add(2) + // Get the build configuration, if any. + if bc := appCtx.GetBuildConfig(); bc != nil { + a.buildConfig = bc + } + a.store = newStateStore(a.appCtx) a.policyStore = &syspolicyHandler{a: a} netmon.RegisterInterfaceGetter(a.getInterfaces)