Giter Club home page Giter Club logo

dns's Introduction

ReactPHP Logo

Event-driven, non-blocking I/O with PHP.

Build Status

ReactPHP is a low-level library for event-driven programming in PHP. At its core is an event loop, on top of which it provides low-level utilities, such as: Streams abstraction, async DNS resolver, network client/server, HTTP client/server and interaction with processes. Third-party libraries can use these components to create async network clients/servers and more.

<?php

// $ composer require react/http react/socket # install example using Composer
// $ php example.php # run example on command line, requires no additional web server

require __DIR__ . '/vendor/autoload.php';

$server = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterface $request) {
    return React\Http\Message\Response::plaintext(
        "Hello World!\n"
    );
});

$socket = new React\Socket\SocketServer('127.0.0.1:8080');
$server->listen($socket);

echo "Server running at http://127.0.0.1:8080" . PHP_EOL;

This simple web server written in ReactPHP responds with "Hello World!" for every request.

ReactPHP is production ready and battle-tested with millions of installations from all kinds of projects around the world. Its event-driven architecture makes it a perfect fit for efficient network servers and clients handling hundreds or thousands of concurrent connections, long-running applications and many other forms of cooperative multitasking with non-blocking I/O operations. What makes ReactPHP special is its vivid ecosystem with hundreds of third-party libraries allowing you to integrate with many existing systems, such as common network services, database systems and other third-party APIs.

  • Production ready and battle-tested.
  • Rock-solid with stable long-term support (LTS) releases.
  • Requires no extensions and runs on any platform - no excuses!
  • Takes advantage of optional extensions to get better performance when available.
  • Highly recommends latest version of PHP 7+ for best performance and support.
  • Supports legacy PHP 5.3+ and HHVM for maximum compatibility.
  • Well designed and reusable components.
  • Decoupled parts so they can be replaced by alternate implementations.
  • Carefully tested (unit & functional).
  • Promotes standard PSRs where possible for maximum interoperability.
  • Aims to be technology neutral, so you can use your preferred application stack.
  • Small core team of professionals supported by large network of outside contributors.

ReactPHP is non-blocking by default. Use workers for blocking I/O. The event loop is based on the reactor pattern (hence the name) and strongly inspired by libraries such as EventMachine (Ruby), Twisted (Python) and Node.js (V8).

This repository you're currently looking at is mostly used as a meta repository to discuss and plan all things @ReactPHP. See the individual components linked below for more details about each component, its documentation and source code.

Core Components

Network Components

Utility Components

Built with ReactPHP

  • Thruway PHP Client and Router Library for Autobahn and WAMP (Web Application Messaging Protocol) for Real-Time Application Messaging voryx/Thruway

  • PPM - PHP Process Manager PPM is a process manager, supercharger and load balancer for modern PHP applications. php-pm/php-pm

  • php-ar-drone 🚁 Port of node-ar-drone which allows user to control a Parrot AR Drone over PHP jolicode/php-ar-drone

  • Ratchet Asynchronous WebSocket server ratchetphp/Ratchet

  • Predis\Async Asynchronous PHP client library for Redis built on top of ReactPHP nrk/predis-async

  • clue/redis-server A Redis server implementation in pure PHP clue/redis-server

And many more on our wiki page »

Articles

  • Sergey Zhuk A series of articles covering ReactPHP: from the basics to the real application examples. sergeyzhuk.me

  • Cees-Jan Kiewiet Blog series about several ReactPHP components and how they work. blog.wyrihaximus.net

  • Loïc Faugeron Super Speed Symfony - ReactPHP. gnugat.github.io

  • Marc J. Schmidt Bring High Performance Into Your PHP App (with ReactPHP). marcjschmidt.de

  • Marc Morera When ReactPHP meet Symfony medium.com/@apisearch

Talks

Getting started

ReactPHP consists of a set of individual components. This means that instead of installing something like a "ReactPHP framework", you actually pick only the components that you need.

This project follows SemVer for all its stable components. The recommended way to install these components is through Composer. New to Composer?

For example, this may look something like this:

# recommended install: pick required components
composer require react/event-loop react/http

As an alternative, we also provide a meta package that will install all stable components at once. Installing this is only recommended for quick prototyping, as the list of stable components may change over time. This meta package can be installed like this:

# quick protoyping only: install all stable components
composer require react/react:^1.4

For more details, check out ReactPHP's homepage for quickstart examples and usage details.

See also the combined changelog for all ReactPHP components for details about version upgrades.

Support

Do you have a question and need help with ReactPHP? Don't worry, we're here to help!

As a first step, check the elaborate documentation that comes with each component (see links to individual documentation for each component above). If you find your question is not answered within the documentation, there's a fair chance that it may be relevant to more people. Please do not hesitate to file your question as an issue in the relevant component so others can also participate.

You can also check out our official Gitter chat room. Most of the people involved in this project are available in this chat room, so many questions get answered in a few minutes to some hours. We also use this chat room to announce all new releases and ongoing development efforts, so consider staying in this chat room for a little longer.

Also follow @reactphp on Twitter for updates. We use this mostly for noteworthy, bigger updates and to keep the community updated about ongoing development efforts. You can always use the #reactphp hashtag if you have anything to share!

We're a very open project and we prefer public communication whenever possible, so that more people can participate and help getting the best solutions available. At the same time, we realize that some things are better addressed in private. Whether you just want to say thank you, want to report a security issue or want to help sponsor a certain feature development, you can reach out to the core team in private by sending an email to [email protected]. Please keep in mind that we're a small team of volunteers and do our best to support anybody reaching out.

Do you want to support ReactPHP? Awesome! Let's start with letting the the world know why you think ReactPHP is awesome and try to help others getting on board! Send a tweet, write a blog post, give a talk at your local user group or conference or even write a book. There are many ways you can help. You can always reach out to us in private and help others in our support channels. Thank you!

Tests

To run the test suite, you first need to clone this repo and then install all dependencies through Composer:

composer install

To run the test suite, go to the project root and run:

vendor/bin/phpunit

The test suite also contains a number of functional integration tests that rely on a stable internet connection. Due to the vast number of integration tests, these are skipped by default during CI runs. If you also do not want to run these, they can simply be skipped like this:

vendor/bin/phpunit --exclude-group internet

License

MIT, see LICENSE.

dns's People

Contributors

akondas avatar arnaud-lb avatar carusogabriel avatar cboden avatar clue avatar e3betht avatar igorw avatar jsor avatar nhedger avatar nrk avatar othillo avatar reedy avatar sergiy-petrov avatar simonfrings avatar wyrihaximus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dns's Issues

Consider adding a passthrough resolver that skips IPs

Quite a few libraries in the react ecosystem require this DNS component to resolve a given hostname to an IP address. This step has to be skipped if the given address is in fact an IP address instead of a hostname. A common pattern looks like this:

