From bb00dcef68fc551ca6851cde3fd4e8c937432b1f Mon Sep 17 00:00:00 2001 From: TheMasterofBlubb Date: Tue, 15 Nov 2022 00:58:43 +0100 Subject: [PATCH 1/9] Offloading Queries to Tasks --- DNS/Server/DnsServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DNS/Server/DnsServer.cs b/DNS/Server/DnsServer.cs index efd997b..8fc5923 100644 --- a/DNS/Server/DnsServer.cs +++ b/DNS/Server/DnsServer.cs @@ -76,7 +76,7 @@ void ReceiveCallback(IAsyncResult result) { try { IPEndPoint remote = new IPEndPoint(0, 0); data = udp.EndReceive(result, ref remote); - HandleRequest(data, remote); + Task.Run(()=> HandleRequest(data, remote)); } catch (ObjectDisposedException) { // run should already be false From d2799e73fb3a1f9e458b62493c191e8f3c07da96 Mon Sep 17 00:00:00 2001 From: Jim Gilmartin Date: Mon, 13 Mar 2023 15:44:51 -0700 Subject: [PATCH 2/9] Add remote endpoint to error events --- DNS/Server/DnsServer.cs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/DNS/Server/DnsServer.cs b/DNS/Server/DnsServer.cs index 8fc5923..8d5f0ae 100644 --- a/DNS/Server/DnsServer.cs +++ b/DNS/Server/DnsServer.cs @@ -65,7 +65,7 @@ public async Task Listen(IPEndPoint endpoint) { udp.Client.IOControl(SIO_UDP_CONNRESET, new byte[4], new byte[4]); } } catch (SocketException e) { - OnError(e); + OnError(e, endpoint); return; } } @@ -83,7 +83,7 @@ void ReceiveCallback(IAsyncResult result) { run = false; } catch (SocketException e) { - OnError(e); + OnError(e, endpoint); } if (run) udp.BeginReceive(ReceiveCallback, null); @@ -114,8 +114,8 @@ protected virtual void Dispose(bool disposing) { } } - private void OnError(Exception e) { - OnEvent(Errored, new ErroredEventArgs(e)); + private void OnError(Exception e, IPEndPoint remote) { + OnEvent(Errored, new ErroredEventArgs(e, remote)); } private async void HandleRequest(byte[] data, IPEndPoint remote) { @@ -132,12 +132,12 @@ await udp .SendAsync(response.ToArray(), response.Size, remote) .WithCancellationTimeout(TimeSpan.FromMilliseconds(UDP_TIMEOUT)).ConfigureAwait(false); } - catch (SocketException e) { OnError(e); } - catch (ArgumentException e) { OnError(e); } - catch (IndexOutOfRangeException e) { OnError(e); } - catch (OperationCanceledException e) { OnError(e); } - catch (IOException e) { OnError(e); } - catch (ObjectDisposedException e) { OnError(e); } + catch (SocketException e) { OnError(e, remote); } + catch (ArgumentException e) { OnError(e, remote); } + catch (IndexOutOfRangeException e) { OnError(e, remote); } + catch (OperationCanceledException e) { OnError(e, remote); } + catch (IOException e) { OnError(e, remote); } + catch (ObjectDisposedException e) { OnError(e, remote); } catch (ResponseException e) { IResponse response = e.Response; @@ -152,7 +152,7 @@ await udp } catch (SocketException) {} catch (OperationCanceledException) {} - finally { OnError(e); } + finally { OnError(e, remote); } } } @@ -183,11 +183,13 @@ public RespondedEventArgs(IRequest request, IResponse response, byte[] data, IPE } public class ErroredEventArgs : EventArgs { - public ErroredEventArgs(Exception e) { + public ErroredEventArgs(Exception e, IPEndPoint remote) { Exception = e; + Remote = remote; } public Exception Exception { get; } + public IPEndPoint Remote { get; } } private class FallbackRequestResolver : IRequestResolver { From 6ebdf64829df227b513b6bf79cf2b0f500e83911 Mon Sep 17 00:00:00 2001 From: Jim Gilmartin Date: Mon, 13 Mar 2023 15:46:05 -0700 Subject: [PATCH 3/9] Update tests and examples to .NET 7 --- Examples/Examples.csproj | 2 +- Tests/Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Examples/Examples.csproj b/Examples/Examples.csproj index 90cb997..8d55bd3 100644 --- a/Examples/Examples.csproj +++ b/Examples/Examples.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.0 + net7.0 diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index a2f6412..ec3c71d 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp2.2 + net7.0 From 3651cee5a49fb34160c5eae0d569e60a79bfe531 Mon Sep 17 00:00:00 2001 From: Kiener Date: Tue, 11 Dec 2018 10:57:22 +0100 Subject: [PATCH 4/9] Enhance Regex pattern for supporting dash/hyphen in domain name, but don't support underline --- DNS/Server/MasterFile.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/DNS/Server/MasterFile.cs b/DNS/Server/MasterFile.cs index b6a1ad5..a4f86bb 100644 --- a/DNS/Server/MasterFile.cs +++ b/DNS/Server/MasterFile.cs @@ -19,7 +19,10 @@ protected static bool Matches(Domain domain, Domain entry) { for (int i = 0; i < labels.Length; i++) { string label = labels[i]; - patterns[i] = label == "*" ? "(\\w+)" : Regex.Escape(label); + // note: support hyphens '-' in domain name + // don't support underline '_' in name + patterns[i] = label == "*" ? "([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*)" : Regex.Escape(label); + //patterns[i] = label == "*" ? "(\\w+)" : Regex.Escape(label); } Regex re = new Regex("^" + string.Join("\\.", patterns) + "$", RegexOptions.IgnoreCase); From 0a95b1799adabcb7f03e67275ccbc679847c4a25 Mon Sep 17 00:00:00 2001 From: Damob Date: Thu, 25 Aug 2022 11:02:59 +0900 Subject: [PATCH 5/9] Add DNS over HTTPS --- DNS/Client/DnsClient.cs | 3 + .../RequestResolver/HttpsRequestResolver.cs | 59 +++++++++++++++++++ DNS/Server/DnsServer.cs | 7 +++ 3 files changed, 69 insertions(+) create mode 100644 DNS/Client/RequestResolver/HttpsRequestResolver.cs diff --git a/DNS/Client/DnsClient.cs b/DNS/Client/DnsClient.cs index 2a7a7a9..82f6eeb 100644 --- a/DNS/Client/DnsClient.cs +++ b/DNS/Client/DnsClient.cs @@ -26,6 +26,9 @@ public DnsClient(string ip, int port = DEFAULT_PORT) : public DnsClient(IRequestResolver resolver) { this.resolver = resolver; } + public DnsClient(Uri uri) : + this(new HttpsRequestResolver(uri)) + { } public ClientRequest FromArray(byte[] message) { Request request = Request.FromArray(message); diff --git a/DNS/Client/RequestResolver/HttpsRequestResolver.cs b/DNS/Client/RequestResolver/HttpsRequestResolver.cs new file mode 100644 index 0000000..22a3255 --- /dev/null +++ b/DNS/Client/RequestResolver/HttpsRequestResolver.cs @@ -0,0 +1,59 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; +using System.IO; +using System.Net.Http; +using System.Net.Http.Headers; +using DNS.Protocol; +using DNS.Protocol.Utils; + +namespace DNS.Client.RequestResolver { + public class HttpsRequestResolver : IRequestResolver { + private int timeout; + private IRequestResolver fallback; + private IPEndPoint dns; + private HttpClient httpClient; + private void SetUpClient(Uri uri) + { + httpClient = new HttpClient() + { + BaseAddress = uri, + Timeout = TimeSpan.FromMilliseconds(timeout) + //DefaultRequestVersion = new Version(2, 0), + }; + httpClient.DefaultRequestHeaders.Add("Accept", "application/dns-message"); + + } + public HttpsRequestResolver(Uri uri, IRequestResolver fallback, int timeout = 5000) { + this.fallback = fallback; + this.timeout = timeout; + SetUpClient(uri); + } + + public HttpsRequestResolver(Uri uri, int timeout = 5000) { + this.fallback = new NullRequestResolver(); + this.timeout = timeout; + SetUpClient(uri); + } + + public async Task Resolve(IRequest request, CancellationToken cancellationToken = default(CancellationToken)) { + var httpRequest = new HttpRequestMessage(HttpMethod.Post, "") + { + Content = new ByteArrayContent(request.ToArray(), 0, request.Size) + }; + httpRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("application/dns-message"); + var httpResponse = await httpClient.SendAsync(httpRequest).WithCancellationTimeout(TimeSpan.FromMilliseconds(timeout), cancellationToken).ConfigureAwait(false); + Byte[] buffer = await httpResponse.Content.ReadAsByteArrayAsync(); + Response response = Response.FromArray(buffer); + + if (response.Truncated) + { + return await fallback.Resolve(request, cancellationToken).ConfigureAwait(false); + } + + return new ClientResponse(request, response, buffer); + } + } +} diff --git a/DNS/Server/DnsServer.cs b/DNS/Server/DnsServer.cs index 8d5f0ae..41bbbb5 100644 --- a/DNS/Server/DnsServer.cs +++ b/DNS/Server/DnsServer.cs @@ -35,6 +35,10 @@ public DnsServer(IRequestResolver resolver, IPAddress endServer, int port = DEFA public DnsServer(IRequestResolver resolver, string endServer, int port = DEFAULT_PORT) : this(resolver, IPAddress.Parse(endServer), port) {} + public DnsServer(IRequestResolver resolver, Uri uri) : + this(new FallbackRequestResolver(resolver, new HttpsRequestResolver(uri))) + { } + public DnsServer(IPEndPoint endServer) : this(new UdpRequestResolver(endServer)) {} @@ -47,6 +51,9 @@ public DnsServer(string endServer, int port = DEFAULT_PORT) : public DnsServer(IRequestResolver resolver) { this.resolver = resolver; } + public DnsServer(Uri uri) : + this(new HttpsRequestResolver(uri)) + { } public Task Listen(int port = DEFAULT_PORT, IPAddress ip = null) { return Listen(new IPEndPoint(ip ?? IPAddress.Any, port)); From 74cc8f40f41e80cde1f976804b9f1757b47056da Mon Sep 17 00:00:00 2001 From: Damob Date: Thu, 25 Aug 2022 13:27:35 +0900 Subject: [PATCH 6/9] Add Dns Over https Example --- Examples/ClientServer/ClientServerExample.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Examples/ClientServer/ClientServerExample.cs b/Examples/ClientServer/ClientServerExample.cs index 65840c8..0d85d94 100644 --- a/Examples/ClientServer/ClientServerExample.cs +++ b/Examples/ClientServer/ClientServerExample.cs @@ -13,7 +13,8 @@ public static void Main(string[] args) { public async static Task MainAsync() { MasterFile masterFile = new MasterFile(); - DnsServer server = new DnsServer(masterFile, "8.8.8.8"); + //Dns Proxy to Dns over https + DnsServer server = new DnsServer(masterFile, new Uri("https://1.1.1.1/dns-query")); masterFile.AddIPAddressResourceRecord("google.com", "127.0.0.1"); From a0a0666480eb40f7192249900b542146283049c3 Mon Sep 17 00:00:00 2001 From: Damob Date: Thu, 25 Aug 2022 13:38:17 +0900 Subject: [PATCH 7/9] Add Dns over Https description in readme --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a93fa6..878cd40 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ It's also possible to modify the `request` instance in the `server.Requested` ca ### Request Resolver -The `DnsServer`, `DnsClient` and `ClientRequest` classes also accept an instance implementing the `IRequestResolver` interface, which they internally use to resolve DNS requests. Some of the default implementations are `UdpRequestResolver`, `TcpRequestResolver` and `MasterFile` classes. But it's also possible to provide a custom request resolver. +The `DnsServer`, `DnsClient` and `ClientRequest` classes also accept an instance implementing the `IRequestResolver` interface, which they internally use to resolve DNS requests. Some of the default implementations are `UdpRequestResolver`, `TcpRequestResolver`, `HttpsRequestResolver` and `MasterFile` classes. But it's also possible to provide a custom request resolver. ```C# // A request resolver that resolves all dns queries to localhost @@ -124,3 +124,17 @@ DnsServer server = new DnsServer(new LocalRequestResolver()); await server.Listen(); ``` + +### Support Dns Over Https + +DNS over HTTPS (DoH), DNS queries and responses are encrypted and sent via the HTTP or HTTP/2 protocols. DoH ensures that attackers cannot forge or alter DNS traffic. DoH uses port 443, which is the standard HTTPS traffic port, to wrap the DNS query in an HTTPS request. DNS queries and responses are camouflaged within other HTTPS traffic, since it all comes and goes from the same port. + +[https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/](https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/) + +```C# +// DoH Proxy Server +MasterFile masterFile = new MasterFile(); +DnsServer server = new DnsServer(masterFile, new Uri("https://1.1.1.1/dns-query")); +// DoH Client +DnsClient client = new DnsClient(new Uri("https://1.1.1.1/dns-query")) +``` From e2b7efc6a6174c3e41d6c794204ae54805a0d8bc Mon Sep 17 00:00:00 2001 From: Damob Date: Wed, 12 Oct 2022 14:39:33 +0900 Subject: [PATCH 8/9] Delete unused imports --- DNS/Client/RequestResolver/HttpsRequestResolver.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/DNS/Client/RequestResolver/HttpsRequestResolver.cs b/DNS/Client/RequestResolver/HttpsRequestResolver.cs index 22a3255..282ea57 100644 --- a/DNS/Client/RequestResolver/HttpsRequestResolver.cs +++ b/DNS/Client/RequestResolver/HttpsRequestResolver.cs @@ -1,9 +1,6 @@ using System; -using System.Net; -using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; -using System.IO; using System.Net.Http; using System.Net.Http.Headers; using DNS.Protocol; @@ -13,7 +10,6 @@ namespace DNS.Client.RequestResolver { public class HttpsRequestResolver : IRequestResolver { private int timeout; private IRequestResolver fallback; - private IPEndPoint dns; private HttpClient httpClient; private void SetUpClient(Uri uri) { @@ -24,7 +20,6 @@ private void SetUpClient(Uri uri) //DefaultRequestVersion = new Version(2, 0), }; httpClient.DefaultRequestHeaders.Add("Accept", "application/dns-message"); - } public HttpsRequestResolver(Uri uri, IRequestResolver fallback, int timeout = 5000) { this.fallback = fallback; @@ -43,6 +38,7 @@ public HttpsRequestResolver(Uri uri, int timeout = 5000) { { Content = new ByteArrayContent(request.ToArray(), 0, request.Size) }; + httpRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("application/dns-message"); var httpResponse = await httpClient.SendAsync(httpRequest).WithCancellationTimeout(TimeSpan.FromMilliseconds(timeout), cancellationToken).ConfigureAwait(false); Byte[] buffer = await httpResponse.Content.ReadAsByteArrayAsync(); From e5e41cf60a88e7c2faf093a5b8c876cba3bb2ba2 Mon Sep 17 00:00:00 2001 From: Jim Gilmartin Date: Mon, 13 Mar 2023 16:19:31 -0700 Subject: [PATCH 9/9] Update github actions workflow and readme --- .github/workflows/test.yml | 6 +++--- README.md | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 60fcc9a..43a1db8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,12 +8,12 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3.3.0 - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3.0.3 with: - dotnet-version: 2.2.x + dotnet-version: 7.0.x - name: Test run: | diff --git a/README.md b/README.md index 878cd40..4c1ef75 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # DNS -A DNS library written in C# targeting .NET Standard 2.0. Versions prior to version two (2.0.0) were written for .NET 4 using blocking network operations. Version two and above use asynchronous operations. +A DNS library written in C# targeting .NET Standard 2.0. -Available through NuGet. +Only original repo is currently available through NuGet. Install-Package DNS -[![Test](https://github.com/kapetan/dns/actions/workflows/test.yml/badge.svg)](https://github.com/kapetan/dns/actions/workflows/test.yml) +[![Test](https://github.com/jgilm/dns/actions/workflows/test.yml/badge.svg)](https://github.com/jgilm/dns/actions/workflows/test.yml) # Usage