dnsolve 3.0.0 copy "dnsolve: ^3.0.0" to clipboard
dnsolve: ^3.0.0 copied to clipboard

Pure Dart library that provides an easy way to perform DNS lookups using native resolution via FFI

example/main.dart

// ignore_for_file: avoid_print

import 'package:dnsolve/dnsolve.dart';

/// Comprehensive example demonstrating all DNSolve v3.0.0 features
Future<void> main() async {
  print('=== DNSolve v3.0.0 Feature Examples ===\n');

  // Example 1: Basic Forward Lookup (system DNS)
  await exampleBasicLookup();

  // Example 2: SRV Record Lookup with Parsed Records
  await exampleSRVLookup();

  // Example 3: Reverse DNS Lookup (IPv4 and IPv6)
  await exampleReverseLookup();

  // Example 4: Custom DNS Server and Timeout
  await exampleCustomServer();

  // Example 5: Batch Lookups
  await exampleBatchLookups();

  // Example 6: Caching and Statistics
  await exampleCachingAndStatistics();

  // Example 7: Builder Pattern
  await exampleBuilderPattern();

  // Example 8: Enhanced Record Parsing (MX, CAA, SOA, TXT)
  await exampleEnhancedRecordParsing();

  // Example 9: Error Handling
  await exampleErrorHandling();

  print('\n=== All Examples Completed ===');
}

/// Example 1: Basic Forward Lookup
Future<void> exampleBasicLookup() async {
  print('1. Basic Forward Lookup (system DNS)');
  print('-' * 40);

  final dnsolve = DNSolve();

  try {
    final response = await dnsolve.lookup(
      'example.com',
    );

    print('Domain: example.com');
    print('Status: ${response.status}');
    if (response.answer?.records != null) {
      for (final record in response.answer!.records!) {
        print('  ${record.name}: ${record.data} (TTL: ${record.ttl})');
      }
    }
  } finally {
    dnsolve.dispose();
  }

  print('');
}

/// Example 2: SRV Record Lookup with Parsed Records
Future<void> exampleSRVLookup() async {
  print('2. SRV Record Lookup with Parsed Records');
  print('-' * 40);

  final dnsolve = DNSolve();

  try {
    final response = await dnsolve.lookup(
      '_xmpp._tcp.vsevex.me',
      dnsSec: true,
      type: RecordType.srv,
      timeout: const Duration(seconds: 10),
    );

    print('SRV Lookup: _xmpp._tcp.vsevex.me');
    print('Status: ${response.status}');

    // Raw records
    if (response.answer?.records != null) {
      print('\nRaw Records:');
      for (final record in response.answer!.records!) {
        print('  ${record.toBind}');
      }
    }

    // Parsed SRV records
    if (response.answer?.srvs != null) {
      print('\nParsed SRV Records:');
      for (final srv in response.answer!.srvs!) {
        print(
          '  Priority: ${srv.priority}, Weight: ${srv.weight}, '
          'Port: ${srv.port}, Target: ${srv.target}',
        );
      }

      // Sort SRV records
      final sorted = SRVRecord.sort(response.answer!.srvs!);
      print('\nSorted SRV Records (by priority and weight):');
      for (final srv in sorted) {
        print(
          '  Priority: ${srv.priority}, Weight: ${srv.weight}, '
          'Port: ${srv.port}',
        );
      }
    }
  } on DNSolveException catch (e) {
    print('DNS error: $e');
  } finally {
    dnsolve.dispose();
  }

  print('');
}

/// Example 3: Reverse DNS Lookup (IPv4 and IPv6)
Future<void> exampleReverseLookup() async {
  print('3. Reverse DNS Lookup');
  print('-' * 40);

  final dnsolve = DNSolve();

  try {
    // IPv4 reverse lookup
    print('IPv4 Reverse Lookup: 8.8.8.8');
    final ipv4Records = await dnsolve.reverseLookup('8.8.8.8');
    for (final record in ipv4Records) {
      print('  PTR: ${record.data}');
    }

    // IPv6 reverse lookup
    print('\nIPv6 Reverse Lookup: 2001:4860:4860::8888');
    try {
      final ipv6Records = await dnsolve.reverseLookup('2001:4860:4860::8888');
      for (final record in ipv6Records) {
        print('  PTR: ${record.data}');
      }
    } on DNSolveException catch (e) {
      print('  Note: IPv6 reverse lookup may not always return results: $e');
    }
  } finally {
    dnsolve.dispose();
  }

  print('');
}

