DNSolve is a Dart library that provides an easy way to perform DNS lookups. It supports both forward and reverse DNS lookups, and can be used with different DNS providers.
This project provides a convenient API wrapper for interacting with public DNS services. While it might appear to function as a traditional DNS client, it's essential to note that it operates by sending HTTP GET requests to public DNS API endpoints like Google and Cloudflare.
- âś… Forward DNS lookups (A, AAAA, MX, SRV, TXT, and many more record types)
- âś… Reverse DNS lookups (PTR records)
- âś… Multiple DNS providers (Google, Cloudflare)
- âś… DNSSEC support
- âś… Custom HTTP client support
- âś… Configurable timeouts
- âś… Comprehensive error handling
- âś… Resource management (proper cleanup)
- âś… IPv6 support (including fixed reverse lookup)
- âś… Enhanced record parsing (MX, CAA, SOA, TXT records)
- âś… Batch lookups (parallel queries)
- âś… Response caching (TTL-based)
- âś… Retry mechanism (with exponential backoff)
- âś… Query statistics (success rate, average response time)
- âś… Builder pattern (fluent configuration API)
To install DNSolve, add the following dependency to your pubspec.yaml file:
dependencies:
dnsolve: ^2.0.0import 'package:dnsolve/dnsolve.dart';
Future<void> main() async {
final dnsolve = DNSolve();
try {
final response = await dnsolve.lookup(
'example.com',
type: RecordType.A,
);
if (response.answer?.records != null) {
for (final record in response.answer!.records!) {
print('${record.name}: ${record.data}');
}
}
} finally {
dnsolve.dispose(); // Always dispose when done
}
}import 'dart:developer';
import 'package:dnsolve/dnsolve.dart';
Future<void> main() async {
final dnsolve = DNSolve();
try {
final response = await dnsolve.lookup(
'_xmpp._tcp.vsevex.me',
dnsSec: true,
type: RecordType.srv,
);
if (response.answer?.records != null) {
for (final record in response.answer!.records!) {
log(record.toBind);
}
}
// Access parsed SRV records
if (response.answer?.srvs != null) {
for (final srv in response.answer!.srvs!) {
print('Priority: ${srv.priority}, Port: ${srv.port}, Target: ${srv.target}');
}
}
} finally {
dnsolve.dispose();
}
}import 'package:dnsolve/dnsolve.dart';
Future<void> main() async {
final dnsolve = DNSolve();
try {
// IPv4 reverse lookup
final records = await dnsolve.reverseLookup('8.8.8.8');
for (final record in records) {
print('PTR: ${record.data}');
}
// IPv6 reverse lookup
final ipv6Records = await dnsolve.reverseLookup('2001:4860:4860::8888');
for (final record in ipv6Records) {
print('PTR: ${record.data}');
}
} finally {
dnsolve.dispose();
}
}import 'package:dnsolve/dnsolve.dart';
import 'package:http/http.dart' as http;
Future<void> main() async {
// Use a custom HTTP client with timeout
final client = http.Client();
final dnsolve = DNSolve(client: client);
try {
final response = await dnsolve.lookup(
'example.com',
timeout: Duration(seconds: 10), // Custom timeout
provider: DNSProvider.cloudflare,
);
print('Status: ${response.status}');
} finally {
dnsolve.dispose();
}
}import 'package:dnsolve/dnsolve.dart';
Future<void> main() async {
final dnsolve = DNSolve();
try {
final response = await dnsolve.lookup(
'example.com',
timeout: Duration(seconds: 5),
);
} on TimeoutException catch (e) {
print('Query timed out: ${e.message}');
} on DNSLookupException catch (e) {
print('DNS lookup failed: ${e.message} (Status: ${e.statusCode})');
} on InvalidDomainException catch (e) {
print('Invalid domain: ${e.message}');
} on NetworkException catch (e) {
print('Network error: ${e.message}');
} finally {
dnsolve.dispose();
}
}DNSolve({http.Client? client})Creates a new DNSolve instance. Optionally accepts a custom HTTP client.
Performs a forward DNS lookup.
Future<ResolveResponse> lookup(
String domain, {
bool dnsSec = false,
RecordType type = RecordType.A,
DNSProvider provider = DNSProvider.google,
Duration? timeout,
})Performs multiple DNS lookups in parallel.
Future<List<ResolveResponse>> lookupBatch(
List<String> domains, {
bool dnsSec = false,
RecordType type = RecordType.A,
DNSProvider provider = DNSProvider.google,
Duration? timeout,
})Parameters:
domain: The domain name to lookup (required)dnsSec: Whether to enable DNSSEC (default:false)type: The DNS record type (default:RecordType.A)provider: The DNS provider to use (default:DNSProvider.google)timeout: Timeout duration (default: 30 seconds)
Returns: Future<ResolveResponse>
Throws:
InvalidDomainException: If domain is empty or invalidTimeoutException: If query exceeds timeoutNetworkException: If network error occursDNSLookupException: If DNS query fails
Performs a reverse DNS lookup (PTR record).
Future<List<Record>> reverseLookup(
String ip, {
DNSProvider provider = DNSProvider.google,
Duration? timeout,
})Parameters:
ip: The IP address (IPv4 or IPv6) to lookup (required)provider: The DNS provider to use (default:DNSProvider.google)timeout: Timeout duration (default: 30 seconds)
Returns: Future<List<Record>>
Throws:
InvalidDomainException: If IP address is invalidTimeoutException: If query exceeds timeoutNetworkException: If network error occursDNSLookupException: If DNS query fails
Performs multiple DNS lookups in parallel.
Future<List<ResolveResponse>> lookupBatch(
List<String> domains, {
bool dnsSec = false,
RecordType type = RecordType.A,
DNSProvider provider = DNSProvider.google,
Duration? timeout,
})Gets query statistics if statistics are enabled.
DNSStatistics? get statisticsClears the DNS cache if caching is enabled.
void clearCache()Gets the current cache size if caching is enabled.
int? get cacheSizeDisposes of resources used by this instance. Always call this when done.
void dispose()Creates a builder for configuring a DNSolve instance.
static DNSolveBuilder builder()The following DNS record types are supported:
A- IPv4 addressaaaa- IPv6 addressany- Any record typecaa- Certificate Authority Authorizationcds- Child DScert- Certificatecname- Canonical namedname- Delegation namednskey- DNS Keyds- Delegation Signerhinfo- Host informationipseckey- IPSEC keymx- Mail exchangenaptr- Name Authority Pointerns- Name servernsec- Next Securensec3Param- NSEC3 parametersptr- Pointer (for reverse lookups)rp- Responsible Personrrsig- Resource Record Signaturesoa- Start of Authorityspf- Sender Policy Frameworksrv- Service locatorsshfp- SSH Fingerprinttlsa- TLSA certificatetxt- Text recordwks- Well-known service
DNSProvider.google- Google Public DNSDNSProvider.cloudflare- Cloudflare DNS
Contains the DNS resolution response.
Properties:
status: DNS status code (0 = success)answer:Answerobject containing DNS recordsquestions: List ofQuestionobjectstc,rd,ra,ad,cd: DNS flagscomment: Additional comments
Contains DNS records.
Properties:
records: List ofRecordobjectssrvs: List of parsedSRVRecordobjects (if SRV type)
Represents a single DNS record.
Properties:
name: Domain namerType: Record typettl: Time to livedata: Record data
Methods:
toBind: Returns BIND format string
Represents a parsed SRV record.
Properties:
priority: Priority valueweight: Weight valueport: Port numbertarget: Target hostnamefqdn: Fully qualified domain name
Methods:
sort(): Static method to sort SRV records by priority and weight
Represents a parsed MX (Mail Exchange) record.
Properties:
priority: Priority value (lower is preferred)exchange: Mail exchange hostnamefqdn: Fully qualified domain name
Represents a parsed CAA (Certificate Authority Authorization) record.
Properties:
flags: Flags bytetag: Tag (e.g., "issue", "issuewild")value: Value associated with the tagfqdn: Fully qualified domain name
Represents a parsed SOA (Start of Authority) record.
Properties:
mname: Primary name serverrname: Administrator email (with @ replaced by .)serial: Serial numberrefresh: Refresh interval in secondsretry: Retry interval in secondsexpire: Expire time in secondsminimum: Minimum TTL in secondsfqdn: Fully qualified domain name
Represents a parsed TXT record.
Properties:
text: Text contentfqdn: Fully qualified domain name
Query statistics tracking.
Properties:
totalQueries: Total number of queriessuccessfulQueries: Number of successful queriesfailedQueries: Number of failed queriesaverageResponseTimeMs: Average response time in millisecondssuccessRate: Success rate as a percentage
Methods:
reset(): Resets all statistics
DNSolveException: Base exception classDNSLookupException: DNS query failedNetworkException: Network connectivity errorTimeoutException: Query timeoutInvalidDomainException: Invalid domain or IP addressResponseException: HTTP response errorSRVRecordFormatException: SRV record parsing error
-
Resource Management: You must now call
dispose()when done with aDNSolveinstance:final dnsolve = DNSolve(); try { // Use dnsolve... } finally { dnsolve.dispose(); }
-
Public Classes:
_Record,_Answer, and_Questionare now public (Record,Answer,Question) -
Enum Naming:
RecordType.nsec3PARAMis nowRecordType.nsec3Param -
Exception Handling:
assert()validation is replaced with proper exceptions that throw in production -
Return Types:
reverseLookup()now returnsList<Record>instead ofList<_Record>
- Custom HTTP client support
- Configurable timeouts
- Enhanced error handling with specific exception types
- Fixed IPv6 reverse lookup
- Better input validation
- Enhanced record parsing (MX, CAA, SOA, TXT)
- Batch lookups
- Response caching with TTL support
- Retry mechanism with exponential backoff
- Query statistics tracking
- Builder pattern for configuration
Contributions are welcome! If you have any improvements, bug fixes, or new features to contribute, please create a pull request.
This project is licensed under the MIT License - see the LICENSE file for details.