supadns 1.0.0 copy "supadns: ^1.0.0" to clipboard
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.

  1. System DNS First: Always tries standard dart:io HttpClient first. If it works, overhead is ~0ms.
  2. Failure Detection: Catches SocketException and Failed host lookup specifically for *.supabase.co domains.
  3. DoH Fallback: Resolves the IPv4 address via https://dns.quad9.net/dns-query (RFC 1035 wire-format).
  4. 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. The SecureSocket is then passed into HttpClient.connectionFactory to route the HTTP protocols.

Requirements #

  • Dart ≥ 3.0

License #

MIT

1
likes
60
points
10
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Bypass blocked DNS for Supabase using DNS-over-HTTPS. A drop-in client that preserves TLS SNI when your ISP poisons Supabase domains.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

http, supabase

More

Packages that depend on supadns