/// Example 4: Custom DNS Server and Timeout
Future<void> exampleCustomServer() async {
  print('4. Custom DNS Server and Timeout');
  print('-' * 40);

  // Use Cloudflare DNS server
  final dnsolve = DNSolve(server: DNSServer.cloudflare);

  try {
    final response = await dnsolve.lookup(
      'google.com',
      timeout: const Duration(seconds: 5),
    );

    print('Server: Cloudflare (1.1.1.1)');
    print('Timeout: 5 seconds');
    print('Status: ${response.status}');
    if (response.answer?.records != null) {
      print('Records found: ${response.answer!.records!.length}');
    }
  } finally {
    dnsolve.dispose();
  }

  // Per-query server override
  final dnsolve2 = DNSolve();
  try {
    final response = await dnsolve2.lookup(
      'google.com',
      server: DNSServer.google,
    );
    print('\nPer-query override to Google DNS:');
    print('Status: ${response.status}');
  } finally {
    dnsolve2.dispose();
  }

  // Custom DNS server
  final dnsolve3 = DNSolve(server: const DNSServer.custom('9.9.9.9'));
  try {
    final response = await dnsolve3.lookup('example.com');
    print('\nCustom server (Quad9 - 9.9.9.9):');
    print('Status: ${response.status}');
  } finally {
    dnsolve3.dispose();
  }

  print('');
}

/// Example 5: Batch Lookups
Future<void> exampleBatchLookups() async {
  print('5. Batch Lookups (Parallel Queries)');
  print('-' * 40);

  final dnsolve = DNSolve();

  try {
    final domains = ['example.com', 'google.com', 'github.com'];
    print('Querying: ${domains.join(', ')}');

    final responses = await dnsolve.lookupBatch(
      domains,
    );

    for (var i = 0; i < domains.length; i++) {
      final response = responses[i];
      print('\n${domains[i]}:');
      print('  Status: ${response.status}');
      if (response.answer?.records != null) {
        print('  Records: ${response.answer!.records!.length}');
        if (response.answer!.records!.isNotEmpty) {
          print('  First IP: ${response.answer!.records!.first.data}');
        }
      }
    }
  } finally {
    dnsolve.dispose();
  }

  print('');
}

/// Example 6: Caching and Statistics
Future<void> exampleCachingAndStatistics() async {
  print('6. Caching and Statistics');
  print('-' * 40);

  final dnsolve = DNSolve(
    enableCache: true,
    cacheMaxSize: 50,
    enableStatistics: true,
    maxRetries: 2,
  );

  try {
    const domain = 'example.com';

    // First lookup - hits the network
    print('First lookup (network):');
    final stopwatch = Stopwatch()..start();
    await dnsolve.lookup(domain);
    stopwatch.stop();
    print('  Time: ${stopwatch.elapsedMilliseconds}ms');
    print('  Cache size: ${dnsolve.cacheSize}');

    // Second lookup - served from cache
    print('\nSecond lookup (cache):');
    stopwatch.reset();
    stopwatch.start();
    await dnsolve.lookup(domain);
    stopwatch.stop();
    print('  Time: ${stopwatch.elapsedMilliseconds}ms');
    print('  Cache size: ${dnsolve.cacheSize}');

    // Check statistics
    final stats = dnsolve.statistics;
    if (stats != null) {
      print('\nStatistics:');
      print('  Total queries: ${stats.totalQueries}');
      print('  Successful: ${stats.successfulQueries}');
      print('  Failed: ${stats.failedQueries}');
      print(
        '  Average time: ${stats.averageResponseTimeMs.toStringAsFixed(2)}ms',
      );
      print(
        '  Success rate: ${stats.successRate.toStringAsFixed(2)}%',
      );
    }

    // Clear cache
    dnsolve.clearCache();
    print('\nCache cleared. New cache size: ${dnsolve.cacheSize}');
  } finally {
    dnsolve.dispose();
  }

  print('');
}

/// Example 7: Builder Pattern
Future<void> exampleBuilderPattern() async {
  print('7. Builder Pattern');
  print('-' * 40);

  final dnsolve = DNSolve.builder()
      .withServer(DNSServer.cloudflare)
      .withCache()
      .withStatistics()
      .withRetries(3)
      .withRetryDelay(const Duration(milliseconds: 500))
      .build();

  try {
    print('Configuration:');
    print('  Server: Cloudflare (1.1.1.1)');
    print('  Cache: enabled (max size: 100)');
    print('  Statistics: enabled');
    print('  Max retries: 3');
    print('  Retry delay: 500ms');

    final response = await dnsolve.lookup('example.com');
    print('\nLookup successful:');
    print('  Status: ${response.status}');
    print('  Records: ${response.answer?.records?.length ?? 0}');
  } finally {
    dnsolve.dispose();
  }

  print('');
}

