raimx / dns
ReactPHP 的异步 DNS 解析器
Requires
- php: >=5.3.0
- react/cache: ^1.0 || ^0.6 || ^0.5
- react/event-loop: ^1.0 || ^0.5 || ^0.4 || ^0.3.5
- react/promise: ^2.1 || ^1.2.1
- react/promise-timer: ^1.2
Requires (Dev)
- clue/block-react: ^1.2
- phpunit/phpunit: ^7.0 || ^6.4 || ^5.7 || ^4.8.35
This package is auto-updated.
Last update: 2021-08-29 02:09:00 UTC
README
异步 DNS 解析器,用于 ReactPHP。
DNS 组件的主要目的是提供异步 DNS 解析。然而,它实际上是一个处理 DNS 消息的工具包,可以很容易地用来创建 DNS 服务器。
目录
基本用法
最基础的用法是创建一个解析器,通过解析器工厂。你需要给它一个域名服务器,然后就可以开始解析名字了,宝贝!
$loop = React\EventLoop\Factory::create(); $config = React\Dns\Config\Config::loadSystemConfigBlocking(); $server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8'; $factory = new React\Dns\Resolver\Factory(); $dns = $factory->create($server, $loop); $dns->resolve('igor.io')->then(function ($ip) { echo "Host: $ip\n"; }); $loop->run();
参见 第一个示例。
可以使用 Config
类来加载系统默认配置。这是一个可能访问文件系统并阻塞的操作。因此,理想情况下,应该在循环开始之前只执行一次,而不是在运行过程中重复执行。请注意,如果系统配置无法加载,则此类可能会返回一个空的配置。因此,如果您找不到任何配置,可能需要像上面那样应用默认域名服务器。
请注意,工厂在创建解析器实例时,会从文件系统中加载一次主机文件。因此,理想情况下,应该在循环开始之前只执行一次,而不是在运行过程中重复执行。
但是还有更多。
缓存
您可以通过将解析器配置为使用 CachedExecutor
来缓存结果
$loop = React\EventLoop\Factory::create(); $config = React\Dns\Config\Config::loadSystemConfigBlocking(); $server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8'; $factory = new React\Dns\Resolver\Factory(); $dns = $factory->createCached($server, $loop); $dns->resolve('igor.io')->then(function ($ip) { echo "Host: $ip\n"; }); ... $dns->resolve('igor.io')->then(function ($ip) { echo "Host: $ip\n"; }); $loop->run();
如果第一个调用在第二个调用之前返回,则只会执行一个查询。第二个结果将从一个内存缓存中提供服务。这对于需要多次查找相同主机名的长时间运行的脚本非常有用。
参见 第三个示例。
自定义缓存适配器
默认情况下,这会使用内存缓存。
您还可以指定一个自定义缓存,该缓存实现 CacheInterface
,以处理记录缓存
$cache = new React\Cache\ArrayCache(); $loop = React\EventLoop\Factory::create(); $factory = new React\Dns\Resolver\Factory(); $dns = $factory->createCached('8.8.8.8', $loop, $cache);
参见维基百科中可能的 缓存实现。
ResolverInterface
resolve()
可以使用 resolve(string $domain): PromiseInterface<string,Exception>
方法将给定的 $domain 域名解析为单个 IPv4 地址(类型 A
查询)。
$resolver->resolve('reactphp.org')->then(function ($ip) { echo 'IP for reactphp.org is ' . $ip . PHP_EOL; });
这是本包中的主要方法之一。它向您的 DNS 服务器发送针对给定 $domain 域名的 DNS 查询,并在成功时返回单个 IP 地址。
如果DNS服务器发送的DNS响应消息包含针对此查询的多个IP地址,它将随机从响应中选取一个IP地址。如果您想获取完整的IP地址列表或想发送不同类型的查询,应使用resolveAll()
方法。
如果DNS服务器发送的DNS响应消息指示错误代码,此方法将使用RecordNotFoundException
拒绝。其消息和代码可以用来检查响应代码。
如果DNS通信失败,服务器未以有效的响应消息回应,此消息将使用Exception
拒绝。
可以通过取消其挂起的Promise来取消挂起的DNS查询,如下所示:
$promise = $resolver->resolve('reactphp.org'); $promise->cancel();
resolveAll()
resolveAll(string $host, int $type): PromiseInterface<array,Exception>
方法可用于解析给定$domain名称和查询类型中的所有记录值。
$resolver->resolveAll('reactphp.org', Message::TYPE_A)->then(function ($ips) { echo 'IPv4 addresses for reactphp.org ' . implode(', ', $ips) . PHP_EOL; }); $resolver->resolveAll('reactphp.org', Message::TYPE_AAAA)->then(function ($ips) { echo 'IPv6 addresses for reactphp.org ' . implode(', ', $ips) . PHP_EOL; });
这是本包中的主要方法之一。它向您的DNS服务器发送针对给定$domain名称的DNS查询,并在成功时返回包含所有记录值的列表。
如果DNS服务器发送包含针对此查询的一个或多个记录的DNS响应消息,它将返回包含所有记录值的列表。您可以使用Message::TYPE_*
常量来控制发送哪种类型的查询。请注意,此方法始终返回记录值的列表,但每种记录值的类型取决于查询类型。例如,它返回类型为A
的查询的IPv4地址,类型为AAAA
的查询的IPv6地址,类型为NS
、CNAME
和PTR
的查询的主机名,以及其他查询的结构化数据。有关更多详细信息,请参阅Record
文档。
如果DNS服务器发送的DNS响应消息指示错误代码,此方法将使用RecordNotFoundException
拒绝。其消息和代码可以用来检查响应代码。
如果DNS通信失败,服务器未以有效的响应消息回应,此消息将使用Exception
拒绝。
可以通过取消其挂起的Promise来取消挂起的DNS查询,如下所示:
$promise = $resolver->resolveAll('reactphp.org', Message::TYPE_AAAA); $promise->cancel();
高级用法
UdpTransportExecutor
可以使用UdpTransportExecutor
通过UDP传输发送DNS查询。
这是向您的DNS服务器发送DNS查询的主要类,并由Resolver
内部用于实际消息传输。
对于更高级的使用,可以直接使用此类。以下示例查找igor.io
的IPv6
地址。
$loop = Factory::create(); $executor = new UdpTransportExecutor('8.8.8.8:53', $loop); $executor->query( new Query($name, Message::TYPE_AAAA, Message::CLASS_IN) )->then(function (Message $message) { foreach ($message->answers as $answer) { echo 'IPv6: ' . $answer->data . PHP_EOL; } }, 'printf'); $loop->run();
请参阅第四个示例。
请注意,此执行器不实现超时,因此您可能会想将其与TimeoutExecutor
一起使用,如下所示:
$executor = new TimeoutExecutor( new UdpTransportExecutor($nameserver, $loop), 3.0, $loop );
此外,请注意,此执行器使用不可靠的UDP传输,并且没有实现任何重试逻辑,因此您可能会想将其与RetryExecutor
一起使用,如下所示:
$executor = new RetryExecutor( new TimeoutExecutor( new UdpTransportExecutor($nameserver, $loop), 3.0, $loop ) );
请注意,此执行器完全是异步的,因此您可以在应用程序中并发执行任意数量的查询。您可能需要限制应用程序中并发查询的数量,否则您可能会在解析器端面临速率限制和封禁。对于许多常见应用,您可能希望在第一个查询仍然挂起时避免发送相同的查询多次,因此您可能会想将其与CoopExecutor
一起使用,如下所示:
$executor = new CoopExecutor( new RetryExecutor( new TimeoutExecutor( new UdpTransportExecutor($nameserver, $loop), 3.0, $loop ) ) );
内部,此类使用PHP的UDP套接字,并且出于组织原因没有利用react/datagram,纯粹是为了避免两个包之间的循环依赖。高级组件应利用数据报组件而不是从头实现此套接字逻辑。
HostsFileExecutor
请注意,上述UdpTransportExecutor
类始终执行实际的DNS查询。如果您还想考虑主机文件中的条目,可以使用以下代码
$hosts = \React\Dns\Config\HostsFile::loadFromPathBlocking(); $executor = new UdpTransportExecutor('8.8.8.8:53', $loop); $executor = new HostsFileExecutor($hosts, $executor); $executor->query( new Query('localhost', Message::TYPE_A, Message::CLASS_IN) );
安装
安装此库的推荐方法是通过Composer。您是Composer的新手吗?
此项目遵循SemVer。这将安装最新支持的版本
$ composer require react/dns:^1.1
有关版本升级的详细信息,请参阅变更日志。
此项目旨在在任何平台上运行,因此不需要任何PHP扩展,并支持在旧版PHP 5.3到当前PHP 7+和HHVM上运行。强烈推荐使用PHP 7+。
测试
要运行测试套件,您首先需要克隆此仓库,然后通过Composer安装所有依赖项
$ composer install
要运行测试套件,请转到项目根目录并运行
$ php vendor/bin/phpunit
测试套件还包含一些依赖于稳定网络连接的功能集成测试。如果您不想运行这些测试,可以像这样简单地跳过
$ php vendor/bin/phpunit --exclude-group internet
许可证
MIT,请参阅LICENSE文件。