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'
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.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
import java.util.concurrent.TimeUnit
import okhttp3.CookieJar
import okhttp3.OkHttpClient
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.local.data.LocalStorageManager
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import java.util.concurrent.TimeUnit
val networkModule
get() = module {
single { AndroidCookieJar() } bind CookieJar::class
single {
val cache = get<LocalStorageManager>().createHttpCache()
OkHttpClient.Builder().apply {
connectTimeout(20, TimeUnit.SECONDS)
readTimeout(60, TimeUnit.SECONDS)
writeTimeout(20, TimeUnit.SECONDS)
cookieJar(get())
cache(get<LocalStorageManager>().createHttpCache())
dns(DoHManager(cache, get()))
cache(cache)
addInterceptor(UserAgentInterceptor())
addInterceptor(CloudFlareInterceptor())
}.build()

View File

@@ -16,6 +16,7 @@ import kotlinx.coroutines.channels.trySendBlocking
import kotlinx.coroutines.flow.callbackFlow
import org.koitharu.kotatsu.BuildConfig
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.utils.ext.getEnumValue
import org.koitharu.kotatsu.utils.ext.putEnumValue
@@ -188,6 +189,9 @@ class AppSettings(context: Context) {
get() = prefs.getBoolean(KEY_SEARCH_SINGLE_SOURCE, false)
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 {
return when (prefs.getString(KEY_PAGES_PRELOAD, null)?.toIntOrNull()) {
NETWORK_ALWAYS -> true
@@ -303,6 +307,7 @@ class AppSettings(context: Context) {
const val KEY_DOWNLOADS_PARALLELISM = "downloads_parallelism"
const val KEY_DOWNLOADS_SLOWDOWN = "downloads_slowdown"
const val KEY_ALL_FAVOURITES_VISIBLE = "all_favourites_visible"
const val KEY_DOH = "doh"
// About
const val KEY_APP_UPDATE = "app_update"

View File

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

View File

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

View File

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

View File

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

View File

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