/// Example 8: Enhanced Record Parsing (MX, CAA, SOA, TXT)
Future<void> exampleEnhancedRecordParsing() async {
  print('8. Enhanced Record Parsing');
  print('-' * 40);

  final dnsolve = DNSolve();

  try {
    // MX Records
    print('MX Records:');
    try {
      final mxResponse = await dnsolve.lookup(
        'google.com',
        type: RecordType.mx,
      );
      if (mxResponse.answer?.mxs != null) {
        for (final mx in mxResponse.answer!.mxs!) {
          print(
            '  Priority: ${mx.priority}, Exchange: ${mx.exchange}',
          );
        }
      }
    } on DNSolveException catch (e) {
      print('  Error: $e');
    }

    // TXT Records
    print('\nTXT Records:');
    try {
      final txtResponse = await dnsolve.lookup(
        'google.com',
        type: RecordType.txt,
      );
      if (txtResponse.answer?.txts != null) {
        for (final txt in txtResponse.answer!.txts!) {
          print('  Text: ${txt.text}');
        }
      }
    } on DNSolveException catch (e) {
      print('  Error: $e');
    }

    // SOA Records
    print('\nSOA Records:');
    try {
      final soaResponse = await dnsolve.lookup(
        'example.com',
        type: RecordType.soa,
      );
      if (soaResponse.answer?.soas != null) {
        for (final soa in soaResponse.answer!.soas!) {
          print('  Primary NS: ${soa.mname}');
          print('  Admin: ${soa.rname}');
          print('  Serial: ${soa.serial}');
          print('  Refresh: ${soa.refresh}s');
        }
      }
    } on DNSolveException catch (e) {
      print('  Error: $e');
    }

    // CAA Records
    print('\nCAA Records:');
    try {
      final caaResponse = await dnsolve.lookup(
        'example.com',
        type: RecordType.caa,
      );
      if (caaResponse.answer?.caas != null) {
        for (final caa in caaResponse.answer!.caas!) {
          print('  Flags: ${caa.flags}, Tag: ${caa.tag}, Value: ${caa.value}');
        }
      } else {
        print('  No CAA records found');
      }
    } on DNSolveException catch (e) {
      print('  Error: $e');
    }
  } finally {
    dnsolve.dispose();
  }

  print('');
}

/// Example 9: Error Handling
Future<void> exampleErrorHandling() async {
  print('9. Error Handling');
  print('-' * 40);

  final dnsolve = DNSolve();

  try {
    // Invalid domain
    print('Testing invalid domain:');
    try {
      await dnsolve.lookup('');
    } on InvalidDomainException catch (e) {
      print('  Caught InvalidDomainException: ${e.message}');
    }

    // Non-existent domain
    print('\nTesting non-existent domain:');
    try {
      await dnsolve.lookup(
        'this-domain-definitely-does-not-exist-12345.com',
        timeout: const Duration(seconds: 5),
      );
    } on DNSLookupException catch (e) {
      print('  Caught DNSLookupException: ${e.message}');
      if (e.statusCode != null) {
        print('  Status Code: ${e.statusCode}');
      }
    } on TimeoutException catch (e) {
      print('  Caught TimeoutException: ${e.message}');
    } on NativeException catch (e) {
      print('  Caught NativeException: ${e.message}');
    }

    // Invalid IP for reverse lookup
    print('\nTesting invalid IP:');
    try {
      await dnsolve.reverseLookup('invalid.ip.address');
    } on DNSLookupException catch (e) {
      print('  Caught DNSLookupException: ${e.message}');
    } on NativeException catch (e) {
      print('  Caught NativeException: ${e.message}');
    }
  } finally {
    dnsolve.dispose();
  }

  print('');
}
2
likes
160
points
2.73k
downloads

Documentation

API reference

Publisher

verified publishervsevex.me

Weekly Downloads

Pure Dart library that provides an easy way to perform DNS lookups using native resolution via FFI

Repository (GitHub)
View/report issues

Topics

#network #dns #ffi

License

MIT (license)

Dependencies

ffi

More

Packages that depend on dnsolve