nelexa/guzzle-doh-middleware

A Dns over Https (DoH) middleware for Guzzle >= 6.0

Maintainers

👁 Ne-Lexa

Package info

github.com/Ne-Lexa/guzzle-doh-middleware

pkg:composer/nelexa/guzzle-doh-middleware

Statistics

Installs: 269

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

1.0.1 2022-03-04 10:32 UTC

Requires

Requires (Dev)

Suggests

  • symfony/cache: Install the PSR-6 or PSR-16 caching implementation

Provides

None

Conflicts

None

Replaces

None

MIT 51fb72c03668d8b6c17245718c71b8888aeb125d

  • Ne-Lexa <alexey.woop@nelexa.ru>

Guzzlemiddlewarednsdns-over-httpsdoh

This package is auto-updated.

Last update: 2026-06-06 14:17:21 UTC


README

👁 nelexa/guzzle-doh-middleware

guzzle-doh-middleware

A DNS over HTTPS (DoH) middleware for Guzzle.

👁 Latest Stable Version
👁 PHP Version Require
👁 Tests
👁 Analysis
👁 Build Status
👁 Scrutinizer Code Quality
👁 Code Coverage
👁 License

Goals

  • Resolving domains, via DoH before sending HTTP requests.
  • Bypassing blocked sites, through DNS packet spoofing.
  • Support for caching DNS responses, via PSR-6 and PSR-16 compatible packages.
  • Support for multiple DoH providers.

Install

composer require nelexa/guzzle-doh-middleware

Usage

use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use Nelexa\Doh\DohMiddleware;

// Create default HandlerStack
$stack = HandlerStack::create();

// Add this middleware to the top with `push`
$stack->push(DohMiddleware::create(), 'doh');

// Initialize the client with the handler option
$client = new Client(['handler' => $stack]);

Setup cache

It is very important to configure caching of DNS requests, so that you do not have to contact a DNS server to resolve domains for every HTTP request.

Install a PSR-6 or PSR-16 compatible caching package.

For example, you can install the popular symfony/cache package.

composer require symfony/cache

Example init PSR-6 redis cache

$cache = new \Symfony\Component\Cache\Adapter\RedisAdapter(
 \Symfony\Component\Cache\Adapter\RedisAdapter::createConnection()
);

Example init PSR-16 redis cache

$cache = new \Symfony\Component\Cache\Psr16Cache(
 new \Symfony\Component\Cache\Adapter\RedisAdapter(
 \Symfony\Component\Cache\Adapter\RedisAdapter::createConnection()
 )
);

You can pass the configured cache as the first argument when creating middleware.
If you don't pass the argument or pass null, the cache will only be stored for the lifetime of the PHP process.

$stack->push(DohMiddleware::create($cache), 'doh');

Setup DoH Servers

You can specify which DoH servers to use as a second argument when creating middleware. They will be chosen in random order.

The defaults are Cloudflare (for Mozilla) and Google.

Example:

$dohServers = [
 'https://mozilla.cloudflare-dns.com/dns-query',
 'https://dns.google/dns-query',
 'https://doh.cleanbrowsing.org/doh/security-filter',
 \Nelexa\Doh\DohServers::SERVER_ADGUARD_FAMILY,
 'https://doh.opendns.com/dns-query',
];
$stack->push(DohMiddleware::create($cache, $dohServers), 'doh');

Setup Logger & Debug

You can add the PSR-3 compatible Logger as a 3rd argument when creating middleware.

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('doh');
$logger->pushHandler(new StreamHandler('path/to/doh.log', Logger::DEBUG));

$stack->push(DohMiddleware::create(
 cache: $cache,
 logger: $logger
), 'doh');

For debugging and console output of all DoH requests to servers, you can pass true as 4th parameter when creating middleware.

$stack->push(DohMiddleware::create(
 cache: $cache,
 debug: true,
), 'doh');

Request options

You can configure requests created and transmitted by the client using request options.

Option "doh"

Summary

Set false to disable domain resolving, via DoH.

Types
  • bool
Default

true

Constant

\Nelexa\Doh\DohMiddleware::OPTION_DOH_ENABLED

// Disable DoH for concrete request
$client->request('GET', 'https://...', [
 'doh' => false,
]);

To disable DoH middleware by default, pass false for the doh option when creating the HTTP client.

$stack = HandlerStack::create();
$stack->push(DohMiddleware::create($cache), 'doh');
$client = new Client([
 'handler' => $stack,
 'doh' => false,
]);

Option "doh_ttl"

Summary

Forced setting of caching time for resolving results. If the option is not passed or null is passed, the caching time from the DNS server is used.

Types
  • integer
  • \DateInterval
  • null
Default

null

Constant

\Nelexa\Doh\DohMiddleware::OPTION_DOH_TTL

$client->request('GET', 'https://...', [
 'doh_ttl' => \DateInterval::createFromDateString('1 hour'),
]);

Option "doh_shuffle"

Summary

Set true to enable shuffling of ip addresses in random order when more than one ip address has been received as a result of domain resolving.

Types
  • bool
Default

false

Constant

\Nelexa\Doh\DohMiddleware::OPTION_DOH_SHUFFLE

// Enable shuffle ip addresses
$client->request('GET', 'https://...', [
 'doh_shuffle' => true,
]);

To enable ip mixing for all requests by default, pass true for the ttl_shuffle option when creating the HTTP client.

$stack = HandlerStack::create();
$stack->push(DohMiddleware::create($cache), 'doh');
$client = new Client([
 'handler' => $stack,
 'doh_shuffle' => true,
]);

Symfony config DI

# config/services.yaml
parameters:
 
 doh.servers:
 - 'https://mozilla.cloudflare-dns.com/dns-query',
 - 'https://dns.google/dns-query',
 - 'https://doh.opendns.com/dns-query'

services:

 app.client.doh_middleware:
 factory: Nelexa\Doh\DohMiddleware::create
 class: Nelexa\Doh\DohMiddleware
 arguments:
 - '@cache.app'
 - '%doh.servers%'
 - '@logger'
 - '%kernel.debug%'

 app.client.handler_stack:
 factory: GuzzleHttp\HandlerStack::create
 class: GuzzleHttp\HandlerStack
 calls:
 - [ push, [ '@app.client.doh_middleware' ] ]

 app.client:
 class: GuzzleHttp\Client
 arguments:
 app.client:
 class: GuzzleHttp\Client
 arguments:
 - handler: '@app.client.handler_stack'
 doh: true
 # doh_ttl: 3600
 # doh_shuffle: true

 # Aliases
 GuzzleHttp\Client: '@app.client'

Credits

Changelog

Changes are documented in the releases page.

License

The MIT License (MIT). Please see LICENSE for more information.