@@ -66,7 +66,7 @@ class LinuxdoDnsResolver(
6666 .dns(StaticDns (endpoints.associate { it.host to it.addresses }))
6767 .build()
6868
69- private val preparedEndpoints = endpoints
69+ private val primaryEndpoint = endpoints.firstOrNull()
7070
7171 fun resolveManagedPayload (requestPayload : ByteArray , query : ParsedDnsQuery ): ByteArray {
7272 val host = query.name.lowercase(Locale .US )
@@ -82,35 +82,30 @@ class LinuxdoDnsResolver(
8282 return DnsPacketCodec .buildResponse(query, resolution)
8383 }
8484
85- var lastError: Exception ? = null
86- for (endpoint in preparedEndpoints) {
87- try {
88- if (supportsDnsMessage(endpoint.url)) {
89- val resolution = queryDohDnsMessageRaw(endpoint, requestPayload, query)
85+ val endpoint = requirePrimaryEndpoint()
86+ try {
87+ if (supportsDnsMessage(endpoint.url)) {
88+ val resolution = queryDohDnsMessageRaw(endpoint, requestPayload, query)
89+ writeCache(host, query.type, resolution)
90+ Log .d(tag, " resolved $host type=${query.type} via ${endpoint.rawUrl} raw dns-message" )
91+ return DnsPacketCodec .buildResponse(query, resolution)
92+ }
93+
94+ if (isJsonFriendlyType(query.type)) {
95+ val resolution = DnsResolution (queryDohJson(endpoint, host, query.type))
96+ if (resolution.answers.isNotEmpty()) {
9097 writeCache(host, query.type, resolution)
91- Log .d(tag, " resolved $host type=${query.type} via ${endpoint.rawUrl} raw dns-message " )
98+ Log .d(tag, " resolved $host type=${query.type} via ${endpoint.rawUrl} answers= ${resolution.answers.size} " )
9299 return DnsPacketCodec .buildResponse(query, resolution)
93100 }
94-
95- if (isJsonFriendlyType(query.type)) {
96- val resolution = DnsResolution (queryDohJson(endpoint, host, query.type))
97- if (resolution.answers.isNotEmpty()) {
98- writeCache(host, query.type, resolution)
99- Log .d(tag, " resolved $host type=${query.type} via ${endpoint.rawUrl} answers=${resolution.answers.size} " )
100- return DnsPacketCodec .buildResponse(query, resolution)
101- }
102- lastError = IOException (" empty answer from ${endpoint.rawUrl} " )
103- continue
104- }
105-
106- lastError = IOException (" endpoint ${endpoint.rawUrl} does not support dns-message for type ${query.type} " )
107- } catch (error: Exception ) {
108- Log .w(tag, " resolver endpoint failed for $host via ${endpoint.rawUrl} : ${error.message} " )
109- lastError = error
101+ throw IOException (" empty answer from ${endpoint.rawUrl} " )
110102 }
111- }
112103
113- throw IOException (" DoH lookup failed for $host type=${query.type} : ${lastError?.message ? : " no endpoint available" } " )
104+ throw IOException (" endpoint ${endpoint.rawUrl} does not support dns-message for type ${query.type} " )
105+ } catch (error: Exception ) {
106+ Log .w(tag, " resolver endpoint failed for $host via ${endpoint.rawUrl} : ${error.message} " )
107+ throw wrapDohFailure(endpoint, host, query.type, error)
108+ }
114109 }
115110
116111 fun resolve (query : ParsedDnsQuery ): DnsResolution {
@@ -124,36 +119,30 @@ class LinuxdoDnsResolver(
124119 return it
125120 }
126121
127- val managedHost = config.isManagedHost (host)
122+ val managedHost = config.shouldUseManagedDoh (host)
128123 resolveLocal(host, query.type)?.let {
129124 val resolution = DnsResolution (it)
130125 writeCache(host, query.type, resolution)
131126 return resolution
132127 }
133128
134- val endpoints = if (managedHost) {
135- preparedEndpoints
136- } else {
137- preparedEndpoints.drop(1 ).ifEmpty { preparedEndpoints }
129+ if (! managedHost) {
130+ return DnsResolution (emptyList())
138131 }
139132
140- var lastError: Exception ? = null
141- for (endpoint in endpoints) {
142- try {
143- val resolution = DnsResolution (queryDoh(endpoint, host, query.type))
144- if (resolution.answers.isNotEmpty()) {
145- writeCache(host, query.type, resolution)
146- Log .d(tag, " resolved $host type=${query.type} via ${endpoint.rawUrl} answers=${resolution.answers.size} " )
147- return resolution
148- }
149- lastError = IOException (" empty answer from ${endpoint.rawUrl} " )
150- } catch (error: Exception ) {
151- Log .w(tag, " resolver endpoint failed for $host via ${endpoint.rawUrl} : ${error.message} " )
152- lastError = error
133+ val endpoint = requirePrimaryEndpoint()
134+ try {
135+ val resolution = DnsResolution (queryDoh(endpoint, host, query.type))
136+ if (resolution.answers.isNotEmpty()) {
137+ writeCache(host, query.type, resolution)
138+ Log .d(tag, " resolved $host type=${query.type} via ${endpoint.rawUrl} answers=${resolution.answers.size} " )
139+ return resolution
153140 }
141+ throw IOException (" empty answer from ${endpoint.rawUrl} " )
142+ } catch (error: Exception ) {
143+ Log .w(tag, " resolver endpoint failed for $host via ${endpoint.rawUrl} : ${error.message} " )
144+ throw wrapDohFailure(endpoint, host, query.type, error)
154145 }
155-
156- throw IOException (" DoH lookup failed for $host : ${lastError?.message ? : " no endpoint available" } " )
157146 }
158147
159148 private fun resolveLocal (host : String , type : Int ): List <DnsAnswerRecord >? {
@@ -186,13 +175,29 @@ class LinuxdoDnsResolver(
186175 }
187176
188177 private fun queryAlias (alias : String , type : Int ): List <DnsAnswerRecord > {
189- for ( endpoint in preparedEndpoints) {
190- try {
191- return queryDoh(endpoint, alias, type)
192- } catch (_: Exception ) {
193- }
178+ val endpoint = primaryEndpoint ? : return emptyList()
179+ return try {
180+ queryDoh(endpoint, alias, type)
181+ } catch (_: Exception ) {
182+ emptyList()
194183 }
195- return emptyList()
184+ }
185+
186+ private fun requirePrimaryEndpoint (): PreparedDohEndpoint {
187+ return primaryEndpoint ? : throw IOException (" DoH 不可用,请自行更换 DoH" )
188+ }
189+
190+ private fun wrapDohFailure (
191+ endpoint : PreparedDohEndpoint ,
192+ host : String ,
193+ type : Int ,
194+ error : Exception ,
195+ ): IOException {
196+ val detail = error.message ? : error.javaClass.simpleName
197+ return IOException (
198+ " DoH 不可用,请自行更换 DoH。当前端点:${endpoint.rawUrl} ,查询:$host ${queryTypeName(type)} ,原因:$detail " ,
199+ error,
200+ )
196201 }
197202
198203 private fun queryDoh (
0 commit comments