Skip to content

Commit

Permalink
Updated documentation and fix code lint.
Browse files Browse the repository at this point in the history
  • Loading branch information
noglitchyo committed Jun 20, 2019
1 parent f7c151a commit d50a03a
Show file tree
Hide file tree
Showing 5 changed files with 431 additions and 36 deletions.
68 changes: 34 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,48 +12,46 @@ It can be use as a middleware or a client and attempt to provide a low-level abs

## Description

Dealdoh can be use in different manners and for different purposes:
- as a middleware in a web server and acts as a DNS proxy
- as a client, using the provided command-line client to make DNS queries with [dealdoh-client](https://github.com/noglitchyo/dealdoh-client/).
- as a low-level abstraction layer for development around DNS.
Dealdoh can be use in different manners and for different purposes. Dealdoh attempt to achieve the following goals:
- provide a DoH middleware which can be use in any PHP application acting as a DNS proxy.
- provide a variety of DNS stub resolver.
- provide a large panel of DNS clients.
- provide a low-level abstraction layer for development around DNS.

Dealdoh also comes with a [dealdoh-client](https://github.com/noglitchyo/dealdoh-client/) embedding the following features:
- an application implementing Dealdoh middleware and ready to be run as a micro-service
- a CLI client to make DNS queries, configure DNS upstreams, etc...

## Features

- [x] Create and forward DNS messages in different format to different type of upstreams.
- [x] Use a pool of DNS upstreams to send queries with a fallback mechanism.
- [x] Use different DNS protocol: RFC-1035 (TCP/UDP), RFC-8484 (DoH), Google DoH API.
- [x] Create and forward DNS messages in different format to different type of DNS upstream resolvers.
- [x] Use a pool of DNS upstream resolvers to send queries with a fallback mechanism.
- [x] Compatible with a variety of DNS protocols: RFC-1035 (TCP/UDP), RFC-8484 (DoH), Google DoH API.
- [x] Provide a DNS low-level abstraction layer for DNS development.
- [x] Make DNS query from the command-line and provide results in JSON

## Roadmap

- [ ] Improve the current DNS clients
- [ ] Improve robustness and compliance of current DNS clients
- [ ] Ability to choose a DNS upstream fallback/selection strategy
- [ ] Dockerized application
- [ ] Good documentation

## Getting started

As mentionned above, there is multiple ways to use Dealdoh.
Let's see what can be done at the time with Dealdoh.

### As a DoH proxy middleware

If you wish to get started quickly, check Please, check out [dealdoh-client](https://github.com/noglitchyo/dealdoh-client/)
If you wish to get started quickly, you might want to use [dealdoh-client](https://github.com/noglitchyo/dealdoh-client/)
which offers a ready-to-use implementation.

#### Requirements

- A web server
- PHP 7.3
- Web server
- HTTPS enabled with valid certificates (self-signed certificates can work but it depends of the DOH client)

To get valid certificates in a local environment, I recommend you to use [mkcert](https://github.com/FiloSottile/mkcert) which generate for you a local Certificate Authority, and create locally trusted certificates with it. Take 3 minutes to check its really simple documentation for your OS. (since installation differs on each OS)

- PHP 7.3
To get trusted certificates in a local environment, I recommend you to use [mkcert](https://github.com/FiloSottile/mkcert) which generate for you a local Certificate Authority, and create locally trusted certificates with it. Take 3 minutes to check its really simple documentation for your OS. (since installation differs on each OS)

#### Installation

- You will need to install Dealdoh as a dependency in your project:
- Install Dealdoh as a dependency:

`composer require noglitchyo/dealdoh`

Expand All @@ -63,21 +61,20 @@ Please check those cool implementations below:
* https://github.com/guzzle/psr7 - `composer require guzzle/psr7`
* https://github.com/zendframework/zend-diactoros - `composer require zendframework/zend-diactoros`

- Configure your middleware/entrypoint to call Dealdoh's HttpProxy
- Configure your middleware/entrypoint to call Dealdoh's `HttpProxy::forward()`

As stated before, `HttpProxy::forward()` method consumes PSR-7 ServerRequest to make integration easier
when implementing on "Action"/"Middleware" classes.
As stated before, `HttpProxy::forward()` method consumes PSR-7 ServerRequest to make the integration easier.

The example below illustrates how to use two DNS upstreams which are using different protocols.
In this example, the used protocols are UDP (RFC-1035) and DoH (RFC-8484).
The example below illustrates how to use two DNS upstream resolvers which are using different protocols.
In this example, the used protocols are TCP/UDP (RFC-1035) and DoH (RFC-8484).
Two types of DNS client who can handle each of the DNS protocols used by our upstreams are injected to handle those upstreams.

```php
<?php
$dnsMessageFactory = new \NoGlitchYo\Dealdoh\Factory\Dns\MessageFactory();
$dnsResolver = new \NoGlitchYo\Dealdoh\Service\DnsPoolResolver(
new \NoGlitchYo\Dealdoh\Entity\DnsUpstreamPool([
'8.8.8.8:53',
'dns://8.8.8.8:53',
'https://cloudflare-dns.com/dns-query',
]),
[
Expand All @@ -103,11 +100,14 @@ $response = $dnsProxy->forward(/* Expect a \Psr\Http\Message\RequestInterface ob
```
- Testing the installation

First, you need to know that most of implemented DoH client/server will send/receive DNS requests on the following path:
`/dns-query`.
First, be aware that usually, DoH client/server will send/receive DNS requests on the following path:
`/dns-query` as recommended in RFC-8484.
Make sure your Dealdoh's entrypoint has been configured to listen on this route or configure your client accordingly if it is possible.

A large variety of client already exists than you can easily find on Internet. For testing purpose, I advise the one below:
A large variety of client already exists than you can easily find on Internet.
For testing purpose, I advise the one below:

* Using [dealdoh-client](https://github.com/noglitchyo/dealdoh-client/)

* Using the doh-client from [Facebook Experimental](https://github.com/facebookexperimental/doh-proxy)

Expand All @@ -121,9 +121,9 @@ To make it easier, I created a [Docker image](https://hub.docker.com/) that you

Please, check [how to use the client](https://github.com/facebookexperimental/doh-proxy#doh-client).

* Using your client browser
* Using client from Web Browser

Firefox provides a [Trusted Recursive Resolver](https://wiki.mozilla.org/Trusted_Recursive_Resolver) who can be configured to query DoH servers.
Mozilla Firefox provides a [Trusted Recursive Resolver](https://wiki.mozilla.org/Trusted_Recursive_Resolver) who can be configured to query DoH servers.

I advise you to read [this really good article from Daniel Stenberg](https://daniel.haxx.se/blog/2018/06/03/inside-firefoxs-doh-engine/)
which will give you lot of details about this TRR and how to configure it like a pro.
Expand All @@ -136,10 +136,8 @@ Checkout some really simple integration examples to get a glimpse on how it can

- [Slim Framework integration](examples/slim-integration/README.md)
- [DoH + Docker + DNS + Hostname Discovery](examples/docker-firefox/README.md)
- [dealdoh-client](https://github.com/noglitchyo/dealdoh-client/)

### As a DNS command-line client

Please, check out [Dealdoh client](https://github.com/noglitchyo/dealdoh-client/) for this.

## Testing

Expand Down Expand Up @@ -176,6 +174,8 @@ Combined with Dealdoh it is amazing.

- [RFC-8484](https://tools.ietf.org/html/rfc8484)
- [RFC-1035](https://tools.ietf.org/html/rfc1035)
- [RFC-4501](https://tools.ietf.org/html/rfc4501)
- [RFC-7719](https://tools.ietf.org/html/rfc7719)
- [PSR-7](https://www.php-fig.org/psr/psr-7/)
- [PSR-18](https://www.php-fig.org/psr/psr-18/)
- [Wiki page DNS-over-HTTPS from Curl](https://github.com/curl/curl/wiki/DNS-over-HTTPS)
10 changes: 10 additions & 0 deletions src/Exception/HttpProxyException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php declare(strict_types=1);

namespace NoGlitchYo\Dealdoh\Exception;

use Exception;

class HttpProxyException extends Exception
{

}
107 changes: 107 additions & 0 deletions src/HttpProxy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php declare(strict_types=1);

namespace NoGlitchYo\Dealdoh;

use NoGlitchYo\Dealdoh\Exception\HttpProxyException;
use NoGlitchYo\Dealdoh\Factory\Dns\MessageFactoryInterface;
use NoGlitchYo\Dealdoh\Factory\DohHttpMessageFactoryInterface;
use NoGlitchYo\Dealdoh\Helper\Base64UrlCodecHelper;
use NoGlitchYo\Dealdoh\Service\DnsResolverInterface;
use Nyholm\Psr7\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Throwable;

class HttpProxy
{
/**
* @var DnsResolverInterface
*/
private $dnsResolver;

/**
* @var LoggerInterface
*/
private $logger;

/**
* @var MessageFactoryInterface
*/
private $dnsMessageFactory;

/**
* @var DohHttpMessageFactoryInterface
*/
private $dohHttpMessageFactory;

public function __construct(
DnsResolverInterface $dnsResolver,
MessageFactoryInterface $dnsMessageFactory,
DohHttpMessageFactoryInterface $dohHttpMessageFactory,
LoggerInterface $logger = null
) {
$this->dnsResolver = $dnsResolver;
$this->logger = $logger ?? new NullLogger();
$this->dnsMessageFactory = $dnsMessageFactory;
$this->dohHttpMessageFactory = $dohHttpMessageFactory;
}

/**
* @throws HttpProxyException
*/
public function forward(ServerRequestInterface $serverRequest): ResponseInterface
{
try {
switch ($serverRequest->getMethod()) {
case 'GET':
$dnsQuery = $serverRequest->getQueryParams()['dns'] ?? null;
if (!$dnsQuery) {
return new Response(400, [], 'Query parameter `dns` is mandatory.');
}
$dnsWireMessage = Base64UrlCodecHelper::decode($dnsQuery);
break;
case 'POST':
$dnsWireMessage = (string)$serverRequest->getBody();
break;
default:
return new Response(405);
}

$dnsRequestMessage = $this->dnsMessageFactory->createMessageFromDnsWireMessage($dnsWireMessage);
} catch (Throwable $t) {
$this->logger->error(
sprintf('Failed to create DNS message: %s', $t->getMessage()),
[
'exception' => $t,
'httpRequest' => $serverRequest
]
);
throw new HttpProxyException('DNS message creation failed.', 0, $t);
}

try {
$dnsResource = $this->dnsResolver->resolve($dnsRequestMessage);
} catch (Throwable $t) {
$this->logger->error(
sprintf('Failed to resolve DNS query: %s', $t->getMessage()),
[
'exception' => $t,
'dnsRequestMessage' => $dnsRequestMessage,
]
);
throw new HttpProxyException('Resolving DNS message failed.', 0, $t);
}

$this->logger->info(
sprintf("Resolved DNS query with method %s", $serverRequest->getMethod()),
[
'dnsRequestMessage' => $dnsResource->getRequest(),
'dnsResponseMessage' => $dnsResource->getResponse(),
]
);

return $this->dohHttpMessageFactory->createResponseFromMessage($dnsResource->getResponse());
}
}
7 changes: 5 additions & 2 deletions src/Service/DnsPoolResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ class DnsPoolResolver implements DnsResolverInterface
*/
private $logger;

public function __construct(DnsUpstreamPoolInterface $dnsUpstreamPool, array $dnsClients, LoggerInterface $logger = null)
{
public function __construct(
DnsUpstreamPoolInterface $dnsUpstreamPool,
array $dnsClients,
LoggerInterface $logger = null
) {
$this->dnsUpstreamPool = $dnsUpstreamPool;
$this->logger = $logger ?? new NullLogger();

Expand Down
Loading

0 comments on commit d50a03a

Please sign in to comment.