Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DNS over HTTPS #94

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions DNS/Client/DnsClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
55 changes: 55 additions & 0 deletions DNS/Client/RequestResolver/HttpsRequestResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using System.Threading;
using System.Threading.Tasks;
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 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<IResponse> 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);
}
}
}
7 changes: 7 additions & 0 deletions DNS/Server/DnsServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {}

Expand All @@ -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));
Expand Down
3 changes: 2 additions & 1 deletion Examples/ClientServer/ClientServerExample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"))
```