DnsClientX 0.5.0
Prefix ReservedSee the version list below for details.
dotnet add package DnsClientX --version 0.5.0
NuGet\Install-Package DnsClientX -Version 0.5.0
<PackageReference Include="DnsClientX" Version="0.5.0" />
<PackageVersion Include="DnsClientX" Version="0.5.0" />
<PackageReference Include="DnsClientX" />
paket add DnsClientX --version 0.5.0
#r "nuget: DnsClientX, 0.5.0"
#:package DnsClientX@0.5.0
#addin nuget:?package=DnsClientX&version=0.5.0
#tool nuget:?package=DnsClientX&version=0.5.0
DnsClientX - DnsClient for .NET and PowerShell
DnsClientX is available as NuGet from the Nuget Gallery and as PowerShell module from PSGallery
π¦ NuGet Package
<p align="center">
</p>
π» PowerShell Module
<p align="center">
</p>
π οΈ Project Information
<p align="center">
</p>
π¨βπ» Author & Social
<p align="center">
</p>
What it's all about
DnsClientX is an async C# library for DNS over UDP, TCP, HTTPS (DoH), and TLS (DoT). It also has a PowerShell module that can be used to query DNS records. It provides a simple way to query DNS records using multiple DNS providers. It supports multiple DNS record types and parallel queries. It's available for .NET 6, .NET 7, .NET 8, .NET Standard 2.0, and .NET 4.7.2.
It provides querying multiple DNS Providers.
Endpoint | DoH | DoQ | DoT | UDP | TCP | DnsCrypt | ODoH |
---|---|---|---|---|---|---|---|
System | β | ||||||
SystemTcp | β | ||||||
Cloudflare | β | ||||||
CloudflareWireFormat | β | ||||||
CloudflareWireFormatPost | β | ||||||
CloudflareSecurity | β | ||||||
CloudflareFamily | β | ||||||
CloudflareQuic | β | ||||||
CloudflareOdoh | β | ||||||
β | |||||||
GoogleWireFormat | β | ||||||
GoogleWireFormatPost | β | ||||||
GoogleQuic | β | ||||||
AdGuard | β | ||||||
AdGuardFamily | β | ||||||
AdGuardNonFiltering | β | ||||||
Quad9 | β | ||||||
Quad9ECS | β | ||||||
Quad9Unsecure | β | ||||||
OpenDNS | β | ||||||
OpenDNSFamily | β | ||||||
DnsCryptCloudflare | β | ||||||
DnsCryptQuad9 | β | ||||||
DnsCryptRelay | β | ||||||
RootServer | β | β |
If you want to learn about DNS:
We try to unify the responses as much as possible for common use cases by translating on the fly. This is because different providers do not store it always the same way. If you find discrepancies please open an issue or better pull request.
Supported .NET Versions
This library supports multiple NET versions:
- .NET 6
- No dependencies
- .NET 7
- No dependencies
- .NET 8
- No dependencies
- .NET Standard 2.0
- System.Text.Json
- .NET 4.7.2
- System.Text.Json
Build Status
Features
- Supports multiple built-in DNS Providers (System, Cloudflare, Google, Quad9, OpenDNS, etc.)
- Supports both JSON and Wireformat
- Supports DNS over HTTPS (DoH) using GET and POST methods
- Supports DNS over TLS (DoT)
- Supports DNS over UDP, and switches to TCP if needed
- Supports DNS over TCP
- Supports DNSSEC
- Supports multiple DNS record types
- Supports parallel queries
- No external dependencies on .NET 6, .NET 7 and .NET 8
- Minimal dependencies on .NET Standard 2.0 and .NET 4.7.2
- Implements IDisposable to release cached HttpClient resources
- Multi-line record data normalized to use
\n
line endings - Supports DNS Service Discovery (DNS-SD)
Understanding DNS Query Behavior
Different Results from Different Providers
When querying DNS records using DnsClientX, you may notice that different DNS providers can return different results for the same domain. This is normal behavior and occurs for several legitimate reasons:
Content Delivery Networks (CDNs)
Many popular websites use CDNs (like Cloudflare, Akamai, AWS CloudFront) to serve content from servers geographically closer to users. CDN-backed domains will return different IP addresses based on:
- Geographic location: Providers route queries to the nearest edge server
- Provider routing policies: Different DNS providers may have different relationships with CDNs
- Load balancing: CDNs dynamically distribute traffic across multiple servers
Example: A domain like www.example.com
might return:
- From Cloudflare:
23.47.124.71
,23.47.124.85
- From OpenDNS:
185.225.251.105
,185.225.251.40
Both responses are correct - they're just optimized for different network paths.
DNS Provider Characteristics
Different DNS providers have distinct characteristics:
- Cloudflare (1.1.1.1): Privacy-focused, fast, global Anycast network
- Google (8.8.8.8): Extensive caching, Google's global infrastructure
- Quad9 (9.9.9.9): Security-focused, blocks malicious domains
- OpenDNS: Content filtering options, enterprise features
Provider | Hostname | Request Format |
---|---|---|
Cloudflare | 1.1.1.1 / 1.0.0.1 |
JSON |
8.8.8.8 / 8.8.4.4 |
JSON | |
Quad9 | dns.quad9.net |
Wire |
OpenDNS | 208.67.222.222 / 208.67.220.220 |
Wire |
AdGuard | dns.adguard.com |
Wire |
AdGuardFamily | dns-family.adguard.com |
Wire |
AdGuardNonFiltering | dns-unfiltered.adguard.com |
Wire |
These differences can result in:
- Varying response times (typically 10-500ms)
- Different cached TTL values
- Different IP addresses for CDN domains
- Slightly different DNSSEC validation results
When to Expect Consistent Results
You should expect consistent results for:
- Non-CDN domains: Simple domains with static IP assignments
- Infrastructure domains: DNS servers, mail servers, etc.
- Record types other than A/AAAA: TXT, MX, NS, DS records are usually consistent
When to Expect Different Results
You should expect different results for:
- CDN-backed websites: Major websites, cloud services, media platforms
- Geographically distributed services: Global services with regional presence
- Load-balanced applications: Services with multiple server endpoints
Performance Considerations
Response Times
DNS query response times can vary significantly:
- Local/ISP DNS: 1-50ms (but may have outdated records)
- Public DNS providers: 10-200ms (usually more up-to-date)
- International queries: 100-500ms (depending on geographic distance)
Timeout and Retry Behavior
DnsClientX implements intelligent timeout and retry logic:
- Default timeout: 1000ms (1 second) - optimized for fast responses
- Automatic retry: Failed queries are retried with exponential backoff
- Provider fallback: Can automatically switch between providers
- Protocol fallback: UDP β TCP β HTTPS/TLS as needed
Best Practices for Testing
When testing DNS resolution:
- Use stable domains for consistency tests (e.g.,
google.com
,github.com
) - Use CDN domains to test geographic/provider differences
- Test multiple record types (A, AAAA, TXT, MX, NS, DS)
- Allow for reasonable response time variation (50-500ms)
- Validate structure, not exact content for CDN domains
Troubleshooting Common Issues
"Different IP addresses returned"
- β Normal for CDN domains - indicates proper geographic optimization
- β οΈ Investigate for non-CDN domains - may indicate DNS propagation issues
"Slow response times"
- Check network connectivity to the DNS provider
- Consider using geographically closer DNS servers
- Verify firewall/proxy settings aren't interfering
"Intermittent failures"
- Enable retry logic and exponential backoff
- Test with multiple DNS providers
- Check for rate limiting or blocking
This behavior is by design and reflects the modern, distributed nature of internet infrastructure. DnsClientX provides tools to work effectively with this reality while maintaining reliable DNS resolution.
System DNS Fallback Mechanism
DnsClientX provides robust system DNS resolution through DnsEndpoint.System
(UDP) and DnsEndpoint.SystemTcp
(TCP) endpoints. These endpoints automatically discover and use your system's configured DNS servers with intelligent cross-platform fallback behavior.
How System DNS Discovery Works
1. Windows and Cross-Platform (.NET)
Primary Method: Network Interface Detection
- Enumerates all active network interfaces using
NetworkInterface.GetAllNetworkInterfaces()
- Prioritizes interfaces with default gateways (internet-connected interfaces)
- Extracts DNS server addresses from interface properties
- Filters out invalid addresses (link-local, multicast, etc.)
- Fallback: If no DNS servers found from gateway interfaces, checks all active interfaces
2. Unix/Linux Systems
Fallback Method: /etc/resolv.conf
Parsing
- If network interface enumeration fails or returns no results
- Reads and parses
/etc/resolv.conf
file - Extracts
nameserver
entries - Validates IP addresses and formats them properly
- Handles both IPv4 and IPv6 addresses
3. Final Safety Net
Public DNS Fallback: If no system DNS servers are discovered
- Cloudflare Primary:
1.1.1.1
- Google Primary:
8.8.8.8
- Ensures DNS resolution always works, even in misconfigured environments
Address Validation and Formatting
The system applies intelligent filtering to ensure reliable DNS servers:
IPv4 Filtering
- β Valid: Public and private IP ranges
- β Filtered: Link-local addresses (
169.254.x.x
) - β Filtered: Loopback addresses
IPv6 Filtering
- β Valid: Global and unique local addresses
- β Filtered: Link-local addresses (
fe80::
) - β Filtered: Multicast addresses
- β Filtered: Site-local addresses (
fec0::
- deprecated) - Auto-formatting: Removes zone identifiers (
%15
) and adds brackets ([::1]
)
Protocol Support
System UDP (DnsEndpoint.System
)
- Primary protocol: DNS over UDP (port 53)
- Automatic fallback: Switches to TCP when UDP packet size limit exceeded
- Timeout: 1000ms default (configurable)
- Best for: General DNS queries, fastest response times
System TCP (DnsEndpoint.SystemTcp
)
- Primary protocol: DNS over TCP (port 53)
- Connection management: Efficient connection pooling
- Timeout: 1000ms default (configurable)
- Best for: Large responses, firewall-restricted environments
Platform-Specific Behavior
Platform | Primary Method | Fallback Method | Final Fallback |
---|---|---|---|
Windows | Network Interface APIs | (Not applicable) | Public DNS |
Linux | Network Interface APIs | /etc/resolv.conf |
Public DNS |
macOS | Network Interface APIs | /etc/resolv.conf |
Public DNS |
Docker/Container | Network Interface APIs | /etc/resolv.conf |
Public DNS |
Example Usage
// Use system DNS with UDP (auto-fallback to TCP)
var response = await ClientX.QueryDns("google.com", DnsRecordType.A, DnsEndpoint.System);
// Use system DNS with TCP only
var response = await ClientX.QueryDns("google.com", DnsRecordType.A, DnsEndpoint.SystemTcp);
// Get system DNS servers programmatically (cached)
var systemDnsServers = SystemInformation.GetDnsFromActiveNetworkCard();
// Refresh the cache when network configuration changes
var refreshedDnsServers = SystemInformation.GetDnsFromActiveNetworkCard(refresh: true);
Advantages of System DNS
- Respects local configuration: Uses DNS servers configured by network admin/DHCP
- Corporate environment friendly: Works with internal DNS servers and split-horizon DNS
- VPN compatibility: Automatically uses VPN-provided DNS servers
- No external dependencies: Works even when public DNS is blocked
- Platform native: Leverages OS-specific network configuration
Troubleshooting System DNS
Common Issues and Solutions
"No DNS servers found"
- Check network connectivity (
ipconfig /all
on Windows,cat /etc/resolv.conf
on Linux) - Verify network interfaces are up and have gateways
- Falls back to public DNS (1.1.1.1, 8.8.8.8) automatically
"Slow response times"
- System DNS may be slower than public DNS providers
- Consider using specific endpoints like
DnsEndpoint.Cloudflare
for better performance - Check if system DNS servers are geographically distant
"Resolution failures in containers"
- Ensure container has proper network configuration
- Docker containers should inherit host DNS or have DNS configured
/etc/resolv.conf
should be readable in Linux containers
The system DNS endpoints provide the most compatible and network-environment-aware DNS resolution, making them excellent default choices for applications that need to work across diverse network configurations.
TO DO
This library is still in development and there are things that need to be done, tested and fixed. If you would like to help, please do so by opening an issue or a pull request. Things may and will change, as I'm not quite sure what I am doing π
- Add more providers
- Add more tests
- Go thru all additional parameters and make sure they have proper responses
Usage in .NET
There are multiple ways to use DnsClientX.
using DnsClientX;
Below are some examples.
Querying DNS over HTTPS via provided hostname that uses /dns-query endpoint and JSON format
var data = await ClientX.QueryDns("evotec.pl", DnsRecordType.A, "1.1.1.1", DnsRequestFormat.JSON);
data.Answers
Querying DNS over HTTPS via defined endpoint using QueryDns
var data = await ClientX.QueryDns("evotec.pl", DnsRecordType.A, DnsEndpoint.CloudflareWireFormat);
data.Answers
Querying DNS over HTTPS via full Uri using QueryDNS and JSON format
var data = await ClientX.QueryDns("evotec.pl", DnsRecordType.A, new Uri("https://1.1.1.1/dns-query"), DnsRequestFormat.JSON);
data.Answers
Customizing HTTP settings
using var client = new ClientX(DnsEndpoint.Cloudflare, userAgent: "MyApp/1.0", httpVersion: new Version(1, 1));
You can also modify client.EndpointConfiguration.UserAgent
and client.EndpointConfiguration.HttpVersion
after construction.
Building a client with ClientXBuilder
using var client = new ClientXBuilder()
.WithEndpoint(DnsEndpoint.Cloudflare)
.WithTimeout(2000)
.Build();
Using a custom endpoint
using var client = new ClientX(DnsEndpoint.Custom);
client.EndpointConfiguration.Hostname = "1.1.1.1";
client.EndpointConfiguration.RequestFormat = DnsRequestFormat.DnsOverHttpsJSON;
client.EndpointConfiguration.BaseUri = new Uri($"https://{client.EndpointConfiguration.Hostname}/dns-query");
Querying DNS over QUIC via Cloudflare
var data = await ClientX.QueryDns("evotec.pl", DnsRecordType.A, DnsEndpoint.CloudflareQuic);
data.Answers
Querying DS record with DNSSEC
using var client = new ClientX(DnsEndpoint.Cloudflare);
var ds = await client.Resolve("evotec.pl", DnsRecordType.DS, requestDnsSec: true);
ds.DisplayToConsole();
Resolving via DNS root servers
var response = await ClientX.QueryDns("evotec.pl", DnsRecordType.A, DnsEndpoint.RootServer);
response.Answers.DisplayToConsole();
Querying DNS over HTTPS via defined endpoint using ResolveAll
using var client = new ClientX(DnsEndpoint.OpenDNS);
var data = await client.ResolveAll(domainName, type);
Because ClientX
implements IDisposable
, wrapping it in a using
statement ensures internal HttpClient
instances are released.
Querying DNS over HTTPS with single endpoint using ResolveAll
using var client = new ClientX(DnsEndpoint.OpenDNS);
var data = await client.ResolveAll(domainName, type);
data
Querying DNS over HTTPS with multiple endpoints using Resolve
var dnsEndpoints = new List<DnsEndpoint> {
DnsEndpoint.Cloudflare,
DnsEndpoint.CloudflareSecurity,
DnsEndpoint.CloudflareFamily,
DnsEndpoint.CloudflareWireFormat,
DnsEndpoint.Google,
DnsEndpoint.Quad9,
DnsEndpoint.Quad9ECS,
DnsEndpoint.Quad9Unsecure,
DnsEndpoint.OpenDNS,
DnsEndpoint.OpenDNSFamily
};
// List of endpoints to exclude
var excludeEndpoints = new List<DnsEndpoint> {
};
var domains = new List<string> {
"github.com",
"microsoft.com",
"evotec.xyz"
};
// List of record types to query
var recordTypes = new List<DnsRecordType> {
DnsRecordType.A,
DnsRecordType.TXT,
DnsRecordType.AAAA,
DnsRecordType.MX,
DnsRecordType.NS,
DnsRecordType.SOA,
DnsRecordType.DS,
DnsRecordType.DNSKEY,
DnsRecordType.NSEC
};
foreach (var endpoint in dnsEndpoints) {
if (excludeEndpoints.Contains(endpoint)) {
continue; // Skip this iteration if the endpoint is in the exclude list
}
// Create a new client for each endpoint
using var client = new ClientX(endpoint) {
Debug = false
};
foreach (var domain in domains) {
foreach (var recordType in recordTypes) {
DnsResponse? response = await client.Resolve(domain, recordType);
response.DisplayToConsole();
}
}
await foreach (var response in client.ResolveStream(domains.ToArray(), recordTypes.ToArray())) {
response.DisplayToConsole();
}
}
Usage in PowerShell
DnsClientX is also available as a PowerShell module. Below are some examples.
Resolve-DnsQuery -Name 'evotec.pl' -Type A | Format-Table
Resolve-DnsQuery -Name 'evotec.pl' -Type A -DnsProvider Cloudflare -Verbose | Format-Table
Resolve-DnsQuery -Name 'evotec.pl' -Type TXT -DnsProvider System -Verbose | Format-Table
Resolve-DnsQuery -Name 'evotec.pl' -Type DS -DnsProvider Cloudflare -Verbose | Format-Table
Resolve-DnsQuery -Name 'github.com', 'evotec.pl', 'google.com' -Type TXT -DnsProvider System -Verbose | Format-Table
It can also deliver more detailed information.
$Output = Resolve-DnsQuery -Name '_25._tcp.mail.ietf.org' -Type TLSA -DnsProvider Cloudflare -Verbose -FullResponse
$Output.Questions | Format-Table
$Output.AnswersMinimal | Format-Table
$Output = Resolve-DnsQuery -Name 'evotec.pl' -Type DS -DnsProvider Cloudflare -Verbose -FullResponse
$Output.Questions | Format-Table
$Output.AnswersMinimal | Format-Table
$Output = Resolve-DnsQuery -Name 'github.com', 'evotec.pl', 'google.com' -Type TXT -DnsProvider Google -Verbose -FullResponse
$Output.Questions | Format-Table
$Output.AnswersMinimal | Format-Table
$Output = Resolve-DnsQuery -Name 'github.com', 'evotec.pl', 'google.com' -Type TXT -DnsProvider Cloudflare -Verbose -FullResponse
$Output.Questions | Format-Table
$Output.AnswersMinimal | Format-Table
$Output = Resolve-DnsQuery -Name 'github.com', 'evotec.pl', 'google.com' -Type TXT, A -Verbose -Server "192.168.241.5" -FullResponse
$Output.Questions | Format-Table
$Output.AnswersMinimal | Format-Table
$Output = Resolve-DnsQuery -Name 'evotec.pl' -Type A -Server '1.1.1.1','8.8.8.8' -Fallback
$Output.AnswersMinimal | Format-Table
$Output = Resolve-DnsQuery -Name 'evotec.pl' -Type A -Server '1.1.1.1','8.8.8.8' -Fallback -RandomServer
$Output.AnswersMinimal | Format-Table
DNS Service Discovery
DnsClientX can discover services advertised via DNS-SD.
using var client = new ClientX();
var services = await client.DiscoverServices("example.com");
foreach (var svc in services) {
Console.WriteLine($"{svc.ServiceName} -> {svc.Target}:{svc.Port}");
}
You can also query a specific service to get its SRV records directly:
using var client = new ClientX();
var records = await client.ResolveServiceAsync("ldap", "tcp", "example.com", resolveHosts: true);
foreach (var r in records) {
Console.WriteLine($"{r.Target}:{r.Port} (pri {r.Priority}, weight {r.Weight})");
if (r.Addresses != null) Console.WriteLine(string.Join(", ", r.Addresses));
}
Get-DnsService -Domain 'example.com'
Zone Transfer
Retrieve all records from a DNS server that allows AXFR:
using var client = new ClientX("127.0.0.1", DnsRequestFormat.DnsOverTCP) { EndpointConfiguration = { Port = 5353 } };
var zoneRecords = await client.ZoneTransferAsync("example.com");
Get-DnsZoneTransfer -Zone 'example.com' -Server '127.0.0.1' -Port 5353
Please share with the community
Please consider sharing a post about DnsClientX and the value it provides. It really does help!
Credits
This project general idea is based on DnsOverHttps by @akac which was an inspiration for DnsClientX.
Other libraries
- DnsClient.NET - DnsClient is a simple yet very powerful and high performant open source library for the .NET Framework to do DNS lookups. If you need standard DNS support - this one is for you.
- DnsOverHttps - DnsOverHttps is a simple yet very powerful and high performant open source library for the .NET Framework to do DNS lookups over HTTPS using Cloudflare. If you only need Cloudflare support and target newer .NET versions - this one is for you.
- DinoDNS - another DNS library with a lot of features.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 is compatible. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.7.2
- Microsoft.Bcl.AsyncInterfaces (>= 8.0.0)
- System.Text.Json (>= 8.0.5)
-
.NETStandard 2.0
- Microsoft.Bcl.AsyncInterfaces (>= 8.0.0)
- System.Net.Http (>= 4.3.4)
- System.Text.Json (>= 8.0.5)
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on DnsClientX:
Repository | Stars |
---|---|
EvotecIT/PSEventViewer
PSEventViewer (Get-Events) is really useful PowerShell wrapper around Get-WinEvent. One of the features you may be interested in is a simple way of getting βhiddenβ events data
|
Version | Downloads | Last Updated |
---|---|---|
1.0.4 | 476 | 9/2/2025 |
1.0.3 | 145 | 9/2/2025 |
1.0.2 | 138 | 9/2/2025 |
1.0.1 | 1,909 | 8/26/2025 |
1.0.0 | 2,705 | 7/17/2025 |
0.5.0 | 2,477 | 7/7/2025 |
0.4.0 | 12,611 | 5/28/2025 |
0.3.4 | 1,455 | 11/25/2024 |
0.3.3 | 128 | 11/25/2024 |
0.3.2 | 129 | 11/25/2024 |
0.3.1 | 179 | 10/19/2024 |
0.3.0 | 133 | 9/19/2024 |
0.2.2 | 151 | 7/14/2024 |
0.2.1 | 369 | 4/27/2024 |
0.2.0 | 150 | 4/27/2024 |
0.1.1 | 154 | 4/5/2024 |