A lightweight, embeddable DNS server implementation in C# built on top of UDP sockets.
The server listens on port 53 and resolves DNS queries via event-based lookup handlers that you plug in at runtime.
This design makes it easy to embed a DNS server inside another application and dynamically control how records are resolved.
- UDP-based DNS server (RFC-style packet handling)
- Supports multiple DNS record types:
A,AAAANSCNAMESOAPTRMXTXTANY
- Event-driven lookup pipeline
- Async / non-blocking request handling
- Minimal dependencies
- Optional
Microsoft.Extensions.Loggingsupport
Add the project reference or NuGet package (if published):
dotnet add package DTooling.DnsServerOr reference the project directly:
<ProjectReference Include="DTooling.DnsServer.csproj" />using DTooling.DnsServer;
var dnsServer = new DnsServerInstance();Or with logging:
using Microsoft.Extensions.Logging;
var logger = loggerFactory.CreateLogger<DnsServerInstance>();
var dnsServer = new DnsServerInstance(logger);Each DNS record type is resolved via an event handler. You can register one or more handlers per record type.
Example: handling A records
dnsServer.LookupARecordAsync += async (endpoint, question, ct) =>
{
if (question.Name == "example.com")
{
return DnsLookupResult.Success(
DnsAnswer.A(question.Name, IPAddress.Parse("127.0.0.1"))
);
}
return DnsLookupResult.Failure();
};Handlers are executed in order. The first handler that returns a successful result wins.
// Default: 0.0.0.0:53
dnsServer.Start();
// Or bind to a specific port
dnsServer.Start(new IPEndPoint(IPAddress.Loopback, 5353));The server will now:
-
Bind to
0.0.0.0:53 -
Accept UDP DNS queries
-
Respond with:
NOERRORwhen a record is resolvedNXDOMAINwhen no handler succeedsSERVFAILon internal errors
⚠️ Binding to port 53 may require administrator/root privileges.
await dnsServer.StopAsync();Or dispose it:
dnsServer.Dispose();- DNS packet is received over UDP
- Packet is parsed into a
DnsMessage - Each question is processed independently
- Based on
DnsType, the corresponding event is invoked - Handlers return a
DnsLookupResult - Successful results are added as answers
- Response is serialized and sent back to the client
LookupARecordAsync
LookupAaaaRecordAsync
LookupNsRecordAsync
LookupCnameRecordAsync
LookupSoaRecordAsync
LookupPtrRecordAsync
LookupMxRecordAsync
LookupTxtRecordAsync
LookupAnyRecordAsyncEach event signature:
Func<IPEndPoint, DnsQuestion, CancellationToken, ValueTask<DnsLookupResult>>Use standard DNS tools:
dig @127.0.0.1 example.com Anslookup example.com 127.0.0.1- UDP only (no TCP fallback)
- No zone file parsing (by design)
- No caching layer
- Designed for embedded / programmable DNS, not full authoritative servers
Licensed under the Apache License 2.0.
See the LICENSE file for details.