protected function resolveHostname($host)
{
    if (false !== filter_var($host, FILTER_VALIDATE_IP)) {
        return Promise\resolve($host);
    }
    return $this->resolver->resolve($host);
}

Given that this is a pretty common pattern, we should consider if it makes sense to add this as part of this DNS component.

Why is $nameserver part of Resolver?

$nameserver in Resolver is only ever passed to the ExecutorInterface instance, as such it should probably just be the job of the ExecutorInterface instance to know the nameserver. This allows implementing other executors getting their nameservers from the system's config for example.

Fatal on call $conn->close() if connection was not created.

Query/Executor::doQuer(). if createConnection throws exception (eg. ErrorException: stream_socket_client(): unable to connect to udp://8.8.8.8:53 (Network is unreachable) if not internet connections) than timeout timer calls $conn->close() on "null object", which causes fatal: PHP Fatal error: Call to a member function close() on a non-object in /var/www/projects/DomainScrapper/vendor/react/dns/Query/Executor.php on line 62

Support Promise cancellation

We should register a Promise cancellation handler so that the following code actually cleans up the underlying socket resource:

$promise = $resolver->resolve('reactphp.org');

$promise->cancel();

(This likely depends on #19)

request inner host , error: DNS Request did not return valid answer.

`<?php

require("./vendor/autoload.php");

$loop = React\EventLoop\Factory::create();
$client = new React\HttpClient\Client($loop);

$url = "http://www.test.com/temp/test.php";

$request = $client->request('GET', $url);
$request->on('response', function ($response) {
$response->on('data', function ($chunk) {
writeLog($chunk);
});
$response->on('end', function() {
writeLog('DONE');
});
});
$request->on('error', function (\Exception $e) {
writeLog("error: \t" . $e->getMessage());
});

writeLog("1111111111111111");

$request->end();

writeLog("2222222222222222");
$loop->run();

function writeLog($log_str) {

echo $log_str . "\n";

}`

www.test.com is inner dns , code like this get a error: DNS Request did not return valid answer.

browser can open the website

Support DNS search domain list (resolve local hostname to FQDN)

We should support the domain and search options listed in /etc/resolv.conf (and possibly Windows' equivalent). Additionally, we should check the system hostname if it includes a domain part if the domain is not explicitly set.

This is useful in corporate and home networks where a short local alias is often used, i.e. intranet actually resolves to intranet.example.com.

See also https://linux.die.net/man/5/resolv.conf, https://linux.die.net/man/2/gethostname, https://unix.stackexchange.com/questions/128091/no-domain-defined-in-etc-resolv-conf and #98.

I'm not currently working on this, but figured it makes sense to report here in order to track this feature request. In case anybody feels like picking this up, any input and PRs would be much appreciated 👍

Test failure because f integer overflow on 32-bit system

There were 20 errors:
1) React\Tests\Dns\Query\TcpTransportExecutorTest::testTriggerIdleTimerAfterQueryRejectedOnCancellationWillCloseSocket
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:188
2) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryAgainAfterPreviousWasCancelledReusesExistingSocket
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:239
3) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryRejectsWhenServerIsNotListening
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:254
4) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryStaysPendingWhenClientCanNotSendExcessiveMessageInOneChunk
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:289
5) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryStaysPendingWhenClientCanNotSendExcessiveMessageInOneChunkWhenServerClosesSocket
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:332
6) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryRejectsWhenClientKeepsSendingWhenServerClosesSocket
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:366
7) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryRejectsWhenServerClosesConnection
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:416
8) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryKeepsPendingIfServerSendsIncompleteMessageLength
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:455
9) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryKeepsPendingIfServerSendsIncompleteMessageBody
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:489
10) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryRejectsWhenServerSendsInvalidMessage
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:520
11) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryRejectsWhenServerSendsInvalidId
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:571
12) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryRejectsIfServerSendsTruncatedResponse
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:622
13) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryResolvesIfServerSendsValidResponse
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:662
14) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryRejectsIfSocketIsClosedAfterPreviousQueryThatWasStillPending
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:685
15) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryResolvesIfServerSendsBackResponseMessageAndWillStartIdleTimer
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:719
16) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryResolvesIfServerSendsBackResponseMessageAfterCancellingQueryAndWillStartIdleTimer
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:753
17) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryResolvesIfServerSendsBackResponseMessageAfterCancellingOtherQueryAndWillStartIdleTimer
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:787
18) React\Tests\Dns\Query\TcpTransportExecutorTest::testTriggerIdleTimerAfterPreviousQueryResolvedWillCloseIdleSocketConnection
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:828
19) React\Tests\Dns\Query\TcpTransportExecutorTest::testClosingConnectionAfterPreviousQueryResolvedWillCancelIdleTimer
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:866
20) React\Tests\Dns\Query\TcpTransportExecutorTest::testQueryAgainAfterPreviousQueryResolvedWillReuseSocketAndCancelIdleTimer
TypeError: stream_set_chunk_size(): Argument #2 ($size) must be of type int, float given
/builddir/build/BUILDROOT/php-react-dns-1.5.0-1.fc35.noarch/usr/share/php/React/Dns/Query/TcpTransportExecutor.php:188
/builddir/build/BUILD/dns-b22b0b20278e8535e633ab71a52472c5bf620aa1/tests/Query/TcpTransportExecutorTest.php:904

32-bit arm is still quite common

Consider supporting "Special-Use Domain Names" (.localhost, .invalid etc.)

There are a number of "Special-Use Domain Names" as defined in https://tools.ietf.org/html/rfc6761, in particular the .localhost and .invalid domain names which we may to explicitly handle instead of passing it to the next domain resolver.

My local system (Ubuntu-based) uses a local domain resolver which takes care of this, so now that #29 is in, this is not a high priority to me. I'm not working on this at the moment, but figured it's worth posting this here anyway. In case anybody feels like picking this up, PRs would be much appreciated 👍

Windows Error: DNS query for google.com failed: too many retries

The code used is (using v0.4.3):

<?php
// dns.php
error_reporting(PHP_INT_MAX);

require_once 'vendor/autoload.php';

$loop = \React\EventLoop\Factory::create();
$factory = new \React\Dns\Resolver\Factory();
$dns = $factory->create('8.8.8.8', $loop);

$dns->resolve($argv[1])
    ->then(
        function ($ip) { echo "Host: $ip\n"; },
        function ($e) { echo "Error: {$e->getMessage()}\n"; }
);

$loop->run();

The command:

php dns.php google.com

The error:

Error: DNS query for google.com failed: too many retries

Is there any way I can debug this further to find out what's causing this? The same code on my linux box works just fine...

Support for multiple types of DNS records

Hi!

