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
1.93k
downloads

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

Documentation

API reference

License

MIT (license)

Dependencies

ffi

More

Packages that depend on dnsolve