supadns 1.0.0
supadns: ^1.0.0 copied to clipboard
Bypass blocked DNS for Supabase using DNS-over-HTTPS. A drop-in client that preserves TLS SNI when your ISP poisons Supabase domains.
SupaDNS (Dart / Flutter) #
Bypass blocked DNS for Supabase using DNS-over-HTTPS (DoH).
If your ISP blocks *.supabase.co via DNS poisoning, standard Supabase apps will silently fail with SocketException: Failed host lookup. supadns provides a drop-in replacement client that detects these failures and transparently routes the connection through DNS-over-HTTPS (Quad9 and Cloudflare) while preserving strict TLS SNI validation.
Install #
Add it to your pubspec.yaml:
dependencies:
supadns: ^1.0.0
supabase: ^2.0.0
Quick Start (with supabase) #
SupaDNS provides a createSmartClient that acts exactly like the standard SupabaseClient constructor, but it intercepts requests to handle DoH fallback automatically.
import 'package:supadns/supadns.dart';
void main() async {
// Use this instead of the standard SupabaseClient constructor
final supabase = createSmartClient(
'https://myproject.supabase.co',
'your-anon-key',
);
// All APIs work transparently: Auth, REST, Storage, Functions
final data = await supabase.from('todos').select('*');
print(data);
}
Using with standard HTTP #
If you are just making raw HTTP requests, you can use the smartFetch wrapper:
import 'package:supadns/supadns.dart';
import 'dart:convert';
void main() async {
final headers = {
'apikey': 'your-anon-key',
'Authorization': 'Bearer your-anon-key'
};
// Automatically handles DoH fallback if DNS is poisoned/blocked
final resp = await smartFetch(
'https://myproject.supabase.co/rest/v1/todos?select=*',
headers: headers,
);
print('Status: ${resp.statusCode}');
final body = await resp.transform(utf8.decoder).join();
print(body);
}
Standalone DoH Resolution #
If you just need to bypass DNS and get the IPv4 address:
import 'package:supadns/supadns.dart';
void main() async {
final ip = await resolveDoH('myproject.supabase.co');
print('Resolved: $ip'); // -> 76.76.21.21
}
How It Works (TLS SNI Preservation) #
The hardest part of direct IP connection with Cloudflare is preserving TLS SNI. Dart's standard HttpClient does not allow decoupling DNS resolution from the Host header easily.
- System DNS First: Always tries standard
dart:io HttpClientfirst. If it works, overhead is ~0ms. - Failure Detection: Catches
SocketExceptionandFailed host lookupspecifically for*.supabase.codomains. - DoH Fallback: Resolves the IPv4 address via
https://dns.quad9.net/dns-query(RFC 1035 wire-format). - TLS SNI: Connects a raw TCP socket to the resolved IP, then upgrades it to TLS using
SecureSocket.secure(socket, host: original_host). This ensures Cloudflare's strict edge SSL terminates correctly. TheSecureSocketis then passed intoHttpClient.connectionFactoryto route the HTTP protocols.
Requirements #
- Dart ≥ 3.0
License #
MIT