I'm looking to use react to build an app that would interact with Consul, ideally it would do so over normal DNS instead of over the HTTP api. For that to happen I would need this DNS library to support SRV records. Right now there´s only support for A and CNAME records (React\Dns\Protocol\Parser), I wanted to explore the idea of using a different approach and moving the DNS parsing to a different library, after researching some different options, this seem like a good candidate: https://github.com/DaveRandom/LibDNS.

That library is the same one used by icicle dns and it would allow to support much more record types without changing a lot of code here. Right now I think the biggest issue blocking this move would be that the library doesn´t parse streams per se, and with tcp queries ( >512 bytes responses) this could lead to some kind of blocking for extremely big payloads.

Has this road been explored? I´ve looking for info about this and on the https://github.com/async-interop/ group but I haven´t found much about it.

Has this been researched and discarded before?

thanks!
Great library!

PHP Fatal error: Maximum function nesting level of '256' reached, aborting! Protocol/Parser.php on line 293

When feed invalid data to Parser, we meet the fatal error.

Test data: hex2bin('80000000016db558016de4c8000000000000000400000001461fffff000005dc000020000000000137cdfa4000000000')

It is caused by the call between readLabels and getCompressedLabel


PHP 242. React\Dns\Protocol\Parser->readLabels($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:273
PHP 243. React\Dns\Protocol\Parser->getCompressedLabel($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:245
PHP 244. React\Dns\Protocol\Parser->readLabels($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:273
PHP 245. React\Dns\Protocol\Parser->getCompressedLabel($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:245
PHP 246. React\Dns\Protocol\Parser->readLabels($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:273
PHP 247. React\Dns\Protocol\Parser->getCompressedLabel($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:245
PHP 248. React\Dns\Protocol\Parser->readLabels($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:273
PHP 249. React\Dns\Protocol\Parser->getCompressedLabel($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:245
PHP 250. React\Dns\Protocol\Parser->readLabels($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:273
PHP 251. React\Dns\Protocol\Parser->getCompressedLabel($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:245
PHP 252. React\Dns\Protocol\Parser->readLabels($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:273
PHP 253. React\Dns\Protocol\Parser->getCompressedLabel($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:245
PHP 254. React\Dns\Protocol\Parser->readLabels($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:273
PHP 255. React\Dns\Protocol\Parser->getCompressedLabel($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:245
PHP 256. React\Dns\Protocol\Parser->getCompressedLabelOffset($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:272
    private function readLabels($data, $consumed)
    {
        $labels = array();

        while (true) {
            if ($this->isEndOfLabels($data, $consumed)) {
                $consumed += 1;
                break;
            }

            if ($this->isCompressedLabel($data, $consumed)) {
                list($newLabels, $consumed) = $this->getCompressedLabel($data, $consumed);
                $labels = array_merge($labels, $newLabels);
                break;
            }

DNS cache should properly limit TTL

This component and its cache support works reasonably well currently.

However, this implementation involves a lot of code because it was actually written before the underlying cache component supports TTL values. Once the underlying cache supports proper TTL values for its cache values via reactphp/cache#11, we should update this component to take advantage of this.

In particular, we should carefully follow the spec to apply proper TTL values, such as when a single query returns two records with varying TTLs.

Opening this ticket as a reminder – the implementation actually depends on reactphp/cache#11

Mark current version as stable / memory limit exceeded

I stumbled upon a problem with TcpTransportExecutor causing any memory limit to exceed in PHP 8.0 when using a simple query over google's 8.8.8.8 DNS server effectively breaking my implementation of communicating over sockets.
However your commits from Dec 6 fixed this. Current version of that class in dev-master works fine and doesn't break anything.

It cascades through several projects up to my main project. Sadly, sometimes there is a requirement to have minimum-stability: stable.
Please can you tag a new version with the current fixes, so it is marked as stable in composer? Thank you.

[RFC] API design for IPv6 and more types of records

Currently this package only supports A and CNAME records in it's implementation and after a quick chat with @clue earlier today we decided we need to come up with a good way support IPv6 and more record types. Here is a quick hack up to get the discussion started:

$resolver = new Resolver('8.8.8.8', Options::PREFER_IPV6);
// Tries to resolve AAAA (IPv6) record first and then tries the A (IPv4) record.
$resolver->resolve('wyrihaximus.net');
$resolver = new Resolver('8.8.8.8');
// Resolves to NS record
$resolver->resolve('wyrihaximus.net', RecordType::NS);

DNS query for X failed: too many retries.

I'm getting this Exception error message from file "/react/dns/src/Query/RetryExecutor.php":

DNS query for X failed: too many retries

I'm using 8.8.8.8 dns server and my libraries version are:
"react/http-client": "0.4.17"
"react/dns":"0.4.11"

I have tried using OpenDNS (208.67.222.222 and 208.67.220.220) but the problems persists...

How can I solve this? Thanks.

DNS cache size should be limited by default

The Factory::createCached() method currently creates an ArrayCache instance by default.The ArrayCache keeps growing and growing when new data is added to it. We should provide a sane default here to avoid consuming an excessive amount of memory.

Note that an explicit cache implementation can be given to avoid the above issue. This implementation could theoretically limit its cache size. It's beyond the control of this library to know whether such an implementation is used, but we should provide sane defaults here.

Opening this ticket as a reminder – the implementation depends on reactphp/cache#17

Exceptions constantly thrown in debugger

using "version": "v1.4.0"

Whenever I run my php in the debugger (vscode) and have it catch exceptions, I'm constantly getting this exception:

vendor/react/dns/src/Resolver/Resolver.php:(86)
Exception has occurred.
React\Dns\RecordNotFoundException: DNS query for discord.com did not return a valid answer (NOERROR / NODATA)

This is for a discord bot, so it connects to discord.com.

I run tcpdump and watch the dns requests and response - there are no issues, and I can always resolve the name using dig/host without any problems.

It's near-instantaneous, as soon as I click "run," it's stopped on that exception.

I hear on the discord group that anyone who debugs has this same problem, so I'm happy to dig into this and see if we can resolve it.

It may be the way the dns is invoked, if so, I'd be happy to get that cleared up for the discord coders.

Recursion and nesting level 1000 on dns resolve

Sometime I got ths fatal when trying to resolve some names. It is not stable but repeatable error. Last time I was able to repeat it with doing resolve for "edu.tc".

Just doing:

$factory = new DnsResolverFactory();
$resolver = $factory->create('8.8.8.8', $loop);
$resolver->resolve('edu.tc');

Here is head ot backtrace. After this part same repeatable calls promise notify.
PHP Fatal error: Maximum function nesting level of '100' reached, aborting! in /var/www/projects/DomainScrapper/vendor/react/promise/src/Promise.php on line 140

PHP Stack trace:
PHP   1. {main}() /usr/local/bin/phpunit:0
PHP   2. PHPUnit_TextUI_Command::main() /usr/local/bin/phpunit:612
PHP   3. PHPUnit_TextUI_Command->run() phar:///usr/local/bin/phpunit/phpunit/TextUI/Command.php:138
PHP   4. PHPUnit_TextUI_TestRunner->doRun() phar:///usr/local/bin/phpunit/phpunit/TextUI/Command.php:186
PHP   5. PHPUnit_Framework_TestSuite->run() phar:///usr/local/bin/phpunit/phpunit/TextUI/TestRunner.php:423
PHP   6. PHPUnit_Framework_TestCase->run() /var/www/projects/DomainScrapper/vendor/phpunit/phpunit/src/Framework/TestSuite.php:751
PHP   7. PHPUnit_Framework_TestResult->run() /var/www/projects/DomainScrapper/vendor/phpunit/phpunit/src/Framework/TestCase.php:711
PHP   8. PHPUnit_Framework_TestCase->runBare() /var/www/projects/DomainScrapper/vendor/phpunit/phpunit/src/Framework/TestResult.php:643
PHP   9. PHPUnit_Framework_TestCase->runTest() /var/www/projects/DomainScrapper/vendor/phpunit/phpunit/src/Framework/TestCase.php:775
PHP  10. ReflectionMethod->invokeArgs() /var/www/projects/DomainScrapper/vendor/phpunit/phpunit/src/Framework/TestCase.php:905
PHP  11. DomainScrapper\UnitTests\Whois\BaseClientTest->testGetAvailability_edutc_Null() /var/www/projects/DomainScrapper/vendor/phpunit/phpunit/src/Framework/TestCase.php:905
PHP  12. DomainScrapper\Whois\ReactCustomClient->getAvailability() /var/www/projects/DomainScrapper/tests/DomainScrapper/UnitTests/Whois/BaseClientTest.php:19
PHP  13. React\EventLoop\LibEventLoop->run() /var/www/projects/DomainScrapper/library/DomainScrapper/Whois/Client/AsyncToSyncTrait.php:38
PHP  14. event_base_loop() /var/www/projects/DomainScrapper/vendor/react/event-loop/LibEventLoop.php:211
PHP  15. React\EventLoop\LibEventLoop->React\EventLoop\{closure}() /var/www/projects/DomainScrapper/vendor/react/event-loop/LibEventLoop.php:211
PHP  16. call_user_func:{/var/www/projects/DomainScrapper/vendor/react/event-loop/LibEventLoop.php:335}() /var/www/projects/DomainScrapper/vendor/react/event-loop/LibEventLoop.php:335
PHP  17. React\Socket\Connection->handleData() /var/www/projects/DomainScrapper/vendor/react/event-loop/LibEventLoop.php:335
PHP  18. Evenement\EventEmitter->emit() /var/www/projects/DomainScrapper/vendor/react/socket/src/Connection.php:15
PHP  19. call_user_func_array:{/var/www/projects/DomainScrapper/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php:64}() /var/www/projects/DomainScrapper/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php:64
PHP  20. React\Stream\Util::React\Stream\{closure}() /var/www/projects/DomainScrapper/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php:64
PHP  21. React\Stream\BufferedSink->write() /var/www/projects/DomainScrapper/vendor/react/stream/src/Util.php:18
PHP  22. React\Promise\Deferred->progress() /var/www/projects/DomainScrapper/vendor/react/stream/src/BufferedSink.php:34
PHP  23. React\Promise\Deferred->notify() /var/www/projects/DomainScrapper/vendor/react/promise/src/Deferred.php:58
PHP  24. call_user_func:{/var/www/projects/DomainScrapper/vendor/react/promise/src/Deferred.php:49}() /var/www/projects/DomainScrapper/vendor/react/promise/src/Deferred.php:49
PHP  25. React\Promise\Promise->React\Promise\{closure}() /var/www/projects/DomainScrapper/vendor/react/promise/src/Deferred.php:49
PHP  26. React\Promise\Promise->notify() /var/www/projects/DomainScrapper/vendor/react/promise/src/Promise.php:175
PHP  27. React\Promise\Promise->React\Promise\{closure}() /var/www/projects/DomainScrapper/vendor/react/promise/src/Promise.php:147
PHP  28. React\Promise\Deferred->progress() /var/www/projects/DomainScrapper/vendor/react/promise/src/Promise.php:103
PHP  29. React\Promise\Deferred->notify() /var/www/projects/DomainScrapper/vendor/react/promise/src/Deferred.php:58
PHP  30. call_user_func:{/var/www/projects/DomainScrapper/vendor/react/promise/src/Deferred.php:49}() /var/www/projects/DomainScrapper/vendor/react/promise/src/Deferred.php:49
PHP  31. React\Promise\Promise->React\Promise\{closure}() /var/www/projects/DomainScrapper/vendor/react/promise/src/Deferred.php:49
PHP  32. React\Promise\Promise->notify() /var/www/projects/DomainScrapper/vendor/react/promise/src/Promise.php:175
PHP  33. React\Promise\Promise->React\Promise\{closure}() /var/www/projects/DomainScrapper/vendor/react/promise/src/Promise.php:147
PHP  34. React\Promise\Promise->notify() /var/www/projects/DomainScrapper/vendor/react/promise/src/Promise.php:175
PHP  35. React\Promise\Promise->React\Promise\{closure}() /var/www/projects/DomainScrapper/vendor/react/promise/src/Promise.php:147
PHP  36. React\Promise\Promise->notify() /var/www/projects/DomainScrapper/vendor/react/promise/src/Promise.php:175
PHP  37. React\Promise\Promise->React\Promise\{closure}() /var/www/projects/DomainScrapper/vendor/react/promise/src/Promise.php:147
PHP  38. React\Promise\Promise->notify() /var/www/projects/DomainScrapper/vendor/react/promise/src/Promise.php:175
PHP  39. React\Promise\Promise->React\Promise\{closure}() /var/www/projects/DomainScrapper/vendor/react/promise/src/Promise.php:147
.....

Windows error: DNS query for www.qq.com failed: too many retries

Country: China
OS: win10
reactphp/dns Version: 0.4.9
DNS: 114.114.114.114

ipconfig /all

Output:

无线局域网适配器 WLAN:

   连接特定的 DNS 后缀 . . . . . . . :
   描述. . . . . . . . . . . . . . . : Intel(R) Dual Band Wireless-AC 3160
   物理地址. . . . . . . . . . . . . : 00-1E-64-F1-CE-21
   DHCP 已启用 . . . . . . . . . . . : 是
   自动配置已启用. . . . . . . . . . : 是
   本地链接 IPv6 地址. . . . . . . . : fe80::7c11:b96f:80de:4889%16(首选)
   IPv4 地址 . . . . . . . . . . . . : 192.168.1.112(首选)
   子网掩码  . . . . . . . . . . . . : 255.255.255.0
   获得租约的时间  . . . . . . . . . : 2017年6月22日 9:21:17
   租约过期的时间  . . . . . . . . . : 2017年6月22日 16:44:09
   默认网关. . . . . . . . . . . . . : 192.168.1.1
   DHCP 服务器 . . . . . . . . . . . : 192.168.1.1
   DHCPv6 IAID . . . . . . . . . . . : 83893860
   DHCPv6 客户端 DUID  . . . . . . . : 00-01-00-01-20-AE-FB-13-00-23-81-23-CA-07

   DNS 服务器  . . . . . . . . . . . : 114.114.114.114

   TCPIP 上的 NetBIOS  . . . . . . . : 已启用

Code:

$ip = gethostbyname('www.qq.com');
var_dump($ip);

Output:

string(13) "180.96.86.192"

Code:

$loop = React\EventLoop\Factory::create();
$factory = new React\Dns\Resolver\Factory();
$dns = $factory->create('114.114.114.114', $loop);

$dns->resolve('www.qq.com')->then(function ($ip) {
    echo "Host: $ip\n";
}, function(RuntimeException $exception){
    echo $exception->getMessage();
});
$loop->run();

Output:

DNS query for www.qq.com failed: too many retries

Connection to DNS server lost

I am trying to get all the records for a domain with actual TTL value from authoritative DNS server (something like DNS_ALL but with authoritative TTL value). This seems to work until I got RuntimeException with "Connection to DNS server lost".

Below are sample code and error message:

<?php

use React\Dns\Model\Message;
use React\Dns\Query\Query;
use React\Dns\Query\TcpTransportExecutor;

require './vendor/autoload.php';

$dnsRecords = [];

$domain = 'cloudflare.com';
$authNameServerIP = '162.159.0.33';
//$authNameServerIP = '162.159.1.33';
//$authNameServerIP = '162.159.2.9';
//$authNameServerIP = '162.159.3.11';
//$authNameServerIP = '162.159.4.8';

$loop = \React\EventLoop\Factory::create();
$executor = new TcpTransportExecutor($authNameServerIP, $loop);

$reflector = new \ReflectionClass(Message::class);
$typeConstants = $reflector->getReflectionConstants();

foreach ($typeConstants as $typeConstant) {
    if ($typeConstant->getName() == 'TYPE_ANY' || strpos($typeConstant->getName(), 'TYPE_') !== 0) {
        continue;
    }

    $query = new Query($domain, $typeConstant->getValue(), Message::CLASS_IN);
    $executor->query($query)->then(function (Message $message) use (&$dnsRecords) {
        foreach ($message->answers as $answer) {
            $dnsRecords[] = [
                'type' => $answer->type,
                'ttl' => $answer->ttl,
                'data' => $answer->data
            ];
        }
    }, 'printf');
}

$loop->run();

print PHP_EOL;
var_export($dnsRecords);
print PHP_EOL;

and below is the output:

RuntimeException: DNS query for cloudflare.com failed: Connection to DNS server lost in /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php:327
Stack trace:
#0 /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php(259): React\Dns\Query\TcpTransportExecutor->closeError('Connection to D...')
#1 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(244): React\Dns\Query\TcpTransportExecutor->handleRead(Resource id #25)
#2 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(211): React\EventLoop\StreamSelectLoop->waitForStreamActivity(NULL)
#3 /PATH-REDACTED/test.php(41): React\EventLoop\StreamSelectLoop->run()
#4 {main}RuntimeException: DNS query for cloudflare.com failed: Connection to DNS server lost in /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php:327
Stack trace:
#0 /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php(259): React\Dns\Query\TcpTransportExecutor->closeError('Connection to D...')
#1 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(244): React\Dns\Query\TcpTransportExecutor->handleRead(Resource id #25)
#2 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(211): React\EventLoop\StreamSelectLoop->waitForStreamActivity(NULL)
#3 /PATH-REDACTED/test.php(41): React\EventLoop\StreamSelectLoop->run()
#4 {main}RuntimeException: DNS query for cloudflare.com failed: Connection to DNS server lost in /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php:327
Stack trace:
#0 /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php(259): React\Dns\Query\TcpTransportExecutor->closeError('Connection to D...')
#1 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(244): React\Dns\Query\TcpTransportExecutor->handleRead(Resource id #25)
#2 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(211): React\EventLoop\StreamSelectLoop->waitForStreamActivity(NULL)
#3 /PATH-REDACTED/test.php(41): React\EventLoop\StreamSelectLoop->run()
#4 {main}RuntimeException: DNS query for cloudflare.com failed: Connection to DNS server lost in /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php:327
Stack trace:
#0 /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php(259): React\Dns\Query\TcpTransportExecutor->closeError('Connection to D...')
#1 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(244): React\Dns\Query\TcpTransportExecutor->handleRead(Resource id #25)
#2 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(211): React\EventLoop\StreamSelectLoop->waitForStreamActivity(NULL)
#3 /PATH-REDACTED/test.php(41): React\EventLoop\StreamSelectLoop->run()
#4 {main}RuntimeException: DNS query for cloudflare.com failed: Connection to DNS server lost in /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php:327
Stack trace:
#0 /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php(259): React\Dns\Query\TcpTransportExecutor->closeError('Connection to D...')
#1 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(244): React\Dns\Query\TcpTransportExecutor->handleRead(Resource id #25)
#2 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(211): React\EventLoop\StreamSelectLoop->waitForStreamActivity(NULL)
#3 /PATH-REDACTED/test.php(41): React\EventLoop\StreamSelectLoop->run()
#4 {main}RuntimeException: DNS query for cloudflare.com failed: Connection to DNS server lost in /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php:327
Stack trace:
#0 /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php(259): React\Dns\Query\TcpTransportExecutor->closeError('Connection to D...')
#1 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(244): React\Dns\Query\TcpTransportExecutor->handleRead(Resource id #25)
#2 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(211): React\EventLoop\StreamSelectLoop->waitForStreamActivity(NULL)
#3 /PATH-REDACTED/test.php(41): React\EventLoop\StreamSelectLoop->run()
#4 {main}RuntimeException: DNS query for cloudflare.com failed: Connection to DNS server lost in /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php:327
Stack trace:
#0 /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php(259): React\Dns\Query\TcpTransportExecutor->closeError('Connection to D...')
#1 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(244): React\Dns\Query\TcpTransportExecutor->handleRead(Resource id #25)
#2 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(211): React\EventLoop\StreamSelectLoop->waitForStreamActivity(NULL)
#3 /PATH-REDACTED/test.php(41): React\EventLoop\StreamSelectLoop->run()
#4 {main}RuntimeException: DNS query for cloudflare.com failed: Connection to DNS server lost in /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php:327
Stack trace:
#0 /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php(259): React\Dns\Query\TcpTransportExecutor->closeError('Connection to D...')
#1 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(244): React\Dns\Query\TcpTransportExecutor->handleRead(Resource id #25)
#2 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(211): React\EventLoop\StreamSelectLoop->waitForStreamActivity(NULL)
#3 /PATH-REDACTED/test.php(41): React\EventLoop\StreamSelectLoop->run()
#4 {main}RuntimeException: DNS query for cloudflare.com failed: Connection to DNS server lost in /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php:327
Stack trace:
#0 /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php(259): React\Dns\Query\TcpTransportExecutor->closeError('Connection to D...')
#1 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(244): React\Dns\Query\TcpTransportExecutor->handleRead(Resource id #25)
#2 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(211): React\EventLoop\StreamSelectLoop->waitForStreamActivity(NULL)
#3 /PATH-REDACTED/test.php(41): React\EventLoop\StreamSelectLoop->run()
#4 {main}RuntimeException: DNS query for cloudflare.com failed: Connection to DNS server lost in /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php:327
Stack trace:
#0 /PATH-REDACTED/vendor/react/dns/src/Query/TcpTransportExecutor.php(259): React\Dns\Query\TcpTransportExecutor->closeError('Connection to D...')
#1 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(244): React\Dns\Query\TcpTransportExecutor->handleRead(Resource id #25)
#2 /PATH-REDACTED/vendor/react/event-loop/src/StreamSelectLoop.php(211): React\EventLoop\StreamSelectLoop->waitForStreamActivity(NULL)
#3 /PATH-REDACTED/test.php(41): React\EventLoop\StreamSelectLoop->run()
#4 {main}
array (
  0 => 
  array (
    'type' => 1,
    'ttl' => 300,
    'data' => '198.41.215.162',
  ),
  1 => 
  array (
    'type' => 1,
    'ttl' => 300,
    'data' => '198.41.214.162',
  ),
)

Add dummy placeholder Resolver (implement the null object pattern)

This library should include a dummy Resolver that fulfills the current interface without actually resolving any domain names. All calls to resolve() should be handled with a rejected Promise. This class will be useful for components that currently require a Resolver but (potentially) could also work without actually resolving any domain names (reactphp/socket-client, reactphp/socket, reactphp/datagram etc.).

The Resolver is currently a single class with no explicit interface definition, so adding a dedicated NullResolver interface would be a bit of work (and possibly a BC break). Instead, we may want to look into passing a (new) NullExecutor to the current Resolver.

Opening this ticket as a reminder and for referencing related tickets.

Querying via TCP broken

This lib implements communication via UDP and TCP, however the TCP implementation is broken in several ways:

  • Messages sent over TCP (both directions) are to be prefixed by the message length, as per RFC 1035 section 4.2.2, here
  • Messages can be chunked and have to be reassembled based on the length prefix, here
  • Uses blocking stream_socket_client() call to connect to the DNS server, here
  • Uses Connection from the react/socket (server!) component, should use react/socket-client, here

Looks like some of these points are currently being addressed as part of #8.

Question using protocol classes directly

Hi there,

For a prove of concept (handling DNS notify queries) I use the protocol classes Parser and BinaryDumper directly. Before I start thinking about production code. Is it wisely to use these classes directly? Are they meant for internal use only?

Cheers,

Frank

Limit number of concurrent DNS queries

Add an executor to limit the number of concurrent DNS queries and queue or reject additional ones.

Additionally, sending the same query in parallel and waiting for a reply for each doesn't make much sense. In particular the caching executor should probably also take this into account.

Roadmap to stable v1.0.0

Let's face it, this project is stable and has been used in production for years :shipit:

However, we're currently following a v0.X.Y release scheme (http://sentimentalversioning.org/).

We should finally make this explicit and fully adhere to SemVer and release a stable v1.0.0.

To a large extend, a stable v1.0.0 helps making BC breaks more explicit and thus the whole project more reliable from a consumer perspective. This project is actively maintained and has received some major updates in the last years and only has some minor updates planned in the next weeks. Given our current versioning scheme, we'd like to ensure all anticipated BC breaks will be merged before the planned v1.0.0 release.

As such, I've set up a quick roadmap that enlists the major upcoming changes with planned release dates towards a stable v1.0.0 release:

v0.4.18 ✅

  • Released 2019-07-09
  • DNS caching fixes

v1.0.0 ✅

  • Released 2019-07-11
  • Drop deprecated APIs
  • Mark internal APIs as such
  • No other changes planned, this should merely mark the previous release as "stable"

This ticket aims to serve as a basic overview and does not contain every single change. Please also see the milestone links and the CHANGELOG for more details.

Obviously, this roadmap is subject to change and I'll try to keep it updated as we progress. In order to avoid cluttering this, please keep discussion in this ticket to a minimum and consider reaching out to us through new tickets or Twitter etc.

Resolving raises an error in the Stream component

Resolving any name raises an error in the Stream component:

Warning: feof(): 60 is not a valid stream resource in .. /src/Socket/Connection.php on line 18

This happens because this component uses the React\Socket\Connection class instead of the React\Stream\Stream class.

Originally reported in: reactphp/socket#4
Documentation bug: reactphp/socket#13
See also: #11


The following is copied from reactphp/socket#4, originally reported by @jeremykendall

I got (almost) the same error this morning while working on the DNS basic usage example. Maybe this could help replicate the warning:

<?php
// dns.php
error_reporting(PHP_INT_MAX);

require_once 'vendor/autoload.php';

$loop = \React\EventLoop\Factory::create();
$factory = new \React\Dns\Resolver\Factory();
$dns = $factory->create('8.8.8.8', $loop);

$dns->resolve($argv[1])
    ->then(
        function ($ip) { echo "Host: $ip\n"; },
        function ($e) { echo "Error: {$e->getMessage()}\n"; }
);

$loop->run();

Running php dns.php jeremykendall.net returned:

$ php dns.php jeremykendall.net
Host: 50.57.159.57
PHP Warning:  feof(): 33 is not a valid stream resource in /Users/jeremykendall/dev/explore-react/vendor/react/react/src/Socket/Connection.php on line 18
PHP Stack trace:
PHP   1. {main}() /Users/jeremykendall/dev/explore-react/dns.php:0
PHP   2. React\EventLoop\StreamSelectLoop->run() /Users/jeremykendall/dev/explore-react/dns.php:17
PHP   3. React\EventLoop\StreamSelectLoop->waitForStreamActivity() /Users/jeremykendall/dev/explore-react/vendor/react/react/src/EventLoop/StreamSelectLoop.php:201
PHP   4. call_user_func:{/Users/jeremykendall/dev/explore-react/vendor/react/react/src/EventLoop/StreamSelectLoop.php:227}() /Users/jeremykendall/dev/explore-react/vendor/react/react/src/EventLoop/StreamSelectLoop.php:227
PHP   5. React\Socket\Connection->handleData() /Users/jeremykendall/dev/explore-react/vendor/react/react/src/EventLoop/StreamSelectLoop.php:227
PHP   6. feof() /Users/jeremykendall/dev/explore-react/vendor/react/react/src/Socket/Connection.php:18

Warning: feof(): 33 is not a valid stream resource in /Users/jeremykendall/dev/explore-react/vendor/react/react/src/Socket/Connection.php on line 18

Call Stack:
    0.0002     238968   1. {main}() /Users/jeremykendall/dev/explore-react/dns.php:0
    0.0060     906616   2. React\EventLoop\StreamSelectLoop->run() /Users/jeremykendall/dev/explore-react/dns.php:17
    0.0062     907648   3. React\EventLoop\StreamSelectLoop->waitForStreamActivity() /Users/jeremykendall/dev/explore-react/vendor/react/react/src/EventLoop/StreamSelectLoop.php:201
    0.0515     908184   4. call_user_func:{/Users/jeremykendall/dev/explore-react/vendor/react/react/src/EventLoop/StreamSelectLoop.php:227}() /Users/jeremykendall/dev/explore-react/vendor/react/react/src/EventLoop/StreamSelectLoop.php:227
    0.0515     908312   5. React\Socket\Connection->handleData() /Users/jeremykendall/dev/explore-react/vendor/react/react/src/EventLoop/StreamSelectLoop.php:227
    0.0527     913368   6. feof() /Users/jeremykendall/dev/explore-react/vendor/react/react/src/Socket/Connection.php:18

Environment:

Mac OS X 10.9.4
PHP 5.5.12
React 0.4.1
$ php -v
PHP 5.5.12 (cli) (built: May 23 2014 15:03:24)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies
    with Xdebug v2.2.4, Copyright (c) 2002-2014, by Derick Rethans

Consider implementing random case to increase message entropy (0x20 hack)

Implementing random case for outgoing DNS queries can help improve message entropy and significantly reduce the risk for DNS poisoning attacks for certain scenarios.

Links for the reference:

This is particularly relevant for UDP queries (the default) and may be less so for in-flight messages over connection oriented protocols (#19 and #80).

I'm not working on this at the moment, but figured it's worth posting this here anyway. In case anybody feels like picking this up, PRs would be much appreciated 👍

Tests fail with PHP 7.1

Tested with PHP 7.1.0 and 7.1.3

There were 3 errors:

1) React\Tests\Dns\Query\ExecutorTest::resolveShouldRetryWithTcpIfResponseIsTruncated
ArgumentCountError: Too few arguments to function React\Tests\Dns\Query\ExecutorTest::React\Tests\Dns\Query\{closure}(), 1 passed in /tmp/dns/vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/ReturnCallback.php on line 25 and exactly 2 expected

/tmp/dns/tests/Query/ExecutorTest.php:352
/tmp/dns/src/Query/Executor.php:113
/tmp/dns/tests/Query/ExecutorTest.php:410
/tmp/dns/src/Query/Executor.php:133
/tmp/dns/src/Query/Executor.php:73
/tmp/dns/src/Query/Executor.php:125
/tmp/dns/tests/Query/ExecutorTest.php:410
/tmp/dns/src/Query/Executor.php:133
/tmp/dns/src/Query/Executor.php:46
/tmp/dns/tests/Query/ExecutorTest.php:163

2) React\Tests\Dns\Query\ExecutorTest::resolveShouldRetryWithTcpIfUdpThrows
ArgumentCountError: Too few arguments to function React\Tests\Dns\Query\ExecutorTest::React\Tests\Dns\Query\{closure}(), 1 passed in /tmp/dns/vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/ReturnCallback.php on line 25 and exactly 2 expected

/tmp/dns/tests/Query/ExecutorTest.php:352
/tmp/dns/src/Query/Executor.php:113
/tmp/dns/tests/Query/ExecutorTest.php:410
/tmp/dns/src/Query/Executor.php:133
/tmp/dns/src/Query/Executor.php:46
/tmp/dns/tests/Query/ExecutorTest.php:194

3) React\Tests\Dns\Query\ExecutorTest::resolveShouldCancelTimerWhenFullResponseIsReceived
ArgumentCountError: Too few arguments to function React\Tests\Dns\Query\ExecutorTest::React\Tests\Dns\Query\{closure}(), 1 passed in /tmp/dns/vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/ReturnCallback.php on line 25 and exactly 2 expected

/tmp/dns/tests/Query/ExecutorTest.php:352
/tmp/dns/src/Query/Executor.php:113
/tmp/dns/tests/Query/ExecutorTest.php:410
/tmp/dns/src/Query/Executor.php:133
/tmp/dns/src/Query/Executor.php:46
/tmp/dns/tests/Query/ExecutorTest.php:304

Gate way issue Discord

9833a7395829bb4e2d56.js:108 WebSocket connection to 'wss://gateway.discord.gg/?encoding=etf&v=6&compress=zstd-stream' failed: Error during WebSocket handshake: Unexpected response code: 520 I need some help as soon as anone can

Ask host OS for DNS service address at startup, if none given by caller

Is it possible to fix reactphp/dns so that if you pass in '' as the DNS service address, it puts resolution on hold and asks the host OS for the correct address to use, before performing any DNS queries?

I arrived here after finding Google's DNS address hard-coded in Phergie IRC framework... This rubs me the wrong way. 1) Google's DNS shouldn't be hard-coded in places like this. 2) Eventually someone's going to fail to setup a non-Internet private network service and wonder why can't lookup any local addresses.

It's fairly easy to do it with shell commands on Windows; here are some answers for doing it from a Unix shell

Support DNS over TLS

All DNS queries are currently sent in plaintext over UDP sockets. There's an open issue to support querying via TCP/IP in #19.

Once this feature is in, we may want to support DNS over TLS as defined in RFC 7858. Once TCP/IP support is in, this should be fairly easy.

Bug in new version of socket

Create composer.json
{ "require": { "react/dns": "0.4.8" } }

$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 8 installs, 0 updates, 0 removals

  • Installing react/promise (v2.5.1): Downloading (100%)
  • Installing react/cache (v0.4.1): Downloading (100%)
  • Installing react/event-loop (v0.4.3): Downloading (100%)
  • Installing react/promise-timer (v1.1.1): Downloading (100%)
  • Installing evenement/evenement (v2.0.0): Downloading (100%)
  • Installing react/stream (v0.6.0): Downloading (100%)
  • Installing react/socket (v0.7.2): Downloading (100%)
  • Installing react/dns (v0.4.8): Downloading (100%)
    react/event-loop suggests installing ext-libevent (>=0.1.0)
    react/event-loop suggests installing ext-event (~1.0)
    react/event-loop suggests installing ext-libev (*)
    Writing lock file
    Generating autoload files

Copy vendor/react/dns/examples/01-one.php to test.php and change:
require __DIR__ . '/../vendor/autoload.php';
to
require 'vendor/autoload.php';

$ php test.php
IP for www.google.com: 173.194.113.211

After that change composer.json to:
{ "require": { "react/dns": "0.4.9" } }

$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 0 installs, 3 updates, 0 removals

  • Updating react/stream (v0.6.0 => v0.7.0): Downloading (100%)
  • Updating react/dns (v0.4.8 => v0.4.9): Downloading (100%)
  • Updating react/socket (v0.7.2 => v0.8.0): Downloading (100%)
    Writing lock file
    Generating autoload files

And run:

$ php test.php

React\Promise\Timer\TimeoutException: Timed out after 5 seconds in /tmp/test/vendor/react/promise-timer/src/functions.php:21
Stack trace:
// ...

DNS query for www.google.com failed: too many retries

Exception unreal4u\TelegramAPI\Exceptions\ClientException caught, message: DNS query for api.telegram.org failed: too many retries

I tried to use only dns too
"name": "react/dns",
"version": "v0.4.11",

from examples
but there is a fail:
DNS query for www.google.com failed: too many retries

01-one.php.txt

Google and api.telegram are enabled and visible from my network and from server network

querying for SOA but got CNAME instead of empty answer or error

here is the code:

$loop = LoopFactory::create();
$executor = new TcpTransportExecutor('8.8.8.8:53', $loop);

$query = new Query('chrome.blogspot.com', Message::TYPE_SOA, Message::CLASS_IN);

$executor->query($query)->then(function (Message $message) {
    var_export((array)$message);
});

$loop->run();

and response:

array (
  'id' => 35669,
  'qr' => true,
  'opcode' => 0,
  'aa' => false,
  'tc' => false,
  'rd' => true,
  'ra' => true,
  'rcode' => 0,
  'questions' => 
  array (
    0 => 
    React\Dns\Query\Query::__set_state(array(
       'name' => 'chrome.blogspot.com',
       'type' => 6,
       'class' => 1,
    )),
  ),
  'answers' => 
  array (
    0 => 
    React\Dns\Model\Record::__set_state(array(
       'name' => 'chrome.blogspot.com',
       'type' => 5,
       'class' => 1,
       'ttl' => 2864,
       'data' => 'blogspot.l.googleusercontent.com',
    )),
  ),
  'authority' => 
  array (
    0 => 
    React\Dns\Model\Record::__set_state(array(
       'name' => 'l.googleusercontent.com',
       'type' => 6,
       'class' => 1,
       'ttl' => 59,
       'data' => 
      array (
        'mname' => 'ns1.google.com',
        'rname' => 'dns-admin.google.com',
        'serial' => 271311469,
        'refresh' => 900,
        'retry' => 900,
        'expire' => 1800,
        'minimum' => 60,
      ),
    )),
  ),
  'additional' => 
  array (
  ),
)

Consider supporting advanced DNS config (nsswitch,conf, hosts.conf, resolv.conf options and ENV variables etc.)

We may want to look into supporting the settings from /etc/nsswitch.conf, /etc/hosts.conf, /etc/resolv.conf options and respective ENV variables such as RES_OPTIONS, RESOLV_HOST_CONF etc.

As of #75 we currently default to always checking the /etc/hosts before passing the request to the DNS resolver (which uses the correct nameserver entry from /etc/resolv.conf as of #29. Technically, the above files and ENV variables can be used to change the order and resolutions options, but this appears to be rarely used in practice. See also the respective man pages for more details.

My local system (Ubuntu-based) uses a local domain resolver which takes care of this, so now that #29 is in, this is not a high priority to me. I'm not working on this at the moment, but figured it's worth posting this here anyway. In case anybody feels like picking this up, PRs would be much appreciated +1

DNS Cache is not used when the type of the response record is CNAME

Hi guys, I'm making an X amount of asynchronous requests using the reactphp HttpClient and I noticed that for every single request it always tries to resolve the DNS, instead of using the cached version.

I saw that the connect method in the DnsConnector calls the resolve method of the Resolver.
Then I used one of the code examples in the repo to test it and try to figure out why it doesn't use the cache. This code tries to resolve the same domain two times and while I am running I listen to the udp port 53 to see if there is an attempt of resolving the domain.

        $loop = \React\EventLoop\Factory::create();
        $config = Config::loadSystemConfigBlocking();
        $server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8';
        $factory = new Factory();
        $resolver = $factory->createCached($server, $loop);
        $name = 'any.example.com';
        $resolver->resolve($name)->then(function ($ip) use ($name) {
            echo 'IP for ' . $name . ': ' . $ip . PHP_EOL;
        }, 'printf');
        
        $loop->addTimer(1.0, function() use ($name, $resolver) {
            $resolver->resolve($name)->then(function ($ip) use ($name) {
                echo 'IP for ' . $name . ': ' . $ip . PHP_EOL;
            }, 'printf');
        });
        $loop->run();

Let's suppose that the $name variable is equal to 'example.com' and we run the code above. It resolves the domain the first time and then the second time it gets from the cache as expected without making any call to the DNS server.

However, let's suppose that $name is equal to 'test.example.com'. It resolves the domain the first time when the resolve method in the code above is called, but when it is called for the second time, instead of getting the value from the cache, it resolves the same domain again.

One difference between the both examples is that in the first one, the DNS server responds with a record of type A (id 1) while in the second one it responds with type CNAME (id 5).

When the cache is saved, this type is used as part of the cache key generated here.

Having this in mind, let's try to run the first example with URL example.com.

The resolve method is called, a cache lookup is done, no entry is found and then a request is done to the DNS server which responds with a TYPE A record. During the second call of the resolve method, a cache lookup is done and an entry with the key 'example.com:1:1' is found \o/

For the URL test.example.com, the resolve method is called, a cache lookup is done, no entry is found and the server responds with a TYPE CNAME record. The cache is then saved with the key: 'test.example.com:5:1'. During the second call, a cache lookup is done and it tries to look for the key 'test.example.com:1:1' because of the default Message::TYPE_A in resolve method which is called on the DnsConnector. As a result, it does not find the cache and it calls the DNS server again.

One question I have is why do we need to specify the record type in the cache? is it possible to have such records coexisting 'example.com:5' and 'example.com:1'?

How could I continue making the assynchronous call with the client without resolving the same domain multiple times?

$loop = React\EventLoop\Factory::create();
$client = new Client($loop);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.