Dns over https option #161

This commit is contained in:
Koitharu
2022-05-12 12:19:01 +03:00
parent 58ff7c9235
commit 48e232e04e
10 changed files with 122 additions and 4 deletions

View File

@@ -96,6 +96,7 @@ dependencies {
kapt 'androidx.room:room-compiler:2.4.2' kapt 'androidx.room:room-compiler:2.4.2'
implementation 'com.squareup.okhttp3:okhttp:4.9.3' implementation 'com.squareup.okhttp3:okhttp:4.9.3'
implementation 'com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.3'
implementation 'com.squareup.okio:okio:3.1.0' implementation 'com.squareup.okio:okio:3.1.0'
implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl:4.3.2' implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl:4.3.2'

View File

@@ -0,0 +1,84 @@
package org.koitharu.kotatsu.core.network
import okhttp3.Cache
import okhttp3.Dns
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import okhttp3.dnsoverhttps.DnsOverHttps
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
import java.net.InetAddress
import java.net.UnknownHostException
class DoHManager(
cache: Cache,
private val settings: AppSettings,
) : Dns {
private val bootstrapClient = OkHttpClient.Builder().cache(cache).build()
private var cachedDelegate: Dns? = null
private var cachedProvider: DoHProvider? = null
override fun lookup(hostname: String): List<InetAddress> {
return getDelegate().lookup(hostname)
}
@Synchronized
private fun getDelegate(): Dns {
var delegate = cachedDelegate
val provider = settings.dnsOverHttps
if (delegate == null || provider != cachedProvider) {
delegate = createDelegate(provider)
cachedDelegate = delegate
cachedProvider = provider
}
return delegate
}
private fun createDelegate(provider: DoHProvider): Dns = when (provider) {
DoHProvider.NONE -> Dns.SYSTEM
DoHProvider.GOOGLE -> DnsOverHttps.Builder().client(bootstrapClient)
.url("https://dns.google/dns-query".toHttpUrl())
.bootstrapDnsHosts(
listOfNotNull(
tryGetByIp("8.8.4.4"),
tryGetByIp("8.8.8.8"),
tryGetByIp("2001:4860:4860::8888"),
tryGetByIp("2001:4860:4860::8844"),
)
).build()
DoHProvider.CLOUDFLARE -> DnsOverHttps.Builder().client(bootstrapClient)
.url("https://cloudflare-dns.com/dns-query".toHttpUrl())
.bootstrapDnsHosts(
listOfNotNull(
tryGetByIp("162.159.36.1"),
tryGetByIp("162.159.46.1"),
tryGetByIp("1.1.1.1"),
tryGetByIp("1.0.0.1"),
tryGetByIp("162.159.132.53"),
tryGetByIp("2606:4700:4700::1111"),
tryGetByIp("2606:4700:4700::1001"),
tryGetByIp("2606:4700:4700::0064"),
tryGetByIp("2606:4700:4700::6400"),
)
).build()
DoHProvider.ADGUARD -> DnsOverHttps.Builder().client(bootstrapClient)
.url("https://dns-unfiltered.adguard.com/dns-query".toHttpUrl())
.bootstrapDnsHosts(
listOfNotNull(
tryGetByIp("94.140.14.140"),
tryGetByIp("94.140.14.141"),
tryGetByIp("2a10:50c0::1:ff"),
tryGetByIp("2a10:50c0::2:ff"),
)
).build()
}
private fun tryGetByIp(ip: String): InetAddress? = try {
InetAddress.getByName(ip)
} catch (e: UnknownHostException) {
e.printStackTraceDebug()
null
}
}

View File

@@ -0,0 +1,6 @@
package org.koitharu.kotatsu.core.network
enum class DoHProvider {
NONE, GOOGLE, CLOUDFLARE, ADGUARD
}

View File

@@ -1,6 +1,5 @@
package org.koitharu.kotatsu.core.network package org.koitharu.kotatsu.core.network
import java.util.concurrent.TimeUnit
import okhttp3.CookieJar import okhttp3.CookieJar
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.koin.dsl.bind import org.koin.dsl.bind
@@ -8,17 +7,20 @@ import org.koin.dsl.module
import org.koitharu.kotatsu.core.parser.MangaLoaderContextImpl import org.koitharu.kotatsu.core.parser.MangaLoaderContextImpl
import org.koitharu.kotatsu.local.data.LocalStorageManager import org.koitharu.kotatsu.local.data.LocalStorageManager
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import java.util.concurrent.TimeUnit
val networkModule val networkModule
get() = module { get() = module {
single { AndroidCookieJar() } bind CookieJar::class single { AndroidCookieJar() } bind CookieJar::class
single { single {
val cache = get<LocalStorageManager>().createHttpCache()
OkHttpClient.Builder().apply { OkHttpClient.Builder().apply {
connectTimeout(20, TimeUnit.SECONDS) connectTimeout(20, TimeUnit.SECONDS)
readTimeout(60, TimeUnit.SECONDS) readTimeout(60, TimeUnit.SECONDS)
writeTimeout(20, TimeUnit.SECONDS) writeTimeout(20, TimeUnit.SECONDS)
cookieJar(get()) cookieJar(get())
cache(get<LocalStorageManager>().createHttpCache()) dns(DoHManager(cache, get()))
cache(cache)
addInterceptor(UserAgentInterceptor()) addInterceptor(UserAgentInterceptor())
addInterceptor(CloudFlareInterceptor()) addInterceptor(CloudFlareInterceptor())
}.build() }.build()

View File

@@ -16,6 +16,7 @@ import kotlinx.coroutines.channels.trySendBlocking
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.callbackFlow
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.model.ZoomMode import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.core.network.DoHProvider
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.utils.ext.getEnumValue import org.koitharu.kotatsu.utils.ext.getEnumValue
import org.koitharu.kotatsu.utils.ext.putEnumValue import org.koitharu.kotatsu.utils.ext.putEnumValue
@@ -188,6 +189,9 @@ class AppSettings(context: Context) {
get() = prefs.getBoolean(KEY_SEARCH_SINGLE_SOURCE, false) get() = prefs.getBoolean(KEY_SEARCH_SINGLE_SOURCE, false)
set(value) = prefs.edit { putBoolean(KEY_SEARCH_SINGLE_SOURCE, value) } set(value) = prefs.edit { putBoolean(KEY_SEARCH_SINGLE_SOURCE, value) }
val dnsOverHttps: DoHProvider
get() = prefs.getEnumValue(KEY_DOH, DoHProvider.NONE)
fun isPagesPreloadAllowed(cm: ConnectivityManager): Boolean { fun isPagesPreloadAllowed(cm: ConnectivityManager): Boolean {
return when (prefs.getString(KEY_PAGES_PRELOAD, null)?.toIntOrNull()) { return when (prefs.getString(KEY_PAGES_PRELOAD, null)?.toIntOrNull()) {
NETWORK_ALWAYS -> true NETWORK_ALWAYS -> true
@@ -303,6 +307,7 @@ class AppSettings(context: Context) {
const val KEY_DOWNLOADS_PARALLELISM = "downloads_parallelism" const val KEY_DOWNLOADS_PARALLELISM = "downloads_parallelism"
const val KEY_DOWNLOADS_SLOWDOWN = "downloads_slowdown" const val KEY_DOWNLOADS_SLOWDOWN = "downloads_slowdown"
const val KEY_ALL_FAVOURITES_VISIBLE = "all_favourites_visible" const val KEY_ALL_FAVOURITES_VISIBLE = "all_favourites_visible"
const val KEY_DOH = "doh"
// About // About
const val KEY_APP_UPDATE = "app_update" const val KEY_APP_UPDATE = "app_update"

View File

@@ -3,18 +3,22 @@ package org.koitharu.kotatsu.settings
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.preference.ListPreference
import androidx.preference.Preference import androidx.preference.Preference
import java.io.File
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BasePreferenceFragment import org.koitharu.kotatsu.base.ui.BasePreferenceFragment
import org.koitharu.kotatsu.base.ui.dialog.StorageSelectDialog import org.koitharu.kotatsu.base.ui.dialog.StorageSelectDialog
import org.koitharu.kotatsu.core.network.DoHProvider
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.local.data.LocalStorageManager import org.koitharu.kotatsu.local.data.LocalStorageManager
import org.koitharu.kotatsu.settings.utils.SliderPreference import org.koitharu.kotatsu.settings.utils.SliderPreference
import org.koitharu.kotatsu.utils.ext.getStorageName import org.koitharu.kotatsu.utils.ext.getStorageName
import org.koitharu.kotatsu.utils.ext.names
import org.koitharu.kotatsu.utils.ext.setDefaultValueCompat
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
import java.io.File
class ContentSettingsFragment : class ContentSettingsFragment :
BasePreferenceFragment(R.string.content), BasePreferenceFragment(R.string.content),
@@ -36,6 +40,10 @@ class ContentSettingsFragment :
true true
} }
} }
findPreference<ListPreference>(AppSettings.KEY_DOH)?.run {
entryValues = enumValues<DoHProvider>().names()
setDefaultValueCompat(DoHProvider.NONE.name)
}
bindRemoteSourcesSummary() bindRemoteSourcesSummary()
} }

View File

@@ -34,4 +34,10 @@
<item>@string/only_using_wifi</item> <item>@string/only_using_wifi</item>
<item>@string/never</item> <item>@string/never</item>
</string-array> </string-array>
<string-array name="doh_providers">
<item>@string/disabled</item>
<item>Google</item>
<item>CloudFlare</item>
<item>AdGuard</item>
</string-array>
</resources> </resources>

View File

@@ -295,4 +295,5 @@
<string name="bookmark_added">Bookmark added</string> <string name="bookmark_added">Bookmark added</string>
<string name="undo">Undo</string> <string name="undo">Undo</string>
<string name="removed_from_history">Removed from history</string> <string name="removed_from_history">Removed from history</string>
<string name="dns_over_https">DNS over HTTPS</string>
</resources> </resources>

View File

@@ -14,6 +14,12 @@
android:persistent="false" android:persistent="false"
android:title="@string/suggestions" /> android:title="@string/suggestions" />
<ListPreference
android:entries="@array/doh_providers"
android:key="doh"
android:title="@string/dns_over_https"
app:useSimpleSummaryProvider="true" />
<Preference <Preference
android:key="local_storage" android:key="local_storage"
android:persistent="false" android:persistent="false"

View File

@@ -13,7 +13,6 @@
android:entries="@array/zoom_modes" android:entries="@array/zoom_modes"
android:key="zoom_mode" android:key="zoom_mode"
android:title="@string/scale_mode" android:title="@string/scale_mode"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<MultiSelectListPreference <MultiSelectListPreference