mirror of
https://github.com/danog/dns.git
synced 2024-11-26 20:14:51 +01:00
Switch to a new API to enable getting not only the first entry and not only A/AAAA records
This now can do queries to dns servers and you'll get the list of raw records in an array
This commit is contained in:
parent
e6ae0bf834
commit
ebb5fb510c
@ -4,7 +4,7 @@ root = true
|
|||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
indent_style = spaces
|
indent_style = space
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
|
|
||||||
[{.travis.yml}]
|
[{.travis.yml}]
|
||||||
|
@ -9,10 +9,11 @@ php:
|
|||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- composer self-update
|
- composer self-update
|
||||||
|
- composer require satooshi/php-coveralls:dev-master
|
||||||
- composer install
|
- composer install
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- vendor/bin/phpunit --coverage-text --coverage-clover build/logs/clover.xml
|
- $(php -r 'if (PHP_MAJOR_VERSION >= 7) echo "phpdbg -qrr"; else echo "php";') vendor/bin/phpunit --coverage-text --coverage-clover build/logs/clover.xml
|
||||||
- php vendor/bin/php-cs-fixer --diff --dry-run -v fix
|
- php vendor/bin/php-cs-fixer --diff --dry-run -v fix
|
||||||
|
|
||||||
after_script:
|
after_script:
|
||||||
|
@ -22,9 +22,8 @@
|
|||||||
"daverandom/libdns": "~1.0"
|
"daverandom/libdns": "~1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "~4.4.0",
|
"phpunit/phpunit": "~4.8",
|
||||||
"fabpot/php-cs-fixer": "~1.9",
|
"fabpot/php-cs-fixer": "~1.9"
|
||||||
"satooshi/php-coveralls": "dev-master"
|
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
5
lib/Record.php
Normal file
5
lib/Record.php
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Amp\Dns;
|
||||||
|
|
||||||
|
class Record extends \LibDNS\Records\ResourceQTypes {}
|
@ -8,7 +8,4 @@ const DEFAULT_PORT = 53;
|
|||||||
const DEFAULT_TIMEOUT = 5000;
|
const DEFAULT_TIMEOUT = 5000;
|
||||||
const MAX_REQUEST_ID = 65536;
|
const MAX_REQUEST_ID = 65536;
|
||||||
const IDLE_TIMEOUT = 15000;
|
const IDLE_TIMEOUT = 15000;
|
||||||
const MODE_INET4 = 1;
|
|
||||||
const MODE_INET6 = 2;
|
|
||||||
const MODE_CNAME = 3;
|
|
||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
|
@ -5,8 +5,6 @@ namespace Amp\Dns;
|
|||||||
use \LibDNS\Messages\MessageFactory;
|
use \LibDNS\Messages\MessageFactory;
|
||||||
use \LibDNS\Messages\MessageTypes;
|
use \LibDNS\Messages\MessageTypes;
|
||||||
use \LibDNS\Records\QuestionFactory;
|
use \LibDNS\Records\QuestionFactory;
|
||||||
use \LibDNS\Records\ResourceTypes;
|
|
||||||
use \LibDNS\Records\ResourceQTypes;
|
|
||||||
use \LibDNS\Encoder\EncoderFactory;
|
use \LibDNS\Encoder\EncoderFactory;
|
||||||
use \LibDNS\Decoder\DecoderFactory;
|
use \LibDNS\Decoder\DecoderFactory;
|
||||||
|
|
||||||
@ -15,24 +13,21 @@ use \LibDNS\Decoder\DecoderFactory;
|
|||||||
*
|
*
|
||||||
* Upon success the returned promise resolves to an indexed array of the form:
|
* Upon success the returned promise resolves to an indexed array of the form:
|
||||||
*
|
*
|
||||||
* [string $resolvedIp, int $mode, int $ttl]
|
* [string $resolvedIp, int $type, int $ttl]
|
||||||
*
|
|
||||||
* The $mode parameter at index 1 corresponds to one of two constant values to
|
|
||||||
* indicate if the resulting IP is IPv4 or IPv6:
|
|
||||||
*
|
|
||||||
* - Amp\Dns\MODE_INET4
|
|
||||||
* - Amp\Dns\MODE_INET6
|
|
||||||
*
|
*
|
||||||
* A null $ttl value indicates the DNS name was resolved from the cache or the
|
* A null $ttl value indicates the DNS name was resolved from the cache or the
|
||||||
* local hosts file.
|
* local hosts file.
|
||||||
|
* $type being one constant from Amp\Dns\Record
|
||||||
*
|
*
|
||||||
* Options:
|
* Options:
|
||||||
*
|
*
|
||||||
* - "server" | string Custom DNS server address in ip or ip:port format
|
* - "server" | string Custom DNS server address in ip or ip:port format
|
||||||
* - "timeout" | int Default: 3000ms
|
* - "timeout" | int Default: 3000ms
|
||||||
* - "mode" | int Either Amp\Dns\MODE_INET4 or Amp\Dns\MODE_INET6
|
|
||||||
* - "no_hosts" | bool Ignore entries in the hosts file
|
* - "no_hosts" | bool Ignore entries in the hosts file
|
||||||
|
* - "reload_hosts" | bool Reload the hosts file (Default: false), only active when no_hosts not true
|
||||||
* - "no_cache" | bool Ignore cached DNS response entries
|
* - "no_cache" | bool Ignore cached DNS response entries
|
||||||
|
* - "types" | array Default: [Record::A, Record::AAAA] (only for resolve())
|
||||||
|
* - "recurse" | bool Check for DNAME and CNAME records (always active for resolve(), Default: false for query())
|
||||||
*
|
*
|
||||||
* If the custom per-request "server" option is not present the resolver will
|
* If the custom per-request "server" option is not present the resolver will
|
||||||
* use the default from the following built-in constant:
|
* use the default from the following built-in constant:
|
||||||
@ -43,25 +38,31 @@ use \LibDNS\Decoder\DecoderFactory;
|
|||||||
* @param array $options
|
* @param array $options
|
||||||
* @return \Amp\Promise
|
* @return \Amp\Promise
|
||||||
* @TODO add boolean "clear_cache" option flag
|
* @TODO add boolean "clear_cache" option flag
|
||||||
* @TODO add boolean "reload_hosts" option flag
|
|
||||||
*/
|
*/
|
||||||
function resolve($name, array $options = []) {
|
function resolve($name, array $options = []) {
|
||||||
$mode = isset($options["mode"]) ? $options["mode"] : MODE_INET4;
|
if (!$inAddr = @\inet_pton($name)) {
|
||||||
if (!($mode === MODE_INET4 || $mode === MODE_INET6)) {
|
if (__isValidHostName($name)) {
|
||||||
return new \Amp\Failure(new ResolutionException(
|
$types = empty($options["types"]) ? [Record::A, Record::AAAA] : $options["types"];
|
||||||
"Invalid request mode option; Amp\Dns\MODE_INET4 or Amp\Dns\MODE_INET6 required"
|
return __pipeResult(__recurseWithHosts($name, $types, $options), $types);
|
||||||
));
|
} else {
|
||||||
} elseif (!$inAddr = @\inet_pton($name)) {
|
return new \Amp\Failure(new ResolutionException("Cannot resolve; invalid host name"));
|
||||||
return __isValidHostName($name)
|
}
|
||||||
? \Amp\resolve(__doResolve($name, $mode, $options))
|
|
||||||
: new \Amp\Failure(new ResolutionException(
|
|
||||||
"Cannot resolve; invalid host name"
|
|
||||||
))
|
|
||||||
;
|
|
||||||
} elseif (isset($inAddr[4])) {
|
|
||||||
return new \Amp\Success([$name, MODE_INET6, $ttl = null]);
|
|
||||||
} else {
|
} else {
|
||||||
return new \Amp\Success([$name, MODE_INET4, $ttl = null]);
|
return new \Amp\Success([[$name, isset($inAddr[4]) ? Record::AAAA : Record::A, $ttl = null]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function query($name, $type, array $options = []) {
|
||||||
|
if (!$inAddr = @\inet_pton($name)) {
|
||||||
|
if (__isValidHostName($name)) {
|
||||||
|
$handler = __NAMESPACE__ . "\\" . (empty($options["recurse"]) ? "__doRecurse" : "__doResolve");
|
||||||
|
$types = (array) $type;
|
||||||
|
return __pipeResult(\Amp\resolve($handler($name, $types, $options)), $types);
|
||||||
|
} else {
|
||||||
|
return new \Amp\Failure(new ResolutionException("Cannot resolve; invalid host name"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new \Amp\Failure(new ResolutionException("Cannot resolve records from an IP address"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,36 +72,93 @@ function __isValidHostName($name) {
|
|||||||
return isset($name[253]) ? false : (bool) \preg_match($pattern, $name);
|
return isset($name[253]) ? false : (bool) \preg_match($pattern, $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
function __doResolve($name, $mode, $options) {
|
// preserve order according to $types
|
||||||
static $state;
|
function __pipeResult($promise, array $types) {
|
||||||
$state = $state ?: (yield \Amp\resolve(__init()));
|
return \Amp\pipe($promise, function (array $result) use ($types) {
|
||||||
|
$retval = [];
|
||||||
|
foreach ($types as $type) {
|
||||||
|
if (isset($result[$type])) {
|
||||||
|
$retval = \array_merge($retval, $result[$type]);
|
||||||
|
unset($result[$type]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result ? \array_merge($retval, $result) : $retval;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$name = \strtolower($name);
|
function __recurseWithHosts($name, array $types, $options) {
|
||||||
|
// Check for hosts file matches
|
||||||
// Check for cache hits
|
if (empty($options["no_hosts"])) {
|
||||||
$cacheKey = "{$mode}#{$name}";
|
static $hosts = null;
|
||||||
if (empty($options["no_cache"])) {
|
if ($hosts === null || !empty($options["reload_hosts"])) {
|
||||||
if (yield $state->arrayCache->has($cacheKey)) {
|
return \Amp\pipe(\Amp\resolve(__loadHostsFile()), function($value) use (&$hosts, $name, $types, $options) {
|
||||||
$result = (yield $state->arrayCache->get($cacheKey));
|
$hosts = $value;
|
||||||
yield new \Amp\CoroutineResult([$result, $mode, $ttl = null]);
|
return __recurseWithHosts($name, $types, $options);
|
||||||
return;
|
});
|
||||||
|
}
|
||||||
|
$result = [];
|
||||||
|
if (in_array(Record::A, $types) && isset($hosts[Record::A][$name])) {
|
||||||
|
$result[Record::A] = [[$hosts[Record::A][$name], Record::A, $ttl = null]];
|
||||||
|
}
|
||||||
|
if (in_array(Record::AAAA, $types) && isset($hosts[Record::AAAA][$name])) {
|
||||||
|
$result[Record::AAAA] = [[$hosts[Record::AAAA][$name], Record::AAAA, $ttl = null]];
|
||||||
|
}
|
||||||
|
if ($result) {
|
||||||
|
return new \Amp\Success($result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for hosts file matches
|
return \Amp\resolve(__doRecurse($name, $types, $options));
|
||||||
if (empty($options["no_hosts"])) {
|
}
|
||||||
$have4 = isset($state->hostsFile[MODE_INET4][$name]);
|
|
||||||
$have6 = isset($state->hostsFile[MODE_INET6][$name]);
|
function __doRecurse($name, array $types, $options) {
|
||||||
$want4 = (bool)($mode & MODE_INET4);
|
if (array_intersect($types, [Record::CNAME, Record::DNAME])) {
|
||||||
$want6 = (bool)($mode & MODE_INET6);
|
throw new ResolutionException("Cannot use recursion for CNAME and DNAME records");
|
||||||
if ($have6 && $want6) {
|
}
|
||||||
$result = [$state->hostsFile[MODE_INET6][$name], MODE_INET6, $ttl = null];
|
|
||||||
} elseif ($have4 && $want4) {
|
$types = array_merge($types, [Record::CNAME, Record::DNAME]);
|
||||||
$result = [$state->hostsFile[MODE_INET4][$name], MODE_INET4, $ttl = null];
|
$lookupName = $name;
|
||||||
} else {
|
for ($i = 0; $i < 30; $i++) {
|
||||||
$result = null;
|
$result = (yield \Amp\resolve(__doResolve($lookupName, $types, $options)));
|
||||||
|
if (count($result) > isset($result[Record::CNAME]) + isset($result[Record::DNAME])) {
|
||||||
|
unset($result[Record::CNAME], $result[Record::DNAME]);
|
||||||
|
yield new \Amp\CoroutineResult($result);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if ($result) {
|
// @TODO check for potentially using recursion and iterate over *all* CNAME/DNAME
|
||||||
|
// @FIXME check higher level for CNAME?
|
||||||
|
foreach ([Record::CNAME, Record::DNAME] as $type) {
|
||||||
|
if (isset($result[$type])) {
|
||||||
|
list($lookupName) = $result[$type][0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ResolutionException("CNAME or DNAME chain too long (possible recursion?)");
|
||||||
|
}
|
||||||
|
|
||||||
|
function __doResolve($name, array $types, $options) {
|
||||||
|
static $state;
|
||||||
|
$state = $state ?: (yield \Amp\resolve(__init()));
|
||||||
|
|
||||||
|
if (empty($types)) {
|
||||||
|
yield new \Amp\CoroutineResult([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = \strtolower($name);
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
// Check for cache hits
|
||||||
|
if (empty($options["no_cache"])) {
|
||||||
|
foreach ($types as $k => $type) {
|
||||||
|
$cacheKey = "$name#$type";
|
||||||
|
if (yield $state->arrayCache->has($cacheKey)) {
|
||||||
|
$result[$type] = (yield $state->arrayCache->get($cacheKey));
|
||||||
|
unset($types[$k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (empty($types)) {
|
||||||
yield new \Amp\CoroutineResult($result);
|
yield new \Amp\CoroutineResult($result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -114,57 +172,53 @@ function __doResolve($name, $mode, $options) {
|
|||||||
;
|
;
|
||||||
$server = __loadExistingServer($state, $uri) ?: __loadNewServer($state, $uri);
|
$server = __loadExistingServer($state, $uri) ?: __loadNewServer($state, $uri);
|
||||||
|
|
||||||
// Get the next available request ID
|
foreach ($types as $type) {
|
||||||
do {
|
// Get the next available request ID
|
||||||
$requestId = $state->requestIdCounter++;
|
do {
|
||||||
if ($state->requestIdCounter >= MAX_REQUEST_ID) {
|
$requestId = $state->requestIdCounter++;
|
||||||
$state->requestIdCounter = 1;
|
if ($state->requestIdCounter >= MAX_REQUEST_ID) {
|
||||||
|
$state->requestIdCounter = 1;
|
||||||
|
}
|
||||||
|
} while (isset($state->pendingRequests[$requestId]));
|
||||||
|
|
||||||
|
// Create question record
|
||||||
|
$question = $state->questionFactory->create($type);
|
||||||
|
$question->setName($name);
|
||||||
|
|
||||||
|
// Create request message
|
||||||
|
$request = $state->messageFactory->create(MessageTypes::QUERY);
|
||||||
|
$request->getQuestionRecords()->add($question);
|
||||||
|
$request->isRecursionDesired(true);
|
||||||
|
$request->setID($requestId);
|
||||||
|
|
||||||
|
// Encode request message
|
||||||
|
$requestPacket = $state->encoder->encode($request);
|
||||||
|
|
||||||
|
// Send request
|
||||||
|
$bytesWritten = \fwrite($server->socket, $requestPacket);
|
||||||
|
if ($bytesWritten === false || isset($packet[$bytesWritten])) {
|
||||||
|
throw new ResolutionException(
|
||||||
|
"Request send failed"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} while (isset($state->pendingRequests[$requestId]));
|
|
||||||
|
|
||||||
// Create question record
|
$promisor = new \Amp\Deferred;
|
||||||
$questionType = ($mode === MODE_INET4) ? ResourceQTypes::A : ResourceQTypes::AAAA;
|
$server->pendingRequests[$requestId] = true;
|
||||||
$question = $state->questionFactory->create($questionType);
|
$state->pendingRequests[$requestId] = [$promisor, $name];
|
||||||
$question->setName($name);
|
$promises[] = $promisor->promise();
|
||||||
|
|
||||||
// Create request message
|
|
||||||
$request = $state->messageFactory->create(MessageTypes::QUERY);
|
|
||||||
$request->getQuestionRecords()->add($question);
|
|
||||||
$request->isRecursionDesired(true);
|
|
||||||
$request->setID($requestId);
|
|
||||||
|
|
||||||
// Encode request message
|
|
||||||
$requestPacket = $state->encoder->encode($request);
|
|
||||||
|
|
||||||
// Send request
|
|
||||||
$bytesWritten = \fwrite($server->socket, $requestPacket);
|
|
||||||
if ($bytesWritten === false || isset($packet[$bytesWritten])) {
|
|
||||||
throw new ResolutionException(
|
|
||||||
"Request send failed"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$promisor = new \Amp\Deferred;
|
|
||||||
$server->pendingRequests[$requestId] = true;
|
|
||||||
$state->pendingRequests[$requestId] = [$promisor, $name, $mode];
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$resultArr = (yield \Amp\timeout($promisor->promise(), $timeout));
|
list( , $resultArr) = (yield \Amp\timeout(\Amp\some($promises), $timeout));
|
||||||
|
foreach ($resultArr as $value) {
|
||||||
|
$result += $value;
|
||||||
|
}
|
||||||
|
yield new \Amp\CoroutineResult($result);
|
||||||
} catch (\Amp\TimeoutException $e) {
|
} catch (\Amp\TimeoutException $e) {
|
||||||
throw new TimeoutException(
|
throw new TimeoutException(
|
||||||
"Name resolution timed out for {$name}"
|
"Name resolution timed out for {$name}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
list($resultIp, $resultMode, $resultTtl) = $resultArr;
|
|
||||||
|
|
||||||
if ($resultMode === MODE_CNAME) {
|
|
||||||
$result = (yield resolve($resultIp, $mode, $options));
|
|
||||||
list($resultIp, $resultMode, $resultTtl) = $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield $state->arrayCache->set($cacheKey, $resultIp, $resultTtl);
|
|
||||||
yield new \Amp\CoroutineResult($resultArr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function __init() {
|
function __init() {
|
||||||
@ -174,7 +228,6 @@ function __init() {
|
|||||||
$state->encoder = (new EncoderFactory)->create();
|
$state->encoder = (new EncoderFactory)->create();
|
||||||
$state->decoder = (new DecoderFactory)->create();
|
$state->decoder = (new DecoderFactory)->create();
|
||||||
$state->arrayCache = new \Amp\Cache\ArrayCache;
|
$state->arrayCache = new \Amp\Cache\ArrayCache;
|
||||||
$state->hostsFile = (yield \Amp\resolve(__loadHostsFile()));
|
|
||||||
$state->requestIdCounter = 1;
|
$state->requestIdCounter = 1;
|
||||||
$state->pendingRequests = [];
|
$state->pendingRequests = [];
|
||||||
$state->serverIdMap = [];
|
$state->serverIdMap = [];
|
||||||
@ -200,10 +253,7 @@ function __init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function __loadHostsFile($path = null) {
|
function __loadHostsFile($path = null) {
|
||||||
$data = [
|
$data = [];
|
||||||
MODE_INET4 => [],
|
|
||||||
MODE_INET6 => [],
|
|
||||||
];
|
|
||||||
if (empty($path)) {
|
if (empty($path)) {
|
||||||
$path = \stripos(PHP_OS, 'win') === 0
|
$path = \stripos(PHP_OS, 'win') === 0
|
||||||
? 'C:\Windows\system32\drivers\etc\hosts'
|
? 'C:\Windows\system32\drivers\etc\hosts'
|
||||||
@ -225,9 +275,9 @@ function __loadHostsFile($path = null) {
|
|||||||
if (!($ip = @\inet_pton($parts[0]))) {
|
if (!($ip = @\inet_pton($parts[0]))) {
|
||||||
continue;
|
continue;
|
||||||
} elseif (isset($ip[4])) {
|
} elseif (isset($ip[4])) {
|
||||||
$key = MODE_INET6;
|
$key = Record::AAAA;
|
||||||
} else {
|
} else {
|
||||||
$key = MODE_INET4;
|
$key = Record::A;
|
||||||
}
|
}
|
||||||
for ($i = 1, $l = \count($parts); $i < $l; $i++) {
|
for ($i = 1, $l = \count($parts); $i < $l; $i++) {
|
||||||
if (__isValidHostName($parts[$i])) {
|
if (__isValidHostName($parts[$i])) {
|
||||||
@ -266,6 +316,7 @@ function __loadExistingServer($state, $uri) {
|
|||||||
if (empty($state->serverUriMap[$uri])) {
|
if (empty($state->serverUriMap[$uri])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$server = $state->serverUriMap[$uri];
|
$server = $state->serverUriMap[$uri];
|
||||||
if (\is_resource($server->socket)) {
|
if (\is_resource($server->socket)) {
|
||||||
unset($state->serverIdTimeoutMap[$server->id]);
|
unset($state->serverIdTimeoutMap[$server->id]);
|
||||||
@ -353,37 +404,20 @@ function __decodeResponsePacket($state, $serverId, $packet) {
|
|||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
__unloadServer($state, $serverId, new ResolutionException(
|
__unloadServer($state, $serverId, new ResolutionException(
|
||||||
"Response decode error",
|
"Response decode error", 0, $e
|
||||||
0,
|
|
||||||
$e
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function __processDecodedResponse($state, $serverId, $requestId, $response) {
|
function __processDecodedResponse($state, $serverId, $requestId, $response) {
|
||||||
static $typeMap = [
|
list( , $name) = $state->pendingRequests[$requestId];
|
||||||
MODE_INET4 => ResourceTypes::A,
|
|
||||||
MODE_INET6 => ResourceTypes::AAAA,
|
|
||||||
];
|
|
||||||
|
|
||||||
list($promisor, $name, $mode) = $state->pendingRequests[$requestId];
|
|
||||||
$answers = $response->getAnswerRecords();
|
$answers = $response->getAnswerRecords();
|
||||||
foreach ($answers as $record) {
|
foreach ($answers as $record) {
|
||||||
switch ($record->getType()) {
|
$result[$record->getType()][] = [(string) $record->getData(), $record->getType(), $record->getTTL()];
|
||||||
case $typeMap[$mode]:
|
|
||||||
$result = [(string) $record->getData(), $mode, $record->getTTL()];
|
|
||||||
break 2;
|
|
||||||
case ResourceTypes::CNAME:
|
|
||||||
// CNAME should only be used if no A records exist so we only
|
|
||||||
// break out of the switch (and not the foreach loop) here.
|
|
||||||
$result = [(string) $record->getData(), MODE_CNAME, $record->getTTL()];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (empty($result)) {
|
if (empty($result)) {
|
||||||
$recordType = ($mode === MODE_INET4) ? "A" : "AAAA";
|
|
||||||
__finalizeResult($state, $serverId, $requestId, new NoRecordException(
|
__finalizeResult($state, $serverId, $requestId, new NoRecordException(
|
||||||
"No {$recordType} records returned for {$name}"
|
"No records returned for {$name}"
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
__finalizeResult($state, $serverId, $requestId, $error = null, $result);
|
__finalizeResult($state, $serverId, $requestId, $error = null, $result);
|
||||||
@ -395,7 +429,7 @@ function __finalizeResult($state, $serverId, $requestId, $error = null, $result
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
list($promisor) = $state->pendingRequests[$requestId];
|
list($promisor, $name) = $state->pendingRequests[$requestId];
|
||||||
$server = $state->serverIdMap[$serverId];
|
$server = $state->serverIdMap[$serverId];
|
||||||
unset(
|
unset(
|
||||||
$state->pendingRequests[$requestId],
|
$state->pendingRequests[$requestId],
|
||||||
@ -409,6 +443,15 @@ function __finalizeResult($state, $serverId, $requestId, $error = null, $result
|
|||||||
if ($error) {
|
if ($error) {
|
||||||
$promisor->fail($error);
|
$promisor->fail($error);
|
||||||
} else {
|
} else {
|
||||||
|
foreach ($result as $type => $records) {
|
||||||
|
$minttl = INF;
|
||||||
|
foreach ($records as list( , $ttl)) {
|
||||||
|
if ($ttl && $minttl > $ttl) {
|
||||||
|
$minttl = $ttl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$state->arrayCache->set("$name#$type", $records, $minttl);
|
||||||
|
}
|
||||||
$promisor->succeed($result);
|
$promisor->succeed($result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,25 +22,13 @@ class IntegrationTest extends \PHPUnit_Framework_TestCase {
|
|||||||
];
|
];
|
||||||
|
|
||||||
foreach ($names as $name) {
|
foreach ($names as $name) {
|
||||||
list($addr, $mode) = (yield \Amp\Dns\resolve($name));
|
$result = (yield \Amp\Dns\resolve($name));
|
||||||
|
list($addr, $type, $ttl) = $result[0];
|
||||||
$inAddr = @\inet_pton($addr);
|
$inAddr = @\inet_pton($addr);
|
||||||
$this->assertNotFalse(
|
$this->assertNotFalse(
|
||||||
$inAddr,
|
$inAddr,
|
||||||
"Server name $name did not resolve to a valid IP address"
|
"Server name $name did not resolve to a valid IP address"
|
||||||
);
|
);
|
||||||
if (isset($inAddr[15])) {
|
|
||||||
$this->assertSame(
|
|
||||||
\Amp\Dns\MODE_INET6,
|
|
||||||
$mode,
|
|
||||||
"Returned mode parameter did not match expected MODE_INET6"
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$this->assertSame(
|
|
||||||
\Amp\Dns\MODE_INET4,
|
|
||||||
$mode,
|
|
||||||
"Returned mode parameter did not match expected MODE_INET4"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
error_reporting(E_ALL);
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
require __DIR__.'/../vendor/autoload.php';
|
||||||
|
|
||||||
if (ini_get("opcache.enable") == true &&
|
if (ini_get("opcache.enable") == true &&
|
||||||
ini_get("opcache.save_comments") == false) {
|
ini_get("opcache.save_comments") == false) {
|
||||||
echo "Cannot run tests. OPCache is enabled and is stripping comments, which are required by PHPUnit to provide data for the tests.\n";
|
echo "Cannot run tests. OPCache is enabled and is stripping comments, which are required by PHPUnit to provide data for the tests.\n";
|
||||||
|
Loading…
Reference in New Issue
Block a user