diff --git a/lib/services/http/doh/doh_resolver.dart b/lib/services/http/doh/doh_resolver.dart index e545662a..e56efec3 100644 --- a/lib/services/http/doh/doh_resolver.dart +++ b/lib/services/http/doh/doh_resolver.dart @@ -105,8 +105,7 @@ class DoHResolver { } } - /// Resolve using specific provider via bootstrap IP - /// This avoids circular DNS dependency by connecting to bootstrap IP directly + /// Resolve using specific provider via hostname static Future> _resolveFromProvider( String host, DoHProvider provider, { @@ -119,58 +118,34 @@ class DoHResolver { return []; } - final uri = Uri.parse(provider.url); - final providerHost = uri.host; - - // Validate bootstrap IPs format - final validBootstrapIps = provider.bootstrapIPs - .where((ip) => _isValidIp(ip)) - .toList(); - if (validBootstrapIps.isEmpty) { - _log('No valid bootstrap IPs for ${provider.name}', isError: true); - return []; - } - - // Try each bootstrap IP until one succeeds - for (int i = 0; i < validBootstrapIps.length; i++) { - final bootstrapIp = validBootstrapIps[i]; - try { - final result = await _queryDoHViaBootstrapIp( - host, - provider, - bootstrapIp, - providerHost, - recordType, - ); - if (result.isNotEmpty) { - _log( - 'Resolved $host via ${provider.name} (bootstrap IP $i+1/${validBootstrapIps.length})', - ); - return result; - } - } catch (e) { - _log('Bootstrap IP $i failed for ${provider.name}: $e'); - continue; + try { + final directResult = await _queryDoHViaHostname( + host, + provider, + recordType, + ); + if (directResult.isNotEmpty) { + _log('Resolved $host via ${provider.name} (hostname mode)'); + stats.successCount++; + return directResult; + } + } catch (e) { + _log('Hostname mode failed for ${provider.name}: $e'); + stats.failureCount++; + stats.lastFailure = DateTime.now(); + if (stats.failureCount >= 3) { + stats.isCircuitOpen = true; + _log('Circuit breaker opened for ${provider.name}', isError: true); } - } - - stats.failureCount++; - stats.lastFailure = DateTime.now(); - // Open circuit after 3 consecutive failures - if (stats.failureCount >= 3) { - stats.isCircuitOpen = true; - _log('Circuit breaker opened for ${provider.name}', isError: true); } return []; } - /// Query DoH via specific bootstrap IP (direct IP connection, no DNS lookup) - static Future> _queryDoHViaBootstrapIp( + /// Query DoH by provider hostname (relies on platform DNS for provider host) + static Future> _queryDoHViaHostname( String targetHost, DoHProvider provider, - String bootstrapIp, - String providerHost, String recordType, ) async { final uri = Uri.parse(provider.url); @@ -178,19 +153,16 @@ class DoHResolver { client.connectionTimeout = _requestTimeout; try { - // Create request with bootstrap IP instead of hostname final request = await client.getUrl( Uri( scheme: uri.scheme, - host: bootstrapIp, // Use bootstrap IP directly + host: uri.host, port: uri.port, path: uri.path, query: 'name=$targetHost&type=$recordType', ), ); - // Set Host header to the actual provider hostname (required for HTTPS SNI) - request.headers.set('Host', providerHost); request.headers.set('Accept', 'application/dns-json'); request.headers.set('User-Agent', 'Mangayomi/1.0'); @@ -201,18 +173,10 @@ class DoHResolver { return _parseDoHResponse(body); } - _log('HTTP ${response.statusCode} from $bootstrapIp (${provider.name})'); + _log('HTTP ${response.statusCode} from hostname (${provider.name})'); return []; - } on SocketException { - // Connection failed with this bootstrap IP - _log('Socket error on $bootstrapIp'); - rethrow; - } on TimeoutException { - // Timeout with this bootstrap IP - _log('Timeout on $bootstrapIp'); - rethrow; } finally { - client.close(); + client.close(force: true); } } @@ -272,6 +236,7 @@ class DoHResolver { return null; }) .whereType() + .where(_isValidIp) .toList(); if (ips.isNotEmpty) { diff --git a/pubspec.lock b/pubspec.lock index c20fb867..ab8688e9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1699,26 +1699,26 @@ packages: dependency: transitive description: name: test - sha256: "77cc98ea27006c84e71a7356cf3daf9ddbde2d91d84f77dbfe64cf0e4d9611ae" + sha256: "54c516bbb7cee2754d327ad4fca637f78abfc3cbcc5ace83b3eda117e42cd71a" url: "https://pub.dev" source: hosted - version: "1.28.0" + version: "1.29.0" test_api: dependency: transitive description: name: test_api - sha256: "19a78f63e83d3a61f00826d09bc2f60e191bf3504183c001262be6ac75589fb8" + sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" url: "https://pub.dev" source: hosted - version: "0.7.8" + version: "0.7.9" test_core: dependency: transitive description: name: test_core - sha256: f1072617a6657e5fc09662e721307f7fb009b4ed89b19f47175d11d5254a62d4 + sha256: "394f07d21f0f2255ec9e3989f21e54d3c7dc0e6e9dbce160e5a9c1a6be0e2943" url: "https://pub.dev" source: hosted - version: "0.6.14" + version: "0.6.15" time: dependency: transitive description: